xref: /openbmc/linux/drivers/crypto/atmel-tdes.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
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