Commit | Line | Data |
---|---|---|
096030e7 FL |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // Copyright (C) 2019 Spreadtrum Communications Inc. | |
3 | ||
4 | #include <linux/clk.h> | |
5 | #include <linux/delay.h> | |
6 | #include <linux/hwspinlock.h> | |
7 | #include <linux/io.h> | |
8 | #include <linux/module.h> | |
9 | #include <linux/nvmem-provider.h> | |
10 | #include <linux/of_device.h> | |
11 | #include <linux/platform_device.h> | |
12 | ||
13 | #define SPRD_EFUSE_ENABLE 0x20 | |
14 | #define SPRD_EFUSE_ERR_FLAG 0x24 | |
15 | #define SPRD_EFUSE_ERR_CLR 0x28 | |
16 | #define SPRD_EFUSE_MAGIC_NUM 0x2c | |
17 | #define SPRD_EFUSE_FW_CFG 0x50 | |
18 | #define SPRD_EFUSE_PW_SWT 0x54 | |
19 | #define SPRD_EFUSE_MEM(val) (0x1000 + ((val) << 2)) | |
20 | ||
21 | #define SPRD_EFUSE_VDD_EN BIT(0) | |
22 | #define SPRD_EFUSE_AUTO_CHECK_EN BIT(1) | |
23 | #define SPRD_EFUSE_DOUBLE_EN BIT(2) | |
24 | #define SPRD_EFUSE_MARGIN_RD_EN BIT(3) | |
25 | #define SPRD_EFUSE_LOCK_WR_EN BIT(4) | |
26 | ||
27 | #define SPRD_EFUSE_ERR_CLR_MASK GENMASK(13, 0) | |
28 | ||
29 | #define SPRD_EFUSE_ENK1_ON BIT(0) | |
30 | #define SPRD_EFUSE_ENK2_ON BIT(1) | |
31 | #define SPRD_EFUSE_PROG_EN BIT(2) | |
32 | ||
33 | #define SPRD_EFUSE_MAGIC_NUMBER 0x8810 | |
34 | ||
35 | /* Block width (bytes) definitions */ | |
36 | #define SPRD_EFUSE_BLOCK_WIDTH 4 | |
37 | ||
38 | /* | |
39 | * The Spreadtrum AP efuse contains 2 parts: normal efuse and secure efuse, | |
40 | * and we can only access the normal efuse in kernel. So define the normal | |
41 | * block offset index and normal block numbers. | |
42 | */ | |
43 | #define SPRD_EFUSE_NORMAL_BLOCK_NUMS 24 | |
44 | #define SPRD_EFUSE_NORMAL_BLOCK_OFFSET 72 | |
45 | ||
46 | /* Timeout (ms) for the trylock of hardware spinlocks */ | |
47 | #define SPRD_EFUSE_HWLOCK_TIMEOUT 5000 | |
48 | ||
49 | /* | |
50 | * Since different Spreadtrum SoC chip can have different normal block numbers | |
51 | * and offset. And some SoC can support block double feature, which means | |
52 | * when reading or writing data to efuse memory, the controller can save double | |
53 | * data in case one data become incorrect after a long period. | |
54 | * | |
55 | * Thus we should save them in the device data structure. | |
56 | */ | |
57 | struct sprd_efuse_variant_data { | |
58 | u32 blk_nums; | |
59 | u32 blk_offset; | |
60 | bool blk_double; | |
61 | }; | |
62 | ||
63 | struct sprd_efuse { | |
64 | struct device *dev; | |
65 | struct clk *clk; | |
66 | struct hwspinlock *hwlock; | |
67 | struct mutex mutex; | |
68 | void __iomem *base; | |
69 | const struct sprd_efuse_variant_data *data; | |
70 | }; | |
71 | ||
72 | static const struct sprd_efuse_variant_data ums312_data = { | |
73 | .blk_nums = SPRD_EFUSE_NORMAL_BLOCK_NUMS, | |
74 | .blk_offset = SPRD_EFUSE_NORMAL_BLOCK_OFFSET, | |
75 | .blk_double = false, | |
76 | }; | |
77 | ||
78 | /* | |
79 | * On Spreadtrum platform, we have multi-subsystems will access the unique | |
80 | * efuse controller, so we need one hardware spinlock to synchronize between | |
81 | * the multiple subsystems. | |
82 | */ | |
83 | static int sprd_efuse_lock(struct sprd_efuse *efuse) | |
84 | { | |
85 | int ret; | |
86 | ||
87 | mutex_lock(&efuse->mutex); | |
88 | ||
89 | ret = hwspin_lock_timeout_raw(efuse->hwlock, | |
90 | SPRD_EFUSE_HWLOCK_TIMEOUT); | |
91 | if (ret) { | |
92 | dev_err(efuse->dev, "timeout get the hwspinlock\n"); | |
93 | mutex_unlock(&efuse->mutex); | |
94 | return ret; | |
95 | } | |
96 | ||
97 | return 0; | |
98 | } | |
99 | ||
100 | static void sprd_efuse_unlock(struct sprd_efuse *efuse) | |
101 | { | |
102 | hwspin_unlock_raw(efuse->hwlock); | |
103 | mutex_unlock(&efuse->mutex); | |
104 | } | |
105 | ||
106 | static void sprd_efuse_set_prog_power(struct sprd_efuse *efuse, bool en) | |
107 | { | |
108 | u32 val = readl(efuse->base + SPRD_EFUSE_PW_SWT); | |
109 | ||
110 | if (en) | |
111 | val &= ~SPRD_EFUSE_ENK2_ON; | |
112 | else | |
113 | val &= ~SPRD_EFUSE_ENK1_ON; | |
114 | ||
115 | writel(val, efuse->base + SPRD_EFUSE_PW_SWT); | |
116 | ||
117 | /* Open or close efuse power need wait 1000us to make power stable. */ | |
118 | usleep_range(1000, 1200); | |
119 | ||
120 | if (en) | |
121 | val |= SPRD_EFUSE_ENK1_ON; | |
122 | else | |
123 | val |= SPRD_EFUSE_ENK2_ON; | |
124 | ||
125 | writel(val, efuse->base + SPRD_EFUSE_PW_SWT); | |
126 | ||
127 | /* Open or close efuse power need wait 1000us to make power stable. */ | |
128 | usleep_range(1000, 1200); | |
129 | } | |
130 | ||
131 | static void sprd_efuse_set_read_power(struct sprd_efuse *efuse, bool en) | |
132 | { | |
133 | u32 val = readl(efuse->base + SPRD_EFUSE_ENABLE); | |
134 | ||
135 | if (en) | |
136 | val |= SPRD_EFUSE_VDD_EN; | |
137 | else | |
138 | val &= ~SPRD_EFUSE_VDD_EN; | |
139 | ||
140 | writel(val, efuse->base + SPRD_EFUSE_ENABLE); | |
141 | ||
142 | /* Open or close efuse power need wait 1000us to make power stable. */ | |
143 | usleep_range(1000, 1200); | |
144 | } | |
145 | ||
146 | static void sprd_efuse_set_prog_lock(struct sprd_efuse *efuse, bool en) | |
147 | { | |
148 | u32 val = readl(efuse->base + SPRD_EFUSE_ENABLE); | |
149 | ||
150 | if (en) | |
151 | val |= SPRD_EFUSE_LOCK_WR_EN; | |
152 | else | |
153 | val &= ~SPRD_EFUSE_LOCK_WR_EN; | |
154 | ||
155 | writel(val, efuse->base + SPRD_EFUSE_ENABLE); | |
156 | } | |
157 | ||
158 | static void sprd_efuse_set_auto_check(struct sprd_efuse *efuse, bool en) | |
159 | { | |
160 | u32 val = readl(efuse->base + SPRD_EFUSE_ENABLE); | |
161 | ||
162 | if (en) | |
163 | val |= SPRD_EFUSE_AUTO_CHECK_EN; | |
164 | else | |
165 | val &= ~SPRD_EFUSE_AUTO_CHECK_EN; | |
166 | ||
167 | writel(val, efuse->base + SPRD_EFUSE_ENABLE); | |
168 | } | |
169 | ||
170 | static void sprd_efuse_set_data_double(struct sprd_efuse *efuse, bool en) | |
171 | { | |
172 | u32 val = readl(efuse->base + SPRD_EFUSE_ENABLE); | |
173 | ||
174 | if (en) | |
175 | val |= SPRD_EFUSE_DOUBLE_EN; | |
176 | else | |
177 | val &= ~SPRD_EFUSE_DOUBLE_EN; | |
178 | ||
179 | writel(val, efuse->base + SPRD_EFUSE_ENABLE); | |
180 | } | |
181 | ||
182 | static void sprd_efuse_set_prog_en(struct sprd_efuse *efuse, bool en) | |
183 | { | |
184 | u32 val = readl(efuse->base + SPRD_EFUSE_PW_SWT); | |
185 | ||
186 | if (en) | |
187 | val |= SPRD_EFUSE_PROG_EN; | |
188 | else | |
189 | val &= ~SPRD_EFUSE_PROG_EN; | |
190 | ||
191 | writel(val, efuse->base + SPRD_EFUSE_PW_SWT); | |
192 | } | |
193 | ||
194 | static int sprd_efuse_raw_prog(struct sprd_efuse *efuse, u32 blk, bool doub, | |
195 | bool lock, u32 *data) | |
196 | { | |
197 | u32 status; | |
198 | int ret = 0; | |
199 | ||
200 | /* | |
201 | * We need set the correct magic number before writing the efuse to | |
202 | * allow programming, and block other programming until we clear the | |
203 | * magic number. | |
204 | */ | |
205 | writel(SPRD_EFUSE_MAGIC_NUMBER, | |
206 | efuse->base + SPRD_EFUSE_MAGIC_NUM); | |
207 | ||
208 | /* | |
209 | * Power on the efuse, enable programme and enable double data | |
210 | * if asked. | |
211 | */ | |
212 | sprd_efuse_set_prog_power(efuse, true); | |
213 | sprd_efuse_set_prog_en(efuse, true); | |
214 | sprd_efuse_set_data_double(efuse, doub); | |
215 | ||
216 | /* | |
217 | * Enable the auto-check function to validate if the programming is | |
218 | * successful. | |
219 | */ | |
5af25388 FL |
220 | if (lock) |
221 | sprd_efuse_set_auto_check(efuse, true); | |
096030e7 FL |
222 | |
223 | writel(*data, efuse->base + SPRD_EFUSE_MEM(blk)); | |
224 | ||
225 | /* Disable auto-check and data double after programming */ | |
5af25388 FL |
226 | if (lock) |
227 | sprd_efuse_set_auto_check(efuse, false); | |
096030e7 FL |
228 | sprd_efuse_set_data_double(efuse, false); |
229 | ||
230 | /* | |
231 | * Check the efuse error status, if the programming is successful, | |
232 | * we should lock this efuse block to avoid programming again. | |
233 | */ | |
234 | status = readl(efuse->base + SPRD_EFUSE_ERR_FLAG); | |
235 | if (status) { | |
236 | dev_err(efuse->dev, | |
237 | "write error status %d of block %d\n", ret, blk); | |
238 | ||
239 | writel(SPRD_EFUSE_ERR_CLR_MASK, | |
240 | efuse->base + SPRD_EFUSE_ERR_CLR); | |
241 | ret = -EBUSY; | |
5af25388 | 242 | } else if (lock) { |
096030e7 | 243 | sprd_efuse_set_prog_lock(efuse, lock); |
c66ebde4 | 244 | writel(0, efuse->base + SPRD_EFUSE_MEM(blk)); |
096030e7 FL |
245 | sprd_efuse_set_prog_lock(efuse, false); |
246 | } | |
247 | ||
248 | sprd_efuse_set_prog_power(efuse, false); | |
249 | writel(0, efuse->base + SPRD_EFUSE_MAGIC_NUM); | |
250 | ||
251 | return ret; | |
252 | } | |
253 | ||
254 | static int sprd_efuse_raw_read(struct sprd_efuse *efuse, int blk, u32 *val, | |
255 | bool doub) | |
256 | { | |
257 | u32 status; | |
258 | ||
259 | /* | |
260 | * Need power on the efuse before reading data from efuse, and will | |
261 | * power off the efuse after reading process. | |
262 | */ | |
263 | sprd_efuse_set_read_power(efuse, true); | |
264 | ||
265 | /* Enable double data if asked */ | |
266 | sprd_efuse_set_data_double(efuse, doub); | |
267 | ||
268 | /* Start to read data from efuse block */ | |
269 | *val = readl(efuse->base + SPRD_EFUSE_MEM(blk)); | |
270 | ||
271 | /* Disable double data */ | |
272 | sprd_efuse_set_data_double(efuse, false); | |
273 | ||
274 | /* Power off the efuse */ | |
275 | sprd_efuse_set_read_power(efuse, false); | |
276 | ||
277 | /* | |
278 | * Check the efuse error status and clear them if there are some | |
279 | * errors occurred. | |
280 | */ | |
281 | status = readl(efuse->base + SPRD_EFUSE_ERR_FLAG); | |
282 | if (status) { | |
283 | dev_err(efuse->dev, | |
284 | "read error status %d of block %d\n", status, blk); | |
285 | ||
286 | writel(SPRD_EFUSE_ERR_CLR_MASK, | |
287 | efuse->base + SPRD_EFUSE_ERR_CLR); | |
288 | return -EBUSY; | |
289 | } | |
290 | ||
291 | return 0; | |
292 | } | |
293 | ||
294 | static int sprd_efuse_read(void *context, u32 offset, void *val, size_t bytes) | |
295 | { | |
296 | struct sprd_efuse *efuse = context; | |
297 | bool blk_double = efuse->data->blk_double; | |
298 | u32 index = offset / SPRD_EFUSE_BLOCK_WIDTH + efuse->data->blk_offset; | |
299 | u32 blk_offset = (offset % SPRD_EFUSE_BLOCK_WIDTH) * BITS_PER_BYTE; | |
300 | u32 data; | |
301 | int ret; | |
302 | ||
303 | ret = sprd_efuse_lock(efuse); | |
304 | if (ret) | |
305 | return ret; | |
306 | ||
307 | ret = clk_prepare_enable(efuse->clk); | |
308 | if (ret) | |
309 | goto unlock; | |
310 | ||
311 | ret = sprd_efuse_raw_read(efuse, index, &data, blk_double); | |
312 | if (!ret) { | |
313 | data >>= blk_offset; | |
314 | memcpy(val, &data, bytes); | |
315 | } | |
316 | ||
317 | clk_disable_unprepare(efuse->clk); | |
318 | ||
319 | unlock: | |
320 | sprd_efuse_unlock(efuse); | |
321 | return ret; | |
322 | } | |
323 | ||
324 | static int sprd_efuse_write(void *context, u32 offset, void *val, size_t bytes) | |
325 | { | |
326 | struct sprd_efuse *efuse = context; | |
4bd5a15d | 327 | bool blk_double = efuse->data->blk_double; |
5af25388 | 328 | bool lock; |
096030e7 FL |
329 | int ret; |
330 | ||
331 | ret = sprd_efuse_lock(efuse); | |
332 | if (ret) | |
333 | return ret; | |
334 | ||
335 | ret = clk_prepare_enable(efuse->clk); | |
336 | if (ret) | |
337 | goto unlock; | |
338 | ||
5af25388 FL |
339 | /* |
340 | * If the writing bytes are equal with the block width, which means the | |
341 | * whole block will be programmed. For this case, we should not allow | |
342 | * this block to be programmed again by locking this block. | |
343 | * | |
344 | * If the block was programmed partially, we should allow this block to | |
345 | * be programmed again. | |
346 | */ | |
347 | if (bytes < SPRD_EFUSE_BLOCK_WIDTH) | |
348 | lock = false; | |
349 | else | |
350 | lock = true; | |
351 | ||
4bd5a15d | 352 | ret = sprd_efuse_raw_prog(efuse, offset, blk_double, lock, val); |
096030e7 FL |
353 | |
354 | clk_disable_unprepare(efuse->clk); | |
355 | ||
356 | unlock: | |
357 | sprd_efuse_unlock(efuse); | |
358 | return ret; | |
359 | } | |
360 | ||
361 | static int sprd_efuse_probe(struct platform_device *pdev) | |
362 | { | |
363 | struct device_node *np = pdev->dev.of_node; | |
364 | struct nvmem_device *nvmem; | |
365 | struct nvmem_config econfig = { }; | |
366 | struct sprd_efuse *efuse; | |
367 | const struct sprd_efuse_variant_data *pdata; | |
368 | int ret; | |
369 | ||
370 | pdata = of_device_get_match_data(&pdev->dev); | |
371 | if (!pdata) { | |
372 | dev_err(&pdev->dev, "No matching driver data found\n"); | |
373 | return -EINVAL; | |
374 | } | |
375 | ||
376 | efuse = devm_kzalloc(&pdev->dev, sizeof(*efuse), GFP_KERNEL); | |
377 | if (!efuse) | |
378 | return -ENOMEM; | |
379 | ||
380 | efuse->base = devm_platform_ioremap_resource(pdev, 0); | |
bcd14bb7 TY |
381 | if (IS_ERR(efuse->base)) |
382 | return PTR_ERR(efuse->base); | |
096030e7 FL |
383 | |
384 | ret = of_hwspin_lock_get_id(np, 0); | |
385 | if (ret < 0) { | |
386 | dev_err(&pdev->dev, "failed to get hwlock id\n"); | |
387 | return ret; | |
388 | } | |
389 | ||
390 | efuse->hwlock = devm_hwspin_lock_request_specific(&pdev->dev, ret); | |
391 | if (!efuse->hwlock) { | |
392 | dev_err(&pdev->dev, "failed to request hwlock\n"); | |
393 | return -ENXIO; | |
394 | } | |
395 | ||
396 | efuse->clk = devm_clk_get(&pdev->dev, "enable"); | |
397 | if (IS_ERR(efuse->clk)) { | |
398 | dev_err(&pdev->dev, "failed to get enable clock\n"); | |
399 | return PTR_ERR(efuse->clk); | |
400 | } | |
401 | ||
402 | mutex_init(&efuse->mutex); | |
403 | efuse->dev = &pdev->dev; | |
404 | efuse->data = pdata; | |
405 | ||
406 | econfig.stride = 1; | |
407 | econfig.word_size = 1; | |
408 | econfig.read_only = false; | |
409 | econfig.name = "sprd-efuse"; | |
410 | econfig.size = efuse->data->blk_nums * SPRD_EFUSE_BLOCK_WIDTH; | |
411 | econfig.reg_read = sprd_efuse_read; | |
412 | econfig.reg_write = sprd_efuse_write; | |
413 | econfig.priv = efuse; | |
414 | econfig.dev = &pdev->dev; | |
415 | nvmem = devm_nvmem_register(&pdev->dev, &econfig); | |
416 | if (IS_ERR(nvmem)) { | |
417 | dev_err(&pdev->dev, "failed to register nvmem\n"); | |
418 | return PTR_ERR(nvmem); | |
419 | } | |
420 | ||
421 | return 0; | |
422 | } | |
423 | ||
424 | static const struct of_device_id sprd_efuse_of_match[] = { | |
425 | { .compatible = "sprd,ums312-efuse", .data = &ums312_data }, | |
426 | { } | |
427 | }; | |
428 | ||
429 | static struct platform_driver sprd_efuse_driver = { | |
430 | .probe = sprd_efuse_probe, | |
431 | .driver = { | |
432 | .name = "sprd-efuse", | |
433 | .of_match_table = sprd_efuse_of_match, | |
434 | }, | |
435 | }; | |
436 | ||
437 | module_platform_driver(sprd_efuse_driver); | |
438 | ||
439 | MODULE_AUTHOR("Freeman Liu <freeman.liu@spreadtrum.com>"); | |
440 | MODULE_DESCRIPTION("Spreadtrum AP efuse driver"); | |
441 | MODULE_LICENSE("GPL v2"); |