aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/crypto
diff options
context:
space:
mode:
authorNaveen Krishna Chatradhi <ch.naveen@samsung.com>2014-05-08 09:58:14 -0400
committerHerbert Xu <herbert@gondor.apana.org.au>2014-05-08 09:58:14 -0400
commit892451071de77a088a6227e36d3a2732d51c5b84 (patch)
tree27235df9e6c1cedfc564ec4f808ebab218f203a0 /drivers/crypto
parent6b9f16e6c2b712f724e6ca1538d18ea8a788dd90 (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.c107
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 */
162struct samsung_aes_variant {
163 bool has_hash_irq;
164 unsigned int aes_offset;
165};
166
149struct s5p_aes_reqctx { 167struct 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
179static struct s5p_aes_dev *s5p_dev; 200static struct s5p_aes_dev *s5p_dev;
180 201
202static const struct samsung_aes_variant s5p_aes_data = {
203 .has_hash_irq = true,
204 .aes_offset = 0x4000,
205};
206
207static const struct samsung_aes_variant exynos_aes_data = {
208 .has_hash_irq = false,
209 .aes_offset = 0x200,
210};
211
181static const struct of_device_id s5p_sss_dt_match[] = { 212static 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};
185MODULE_DEVICE_TABLE(of, s5p_sss_dt_match); 223MODULE_DEVICE_TABLE(of, s5p_sss_dt_match);
186 224
225static 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
187static void s5p_set_dma_indata(struct s5p_aes_dev *dev, struct scatterlist *sg) 238static 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;