aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/crypto/Kconfig2
-rw-r--r--drivers/crypto/Makefile1
-rw-r--r--drivers/crypto/stm32/Kconfig7
-rw-r--r--drivers/crypto/stm32/Makefile2
-rw-r--r--drivers/crypto/stm32/stm32_crc32.c324
5 files changed, 336 insertions, 0 deletions
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 1a60626937e4..3cd234052775 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -626,4 +626,6 @@ config CRYPTO_DEV_BCM_SPU
626 Secure Processing Unit (SPU). The SPU driver registers ablkcipher, 626 Secure Processing Unit (SPU). The SPU driver registers ablkcipher,
627 ahash, and aead algorithms with the kernel cryptographic API. 627 ahash, and aead algorithms with the kernel cryptographic API.
628 628
629source "drivers/crypto/stm32/Kconfig"
630
629endif # CRYPTO_HW 631endif # CRYPTO_HW
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index 41ca339e89d3..ea26c8dd5e14 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -31,6 +31,7 @@ obj-$(CONFIG_CRYPTO_DEV_QCE) += qce/
31obj-$(CONFIG_CRYPTO_DEV_ROCKCHIP) += rockchip/ 31obj-$(CONFIG_CRYPTO_DEV_ROCKCHIP) += rockchip/
32obj-$(CONFIG_CRYPTO_DEV_S5P) += s5p-sss.o 32obj-$(CONFIG_CRYPTO_DEV_S5P) += s5p-sss.o
33obj-$(CONFIG_CRYPTO_DEV_SAHARA) += sahara.o 33obj-$(CONFIG_CRYPTO_DEV_SAHARA) += sahara.o
34obj-$(CONFIG_CRYPTO_DEV_STM32) += stm32/
34obj-$(CONFIG_CRYPTO_DEV_SUN4I_SS) += sunxi-ss/ 35obj-$(CONFIG_CRYPTO_DEV_SUN4I_SS) += sunxi-ss/
35obj-$(CONFIG_CRYPTO_DEV_TALITOS) += talitos.o 36obj-$(CONFIG_CRYPTO_DEV_TALITOS) += talitos.o
36obj-$(CONFIG_CRYPTO_DEV_UX500) += ux500/ 37obj-$(CONFIG_CRYPTO_DEV_UX500) += ux500/
diff --git a/drivers/crypto/stm32/Kconfig b/drivers/crypto/stm32/Kconfig
new file mode 100644
index 000000000000..09b4ec87c212
--- /dev/null
+++ b/drivers/crypto/stm32/Kconfig
@@ -0,0 +1,7 @@
1config CRYPTO_DEV_STM32
2 tristate "Support for STM32 crypto accelerators"
3 depends on ARCH_STM32
4 select CRYPTO_HASH
5 help
6 This enables support for the CRC32 hw accelerator which can be found
7 on STMicroelectronis STM32 SOC.
diff --git a/drivers/crypto/stm32/Makefile b/drivers/crypto/stm32/Makefile
new file mode 100644
index 000000000000..73b4c6e47f5f
--- /dev/null
+++ b/drivers/crypto/stm32/Makefile
@@ -0,0 +1,2 @@
1obj-$(CONFIG_CRYPTO_DEV_STM32) += stm32_cryp.o
2stm32_cryp-objs := stm32_crc32.o
diff --git a/drivers/crypto/stm32/stm32_crc32.c b/drivers/crypto/stm32/stm32_crc32.c
new file mode 100644
index 000000000000..765282262d44
--- /dev/null
+++ b/drivers/crypto/stm32/stm32_crc32.c
@@ -0,0 +1,324 @@
1/*
2 * Copyright (C) STMicroelectronics SA 2017
3 * Author: Fabien Dessenne <fabien.dessenne@st.com>
4 * License terms: GNU General Public License (GPL), version 2
5 */
6
7#include <linux/bitrev.h>
8#include <linux/clk.h>
9#include <linux/module.h>
10#include <linux/platform_device.h>
11
12#include <crypto/internal/hash.h>
13
14#include <asm/unaligned.h>
15
16#define DRIVER_NAME "stm32-crc32"
17#define CHKSUM_DIGEST_SIZE 4
18#define CHKSUM_BLOCK_SIZE 1
19
20/* Registers */
21#define CRC_DR 0x00000000
22#define CRC_CR 0x00000008
23#define CRC_INIT 0x00000010
24#define CRC_POL 0x00000014
25
26/* Registers values */
27#define CRC_CR_RESET BIT(0)
28#define CRC_CR_REVERSE (BIT(7) | BIT(6) | BIT(5))
29#define CRC_INIT_DEFAULT 0xFFFFFFFF
30
31/* Polynomial reversed */
32#define POLY_CRC32 0xEDB88320
33#define POLY_CRC32C 0x82F63B78
34
35struct stm32_crc {
36 struct list_head list;
37 struct device *dev;
38 void __iomem *regs;
39 struct clk *clk;
40 u8 pending_data[sizeof(u32)];
41 size_t nb_pending_bytes;
42};
43
44struct stm32_crc_list {
45 struct list_head dev_list;
46 spinlock_t lock; /* protect dev_list */
47};
48
49static struct stm32_crc_list crc_list = {
50 .dev_list = LIST_HEAD_INIT(crc_list.dev_list),
51 .lock = __SPIN_LOCK_UNLOCKED(crc_list.lock),
52};
53
54struct stm32_crc_ctx {
55 u32 key;
56 u32 poly;
57};
58
59struct stm32_crc_desc_ctx {
60 u32 partial; /* crc32c: partial in first 4 bytes of that struct */
61 struct stm32_crc *crc;
62};
63
64static int stm32_crc32_cra_init(struct crypto_tfm *tfm)
65{
66 struct stm32_crc_ctx *mctx = crypto_tfm_ctx(tfm);
67
68 mctx->key = CRC_INIT_DEFAULT;
69 mctx->poly = POLY_CRC32;
70 return 0;
71}
72
73static int stm32_crc32c_cra_init(struct crypto_tfm *tfm)
74{
75 struct stm32_crc_ctx *mctx = crypto_tfm_ctx(tfm);
76
77 mctx->key = CRC_INIT_DEFAULT;
78 mctx->poly = POLY_CRC32C;
79 return 0;
80}
81
82static int stm32_crc_setkey(struct crypto_shash *tfm, const u8 *key,
83 unsigned int keylen)
84{
85 struct stm32_crc_ctx *mctx = crypto_shash_ctx(tfm);
86
87 if (keylen != sizeof(u32)) {
88 crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
89 return -EINVAL;
90 }
91
92 mctx->key = get_unaligned_le32(key);
93 return 0;
94}
95
96static int stm32_crc_init(struct shash_desc *desc)
97{
98 struct stm32_crc_desc_ctx *ctx = shash_desc_ctx(desc);
99 struct stm32_crc_ctx *mctx = crypto_shash_ctx(desc->tfm);
100 struct stm32_crc *crc;
101
102 spin_lock_bh(&crc_list.lock);
103 list_for_each_entry(crc, &crc_list.dev_list, list) {
104 ctx->crc = crc;
105 break;
106 }
107 spin_unlock_bh(&crc_list.lock);
108
109 /* Reset, set key, poly and configure in bit reverse mode */
110 writel(bitrev32(mctx->key), ctx->crc->regs + CRC_INIT);
111 writel(bitrev32(mctx->poly), ctx->crc->regs + CRC_POL);
112 writel(CRC_CR_RESET | CRC_CR_REVERSE, ctx->crc->regs + CRC_CR);
113
114 /* Store partial result */
115 ctx->partial = readl(ctx->crc->regs + CRC_DR);
116 ctx->crc->nb_pending_bytes = 0;
117
118 return 0;
119}
120
121static int stm32_crc_update(struct shash_desc *desc, const u8 *d8,
122 unsigned int length)
123{
124 struct stm32_crc_desc_ctx *ctx = shash_desc_ctx(desc);
125 struct stm32_crc *crc = ctx->crc;
126 u32 *d32;
127 unsigned int i;
128
129 if (unlikely(crc->nb_pending_bytes)) {
130 while (crc->nb_pending_bytes != sizeof(u32) && length) {
131 /* Fill in pending data */
132 crc->pending_data[crc->nb_pending_bytes++] = *(d8++);
133 length--;
134 }
135
136 if (crc->nb_pending_bytes == sizeof(u32)) {
137 /* Process completed pending data */
138 writel(*(u32 *)crc->pending_data, crc->regs + CRC_DR);
139 crc->nb_pending_bytes = 0;
140 }
141 }
142
143 d32 = (u32 *)d8;
144 for (i = 0; i < length >> 2; i++)
145 /* Process 32 bits data */
146 writel(*(d32++), crc->regs + CRC_DR);
147
148 /* Store partial result */
149 ctx->partial = readl(crc->regs + CRC_DR);
150
151 /* Check for pending data (non 32 bits) */
152 length &= 3;
153 if (likely(!length))
154 return 0;
155
156 if ((crc->nb_pending_bytes + length) >= sizeof(u32)) {
157 /* Shall not happen */
158 dev_err(crc->dev, "Pending data overflow\n");
159 return -EINVAL;
160 }
161
162 d8 = (const u8 *)d32;
163 for (i = 0; i < length; i++)
164 /* Store pending data */
165 crc->pending_data[crc->nb_pending_bytes++] = *(d8++);
166
167 return 0;
168}
169
170static int stm32_crc_final(struct shash_desc *desc, u8 *out)
171{
172 struct stm32_crc_desc_ctx *ctx = shash_desc_ctx(desc);
173 struct stm32_crc_ctx *mctx = crypto_shash_ctx(desc->tfm);
174
175 /* Send computed CRC */
176 put_unaligned_le32(mctx->poly == POLY_CRC32C ?
177 ~ctx->partial : ctx->partial, out);
178
179 return 0;
180}
181
182static int stm32_crc_finup(struct shash_desc *desc, const u8 *data,
183 unsigned int length, u8 *out)
184{
185 return stm32_crc_update(desc, data, length) ?:
186 stm32_crc_final(desc, out);
187}
188
189static int stm32_crc_digest(struct shash_desc *desc, const u8 *data,
190 unsigned int length, u8 *out)
191{
192 return stm32_crc_init(desc) ?: stm32_crc_finup(desc, data, length, out);
193}
194
195static struct shash_alg algs[] = {
196 /* CRC-32 */
197 {
198 .setkey = stm32_crc_setkey,
199 .init = stm32_crc_init,
200 .update = stm32_crc_update,
201 .final = stm32_crc_final,
202 .finup = stm32_crc_finup,
203 .digest = stm32_crc_digest,
204 .descsize = sizeof(struct stm32_crc_desc_ctx),
205 .digestsize = CHKSUM_DIGEST_SIZE,
206 .base = {
207 .cra_name = "crc32",
208 .cra_driver_name = DRIVER_NAME,
209 .cra_priority = 200,
210 .cra_blocksize = CHKSUM_BLOCK_SIZE,
211 .cra_alignmask = 3,
212 .cra_ctxsize = sizeof(struct stm32_crc_ctx),
213 .cra_module = THIS_MODULE,
214 .cra_init = stm32_crc32_cra_init,
215 }
216 },
217 /* CRC-32Castagnoli */
218 {
219 .setkey = stm32_crc_setkey,
220 .init = stm32_crc_init,
221 .update = stm32_crc_update,
222 .final = stm32_crc_final,
223 .finup = stm32_crc_finup,
224 .digest = stm32_crc_digest,
225 .descsize = sizeof(struct stm32_crc_desc_ctx),
226 .digestsize = CHKSUM_DIGEST_SIZE,
227 .base = {
228 .cra_name = "crc32c",
229 .cra_driver_name = DRIVER_NAME,
230 .cra_priority = 200,
231 .cra_blocksize = CHKSUM_BLOCK_SIZE,
232 .cra_alignmask = 3,
233 .cra_ctxsize = sizeof(struct stm32_crc_ctx),
234 .cra_module = THIS_MODULE,
235 .cra_init = stm32_crc32c_cra_init,
236 }
237 }
238};
239
240static int stm32_crc_probe(struct platform_device *pdev)
241{
242 struct device *dev = &pdev->dev;
243 struct stm32_crc *crc;
244 struct resource *res;
245 int ret;
246
247 crc = devm_kzalloc(dev, sizeof(*crc), GFP_KERNEL);
248 if (!crc)
249 return -ENOMEM;
250
251 crc->dev = dev;
252
253 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
254 crc->regs = devm_ioremap_resource(dev, res);
255 if (IS_ERR(crc->regs)) {
256 dev_err(dev, "Cannot map CRC IO\n");
257 return PTR_ERR(crc->regs);
258 }
259
260 crc->clk = devm_clk_get(dev, NULL);
261 if (IS_ERR(crc->clk)) {
262 dev_err(dev, "Could not get clock\n");
263 return PTR_ERR(crc->clk);
264 }
265
266 ret = clk_prepare_enable(crc->clk);
267 if (ret) {
268 dev_err(crc->dev, "Failed to enable clock\n");
269 return ret;
270 }
271
272 platform_set_drvdata(pdev, crc);
273
274 spin_lock(&crc_list.lock);
275 list_add(&crc->list, &crc_list.dev_list);
276 spin_unlock(&crc_list.lock);
277
278 ret = crypto_register_shashes(algs, ARRAY_SIZE(algs));
279 if (ret) {
280 dev_err(dev, "Failed to register\n");
281 clk_disable_unprepare(crc->clk);
282 return ret;
283 }
284
285 dev_info(dev, "Initialized\n");
286
287 return 0;
288}
289
290static int stm32_crc_remove(struct platform_device *pdev)
291{
292 struct stm32_crc *crc = platform_get_drvdata(pdev);
293
294 spin_lock(&crc_list.lock);
295 list_del(&crc->list);
296 spin_unlock(&crc_list.lock);
297
298 crypto_unregister_shash(algs);
299
300 clk_disable_unprepare(crc->clk);
301
302 return 0;
303}
304
305static const struct of_device_id stm32_dt_ids[] = {
306 { .compatible = "st,stm32f7-crc", },
307 {},
308};
309MODULE_DEVICE_TABLE(of, sti_dt_ids);
310
311static struct platform_driver stm32_crc_driver = {
312 .probe = stm32_crc_probe,
313 .remove = stm32_crc_remove,
314 .driver = {
315 .name = DRIVER_NAME,
316 .of_match_table = stm32_dt_ids,
317 },
318};
319
320module_platform_driver(stm32_crc_driver);
321
322MODULE_AUTHOR("Fabien Dessenne <fabien.dessenne@st.com>");
323MODULE_DESCRIPTION("STMicrolectronics STM32 CRC32 hardware driver");
324MODULE_LICENSE("GPL");