diff options
author | Naveen Krishna Chatradhi <ch.naveen@samsung.com> | 2014-05-08 09:58:14 -0400 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2014-05-08 09:58:14 -0400 |
commit | 892451071de77a088a6227e36d3a2732d51c5b84 (patch) | |
tree | 27235df9e6c1cedfc564ec4f808ebab218f203a0 /drivers/crypto | |
parent | 6b9f16e6c2b712f724e6ca1538d18ea8a788dd90 (diff) |
crypto: s5p-sss - Add support for SSS module on Exynos
This patch adds new compatible and variant struct to support the SSS
module on Exynos4 (Exynos4210), Exynos5 (Exynos5420 and Exynos5250)
for which
1. AES register are at an offset of 0x200 and
2. hash interrupt is not available
Signed-off-by: Naveen Krishna Chatradhi <ch.naveen@samsung.com>
Reviewed-by: Tomasz Figa <t.figa@samsung.com>
CC: David S. Miller <davem@davemloft.net>
CC: <linux-samsung-soc@vger.kernel.org>
Acked-by: Vladimir Zapolskiy <vz@mleia.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'drivers/crypto')
-rw-r--r-- | drivers/crypto/s5p-sss.c | 107 |
1 files changed, 83 insertions, 24 deletions
diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c index c6aafe84e06a..37e0598a8cba 100644 --- a/drivers/crypto/s5p-sss.c +++ b/drivers/crypto/s5p-sss.c | |||
@@ -106,7 +106,7 @@ | |||
106 | #define SSS_REG_FCPKDMAO 0x005C | 106 | #define SSS_REG_FCPKDMAO 0x005C |
107 | 107 | ||
108 | /* AES registers */ | 108 | /* AES registers */ |
109 | #define SSS_REG_AES_CONTROL 0x4000 | 109 | #define SSS_REG_AES_CONTROL 0x00 |
110 | #define SSS_AES_BYTESWAP_DI _BIT(11) | 110 | #define SSS_AES_BYTESWAP_DI _BIT(11) |
111 | #define SSS_AES_BYTESWAP_DO _BIT(10) | 111 | #define SSS_AES_BYTESWAP_DO _BIT(10) |
112 | #define SSS_AES_BYTESWAP_IV _BIT(9) | 112 | #define SSS_AES_BYTESWAP_IV _BIT(9) |
@@ -122,21 +122,25 @@ | |||
122 | #define SSS_AES_CHAIN_MODE_CTR _SBF(1, 0x02) | 122 | #define SSS_AES_CHAIN_MODE_CTR _SBF(1, 0x02) |
123 | #define SSS_AES_MODE_DECRYPT _BIT(0) | 123 | #define SSS_AES_MODE_DECRYPT _BIT(0) |
124 | 124 | ||
125 | #define SSS_REG_AES_STATUS 0x4004 | 125 | #define SSS_REG_AES_STATUS 0x04 |
126 | #define SSS_AES_BUSY _BIT(2) | 126 | #define SSS_AES_BUSY _BIT(2) |
127 | #define SSS_AES_INPUT_READY _BIT(1) | 127 | #define SSS_AES_INPUT_READY _BIT(1) |
128 | #define SSS_AES_OUTPUT_READY _BIT(0) | 128 | #define SSS_AES_OUTPUT_READY _BIT(0) |
129 | 129 | ||
130 | #define SSS_REG_AES_IN_DATA(s) (0x4010 + (s << 2)) | 130 | #define SSS_REG_AES_IN_DATA(s) (0x10 + (s << 2)) |
131 | #define SSS_REG_AES_OUT_DATA(s) (0x4020 + (s << 2)) | 131 | #define SSS_REG_AES_OUT_DATA(s) (0x20 + (s << 2)) |
132 | #define SSS_REG_AES_IV_DATA(s) (0x4030 + (s << 2)) | 132 | #define SSS_REG_AES_IV_DATA(s) (0x30 + (s << 2)) |
133 | #define SSS_REG_AES_CNT_DATA(s) (0x4040 + (s << 2)) | 133 | #define SSS_REG_AES_CNT_DATA(s) (0x40 + (s << 2)) |
134 | #define SSS_REG_AES_KEY_DATA(s) (0x4080 + (s << 2)) | 134 | #define SSS_REG_AES_KEY_DATA(s) (0x80 + (s << 2)) |
135 | 135 | ||
136 | #define SSS_REG(dev, reg) ((dev)->ioaddr + (SSS_REG_##reg)) | 136 | #define SSS_REG(dev, reg) ((dev)->ioaddr + (SSS_REG_##reg)) |
137 | #define SSS_READ(dev, reg) __raw_readl(SSS_REG(dev, reg)) | 137 | #define SSS_READ(dev, reg) __raw_readl(SSS_REG(dev, reg)) |
138 | #define SSS_WRITE(dev, reg, val) __raw_writel((val), SSS_REG(dev, reg)) | 138 | #define SSS_WRITE(dev, reg, val) __raw_writel((val), SSS_REG(dev, reg)) |
139 | 139 | ||
140 | #define SSS_AES_REG(dev, reg) ((dev)->aes_ioaddr + SSS_REG_##reg) | ||
141 | #define SSS_AES_WRITE(dev, reg, val) __raw_writel((val), \ | ||
142 | SSS_AES_REG(dev, reg)) | ||
143 | |||
140 | /* HW engine modes */ | 144 | /* HW engine modes */ |
141 | #define FLAGS_AES_DECRYPT _BIT(0) | 145 | #define FLAGS_AES_DECRYPT _BIT(0) |
142 | #define FLAGS_AES_MODE_MASK _SBF(1, 0x03) | 146 | #define FLAGS_AES_MODE_MASK _SBF(1, 0x03) |
@@ -146,6 +150,20 @@ | |||
146 | #define AES_KEY_LEN 16 | 150 | #define AES_KEY_LEN 16 |
147 | #define CRYPTO_QUEUE_LEN 1 | 151 | #define CRYPTO_QUEUE_LEN 1 |
148 | 152 | ||
153 | /** | ||
154 | * struct samsung_aes_variant - platform specific SSS driver data | ||
155 | * @has_hash_irq: true if SSS module uses hash interrupt, false otherwise | ||
156 | * @aes_offset: AES register offset from SSS module's base. | ||
157 | * | ||
158 | * Specifies platform specific configuration of SSS module. | ||
159 | * Note: A structure for driver specific platform data is used for future | ||
160 | * expansion of its usage. | ||
161 | */ | ||
162 | struct samsung_aes_variant { | ||
163 | bool has_hash_irq; | ||
164 | unsigned int aes_offset; | ||
165 | }; | ||
166 | |||
149 | struct s5p_aes_reqctx { | 167 | struct s5p_aes_reqctx { |
150 | unsigned long mode; | 168 | unsigned long mode; |
151 | }; | 169 | }; |
@@ -162,6 +180,7 @@ struct s5p_aes_dev { | |||
162 | struct device *dev; | 180 | struct device *dev; |
163 | struct clk *clk; | 181 | struct clk *clk; |
164 | void __iomem *ioaddr; | 182 | void __iomem *ioaddr; |
183 | void __iomem *aes_ioaddr; | ||
165 | int irq_hash; | 184 | int irq_hash; |
166 | int irq_fc; | 185 | int irq_fc; |
167 | 186 | ||
@@ -174,16 +193,48 @@ struct s5p_aes_dev { | |||
174 | struct crypto_queue queue; | 193 | struct crypto_queue queue; |
175 | bool busy; | 194 | bool busy; |
176 | spinlock_t lock; | 195 | spinlock_t lock; |
196 | |||
197 | struct samsung_aes_variant *variant; | ||
177 | }; | 198 | }; |
178 | 199 | ||
179 | static struct s5p_aes_dev *s5p_dev; | 200 | static struct s5p_aes_dev *s5p_dev; |
180 | 201 | ||
202 | static const struct samsung_aes_variant s5p_aes_data = { | ||
203 | .has_hash_irq = true, | ||
204 | .aes_offset = 0x4000, | ||
205 | }; | ||
206 | |||
207 | static const struct samsung_aes_variant exynos_aes_data = { | ||
208 | .has_hash_irq = false, | ||
209 | .aes_offset = 0x200, | ||
210 | }; | ||
211 | |||
181 | static const struct of_device_id s5p_sss_dt_match[] = { | 212 | static const struct of_device_id s5p_sss_dt_match[] = { |
182 | { .compatible = "samsung,s5pv210-secss" }, | 213 | { |
214 | .compatible = "samsung,s5pv210-secss", | ||
215 | .data = &s5p_aes_data, | ||
216 | }, | ||
217 | { | ||
218 | .compatible = "samsung,exynos4210-secss", | ||
219 | .data = &exynos_aes_data, | ||
220 | }, | ||
183 | { }, | 221 | { }, |
184 | }; | 222 | }; |
185 | MODULE_DEVICE_TABLE(of, s5p_sss_dt_match); | 223 | MODULE_DEVICE_TABLE(of, s5p_sss_dt_match); |
186 | 224 | ||
225 | static inline struct samsung_aes_variant *find_s5p_sss_version | ||
226 | (struct platform_device *pdev) | ||
227 | { | ||
228 | if (IS_ENABLED(CONFIG_OF) && (pdev->dev.of_node)) { | ||
229 | const struct of_device_id *match; | ||
230 | match = of_match_node(s5p_sss_dt_match, | ||
231 | pdev->dev.of_node); | ||
232 | return (struct samsung_aes_variant *)match->data; | ||
233 | } | ||
234 | return (struct samsung_aes_variant *) | ||
235 | platform_get_device_id(pdev)->driver_data; | ||
236 | } | ||
237 | |||
187 | static void s5p_set_dma_indata(struct s5p_aes_dev *dev, struct scatterlist *sg) | 238 | static void s5p_set_dma_indata(struct s5p_aes_dev *dev, struct scatterlist *sg) |
188 | { | 239 | { |
189 | SSS_WRITE(dev, FCBRDMAS, sg_dma_address(sg)); | 240 | SSS_WRITE(dev, FCBRDMAS, sg_dma_address(sg)); |
@@ -329,14 +380,14 @@ static void s5p_set_aes(struct s5p_aes_dev *dev, | |||
329 | { | 380 | { |
330 | void __iomem *keystart; | 381 | void __iomem *keystart; |
331 | 382 | ||
332 | memcpy(dev->ioaddr + SSS_REG_AES_IV_DATA(0), iv, 0x10); | 383 | memcpy(dev->aes_ioaddr + SSS_REG_AES_IV_DATA(0), iv, 0x10); |
333 | 384 | ||
334 | if (keylen == AES_KEYSIZE_256) | 385 | if (keylen == AES_KEYSIZE_256) |
335 | keystart = dev->ioaddr + SSS_REG_AES_KEY_DATA(0); | 386 | keystart = dev->aes_ioaddr + SSS_REG_AES_KEY_DATA(0); |
336 | else if (keylen == AES_KEYSIZE_192) | 387 | else if (keylen == AES_KEYSIZE_192) |
337 | keystart = dev->ioaddr + SSS_REG_AES_KEY_DATA(2); | 388 | keystart = dev->aes_ioaddr + SSS_REG_AES_KEY_DATA(2); |
338 | else | 389 | else |
339 | keystart = dev->ioaddr + SSS_REG_AES_KEY_DATA(4); | 390 | keystart = dev->aes_ioaddr + SSS_REG_AES_KEY_DATA(4); |
340 | 391 | ||
341 | memcpy(keystart, key, keylen); | 392 | memcpy(keystart, key, keylen); |
342 | } | 393 | } |
@@ -386,7 +437,7 @@ static void s5p_aes_crypt_start(struct s5p_aes_dev *dev, unsigned long mode) | |||
386 | if (err) | 437 | if (err) |
387 | goto outdata_error; | 438 | goto outdata_error; |
388 | 439 | ||
389 | SSS_WRITE(dev, AES_CONTROL, aes_control); | 440 | SSS_AES_WRITE(dev, AES_CONTROL, aes_control); |
390 | s5p_set_aes(dev, dev->ctx->aes_key, req->info, dev->ctx->keylen); | 441 | s5p_set_aes(dev, dev->ctx->aes_key, req->info, dev->ctx->keylen); |
391 | 442 | ||
392 | s5p_set_dma_indata(dev, req->src); | 443 | s5p_set_dma_indata(dev, req->src); |
@@ -571,6 +622,7 @@ static int s5p_aes_probe(struct platform_device *pdev) | |||
571 | struct s5p_aes_dev *pdata; | 622 | struct s5p_aes_dev *pdata; |
572 | struct device *dev = &pdev->dev; | 623 | struct device *dev = &pdev->dev; |
573 | struct resource *res; | 624 | struct resource *res; |
625 | struct samsung_aes_variant *variant; | ||
574 | 626 | ||
575 | if (s5p_dev) | 627 | if (s5p_dev) |
576 | return -EEXIST; | 628 | return -EEXIST; |
@@ -584,6 +636,8 @@ static int s5p_aes_probe(struct platform_device *pdev) | |||
584 | if (IS_ERR(pdata->ioaddr)) | 636 | if (IS_ERR(pdata->ioaddr)) |
585 | return PTR_ERR(pdata->ioaddr); | 637 | return PTR_ERR(pdata->ioaddr); |
586 | 638 | ||
639 | variant = find_s5p_sss_version(pdev); | ||
640 | |||
587 | pdata->clk = devm_clk_get(dev, "secss"); | 641 | pdata->clk = devm_clk_get(dev, "secss"); |
588 | if (IS_ERR(pdata->clk)) { | 642 | if (IS_ERR(pdata->clk)) { |
589 | dev_err(dev, "failed to find secss clock source\n"); | 643 | dev_err(dev, "failed to find secss clock source\n"); |
@@ -594,6 +648,8 @@ static int s5p_aes_probe(struct platform_device *pdev) | |||
594 | 648 | ||
595 | spin_lock_init(&pdata->lock); | 649 | spin_lock_init(&pdata->lock); |
596 | 650 | ||
651 | pdata->aes_ioaddr = pdata->ioaddr + variant->aes_offset; | ||
652 | |||
597 | pdata->irq_fc = platform_get_irq(pdev, 0); | 653 | pdata->irq_fc = platform_get_irq(pdev, 0); |
598 | if (pdata->irq_fc < 0) { | 654 | if (pdata->irq_fc < 0) { |
599 | err = pdata->irq_fc; | 655 | err = pdata->irq_fc; |
@@ -607,19 +663,22 @@ static int s5p_aes_probe(struct platform_device *pdev) | |||
607 | goto err_irq; | 663 | goto err_irq; |
608 | } | 664 | } |
609 | 665 | ||
610 | pdata->irq_hash = platform_get_irq(pdev, 1); | 666 | if (variant->has_hash_irq) { |
611 | if (pdata->irq_hash < 0) { | 667 | pdata->irq_hash = platform_get_irq(pdev, 1); |
612 | err = pdata->irq_hash; | 668 | if (pdata->irq_hash < 0) { |
613 | dev_warn(dev, "hash interrupt is not available.\n"); | 669 | err = pdata->irq_hash; |
614 | goto err_irq; | 670 | dev_warn(dev, "hash interrupt is not available.\n"); |
615 | } | 671 | goto err_irq; |
616 | err = devm_request_irq(dev, pdata->irq_hash, s5p_aes_interrupt, | 672 | } |
617 | IRQF_SHARED, pdev->name, pdev); | 673 | err = devm_request_irq(dev, pdata->irq_hash, s5p_aes_interrupt, |
618 | if (err < 0) { | 674 | IRQF_SHARED, pdev->name, pdev); |
619 | dev_warn(dev, "hash interrupt is not available.\n"); | 675 | if (err < 0) { |
620 | goto err_irq; | 676 | dev_warn(dev, "hash interrupt is not available.\n"); |
677 | goto err_irq; | ||
678 | } | ||
621 | } | 679 | } |
622 | 680 | ||
681 | pdata->variant = variant; | ||
623 | pdata->dev = dev; | 682 | pdata->dev = dev; |
624 | platform_set_drvdata(pdev, pdata); | 683 | platform_set_drvdata(pdev, pdata); |
625 | s5p_dev = pdata; | 684 | s5p_dev = pdata; |