1820684ccSTudor Ambarus // SPDX-License-Identifier: GPL-2.0
213802005SNicolas Royer /*
313802005SNicolas Royer * Cryptographic API.
413802005SNicolas Royer *
513802005SNicolas Royer * Support for ATMEL DES/TDES HW acceleration.
613802005SNicolas Royer *
713802005SNicolas Royer * Copyright (c) 2012 Eukréa Electromatique - ATMEL
813802005SNicolas Royer * Author: Nicolas Royer <nicolas@eukrea.com>
913802005SNicolas Royer *
1013802005SNicolas Royer * Some ideas are from omap-aes.c drivers.
1113802005SNicolas Royer */
1213802005SNicolas Royer
1313802005SNicolas Royer
1413802005SNicolas Royer #include <linux/kernel.h>
1513802005SNicolas Royer #include <linux/module.h>
1613802005SNicolas Royer #include <linux/slab.h>
1713802005SNicolas Royer #include <linux/err.h>
1813802005SNicolas Royer #include <linux/clk.h>
1913802005SNicolas Royer #include <linux/io.h>
2013802005SNicolas Royer #include <linux/hw_random.h>
2113802005SNicolas Royer #include <linux/platform_device.h>
2213802005SNicolas Royer
2313802005SNicolas Royer #include <linux/device.h>
24b46f36c0STudor Ambarus #include <linux/dmaengine.h>
2513802005SNicolas Royer #include <linux/init.h>
2613802005SNicolas Royer #include <linux/errno.h>
2713802005SNicolas Royer #include <linux/interrupt.h>
2813802005SNicolas Royer #include <linux/irq.h>
2913802005SNicolas Royer #include <linux/scatterlist.h>
3013802005SNicolas Royer #include <linux/dma-mapping.h>
31*b0cc7491SRob Herring #include <linux/mod_devicetable.h>
3213802005SNicolas Royer #include <linux/delay.h>
3313802005SNicolas Royer #include <linux/crypto.h>
3413802005SNicolas Royer #include <crypto/scatterwalk.h>
3513802005SNicolas Royer #include <crypto/algapi.h>
3692c203e2SArd Biesheuvel #include <crypto/internal/des.h>
37967d4910SArd Biesheuvel #include <crypto/internal/skcipher.h>
3813802005SNicolas Royer #include "atmel-tdes-regs.h"
3913802005SNicolas Royer
407c783029STudor Ambarus #define ATMEL_TDES_PRIORITY 300
417c783029STudor Ambarus
4213802005SNicolas Royer /* TDES flags */
43848572f8STudor Ambarus /* Reserve bits [17:16], [13:12], [2:0] for AES Mode Register */
44848572f8STudor Ambarus #define TDES_FLAGS_ENCRYPT TDES_MR_CYPHER_ENC
45848572f8STudor Ambarus #define TDES_FLAGS_OPMODE_MASK (TDES_MR_OPMOD_MASK | TDES_MR_CFBS_MASK)
46848572f8STudor Ambarus #define TDES_FLAGS_ECB TDES_MR_OPMOD_ECB
47848572f8STudor Ambarus #define TDES_FLAGS_CBC TDES_MR_OPMOD_CBC
48848572f8STudor Ambarus #define TDES_FLAGS_OFB TDES_MR_OPMOD_OFB
49848572f8STudor Ambarus #define TDES_FLAGS_CFB64 (TDES_MR_OPMOD_CFB | TDES_MR_CFBS_64b)
50848572f8STudor Ambarus #define TDES_FLAGS_CFB32 (TDES_MR_OPMOD_CFB | TDES_MR_CFBS_32b)
51848572f8STudor Ambarus #define TDES_FLAGS_CFB16 (TDES_MR_OPMOD_CFB | TDES_MR_CFBS_16b)
52848572f8STudor Ambarus #define TDES_FLAGS_CFB8 (TDES_MR_OPMOD_CFB | TDES_MR_CFBS_8b)
5313802005SNicolas Royer
54848572f8STudor Ambarus #define TDES_FLAGS_MODE_MASK (TDES_FLAGS_OPMODE_MASK | TDES_FLAGS_ENCRYPT)
55848572f8STudor Ambarus
56848572f8STudor Ambarus #define TDES_FLAGS_INIT BIT(3)
57848572f8STudor Ambarus #define TDES_FLAGS_FAST BIT(4)
58848572f8STudor Ambarus #define TDES_FLAGS_BUSY BIT(5)
59848572f8STudor Ambarus #define TDES_FLAGS_DMA BIT(6)
6013802005SNicolas Royer
611f858040SNicolas Royer #define ATMEL_TDES_QUEUE_LENGTH 50
6213802005SNicolas Royer
6313802005SNicolas Royer #define CFB8_BLOCK_SIZE 1
6413802005SNicolas Royer #define CFB16_BLOCK_SIZE 2
6513802005SNicolas Royer #define CFB32_BLOCK_SIZE 4
6613802005SNicolas Royer
671f858040SNicolas Royer struct atmel_tdes_caps {
681f858040SNicolas Royer bool has_dma;
691f858040SNicolas Royer u32 has_cfb_3keys;
701f858040SNicolas Royer };
7113802005SNicolas Royer
7213802005SNicolas Royer struct atmel_tdes_dev;
7313802005SNicolas Royer
7413802005SNicolas Royer struct atmel_tdes_ctx {
7513802005SNicolas Royer struct atmel_tdes_dev *dd;
7613802005SNicolas Royer
7713802005SNicolas Royer int keylen;
78967d4910SArd Biesheuvel u32 key[DES3_EDE_KEY_SIZE / sizeof(u32)];
7913802005SNicolas Royer unsigned long flags;
801f858040SNicolas Royer
811f858040SNicolas Royer u16 block_size;
8213802005SNicolas Royer };
8313802005SNicolas Royer
8413802005SNicolas Royer struct atmel_tdes_reqctx {
8513802005SNicolas Royer unsigned long mode;
8661b0dd66STudor Ambarus u8 lastc[DES_BLOCK_SIZE];
8713802005SNicolas Royer };
8813802005SNicolas Royer
891f858040SNicolas Royer struct atmel_tdes_dma {
901f858040SNicolas Royer struct dma_chan *chan;
911f858040SNicolas Royer struct dma_slave_config dma_conf;
921f858040SNicolas Royer };
931f858040SNicolas Royer
9413802005SNicolas Royer struct atmel_tdes_dev {
9513802005SNicolas Royer struct list_head list;
9613802005SNicolas Royer unsigned long phys_base;
9713802005SNicolas Royer void __iomem *io_base;
9813802005SNicolas Royer
9913802005SNicolas Royer struct atmel_tdes_ctx *ctx;
10013802005SNicolas Royer struct device *dev;
10113802005SNicolas Royer struct clk *iclk;
10213802005SNicolas Royer int irq;
10313802005SNicolas Royer
10413802005SNicolas Royer unsigned long flags;
10513802005SNicolas Royer
10613802005SNicolas Royer spinlock_t lock;
10713802005SNicolas Royer struct crypto_queue queue;
10813802005SNicolas Royer
10913802005SNicolas Royer struct tasklet_struct done_task;
11013802005SNicolas Royer struct tasklet_struct queue_task;
11113802005SNicolas Royer
112967d4910SArd Biesheuvel struct skcipher_request *req;
11313802005SNicolas Royer size_t total;
11413802005SNicolas Royer
11513802005SNicolas Royer struct scatterlist *in_sg;
1161f858040SNicolas Royer unsigned int nb_in_sg;
11713802005SNicolas Royer size_t in_offset;
11813802005SNicolas Royer struct scatterlist *out_sg;
1191f858040SNicolas Royer unsigned int nb_out_sg;
12013802005SNicolas Royer size_t out_offset;
12113802005SNicolas Royer
12213802005SNicolas Royer size_t buflen;
12313802005SNicolas Royer size_t dma_size;
12413802005SNicolas Royer
12513802005SNicolas Royer void *buf_in;
12613802005SNicolas Royer int dma_in;
12713802005SNicolas Royer dma_addr_t dma_addr_in;
1281f858040SNicolas Royer struct atmel_tdes_dma dma_lch_in;
12913802005SNicolas Royer
13013802005SNicolas Royer void *buf_out;
13113802005SNicolas Royer int dma_out;
13213802005SNicolas Royer dma_addr_t dma_addr_out;
1331f858040SNicolas Royer struct atmel_tdes_dma dma_lch_out;
1341f858040SNicolas Royer
1351f858040SNicolas Royer struct atmel_tdes_caps caps;
1361f858040SNicolas Royer
1371f858040SNicolas Royer u32 hw_version;
13813802005SNicolas Royer };
13913802005SNicolas Royer
14013802005SNicolas Royer struct atmel_tdes_drv {
14113802005SNicolas Royer struct list_head dev_list;
14213802005SNicolas Royer spinlock_t lock;
14313802005SNicolas Royer };
14413802005SNicolas Royer
14513802005SNicolas Royer static struct atmel_tdes_drv atmel_tdes = {
14613802005SNicolas Royer .dev_list = LIST_HEAD_INIT(atmel_tdes.dev_list),
14713802005SNicolas Royer .lock = __SPIN_LOCK_UNLOCKED(atmel_tdes.lock),
14813802005SNicolas Royer };
14913802005SNicolas Royer
atmel_tdes_sg_copy(struct scatterlist ** sg,size_t * offset,void * buf,size_t buflen,size_t total,int out)15013802005SNicolas Royer static int atmel_tdes_sg_copy(struct scatterlist **sg, size_t *offset,
15113802005SNicolas Royer void *buf, size_t buflen, size_t total, int out)
15213802005SNicolas Royer {
1534c147bcfSArnd Bergmann size_t count, off = 0;
15413802005SNicolas Royer
15513802005SNicolas Royer while (buflen && total) {
15613802005SNicolas Royer count = min((*sg)->length - *offset, total);
15713802005SNicolas Royer count = min(count, buflen);
15813802005SNicolas Royer
15913802005SNicolas Royer if (!count)
16013802005SNicolas Royer return off;
16113802005SNicolas Royer
16213802005SNicolas Royer scatterwalk_map_and_copy(buf + off, *sg, *offset, count, out);
16313802005SNicolas Royer
16413802005SNicolas Royer off += count;
16513802005SNicolas Royer buflen -= count;
16613802005SNicolas Royer *offset += count;
16713802005SNicolas Royer total -= count;
16813802005SNicolas Royer
16913802005SNicolas Royer if (*offset == (*sg)->length) {
17013802005SNicolas Royer *sg = sg_next(*sg);
17113802005SNicolas Royer if (*sg)
17213802005SNicolas Royer *offset = 0;
17313802005SNicolas Royer else
17413802005SNicolas Royer total = 0;
17513802005SNicolas Royer }
17613802005SNicolas Royer }
17713802005SNicolas Royer
17813802005SNicolas Royer return off;
17913802005SNicolas Royer }
18013802005SNicolas Royer
atmel_tdes_read(struct atmel_tdes_dev * dd,u32 offset)18113802005SNicolas Royer static inline u32 atmel_tdes_read(struct atmel_tdes_dev *dd, u32 offset)
18213802005SNicolas Royer {
18313802005SNicolas Royer return readl_relaxed(dd->io_base + offset);
18413802005SNicolas Royer }
18513802005SNicolas Royer
atmel_tdes_write(struct atmel_tdes_dev * dd,u32 offset,u32 value)18613802005SNicolas Royer static inline void atmel_tdes_write(struct atmel_tdes_dev *dd,
18713802005SNicolas Royer u32 offset, u32 value)
18813802005SNicolas Royer {
18913802005SNicolas Royer writel_relaxed(value, dd->io_base + offset);
19013802005SNicolas Royer }
19113802005SNicolas Royer
atmel_tdes_write_n(struct atmel_tdes_dev * dd,u32 offset,const u32 * value,int count)19213802005SNicolas Royer static void atmel_tdes_write_n(struct atmel_tdes_dev *dd, u32 offset,
1937b49fabfSTudor Ambarus const u32 *value, int count)
19413802005SNicolas Royer {
19513802005SNicolas Royer for (; count--; value++, offset += 4)
19613802005SNicolas Royer atmel_tdes_write(dd, offset, *value);
19713802005SNicolas Royer }
19813802005SNicolas Royer
atmel_tdes_dev_alloc(void)199632a761aSTudor Ambarus static struct atmel_tdes_dev *atmel_tdes_dev_alloc(void)
20013802005SNicolas Royer {
201632a761aSTudor Ambarus struct atmel_tdes_dev *tdes_dd;
20213802005SNicolas Royer
20313802005SNicolas Royer spin_lock_bh(&atmel_tdes.lock);
204632a761aSTudor Ambarus /* One TDES IP per SoC. */
205632a761aSTudor Ambarus tdes_dd = list_first_entry_or_null(&atmel_tdes.dev_list,
206632a761aSTudor Ambarus struct atmel_tdes_dev, list);
20713802005SNicolas Royer spin_unlock_bh(&atmel_tdes.lock);
20813802005SNicolas Royer return tdes_dd;
20913802005SNicolas Royer }
21013802005SNicolas Royer
atmel_tdes_hw_init(struct atmel_tdes_dev * dd)21113802005SNicolas Royer static int atmel_tdes_hw_init(struct atmel_tdes_dev *dd)
21213802005SNicolas Royer {
2139d83d299SLABBE Corentin int err;
2149d83d299SLABBE Corentin
2159d83d299SLABBE Corentin err = clk_prepare_enable(dd->iclk);
2169d83d299SLABBE Corentin if (err)
2179d83d299SLABBE Corentin return err;
21813802005SNicolas Royer
21913802005SNicolas Royer if (!(dd->flags & TDES_FLAGS_INIT)) {
22013802005SNicolas Royer atmel_tdes_write(dd, TDES_CR, TDES_CR_SWRST);
22113802005SNicolas Royer dd->flags |= TDES_FLAGS_INIT;
22213802005SNicolas Royer }
22313802005SNicolas Royer
22413802005SNicolas Royer return 0;
22513802005SNicolas Royer }
22613802005SNicolas Royer
atmel_tdes_get_version(struct atmel_tdes_dev * dd)2271f858040SNicolas Royer static inline unsigned int atmel_tdes_get_version(struct atmel_tdes_dev *dd)
2281f858040SNicolas Royer {
2291f858040SNicolas Royer return atmel_tdes_read(dd, TDES_HW_VERSION) & 0x00000fff;
2301f858040SNicolas Royer }
2311f858040SNicolas Royer
atmel_tdes_hw_version_init(struct atmel_tdes_dev * dd)2320efe58f3STudor Ambarus static int atmel_tdes_hw_version_init(struct atmel_tdes_dev *dd)
2331f858040SNicolas Royer {
2340efe58f3STudor Ambarus int err;
2350efe58f3STudor Ambarus
2360efe58f3STudor Ambarus err = atmel_tdes_hw_init(dd);
2370efe58f3STudor Ambarus if (err)
2380efe58f3STudor Ambarus return err;
2391f858040SNicolas Royer
2401f858040SNicolas Royer dd->hw_version = atmel_tdes_get_version(dd);
2411f858040SNicolas Royer
2421f858040SNicolas Royer dev_info(dd->dev,
2431f858040SNicolas Royer "version: 0x%x\n", dd->hw_version);
2441f858040SNicolas Royer
2451f858040SNicolas Royer clk_disable_unprepare(dd->iclk);
2460efe58f3STudor Ambarus
2470efe58f3STudor Ambarus return 0;
2481f858040SNicolas Royer }
2491f858040SNicolas Royer
atmel_tdes_dma_callback(void * data)2501f858040SNicolas Royer static void atmel_tdes_dma_callback(void *data)
2511f858040SNicolas Royer {
2521f858040SNicolas Royer struct atmel_tdes_dev *dd = data;
2531f858040SNicolas Royer
2541f858040SNicolas Royer /* dma_lch_out - completed */
2551f858040SNicolas Royer tasklet_schedule(&dd->done_task);
2561f858040SNicolas Royer }
2571f858040SNicolas Royer
atmel_tdes_write_ctrl(struct atmel_tdes_dev * dd)25813802005SNicolas Royer static int atmel_tdes_write_ctrl(struct atmel_tdes_dev *dd)
25913802005SNicolas Royer {
26013802005SNicolas Royer int err;
2617d0979e2STudor Ambarus u32 valmr = TDES_MR_SMOD_PDC;
26213802005SNicolas Royer
26313802005SNicolas Royer err = atmel_tdes_hw_init(dd);
26413802005SNicolas Royer
26513802005SNicolas Royer if (err)
26613802005SNicolas Royer return err;
26713802005SNicolas Royer
2681f858040SNicolas Royer if (!dd->caps.has_dma)
2691f858040SNicolas Royer atmel_tdes_write(dd, TDES_PTCR,
2701f858040SNicolas Royer TDES_PTCR_TXTDIS | TDES_PTCR_RXTDIS);
27113802005SNicolas Royer
27213802005SNicolas Royer /* MR register must be set before IV registers */
27313802005SNicolas Royer if (dd->ctx->keylen > (DES_KEY_SIZE << 1)) {
27413802005SNicolas Royer valmr |= TDES_MR_KEYMOD_3KEY;
27513802005SNicolas Royer valmr |= TDES_MR_TDESMOD_TDES;
27613802005SNicolas Royer } else if (dd->ctx->keylen > DES_KEY_SIZE) {
27713802005SNicolas Royer valmr |= TDES_MR_KEYMOD_2KEY;
27813802005SNicolas Royer valmr |= TDES_MR_TDESMOD_TDES;
27913802005SNicolas Royer } else {
28013802005SNicolas Royer valmr |= TDES_MR_TDESMOD_DES;
28113802005SNicolas Royer }
28213802005SNicolas Royer
283848572f8STudor Ambarus valmr |= dd->flags & TDES_FLAGS_MODE_MASK;
28413802005SNicolas Royer
28513802005SNicolas Royer atmel_tdes_write(dd, TDES_MR, valmr);
28613802005SNicolas Royer
28713802005SNicolas Royer atmel_tdes_write_n(dd, TDES_KEY1W1R, dd->ctx->key,
28813802005SNicolas Royer dd->ctx->keylen >> 2);
28913802005SNicolas Royer
290848572f8STudor Ambarus if (dd->req->iv && (valmr & TDES_MR_OPMOD_MASK) != TDES_MR_OPMOD_ECB)
291967d4910SArd Biesheuvel atmel_tdes_write_n(dd, TDES_IV1R, (void *)dd->req->iv, 2);
29213802005SNicolas Royer
29313802005SNicolas Royer return 0;
29413802005SNicolas Royer }
29513802005SNicolas Royer
atmel_tdes_crypt_pdc_stop(struct atmel_tdes_dev * dd)2961f858040SNicolas Royer static int atmel_tdes_crypt_pdc_stop(struct atmel_tdes_dev *dd)
29713802005SNicolas Royer {
29813802005SNicolas Royer int err = 0;
29913802005SNicolas Royer size_t count;
30013802005SNicolas Royer
30113802005SNicolas Royer atmel_tdes_write(dd, TDES_PTCR, TDES_PTCR_TXTDIS|TDES_PTCR_RXTDIS);
30213802005SNicolas Royer
30313802005SNicolas Royer if (dd->flags & TDES_FLAGS_FAST) {
30413802005SNicolas Royer dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_FROM_DEVICE);
30513802005SNicolas Royer dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
30613802005SNicolas Royer } else {
30713802005SNicolas Royer dma_sync_single_for_device(dd->dev, dd->dma_addr_out,
30813802005SNicolas Royer dd->dma_size, DMA_FROM_DEVICE);
30913802005SNicolas Royer
31013802005SNicolas Royer /* copy data */
31113802005SNicolas Royer count = atmel_tdes_sg_copy(&dd->out_sg, &dd->out_offset,
31213802005SNicolas Royer dd->buf_out, dd->buflen, dd->dma_size, 1);
31313802005SNicolas Royer if (count != dd->dma_size) {
31413802005SNicolas Royer err = -EINVAL;
315817b804cSTudor Ambarus dev_dbg(dd->dev, "not all data converted: %zu\n", count);
31613802005SNicolas Royer }
31713802005SNicolas Royer }
31813802005SNicolas Royer
31913802005SNicolas Royer return err;
32013802005SNicolas Royer }
32113802005SNicolas Royer
atmel_tdes_buff_init(struct atmel_tdes_dev * dd)3221f858040SNicolas Royer static int atmel_tdes_buff_init(struct atmel_tdes_dev *dd)
32313802005SNicolas Royer {
32413802005SNicolas Royer int err = -ENOMEM;
32513802005SNicolas Royer
32613802005SNicolas Royer dd->buf_in = (void *)__get_free_pages(GFP_KERNEL, 0);
32713802005SNicolas Royer dd->buf_out = (void *)__get_free_pages(GFP_KERNEL, 0);
32813802005SNicolas Royer dd->buflen = PAGE_SIZE;
32913802005SNicolas Royer dd->buflen &= ~(DES_BLOCK_SIZE - 1);
33013802005SNicolas Royer
33113802005SNicolas Royer if (!dd->buf_in || !dd->buf_out) {
332817b804cSTudor Ambarus dev_dbg(dd->dev, "unable to alloc pages.\n");
33313802005SNicolas Royer goto err_alloc;
33413802005SNicolas Royer }
33513802005SNicolas Royer
33613802005SNicolas Royer /* MAP here */
33713802005SNicolas Royer dd->dma_addr_in = dma_map_single(dd->dev, dd->buf_in,
33813802005SNicolas Royer dd->buflen, DMA_TO_DEVICE);
339817b804cSTudor Ambarus err = dma_mapping_error(dd->dev, dd->dma_addr_in);
340817b804cSTudor Ambarus if (err) {
341817b804cSTudor Ambarus dev_dbg(dd->dev, "dma %zd bytes error\n", dd->buflen);
34213802005SNicolas Royer goto err_map_in;
34313802005SNicolas Royer }
34413802005SNicolas Royer
34513802005SNicolas Royer dd->dma_addr_out = dma_map_single(dd->dev, dd->buf_out,
34613802005SNicolas Royer dd->buflen, DMA_FROM_DEVICE);
347817b804cSTudor Ambarus err = dma_mapping_error(dd->dev, dd->dma_addr_out);
348817b804cSTudor Ambarus if (err) {
349817b804cSTudor Ambarus dev_dbg(dd->dev, "dma %zd bytes error\n", dd->buflen);
35013802005SNicolas Royer goto err_map_out;
35113802005SNicolas Royer }
35213802005SNicolas Royer
35313802005SNicolas Royer return 0;
35413802005SNicolas Royer
35513802005SNicolas Royer err_map_out:
35613802005SNicolas Royer dma_unmap_single(dd->dev, dd->dma_addr_in, dd->buflen,
35713802005SNicolas Royer DMA_TO_DEVICE);
35813802005SNicolas Royer err_map_in:
359088f628cSChristophe Jaillet err_alloc:
36013802005SNicolas Royer free_page((unsigned long)dd->buf_out);
36113802005SNicolas Royer free_page((unsigned long)dd->buf_in);
36213802005SNicolas Royer return err;
36313802005SNicolas Royer }
36413802005SNicolas Royer
atmel_tdes_buff_cleanup(struct atmel_tdes_dev * dd)3651f858040SNicolas Royer static void atmel_tdes_buff_cleanup(struct atmel_tdes_dev *dd)
36613802005SNicolas Royer {
36713802005SNicolas Royer dma_unmap_single(dd->dev, dd->dma_addr_out, dd->buflen,
36813802005SNicolas Royer DMA_FROM_DEVICE);
36913802005SNicolas Royer dma_unmap_single(dd->dev, dd->dma_addr_in, dd->buflen,
37013802005SNicolas Royer DMA_TO_DEVICE);
37113802005SNicolas Royer free_page((unsigned long)dd->buf_out);
37213802005SNicolas Royer free_page((unsigned long)dd->buf_in);
37313802005SNicolas Royer }
37413802005SNicolas Royer
atmel_tdes_crypt_pdc(struct atmel_tdes_dev * dd,dma_addr_t dma_addr_in,dma_addr_t dma_addr_out,int length)37575eca7a7STudor Ambarus static int atmel_tdes_crypt_pdc(struct atmel_tdes_dev *dd,
37675eca7a7STudor Ambarus dma_addr_t dma_addr_in,
37713802005SNicolas Royer dma_addr_t dma_addr_out, int length)
37813802005SNicolas Royer {
379848572f8STudor Ambarus struct atmel_tdes_reqctx *rctx = skcipher_request_ctx(dd->req);
38013802005SNicolas Royer int len32;
38113802005SNicolas Royer
38213802005SNicolas Royer dd->dma_size = length;
38313802005SNicolas Royer
38413802005SNicolas Royer if (!(dd->flags & TDES_FLAGS_FAST)) {
38513802005SNicolas Royer dma_sync_single_for_device(dd->dev, dma_addr_in, length,
38613802005SNicolas Royer DMA_TO_DEVICE);
38713802005SNicolas Royer }
38813802005SNicolas Royer
389848572f8STudor Ambarus switch (rctx->mode & TDES_FLAGS_OPMODE_MASK) {
390848572f8STudor Ambarus case TDES_FLAGS_CFB8:
39113802005SNicolas Royer len32 = DIV_ROUND_UP(length, sizeof(u8));
392848572f8STudor Ambarus break;
393848572f8STudor Ambarus
394848572f8STudor Ambarus case TDES_FLAGS_CFB16:
39513802005SNicolas Royer len32 = DIV_ROUND_UP(length, sizeof(u16));
396848572f8STudor Ambarus break;
397848572f8STudor Ambarus
398848572f8STudor Ambarus default:
39913802005SNicolas Royer len32 = DIV_ROUND_UP(length, sizeof(u32));
400848572f8STudor Ambarus break;
401848572f8STudor Ambarus }
40213802005SNicolas Royer
40313802005SNicolas Royer atmel_tdes_write(dd, TDES_PTCR, TDES_PTCR_TXTDIS|TDES_PTCR_RXTDIS);
40413802005SNicolas Royer atmel_tdes_write(dd, TDES_TPR, dma_addr_in);
40513802005SNicolas Royer atmel_tdes_write(dd, TDES_TCR, len32);
40613802005SNicolas Royer atmel_tdes_write(dd, TDES_RPR, dma_addr_out);
40713802005SNicolas Royer atmel_tdes_write(dd, TDES_RCR, len32);
40813802005SNicolas Royer
40913802005SNicolas Royer /* Enable Interrupt */
41013802005SNicolas Royer atmel_tdes_write(dd, TDES_IER, TDES_INT_ENDRX);
41113802005SNicolas Royer
41213802005SNicolas Royer /* Start DMA transfer */
41313802005SNicolas Royer atmel_tdes_write(dd, TDES_PTCR, TDES_PTCR_TXTEN | TDES_PTCR_RXTEN);
41413802005SNicolas Royer
41513802005SNicolas Royer return 0;
41613802005SNicolas Royer }
41713802005SNicolas Royer
atmel_tdes_crypt_dma(struct atmel_tdes_dev * dd,dma_addr_t dma_addr_in,dma_addr_t dma_addr_out,int length)41875eca7a7STudor Ambarus static int atmel_tdes_crypt_dma(struct atmel_tdes_dev *dd,
41975eca7a7STudor Ambarus dma_addr_t dma_addr_in,
4201f858040SNicolas Royer dma_addr_t dma_addr_out, int length)
4211f858040SNicolas Royer {
422848572f8STudor Ambarus struct atmel_tdes_reqctx *rctx = skcipher_request_ctx(dd->req);
4231f858040SNicolas Royer struct scatterlist sg[2];
4241f858040SNicolas Royer struct dma_async_tx_descriptor *in_desc, *out_desc;
425848572f8STudor Ambarus enum dma_slave_buswidth addr_width;
4261f858040SNicolas Royer
4271f858040SNicolas Royer dd->dma_size = length;
4281f858040SNicolas Royer
4291f858040SNicolas Royer if (!(dd->flags & TDES_FLAGS_FAST)) {
4301f858040SNicolas Royer dma_sync_single_for_device(dd->dev, dma_addr_in, length,
4311f858040SNicolas Royer DMA_TO_DEVICE);
4321f858040SNicolas Royer }
4331f858040SNicolas Royer
434848572f8STudor Ambarus switch (rctx->mode & TDES_FLAGS_OPMODE_MASK) {
435848572f8STudor Ambarus case TDES_FLAGS_CFB8:
436848572f8STudor Ambarus addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
437848572f8STudor Ambarus break;
438848572f8STudor Ambarus
439848572f8STudor Ambarus case TDES_FLAGS_CFB16:
440848572f8STudor Ambarus addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
441848572f8STudor Ambarus break;
442848572f8STudor Ambarus
443848572f8STudor Ambarus default:
444848572f8STudor Ambarus addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
445848572f8STudor Ambarus break;
4461f858040SNicolas Royer }
4471f858040SNicolas Royer
448848572f8STudor Ambarus dd->dma_lch_in.dma_conf.dst_addr_width = addr_width;
449848572f8STudor Ambarus dd->dma_lch_out.dma_conf.src_addr_width = addr_width;
450848572f8STudor Ambarus
4511f858040SNicolas Royer dmaengine_slave_config(dd->dma_lch_in.chan, &dd->dma_lch_in.dma_conf);
4521f858040SNicolas Royer dmaengine_slave_config(dd->dma_lch_out.chan, &dd->dma_lch_out.dma_conf);
4531f858040SNicolas Royer
4541f858040SNicolas Royer dd->flags |= TDES_FLAGS_DMA;
4551f858040SNicolas Royer
4561f858040SNicolas Royer sg_init_table(&sg[0], 1);
4571f858040SNicolas Royer sg_dma_address(&sg[0]) = dma_addr_in;
4581f858040SNicolas Royer sg_dma_len(&sg[0]) = length;
4591f858040SNicolas Royer
4601f858040SNicolas Royer sg_init_table(&sg[1], 1);
4611f858040SNicolas Royer sg_dma_address(&sg[1]) = dma_addr_out;
4621f858040SNicolas Royer sg_dma_len(&sg[1]) = length;
4631f858040SNicolas Royer
4641f858040SNicolas Royer in_desc = dmaengine_prep_slave_sg(dd->dma_lch_in.chan, &sg[0],
4651f858040SNicolas Royer 1, DMA_MEM_TO_DEV,
4661f858040SNicolas Royer DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
4671f858040SNicolas Royer if (!in_desc)
4681f858040SNicolas Royer return -EINVAL;
4691f858040SNicolas Royer
4701f858040SNicolas Royer out_desc = dmaengine_prep_slave_sg(dd->dma_lch_out.chan, &sg[1],
4711f858040SNicolas Royer 1, DMA_DEV_TO_MEM,
4721f858040SNicolas Royer DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
4731f858040SNicolas Royer if (!out_desc)
4741f858040SNicolas Royer return -EINVAL;
4751f858040SNicolas Royer
4761f858040SNicolas Royer out_desc->callback = atmel_tdes_dma_callback;
4771f858040SNicolas Royer out_desc->callback_param = dd;
4781f858040SNicolas Royer
4791f858040SNicolas Royer dmaengine_submit(out_desc);
4801f858040SNicolas Royer dma_async_issue_pending(dd->dma_lch_out.chan);
4811f858040SNicolas Royer
4821f858040SNicolas Royer dmaengine_submit(in_desc);
4831f858040SNicolas Royer dma_async_issue_pending(dd->dma_lch_in.chan);
4841f858040SNicolas Royer
4851f858040SNicolas Royer return 0;
4861f858040SNicolas Royer }
4871f858040SNicolas Royer
atmel_tdes_crypt_start(struct atmel_tdes_dev * dd)4881f858040SNicolas Royer static int atmel_tdes_crypt_start(struct atmel_tdes_dev *dd)
48913802005SNicolas Royer {
49013802005SNicolas Royer int err, fast = 0, in, out;
49113802005SNicolas Royer size_t count;
49213802005SNicolas Royer dma_addr_t addr_in, addr_out;
49313802005SNicolas Royer
4941f858040SNicolas Royer if ((!dd->in_offset) && (!dd->out_offset)) {
49513802005SNicolas Royer /* check for alignment */
4961f858040SNicolas Royer in = IS_ALIGNED((u32)dd->in_sg->offset, sizeof(u32)) &&
4971f858040SNicolas Royer IS_ALIGNED(dd->in_sg->length, dd->ctx->block_size);
4981f858040SNicolas Royer out = IS_ALIGNED((u32)dd->out_sg->offset, sizeof(u32)) &&
4991f858040SNicolas Royer IS_ALIGNED(dd->out_sg->length, dd->ctx->block_size);
50013802005SNicolas Royer fast = in && out;
5011f858040SNicolas Royer
5021f858040SNicolas Royer if (sg_dma_len(dd->in_sg) != sg_dma_len(dd->out_sg))
5031f858040SNicolas Royer fast = 0;
50413802005SNicolas Royer }
50513802005SNicolas Royer
5061f858040SNicolas Royer
50713802005SNicolas Royer if (fast) {
5084c147bcfSArnd Bergmann count = min_t(size_t, dd->total, sg_dma_len(dd->in_sg));
5094c147bcfSArnd Bergmann count = min_t(size_t, count, sg_dma_len(dd->out_sg));
51013802005SNicolas Royer
51113802005SNicolas Royer err = dma_map_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
51213802005SNicolas Royer if (!err) {
513817b804cSTudor Ambarus dev_dbg(dd->dev, "dma_map_sg() error\n");
51413802005SNicolas Royer return -EINVAL;
51513802005SNicolas Royer }
51613802005SNicolas Royer
51713802005SNicolas Royer err = dma_map_sg(dd->dev, dd->out_sg, 1,
51813802005SNicolas Royer DMA_FROM_DEVICE);
51913802005SNicolas Royer if (!err) {
520817b804cSTudor Ambarus dev_dbg(dd->dev, "dma_map_sg() error\n");
52113802005SNicolas Royer dma_unmap_sg(dd->dev, dd->in_sg, 1,
52213802005SNicolas Royer DMA_TO_DEVICE);
52313802005SNicolas Royer return -EINVAL;
52413802005SNicolas Royer }
52513802005SNicolas Royer
52613802005SNicolas Royer addr_in = sg_dma_address(dd->in_sg);
52713802005SNicolas Royer addr_out = sg_dma_address(dd->out_sg);
52813802005SNicolas Royer
52913802005SNicolas Royer dd->flags |= TDES_FLAGS_FAST;
53013802005SNicolas Royer
53113802005SNicolas Royer } else {
53213802005SNicolas Royer /* use cache buffers */
53313802005SNicolas Royer count = atmel_tdes_sg_copy(&dd->in_sg, &dd->in_offset,
53413802005SNicolas Royer dd->buf_in, dd->buflen, dd->total, 0);
53513802005SNicolas Royer
53613802005SNicolas Royer addr_in = dd->dma_addr_in;
53713802005SNicolas Royer addr_out = dd->dma_addr_out;
53813802005SNicolas Royer
53913802005SNicolas Royer dd->flags &= ~TDES_FLAGS_FAST;
54013802005SNicolas Royer }
54113802005SNicolas Royer
54213802005SNicolas Royer dd->total -= count;
54313802005SNicolas Royer
5441f858040SNicolas Royer if (dd->caps.has_dma)
54575eca7a7STudor Ambarus err = atmel_tdes_crypt_dma(dd, addr_in, addr_out, count);
5461f858040SNicolas Royer else
54775eca7a7STudor Ambarus err = atmel_tdes_crypt_pdc(dd, addr_in, addr_out, count);
5481f858040SNicolas Royer
5491f858040SNicolas Royer if (err && (dd->flags & TDES_FLAGS_FAST)) {
55013802005SNicolas Royer dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
55113802005SNicolas Royer dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_TO_DEVICE);
55213802005SNicolas Royer }
55313802005SNicolas Royer
55413802005SNicolas Royer return err;
55513802005SNicolas Royer }
55613802005SNicolas Royer
55761b0dd66STudor Ambarus static void
atmel_tdes_set_iv_as_last_ciphertext_block(struct atmel_tdes_dev * dd)55861b0dd66STudor Ambarus atmel_tdes_set_iv_as_last_ciphertext_block(struct atmel_tdes_dev *dd)
55961b0dd66STudor Ambarus {
56061b0dd66STudor Ambarus struct skcipher_request *req = dd->req;
56161b0dd66STudor Ambarus struct atmel_tdes_reqctx *rctx = skcipher_request_ctx(req);
56261b0dd66STudor Ambarus struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
56361b0dd66STudor Ambarus unsigned int ivsize = crypto_skcipher_ivsize(skcipher);
56461b0dd66STudor Ambarus
56561b0dd66STudor Ambarus if (req->cryptlen < ivsize)
56661b0dd66STudor Ambarus return;
56761b0dd66STudor Ambarus
568c13357fdSRyan Wanner if (rctx->mode & TDES_FLAGS_ENCRYPT)
56961b0dd66STudor Ambarus scatterwalk_map_and_copy(req->iv, req->dst,
57061b0dd66STudor Ambarus req->cryptlen - ivsize, ivsize, 0);
57161b0dd66STudor Ambarus else
572c13357fdSRyan Wanner memcpy(req->iv, rctx->lastc, ivsize);
573c13357fdSRyan Wanner
57461b0dd66STudor Ambarus }
57561b0dd66STudor Ambarus
atmel_tdes_finish_req(struct atmel_tdes_dev * dd,int err)57613802005SNicolas Royer static void atmel_tdes_finish_req(struct atmel_tdes_dev *dd, int err)
57713802005SNicolas Royer {
578967d4910SArd Biesheuvel struct skcipher_request *req = dd->req;
579c65d1237STudor Ambarus struct atmel_tdes_reqctx *rctx = skcipher_request_ctx(req);
58013802005SNicolas Royer
58113802005SNicolas Royer clk_disable_unprepare(dd->iclk);
58213802005SNicolas Royer
58313802005SNicolas Royer dd->flags &= ~TDES_FLAGS_BUSY;
58413802005SNicolas Royer
58527f4adf7STudor Ambarus if (!err && (rctx->mode & TDES_FLAGS_OPMODE_MASK) != TDES_FLAGS_ECB)
58661b0dd66STudor Ambarus atmel_tdes_set_iv_as_last_ciphertext_block(dd);
58761b0dd66STudor Ambarus
5887d19abdcSHerbert Xu skcipher_request_complete(req, err);
58913802005SNicolas Royer }
59013802005SNicolas Royer
atmel_tdes_handle_queue(struct atmel_tdes_dev * dd,struct skcipher_request * req)59113802005SNicolas Royer static int atmel_tdes_handle_queue(struct atmel_tdes_dev *dd,
592967d4910SArd Biesheuvel struct skcipher_request *req)
59313802005SNicolas Royer {
59413802005SNicolas Royer struct crypto_async_request *async_req, *backlog;
59513802005SNicolas Royer struct atmel_tdes_ctx *ctx;
59613802005SNicolas Royer struct atmel_tdes_reqctx *rctx;
59713802005SNicolas Royer unsigned long flags;
59813802005SNicolas Royer int err, ret = 0;
59913802005SNicolas Royer
60013802005SNicolas Royer spin_lock_irqsave(&dd->lock, flags);
60113802005SNicolas Royer if (req)
602967d4910SArd Biesheuvel ret = crypto_enqueue_request(&dd->queue, &req->base);
60313802005SNicolas Royer if (dd->flags & TDES_FLAGS_BUSY) {
60413802005SNicolas Royer spin_unlock_irqrestore(&dd->lock, flags);
60513802005SNicolas Royer return ret;
60613802005SNicolas Royer }
60713802005SNicolas Royer backlog = crypto_get_backlog(&dd->queue);
60813802005SNicolas Royer async_req = crypto_dequeue_request(&dd->queue);
60913802005SNicolas Royer if (async_req)
61013802005SNicolas Royer dd->flags |= TDES_FLAGS_BUSY;
61113802005SNicolas Royer spin_unlock_irqrestore(&dd->lock, flags);
61213802005SNicolas Royer
61313802005SNicolas Royer if (!async_req)
61413802005SNicolas Royer return ret;
61513802005SNicolas Royer
61613802005SNicolas Royer if (backlog)
6177d19abdcSHerbert Xu crypto_request_complete(backlog, -EINPROGRESS);
61813802005SNicolas Royer
619967d4910SArd Biesheuvel req = skcipher_request_cast(async_req);
62013802005SNicolas Royer
62113802005SNicolas Royer /* assign new request to device */
62213802005SNicolas Royer dd->req = req;
623967d4910SArd Biesheuvel dd->total = req->cryptlen;
62413802005SNicolas Royer dd->in_offset = 0;
62513802005SNicolas Royer dd->in_sg = req->src;
62613802005SNicolas Royer dd->out_offset = 0;
62713802005SNicolas Royer dd->out_sg = req->dst;
62813802005SNicolas Royer
629967d4910SArd Biesheuvel rctx = skcipher_request_ctx(req);
630967d4910SArd Biesheuvel ctx = crypto_skcipher_ctx(crypto_skcipher_reqtfm(req));
63113802005SNicolas Royer rctx->mode &= TDES_FLAGS_MODE_MASK;
63213802005SNicolas Royer dd->flags = (dd->flags & ~TDES_FLAGS_MODE_MASK) | rctx->mode;
63313802005SNicolas Royer dd->ctx = ctx;
63413802005SNicolas Royer
63513802005SNicolas Royer err = atmel_tdes_write_ctrl(dd);
63613802005SNicolas Royer if (!err)
6371f858040SNicolas Royer err = atmel_tdes_crypt_start(dd);
63813802005SNicolas Royer if (err) {
63913802005SNicolas Royer /* des_task will not finish it, so do it here */
64013802005SNicolas Royer atmel_tdes_finish_req(dd, err);
64113802005SNicolas Royer tasklet_schedule(&dd->queue_task);
64213802005SNicolas Royer }
64313802005SNicolas Royer
64413802005SNicolas Royer return ret;
64513802005SNicolas Royer }
64613802005SNicolas Royer
atmel_tdes_crypt_dma_stop(struct atmel_tdes_dev * dd)6471f858040SNicolas Royer static int atmel_tdes_crypt_dma_stop(struct atmel_tdes_dev *dd)
6481f858040SNicolas Royer {
6491f858040SNicolas Royer int err = -EINVAL;
6501f858040SNicolas Royer size_t count;
6511f858040SNicolas Royer
6521f858040SNicolas Royer if (dd->flags & TDES_FLAGS_DMA) {
6531f858040SNicolas Royer err = 0;
6541f858040SNicolas Royer if (dd->flags & TDES_FLAGS_FAST) {
6551f858040SNicolas Royer dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_FROM_DEVICE);
6561f858040SNicolas Royer dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
6571f858040SNicolas Royer } else {
6581f858040SNicolas Royer dma_sync_single_for_device(dd->dev, dd->dma_addr_out,
6591f858040SNicolas Royer dd->dma_size, DMA_FROM_DEVICE);
6601f858040SNicolas Royer
6611f858040SNicolas Royer /* copy data */
6621f858040SNicolas Royer count = atmel_tdes_sg_copy(&dd->out_sg, &dd->out_offset,
6631f858040SNicolas Royer dd->buf_out, dd->buflen, dd->dma_size, 1);
6641f858040SNicolas Royer if (count != dd->dma_size) {
6651f858040SNicolas Royer err = -EINVAL;
666817b804cSTudor Ambarus dev_dbg(dd->dev, "not all data converted: %zu\n", count);
6671f858040SNicolas Royer }
6681f858040SNicolas Royer }
6691f858040SNicolas Royer }
6701f858040SNicolas Royer return err;
6711f858040SNicolas Royer }
67213802005SNicolas Royer
atmel_tdes_crypt(struct skcipher_request * req,unsigned long mode)673967d4910SArd Biesheuvel static int atmel_tdes_crypt(struct skcipher_request *req, unsigned long mode)
67413802005SNicolas Royer {
67561b0dd66STudor Ambarus struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
67661b0dd66STudor Ambarus struct atmel_tdes_ctx *ctx = crypto_skcipher_ctx(skcipher);
677967d4910SArd Biesheuvel struct atmel_tdes_reqctx *rctx = skcipher_request_ctx(req);
678817b804cSTudor Ambarus struct device *dev = ctx->dd->dev;
67913802005SNicolas Royer
680031f5e00STudor Ambarus if (!req->cryptlen)
681031f5e00STudor Ambarus return 0;
682031f5e00STudor Ambarus
683848572f8STudor Ambarus switch (mode & TDES_FLAGS_OPMODE_MASK) {
684848572f8STudor Ambarus case TDES_FLAGS_CFB8:
685967d4910SArd Biesheuvel if (!IS_ALIGNED(req->cryptlen, CFB8_BLOCK_SIZE)) {
686817b804cSTudor Ambarus dev_dbg(dev, "request size is not exact amount of CFB8 blocks\n");
68713802005SNicolas Royer return -EINVAL;
68813802005SNicolas Royer }
6891f858040SNicolas Royer ctx->block_size = CFB8_BLOCK_SIZE;
690848572f8STudor Ambarus break;
691848572f8STudor Ambarus
692848572f8STudor Ambarus case TDES_FLAGS_CFB16:
693967d4910SArd Biesheuvel if (!IS_ALIGNED(req->cryptlen, CFB16_BLOCK_SIZE)) {
694817b804cSTudor Ambarus dev_dbg(dev, "request size is not exact amount of CFB16 blocks\n");
69513802005SNicolas Royer return -EINVAL;
69613802005SNicolas Royer }
6971f858040SNicolas Royer ctx->block_size = CFB16_BLOCK_SIZE;
698848572f8STudor Ambarus break;
699848572f8STudor Ambarus
700848572f8STudor Ambarus case TDES_FLAGS_CFB32:
701967d4910SArd Biesheuvel if (!IS_ALIGNED(req->cryptlen, CFB32_BLOCK_SIZE)) {
702817b804cSTudor Ambarus dev_dbg(dev, "request size is not exact amount of CFB32 blocks\n");
70313802005SNicolas Royer return -EINVAL;
70413802005SNicolas Royer }
7051f858040SNicolas Royer ctx->block_size = CFB32_BLOCK_SIZE;
706848572f8STudor Ambarus break;
707848572f8STudor Ambarus
708848572f8STudor Ambarus default:
709967d4910SArd Biesheuvel if (!IS_ALIGNED(req->cryptlen, DES_BLOCK_SIZE)) {
710817b804cSTudor Ambarus dev_dbg(dev, "request size is not exact amount of DES blocks\n");
71113802005SNicolas Royer return -EINVAL;
71213802005SNicolas Royer }
7131f858040SNicolas Royer ctx->block_size = DES_BLOCK_SIZE;
714848572f8STudor Ambarus break;
7151f858040SNicolas Royer }
71613802005SNicolas Royer
71713802005SNicolas Royer rctx->mode = mode;
71813802005SNicolas Royer
719c65d1237STudor Ambarus if ((mode & TDES_FLAGS_OPMODE_MASK) != TDES_FLAGS_ECB &&
720c13357fdSRyan Wanner !(mode & TDES_FLAGS_ENCRYPT)) {
72161b0dd66STudor Ambarus unsigned int ivsize = crypto_skcipher_ivsize(skcipher);
72261b0dd66STudor Ambarus
72361b0dd66STudor Ambarus if (req->cryptlen >= ivsize)
72461b0dd66STudor Ambarus scatterwalk_map_and_copy(rctx->lastc, req->src,
72561b0dd66STudor Ambarus req->cryptlen - ivsize,
72661b0dd66STudor Ambarus ivsize, 0);
72761b0dd66STudor Ambarus }
72861b0dd66STudor Ambarus
7291f858040SNicolas Royer return atmel_tdes_handle_queue(ctx->dd, req);
7301f858040SNicolas Royer }
7311f858040SNicolas Royer
atmel_tdes_dma_init(struct atmel_tdes_dev * dd)732827a98dfSTudor Ambarus static int atmel_tdes_dma_init(struct atmel_tdes_dev *dd)
7331f858040SNicolas Royer {
73445a536e3SPeter Ujfalusi int ret;
7351f858040SNicolas Royer
7361f858040SNicolas Royer /* Try to grab 2 DMA channels */
73745a536e3SPeter Ujfalusi dd->dma_lch_in.chan = dma_request_chan(dd->dev, "tx");
73845a536e3SPeter Ujfalusi if (IS_ERR(dd->dma_lch_in.chan)) {
73945a536e3SPeter Ujfalusi ret = PTR_ERR(dd->dma_lch_in.chan);
7401f858040SNicolas Royer goto err_dma_in;
74145a536e3SPeter Ujfalusi }
7421f858040SNicolas Royer
7431f858040SNicolas Royer dd->dma_lch_in.dma_conf.dst_addr = dd->phys_base +
7441f858040SNicolas Royer TDES_IDATA1R;
7451f858040SNicolas Royer dd->dma_lch_in.dma_conf.src_maxburst = 1;
7461f858040SNicolas Royer dd->dma_lch_in.dma_conf.src_addr_width =
7471f858040SNicolas Royer DMA_SLAVE_BUSWIDTH_4_BYTES;
7481f858040SNicolas Royer dd->dma_lch_in.dma_conf.dst_maxburst = 1;
7491f858040SNicolas Royer dd->dma_lch_in.dma_conf.dst_addr_width =
7501f858040SNicolas Royer DMA_SLAVE_BUSWIDTH_4_BYTES;
7511f858040SNicolas Royer dd->dma_lch_in.dma_conf.device_fc = false;
7521f858040SNicolas Royer
75345a536e3SPeter Ujfalusi dd->dma_lch_out.chan = dma_request_chan(dd->dev, "rx");
75445a536e3SPeter Ujfalusi if (IS_ERR(dd->dma_lch_out.chan)) {
75545a536e3SPeter Ujfalusi ret = PTR_ERR(dd->dma_lch_out.chan);
7561f858040SNicolas Royer goto err_dma_out;
75745a536e3SPeter Ujfalusi }
7581f858040SNicolas Royer
7591f858040SNicolas Royer dd->dma_lch_out.dma_conf.src_addr = dd->phys_base +
7601f858040SNicolas Royer TDES_ODATA1R;
7611f858040SNicolas Royer dd->dma_lch_out.dma_conf.src_maxburst = 1;
7621f858040SNicolas Royer dd->dma_lch_out.dma_conf.src_addr_width =
7631f858040SNicolas Royer DMA_SLAVE_BUSWIDTH_4_BYTES;
7641f858040SNicolas Royer dd->dma_lch_out.dma_conf.dst_maxburst = 1;
7651f858040SNicolas Royer dd->dma_lch_out.dma_conf.dst_addr_width =
7661f858040SNicolas Royer DMA_SLAVE_BUSWIDTH_4_BYTES;
7671f858040SNicolas Royer dd->dma_lch_out.dma_conf.device_fc = false;
7681f858040SNicolas Royer
7691f858040SNicolas Royer return 0;
7701f858040SNicolas Royer
7711f858040SNicolas Royer err_dma_out:
7721f858040SNicolas Royer dma_release_channel(dd->dma_lch_in.chan);
7731f858040SNicolas Royer err_dma_in:
774e9ce6aeeSTudor Ambarus dev_err(dd->dev, "no DMA channel available\n");
77545a536e3SPeter Ujfalusi return ret;
7761f858040SNicolas Royer }
7771f858040SNicolas Royer
atmel_tdes_dma_cleanup(struct atmel_tdes_dev * dd)7781f858040SNicolas Royer static void atmel_tdes_dma_cleanup(struct atmel_tdes_dev *dd)
7791f858040SNicolas Royer {
7801f858040SNicolas Royer dma_release_channel(dd->dma_lch_in.chan);
7811f858040SNicolas Royer dma_release_channel(dd->dma_lch_out.chan);
78213802005SNicolas Royer }
78313802005SNicolas Royer
atmel_des_setkey(struct crypto_skcipher * tfm,const u8 * key,unsigned int keylen)784967d4910SArd Biesheuvel static int atmel_des_setkey(struct crypto_skcipher *tfm, const u8 *key,
78513802005SNicolas Royer unsigned int keylen)
78613802005SNicolas Royer {
787967d4910SArd Biesheuvel struct atmel_tdes_ctx *ctx = crypto_skcipher_ctx(tfm);
78892c203e2SArd Biesheuvel int err;
78913802005SNicolas Royer
790967d4910SArd Biesheuvel err = verify_skcipher_des_key(tfm, key);
79192c203e2SArd Biesheuvel if (err)
79292c203e2SArd Biesheuvel return err;
79313802005SNicolas Royer
79413802005SNicolas Royer memcpy(ctx->key, key, keylen);
79513802005SNicolas Royer ctx->keylen = keylen;
79613802005SNicolas Royer
79713802005SNicolas Royer return 0;
79813802005SNicolas Royer }
79913802005SNicolas Royer
atmel_tdes_setkey(struct crypto_skcipher * tfm,const u8 * key,unsigned int keylen)800967d4910SArd Biesheuvel static int atmel_tdes_setkey(struct crypto_skcipher *tfm, const u8 *key,
80113802005SNicolas Royer unsigned int keylen)
80213802005SNicolas Royer {
803967d4910SArd Biesheuvel struct atmel_tdes_ctx *ctx = crypto_skcipher_ctx(tfm);
80452ea3cd2SHerbert Xu int err;
80513802005SNicolas Royer
806967d4910SArd Biesheuvel err = verify_skcipher_des3_key(tfm, key);
80792c203e2SArd Biesheuvel if (err)
80852ea3cd2SHerbert Xu return err;
80913802005SNicolas Royer
81013802005SNicolas Royer memcpy(ctx->key, key, keylen);
81113802005SNicolas Royer ctx->keylen = keylen;
81213802005SNicolas Royer
81313802005SNicolas Royer return 0;
81413802005SNicolas Royer }
81513802005SNicolas Royer
atmel_tdes_ecb_encrypt(struct skcipher_request * req)816967d4910SArd Biesheuvel static int atmel_tdes_ecb_encrypt(struct skcipher_request *req)
81713802005SNicolas Royer {
818848572f8STudor Ambarus return atmel_tdes_crypt(req, TDES_FLAGS_ECB | TDES_FLAGS_ENCRYPT);
81913802005SNicolas Royer }
82013802005SNicolas Royer
atmel_tdes_ecb_decrypt(struct skcipher_request * req)821967d4910SArd Biesheuvel static int atmel_tdes_ecb_decrypt(struct skcipher_request *req)
82213802005SNicolas Royer {
823848572f8STudor Ambarus return atmel_tdes_crypt(req, TDES_FLAGS_ECB);
82413802005SNicolas Royer }
82513802005SNicolas Royer
atmel_tdes_cbc_encrypt(struct skcipher_request * req)826967d4910SArd Biesheuvel static int atmel_tdes_cbc_encrypt(struct skcipher_request *req)
82713802005SNicolas Royer {
828848572f8STudor Ambarus return atmel_tdes_crypt(req, TDES_FLAGS_CBC | TDES_FLAGS_ENCRYPT);
82913802005SNicolas Royer }
83013802005SNicolas Royer
atmel_tdes_cbc_decrypt(struct skcipher_request * req)831967d4910SArd Biesheuvel static int atmel_tdes_cbc_decrypt(struct skcipher_request *req)
83213802005SNicolas Royer {
83313802005SNicolas Royer return atmel_tdes_crypt(req, TDES_FLAGS_CBC);
83413802005SNicolas Royer }
atmel_tdes_cfb_encrypt(struct skcipher_request * req)835967d4910SArd Biesheuvel static int atmel_tdes_cfb_encrypt(struct skcipher_request *req)
83613802005SNicolas Royer {
837848572f8STudor Ambarus return atmel_tdes_crypt(req, TDES_FLAGS_CFB64 | TDES_FLAGS_ENCRYPT);
83813802005SNicolas Royer }
83913802005SNicolas Royer
atmel_tdes_cfb_decrypt(struct skcipher_request * req)840967d4910SArd Biesheuvel static int atmel_tdes_cfb_decrypt(struct skcipher_request *req)
84113802005SNicolas Royer {
842848572f8STudor Ambarus return atmel_tdes_crypt(req, TDES_FLAGS_CFB64);
84313802005SNicolas Royer }
84413802005SNicolas Royer
atmel_tdes_cfb8_encrypt(struct skcipher_request * req)845967d4910SArd Biesheuvel static int atmel_tdes_cfb8_encrypt(struct skcipher_request *req)
84613802005SNicolas Royer {
847848572f8STudor Ambarus return atmel_tdes_crypt(req, TDES_FLAGS_CFB8 | TDES_FLAGS_ENCRYPT);
84813802005SNicolas Royer }
84913802005SNicolas Royer
atmel_tdes_cfb8_decrypt(struct skcipher_request * req)850967d4910SArd Biesheuvel static int atmel_tdes_cfb8_decrypt(struct skcipher_request *req)
85113802005SNicolas Royer {
852848572f8STudor Ambarus return atmel_tdes_crypt(req, TDES_FLAGS_CFB8);
85313802005SNicolas Royer }
85413802005SNicolas Royer
atmel_tdes_cfb16_encrypt(struct skcipher_request * req)855967d4910SArd Biesheuvel static int atmel_tdes_cfb16_encrypt(struct skcipher_request *req)
85613802005SNicolas Royer {
857848572f8STudor Ambarus return atmel_tdes_crypt(req, TDES_FLAGS_CFB16 | TDES_FLAGS_ENCRYPT);
85813802005SNicolas Royer }
85913802005SNicolas Royer
atmel_tdes_cfb16_decrypt(struct skcipher_request * req)860967d4910SArd Biesheuvel static int atmel_tdes_cfb16_decrypt(struct skcipher_request *req)
86113802005SNicolas Royer {
862848572f8STudor Ambarus return atmel_tdes_crypt(req, TDES_FLAGS_CFB16);
86313802005SNicolas Royer }
86413802005SNicolas Royer
atmel_tdes_cfb32_encrypt(struct skcipher_request * req)865967d4910SArd Biesheuvel static int atmel_tdes_cfb32_encrypt(struct skcipher_request *req)
86613802005SNicolas Royer {
867848572f8STudor Ambarus return atmel_tdes_crypt(req, TDES_FLAGS_CFB32 | TDES_FLAGS_ENCRYPT);
86813802005SNicolas Royer }
86913802005SNicolas Royer
atmel_tdes_cfb32_decrypt(struct skcipher_request * req)870967d4910SArd Biesheuvel static int atmel_tdes_cfb32_decrypt(struct skcipher_request *req)
87113802005SNicolas Royer {
872848572f8STudor Ambarus return atmel_tdes_crypt(req, TDES_FLAGS_CFB32);
87313802005SNicolas Royer }
87413802005SNicolas Royer
atmel_tdes_ofb_encrypt(struct skcipher_request * req)875967d4910SArd Biesheuvel static int atmel_tdes_ofb_encrypt(struct skcipher_request *req)
87613802005SNicolas Royer {
877848572f8STudor Ambarus return atmel_tdes_crypt(req, TDES_FLAGS_OFB | TDES_FLAGS_ENCRYPT);
87813802005SNicolas Royer }
87913802005SNicolas Royer
atmel_tdes_ofb_decrypt(struct skcipher_request * req)880967d4910SArd Biesheuvel static int atmel_tdes_ofb_decrypt(struct skcipher_request *req)
88113802005SNicolas Royer {
88213802005SNicolas Royer return atmel_tdes_crypt(req, TDES_FLAGS_OFB);
88313802005SNicolas Royer }
88413802005SNicolas Royer
atmel_tdes_init_tfm(struct crypto_skcipher * tfm)885967d4910SArd Biesheuvel static int atmel_tdes_init_tfm(struct crypto_skcipher *tfm)
88613802005SNicolas Royer {
887967d4910SArd Biesheuvel struct atmel_tdes_ctx *ctx = crypto_skcipher_ctx(tfm);
888632a761aSTudor Ambarus
889632a761aSTudor Ambarus ctx->dd = atmel_tdes_dev_alloc();
890632a761aSTudor Ambarus if (!ctx->dd)
891632a761aSTudor Ambarus return -ENODEV;
8921f858040SNicolas Royer
893967d4910SArd Biesheuvel crypto_skcipher_set_reqsize(tfm, sizeof(struct atmel_tdes_reqctx));
89413802005SNicolas Royer
89513802005SNicolas Royer return 0;
89613802005SNicolas Royer }
89713802005SNicolas Royer
atmel_tdes_skcipher_alg_init(struct skcipher_alg * alg)898aebe5bd7STudor Ambarus static void atmel_tdes_skcipher_alg_init(struct skcipher_alg *alg)
899aebe5bd7STudor Ambarus {
900aebe5bd7STudor Ambarus alg->base.cra_priority = ATMEL_TDES_PRIORITY;
901aebe5bd7STudor Ambarus alg->base.cra_flags = CRYPTO_ALG_ASYNC;
902ed4424f2SJulia Lawall alg->base.cra_ctxsize = sizeof(struct atmel_tdes_ctx);
903aebe5bd7STudor Ambarus alg->base.cra_module = THIS_MODULE;
904aebe5bd7STudor Ambarus
905aebe5bd7STudor Ambarus alg->init = atmel_tdes_init_tfm;
906aebe5bd7STudor Ambarus }
907aebe5bd7STudor Ambarus
908967d4910SArd Biesheuvel static struct skcipher_alg tdes_algs[] = {
90913802005SNicolas Royer {
910967d4910SArd Biesheuvel .base.cra_name = "ecb(des)",
911967d4910SArd Biesheuvel .base.cra_driver_name = "atmel-ecb-des",
912967d4910SArd Biesheuvel .base.cra_blocksize = DES_BLOCK_SIZE,
913967d4910SArd Biesheuvel .base.cra_alignmask = 0x7,
914967d4910SArd Biesheuvel
91513802005SNicolas Royer .min_keysize = DES_KEY_SIZE,
91613802005SNicolas Royer .max_keysize = DES_KEY_SIZE,
91713802005SNicolas Royer .setkey = atmel_des_setkey,
91813802005SNicolas Royer .encrypt = atmel_tdes_ecb_encrypt,
91913802005SNicolas Royer .decrypt = atmel_tdes_ecb_decrypt,
92013802005SNicolas Royer },
92113802005SNicolas Royer {
922967d4910SArd Biesheuvel .base.cra_name = "cbc(des)",
923967d4910SArd Biesheuvel .base.cra_driver_name = "atmel-cbc-des",
924967d4910SArd Biesheuvel .base.cra_blocksize = DES_BLOCK_SIZE,
925967d4910SArd Biesheuvel .base.cra_alignmask = 0x7,
926967d4910SArd Biesheuvel
92713802005SNicolas Royer .min_keysize = DES_KEY_SIZE,
92813802005SNicolas Royer .max_keysize = DES_KEY_SIZE,
92913802005SNicolas Royer .ivsize = DES_BLOCK_SIZE,
93013802005SNicolas Royer .setkey = atmel_des_setkey,
93113802005SNicolas Royer .encrypt = atmel_tdes_cbc_encrypt,
93213802005SNicolas Royer .decrypt = atmel_tdes_cbc_decrypt,
93313802005SNicolas Royer },
93413802005SNicolas Royer {
935967d4910SArd Biesheuvel .base.cra_name = "cfb(des)",
936967d4910SArd Biesheuvel .base.cra_driver_name = "atmel-cfb-des",
937967d4910SArd Biesheuvel .base.cra_blocksize = DES_BLOCK_SIZE,
938967d4910SArd Biesheuvel .base.cra_alignmask = 0x7,
939967d4910SArd Biesheuvel
94013802005SNicolas Royer .min_keysize = DES_KEY_SIZE,
94113802005SNicolas Royer .max_keysize = DES_KEY_SIZE,
94213802005SNicolas Royer .ivsize = DES_BLOCK_SIZE,
94313802005SNicolas Royer .setkey = atmel_des_setkey,
94413802005SNicolas Royer .encrypt = atmel_tdes_cfb_encrypt,
94513802005SNicolas Royer .decrypt = atmel_tdes_cfb_decrypt,
94613802005SNicolas Royer },
94713802005SNicolas Royer {
948967d4910SArd Biesheuvel .base.cra_name = "cfb8(des)",
949967d4910SArd Biesheuvel .base.cra_driver_name = "atmel-cfb8-des",
950967d4910SArd Biesheuvel .base.cra_blocksize = CFB8_BLOCK_SIZE,
951967d4910SArd Biesheuvel .base.cra_alignmask = 0,
952967d4910SArd Biesheuvel
95313802005SNicolas Royer .min_keysize = DES_KEY_SIZE,
95413802005SNicolas Royer .max_keysize = DES_KEY_SIZE,
95513802005SNicolas Royer .ivsize = DES_BLOCK_SIZE,
95613802005SNicolas Royer .setkey = atmel_des_setkey,
95713802005SNicolas Royer .encrypt = atmel_tdes_cfb8_encrypt,
95813802005SNicolas Royer .decrypt = atmel_tdes_cfb8_decrypt,
95913802005SNicolas Royer },
96013802005SNicolas Royer {
961967d4910SArd Biesheuvel .base.cra_name = "cfb16(des)",
962967d4910SArd Biesheuvel .base.cra_driver_name = "atmel-cfb16-des",
963967d4910SArd Biesheuvel .base.cra_blocksize = CFB16_BLOCK_SIZE,
964967d4910SArd Biesheuvel .base.cra_alignmask = 0x1,
965967d4910SArd Biesheuvel
96613802005SNicolas Royer .min_keysize = DES_KEY_SIZE,
96713802005SNicolas Royer .max_keysize = DES_KEY_SIZE,
96813802005SNicolas Royer .ivsize = DES_BLOCK_SIZE,
96913802005SNicolas Royer .setkey = atmel_des_setkey,
97013802005SNicolas Royer .encrypt = atmel_tdes_cfb16_encrypt,
97113802005SNicolas Royer .decrypt = atmel_tdes_cfb16_decrypt,
97213802005SNicolas Royer },
97313802005SNicolas Royer {
974967d4910SArd Biesheuvel .base.cra_name = "cfb32(des)",
975967d4910SArd Biesheuvel .base.cra_driver_name = "atmel-cfb32-des",
976967d4910SArd Biesheuvel .base.cra_blocksize = CFB32_BLOCK_SIZE,
977967d4910SArd Biesheuvel .base.cra_alignmask = 0x3,
978967d4910SArd Biesheuvel
97913802005SNicolas Royer .min_keysize = DES_KEY_SIZE,
98013802005SNicolas Royer .max_keysize = DES_KEY_SIZE,
98113802005SNicolas Royer .ivsize = DES_BLOCK_SIZE,
98213802005SNicolas Royer .setkey = atmel_des_setkey,
98313802005SNicolas Royer .encrypt = atmel_tdes_cfb32_encrypt,
98413802005SNicolas Royer .decrypt = atmel_tdes_cfb32_decrypt,
98513802005SNicolas Royer },
98613802005SNicolas Royer {
987967d4910SArd Biesheuvel .base.cra_name = "ofb(des)",
988967d4910SArd Biesheuvel .base.cra_driver_name = "atmel-ofb-des",
98976d579f2STudor Ambarus .base.cra_blocksize = 1,
990967d4910SArd Biesheuvel .base.cra_alignmask = 0x7,
991967d4910SArd Biesheuvel
99213802005SNicolas Royer .min_keysize = DES_KEY_SIZE,
99313802005SNicolas Royer .max_keysize = DES_KEY_SIZE,
99413802005SNicolas Royer .ivsize = DES_BLOCK_SIZE,
99513802005SNicolas Royer .setkey = atmel_des_setkey,
99613802005SNicolas Royer .encrypt = atmel_tdes_ofb_encrypt,
99713802005SNicolas Royer .decrypt = atmel_tdes_ofb_decrypt,
99813802005SNicolas Royer },
99913802005SNicolas Royer {
1000967d4910SArd Biesheuvel .base.cra_name = "ecb(des3_ede)",
1001967d4910SArd Biesheuvel .base.cra_driver_name = "atmel-ecb-tdes",
1002967d4910SArd Biesheuvel .base.cra_blocksize = DES_BLOCK_SIZE,
1003967d4910SArd Biesheuvel .base.cra_alignmask = 0x7,
1004967d4910SArd Biesheuvel
1005967d4910SArd Biesheuvel .min_keysize = DES3_EDE_KEY_SIZE,
1006967d4910SArd Biesheuvel .max_keysize = DES3_EDE_KEY_SIZE,
100713802005SNicolas Royer .setkey = atmel_tdes_setkey,
100813802005SNicolas Royer .encrypt = atmel_tdes_ecb_encrypt,
100913802005SNicolas Royer .decrypt = atmel_tdes_ecb_decrypt,
101013802005SNicolas Royer },
101113802005SNicolas Royer {
1012967d4910SArd Biesheuvel .base.cra_name = "cbc(des3_ede)",
1013967d4910SArd Biesheuvel .base.cra_driver_name = "atmel-cbc-tdes",
1014967d4910SArd Biesheuvel .base.cra_blocksize = DES_BLOCK_SIZE,
1015967d4910SArd Biesheuvel .base.cra_alignmask = 0x7,
1016967d4910SArd Biesheuvel
1017967d4910SArd Biesheuvel .min_keysize = DES3_EDE_KEY_SIZE,
1018967d4910SArd Biesheuvel .max_keysize = DES3_EDE_KEY_SIZE,
101913802005SNicolas Royer .setkey = atmel_tdes_setkey,
102013802005SNicolas Royer .encrypt = atmel_tdes_cbc_encrypt,
102113802005SNicolas Royer .decrypt = atmel_tdes_cbc_decrypt,
1022967d4910SArd Biesheuvel .ivsize = DES_BLOCK_SIZE,
102313802005SNicolas Royer },
102413802005SNicolas Royer {
1025967d4910SArd Biesheuvel .base.cra_name = "ofb(des3_ede)",
1026967d4910SArd Biesheuvel .base.cra_driver_name = "atmel-ofb-tdes",
1027967d4910SArd Biesheuvel .base.cra_blocksize = DES_BLOCK_SIZE,
1028967d4910SArd Biesheuvel .base.cra_alignmask = 0x7,
1029967d4910SArd Biesheuvel
1030967d4910SArd Biesheuvel .min_keysize = DES3_EDE_KEY_SIZE,
1031967d4910SArd Biesheuvel .max_keysize = DES3_EDE_KEY_SIZE,
103213802005SNicolas Royer .setkey = atmel_tdes_setkey,
103313802005SNicolas Royer .encrypt = atmel_tdes_ofb_encrypt,
103413802005SNicolas Royer .decrypt = atmel_tdes_ofb_decrypt,
1035967d4910SArd Biesheuvel .ivsize = DES_BLOCK_SIZE,
103613802005SNicolas Royer },
103713802005SNicolas Royer };
103813802005SNicolas Royer
atmel_tdes_queue_task(unsigned long data)103913802005SNicolas Royer static void atmel_tdes_queue_task(unsigned long data)
104013802005SNicolas Royer {
104113802005SNicolas Royer struct atmel_tdes_dev *dd = (struct atmel_tdes_dev *)data;
104213802005SNicolas Royer
104313802005SNicolas Royer atmel_tdes_handle_queue(dd, NULL);
104413802005SNicolas Royer }
104513802005SNicolas Royer
atmel_tdes_done_task(unsigned long data)104613802005SNicolas Royer static void atmel_tdes_done_task(unsigned long data)
104713802005SNicolas Royer {
104813802005SNicolas Royer struct atmel_tdes_dev *dd = (struct atmel_tdes_dev *) data;
104913802005SNicolas Royer int err;
105013802005SNicolas Royer
10511f858040SNicolas Royer if (!(dd->flags & TDES_FLAGS_DMA))
10521f858040SNicolas Royer err = atmel_tdes_crypt_pdc_stop(dd);
10531f858040SNicolas Royer else
105413802005SNicolas Royer err = atmel_tdes_crypt_dma_stop(dd);
105513802005SNicolas Royer
105613802005SNicolas Royer if (dd->total && !err) {
10571f858040SNicolas Royer if (dd->flags & TDES_FLAGS_FAST) {
10581f858040SNicolas Royer dd->in_sg = sg_next(dd->in_sg);
10591f858040SNicolas Royer dd->out_sg = sg_next(dd->out_sg);
10601f858040SNicolas Royer if (!dd->in_sg || !dd->out_sg)
10611f858040SNicolas Royer err = -EINVAL;
10621f858040SNicolas Royer }
106313802005SNicolas Royer if (!err)
10641f858040SNicolas Royer err = atmel_tdes_crypt_start(dd);
10651f858040SNicolas Royer if (!err)
10661f858040SNicolas Royer return; /* DMA started. Not fininishing. */
106713802005SNicolas Royer }
106813802005SNicolas Royer
106913802005SNicolas Royer atmel_tdes_finish_req(dd, err);
107013802005SNicolas Royer atmel_tdes_handle_queue(dd, NULL);
107113802005SNicolas Royer }
107213802005SNicolas Royer
atmel_tdes_irq(int irq,void * dev_id)107313802005SNicolas Royer static irqreturn_t atmel_tdes_irq(int irq, void *dev_id)
107413802005SNicolas Royer {
107513802005SNicolas Royer struct atmel_tdes_dev *tdes_dd = dev_id;
107613802005SNicolas Royer u32 reg;
107713802005SNicolas Royer
107813802005SNicolas Royer reg = atmel_tdes_read(tdes_dd, TDES_ISR);
107913802005SNicolas Royer if (reg & atmel_tdes_read(tdes_dd, TDES_IMR)) {
108013802005SNicolas Royer atmel_tdes_write(tdes_dd, TDES_IDR, reg);
108113802005SNicolas Royer if (TDES_FLAGS_BUSY & tdes_dd->flags)
108213802005SNicolas Royer tasklet_schedule(&tdes_dd->done_task);
108313802005SNicolas Royer else
108413802005SNicolas Royer dev_warn(tdes_dd->dev, "TDES interrupt when no active requests.\n");
108513802005SNicolas Royer return IRQ_HANDLED;
108613802005SNicolas Royer }
108713802005SNicolas Royer
108813802005SNicolas Royer return IRQ_NONE;
108913802005SNicolas Royer }
109013802005SNicolas Royer
atmel_tdes_unregister_algs(struct atmel_tdes_dev * dd)109113802005SNicolas Royer static void atmel_tdes_unregister_algs(struct atmel_tdes_dev *dd)
109213802005SNicolas Royer {
109313802005SNicolas Royer int i;
109413802005SNicolas Royer
109513802005SNicolas Royer for (i = 0; i < ARRAY_SIZE(tdes_algs); i++)
1096967d4910SArd Biesheuvel crypto_unregister_skcipher(&tdes_algs[i]);
109713802005SNicolas Royer }
109813802005SNicolas Royer
atmel_tdes_register_algs(struct atmel_tdes_dev * dd)109913802005SNicolas Royer static int atmel_tdes_register_algs(struct atmel_tdes_dev *dd)
110013802005SNicolas Royer {
110113802005SNicolas Royer int err, i, j;
110213802005SNicolas Royer
110313802005SNicolas Royer for (i = 0; i < ARRAY_SIZE(tdes_algs); i++) {
1104aebe5bd7STudor Ambarus atmel_tdes_skcipher_alg_init(&tdes_algs[i]);
1105aebe5bd7STudor Ambarus
1106967d4910SArd Biesheuvel err = crypto_register_skcipher(&tdes_algs[i]);
110713802005SNicolas Royer if (err)
110813802005SNicolas Royer goto err_tdes_algs;
110913802005SNicolas Royer }
111013802005SNicolas Royer
111113802005SNicolas Royer return 0;
111213802005SNicolas Royer
111313802005SNicolas Royer err_tdes_algs:
111413802005SNicolas Royer for (j = 0; j < i; j++)
1115967d4910SArd Biesheuvel crypto_unregister_skcipher(&tdes_algs[j]);
111613802005SNicolas Royer
111713802005SNicolas Royer return err;
111813802005SNicolas Royer }
111913802005SNicolas Royer
atmel_tdes_get_cap(struct atmel_tdes_dev * dd)11201f858040SNicolas Royer static void atmel_tdes_get_cap(struct atmel_tdes_dev *dd)
11211f858040SNicolas Royer {
11221f858040SNicolas Royer
11231f858040SNicolas Royer dd->caps.has_dma = 0;
11241f858040SNicolas Royer dd->caps.has_cfb_3keys = 0;
11251f858040SNicolas Royer
11261f858040SNicolas Royer /* keep only major version number */
11271f858040SNicolas Royer switch (dd->hw_version & 0xf00) {
1128e8bf24bdSTudor Ambarus case 0x800:
11291f858040SNicolas Royer case 0x700:
11301f858040SNicolas Royer dd->caps.has_dma = 1;
11311f858040SNicolas Royer dd->caps.has_cfb_3keys = 1;
11321f858040SNicolas Royer break;
11331f858040SNicolas Royer case 0x600:
11341f858040SNicolas Royer break;
11351f858040SNicolas Royer default:
11361f858040SNicolas Royer dev_warn(dd->dev,
11371f858040SNicolas Royer "Unmanaged tdes version, set minimum capabilities\n");
11381f858040SNicolas Royer break;
11391f858040SNicolas Royer }
11401f858040SNicolas Royer }
11411f858040SNicolas Royer
114284c8976bSNicolas Ferre static const struct of_device_id atmel_tdes_dt_ids[] = {
114384c8976bSNicolas Ferre { .compatible = "atmel,at91sam9g46-tdes" },
114484c8976bSNicolas Ferre { /* sentinel */ }
114584c8976bSNicolas Ferre };
114684c8976bSNicolas Ferre MODULE_DEVICE_TABLE(of, atmel_tdes_dt_ids);
114784c8976bSNicolas Ferre
atmel_tdes_probe(struct platform_device * pdev)114849cfe4dbSGreg Kroah-Hartman static int atmel_tdes_probe(struct platform_device *pdev)
114913802005SNicolas Royer {
115013802005SNicolas Royer struct atmel_tdes_dev *tdes_dd;
115113802005SNicolas Royer struct device *dev = &pdev->dev;
115213802005SNicolas Royer struct resource *tdes_res;
115313802005SNicolas Royer int err;
115413802005SNicolas Royer
1155c659d07fSPramod Gurav tdes_dd = devm_kmalloc(&pdev->dev, sizeof(*tdes_dd), GFP_KERNEL);
1156c9063a02STudor Ambarus if (!tdes_dd)
1157c9063a02STudor Ambarus return -ENOMEM;
115813802005SNicolas Royer
115913802005SNicolas Royer tdes_dd->dev = dev;
116013802005SNicolas Royer
116113802005SNicolas Royer platform_set_drvdata(pdev, tdes_dd);
116213802005SNicolas Royer
116313802005SNicolas Royer INIT_LIST_HEAD(&tdes_dd->list);
11641d1b9163SLeilei Zhao spin_lock_init(&tdes_dd->lock);
116513802005SNicolas Royer
116613802005SNicolas Royer tasklet_init(&tdes_dd->done_task, atmel_tdes_done_task,
116713802005SNicolas Royer (unsigned long)tdes_dd);
116813802005SNicolas Royer tasklet_init(&tdes_dd->queue_task, atmel_tdes_queue_task,
116913802005SNicolas Royer (unsigned long)tdes_dd);
117013802005SNicolas Royer
117113802005SNicolas Royer crypto_init_queue(&tdes_dd->queue, ATMEL_TDES_QUEUE_LENGTH);
117213802005SNicolas Royer
117332f91bb3SYangtao Li tdes_dd->io_base = devm_platform_get_and_ioremap_resource(pdev, 0, &tdes_res);
117432f91bb3SYangtao Li if (IS_ERR(tdes_dd->io_base)) {
117532f91bb3SYangtao Li err = PTR_ERR(tdes_dd->io_base);
1176e7836518STudor Ambarus goto err_tasklet_kill;
117713802005SNicolas Royer }
117813802005SNicolas Royer tdes_dd->phys_base = tdes_res->start;
117913802005SNicolas Royer
118013802005SNicolas Royer /* Get the IRQ */
118113802005SNicolas Royer tdes_dd->irq = platform_get_irq(pdev, 0);
118213802005SNicolas Royer if (tdes_dd->irq < 0) {
118313802005SNicolas Royer err = tdes_dd->irq;
1184e7836518STudor Ambarus goto err_tasklet_kill;
118513802005SNicolas Royer }
118613802005SNicolas Royer
1187b0e8b341SLABBE Corentin err = devm_request_irq(&pdev->dev, tdes_dd->irq, atmel_tdes_irq,
1188b0e8b341SLABBE Corentin IRQF_SHARED, "atmel-tdes", tdes_dd);
118913802005SNicolas Royer if (err) {
119013802005SNicolas Royer dev_err(dev, "unable to request tdes irq.\n");
1191e7836518STudor Ambarus goto err_tasklet_kill;
119213802005SNicolas Royer }
119313802005SNicolas Royer
119413802005SNicolas Royer /* Initializing the clock */
1195b0e8b341SLABBE Corentin tdes_dd->iclk = devm_clk_get(&pdev->dev, "tdes_clk");
119613802005SNicolas Royer if (IS_ERR(tdes_dd->iclk)) {
1197be208356SColin Ian King dev_err(dev, "clock initialization failed.\n");
119813802005SNicolas Royer err = PTR_ERR(tdes_dd->iclk);
1199e7836518STudor Ambarus goto err_tasklet_kill;
120013802005SNicolas Royer }
120113802005SNicolas Royer
12020efe58f3STudor Ambarus err = atmel_tdes_hw_version_init(tdes_dd);
12030efe58f3STudor Ambarus if (err)
1204e7836518STudor Ambarus goto err_tasklet_kill;
12051f858040SNicolas Royer
12061f858040SNicolas Royer atmel_tdes_get_cap(tdes_dd);
12071f858040SNicolas Royer
12081f858040SNicolas Royer err = atmel_tdes_buff_init(tdes_dd);
12091f858040SNicolas Royer if (err)
1210e7836518STudor Ambarus goto err_tasklet_kill;
12111f858040SNicolas Royer
12121f858040SNicolas Royer if (tdes_dd->caps.has_dma) {
1213827a98dfSTudor Ambarus err = atmel_tdes_dma_init(tdes_dd);
121413802005SNicolas Royer if (err)
1215e7836518STudor Ambarus goto err_buff_cleanup;
121684c8976bSNicolas Ferre
121784c8976bSNicolas Ferre dev_info(dev, "using %s, %s for DMA transfers\n",
121884c8976bSNicolas Ferre dma_chan_name(tdes_dd->dma_lch_in.chan),
121984c8976bSNicolas Ferre dma_chan_name(tdes_dd->dma_lch_out.chan));
12201f858040SNicolas Royer }
122113802005SNicolas Royer
122213802005SNicolas Royer spin_lock(&atmel_tdes.lock);
122313802005SNicolas Royer list_add_tail(&tdes_dd->list, &atmel_tdes.dev_list);
122413802005SNicolas Royer spin_unlock(&atmel_tdes.lock);
122513802005SNicolas Royer
122613802005SNicolas Royer err = atmel_tdes_register_algs(tdes_dd);
122713802005SNicolas Royer if (err)
122813802005SNicolas Royer goto err_algs;
122913802005SNicolas Royer
123013802005SNicolas Royer dev_info(dev, "Atmel DES/TDES\n");
123113802005SNicolas Royer
123213802005SNicolas Royer return 0;
123313802005SNicolas Royer
123413802005SNicolas Royer err_algs:
123513802005SNicolas Royer spin_lock(&atmel_tdes.lock);
123613802005SNicolas Royer list_del(&tdes_dd->list);
123713802005SNicolas Royer spin_unlock(&atmel_tdes.lock);
12381f858040SNicolas Royer if (tdes_dd->caps.has_dma)
123913802005SNicolas Royer atmel_tdes_dma_cleanup(tdes_dd);
1240e7836518STudor Ambarus err_buff_cleanup:
12411f858040SNicolas Royer atmel_tdes_buff_cleanup(tdes_dd);
1242e7836518STudor Ambarus err_tasklet_kill:
124313802005SNicolas Royer tasklet_kill(&tdes_dd->done_task);
124413802005SNicolas Royer tasklet_kill(&tdes_dd->queue_task);
124513802005SNicolas Royer
124613802005SNicolas Royer return err;
124713802005SNicolas Royer }
124813802005SNicolas Royer
atmel_tdes_remove(struct platform_device * pdev)124949cfe4dbSGreg Kroah-Hartman static int atmel_tdes_remove(struct platform_device *pdev)
125013802005SNicolas Royer {
12516c14a965SClaudiu Beznea struct atmel_tdes_dev *tdes_dd = platform_get_drvdata(pdev);
1252515f4fc6SUwe Kleine-König
125313802005SNicolas Royer spin_lock(&atmel_tdes.lock);
125413802005SNicolas Royer list_del(&tdes_dd->list);
125513802005SNicolas Royer spin_unlock(&atmel_tdes.lock);
125613802005SNicolas Royer
125713802005SNicolas Royer atmel_tdes_unregister_algs(tdes_dd);
125813802005SNicolas Royer
125913802005SNicolas Royer tasklet_kill(&tdes_dd->done_task);
126013802005SNicolas Royer tasklet_kill(&tdes_dd->queue_task);
126113802005SNicolas Royer
12621f858040SNicolas Royer if (tdes_dd->caps.has_dma)
126313802005SNicolas Royer atmel_tdes_dma_cleanup(tdes_dd);
126413802005SNicolas Royer
12651f858040SNicolas Royer atmel_tdes_buff_cleanup(tdes_dd);
12661f858040SNicolas Royer
126713802005SNicolas Royer return 0;
126813802005SNicolas Royer }
126913802005SNicolas Royer
127013802005SNicolas Royer static struct platform_driver atmel_tdes_driver = {
127113802005SNicolas Royer .probe = atmel_tdes_probe,
127249cfe4dbSGreg Kroah-Hartman .remove = atmel_tdes_remove,
127313802005SNicolas Royer .driver = {
127413802005SNicolas Royer .name = "atmel_tdes",
1275*b0cc7491SRob Herring .of_match_table = atmel_tdes_dt_ids,
127613802005SNicolas Royer },
127713802005SNicolas Royer };
127813802005SNicolas Royer
127913802005SNicolas Royer module_platform_driver(atmel_tdes_driver);
128013802005SNicolas Royer
128113802005SNicolas Royer MODULE_DESCRIPTION("Atmel DES/TDES hw acceleration support.");
128213802005SNicolas Royer MODULE_LICENSE("GPL v2");
128313802005SNicolas Royer MODULE_AUTHOR("Nicolas Royer - Eukréa Electromatique");
1284