1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (C) STMicroelectronics SA 2017 |
4 | * Author: Fabien Dessenne <fabien.dessenne@st.com> |
5 | */ |
6 | |
7 | #include <linux/bitrev.h> |
8 | #include <linux/clk.h> |
9 | #include <linux/crc32.h> |
10 | #include <linux/crc32poly.h> |
11 | #include <linux/io.h> |
12 | #include <linux/kernel.h> |
13 | #include <linux/module.h> |
14 | #include <linux/mod_devicetable.h> |
15 | #include <linux/platform_device.h> |
16 | #include <linux/pm_runtime.h> |
17 | |
18 | #include <crypto/internal/hash.h> |
19 | |
20 | #include <asm/unaligned.h> |
21 | |
22 | #define DRIVER_NAME "stm32-crc32" |
23 | #define CHKSUM_DIGEST_SIZE 4 |
24 | #define CHKSUM_BLOCK_SIZE 1 |
25 | |
26 | /* Registers */ |
27 | #define CRC_DR 0x00000000 |
28 | #define CRC_CR 0x00000008 |
29 | #define CRC_INIT 0x00000010 |
30 | #define CRC_POL 0x00000014 |
31 | |
32 | /* Registers values */ |
33 | #define CRC_CR_RESET BIT(0) |
34 | #define CRC_CR_REV_IN_WORD (BIT(6) | BIT(5)) |
35 | #define CRC_CR_REV_IN_BYTE BIT(5) |
36 | #define CRC_CR_REV_OUT BIT(7) |
37 | #define CRC32C_INIT_DEFAULT 0xFFFFFFFF |
38 | |
39 | #define CRC_AUTOSUSPEND_DELAY 50 |
40 | |
41 | static unsigned int burst_size; |
42 | module_param(burst_size, uint, 0644); |
43 | MODULE_PARM_DESC(burst_size, "Select burst byte size (0 unlimited)" ); |
44 | |
45 | struct stm32_crc { |
46 | struct list_head list; |
47 | struct device *dev; |
48 | void __iomem *regs; |
49 | struct clk *clk; |
50 | spinlock_t lock; |
51 | }; |
52 | |
53 | struct stm32_crc_list { |
54 | struct list_head dev_list; |
55 | spinlock_t lock; /* protect dev_list */ |
56 | }; |
57 | |
58 | static struct stm32_crc_list crc_list = { |
59 | .dev_list = LIST_HEAD_INIT(crc_list.dev_list), |
60 | .lock = __SPIN_LOCK_UNLOCKED(crc_list.lock), |
61 | }; |
62 | |
63 | struct stm32_crc_ctx { |
64 | u32 key; |
65 | u32 poly; |
66 | }; |
67 | |
68 | struct stm32_crc_desc_ctx { |
69 | u32 partial; /* crc32c: partial in first 4 bytes of that struct */ |
70 | }; |
71 | |
72 | static int stm32_crc32_cra_init(struct crypto_tfm *tfm) |
73 | { |
74 | struct stm32_crc_ctx *mctx = crypto_tfm_ctx(tfm); |
75 | |
76 | mctx->key = 0; |
77 | mctx->poly = CRC32_POLY_LE; |
78 | return 0; |
79 | } |
80 | |
81 | static int stm32_crc32c_cra_init(struct crypto_tfm *tfm) |
82 | { |
83 | struct stm32_crc_ctx *mctx = crypto_tfm_ctx(tfm); |
84 | |
85 | mctx->key = CRC32C_INIT_DEFAULT; |
86 | mctx->poly = CRC32C_POLY_LE; |
87 | return 0; |
88 | } |
89 | |
90 | static int stm32_crc_setkey(struct crypto_shash *tfm, const u8 *key, |
91 | unsigned int keylen) |
92 | { |
93 | struct stm32_crc_ctx *mctx = crypto_shash_ctx(tfm); |
94 | |
95 | if (keylen != sizeof(u32)) |
96 | return -EINVAL; |
97 | |
98 | mctx->key = get_unaligned_le32(p: key); |
99 | return 0; |
100 | } |
101 | |
102 | static struct stm32_crc *stm32_crc_get_next_crc(void) |
103 | { |
104 | struct stm32_crc *crc; |
105 | |
106 | spin_lock_bh(lock: &crc_list.lock); |
107 | crc = list_first_entry_or_null(&crc_list.dev_list, struct stm32_crc, list); |
108 | if (crc) |
109 | list_move_tail(list: &crc->list, head: &crc_list.dev_list); |
110 | spin_unlock_bh(lock: &crc_list.lock); |
111 | |
112 | return crc; |
113 | } |
114 | |
115 | static int stm32_crc_init(struct shash_desc *desc) |
116 | { |
117 | struct stm32_crc_desc_ctx *ctx = shash_desc_ctx(desc); |
118 | struct stm32_crc_ctx *mctx = crypto_shash_ctx(tfm: desc->tfm); |
119 | struct stm32_crc *crc; |
120 | unsigned long flags; |
121 | |
122 | crc = stm32_crc_get_next_crc(); |
123 | if (!crc) |
124 | return -ENODEV; |
125 | |
126 | pm_runtime_get_sync(dev: crc->dev); |
127 | |
128 | spin_lock_irqsave(&crc->lock, flags); |
129 | |
130 | /* Reset, set key, poly and configure in bit reverse mode */ |
131 | writel_relaxed(bitrev32(mctx->key), crc->regs + CRC_INIT); |
132 | writel_relaxed(bitrev32(mctx->poly), crc->regs + CRC_POL); |
133 | writel_relaxed(CRC_CR_RESET | CRC_CR_REV_IN_WORD | CRC_CR_REV_OUT, |
134 | crc->regs + CRC_CR); |
135 | |
136 | /* Store partial result */ |
137 | ctx->partial = readl_relaxed(crc->regs + CRC_DR); |
138 | |
139 | spin_unlock_irqrestore(lock: &crc->lock, flags); |
140 | |
141 | pm_runtime_mark_last_busy(dev: crc->dev); |
142 | pm_runtime_put_autosuspend(dev: crc->dev); |
143 | |
144 | return 0; |
145 | } |
146 | |
147 | static int burst_update(struct shash_desc *desc, const u8 *d8, |
148 | size_t length) |
149 | { |
150 | struct stm32_crc_desc_ctx *ctx = shash_desc_ctx(desc); |
151 | struct stm32_crc_ctx *mctx = crypto_shash_ctx(tfm: desc->tfm); |
152 | struct stm32_crc *crc; |
153 | |
154 | crc = stm32_crc_get_next_crc(); |
155 | if (!crc) |
156 | return -ENODEV; |
157 | |
158 | pm_runtime_get_sync(dev: crc->dev); |
159 | |
160 | if (!spin_trylock(lock: &crc->lock)) { |
161 | /* Hardware is busy, calculate crc32 by software */ |
162 | if (mctx->poly == CRC32_POLY_LE) |
163 | ctx->partial = crc32_le(crc: ctx->partial, p: d8, len: length); |
164 | else |
165 | ctx->partial = __crc32c_le(crc: ctx->partial, p: d8, len: length); |
166 | |
167 | goto pm_out; |
168 | } |
169 | |
170 | /* |
171 | * Restore previously calculated CRC for this context as init value |
172 | * Restore polynomial configuration |
173 | * Configure in register for word input data, |
174 | * Configure out register in reversed bit mode data. |
175 | */ |
176 | writel_relaxed(bitrev32(ctx->partial), crc->regs + CRC_INIT); |
177 | writel_relaxed(bitrev32(mctx->poly), crc->regs + CRC_POL); |
178 | writel_relaxed(CRC_CR_RESET | CRC_CR_REV_IN_WORD | CRC_CR_REV_OUT, |
179 | crc->regs + CRC_CR); |
180 | |
181 | if (d8 != PTR_ALIGN(d8, sizeof(u32))) { |
182 | /* Configure for byte data */ |
183 | writel_relaxed(CRC_CR_REV_IN_BYTE | CRC_CR_REV_OUT, |
184 | crc->regs + CRC_CR); |
185 | while (d8 != PTR_ALIGN(d8, sizeof(u32)) && length) { |
186 | writeb_relaxed(*d8++, crc->regs + CRC_DR); |
187 | length--; |
188 | } |
189 | /* Configure for word data */ |
190 | writel_relaxed(CRC_CR_REV_IN_WORD | CRC_CR_REV_OUT, |
191 | crc->regs + CRC_CR); |
192 | } |
193 | |
194 | for (; length >= sizeof(u32); d8 += sizeof(u32), length -= sizeof(u32)) |
195 | writel_relaxed(*((u32 *)d8), crc->regs + CRC_DR); |
196 | |
197 | if (length) { |
198 | /* Configure for byte data */ |
199 | writel_relaxed(CRC_CR_REV_IN_BYTE | CRC_CR_REV_OUT, |
200 | crc->regs + CRC_CR); |
201 | while (length--) |
202 | writeb_relaxed(*d8++, crc->regs + CRC_DR); |
203 | } |
204 | |
205 | /* Store partial result */ |
206 | ctx->partial = readl_relaxed(crc->regs + CRC_DR); |
207 | |
208 | spin_unlock(lock: &crc->lock); |
209 | |
210 | pm_out: |
211 | pm_runtime_mark_last_busy(dev: crc->dev); |
212 | pm_runtime_put_autosuspend(dev: crc->dev); |
213 | |
214 | return 0; |
215 | } |
216 | |
217 | static int stm32_crc_update(struct shash_desc *desc, const u8 *d8, |
218 | unsigned int length) |
219 | { |
220 | const unsigned int burst_sz = burst_size; |
221 | unsigned int rem_sz; |
222 | const u8 *cur; |
223 | size_t size; |
224 | int ret; |
225 | |
226 | if (!burst_sz) |
227 | return burst_update(desc, d8, length); |
228 | |
229 | /* Digest first bytes not 32bit aligned at first pass in the loop */ |
230 | size = min_t(size_t, length, burst_sz + (size_t)d8 - |
231 | ALIGN_DOWN((size_t)d8, sizeof(u32))); |
232 | for (rem_sz = length, cur = d8; rem_sz; |
233 | rem_sz -= size, cur += size, size = min(rem_sz, burst_sz)) { |
234 | ret = burst_update(desc, d8: cur, length: size); |
235 | if (ret) |
236 | return ret; |
237 | } |
238 | |
239 | return 0; |
240 | } |
241 | |
242 | static int stm32_crc_final(struct shash_desc *desc, u8 *out) |
243 | { |
244 | struct stm32_crc_desc_ctx *ctx = shash_desc_ctx(desc); |
245 | struct stm32_crc_ctx *mctx = crypto_shash_ctx(tfm: desc->tfm); |
246 | |
247 | /* Send computed CRC */ |
248 | put_unaligned_le32(val: mctx->poly == CRC32C_POLY_LE ? |
249 | ~ctx->partial : ctx->partial, p: out); |
250 | |
251 | return 0; |
252 | } |
253 | |
254 | static int stm32_crc_finup(struct shash_desc *desc, const u8 *data, |
255 | unsigned int length, u8 *out) |
256 | { |
257 | return stm32_crc_update(desc, d8: data, length) ?: |
258 | stm32_crc_final(desc, out); |
259 | } |
260 | |
261 | static int stm32_crc_digest(struct shash_desc *desc, const u8 *data, |
262 | unsigned int length, u8 *out) |
263 | { |
264 | return stm32_crc_init(desc) ?: stm32_crc_finup(desc, data, length, out); |
265 | } |
266 | |
267 | static unsigned int refcnt; |
268 | static DEFINE_MUTEX(refcnt_lock); |
269 | static struct shash_alg algs[] = { |
270 | /* CRC-32 */ |
271 | { |
272 | .setkey = stm32_crc_setkey, |
273 | .init = stm32_crc_init, |
274 | .update = stm32_crc_update, |
275 | .final = stm32_crc_final, |
276 | .finup = stm32_crc_finup, |
277 | .digest = stm32_crc_digest, |
278 | .descsize = sizeof(struct stm32_crc_desc_ctx), |
279 | .digestsize = CHKSUM_DIGEST_SIZE, |
280 | .base = { |
281 | .cra_name = "crc32" , |
282 | .cra_driver_name = "stm32-crc32-crc32" , |
283 | .cra_priority = 200, |
284 | .cra_flags = CRYPTO_ALG_OPTIONAL_KEY, |
285 | .cra_blocksize = CHKSUM_BLOCK_SIZE, |
286 | .cra_ctxsize = sizeof(struct stm32_crc_ctx), |
287 | .cra_module = THIS_MODULE, |
288 | .cra_init = stm32_crc32_cra_init, |
289 | } |
290 | }, |
291 | /* CRC-32Castagnoli */ |
292 | { |
293 | .setkey = stm32_crc_setkey, |
294 | .init = stm32_crc_init, |
295 | .update = stm32_crc_update, |
296 | .final = stm32_crc_final, |
297 | .finup = stm32_crc_finup, |
298 | .digest = stm32_crc_digest, |
299 | .descsize = sizeof(struct stm32_crc_desc_ctx), |
300 | .digestsize = CHKSUM_DIGEST_SIZE, |
301 | .base = { |
302 | .cra_name = "crc32c" , |
303 | .cra_driver_name = "stm32-crc32-crc32c" , |
304 | .cra_priority = 200, |
305 | .cra_flags = CRYPTO_ALG_OPTIONAL_KEY, |
306 | .cra_blocksize = CHKSUM_BLOCK_SIZE, |
307 | .cra_ctxsize = sizeof(struct stm32_crc_ctx), |
308 | .cra_module = THIS_MODULE, |
309 | .cra_init = stm32_crc32c_cra_init, |
310 | } |
311 | } |
312 | }; |
313 | |
314 | static int stm32_crc_probe(struct platform_device *pdev) |
315 | { |
316 | struct device *dev = &pdev->dev; |
317 | struct stm32_crc *crc; |
318 | int ret; |
319 | |
320 | crc = devm_kzalloc(dev, size: sizeof(*crc), GFP_KERNEL); |
321 | if (!crc) |
322 | return -ENOMEM; |
323 | |
324 | crc->dev = dev; |
325 | |
326 | crc->regs = devm_platform_ioremap_resource(pdev, index: 0); |
327 | if (IS_ERR(ptr: crc->regs)) { |
328 | dev_err(dev, "Cannot map CRC IO\n" ); |
329 | return PTR_ERR(ptr: crc->regs); |
330 | } |
331 | |
332 | crc->clk = devm_clk_get(dev, NULL); |
333 | if (IS_ERR(ptr: crc->clk)) { |
334 | dev_err(dev, "Could not get clock\n" ); |
335 | return PTR_ERR(ptr: crc->clk); |
336 | } |
337 | |
338 | ret = clk_prepare_enable(clk: crc->clk); |
339 | if (ret) { |
340 | dev_err(crc->dev, "Failed to enable clock\n" ); |
341 | return ret; |
342 | } |
343 | |
344 | pm_runtime_set_autosuspend_delay(dev, CRC_AUTOSUSPEND_DELAY); |
345 | pm_runtime_use_autosuspend(dev); |
346 | |
347 | pm_runtime_get_noresume(dev); |
348 | pm_runtime_set_active(dev); |
349 | pm_runtime_irq_safe(dev); |
350 | pm_runtime_enable(dev); |
351 | |
352 | spin_lock_init(&crc->lock); |
353 | |
354 | platform_set_drvdata(pdev, data: crc); |
355 | |
356 | spin_lock(lock: &crc_list.lock); |
357 | list_add(new: &crc->list, head: &crc_list.dev_list); |
358 | spin_unlock(lock: &crc_list.lock); |
359 | |
360 | mutex_lock(&refcnt_lock); |
361 | if (!refcnt) { |
362 | ret = crypto_register_shashes(algs, ARRAY_SIZE(algs)); |
363 | if (ret) { |
364 | mutex_unlock(lock: &refcnt_lock); |
365 | dev_err(dev, "Failed to register\n" ); |
366 | clk_disable_unprepare(clk: crc->clk); |
367 | return ret; |
368 | } |
369 | } |
370 | refcnt++; |
371 | mutex_unlock(lock: &refcnt_lock); |
372 | |
373 | dev_info(dev, "Initialized\n" ); |
374 | |
375 | pm_runtime_put_sync(dev); |
376 | |
377 | return 0; |
378 | } |
379 | |
380 | static void stm32_crc_remove(struct platform_device *pdev) |
381 | { |
382 | struct stm32_crc *crc = platform_get_drvdata(pdev); |
383 | int ret = pm_runtime_get_sync(dev: crc->dev); |
384 | |
385 | spin_lock(lock: &crc_list.lock); |
386 | list_del(entry: &crc->list); |
387 | spin_unlock(lock: &crc_list.lock); |
388 | |
389 | mutex_lock(&refcnt_lock); |
390 | if (!--refcnt) |
391 | crypto_unregister_shashes(algs, ARRAY_SIZE(algs)); |
392 | mutex_unlock(lock: &refcnt_lock); |
393 | |
394 | pm_runtime_disable(dev: crc->dev); |
395 | pm_runtime_put_noidle(dev: crc->dev); |
396 | |
397 | if (ret >= 0) |
398 | clk_disable(clk: crc->clk); |
399 | clk_unprepare(clk: crc->clk); |
400 | } |
401 | |
402 | static int __maybe_unused stm32_crc_suspend(struct device *dev) |
403 | { |
404 | struct stm32_crc *crc = dev_get_drvdata(dev); |
405 | int ret; |
406 | |
407 | ret = pm_runtime_force_suspend(dev); |
408 | if (ret) |
409 | return ret; |
410 | |
411 | clk_unprepare(clk: crc->clk); |
412 | |
413 | return 0; |
414 | } |
415 | |
416 | static int __maybe_unused stm32_crc_resume(struct device *dev) |
417 | { |
418 | struct stm32_crc *crc = dev_get_drvdata(dev); |
419 | int ret; |
420 | |
421 | ret = clk_prepare(clk: crc->clk); |
422 | if (ret) { |
423 | dev_err(crc->dev, "Failed to prepare clock\n" ); |
424 | return ret; |
425 | } |
426 | |
427 | return pm_runtime_force_resume(dev); |
428 | } |
429 | |
430 | static int __maybe_unused stm32_crc_runtime_suspend(struct device *dev) |
431 | { |
432 | struct stm32_crc *crc = dev_get_drvdata(dev); |
433 | |
434 | clk_disable(clk: crc->clk); |
435 | |
436 | return 0; |
437 | } |
438 | |
439 | static int __maybe_unused stm32_crc_runtime_resume(struct device *dev) |
440 | { |
441 | struct stm32_crc *crc = dev_get_drvdata(dev); |
442 | int ret; |
443 | |
444 | ret = clk_enable(clk: crc->clk); |
445 | if (ret) { |
446 | dev_err(crc->dev, "Failed to enable clock\n" ); |
447 | return ret; |
448 | } |
449 | |
450 | return 0; |
451 | } |
452 | |
453 | static const struct dev_pm_ops stm32_crc_pm_ops = { |
454 | SET_SYSTEM_SLEEP_PM_OPS(stm32_crc_suspend, |
455 | stm32_crc_resume) |
456 | SET_RUNTIME_PM_OPS(stm32_crc_runtime_suspend, |
457 | stm32_crc_runtime_resume, NULL) |
458 | }; |
459 | |
460 | static const struct of_device_id stm32_dt_ids[] = { |
461 | { .compatible = "st,stm32f7-crc" , }, |
462 | {}, |
463 | }; |
464 | MODULE_DEVICE_TABLE(of, stm32_dt_ids); |
465 | |
466 | static struct platform_driver stm32_crc_driver = { |
467 | .probe = stm32_crc_probe, |
468 | .remove_new = stm32_crc_remove, |
469 | .driver = { |
470 | .name = DRIVER_NAME, |
471 | .pm = &stm32_crc_pm_ops, |
472 | .of_match_table = stm32_dt_ids, |
473 | }, |
474 | }; |
475 | |
476 | module_platform_driver(stm32_crc_driver); |
477 | |
478 | MODULE_AUTHOR("Fabien Dessenne <fabien.dessenne@st.com>" ); |
479 | MODULE_DESCRIPTION("STMicrolectronics STM32 CRC32 hardware driver" ); |
480 | MODULE_LICENSE("GPL" ); |
481 | |