aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/crypto
diff options
context:
space:
mode:
authorVladimir Zapolskiy <vzapolskiy@gmail.com>2011-04-08 08:40:51 -0400
committerHerbert Xu <herbert@gondor.apana.org.au>2011-04-08 08:40:51 -0400
commita49e490c7a8a5c6c9474b1936ad8048f3e4440fc (patch)
tree5d55ab67cf6f412a4b060133c980fff887f3304b /drivers/crypto
parentb3b7f0550f84e06ae60df0a13c2992792fbd1af9 (diff)
crypto: s5p-sss - add S5PV210 advanced crypto engine support
This change adds support for AES encrypting and decrypting using advanced crypto engine found on Samsung S5PV210 and S5PC110 SoCs. Signed-off-by: Vladimir Zapolskiy <vzapolskiy@gmail.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'drivers/crypto')
-rw-r--r--drivers/crypto/Kconfig11
-rw-r--r--drivers/crypto/Makefile1
-rw-r--r--drivers/crypto/s5p-sss.c701
3 files changed, 713 insertions, 0 deletions
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index a27224aa883e..7957acbf76a2 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -271,4 +271,15 @@ config CRYPTO_DEV_PICOXCELL
271 271
272 Saying m here will build a module named pipcoxcell_crypto. 272 Saying m here will build a module named pipcoxcell_crypto.
273 273
274config CRYPTO_DEV_S5P
275 tristate "Support for Samsung S5PV210 crypto accelerator"
276 depends on ARCH_S5PV210
277 select CRYPTO_AES
278 select CRYPTO_ALGAPI
279 select CRYPTO_BLKCIPHER
280 help
281 This option allows you to have support for S5P crypto acceleration.
282 Select this to offload Samsung S5PV210 or S5PC110 from AES
283 algorithms execution.
284
274endif # CRYPTO_HW 285endif # CRYPTO_HW
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index 663c5efec13b..53ea50155319 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -12,3 +12,4 @@ obj-$(CONFIG_CRYPTO_DEV_PPC4XX) += amcc/
12obj-$(CONFIG_CRYPTO_DEV_OMAP_SHAM) += omap-sham.o 12obj-$(CONFIG_CRYPTO_DEV_OMAP_SHAM) += omap-sham.o
13obj-$(CONFIG_CRYPTO_DEV_OMAP_AES) += omap-aes.o 13obj-$(CONFIG_CRYPTO_DEV_OMAP_AES) += omap-aes.o
14obj-$(CONFIG_CRYPTO_DEV_PICOXCELL) += picoxcell_crypto.o 14obj-$(CONFIG_CRYPTO_DEV_PICOXCELL) += picoxcell_crypto.o
15obj-$(CONFIG_CRYPTO_DEV_S5P) += s5p-sss.o
diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c
new file mode 100644
index 000000000000..8115417a1c93
--- /dev/null
+++ b/drivers/crypto/s5p-sss.c
@@ -0,0 +1,701 @@
1/*
2 * Cryptographic API.
3 *
4 * Support for Samsung S5PV210 HW acceleration.
5 *
6 * Copyright (C) 2011 NetUP Inc. All rights reserved.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as published
10 * by the Free Software Foundation.
11 *
12 */
13
14#include <linux/delay.h>
15#include <linux/err.h>
16#include <linux/module.h>
17#include <linux/init.h>
18#include <linux/errno.h>
19#include <linux/kernel.h>
20#include <linux/clk.h>
21#include <linux/platform_device.h>
22#include <linux/scatterlist.h>
23#include <linux/dma-mapping.h>
24#include <linux/io.h>
25#include <linux/crypto.h>
26#include <linux/interrupt.h>
27
28#include <crypto/algapi.h>
29#include <crypto/aes.h>
30#include <crypto/ctr.h>
31
32#include <plat/cpu.h>
33#include <plat/dma.h>
34
35#define _SBF(s, v) ((v) << (s))
36#define _BIT(b) _SBF(b, 1)
37
38/* Feed control registers */
39#define SSS_REG_FCINTSTAT 0x0000
40#define SSS_FCINTSTAT_BRDMAINT _BIT(3)
41#define SSS_FCINTSTAT_BTDMAINT _BIT(2)
42#define SSS_FCINTSTAT_HRDMAINT _BIT(1)
43#define SSS_FCINTSTAT_PKDMAINT _BIT(0)
44
45#define SSS_REG_FCINTENSET 0x0004
46#define SSS_FCINTENSET_BRDMAINTENSET _BIT(3)
47#define SSS_FCINTENSET_BTDMAINTENSET _BIT(2)
48#define SSS_FCINTENSET_HRDMAINTENSET _BIT(1)
49#define SSS_FCINTENSET_PKDMAINTENSET _BIT(0)
50
51#define SSS_REG_FCINTENCLR 0x0008
52#define SSS_FCINTENCLR_BRDMAINTENCLR _BIT(3)
53#define SSS_FCINTENCLR_BTDMAINTENCLR _BIT(2)
54#define SSS_FCINTENCLR_HRDMAINTENCLR _BIT(1)
55#define SSS_FCINTENCLR_PKDMAINTENCLR _BIT(0)
56
57#define SSS_REG_FCINTPEND 0x000C
58#define SSS_FCINTPEND_BRDMAINTP _BIT(3)
59#define SSS_FCINTPEND_BTDMAINTP _BIT(2)
60#define SSS_FCINTPEND_HRDMAINTP _BIT(1)
61#define SSS_FCINTPEND_PKDMAINTP _BIT(0)
62
63#define SSS_REG_FCFIFOSTAT 0x0010
64#define SSS_FCFIFOSTAT_BRFIFOFUL _BIT(7)
65#define SSS_FCFIFOSTAT_BRFIFOEMP _BIT(6)
66#define SSS_FCFIFOSTAT_BTFIFOFUL _BIT(5)
67#define SSS_FCFIFOSTAT_BTFIFOEMP _BIT(4)
68#define SSS_FCFIFOSTAT_HRFIFOFUL _BIT(3)
69#define SSS_FCFIFOSTAT_HRFIFOEMP _BIT(2)
70#define SSS_FCFIFOSTAT_PKFIFOFUL _BIT(1)
71#define SSS_FCFIFOSTAT_PKFIFOEMP _BIT(0)
72
73#define SSS_REG_FCFIFOCTRL 0x0014
74#define SSS_FCFIFOCTRL_DESSEL _BIT(2)
75#define SSS_HASHIN_INDEPENDENT _SBF(0, 0x00)
76#define SSS_HASHIN_CIPHER_INPUT _SBF(0, 0x01)
77#define SSS_HASHIN_CIPHER_OUTPUT _SBF(0, 0x02)
78
79#define SSS_REG_FCBRDMAS 0x0020
80#define SSS_REG_FCBRDMAL 0x0024
81#define SSS_REG_FCBRDMAC 0x0028
82#define SSS_FCBRDMAC_BYTESWAP _BIT(1)
83#define SSS_FCBRDMAC_FLUSH _BIT(0)
84
85#define SSS_REG_FCBTDMAS 0x0030
86#define SSS_REG_FCBTDMAL 0x0034
87#define SSS_REG_FCBTDMAC 0x0038
88#define SSS_FCBTDMAC_BYTESWAP _BIT(1)
89#define SSS_FCBTDMAC_FLUSH _BIT(0)
90
91#define SSS_REG_FCHRDMAS 0x0040
92#define SSS_REG_FCHRDMAL 0x0044
93#define SSS_REG_FCHRDMAC 0x0048
94#define SSS_FCHRDMAC_BYTESWAP _BIT(1)
95#define SSS_FCHRDMAC_FLUSH _BIT(0)
96
97#define SSS_REG_FCPKDMAS 0x0050
98#define SSS_REG_FCPKDMAL 0x0054
99#define SSS_REG_FCPKDMAC 0x0058
100#define SSS_FCPKDMAC_BYTESWAP _BIT(3)
101#define SSS_FCPKDMAC_DESCEND _BIT(2)
102#define SSS_FCPKDMAC_TRANSMIT _BIT(1)
103#define SSS_FCPKDMAC_FLUSH _BIT(0)
104
105#define SSS_REG_FCPKDMAO 0x005C
106
107/* AES registers */
108#define SSS_REG_AES_CONTROL 0x4000
109#define SSS_AES_BYTESWAP_DI _BIT(11)
110#define SSS_AES_BYTESWAP_DO _BIT(10)
111#define SSS_AES_BYTESWAP_IV _BIT(9)
112#define SSS_AES_BYTESWAP_CNT _BIT(8)
113#define SSS_AES_BYTESWAP_KEY _BIT(7)
114#define SSS_AES_KEY_CHANGE_MODE _BIT(6)
115#define SSS_AES_KEY_SIZE_128 _SBF(4, 0x00)
116#define SSS_AES_KEY_SIZE_192 _SBF(4, 0x01)
117#define SSS_AES_KEY_SIZE_256 _SBF(4, 0x02)
118#define SSS_AES_FIFO_MODE _BIT(3)
119#define SSS_AES_CHAIN_MODE_ECB _SBF(1, 0x00)
120#define SSS_AES_CHAIN_MODE_CBC _SBF(1, 0x01)
121#define SSS_AES_CHAIN_MODE_CTR _SBF(1, 0x02)
122#define SSS_AES_MODE_DECRYPT _BIT(0)
123
124#define SSS_REG_AES_STATUS 0x4004
125#define SSS_AES_BUSY _BIT(2)
126#define SSS_AES_INPUT_READY _BIT(1)
127#define SSS_AES_OUTPUT_READY _BIT(0)
128
129#define SSS_REG_AES_IN_DATA(s) (0x4010 + (s << 2))
130#define SSS_REG_AES_OUT_DATA(s) (0x4020 + (s << 2))
131#define SSS_REG_AES_IV_DATA(s) (0x4030 + (s << 2))
132#define SSS_REG_AES_CNT_DATA(s) (0x4040 + (s << 2))
133#define SSS_REG_AES_KEY_DATA(s) (0x4080 + (s << 2))
134
135#define SSS_REG(dev, reg) ((dev)->ioaddr + (SSS_REG_##reg))
136#define SSS_READ(dev, reg) __raw_readl(SSS_REG(dev, reg))
137#define SSS_WRITE(dev, reg, val) __raw_writel((val), SSS_REG(dev, reg))
138
139/* HW engine modes */
140#define FLAGS_AES_DECRYPT _BIT(0)
141#define FLAGS_AES_MODE_MASK _SBF(1, 0x03)
142#define FLAGS_AES_CBC _SBF(1, 0x01)
143#define FLAGS_AES_CTR _SBF(1, 0x02)
144
145#define AES_KEY_LEN 16
146#define CRYPTO_QUEUE_LEN 1
147
148struct s5p_aes_reqctx {
149 unsigned long mode;
150};
151
152struct s5p_aes_ctx {
153 struct s5p_aes_dev *dev;
154
155 uint8_t aes_key[AES_MAX_KEY_SIZE];
156 uint8_t nonce[CTR_RFC3686_NONCE_SIZE];
157 int keylen;
158};
159
160struct s5p_aes_dev {
161 struct device *dev;
162 struct clk *clk;
163 void __iomem *ioaddr;
164 int irq_hash;
165 int irq_fc;
166
167 struct ablkcipher_request *req;
168 struct s5p_aes_ctx *ctx;
169 struct scatterlist *sg_src;
170 struct scatterlist *sg_dst;
171
172 struct tasklet_struct tasklet;
173 struct crypto_queue queue;
174 bool busy;
175 spinlock_t lock;
176};
177
178static struct s5p_aes_dev *s5p_dev;
179
180static void s5p_set_dma_indata(struct s5p_aes_dev *dev, struct scatterlist *sg)
181{
182 SSS_WRITE(dev, FCBRDMAS, sg_dma_address(sg));
183 SSS_WRITE(dev, FCBRDMAL, sg_dma_len(sg));
184}
185
186static void s5p_set_dma_outdata(struct s5p_aes_dev *dev, struct scatterlist *sg)
187{
188 SSS_WRITE(dev, FCBTDMAS, sg_dma_address(sg));
189 SSS_WRITE(dev, FCBTDMAL, sg_dma_len(sg));
190}
191
192static void s5p_aes_complete(struct s5p_aes_dev *dev, int err)
193{
194 /* holding a lock outside */
195 dev->req->base.complete(&dev->req->base, err);
196 dev->busy = false;
197}
198
199static void s5p_unset_outdata(struct s5p_aes_dev *dev)
200{
201 dma_unmap_sg(dev->dev, dev->sg_dst, 1, DMA_FROM_DEVICE);
202}
203
204static void s5p_unset_indata(struct s5p_aes_dev *dev)
205{
206 dma_unmap_sg(dev->dev, dev->sg_src, 1, DMA_TO_DEVICE);
207}
208
209static int s5p_set_outdata(struct s5p_aes_dev *dev, struct scatterlist *sg)
210{
211 int err;
212
213 if (!IS_ALIGNED(sg_dma_len(sg), AES_BLOCK_SIZE)) {
214 err = -EINVAL;
215 goto exit;
216 }
217 if (!sg_dma_len(sg)) {
218 err = -EINVAL;
219 goto exit;
220 }
221
222 err = dma_map_sg(dev->dev, sg, 1, DMA_FROM_DEVICE);
223 if (!err) {
224 err = -ENOMEM;
225 goto exit;
226 }
227
228 dev->sg_dst = sg;
229 err = 0;
230
231 exit:
232 return err;
233}
234
235static int s5p_set_indata(struct s5p_aes_dev *dev, struct scatterlist *sg)
236{
237 int err;
238
239 if (!IS_ALIGNED(sg_dma_len(sg), AES_BLOCK_SIZE)) {
240 err = -EINVAL;
241 goto exit;
242 }
243 if (!sg_dma_len(sg)) {
244 err = -EINVAL;
245 goto exit;
246 }
247
248 err = dma_map_sg(dev->dev, sg, 1, DMA_TO_DEVICE);
249 if (!err) {
250 err = -ENOMEM;
251 goto exit;
252 }
253
254 dev->sg_src = sg;
255 err = 0;
256
257 exit:
258 return err;
259}
260
261static void s5p_aes_tx(struct s5p_aes_dev *dev)
262{
263 int err = 0;
264
265 s5p_unset_outdata(dev);
266
267 if (!sg_is_last(dev->sg_dst)) {
268 err = s5p_set_outdata(dev, sg_next(dev->sg_dst));
269 if (err) {
270 s5p_aes_complete(dev, err);
271 return;
272 }
273
274 s5p_set_dma_outdata(dev, dev->sg_dst);
275 } else
276 s5p_aes_complete(dev, err);
277}
278
279static void s5p_aes_rx(struct s5p_aes_dev *dev)
280{
281 int err;
282
283 s5p_unset_indata(dev);
284
285 if (!sg_is_last(dev->sg_src)) {
286 err = s5p_set_indata(dev, sg_next(dev->sg_src));
287 if (err) {
288 s5p_aes_complete(dev, err);
289 return;
290 }
291
292 s5p_set_dma_indata(dev, dev->sg_src);
293 }
294}
295
296static irqreturn_t s5p_aes_interrupt(int irq, void *dev_id)
297{
298 struct platform_device *pdev = dev_id;
299 struct s5p_aes_dev *dev = platform_get_drvdata(pdev);
300 uint32_t status;
301 unsigned long flags;
302
303 spin_lock_irqsave(&dev->lock, flags);
304
305 if (irq == dev->irq_fc) {
306 status = SSS_READ(dev, FCINTSTAT);
307 if (status & SSS_FCINTSTAT_BRDMAINT)
308 s5p_aes_rx(dev);
309 if (status & SSS_FCINTSTAT_BTDMAINT)
310 s5p_aes_tx(dev);
311
312 SSS_WRITE(dev, FCINTPEND, status);
313 }
314
315 spin_unlock_irqrestore(&dev->lock, flags);
316
317 return IRQ_HANDLED;
318}
319
320static void s5p_set_aes(struct s5p_aes_dev *dev,
321 uint8_t *key, uint8_t *iv, unsigned int keylen)
322{
323 void __iomem *keystart;
324
325 memcpy(dev->ioaddr + SSS_REG_AES_IV_DATA(0), iv, 0x10);
326
327 if (keylen == AES_KEYSIZE_256)
328 keystart = dev->ioaddr + SSS_REG_AES_KEY_DATA(0);
329 else if (keylen == AES_KEYSIZE_192)
330 keystart = dev->ioaddr + SSS_REG_AES_KEY_DATA(2);
331 else
332 keystart = dev->ioaddr + SSS_REG_AES_KEY_DATA(4);
333
334 memcpy(keystart, key, keylen);
335}
336
337static void s5p_aes_crypt_start(struct s5p_aes_dev *dev, unsigned long mode)
338{
339 struct ablkcipher_request *req = dev->req;
340
341 uint32_t aes_control;
342 int err;
343 unsigned long flags;
344
345 aes_control = SSS_AES_KEY_CHANGE_MODE;
346 if (mode & FLAGS_AES_DECRYPT)
347 aes_control |= SSS_AES_MODE_DECRYPT;
348
349 if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CBC)
350 aes_control |= SSS_AES_CHAIN_MODE_CBC;
351 else if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CTR)
352 aes_control |= SSS_AES_CHAIN_MODE_CTR;
353
354 if (dev->ctx->keylen == AES_KEYSIZE_192)
355 aes_control |= SSS_AES_KEY_SIZE_192;
356 else if (dev->ctx->keylen == AES_KEYSIZE_256)
357 aes_control |= SSS_AES_KEY_SIZE_256;
358
359 aes_control |= SSS_AES_FIFO_MODE;
360
361 /* as a variant it is possible to use byte swapping on DMA side */
362 aes_control |= SSS_AES_BYTESWAP_DI
363 | SSS_AES_BYTESWAP_DO
364 | SSS_AES_BYTESWAP_IV
365 | SSS_AES_BYTESWAP_KEY
366 | SSS_AES_BYTESWAP_CNT;
367
368 spin_lock_irqsave(&dev->lock, flags);
369
370 SSS_WRITE(dev, FCINTENCLR,
371 SSS_FCINTENCLR_BTDMAINTENCLR | SSS_FCINTENCLR_BRDMAINTENCLR);
372 SSS_WRITE(dev, FCFIFOCTRL, 0x00);
373
374 err = s5p_set_indata(dev, req->src);
375 if (err)
376 goto indata_error;
377
378 err = s5p_set_outdata(dev, req->dst);
379 if (err)
380 goto outdata_error;
381
382 SSS_WRITE(dev, AES_CONTROL, aes_control);
383 s5p_set_aes(dev, dev->ctx->aes_key, req->info, dev->ctx->keylen);
384
385 s5p_set_dma_indata(dev, req->src);
386 s5p_set_dma_outdata(dev, req->dst);
387
388 SSS_WRITE(dev, FCINTENSET,
389 SSS_FCINTENSET_BTDMAINTENSET | SSS_FCINTENSET_BRDMAINTENSET);
390
391 spin_unlock_irqrestore(&dev->lock, flags);
392
393 return;
394
395 outdata_error:
396 s5p_unset_indata(dev);
397
398 indata_error:
399 s5p_aes_complete(dev, err);
400 spin_unlock_irqrestore(&dev->lock, flags);
401}
402
403static void s5p_tasklet_cb(unsigned long data)
404{
405 struct s5p_aes_dev *dev = (struct s5p_aes_dev *)data;
406 struct crypto_async_request *async_req, *backlog;
407 struct s5p_aes_reqctx *reqctx;
408 unsigned long flags;
409
410 spin_lock_irqsave(&dev->lock, flags);
411 backlog = crypto_get_backlog(&dev->queue);
412 async_req = crypto_dequeue_request(&dev->queue);
413 spin_unlock_irqrestore(&dev->lock, flags);
414
415 if (!async_req)
416 return;
417
418 if (backlog)
419 backlog->complete(backlog, -EINPROGRESS);
420
421 dev->req = ablkcipher_request_cast(async_req);
422 dev->ctx = crypto_tfm_ctx(dev->req->base.tfm);
423 reqctx = ablkcipher_request_ctx(dev->req);
424
425 s5p_aes_crypt_start(dev, reqctx->mode);
426}
427
428static int s5p_aes_handle_req(struct s5p_aes_dev *dev,
429 struct ablkcipher_request *req)
430{
431 unsigned long flags;
432 int err;
433
434 spin_lock_irqsave(&dev->lock, flags);
435 if (dev->busy) {
436 err = -EAGAIN;
437 spin_unlock_irqrestore(&dev->lock, flags);
438 goto exit;
439 }
440 dev->busy = true;
441
442 err = ablkcipher_enqueue_request(&dev->queue, req);
443 spin_unlock_irqrestore(&dev->lock, flags);
444
445 tasklet_schedule(&dev->tasklet);
446
447 exit:
448 return err;
449}
450
451static int s5p_aes_crypt(struct ablkcipher_request *req, unsigned long mode)
452{
453 struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req);
454 struct s5p_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm);
455 struct s5p_aes_reqctx *reqctx = ablkcipher_request_ctx(req);
456 struct s5p_aes_dev *dev = ctx->dev;
457
458 if (!IS_ALIGNED(req->nbytes, AES_BLOCK_SIZE)) {
459 pr_err("request size is not exact amount of AES blocks\n");
460 return -EINVAL;
461 }
462
463 reqctx->mode = mode;
464
465 return s5p_aes_handle_req(dev, req);
466}
467
468static int s5p_aes_setkey(struct crypto_ablkcipher *cipher,
469 const uint8_t *key, unsigned int keylen)
470{
471 struct crypto_tfm *tfm = crypto_ablkcipher_tfm(cipher);
472 struct s5p_aes_ctx *ctx = crypto_tfm_ctx(tfm);
473
474 if (keylen != AES_KEYSIZE_128 &&
475 keylen != AES_KEYSIZE_192 &&
476 keylen != AES_KEYSIZE_256)
477 return -EINVAL;
478
479 memcpy(ctx->aes_key, key, keylen);
480 ctx->keylen = keylen;
481
482 return 0;
483}
484
485static int s5p_aes_ecb_encrypt(struct ablkcipher_request *req)
486{
487 return s5p_aes_crypt(req, 0);
488}
489
490static int s5p_aes_ecb_decrypt(struct ablkcipher_request *req)
491{
492 return s5p_aes_crypt(req, FLAGS_AES_DECRYPT);
493}
494
495static int s5p_aes_cbc_encrypt(struct ablkcipher_request *req)
496{
497 return s5p_aes_crypt(req, FLAGS_AES_CBC);
498}
499
500static int s5p_aes_cbc_decrypt(struct ablkcipher_request *req)
501{
502 return s5p_aes_crypt(req, FLAGS_AES_DECRYPT | FLAGS_AES_CBC);
503}
504
505static int s5p_aes_cra_init(struct crypto_tfm *tfm)
506{
507 struct s5p_aes_ctx *ctx = crypto_tfm_ctx(tfm);
508
509 ctx->dev = s5p_dev;
510 tfm->crt_ablkcipher.reqsize = sizeof(struct s5p_aes_reqctx);
511
512 return 0;
513}
514
515static struct crypto_alg algs[] = {
516 {
517 .cra_name = "ecb(aes)",
518 .cra_driver_name = "ecb-aes-s5p",
519 .cra_priority = 100,
520 .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
521 CRYPTO_ALG_ASYNC,
522 .cra_blocksize = AES_BLOCK_SIZE,
523 .cra_ctxsize = sizeof(struct s5p_aes_ctx),
524 .cra_alignmask = 0x0f,
525 .cra_type = &crypto_ablkcipher_type,
526 .cra_module = THIS_MODULE,
527 .cra_init = s5p_aes_cra_init,
528 .cra_u.ablkcipher = {
529 .min_keysize = AES_MIN_KEY_SIZE,
530 .max_keysize = AES_MAX_KEY_SIZE,
531 .setkey = s5p_aes_setkey,
532 .encrypt = s5p_aes_ecb_encrypt,
533 .decrypt = s5p_aes_ecb_decrypt,
534 }
535 },
536 {
537 .cra_name = "cbc(aes)",
538 .cra_driver_name = "cbc-aes-s5p",
539 .cra_priority = 100,
540 .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
541 CRYPTO_ALG_ASYNC,
542 .cra_blocksize = AES_BLOCK_SIZE,
543 .cra_ctxsize = sizeof(struct s5p_aes_ctx),
544 .cra_alignmask = 0x0f,
545 .cra_type = &crypto_ablkcipher_type,
546 .cra_module = THIS_MODULE,
547 .cra_init = s5p_aes_cra_init,
548 .cra_u.ablkcipher = {
549 .min_keysize = AES_MIN_KEY_SIZE,
550 .max_keysize = AES_MAX_KEY_SIZE,
551 .ivsize = AES_BLOCK_SIZE,
552 .setkey = s5p_aes_setkey,
553 .encrypt = s5p_aes_cbc_encrypt,
554 .decrypt = s5p_aes_cbc_decrypt,
555 }
556 },
557};
558
559static int s5p_aes_probe(struct platform_device *pdev)
560{
561 int i, j, err = -ENODEV;
562 struct s5p_aes_dev *pdata;
563 struct device *dev = &pdev->dev;
564 struct resource *res;
565
566 if (s5p_dev)
567 return -EEXIST;
568
569 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
570 if (!res)
571 return -ENODEV;
572
573 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
574 if (!pdata)
575 return -ENOMEM;
576
577 if (!devm_request_mem_region(dev, res->start,
578 resource_size(res), pdev->name))
579 return -EBUSY;
580
581 pdata->clk = clk_get(dev, "secss");
582 if (IS_ERR(pdata->clk)) {
583 dev_err(dev, "failed to find secss clock source\n");
584 return -ENOENT;
585 }
586
587 clk_enable(pdata->clk);
588
589 spin_lock_init(&pdata->lock);
590 pdata->ioaddr = devm_ioremap(dev, res->start,
591 resource_size(res));
592
593 pdata->irq_hash = platform_get_irq_byname(pdev, "hash");
594 if (pdata->irq_hash < 0) {
595 err = pdata->irq_hash;
596 dev_warn(dev, "hash interrupt is not available.\n");
597 goto err_irq;
598 }
599 err = devm_request_irq(dev, pdata->irq_hash, s5p_aes_interrupt,
600 IRQF_SHARED, pdev->name, pdev);
601 if (err < 0) {
602 dev_warn(dev, "hash interrupt is not available.\n");
603 goto err_irq;
604 }
605
606 pdata->irq_fc = platform_get_irq_byname(pdev, "feed control");
607 if (pdata->irq_fc < 0) {
608 err = pdata->irq_fc;
609 dev_warn(dev, "feed control interrupt is not available.\n");
610 goto err_irq;
611 }
612 err = devm_request_irq(dev, pdata->irq_fc, s5p_aes_interrupt,
613 IRQF_SHARED, pdev->name, pdev);
614 if (err < 0) {
615 dev_warn(dev, "feed control interrupt is not available.\n");
616 goto err_irq;
617 }
618
619 pdata->dev = dev;
620 platform_set_drvdata(pdev, pdata);
621 s5p_dev = pdata;
622
623 tasklet_init(&pdata->tasklet, s5p_tasklet_cb, (unsigned long)pdata);
624 crypto_init_queue(&pdata->queue, CRYPTO_QUEUE_LEN);
625
626 for (i = 0; i < ARRAY_SIZE(algs); i++) {
627 INIT_LIST_HEAD(&algs[i].cra_list);
628 err = crypto_register_alg(&algs[i]);
629 if (err)
630 goto err_algs;
631 }
632
633 pr_info("s5p-sss driver registered\n");
634
635 return 0;
636
637 err_algs:
638 dev_err(dev, "can't register '%s': %d\n", algs[i].cra_name, err);
639
640 for (j = 0; j < i; j++)
641 crypto_unregister_alg(&algs[j]);
642
643 tasklet_kill(&pdata->tasklet);
644
645 err_irq:
646 clk_disable(pdata->clk);
647 clk_put(pdata->clk);
648
649 s5p_dev = NULL;
650 platform_set_drvdata(pdev, NULL);
651
652 return err;
653}
654
655static int s5p_aes_remove(struct platform_device *pdev)
656{
657 struct s5p_aes_dev *pdata = platform_get_drvdata(pdev);
658 int i;
659
660 if (!pdata)
661 return -ENODEV;
662
663 for (i = 0; i < ARRAY_SIZE(algs); i++)
664 crypto_unregister_alg(&algs[i]);
665
666 tasklet_kill(&pdata->tasklet);
667
668 clk_disable(pdata->clk);
669 clk_put(pdata->clk);
670
671 s5p_dev = NULL;
672 platform_set_drvdata(pdev, NULL);
673
674 return 0;
675}
676
677static struct platform_driver s5p_aes_crypto = {
678 .probe = s5p_aes_probe,
679 .remove = s5p_aes_remove,
680 .driver = {
681 .owner = THIS_MODULE,
682 .name = "s5p-secss",
683 },
684};
685
686static int __init s5p_aes_mod_init(void)
687{
688 return platform_driver_register(&s5p_aes_crypto);
689}
690
691static void __exit s5p_aes_mod_exit(void)
692{
693 platform_driver_unregister(&s5p_aes_crypto);
694}
695
696module_init(s5p_aes_mod_init);
697module_exit(s5p_aes_mod_exit);
698
699MODULE_DESCRIPTION("S5PV210 AES hw acceleration support.");
700MODULE_LICENSE("GPL v2");
701MODULE_AUTHOR("Vladimir Zapolskiy <vzapolskiy@gmail.com>");