xref: /openbmc/linux/drivers/crypto/atmel-sha.c (revision 9b52d55f)
1ebc82efaSNicolas Royer /*
2ebc82efaSNicolas Royer  * Cryptographic API.
3ebc82efaSNicolas Royer  *
4ebc82efaSNicolas Royer  * Support for ATMEL SHA1/SHA256 HW acceleration.
5ebc82efaSNicolas Royer  *
6ebc82efaSNicolas Royer  * Copyright (c) 2012 Eukréa Electromatique - ATMEL
7ebc82efaSNicolas Royer  * Author: Nicolas Royer <nicolas@eukrea.com>
8ebc82efaSNicolas Royer  *
9ebc82efaSNicolas Royer  * This program is free software; you can redistribute it and/or modify
10ebc82efaSNicolas Royer  * it under the terms of the GNU General Public License version 2 as published
11ebc82efaSNicolas Royer  * by the Free Software Foundation.
12ebc82efaSNicolas Royer  *
13ebc82efaSNicolas Royer  * Some ideas are from omap-sham.c drivers.
14ebc82efaSNicolas Royer  */
15ebc82efaSNicolas Royer 
16ebc82efaSNicolas Royer 
17ebc82efaSNicolas Royer #include <linux/kernel.h>
18ebc82efaSNicolas Royer #include <linux/module.h>
19ebc82efaSNicolas Royer #include <linux/slab.h>
20ebc82efaSNicolas Royer #include <linux/err.h>
21ebc82efaSNicolas Royer #include <linux/clk.h>
22ebc82efaSNicolas Royer #include <linux/io.h>
23ebc82efaSNicolas Royer #include <linux/hw_random.h>
24ebc82efaSNicolas Royer #include <linux/platform_device.h>
25ebc82efaSNicolas Royer 
26ebc82efaSNicolas Royer #include <linux/device.h>
27ebc82efaSNicolas Royer #include <linux/init.h>
28ebc82efaSNicolas Royer #include <linux/errno.h>
29ebc82efaSNicolas Royer #include <linux/interrupt.h>
30ebc82efaSNicolas Royer #include <linux/irq.h>
31ebc82efaSNicolas Royer #include <linux/scatterlist.h>
32ebc82efaSNicolas Royer #include <linux/dma-mapping.h>
33abfe7ae4SNicolas Ferre #include <linux/of_device.h>
34ebc82efaSNicolas Royer #include <linux/delay.h>
35ebc82efaSNicolas Royer #include <linux/crypto.h>
36ebc82efaSNicolas Royer #include <linux/cryptohash.h>
37ebc82efaSNicolas Royer #include <crypto/scatterwalk.h>
38ebc82efaSNicolas Royer #include <crypto/algapi.h>
39ebc82efaSNicolas Royer #include <crypto/sha.h>
40ebc82efaSNicolas Royer #include <crypto/hash.h>
41ebc82efaSNicolas Royer #include <crypto/internal/hash.h>
42d4905b38SNicolas Royer #include <linux/platform_data/crypto-atmel.h>
43ebc82efaSNicolas Royer #include "atmel-sha-regs.h"
44ebc82efaSNicolas Royer 
45ebc82efaSNicolas Royer /* SHA flags */
46ebc82efaSNicolas Royer #define SHA_FLAGS_BUSY			BIT(0)
47ebc82efaSNicolas Royer #define	SHA_FLAGS_FINAL			BIT(1)
48ebc82efaSNicolas Royer #define SHA_FLAGS_DMA_ACTIVE	BIT(2)
49ebc82efaSNicolas Royer #define SHA_FLAGS_OUTPUT_READY	BIT(3)
50ebc82efaSNicolas Royer #define SHA_FLAGS_INIT			BIT(4)
51ebc82efaSNicolas Royer #define SHA_FLAGS_CPU			BIT(5)
52ebc82efaSNicolas Royer #define SHA_FLAGS_DMA_READY		BIT(6)
53ebc82efaSNicolas Royer 
54ebc82efaSNicolas Royer #define SHA_FLAGS_FINUP		BIT(16)
55ebc82efaSNicolas Royer #define SHA_FLAGS_SG		BIT(17)
567cee3508SCyrille Pitchen #define SHA_FLAGS_ALGO_MASK	GENMASK(22, 18)
57ebc82efaSNicolas Royer #define SHA_FLAGS_SHA1		BIT(18)
58d4905b38SNicolas Royer #define SHA_FLAGS_SHA224	BIT(19)
59d4905b38SNicolas Royer #define SHA_FLAGS_SHA256	BIT(20)
60d4905b38SNicolas Royer #define SHA_FLAGS_SHA384	BIT(21)
61d4905b38SNicolas Royer #define SHA_FLAGS_SHA512	BIT(22)
62d4905b38SNicolas Royer #define SHA_FLAGS_ERROR		BIT(23)
63d4905b38SNicolas Royer #define SHA_FLAGS_PAD		BIT(24)
647cee3508SCyrille Pitchen #define SHA_FLAGS_RESTORE	BIT(25)
65ebc82efaSNicolas Royer 
66ebc82efaSNicolas Royer #define SHA_OP_UPDATE	1
67ebc82efaSNicolas Royer #define SHA_OP_FINAL	2
68ebc82efaSNicolas Royer 
69cc831d32SCyrille Pitchen #define SHA_BUFFER_LEN		(PAGE_SIZE / 16)
70ebc82efaSNicolas Royer 
71ebc82efaSNicolas Royer #define ATMEL_SHA_DMA_THRESHOLD		56
72ebc82efaSNicolas Royer 
73d4905b38SNicolas Royer struct atmel_sha_caps {
74d4905b38SNicolas Royer 	bool	has_dma;
75d4905b38SNicolas Royer 	bool	has_dualbuff;
76d4905b38SNicolas Royer 	bool	has_sha224;
77d4905b38SNicolas Royer 	bool	has_sha_384_512;
787cee3508SCyrille Pitchen 	bool	has_uihv;
79d4905b38SNicolas Royer };
80ebc82efaSNicolas Royer 
81ebc82efaSNicolas Royer struct atmel_sha_dev;
82ebc82efaSNicolas Royer 
83cc831d32SCyrille Pitchen /*
849c4274d9SCyrille Pitchen  * .statesize = sizeof(struct atmel_sha_reqctx) must be <= PAGE_SIZE / 8 as
85cc831d32SCyrille Pitchen  * tested by the ahash_prepare_alg() function.
86cc831d32SCyrille Pitchen  */
87ebc82efaSNicolas Royer struct atmel_sha_reqctx {
88ebc82efaSNicolas Royer 	struct atmel_sha_dev	*dd;
89ebc82efaSNicolas Royer 	unsigned long	flags;
90ebc82efaSNicolas Royer 	unsigned long	op;
91ebc82efaSNicolas Royer 
92d4905b38SNicolas Royer 	u8	digest[SHA512_DIGEST_SIZE] __aligned(sizeof(u32));
93d4905b38SNicolas Royer 	u64	digcnt[2];
94ebc82efaSNicolas Royer 	size_t	bufcnt;
95ebc82efaSNicolas Royer 	size_t	buflen;
96ebc82efaSNicolas Royer 	dma_addr_t	dma_addr;
97ebc82efaSNicolas Royer 
98ebc82efaSNicolas Royer 	/* walk state */
99ebc82efaSNicolas Royer 	struct scatterlist	*sg;
100ebc82efaSNicolas Royer 	unsigned int	offset;	/* offset in current sg */
101ebc82efaSNicolas Royer 	unsigned int	total;	/* total request */
102ebc82efaSNicolas Royer 
103d4905b38SNicolas Royer 	size_t block_size;
104d4905b38SNicolas Royer 
1059c4274d9SCyrille Pitchen 	u8 buffer[SHA_BUFFER_LEN + SHA512_BLOCK_SIZE] __aligned(sizeof(u32));
106ebc82efaSNicolas Royer };
107ebc82efaSNicolas Royer 
108ebc82efaSNicolas Royer struct atmel_sha_ctx {
109ebc82efaSNicolas Royer 	struct atmel_sha_dev	*dd;
110ebc82efaSNicolas Royer 
111ebc82efaSNicolas Royer 	unsigned long		flags;
112ebc82efaSNicolas Royer };
113ebc82efaSNicolas Royer 
114d4905b38SNicolas Royer #define ATMEL_SHA_QUEUE_LENGTH	50
115d4905b38SNicolas Royer 
116d4905b38SNicolas Royer struct atmel_sha_dma {
117d4905b38SNicolas Royer 	struct dma_chan			*chan;
118d4905b38SNicolas Royer 	struct dma_slave_config dma_conf;
119d4905b38SNicolas Royer };
120ebc82efaSNicolas Royer 
121ebc82efaSNicolas Royer struct atmel_sha_dev {
122ebc82efaSNicolas Royer 	struct list_head	list;
123ebc82efaSNicolas Royer 	unsigned long		phys_base;
124ebc82efaSNicolas Royer 	struct device		*dev;
125ebc82efaSNicolas Royer 	struct clk			*iclk;
126ebc82efaSNicolas Royer 	int					irq;
127ebc82efaSNicolas Royer 	void __iomem		*io_base;
128ebc82efaSNicolas Royer 
129ebc82efaSNicolas Royer 	spinlock_t		lock;
130ebc82efaSNicolas Royer 	int			err;
131ebc82efaSNicolas Royer 	struct tasklet_struct	done_task;
132f56809c3SCyrille Pitchen 	struct tasklet_struct	queue_task;
133ebc82efaSNicolas Royer 
134ebc82efaSNicolas Royer 	unsigned long		flags;
135ebc82efaSNicolas Royer 	struct crypto_queue	queue;
136ebc82efaSNicolas Royer 	struct ahash_request	*req;
137d4905b38SNicolas Royer 
138d4905b38SNicolas Royer 	struct atmel_sha_dma	dma_lch_in;
139d4905b38SNicolas Royer 
140d4905b38SNicolas Royer 	struct atmel_sha_caps	caps;
141d4905b38SNicolas Royer 
142d4905b38SNicolas Royer 	u32	hw_version;
143ebc82efaSNicolas Royer };
144ebc82efaSNicolas Royer 
145ebc82efaSNicolas Royer struct atmel_sha_drv {
146ebc82efaSNicolas Royer 	struct list_head	dev_list;
147ebc82efaSNicolas Royer 	spinlock_t		lock;
148ebc82efaSNicolas Royer };
149ebc82efaSNicolas Royer 
150ebc82efaSNicolas Royer static struct atmel_sha_drv atmel_sha = {
151ebc82efaSNicolas Royer 	.dev_list = LIST_HEAD_INIT(atmel_sha.dev_list),
152ebc82efaSNicolas Royer 	.lock = __SPIN_LOCK_UNLOCKED(atmel_sha.lock),
153ebc82efaSNicolas Royer };
154ebc82efaSNicolas Royer 
155ebc82efaSNicolas Royer static inline u32 atmel_sha_read(struct atmel_sha_dev *dd, u32 offset)
156ebc82efaSNicolas Royer {
157ebc82efaSNicolas Royer 	return readl_relaxed(dd->io_base + offset);
158ebc82efaSNicolas Royer }
159ebc82efaSNicolas Royer 
160ebc82efaSNicolas Royer static inline void atmel_sha_write(struct atmel_sha_dev *dd,
161ebc82efaSNicolas Royer 					u32 offset, u32 value)
162ebc82efaSNicolas Royer {
163ebc82efaSNicolas Royer 	writel_relaxed(value, dd->io_base + offset);
164ebc82efaSNicolas Royer }
165ebc82efaSNicolas Royer 
166ebc82efaSNicolas Royer static size_t atmel_sha_append_sg(struct atmel_sha_reqctx *ctx)
167ebc82efaSNicolas Royer {
168ebc82efaSNicolas Royer 	size_t count;
169ebc82efaSNicolas Royer 
170ebc82efaSNicolas Royer 	while ((ctx->bufcnt < ctx->buflen) && ctx->total) {
171ebc82efaSNicolas Royer 		count = min(ctx->sg->length - ctx->offset, ctx->total);
172ebc82efaSNicolas Royer 		count = min(count, ctx->buflen - ctx->bufcnt);
173ebc82efaSNicolas Royer 
174803eeae8SLeilei Zhao 		if (count <= 0) {
175803eeae8SLeilei Zhao 			/*
176803eeae8SLeilei Zhao 			* Check if count <= 0 because the buffer is full or
177803eeae8SLeilei Zhao 			* because the sg length is 0. In the latest case,
178803eeae8SLeilei Zhao 			* check if there is another sg in the list, a 0 length
179803eeae8SLeilei Zhao 			* sg doesn't necessarily mean the end of the sg list.
180803eeae8SLeilei Zhao 			*/
181803eeae8SLeilei Zhao 			if ((ctx->sg->length == 0) && !sg_is_last(ctx->sg)) {
182803eeae8SLeilei Zhao 				ctx->sg = sg_next(ctx->sg);
183803eeae8SLeilei Zhao 				continue;
184803eeae8SLeilei Zhao 			} else {
185ebc82efaSNicolas Royer 				break;
186803eeae8SLeilei Zhao 			}
187803eeae8SLeilei Zhao 		}
188ebc82efaSNicolas Royer 
189ebc82efaSNicolas Royer 		scatterwalk_map_and_copy(ctx->buffer + ctx->bufcnt, ctx->sg,
190ebc82efaSNicolas Royer 			ctx->offset, count, 0);
191ebc82efaSNicolas Royer 
192ebc82efaSNicolas Royer 		ctx->bufcnt += count;
193ebc82efaSNicolas Royer 		ctx->offset += count;
194ebc82efaSNicolas Royer 		ctx->total -= count;
195ebc82efaSNicolas Royer 
196ebc82efaSNicolas Royer 		if (ctx->offset == ctx->sg->length) {
197ebc82efaSNicolas Royer 			ctx->sg = sg_next(ctx->sg);
198ebc82efaSNicolas Royer 			if (ctx->sg)
199ebc82efaSNicolas Royer 				ctx->offset = 0;
200ebc82efaSNicolas Royer 			else
201ebc82efaSNicolas Royer 				ctx->total = 0;
202ebc82efaSNicolas Royer 		}
203ebc82efaSNicolas Royer 	}
204ebc82efaSNicolas Royer 
205ebc82efaSNicolas Royer 	return 0;
206ebc82efaSNicolas Royer }
207ebc82efaSNicolas Royer 
208ebc82efaSNicolas Royer /*
209d4905b38SNicolas Royer  * The purpose of this padding is to ensure that the padded message is a
210d4905b38SNicolas Royer  * multiple of 512 bits (SHA1/SHA224/SHA256) or 1024 bits (SHA384/SHA512).
211d4905b38SNicolas Royer  * The bit "1" is appended at the end of the message followed by
212d4905b38SNicolas Royer  * "padlen-1" zero bits. Then a 64 bits block (SHA1/SHA224/SHA256) or
213d4905b38SNicolas Royer  * 128 bits block (SHA384/SHA512) equals to the message length in bits
214d4905b38SNicolas Royer  * is appended.
215ebc82efaSNicolas Royer  *
216d4905b38SNicolas Royer  * For SHA1/SHA224/SHA256, padlen is calculated as followed:
217ebc82efaSNicolas Royer  *  - if message length < 56 bytes then padlen = 56 - message length
218ebc82efaSNicolas Royer  *  - else padlen = 64 + 56 - message length
219d4905b38SNicolas Royer  *
220d4905b38SNicolas Royer  * For SHA384/SHA512, padlen is calculated as followed:
221d4905b38SNicolas Royer  *  - if message length < 112 bytes then padlen = 112 - message length
222d4905b38SNicolas Royer  *  - else padlen = 128 + 112 - message length
223ebc82efaSNicolas Royer  */
224ebc82efaSNicolas Royer static void atmel_sha_fill_padding(struct atmel_sha_reqctx *ctx, int length)
225ebc82efaSNicolas Royer {
226ebc82efaSNicolas Royer 	unsigned int index, padlen;
227d4905b38SNicolas Royer 	u64 bits[2];
228d4905b38SNicolas Royer 	u64 size[2];
229ebc82efaSNicolas Royer 
230d4905b38SNicolas Royer 	size[0] = ctx->digcnt[0];
231d4905b38SNicolas Royer 	size[1] = ctx->digcnt[1];
232ebc82efaSNicolas Royer 
233d4905b38SNicolas Royer 	size[0] += ctx->bufcnt;
234d4905b38SNicolas Royer 	if (size[0] < ctx->bufcnt)
235d4905b38SNicolas Royer 		size[1]++;
236d4905b38SNicolas Royer 
237d4905b38SNicolas Royer 	size[0] += length;
238d4905b38SNicolas Royer 	if (size[0]  < length)
239d4905b38SNicolas Royer 		size[1]++;
240d4905b38SNicolas Royer 
241d4905b38SNicolas Royer 	bits[1] = cpu_to_be64(size[0] << 3);
242d4905b38SNicolas Royer 	bits[0] = cpu_to_be64(size[1] << 3 | size[0] >> 61);
243d4905b38SNicolas Royer 
244d4905b38SNicolas Royer 	if (ctx->flags & (SHA_FLAGS_SHA384 | SHA_FLAGS_SHA512)) {
245d4905b38SNicolas Royer 		index = ctx->bufcnt & 0x7f;
246d4905b38SNicolas Royer 		padlen = (index < 112) ? (112 - index) : ((128+112) - index);
247d4905b38SNicolas Royer 		*(ctx->buffer + ctx->bufcnt) = 0x80;
248d4905b38SNicolas Royer 		memset(ctx->buffer + ctx->bufcnt + 1, 0, padlen-1);
249d4905b38SNicolas Royer 		memcpy(ctx->buffer + ctx->bufcnt + padlen, bits, 16);
250d4905b38SNicolas Royer 		ctx->bufcnt += padlen + 16;
251d4905b38SNicolas Royer 		ctx->flags |= SHA_FLAGS_PAD;
252d4905b38SNicolas Royer 	} else {
253ebc82efaSNicolas Royer 		index = ctx->bufcnt & 0x3f;
254ebc82efaSNicolas Royer 		padlen = (index < 56) ? (56 - index) : ((64+56) - index);
255ebc82efaSNicolas Royer 		*(ctx->buffer + ctx->bufcnt) = 0x80;
256ebc82efaSNicolas Royer 		memset(ctx->buffer + ctx->bufcnt + 1, 0, padlen-1);
257d4905b38SNicolas Royer 		memcpy(ctx->buffer + ctx->bufcnt + padlen, &bits[1], 8);
258ebc82efaSNicolas Royer 		ctx->bufcnt += padlen + 8;
259ebc82efaSNicolas Royer 		ctx->flags |= SHA_FLAGS_PAD;
260ebc82efaSNicolas Royer 	}
261d4905b38SNicolas Royer }
262ebc82efaSNicolas Royer 
263ebc82efaSNicolas Royer static int atmel_sha_init(struct ahash_request *req)
264ebc82efaSNicolas Royer {
265ebc82efaSNicolas Royer 	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
266ebc82efaSNicolas Royer 	struct atmel_sha_ctx *tctx = crypto_ahash_ctx(tfm);
267ebc82efaSNicolas Royer 	struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
268ebc82efaSNicolas Royer 	struct atmel_sha_dev *dd = NULL;
269ebc82efaSNicolas Royer 	struct atmel_sha_dev *tmp;
270ebc82efaSNicolas Royer 
271ebc82efaSNicolas Royer 	spin_lock_bh(&atmel_sha.lock);
272ebc82efaSNicolas Royer 	if (!tctx->dd) {
273ebc82efaSNicolas Royer 		list_for_each_entry(tmp, &atmel_sha.dev_list, list) {
274ebc82efaSNicolas Royer 			dd = tmp;
275ebc82efaSNicolas Royer 			break;
276ebc82efaSNicolas Royer 		}
277ebc82efaSNicolas Royer 		tctx->dd = dd;
278ebc82efaSNicolas Royer 	} else {
279ebc82efaSNicolas Royer 		dd = tctx->dd;
280ebc82efaSNicolas Royer 	}
281ebc82efaSNicolas Royer 
282ebc82efaSNicolas Royer 	spin_unlock_bh(&atmel_sha.lock);
283ebc82efaSNicolas Royer 
284ebc82efaSNicolas Royer 	ctx->dd = dd;
285ebc82efaSNicolas Royer 
286ebc82efaSNicolas Royer 	ctx->flags = 0;
287ebc82efaSNicolas Royer 
288ebc82efaSNicolas Royer 	dev_dbg(dd->dev, "init: digest size: %d\n",
289ebc82efaSNicolas Royer 		crypto_ahash_digestsize(tfm));
290ebc82efaSNicolas Royer 
291d4905b38SNicolas Royer 	switch (crypto_ahash_digestsize(tfm)) {
292d4905b38SNicolas Royer 	case SHA1_DIGEST_SIZE:
293ebc82efaSNicolas Royer 		ctx->flags |= SHA_FLAGS_SHA1;
294d4905b38SNicolas Royer 		ctx->block_size = SHA1_BLOCK_SIZE;
295d4905b38SNicolas Royer 		break;
296d4905b38SNicolas Royer 	case SHA224_DIGEST_SIZE:
297d4905b38SNicolas Royer 		ctx->flags |= SHA_FLAGS_SHA224;
298d4905b38SNicolas Royer 		ctx->block_size = SHA224_BLOCK_SIZE;
299d4905b38SNicolas Royer 		break;
300d4905b38SNicolas Royer 	case SHA256_DIGEST_SIZE:
301ebc82efaSNicolas Royer 		ctx->flags |= SHA_FLAGS_SHA256;
302d4905b38SNicolas Royer 		ctx->block_size = SHA256_BLOCK_SIZE;
303d4905b38SNicolas Royer 		break;
304d4905b38SNicolas Royer 	case SHA384_DIGEST_SIZE:
305d4905b38SNicolas Royer 		ctx->flags |= SHA_FLAGS_SHA384;
306d4905b38SNicolas Royer 		ctx->block_size = SHA384_BLOCK_SIZE;
307d4905b38SNicolas Royer 		break;
308d4905b38SNicolas Royer 	case SHA512_DIGEST_SIZE:
309d4905b38SNicolas Royer 		ctx->flags |= SHA_FLAGS_SHA512;
310d4905b38SNicolas Royer 		ctx->block_size = SHA512_BLOCK_SIZE;
311d4905b38SNicolas Royer 		break;
312d4905b38SNicolas Royer 	default:
313d4905b38SNicolas Royer 		return -EINVAL;
314d4905b38SNicolas Royer 		break;
315d4905b38SNicolas Royer 	}
316ebc82efaSNicolas Royer 
317ebc82efaSNicolas Royer 	ctx->bufcnt = 0;
318d4905b38SNicolas Royer 	ctx->digcnt[0] = 0;
319d4905b38SNicolas Royer 	ctx->digcnt[1] = 0;
320ebc82efaSNicolas Royer 	ctx->buflen = SHA_BUFFER_LEN;
321ebc82efaSNicolas Royer 
322ebc82efaSNicolas Royer 	return 0;
323ebc82efaSNicolas Royer }
324ebc82efaSNicolas Royer 
325ebc82efaSNicolas Royer static void atmel_sha_write_ctrl(struct atmel_sha_dev *dd, int dma)
326ebc82efaSNicolas Royer {
327ebc82efaSNicolas Royer 	struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req);
3287cee3508SCyrille Pitchen 	u32 valmr = SHA_MR_MODE_AUTO;
3297cee3508SCyrille Pitchen 	unsigned int i, hashsize = 0;
330ebc82efaSNicolas Royer 
331ebc82efaSNicolas Royer 	if (likely(dma)) {
332d4905b38SNicolas Royer 		if (!dd->caps.has_dma)
333ebc82efaSNicolas Royer 			atmel_sha_write(dd, SHA_IER, SHA_INT_TXBUFE);
334ebc82efaSNicolas Royer 		valmr = SHA_MR_MODE_PDC;
335d4905b38SNicolas Royer 		if (dd->caps.has_dualbuff)
336d4905b38SNicolas Royer 			valmr |= SHA_MR_DUALBUFF;
337ebc82efaSNicolas Royer 	} else {
338ebc82efaSNicolas Royer 		atmel_sha_write(dd, SHA_IER, SHA_INT_DATARDY);
339ebc82efaSNicolas Royer 	}
340ebc82efaSNicolas Royer 
3417cee3508SCyrille Pitchen 	switch (ctx->flags & SHA_FLAGS_ALGO_MASK) {
3427cee3508SCyrille Pitchen 	case SHA_FLAGS_SHA1:
343d4905b38SNicolas Royer 		valmr |= SHA_MR_ALGO_SHA1;
3447cee3508SCyrille Pitchen 		hashsize = SHA1_DIGEST_SIZE;
3457cee3508SCyrille Pitchen 		break;
3467cee3508SCyrille Pitchen 
3477cee3508SCyrille Pitchen 	case SHA_FLAGS_SHA224:
348d4905b38SNicolas Royer 		valmr |= SHA_MR_ALGO_SHA224;
3497cee3508SCyrille Pitchen 		hashsize = SHA256_DIGEST_SIZE;
3507cee3508SCyrille Pitchen 		break;
3517cee3508SCyrille Pitchen 
3527cee3508SCyrille Pitchen 	case SHA_FLAGS_SHA256:
353ebc82efaSNicolas Royer 		valmr |= SHA_MR_ALGO_SHA256;
3547cee3508SCyrille Pitchen 		hashsize = SHA256_DIGEST_SIZE;
3557cee3508SCyrille Pitchen 		break;
3567cee3508SCyrille Pitchen 
3577cee3508SCyrille Pitchen 	case SHA_FLAGS_SHA384:
358d4905b38SNicolas Royer 		valmr |= SHA_MR_ALGO_SHA384;
3597cee3508SCyrille Pitchen 		hashsize = SHA512_DIGEST_SIZE;
3607cee3508SCyrille Pitchen 		break;
3617cee3508SCyrille Pitchen 
3627cee3508SCyrille Pitchen 	case SHA_FLAGS_SHA512:
363d4905b38SNicolas Royer 		valmr |= SHA_MR_ALGO_SHA512;
3647cee3508SCyrille Pitchen 		hashsize = SHA512_DIGEST_SIZE;
3657cee3508SCyrille Pitchen 		break;
3667cee3508SCyrille Pitchen 
3677cee3508SCyrille Pitchen 	default:
3687cee3508SCyrille Pitchen 		break;
3697cee3508SCyrille Pitchen 	}
370ebc82efaSNicolas Royer 
371ebc82efaSNicolas Royer 	/* Setting CR_FIRST only for the first iteration */
3727cee3508SCyrille Pitchen 	if (!(ctx->digcnt[0] || ctx->digcnt[1])) {
3737cee3508SCyrille Pitchen 		atmel_sha_write(dd, SHA_CR, SHA_CR_FIRST);
3747cee3508SCyrille Pitchen 	} else if (dd->caps.has_uihv && (ctx->flags & SHA_FLAGS_RESTORE)) {
3757cee3508SCyrille Pitchen 		const u32 *hash = (const u32 *)ctx->digest;
376ebc82efaSNicolas Royer 
3777cee3508SCyrille Pitchen 		/*
3787cee3508SCyrille Pitchen 		 * Restore the hardware context: update the User Initialize
3797cee3508SCyrille Pitchen 		 * Hash Value (UIHV) with the value saved when the latest
3807cee3508SCyrille Pitchen 		 * 'update' operation completed on this very same crypto
3817cee3508SCyrille Pitchen 		 * request.
3827cee3508SCyrille Pitchen 		 */
3837cee3508SCyrille Pitchen 		ctx->flags &= ~SHA_FLAGS_RESTORE;
3847cee3508SCyrille Pitchen 		atmel_sha_write(dd, SHA_CR, SHA_CR_WUIHV);
3857cee3508SCyrille Pitchen 		for (i = 0; i < hashsize / sizeof(u32); ++i)
3867cee3508SCyrille Pitchen 			atmel_sha_write(dd, SHA_REG_DIN(i), hash[i]);
3877cee3508SCyrille Pitchen 		atmel_sha_write(dd, SHA_CR, SHA_CR_FIRST);
3887cee3508SCyrille Pitchen 		valmr |= SHA_MR_UIHV;
3897cee3508SCyrille Pitchen 	}
3907cee3508SCyrille Pitchen 	/*
3917cee3508SCyrille Pitchen 	 * WARNING: If the UIHV feature is not available, the hardware CANNOT
3927cee3508SCyrille Pitchen 	 * process concurrent requests: the internal registers used to store
3937cee3508SCyrille Pitchen 	 * the hash/digest are still set to the partial digest output values
3947cee3508SCyrille Pitchen 	 * computed during the latest round.
3957cee3508SCyrille Pitchen 	 */
3967cee3508SCyrille Pitchen 
397ebc82efaSNicolas Royer 	atmel_sha_write(dd, SHA_MR, valmr);
398ebc82efaSNicolas Royer }
399ebc82efaSNicolas Royer 
400ebc82efaSNicolas Royer static int atmel_sha_xmit_cpu(struct atmel_sha_dev *dd, const u8 *buf,
401ebc82efaSNicolas Royer 			      size_t length, int final)
402ebc82efaSNicolas Royer {
403ebc82efaSNicolas Royer 	struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req);
404ebc82efaSNicolas Royer 	int count, len32;
405ebc82efaSNicolas Royer 	const u32 *buffer = (const u32 *)buf;
406ebc82efaSNicolas Royer 
407d4905b38SNicolas Royer 	dev_dbg(dd->dev, "xmit_cpu: digcnt: 0x%llx 0x%llx, length: %d, final: %d\n",
408d4905b38SNicolas Royer 		ctx->digcnt[1], ctx->digcnt[0], length, final);
409ebc82efaSNicolas Royer 
410ebc82efaSNicolas Royer 	atmel_sha_write_ctrl(dd, 0);
411ebc82efaSNicolas Royer 
412ebc82efaSNicolas Royer 	/* should be non-zero before next lines to disable clocks later */
413d4905b38SNicolas Royer 	ctx->digcnt[0] += length;
414d4905b38SNicolas Royer 	if (ctx->digcnt[0] < length)
415d4905b38SNicolas Royer 		ctx->digcnt[1]++;
416ebc82efaSNicolas Royer 
417ebc82efaSNicolas Royer 	if (final)
418ebc82efaSNicolas Royer 		dd->flags |= SHA_FLAGS_FINAL; /* catch last interrupt */
419ebc82efaSNicolas Royer 
420ebc82efaSNicolas Royer 	len32 = DIV_ROUND_UP(length, sizeof(u32));
421ebc82efaSNicolas Royer 
422ebc82efaSNicolas Royer 	dd->flags |= SHA_FLAGS_CPU;
423ebc82efaSNicolas Royer 
424ebc82efaSNicolas Royer 	for (count = 0; count < len32; count++)
425ebc82efaSNicolas Royer 		atmel_sha_write(dd, SHA_REG_DIN(count), buffer[count]);
426ebc82efaSNicolas Royer 
427ebc82efaSNicolas Royer 	return -EINPROGRESS;
428ebc82efaSNicolas Royer }
429ebc82efaSNicolas Royer 
430ebc82efaSNicolas Royer static int atmel_sha_xmit_pdc(struct atmel_sha_dev *dd, dma_addr_t dma_addr1,
431ebc82efaSNicolas Royer 		size_t length1, dma_addr_t dma_addr2, size_t length2, int final)
432ebc82efaSNicolas Royer {
433ebc82efaSNicolas Royer 	struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req);
434ebc82efaSNicolas Royer 	int len32;
435ebc82efaSNicolas Royer 
436d4905b38SNicolas Royer 	dev_dbg(dd->dev, "xmit_pdc: digcnt: 0x%llx 0x%llx, length: %d, final: %d\n",
437d4905b38SNicolas Royer 		ctx->digcnt[1], ctx->digcnt[0], length1, final);
438ebc82efaSNicolas Royer 
439ebc82efaSNicolas Royer 	len32 = DIV_ROUND_UP(length1, sizeof(u32));
440ebc82efaSNicolas Royer 	atmel_sha_write(dd, SHA_PTCR, SHA_PTCR_TXTDIS);
441ebc82efaSNicolas Royer 	atmel_sha_write(dd, SHA_TPR, dma_addr1);
442ebc82efaSNicolas Royer 	atmel_sha_write(dd, SHA_TCR, len32);
443ebc82efaSNicolas Royer 
444ebc82efaSNicolas Royer 	len32 = DIV_ROUND_UP(length2, sizeof(u32));
445ebc82efaSNicolas Royer 	atmel_sha_write(dd, SHA_TNPR, dma_addr2);
446ebc82efaSNicolas Royer 	atmel_sha_write(dd, SHA_TNCR, len32);
447ebc82efaSNicolas Royer 
448ebc82efaSNicolas Royer 	atmel_sha_write_ctrl(dd, 1);
449ebc82efaSNicolas Royer 
450ebc82efaSNicolas Royer 	/* should be non-zero before next lines to disable clocks later */
451d4905b38SNicolas Royer 	ctx->digcnt[0] += length1;
452d4905b38SNicolas Royer 	if (ctx->digcnt[0] < length1)
453d4905b38SNicolas Royer 		ctx->digcnt[1]++;
454ebc82efaSNicolas Royer 
455ebc82efaSNicolas Royer 	if (final)
456ebc82efaSNicolas Royer 		dd->flags |= SHA_FLAGS_FINAL; /* catch last interrupt */
457ebc82efaSNicolas Royer 
458ebc82efaSNicolas Royer 	dd->flags |=  SHA_FLAGS_DMA_ACTIVE;
459ebc82efaSNicolas Royer 
460ebc82efaSNicolas Royer 	/* Start DMA transfer */
461ebc82efaSNicolas Royer 	atmel_sha_write(dd, SHA_PTCR, SHA_PTCR_TXTEN);
462ebc82efaSNicolas Royer 
463ebc82efaSNicolas Royer 	return -EINPROGRESS;
464ebc82efaSNicolas Royer }
465ebc82efaSNicolas Royer 
466d4905b38SNicolas Royer static void atmel_sha_dma_callback(void *data)
467d4905b38SNicolas Royer {
468d4905b38SNicolas Royer 	struct atmel_sha_dev *dd = data;
469d4905b38SNicolas Royer 
470d4905b38SNicolas Royer 	/* dma_lch_in - completed - wait DATRDY */
471d4905b38SNicolas Royer 	atmel_sha_write(dd, SHA_IER, SHA_INT_DATARDY);
472d4905b38SNicolas Royer }
473d4905b38SNicolas Royer 
474d4905b38SNicolas Royer static int atmel_sha_xmit_dma(struct atmel_sha_dev *dd, dma_addr_t dma_addr1,
475d4905b38SNicolas Royer 		size_t length1, dma_addr_t dma_addr2, size_t length2, int final)
476d4905b38SNicolas Royer {
477d4905b38SNicolas Royer 	struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req);
478d4905b38SNicolas Royer 	struct dma_async_tx_descriptor	*in_desc;
479d4905b38SNicolas Royer 	struct scatterlist sg[2];
480d4905b38SNicolas Royer 
481d4905b38SNicolas Royer 	dev_dbg(dd->dev, "xmit_dma: digcnt: 0x%llx 0x%llx, length: %d, final: %d\n",
482d4905b38SNicolas Royer 		ctx->digcnt[1], ctx->digcnt[0], length1, final);
483d4905b38SNicolas Royer 
484d4905b38SNicolas Royer 	dd->dma_lch_in.dma_conf.src_maxburst = 16;
485d4905b38SNicolas Royer 	dd->dma_lch_in.dma_conf.dst_maxburst = 16;
486d4905b38SNicolas Royer 
487d4905b38SNicolas Royer 	dmaengine_slave_config(dd->dma_lch_in.chan, &dd->dma_lch_in.dma_conf);
488d4905b38SNicolas Royer 
489d4905b38SNicolas Royer 	if (length2) {
490d4905b38SNicolas Royer 		sg_init_table(sg, 2);
491d4905b38SNicolas Royer 		sg_dma_address(&sg[0]) = dma_addr1;
492d4905b38SNicolas Royer 		sg_dma_len(&sg[0]) = length1;
493d4905b38SNicolas Royer 		sg_dma_address(&sg[1]) = dma_addr2;
494d4905b38SNicolas Royer 		sg_dma_len(&sg[1]) = length2;
495d4905b38SNicolas Royer 		in_desc = dmaengine_prep_slave_sg(dd->dma_lch_in.chan, sg, 2,
496d4905b38SNicolas Royer 			DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
497d4905b38SNicolas Royer 	} else {
498d4905b38SNicolas Royer 		sg_init_table(sg, 1);
499d4905b38SNicolas Royer 		sg_dma_address(&sg[0]) = dma_addr1;
500d4905b38SNicolas Royer 		sg_dma_len(&sg[0]) = length1;
501d4905b38SNicolas Royer 		in_desc = dmaengine_prep_slave_sg(dd->dma_lch_in.chan, sg, 1,
502d4905b38SNicolas Royer 			DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
503d4905b38SNicolas Royer 	}
504d4905b38SNicolas Royer 	if (!in_desc)
505d4905b38SNicolas Royer 		return -EINVAL;
506d4905b38SNicolas Royer 
507d4905b38SNicolas Royer 	in_desc->callback = atmel_sha_dma_callback;
508d4905b38SNicolas Royer 	in_desc->callback_param = dd;
509d4905b38SNicolas Royer 
510d4905b38SNicolas Royer 	atmel_sha_write_ctrl(dd, 1);
511d4905b38SNicolas Royer 
512d4905b38SNicolas Royer 	/* should be non-zero before next lines to disable clocks later */
513d4905b38SNicolas Royer 	ctx->digcnt[0] += length1;
514d4905b38SNicolas Royer 	if (ctx->digcnt[0] < length1)
515d4905b38SNicolas Royer 		ctx->digcnt[1]++;
516d4905b38SNicolas Royer 
517d4905b38SNicolas Royer 	if (final)
518d4905b38SNicolas Royer 		dd->flags |= SHA_FLAGS_FINAL; /* catch last interrupt */
519d4905b38SNicolas Royer 
520d4905b38SNicolas Royer 	dd->flags |=  SHA_FLAGS_DMA_ACTIVE;
521d4905b38SNicolas Royer 
522d4905b38SNicolas Royer 	/* Start DMA transfer */
523d4905b38SNicolas Royer 	dmaengine_submit(in_desc);
524d4905b38SNicolas Royer 	dma_async_issue_pending(dd->dma_lch_in.chan);
525d4905b38SNicolas Royer 
526d4905b38SNicolas Royer 	return -EINPROGRESS;
527d4905b38SNicolas Royer }
528d4905b38SNicolas Royer 
529d4905b38SNicolas Royer static int atmel_sha_xmit_start(struct atmel_sha_dev *dd, dma_addr_t dma_addr1,
530d4905b38SNicolas Royer 		size_t length1, dma_addr_t dma_addr2, size_t length2, int final)
531d4905b38SNicolas Royer {
532d4905b38SNicolas Royer 	if (dd->caps.has_dma)
533d4905b38SNicolas Royer 		return atmel_sha_xmit_dma(dd, dma_addr1, length1,
534d4905b38SNicolas Royer 				dma_addr2, length2, final);
535d4905b38SNicolas Royer 	else
536d4905b38SNicolas Royer 		return atmel_sha_xmit_pdc(dd, dma_addr1, length1,
537d4905b38SNicolas Royer 				dma_addr2, length2, final);
538d4905b38SNicolas Royer }
539d4905b38SNicolas Royer 
540ebc82efaSNicolas Royer static int atmel_sha_update_cpu(struct atmel_sha_dev *dd)
541ebc82efaSNicolas Royer {
542ebc82efaSNicolas Royer 	struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req);
543ebc82efaSNicolas Royer 	int bufcnt;
544ebc82efaSNicolas Royer 
545ebc82efaSNicolas Royer 	atmel_sha_append_sg(ctx);
546ebc82efaSNicolas Royer 	atmel_sha_fill_padding(ctx, 0);
547ebc82efaSNicolas Royer 	bufcnt = ctx->bufcnt;
548ebc82efaSNicolas Royer 	ctx->bufcnt = 0;
549ebc82efaSNicolas Royer 
550ebc82efaSNicolas Royer 	return atmel_sha_xmit_cpu(dd, ctx->buffer, bufcnt, 1);
551ebc82efaSNicolas Royer }
552ebc82efaSNicolas Royer 
553ebc82efaSNicolas Royer static int atmel_sha_xmit_dma_map(struct atmel_sha_dev *dd,
554ebc82efaSNicolas Royer 					struct atmel_sha_reqctx *ctx,
555ebc82efaSNicolas Royer 					size_t length, int final)
556ebc82efaSNicolas Royer {
557ebc82efaSNicolas Royer 	ctx->dma_addr = dma_map_single(dd->dev, ctx->buffer,
558d4905b38SNicolas Royer 				ctx->buflen + ctx->block_size, DMA_TO_DEVICE);
559ebc82efaSNicolas Royer 	if (dma_mapping_error(dd->dev, ctx->dma_addr)) {
560ebc82efaSNicolas Royer 		dev_err(dd->dev, "dma %u bytes error\n", ctx->buflen +
561d4905b38SNicolas Royer 				ctx->block_size);
562ebc82efaSNicolas Royer 		return -EINVAL;
563ebc82efaSNicolas Royer 	}
564ebc82efaSNicolas Royer 
565ebc82efaSNicolas Royer 	ctx->flags &= ~SHA_FLAGS_SG;
566ebc82efaSNicolas Royer 
567ebc82efaSNicolas Royer 	/* next call does not fail... so no unmap in the case of error */
568d4905b38SNicolas Royer 	return atmel_sha_xmit_start(dd, ctx->dma_addr, length, 0, 0, final);
569ebc82efaSNicolas Royer }
570ebc82efaSNicolas Royer 
571ebc82efaSNicolas Royer static int atmel_sha_update_dma_slow(struct atmel_sha_dev *dd)
572ebc82efaSNicolas Royer {
573ebc82efaSNicolas Royer 	struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req);
574ebc82efaSNicolas Royer 	unsigned int final;
575ebc82efaSNicolas Royer 	size_t count;
576ebc82efaSNicolas Royer 
577ebc82efaSNicolas Royer 	atmel_sha_append_sg(ctx);
578ebc82efaSNicolas Royer 
579ebc82efaSNicolas Royer 	final = (ctx->flags & SHA_FLAGS_FINUP) && !ctx->total;
580ebc82efaSNicolas Royer 
581d4905b38SNicolas Royer 	dev_dbg(dd->dev, "slow: bufcnt: %u, digcnt: 0x%llx 0x%llx, final: %d\n",
582d4905b38SNicolas Royer 		 ctx->bufcnt, ctx->digcnt[1], ctx->digcnt[0], final);
583ebc82efaSNicolas Royer 
584ebc82efaSNicolas Royer 	if (final)
585ebc82efaSNicolas Royer 		atmel_sha_fill_padding(ctx, 0);
586ebc82efaSNicolas Royer 
5870099286bSLudovic Desroches 	if (final || (ctx->bufcnt == ctx->buflen)) {
588ebc82efaSNicolas Royer 		count = ctx->bufcnt;
589ebc82efaSNicolas Royer 		ctx->bufcnt = 0;
590ebc82efaSNicolas Royer 		return atmel_sha_xmit_dma_map(dd, ctx, count, final);
591ebc82efaSNicolas Royer 	}
592ebc82efaSNicolas Royer 
593ebc82efaSNicolas Royer 	return 0;
594ebc82efaSNicolas Royer }
595ebc82efaSNicolas Royer 
596ebc82efaSNicolas Royer static int atmel_sha_update_dma_start(struct atmel_sha_dev *dd)
597ebc82efaSNicolas Royer {
598ebc82efaSNicolas Royer 	struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req);
599ebc82efaSNicolas Royer 	unsigned int length, final, tail;
600ebc82efaSNicolas Royer 	struct scatterlist *sg;
601ebc82efaSNicolas Royer 	unsigned int count;
602ebc82efaSNicolas Royer 
603ebc82efaSNicolas Royer 	if (!ctx->total)
604ebc82efaSNicolas Royer 		return 0;
605ebc82efaSNicolas Royer 
606ebc82efaSNicolas Royer 	if (ctx->bufcnt || ctx->offset)
607ebc82efaSNicolas Royer 		return atmel_sha_update_dma_slow(dd);
608ebc82efaSNicolas Royer 
609d4905b38SNicolas Royer 	dev_dbg(dd->dev, "fast: digcnt: 0x%llx 0x%llx, bufcnt: %u, total: %u\n",
610d4905b38SNicolas Royer 		ctx->digcnt[1], ctx->digcnt[0], ctx->bufcnt, ctx->total);
611ebc82efaSNicolas Royer 
612ebc82efaSNicolas Royer 	sg = ctx->sg;
613ebc82efaSNicolas Royer 
614ebc82efaSNicolas Royer 	if (!IS_ALIGNED(sg->offset, sizeof(u32)))
615ebc82efaSNicolas Royer 		return atmel_sha_update_dma_slow(dd);
616ebc82efaSNicolas Royer 
617d4905b38SNicolas Royer 	if (!sg_is_last(sg) && !IS_ALIGNED(sg->length, ctx->block_size))
618d4905b38SNicolas Royer 		/* size is not ctx->block_size aligned */
619ebc82efaSNicolas Royer 		return atmel_sha_update_dma_slow(dd);
620ebc82efaSNicolas Royer 
621ebc82efaSNicolas Royer 	length = min(ctx->total, sg->length);
622ebc82efaSNicolas Royer 
623ebc82efaSNicolas Royer 	if (sg_is_last(sg)) {
624ebc82efaSNicolas Royer 		if (!(ctx->flags & SHA_FLAGS_FINUP)) {
625d4905b38SNicolas Royer 			/* not last sg must be ctx->block_size aligned */
626d4905b38SNicolas Royer 			tail = length & (ctx->block_size - 1);
627ebc82efaSNicolas Royer 			length -= tail;
628ebc82efaSNicolas Royer 		}
629ebc82efaSNicolas Royer 	}
630ebc82efaSNicolas Royer 
631ebc82efaSNicolas Royer 	ctx->total -= length;
632ebc82efaSNicolas Royer 	ctx->offset = length; /* offset where to start slow */
633ebc82efaSNicolas Royer 
634ebc82efaSNicolas Royer 	final = (ctx->flags & SHA_FLAGS_FINUP) && !ctx->total;
635ebc82efaSNicolas Royer 
636ebc82efaSNicolas Royer 	/* Add padding */
637ebc82efaSNicolas Royer 	if (final) {
638d4905b38SNicolas Royer 		tail = length & (ctx->block_size - 1);
639ebc82efaSNicolas Royer 		length -= tail;
640ebc82efaSNicolas Royer 		ctx->total += tail;
641ebc82efaSNicolas Royer 		ctx->offset = length; /* offset where to start slow */
642ebc82efaSNicolas Royer 
643ebc82efaSNicolas Royer 		sg = ctx->sg;
644ebc82efaSNicolas Royer 		atmel_sha_append_sg(ctx);
645ebc82efaSNicolas Royer 
646ebc82efaSNicolas Royer 		atmel_sha_fill_padding(ctx, length);
647ebc82efaSNicolas Royer 
648ebc82efaSNicolas Royer 		ctx->dma_addr = dma_map_single(dd->dev, ctx->buffer,
649d4905b38SNicolas Royer 			ctx->buflen + ctx->block_size, DMA_TO_DEVICE);
650ebc82efaSNicolas Royer 		if (dma_mapping_error(dd->dev, ctx->dma_addr)) {
651ebc82efaSNicolas Royer 			dev_err(dd->dev, "dma %u bytes error\n",
652d4905b38SNicolas Royer 				ctx->buflen + ctx->block_size);
653ebc82efaSNicolas Royer 			return -EINVAL;
654ebc82efaSNicolas Royer 		}
655ebc82efaSNicolas Royer 
656ebc82efaSNicolas Royer 		if (length == 0) {
657ebc82efaSNicolas Royer 			ctx->flags &= ~SHA_FLAGS_SG;
658ebc82efaSNicolas Royer 			count = ctx->bufcnt;
659ebc82efaSNicolas Royer 			ctx->bufcnt = 0;
660d4905b38SNicolas Royer 			return atmel_sha_xmit_start(dd, ctx->dma_addr, count, 0,
661ebc82efaSNicolas Royer 					0, final);
662ebc82efaSNicolas Royer 		} else {
663ebc82efaSNicolas Royer 			ctx->sg = sg;
664ebc82efaSNicolas Royer 			if (!dma_map_sg(dd->dev, ctx->sg, 1,
665ebc82efaSNicolas Royer 				DMA_TO_DEVICE)) {
666ebc82efaSNicolas Royer 					dev_err(dd->dev, "dma_map_sg  error\n");
667ebc82efaSNicolas Royer 					return -EINVAL;
668ebc82efaSNicolas Royer 			}
669ebc82efaSNicolas Royer 
670ebc82efaSNicolas Royer 			ctx->flags |= SHA_FLAGS_SG;
671ebc82efaSNicolas Royer 
672ebc82efaSNicolas Royer 			count = ctx->bufcnt;
673ebc82efaSNicolas Royer 			ctx->bufcnt = 0;
674d4905b38SNicolas Royer 			return atmel_sha_xmit_start(dd, sg_dma_address(ctx->sg),
675ebc82efaSNicolas Royer 					length, ctx->dma_addr, count, final);
676ebc82efaSNicolas Royer 		}
677ebc82efaSNicolas Royer 	}
678ebc82efaSNicolas Royer 
679ebc82efaSNicolas Royer 	if (!dma_map_sg(dd->dev, ctx->sg, 1, DMA_TO_DEVICE)) {
680ebc82efaSNicolas Royer 		dev_err(dd->dev, "dma_map_sg  error\n");
681ebc82efaSNicolas Royer 		return -EINVAL;
682ebc82efaSNicolas Royer 	}
683ebc82efaSNicolas Royer 
684ebc82efaSNicolas Royer 	ctx->flags |= SHA_FLAGS_SG;
685ebc82efaSNicolas Royer 
686ebc82efaSNicolas Royer 	/* next call does not fail... so no unmap in the case of error */
687d4905b38SNicolas Royer 	return atmel_sha_xmit_start(dd, sg_dma_address(ctx->sg), length, 0,
688ebc82efaSNicolas Royer 								0, final);
689ebc82efaSNicolas Royer }
690ebc82efaSNicolas Royer 
691ebc82efaSNicolas Royer static int atmel_sha_update_dma_stop(struct atmel_sha_dev *dd)
692ebc82efaSNicolas Royer {
693ebc82efaSNicolas Royer 	struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req);
694ebc82efaSNicolas Royer 
695ebc82efaSNicolas Royer 	if (ctx->flags & SHA_FLAGS_SG) {
696ebc82efaSNicolas Royer 		dma_unmap_sg(dd->dev, ctx->sg, 1, DMA_TO_DEVICE);
697ebc82efaSNicolas Royer 		if (ctx->sg->length == ctx->offset) {
698ebc82efaSNicolas Royer 			ctx->sg = sg_next(ctx->sg);
699ebc82efaSNicolas Royer 			if (ctx->sg)
700ebc82efaSNicolas Royer 				ctx->offset = 0;
701ebc82efaSNicolas Royer 		}
702d4905b38SNicolas Royer 		if (ctx->flags & SHA_FLAGS_PAD) {
703ebc82efaSNicolas Royer 			dma_unmap_single(dd->dev, ctx->dma_addr,
704d4905b38SNicolas Royer 				ctx->buflen + ctx->block_size, DMA_TO_DEVICE);
705d4905b38SNicolas Royer 		}
706ebc82efaSNicolas Royer 	} else {
707ebc82efaSNicolas Royer 		dma_unmap_single(dd->dev, ctx->dma_addr, ctx->buflen +
708d4905b38SNicolas Royer 						ctx->block_size, DMA_TO_DEVICE);
709ebc82efaSNicolas Royer 	}
710ebc82efaSNicolas Royer 
711ebc82efaSNicolas Royer 	return 0;
712ebc82efaSNicolas Royer }
713ebc82efaSNicolas Royer 
714ebc82efaSNicolas Royer static int atmel_sha_update_req(struct atmel_sha_dev *dd)
715ebc82efaSNicolas Royer {
716ebc82efaSNicolas Royer 	struct ahash_request *req = dd->req;
717ebc82efaSNicolas Royer 	struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
718ebc82efaSNicolas Royer 	int err;
719ebc82efaSNicolas Royer 
720d4905b38SNicolas Royer 	dev_dbg(dd->dev, "update_req: total: %u, digcnt: 0x%llx 0x%llx\n",
721d4905b38SNicolas Royer 		ctx->total, ctx->digcnt[1], ctx->digcnt[0]);
722ebc82efaSNicolas Royer 
723ebc82efaSNicolas Royer 	if (ctx->flags & SHA_FLAGS_CPU)
724ebc82efaSNicolas Royer 		err = atmel_sha_update_cpu(dd);
725ebc82efaSNicolas Royer 	else
726ebc82efaSNicolas Royer 		err = atmel_sha_update_dma_start(dd);
727ebc82efaSNicolas Royer 
728ebc82efaSNicolas Royer 	/* wait for dma completion before can take more data */
729d4905b38SNicolas Royer 	dev_dbg(dd->dev, "update: err: %d, digcnt: 0x%llx 0%llx\n",
730d4905b38SNicolas Royer 			err, ctx->digcnt[1], ctx->digcnt[0]);
731ebc82efaSNicolas Royer 
732ebc82efaSNicolas Royer 	return err;
733ebc82efaSNicolas Royer }
734ebc82efaSNicolas Royer 
735ebc82efaSNicolas Royer static int atmel_sha_final_req(struct atmel_sha_dev *dd)
736ebc82efaSNicolas Royer {
737ebc82efaSNicolas Royer 	struct ahash_request *req = dd->req;
738ebc82efaSNicolas Royer 	struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
739ebc82efaSNicolas Royer 	int err = 0;
740ebc82efaSNicolas Royer 	int count;
741ebc82efaSNicolas Royer 
742ebc82efaSNicolas Royer 	if (ctx->bufcnt >= ATMEL_SHA_DMA_THRESHOLD) {
743ebc82efaSNicolas Royer 		atmel_sha_fill_padding(ctx, 0);
744ebc82efaSNicolas Royer 		count = ctx->bufcnt;
745ebc82efaSNicolas Royer 		ctx->bufcnt = 0;
746ebc82efaSNicolas Royer 		err = atmel_sha_xmit_dma_map(dd, ctx, count, 1);
747ebc82efaSNicolas Royer 	}
748ebc82efaSNicolas Royer 	/* faster to handle last block with cpu */
749ebc82efaSNicolas Royer 	else {
750ebc82efaSNicolas Royer 		atmel_sha_fill_padding(ctx, 0);
751ebc82efaSNicolas Royer 		count = ctx->bufcnt;
752ebc82efaSNicolas Royer 		ctx->bufcnt = 0;
753ebc82efaSNicolas Royer 		err = atmel_sha_xmit_cpu(dd, ctx->buffer, count, 1);
754ebc82efaSNicolas Royer 	}
755ebc82efaSNicolas Royer 
756ebc82efaSNicolas Royer 	dev_dbg(dd->dev, "final_req: err: %d\n", err);
757ebc82efaSNicolas Royer 
758ebc82efaSNicolas Royer 	return err;
759ebc82efaSNicolas Royer }
760ebc82efaSNicolas Royer 
761ebc82efaSNicolas Royer static void atmel_sha_copy_hash(struct ahash_request *req)
762ebc82efaSNicolas Royer {
763ebc82efaSNicolas Royer 	struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
764ebc82efaSNicolas Royer 	u32 *hash = (u32 *)ctx->digest;
7657cee3508SCyrille Pitchen 	unsigned int i, hashsize;
766ebc82efaSNicolas Royer 
7677cee3508SCyrille Pitchen 	switch (ctx->flags & SHA_FLAGS_ALGO_MASK) {
7687cee3508SCyrille Pitchen 	case SHA_FLAGS_SHA1:
7697cee3508SCyrille Pitchen 		hashsize = SHA1_DIGEST_SIZE;
7707cee3508SCyrille Pitchen 		break;
7717cee3508SCyrille Pitchen 
7727cee3508SCyrille Pitchen 	case SHA_FLAGS_SHA224:
7737cee3508SCyrille Pitchen 	case SHA_FLAGS_SHA256:
7747cee3508SCyrille Pitchen 		hashsize = SHA256_DIGEST_SIZE;
7757cee3508SCyrille Pitchen 		break;
7767cee3508SCyrille Pitchen 
7777cee3508SCyrille Pitchen 	case SHA_FLAGS_SHA384:
7787cee3508SCyrille Pitchen 	case SHA_FLAGS_SHA512:
7797cee3508SCyrille Pitchen 		hashsize = SHA512_DIGEST_SIZE;
7807cee3508SCyrille Pitchen 		break;
7817cee3508SCyrille Pitchen 
7827cee3508SCyrille Pitchen 	default:
7837cee3508SCyrille Pitchen 		/* Should not happen... */
7847cee3508SCyrille Pitchen 		return;
7857cee3508SCyrille Pitchen 	}
7867cee3508SCyrille Pitchen 
7877cee3508SCyrille Pitchen 	for (i = 0; i < hashsize / sizeof(u32); ++i)
788ebc82efaSNicolas Royer 		hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i));
7897cee3508SCyrille Pitchen 	ctx->flags |= SHA_FLAGS_RESTORE;
790ebc82efaSNicolas Royer }
791ebc82efaSNicolas Royer 
792ebc82efaSNicolas Royer static void atmel_sha_copy_ready_hash(struct ahash_request *req)
793ebc82efaSNicolas Royer {
794ebc82efaSNicolas Royer 	struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
795ebc82efaSNicolas Royer 
796ebc82efaSNicolas Royer 	if (!req->result)
797ebc82efaSNicolas Royer 		return;
798ebc82efaSNicolas Royer 
799d4905b38SNicolas Royer 	if (ctx->flags & SHA_FLAGS_SHA1)
800ebc82efaSNicolas Royer 		memcpy(req->result, ctx->digest, SHA1_DIGEST_SIZE);
801d4905b38SNicolas Royer 	else if (ctx->flags & SHA_FLAGS_SHA224)
802d4905b38SNicolas Royer 		memcpy(req->result, ctx->digest, SHA224_DIGEST_SIZE);
803d4905b38SNicolas Royer 	else if (ctx->flags & SHA_FLAGS_SHA256)
804ebc82efaSNicolas Royer 		memcpy(req->result, ctx->digest, SHA256_DIGEST_SIZE);
805d4905b38SNicolas Royer 	else if (ctx->flags & SHA_FLAGS_SHA384)
806d4905b38SNicolas Royer 		memcpy(req->result, ctx->digest, SHA384_DIGEST_SIZE);
807d4905b38SNicolas Royer 	else
808d4905b38SNicolas Royer 		memcpy(req->result, ctx->digest, SHA512_DIGEST_SIZE);
809ebc82efaSNicolas Royer }
810ebc82efaSNicolas Royer 
811ebc82efaSNicolas Royer static int atmel_sha_finish(struct ahash_request *req)
812ebc82efaSNicolas Royer {
813ebc82efaSNicolas Royer 	struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
814ebc82efaSNicolas Royer 	struct atmel_sha_dev *dd = ctx->dd;
815ebc82efaSNicolas Royer 
816d4905b38SNicolas Royer 	if (ctx->digcnt[0] || ctx->digcnt[1])
817ebc82efaSNicolas Royer 		atmel_sha_copy_ready_hash(req);
818ebc82efaSNicolas Royer 
819d4905b38SNicolas Royer 	dev_dbg(dd->dev, "digcnt: 0x%llx 0x%llx, bufcnt: %d\n", ctx->digcnt[1],
820d4905b38SNicolas Royer 		ctx->digcnt[0], ctx->bufcnt);
821ebc82efaSNicolas Royer 
822871b88a8SRahul Pathak 	return 0;
823ebc82efaSNicolas Royer }
824ebc82efaSNicolas Royer 
825ebc82efaSNicolas Royer static void atmel_sha_finish_req(struct ahash_request *req, int err)
826ebc82efaSNicolas Royer {
827ebc82efaSNicolas Royer 	struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
828ebc82efaSNicolas Royer 	struct atmel_sha_dev *dd = ctx->dd;
829ebc82efaSNicolas Royer 
830ebc82efaSNicolas Royer 	if (!err) {
831ebc82efaSNicolas Royer 		atmel_sha_copy_hash(req);
832ebc82efaSNicolas Royer 		if (SHA_FLAGS_FINAL & dd->flags)
833ebc82efaSNicolas Royer 			err = atmel_sha_finish(req);
834ebc82efaSNicolas Royer 	} else {
835ebc82efaSNicolas Royer 		ctx->flags |= SHA_FLAGS_ERROR;
836ebc82efaSNicolas Royer 	}
837ebc82efaSNicolas Royer 
838ebc82efaSNicolas Royer 	/* atomic operation is not needed here */
839ebc82efaSNicolas Royer 	dd->flags &= ~(SHA_FLAGS_BUSY | SHA_FLAGS_FINAL | SHA_FLAGS_CPU |
840ebc82efaSNicolas Royer 			SHA_FLAGS_DMA_READY | SHA_FLAGS_OUTPUT_READY);
841ebc82efaSNicolas Royer 
842ebc82efaSNicolas Royer 	clk_disable_unprepare(dd->iclk);
843ebc82efaSNicolas Royer 
844ebc82efaSNicolas Royer 	if (req->base.complete)
845ebc82efaSNicolas Royer 		req->base.complete(&req->base, err);
846ebc82efaSNicolas Royer 
847ebc82efaSNicolas Royer 	/* handle new request */
848f56809c3SCyrille Pitchen 	tasklet_schedule(&dd->queue_task);
849ebc82efaSNicolas Royer }
850ebc82efaSNicolas Royer 
851ebc82efaSNicolas Royer static int atmel_sha_hw_init(struct atmel_sha_dev *dd)
852ebc82efaSNicolas Royer {
8539d83d299SLABBE Corentin 	int err;
8549d83d299SLABBE Corentin 
8559d83d299SLABBE Corentin 	err = clk_prepare_enable(dd->iclk);
8569d83d299SLABBE Corentin 	if (err)
8579d83d299SLABBE Corentin 		return err;
858ebc82efaSNicolas Royer 
859d4905b38SNicolas Royer 	if (!(SHA_FLAGS_INIT & dd->flags)) {
860ebc82efaSNicolas Royer 		atmel_sha_write(dd, SHA_CR, SHA_CR_SWRST);
861ebc82efaSNicolas Royer 		dd->flags |= SHA_FLAGS_INIT;
862ebc82efaSNicolas Royer 		dd->err = 0;
863ebc82efaSNicolas Royer 	}
864ebc82efaSNicolas Royer 
865ebc82efaSNicolas Royer 	return 0;
866ebc82efaSNicolas Royer }
867ebc82efaSNicolas Royer 
868d4905b38SNicolas Royer static inline unsigned int atmel_sha_get_version(struct atmel_sha_dev *dd)
869d4905b38SNicolas Royer {
870d4905b38SNicolas Royer 	return atmel_sha_read(dd, SHA_HW_VERSION) & 0x00000fff;
871d4905b38SNicolas Royer }
872d4905b38SNicolas Royer 
873d4905b38SNicolas Royer static void atmel_sha_hw_version_init(struct atmel_sha_dev *dd)
874d4905b38SNicolas Royer {
875d4905b38SNicolas Royer 	atmel_sha_hw_init(dd);
876d4905b38SNicolas Royer 
877d4905b38SNicolas Royer 	dd->hw_version = atmel_sha_get_version(dd);
878d4905b38SNicolas Royer 
879d4905b38SNicolas Royer 	dev_info(dd->dev,
880d4905b38SNicolas Royer 			"version: 0x%x\n", dd->hw_version);
881d4905b38SNicolas Royer 
882d4905b38SNicolas Royer 	clk_disable_unprepare(dd->iclk);
883d4905b38SNicolas Royer }
884d4905b38SNicolas Royer 
885ebc82efaSNicolas Royer static int atmel_sha_handle_queue(struct atmel_sha_dev *dd,
886ebc82efaSNicolas Royer 				  struct ahash_request *req)
887ebc82efaSNicolas Royer {
888ebc82efaSNicolas Royer 	struct crypto_async_request *async_req, *backlog;
889ebc82efaSNicolas Royer 	struct atmel_sha_reqctx *ctx;
890ebc82efaSNicolas Royer 	unsigned long flags;
891ebc82efaSNicolas Royer 	int err = 0, ret = 0;
892ebc82efaSNicolas Royer 
893ebc82efaSNicolas Royer 	spin_lock_irqsave(&dd->lock, flags);
894ebc82efaSNicolas Royer 	if (req)
895ebc82efaSNicolas Royer 		ret = ahash_enqueue_request(&dd->queue, req);
896ebc82efaSNicolas Royer 
897ebc82efaSNicolas Royer 	if (SHA_FLAGS_BUSY & dd->flags) {
898ebc82efaSNicolas Royer 		spin_unlock_irqrestore(&dd->lock, flags);
899ebc82efaSNicolas Royer 		return ret;
900ebc82efaSNicolas Royer 	}
901ebc82efaSNicolas Royer 
902ebc82efaSNicolas Royer 	backlog = crypto_get_backlog(&dd->queue);
903ebc82efaSNicolas Royer 	async_req = crypto_dequeue_request(&dd->queue);
904ebc82efaSNicolas Royer 	if (async_req)
905ebc82efaSNicolas Royer 		dd->flags |= SHA_FLAGS_BUSY;
906ebc82efaSNicolas Royer 
907ebc82efaSNicolas Royer 	spin_unlock_irqrestore(&dd->lock, flags);
908ebc82efaSNicolas Royer 
909ebc82efaSNicolas Royer 	if (!async_req)
910ebc82efaSNicolas Royer 		return ret;
911ebc82efaSNicolas Royer 
912ebc82efaSNicolas Royer 	if (backlog)
913ebc82efaSNicolas Royer 		backlog->complete(backlog, -EINPROGRESS);
914ebc82efaSNicolas Royer 
915ebc82efaSNicolas Royer 	req = ahash_request_cast(async_req);
916ebc82efaSNicolas Royer 	dd->req = req;
917ebc82efaSNicolas Royer 	ctx = ahash_request_ctx(req);
918ebc82efaSNicolas Royer 
919ebc82efaSNicolas Royer 	dev_dbg(dd->dev, "handling new req, op: %lu, nbytes: %d\n",
920ebc82efaSNicolas Royer 						ctx->op, req->nbytes);
921ebc82efaSNicolas Royer 
922ebc82efaSNicolas Royer 	err = atmel_sha_hw_init(dd);
923ebc82efaSNicolas Royer 
924ebc82efaSNicolas Royer 	if (err)
925ebc82efaSNicolas Royer 		goto err1;
926ebc82efaSNicolas Royer 
927ebc82efaSNicolas Royer 	if (ctx->op == SHA_OP_UPDATE) {
928ebc82efaSNicolas Royer 		err = atmel_sha_update_req(dd);
929d4905b38SNicolas Royer 		if (err != -EINPROGRESS && (ctx->flags & SHA_FLAGS_FINUP))
930ebc82efaSNicolas Royer 			/* no final() after finup() */
931ebc82efaSNicolas Royer 			err = atmel_sha_final_req(dd);
932ebc82efaSNicolas Royer 	} else if (ctx->op == SHA_OP_FINAL) {
933ebc82efaSNicolas Royer 		err = atmel_sha_final_req(dd);
934ebc82efaSNicolas Royer 	}
935ebc82efaSNicolas Royer 
936ebc82efaSNicolas Royer err1:
937ebc82efaSNicolas Royer 	if (err != -EINPROGRESS)
938ebc82efaSNicolas Royer 		/* done_task will not finish it, so do it here */
939ebc82efaSNicolas Royer 		atmel_sha_finish_req(req, err);
940ebc82efaSNicolas Royer 
941ebc82efaSNicolas Royer 	dev_dbg(dd->dev, "exit, err: %d\n", err);
942ebc82efaSNicolas Royer 
943ebc82efaSNicolas Royer 	return ret;
944ebc82efaSNicolas Royer }
945ebc82efaSNicolas Royer 
946ebc82efaSNicolas Royer static int atmel_sha_enqueue(struct ahash_request *req, unsigned int op)
947ebc82efaSNicolas Royer {
948ebc82efaSNicolas Royer 	struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
949ebc82efaSNicolas Royer 	struct atmel_sha_ctx *tctx = crypto_tfm_ctx(req->base.tfm);
950ebc82efaSNicolas Royer 	struct atmel_sha_dev *dd = tctx->dd;
951ebc82efaSNicolas Royer 
952ebc82efaSNicolas Royer 	ctx->op = op;
953ebc82efaSNicolas Royer 
954ebc82efaSNicolas Royer 	return atmel_sha_handle_queue(dd, req);
955ebc82efaSNicolas Royer }
956ebc82efaSNicolas Royer 
957ebc82efaSNicolas Royer static int atmel_sha_update(struct ahash_request *req)
958ebc82efaSNicolas Royer {
959ebc82efaSNicolas Royer 	struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
960ebc82efaSNicolas Royer 
961ebc82efaSNicolas Royer 	if (!req->nbytes)
962ebc82efaSNicolas Royer 		return 0;
963ebc82efaSNicolas Royer 
964ebc82efaSNicolas Royer 	ctx->total = req->nbytes;
965ebc82efaSNicolas Royer 	ctx->sg = req->src;
966ebc82efaSNicolas Royer 	ctx->offset = 0;
967ebc82efaSNicolas Royer 
968ebc82efaSNicolas Royer 	if (ctx->flags & SHA_FLAGS_FINUP) {
969ebc82efaSNicolas Royer 		if (ctx->bufcnt + ctx->total < ATMEL_SHA_DMA_THRESHOLD)
970ebc82efaSNicolas Royer 			/* faster to use CPU for short transfers */
971ebc82efaSNicolas Royer 			ctx->flags |= SHA_FLAGS_CPU;
972ebc82efaSNicolas Royer 	} else if (ctx->bufcnt + ctx->total < ctx->buflen) {
973ebc82efaSNicolas Royer 		atmel_sha_append_sg(ctx);
974ebc82efaSNicolas Royer 		return 0;
975ebc82efaSNicolas Royer 	}
976ebc82efaSNicolas Royer 	return atmel_sha_enqueue(req, SHA_OP_UPDATE);
977ebc82efaSNicolas Royer }
978ebc82efaSNicolas Royer 
979ebc82efaSNicolas Royer static int atmel_sha_final(struct ahash_request *req)
980ebc82efaSNicolas Royer {
981ebc82efaSNicolas Royer 	struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
982ebc82efaSNicolas Royer 
983ebc82efaSNicolas Royer 	ctx->flags |= SHA_FLAGS_FINUP;
984ebc82efaSNicolas Royer 
985ebc82efaSNicolas Royer 	if (ctx->flags & SHA_FLAGS_ERROR)
986ebc82efaSNicolas Royer 		return 0; /* uncompleted hash is not needed */
987ebc82efaSNicolas Royer 
988ad84112aSCyrille Pitchen 	if (ctx->flags & SHA_FLAGS_PAD)
989ebc82efaSNicolas Royer 		/* copy ready hash (+ finalize hmac) */
990ebc82efaSNicolas Royer 		return atmel_sha_finish(req);
991ebc82efaSNicolas Royer 
992ad84112aSCyrille Pitchen 	return atmel_sha_enqueue(req, SHA_OP_FINAL);
993ebc82efaSNicolas Royer }
994ebc82efaSNicolas Royer 
995ebc82efaSNicolas Royer static int atmel_sha_finup(struct ahash_request *req)
996ebc82efaSNicolas Royer {
997ebc82efaSNicolas Royer 	struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
998ebc82efaSNicolas Royer 	int err1, err2;
999ebc82efaSNicolas Royer 
1000ebc82efaSNicolas Royer 	ctx->flags |= SHA_FLAGS_FINUP;
1001ebc82efaSNicolas Royer 
1002ebc82efaSNicolas Royer 	err1 = atmel_sha_update(req);
1003ebc82efaSNicolas Royer 	if (err1 == -EINPROGRESS || err1 == -EBUSY)
1004ebc82efaSNicolas Royer 		return err1;
1005ebc82efaSNicolas Royer 
1006ebc82efaSNicolas Royer 	/*
1007ebc82efaSNicolas Royer 	 * final() has to be always called to cleanup resources
1008ebc82efaSNicolas Royer 	 * even if udpate() failed, except EINPROGRESS
1009ebc82efaSNicolas Royer 	 */
1010ebc82efaSNicolas Royer 	err2 = atmel_sha_final(req);
1011ebc82efaSNicolas Royer 
1012ebc82efaSNicolas Royer 	return err1 ?: err2;
1013ebc82efaSNicolas Royer }
1014ebc82efaSNicolas Royer 
1015ebc82efaSNicolas Royer static int atmel_sha_digest(struct ahash_request *req)
1016ebc82efaSNicolas Royer {
1017ebc82efaSNicolas Royer 	return atmel_sha_init(req) ?: atmel_sha_finup(req);
1018ebc82efaSNicolas Royer }
1019ebc82efaSNicolas Royer 
1020cc831d32SCyrille Pitchen 
1021cc831d32SCyrille Pitchen static int atmel_sha_export(struct ahash_request *req, void *out)
1022cc831d32SCyrille Pitchen {
1023cc831d32SCyrille Pitchen 	const struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
1024cc831d32SCyrille Pitchen 
10259c4274d9SCyrille Pitchen 	memcpy(out, ctx, sizeof(*ctx));
1026cc831d32SCyrille Pitchen 	return 0;
1027cc831d32SCyrille Pitchen }
1028cc831d32SCyrille Pitchen 
1029cc831d32SCyrille Pitchen static int atmel_sha_import(struct ahash_request *req, const void *in)
1030cc831d32SCyrille Pitchen {
1031cc831d32SCyrille Pitchen 	struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
1032cc831d32SCyrille Pitchen 
10339c4274d9SCyrille Pitchen 	memcpy(ctx, in, sizeof(*ctx));
1034cc831d32SCyrille Pitchen 	return 0;
1035cc831d32SCyrille Pitchen }
1036cc831d32SCyrille Pitchen 
1037be95f0faSSvenning Sørensen static int atmel_sha_cra_init(struct crypto_tfm *tfm)
1038ebc82efaSNicolas Royer {
1039ebc82efaSNicolas Royer 	crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
10409c4274d9SCyrille Pitchen 				 sizeof(struct atmel_sha_reqctx));
1041ebc82efaSNicolas Royer 
1042ebc82efaSNicolas Royer 	return 0;
1043ebc82efaSNicolas Royer }
1044ebc82efaSNicolas Royer 
1045d4905b38SNicolas Royer static struct ahash_alg sha_1_256_algs[] = {
1046ebc82efaSNicolas Royer {
1047ebc82efaSNicolas Royer 	.init		= atmel_sha_init,
1048ebc82efaSNicolas Royer 	.update		= atmel_sha_update,
1049ebc82efaSNicolas Royer 	.final		= atmel_sha_final,
1050ebc82efaSNicolas Royer 	.finup		= atmel_sha_finup,
1051ebc82efaSNicolas Royer 	.digest		= atmel_sha_digest,
1052cc831d32SCyrille Pitchen 	.export		= atmel_sha_export,
1053cc831d32SCyrille Pitchen 	.import		= atmel_sha_import,
1054ebc82efaSNicolas Royer 	.halg = {
1055ebc82efaSNicolas Royer 		.digestsize	= SHA1_DIGEST_SIZE,
10569c4274d9SCyrille Pitchen 		.statesize	= sizeof(struct atmel_sha_reqctx),
1057ebc82efaSNicolas Royer 		.base	= {
1058ebc82efaSNicolas Royer 			.cra_name		= "sha1",
1059ebc82efaSNicolas Royer 			.cra_driver_name	= "atmel-sha1",
1060ebc82efaSNicolas Royer 			.cra_priority		= 100,
1061be95f0faSSvenning Sørensen 			.cra_flags		= CRYPTO_ALG_ASYNC,
1062ebc82efaSNicolas Royer 			.cra_blocksize		= SHA1_BLOCK_SIZE,
1063ebc82efaSNicolas Royer 			.cra_ctxsize		= sizeof(struct atmel_sha_ctx),
1064ebc82efaSNicolas Royer 			.cra_alignmask		= 0,
1065ebc82efaSNicolas Royer 			.cra_module		= THIS_MODULE,
1066ebc82efaSNicolas Royer 			.cra_init		= atmel_sha_cra_init,
1067ebc82efaSNicolas Royer 		}
1068ebc82efaSNicolas Royer 	}
1069ebc82efaSNicolas Royer },
1070ebc82efaSNicolas Royer {
1071ebc82efaSNicolas Royer 	.init		= atmel_sha_init,
1072ebc82efaSNicolas Royer 	.update		= atmel_sha_update,
1073ebc82efaSNicolas Royer 	.final		= atmel_sha_final,
1074ebc82efaSNicolas Royer 	.finup		= atmel_sha_finup,
1075ebc82efaSNicolas Royer 	.digest		= atmel_sha_digest,
1076cc831d32SCyrille Pitchen 	.export		= atmel_sha_export,
1077cc831d32SCyrille Pitchen 	.import		= atmel_sha_import,
1078ebc82efaSNicolas Royer 	.halg = {
1079ebc82efaSNicolas Royer 		.digestsize	= SHA256_DIGEST_SIZE,
10809c4274d9SCyrille Pitchen 		.statesize	= sizeof(struct atmel_sha_reqctx),
1081ebc82efaSNicolas Royer 		.base	= {
1082ebc82efaSNicolas Royer 			.cra_name		= "sha256",
1083ebc82efaSNicolas Royer 			.cra_driver_name	= "atmel-sha256",
1084ebc82efaSNicolas Royer 			.cra_priority		= 100,
1085be95f0faSSvenning Sørensen 			.cra_flags		= CRYPTO_ALG_ASYNC,
1086ebc82efaSNicolas Royer 			.cra_blocksize		= SHA256_BLOCK_SIZE,
1087ebc82efaSNicolas Royer 			.cra_ctxsize		= sizeof(struct atmel_sha_ctx),
1088ebc82efaSNicolas Royer 			.cra_alignmask		= 0,
1089ebc82efaSNicolas Royer 			.cra_module		= THIS_MODULE,
1090ebc82efaSNicolas Royer 			.cra_init		= atmel_sha_cra_init,
1091ebc82efaSNicolas Royer 		}
1092ebc82efaSNicolas Royer 	}
1093ebc82efaSNicolas Royer },
1094ebc82efaSNicolas Royer };
1095ebc82efaSNicolas Royer 
1096d4905b38SNicolas Royer static struct ahash_alg sha_224_alg = {
1097d4905b38SNicolas Royer 	.init		= atmel_sha_init,
1098d4905b38SNicolas Royer 	.update		= atmel_sha_update,
1099d4905b38SNicolas Royer 	.final		= atmel_sha_final,
1100d4905b38SNicolas Royer 	.finup		= atmel_sha_finup,
1101d4905b38SNicolas Royer 	.digest		= atmel_sha_digest,
1102cc831d32SCyrille Pitchen 	.export		= atmel_sha_export,
1103cc831d32SCyrille Pitchen 	.import		= atmel_sha_import,
1104d4905b38SNicolas Royer 	.halg = {
1105d4905b38SNicolas Royer 		.digestsize	= SHA224_DIGEST_SIZE,
11069c4274d9SCyrille Pitchen 		.statesize	= sizeof(struct atmel_sha_reqctx),
1107d4905b38SNicolas Royer 		.base	= {
1108d4905b38SNicolas Royer 			.cra_name		= "sha224",
1109d4905b38SNicolas Royer 			.cra_driver_name	= "atmel-sha224",
1110d4905b38SNicolas Royer 			.cra_priority		= 100,
1111be95f0faSSvenning Sørensen 			.cra_flags		= CRYPTO_ALG_ASYNC,
1112d4905b38SNicolas Royer 			.cra_blocksize		= SHA224_BLOCK_SIZE,
1113d4905b38SNicolas Royer 			.cra_ctxsize		= sizeof(struct atmel_sha_ctx),
1114d4905b38SNicolas Royer 			.cra_alignmask		= 0,
1115d4905b38SNicolas Royer 			.cra_module		= THIS_MODULE,
1116d4905b38SNicolas Royer 			.cra_init		= atmel_sha_cra_init,
1117d4905b38SNicolas Royer 		}
1118d4905b38SNicolas Royer 	}
1119d4905b38SNicolas Royer };
1120d4905b38SNicolas Royer 
1121d4905b38SNicolas Royer static struct ahash_alg sha_384_512_algs[] = {
1122d4905b38SNicolas Royer {
1123d4905b38SNicolas Royer 	.init		= atmel_sha_init,
1124d4905b38SNicolas Royer 	.update		= atmel_sha_update,
1125d4905b38SNicolas Royer 	.final		= atmel_sha_final,
1126d4905b38SNicolas Royer 	.finup		= atmel_sha_finup,
1127d4905b38SNicolas Royer 	.digest		= atmel_sha_digest,
1128cc831d32SCyrille Pitchen 	.export		= atmel_sha_export,
1129cc831d32SCyrille Pitchen 	.import		= atmel_sha_import,
1130d4905b38SNicolas Royer 	.halg = {
1131d4905b38SNicolas Royer 		.digestsize	= SHA384_DIGEST_SIZE,
11329c4274d9SCyrille Pitchen 		.statesize	= sizeof(struct atmel_sha_reqctx),
1133d4905b38SNicolas Royer 		.base	= {
1134d4905b38SNicolas Royer 			.cra_name		= "sha384",
1135d4905b38SNicolas Royer 			.cra_driver_name	= "atmel-sha384",
1136d4905b38SNicolas Royer 			.cra_priority		= 100,
1137be95f0faSSvenning Sørensen 			.cra_flags		= CRYPTO_ALG_ASYNC,
1138d4905b38SNicolas Royer 			.cra_blocksize		= SHA384_BLOCK_SIZE,
1139d4905b38SNicolas Royer 			.cra_ctxsize		= sizeof(struct atmel_sha_ctx),
1140d4905b38SNicolas Royer 			.cra_alignmask		= 0x3,
1141d4905b38SNicolas Royer 			.cra_module		= THIS_MODULE,
1142d4905b38SNicolas Royer 			.cra_init		= atmel_sha_cra_init,
1143d4905b38SNicolas Royer 		}
1144d4905b38SNicolas Royer 	}
1145d4905b38SNicolas Royer },
1146d4905b38SNicolas Royer {
1147d4905b38SNicolas Royer 	.init		= atmel_sha_init,
1148d4905b38SNicolas Royer 	.update		= atmel_sha_update,
1149d4905b38SNicolas Royer 	.final		= atmel_sha_final,
1150d4905b38SNicolas Royer 	.finup		= atmel_sha_finup,
1151d4905b38SNicolas Royer 	.digest		= atmel_sha_digest,
1152cc831d32SCyrille Pitchen 	.export		= atmel_sha_export,
1153cc831d32SCyrille Pitchen 	.import		= atmel_sha_import,
1154d4905b38SNicolas Royer 	.halg = {
1155d4905b38SNicolas Royer 		.digestsize	= SHA512_DIGEST_SIZE,
11569c4274d9SCyrille Pitchen 		.statesize	= sizeof(struct atmel_sha_reqctx),
1157d4905b38SNicolas Royer 		.base	= {
1158d4905b38SNicolas Royer 			.cra_name		= "sha512",
1159d4905b38SNicolas Royer 			.cra_driver_name	= "atmel-sha512",
1160d4905b38SNicolas Royer 			.cra_priority		= 100,
1161be95f0faSSvenning Sørensen 			.cra_flags		= CRYPTO_ALG_ASYNC,
1162d4905b38SNicolas Royer 			.cra_blocksize		= SHA512_BLOCK_SIZE,
1163d4905b38SNicolas Royer 			.cra_ctxsize		= sizeof(struct atmel_sha_ctx),
1164d4905b38SNicolas Royer 			.cra_alignmask		= 0x3,
1165d4905b38SNicolas Royer 			.cra_module		= THIS_MODULE,
1166d4905b38SNicolas Royer 			.cra_init		= atmel_sha_cra_init,
1167d4905b38SNicolas Royer 		}
1168d4905b38SNicolas Royer 	}
1169d4905b38SNicolas Royer },
1170d4905b38SNicolas Royer };
1171d4905b38SNicolas Royer 
1172f56809c3SCyrille Pitchen static void atmel_sha_queue_task(unsigned long data)
1173f56809c3SCyrille Pitchen {
1174f56809c3SCyrille Pitchen 	struct atmel_sha_dev *dd = (struct atmel_sha_dev *)data;
1175f56809c3SCyrille Pitchen 
1176f56809c3SCyrille Pitchen 	atmel_sha_handle_queue(dd, NULL);
1177f56809c3SCyrille Pitchen }
1178f56809c3SCyrille Pitchen 
1179ebc82efaSNicolas Royer static void atmel_sha_done_task(unsigned long data)
1180ebc82efaSNicolas Royer {
1181ebc82efaSNicolas Royer 	struct atmel_sha_dev *dd = (struct atmel_sha_dev *)data;
1182ebc82efaSNicolas Royer 	int err = 0;
1183ebc82efaSNicolas Royer 
1184ebc82efaSNicolas Royer 	if (SHA_FLAGS_CPU & dd->flags) {
1185ebc82efaSNicolas Royer 		if (SHA_FLAGS_OUTPUT_READY & dd->flags) {
1186ebc82efaSNicolas Royer 			dd->flags &= ~SHA_FLAGS_OUTPUT_READY;
1187ebc82efaSNicolas Royer 			goto finish;
1188ebc82efaSNicolas Royer 		}
1189ebc82efaSNicolas Royer 	} else if (SHA_FLAGS_DMA_READY & dd->flags) {
1190ebc82efaSNicolas Royer 		if (SHA_FLAGS_DMA_ACTIVE & dd->flags) {
1191ebc82efaSNicolas Royer 			dd->flags &= ~SHA_FLAGS_DMA_ACTIVE;
1192ebc82efaSNicolas Royer 			atmel_sha_update_dma_stop(dd);
1193ebc82efaSNicolas Royer 			if (dd->err) {
1194ebc82efaSNicolas Royer 				err = dd->err;
1195ebc82efaSNicolas Royer 				goto finish;
1196ebc82efaSNicolas Royer 			}
1197ebc82efaSNicolas Royer 		}
1198ebc82efaSNicolas Royer 		if (SHA_FLAGS_OUTPUT_READY & dd->flags) {
1199ebc82efaSNicolas Royer 			/* hash or semi-hash ready */
1200ebc82efaSNicolas Royer 			dd->flags &= ~(SHA_FLAGS_DMA_READY |
1201ebc82efaSNicolas Royer 						SHA_FLAGS_OUTPUT_READY);
1202ebc82efaSNicolas Royer 			err = atmel_sha_update_dma_start(dd);
1203ebc82efaSNicolas Royer 			if (err != -EINPROGRESS)
1204ebc82efaSNicolas Royer 				goto finish;
1205ebc82efaSNicolas Royer 		}
1206ebc82efaSNicolas Royer 	}
1207ebc82efaSNicolas Royer 	return;
1208ebc82efaSNicolas Royer 
1209ebc82efaSNicolas Royer finish:
1210ebc82efaSNicolas Royer 	/* finish curent request */
1211ebc82efaSNicolas Royer 	atmel_sha_finish_req(dd->req, err);
1212ebc82efaSNicolas Royer }
1213ebc82efaSNicolas Royer 
1214ebc82efaSNicolas Royer static irqreturn_t atmel_sha_irq(int irq, void *dev_id)
1215ebc82efaSNicolas Royer {
1216ebc82efaSNicolas Royer 	struct atmel_sha_dev *sha_dd = dev_id;
1217ebc82efaSNicolas Royer 	u32 reg;
1218ebc82efaSNicolas Royer 
1219ebc82efaSNicolas Royer 	reg = atmel_sha_read(sha_dd, SHA_ISR);
1220ebc82efaSNicolas Royer 	if (reg & atmel_sha_read(sha_dd, SHA_IMR)) {
1221ebc82efaSNicolas Royer 		atmel_sha_write(sha_dd, SHA_IDR, reg);
1222ebc82efaSNicolas Royer 		if (SHA_FLAGS_BUSY & sha_dd->flags) {
1223ebc82efaSNicolas Royer 			sha_dd->flags |= SHA_FLAGS_OUTPUT_READY;
1224ebc82efaSNicolas Royer 			if (!(SHA_FLAGS_CPU & sha_dd->flags))
1225ebc82efaSNicolas Royer 				sha_dd->flags |= SHA_FLAGS_DMA_READY;
1226ebc82efaSNicolas Royer 			tasklet_schedule(&sha_dd->done_task);
1227ebc82efaSNicolas Royer 		} else {
1228ebc82efaSNicolas Royer 			dev_warn(sha_dd->dev, "SHA interrupt when no active requests.\n");
1229ebc82efaSNicolas Royer 		}
1230ebc82efaSNicolas Royer 		return IRQ_HANDLED;
1231ebc82efaSNicolas Royer 	}
1232ebc82efaSNicolas Royer 
1233ebc82efaSNicolas Royer 	return IRQ_NONE;
1234ebc82efaSNicolas Royer }
1235ebc82efaSNicolas Royer 
1236ebc82efaSNicolas Royer static void atmel_sha_unregister_algs(struct atmel_sha_dev *dd)
1237ebc82efaSNicolas Royer {
1238ebc82efaSNicolas Royer 	int i;
1239ebc82efaSNicolas Royer 
1240d4905b38SNicolas Royer 	for (i = 0; i < ARRAY_SIZE(sha_1_256_algs); i++)
1241d4905b38SNicolas Royer 		crypto_unregister_ahash(&sha_1_256_algs[i]);
1242d4905b38SNicolas Royer 
1243d4905b38SNicolas Royer 	if (dd->caps.has_sha224)
1244d4905b38SNicolas Royer 		crypto_unregister_ahash(&sha_224_alg);
1245d4905b38SNicolas Royer 
1246d4905b38SNicolas Royer 	if (dd->caps.has_sha_384_512) {
1247d4905b38SNicolas Royer 		for (i = 0; i < ARRAY_SIZE(sha_384_512_algs); i++)
1248d4905b38SNicolas Royer 			crypto_unregister_ahash(&sha_384_512_algs[i]);
1249d4905b38SNicolas Royer 	}
1250ebc82efaSNicolas Royer }
1251ebc82efaSNicolas Royer 
1252ebc82efaSNicolas Royer static int atmel_sha_register_algs(struct atmel_sha_dev *dd)
1253ebc82efaSNicolas Royer {
1254ebc82efaSNicolas Royer 	int err, i, j;
1255ebc82efaSNicolas Royer 
1256d4905b38SNicolas Royer 	for (i = 0; i < ARRAY_SIZE(sha_1_256_algs); i++) {
1257d4905b38SNicolas Royer 		err = crypto_register_ahash(&sha_1_256_algs[i]);
1258ebc82efaSNicolas Royer 		if (err)
1259d4905b38SNicolas Royer 			goto err_sha_1_256_algs;
1260d4905b38SNicolas Royer 	}
1261d4905b38SNicolas Royer 
1262d4905b38SNicolas Royer 	if (dd->caps.has_sha224) {
1263d4905b38SNicolas Royer 		err = crypto_register_ahash(&sha_224_alg);
1264d4905b38SNicolas Royer 		if (err)
1265d4905b38SNicolas Royer 			goto err_sha_224_algs;
1266d4905b38SNicolas Royer 	}
1267d4905b38SNicolas Royer 
1268d4905b38SNicolas Royer 	if (dd->caps.has_sha_384_512) {
1269d4905b38SNicolas Royer 		for (i = 0; i < ARRAY_SIZE(sha_384_512_algs); i++) {
1270d4905b38SNicolas Royer 			err = crypto_register_ahash(&sha_384_512_algs[i]);
1271d4905b38SNicolas Royer 			if (err)
1272d4905b38SNicolas Royer 				goto err_sha_384_512_algs;
1273d4905b38SNicolas Royer 		}
1274ebc82efaSNicolas Royer 	}
1275ebc82efaSNicolas Royer 
1276ebc82efaSNicolas Royer 	return 0;
1277ebc82efaSNicolas Royer 
1278d4905b38SNicolas Royer err_sha_384_512_algs:
1279ebc82efaSNicolas Royer 	for (j = 0; j < i; j++)
1280d4905b38SNicolas Royer 		crypto_unregister_ahash(&sha_384_512_algs[j]);
1281d4905b38SNicolas Royer 	crypto_unregister_ahash(&sha_224_alg);
1282d4905b38SNicolas Royer err_sha_224_algs:
1283d4905b38SNicolas Royer 	i = ARRAY_SIZE(sha_1_256_algs);
1284d4905b38SNicolas Royer err_sha_1_256_algs:
1285d4905b38SNicolas Royer 	for (j = 0; j < i; j++)
1286d4905b38SNicolas Royer 		crypto_unregister_ahash(&sha_1_256_algs[j]);
1287ebc82efaSNicolas Royer 
1288ebc82efaSNicolas Royer 	return err;
1289ebc82efaSNicolas Royer }
1290ebc82efaSNicolas Royer 
1291d4905b38SNicolas Royer static bool atmel_sha_filter(struct dma_chan *chan, void *slave)
1292d4905b38SNicolas Royer {
1293d4905b38SNicolas Royer 	struct at_dma_slave	*sl = slave;
1294d4905b38SNicolas Royer 
1295d4905b38SNicolas Royer 	if (sl && sl->dma_dev == chan->device->dev) {
1296d4905b38SNicolas Royer 		chan->private = sl;
1297d4905b38SNicolas Royer 		return true;
1298d4905b38SNicolas Royer 	} else {
1299d4905b38SNicolas Royer 		return false;
1300d4905b38SNicolas Royer 	}
1301d4905b38SNicolas Royer }
1302d4905b38SNicolas Royer 
1303d4905b38SNicolas Royer static int atmel_sha_dma_init(struct atmel_sha_dev *dd,
1304d4905b38SNicolas Royer 				struct crypto_platform_data *pdata)
1305d4905b38SNicolas Royer {
1306d4905b38SNicolas Royer 	int err = -ENOMEM;
1307d4905b38SNicolas Royer 	dma_cap_mask_t mask_in;
1308d4905b38SNicolas Royer 
1309d4905b38SNicolas Royer 	/* Try to grab DMA channel */
1310d4905b38SNicolas Royer 	dma_cap_zero(mask_in);
1311d4905b38SNicolas Royer 	dma_cap_set(DMA_SLAVE, mask_in);
1312d4905b38SNicolas Royer 
1313abfe7ae4SNicolas Ferre 	dd->dma_lch_in.chan = dma_request_slave_channel_compat(mask_in,
1314abfe7ae4SNicolas Ferre 			atmel_sha_filter, &pdata->dma_slave->rxdata, dd->dev, "tx");
1315abfe7ae4SNicolas Ferre 	if (!dd->dma_lch_in.chan) {
1316abfe7ae4SNicolas Ferre 		dev_warn(dd->dev, "no DMA channel available\n");
1317d4905b38SNicolas Royer 		return err;
1318abfe7ae4SNicolas Ferre 	}
1319d4905b38SNicolas Royer 
1320d4905b38SNicolas Royer 	dd->dma_lch_in.dma_conf.direction = DMA_MEM_TO_DEV;
1321d4905b38SNicolas Royer 	dd->dma_lch_in.dma_conf.dst_addr = dd->phys_base +
1322d4905b38SNicolas Royer 		SHA_REG_DIN(0);
1323d4905b38SNicolas Royer 	dd->dma_lch_in.dma_conf.src_maxburst = 1;
1324d4905b38SNicolas Royer 	dd->dma_lch_in.dma_conf.src_addr_width =
1325d4905b38SNicolas Royer 		DMA_SLAVE_BUSWIDTH_4_BYTES;
1326d4905b38SNicolas Royer 	dd->dma_lch_in.dma_conf.dst_maxburst = 1;
1327d4905b38SNicolas Royer 	dd->dma_lch_in.dma_conf.dst_addr_width =
1328d4905b38SNicolas Royer 		DMA_SLAVE_BUSWIDTH_4_BYTES;
1329d4905b38SNicolas Royer 	dd->dma_lch_in.dma_conf.device_fc = false;
1330d4905b38SNicolas Royer 
1331d4905b38SNicolas Royer 	return 0;
1332d4905b38SNicolas Royer }
1333d4905b38SNicolas Royer 
1334d4905b38SNicolas Royer static void atmel_sha_dma_cleanup(struct atmel_sha_dev *dd)
1335d4905b38SNicolas Royer {
1336d4905b38SNicolas Royer 	dma_release_channel(dd->dma_lch_in.chan);
1337d4905b38SNicolas Royer }
1338d4905b38SNicolas Royer 
1339d4905b38SNicolas Royer static void atmel_sha_get_cap(struct atmel_sha_dev *dd)
1340d4905b38SNicolas Royer {
1341d4905b38SNicolas Royer 
1342d4905b38SNicolas Royer 	dd->caps.has_dma = 0;
1343d4905b38SNicolas Royer 	dd->caps.has_dualbuff = 0;
1344d4905b38SNicolas Royer 	dd->caps.has_sha224 = 0;
1345d4905b38SNicolas Royer 	dd->caps.has_sha_384_512 = 0;
13467cee3508SCyrille Pitchen 	dd->caps.has_uihv = 0;
1347d4905b38SNicolas Royer 
1348d4905b38SNicolas Royer 	/* keep only major version number */
1349d4905b38SNicolas Royer 	switch (dd->hw_version & 0xff0) {
1350507c5cc2SCyrille Pitchen 	case 0x510:
1351507c5cc2SCyrille Pitchen 		dd->caps.has_dma = 1;
1352507c5cc2SCyrille Pitchen 		dd->caps.has_dualbuff = 1;
1353507c5cc2SCyrille Pitchen 		dd->caps.has_sha224 = 1;
1354507c5cc2SCyrille Pitchen 		dd->caps.has_sha_384_512 = 1;
13557cee3508SCyrille Pitchen 		dd->caps.has_uihv = 1;
1356507c5cc2SCyrille Pitchen 		break;
1357141824d0SLeilei Zhao 	case 0x420:
1358141824d0SLeilei Zhao 		dd->caps.has_dma = 1;
1359141824d0SLeilei Zhao 		dd->caps.has_dualbuff = 1;
1360141824d0SLeilei Zhao 		dd->caps.has_sha224 = 1;
1361141824d0SLeilei Zhao 		dd->caps.has_sha_384_512 = 1;
13627cee3508SCyrille Pitchen 		dd->caps.has_uihv = 1;
1363141824d0SLeilei Zhao 		break;
1364d4905b38SNicolas Royer 	case 0x410:
1365d4905b38SNicolas Royer 		dd->caps.has_dma = 1;
1366d4905b38SNicolas Royer 		dd->caps.has_dualbuff = 1;
1367d4905b38SNicolas Royer 		dd->caps.has_sha224 = 1;
1368d4905b38SNicolas Royer 		dd->caps.has_sha_384_512 = 1;
1369d4905b38SNicolas Royer 		break;
1370d4905b38SNicolas Royer 	case 0x400:
1371d4905b38SNicolas Royer 		dd->caps.has_dma = 1;
1372d4905b38SNicolas Royer 		dd->caps.has_dualbuff = 1;
1373d4905b38SNicolas Royer 		dd->caps.has_sha224 = 1;
1374d4905b38SNicolas Royer 		break;
1375d4905b38SNicolas Royer 	case 0x320:
1376d4905b38SNicolas Royer 		break;
1377d4905b38SNicolas Royer 	default:
1378d4905b38SNicolas Royer 		dev_warn(dd->dev,
1379d4905b38SNicolas Royer 				"Unmanaged sha version, set minimum capabilities\n");
1380d4905b38SNicolas Royer 		break;
1381d4905b38SNicolas Royer 	}
1382d4905b38SNicolas Royer }
1383d4905b38SNicolas Royer 
1384abfe7ae4SNicolas Ferre #if defined(CONFIG_OF)
1385abfe7ae4SNicolas Ferre static const struct of_device_id atmel_sha_dt_ids[] = {
1386abfe7ae4SNicolas Ferre 	{ .compatible = "atmel,at91sam9g46-sha" },
1387abfe7ae4SNicolas Ferre 	{ /* sentinel */ }
1388abfe7ae4SNicolas Ferre };
1389abfe7ae4SNicolas Ferre 
1390abfe7ae4SNicolas Ferre MODULE_DEVICE_TABLE(of, atmel_sha_dt_ids);
1391abfe7ae4SNicolas Ferre 
1392abfe7ae4SNicolas Ferre static struct crypto_platform_data *atmel_sha_of_init(struct platform_device *pdev)
1393abfe7ae4SNicolas Ferre {
1394abfe7ae4SNicolas Ferre 	struct device_node *np = pdev->dev.of_node;
1395abfe7ae4SNicolas Ferre 	struct crypto_platform_data *pdata;
1396abfe7ae4SNicolas Ferre 
1397abfe7ae4SNicolas Ferre 	if (!np) {
1398abfe7ae4SNicolas Ferre 		dev_err(&pdev->dev, "device node not found\n");
1399abfe7ae4SNicolas Ferre 		return ERR_PTR(-EINVAL);
1400abfe7ae4SNicolas Ferre 	}
1401abfe7ae4SNicolas Ferre 
1402abfe7ae4SNicolas Ferre 	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
1403abfe7ae4SNicolas Ferre 	if (!pdata) {
1404abfe7ae4SNicolas Ferre 		dev_err(&pdev->dev, "could not allocate memory for pdata\n");
1405abfe7ae4SNicolas Ferre 		return ERR_PTR(-ENOMEM);
1406abfe7ae4SNicolas Ferre 	}
1407abfe7ae4SNicolas Ferre 
1408abfe7ae4SNicolas Ferre 	pdata->dma_slave = devm_kzalloc(&pdev->dev,
1409abfe7ae4SNicolas Ferre 					sizeof(*(pdata->dma_slave)),
1410abfe7ae4SNicolas Ferre 					GFP_KERNEL);
1411abfe7ae4SNicolas Ferre 	if (!pdata->dma_slave) {
1412abfe7ae4SNicolas Ferre 		dev_err(&pdev->dev, "could not allocate memory for dma_slave\n");
1413abfe7ae4SNicolas Ferre 		return ERR_PTR(-ENOMEM);
1414abfe7ae4SNicolas Ferre 	}
1415abfe7ae4SNicolas Ferre 
1416abfe7ae4SNicolas Ferre 	return pdata;
1417abfe7ae4SNicolas Ferre }
1418abfe7ae4SNicolas Ferre #else /* CONFIG_OF */
1419abfe7ae4SNicolas Ferre static inline struct crypto_platform_data *atmel_sha_of_init(struct platform_device *dev)
1420abfe7ae4SNicolas Ferre {
1421abfe7ae4SNicolas Ferre 	return ERR_PTR(-EINVAL);
1422abfe7ae4SNicolas Ferre }
1423abfe7ae4SNicolas Ferre #endif
1424abfe7ae4SNicolas Ferre 
142549cfe4dbSGreg Kroah-Hartman static int atmel_sha_probe(struct platform_device *pdev)
1426ebc82efaSNicolas Royer {
1427ebc82efaSNicolas Royer 	struct atmel_sha_dev *sha_dd;
1428d4905b38SNicolas Royer 	struct crypto_platform_data	*pdata;
1429ebc82efaSNicolas Royer 	struct device *dev = &pdev->dev;
1430ebc82efaSNicolas Royer 	struct resource *sha_res;
1431ebc82efaSNicolas Royer 	int err;
1432ebc82efaSNicolas Royer 
1433b0e8b341SLABBE Corentin 	sha_dd = devm_kzalloc(&pdev->dev, sizeof(*sha_dd), GFP_KERNEL);
1434ebc82efaSNicolas Royer 	if (sha_dd == NULL) {
1435ebc82efaSNicolas Royer 		dev_err(dev, "unable to alloc data struct.\n");
1436ebc82efaSNicolas Royer 		err = -ENOMEM;
1437ebc82efaSNicolas Royer 		goto sha_dd_err;
1438ebc82efaSNicolas Royer 	}
1439ebc82efaSNicolas Royer 
1440ebc82efaSNicolas Royer 	sha_dd->dev = dev;
1441ebc82efaSNicolas Royer 
1442ebc82efaSNicolas Royer 	platform_set_drvdata(pdev, sha_dd);
1443ebc82efaSNicolas Royer 
1444ebc82efaSNicolas Royer 	INIT_LIST_HEAD(&sha_dd->list);
144562728e82SLeilei Zhao 	spin_lock_init(&sha_dd->lock);
1446ebc82efaSNicolas Royer 
1447ebc82efaSNicolas Royer 	tasklet_init(&sha_dd->done_task, atmel_sha_done_task,
1448ebc82efaSNicolas Royer 					(unsigned long)sha_dd);
1449f56809c3SCyrille Pitchen 	tasklet_init(&sha_dd->queue_task, atmel_sha_queue_task,
1450f56809c3SCyrille Pitchen 					(unsigned long)sha_dd);
1451ebc82efaSNicolas Royer 
1452ebc82efaSNicolas Royer 	crypto_init_queue(&sha_dd->queue, ATMEL_SHA_QUEUE_LENGTH);
1453ebc82efaSNicolas Royer 
1454ebc82efaSNicolas Royer 	sha_dd->irq = -1;
1455ebc82efaSNicolas Royer 
1456ebc82efaSNicolas Royer 	/* Get the base address */
1457ebc82efaSNicolas Royer 	sha_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1458ebc82efaSNicolas Royer 	if (!sha_res) {
1459ebc82efaSNicolas Royer 		dev_err(dev, "no MEM resource info\n");
1460ebc82efaSNicolas Royer 		err = -ENODEV;
1461ebc82efaSNicolas Royer 		goto res_err;
1462ebc82efaSNicolas Royer 	}
1463ebc82efaSNicolas Royer 	sha_dd->phys_base = sha_res->start;
1464ebc82efaSNicolas Royer 
1465ebc82efaSNicolas Royer 	/* Get the IRQ */
1466ebc82efaSNicolas Royer 	sha_dd->irq = platform_get_irq(pdev,  0);
1467ebc82efaSNicolas Royer 	if (sha_dd->irq < 0) {
1468ebc82efaSNicolas Royer 		dev_err(dev, "no IRQ resource info\n");
1469ebc82efaSNicolas Royer 		err = sha_dd->irq;
1470ebc82efaSNicolas Royer 		goto res_err;
1471ebc82efaSNicolas Royer 	}
1472ebc82efaSNicolas Royer 
1473b0e8b341SLABBE Corentin 	err = devm_request_irq(&pdev->dev, sha_dd->irq, atmel_sha_irq,
1474b0e8b341SLABBE Corentin 			       IRQF_SHARED, "atmel-sha", sha_dd);
1475ebc82efaSNicolas Royer 	if (err) {
1476ebc82efaSNicolas Royer 		dev_err(dev, "unable to request sha irq.\n");
1477ebc82efaSNicolas Royer 		goto res_err;
1478ebc82efaSNicolas Royer 	}
1479ebc82efaSNicolas Royer 
1480ebc82efaSNicolas Royer 	/* Initializing the clock */
1481b0e8b341SLABBE Corentin 	sha_dd->iclk = devm_clk_get(&pdev->dev, "sha_clk");
1482ebc82efaSNicolas Royer 	if (IS_ERR(sha_dd->iclk)) {
1483be208356SColin Ian King 		dev_err(dev, "clock initialization failed.\n");
1484ebc82efaSNicolas Royer 		err = PTR_ERR(sha_dd->iclk);
1485b0e8b341SLABBE Corentin 		goto res_err;
1486ebc82efaSNicolas Royer 	}
1487ebc82efaSNicolas Royer 
1488b0e8b341SLABBE Corentin 	sha_dd->io_base = devm_ioremap_resource(&pdev->dev, sha_res);
14899b52d55fSVladimir Zapolskiy 	if (IS_ERR(sha_dd->io_base)) {
1490ebc82efaSNicolas Royer 		dev_err(dev, "can't ioremap\n");
14919b52d55fSVladimir Zapolskiy 		err = PTR_ERR(sha_dd->io_base);
1492b0e8b341SLABBE Corentin 		goto res_err;
1493ebc82efaSNicolas Royer 	}
1494ebc82efaSNicolas Royer 
1495d4905b38SNicolas Royer 	atmel_sha_hw_version_init(sha_dd);
1496d4905b38SNicolas Royer 
1497d4905b38SNicolas Royer 	atmel_sha_get_cap(sha_dd);
1498d4905b38SNicolas Royer 
1499d4905b38SNicolas Royer 	if (sha_dd->caps.has_dma) {
1500d4905b38SNicolas Royer 		pdata = pdev->dev.platform_data;
1501d4905b38SNicolas Royer 		if (!pdata) {
1502abfe7ae4SNicolas Ferre 			pdata = atmel_sha_of_init(pdev);
1503abfe7ae4SNicolas Ferre 			if (IS_ERR(pdata)) {
1504d4905b38SNicolas Royer 				dev_err(&pdev->dev, "platform data not available\n");
1505abfe7ae4SNicolas Ferre 				err = PTR_ERR(pdata);
1506b0e8b341SLABBE Corentin 				goto res_err;
1507abfe7ae4SNicolas Ferre 			}
1508abfe7ae4SNicolas Ferre 		}
1509abfe7ae4SNicolas Ferre 		if (!pdata->dma_slave) {
1510d4905b38SNicolas Royer 			err = -ENXIO;
1511b0e8b341SLABBE Corentin 			goto res_err;
1512d4905b38SNicolas Royer 		}
1513d4905b38SNicolas Royer 		err = atmel_sha_dma_init(sha_dd, pdata);
1514d4905b38SNicolas Royer 		if (err)
1515d4905b38SNicolas Royer 			goto err_sha_dma;
1516abfe7ae4SNicolas Ferre 
1517abfe7ae4SNicolas Ferre 		dev_info(dev, "using %s for DMA transfers\n",
1518abfe7ae4SNicolas Ferre 				dma_chan_name(sha_dd->dma_lch_in.chan));
1519d4905b38SNicolas Royer 	}
1520d4905b38SNicolas Royer 
1521ebc82efaSNicolas Royer 	spin_lock(&atmel_sha.lock);
1522ebc82efaSNicolas Royer 	list_add_tail(&sha_dd->list, &atmel_sha.dev_list);
1523ebc82efaSNicolas Royer 	spin_unlock(&atmel_sha.lock);
1524ebc82efaSNicolas Royer 
1525ebc82efaSNicolas Royer 	err = atmel_sha_register_algs(sha_dd);
1526ebc82efaSNicolas Royer 	if (err)
1527ebc82efaSNicolas Royer 		goto err_algs;
1528ebc82efaSNicolas Royer 
15291ca5b7d9SNicolas Ferre 	dev_info(dev, "Atmel SHA1/SHA256%s%s\n",
15301ca5b7d9SNicolas Ferre 			sha_dd->caps.has_sha224 ? "/SHA224" : "",
15311ca5b7d9SNicolas Ferre 			sha_dd->caps.has_sha_384_512 ? "/SHA384/SHA512" : "");
1532ebc82efaSNicolas Royer 
1533ebc82efaSNicolas Royer 	return 0;
1534ebc82efaSNicolas Royer 
1535ebc82efaSNicolas Royer err_algs:
1536ebc82efaSNicolas Royer 	spin_lock(&atmel_sha.lock);
1537ebc82efaSNicolas Royer 	list_del(&sha_dd->list);
1538ebc82efaSNicolas Royer 	spin_unlock(&atmel_sha.lock);
1539d4905b38SNicolas Royer 	if (sha_dd->caps.has_dma)
1540d4905b38SNicolas Royer 		atmel_sha_dma_cleanup(sha_dd);
1541d4905b38SNicolas Royer err_sha_dma:
1542ebc82efaSNicolas Royer res_err:
1543f56809c3SCyrille Pitchen 	tasklet_kill(&sha_dd->queue_task);
1544ebc82efaSNicolas Royer 	tasklet_kill(&sha_dd->done_task);
1545ebc82efaSNicolas Royer sha_dd_err:
1546ebc82efaSNicolas Royer 	dev_err(dev, "initialization failed.\n");
1547ebc82efaSNicolas Royer 
1548ebc82efaSNicolas Royer 	return err;
1549ebc82efaSNicolas Royer }
1550ebc82efaSNicolas Royer 
155149cfe4dbSGreg Kroah-Hartman static int atmel_sha_remove(struct platform_device *pdev)
1552ebc82efaSNicolas Royer {
1553ebc82efaSNicolas Royer 	static struct atmel_sha_dev *sha_dd;
1554ebc82efaSNicolas Royer 
1555ebc82efaSNicolas Royer 	sha_dd = platform_get_drvdata(pdev);
1556ebc82efaSNicolas Royer 	if (!sha_dd)
1557ebc82efaSNicolas Royer 		return -ENODEV;
1558ebc82efaSNicolas Royer 	spin_lock(&atmel_sha.lock);
1559ebc82efaSNicolas Royer 	list_del(&sha_dd->list);
1560ebc82efaSNicolas Royer 	spin_unlock(&atmel_sha.lock);
1561ebc82efaSNicolas Royer 
1562ebc82efaSNicolas Royer 	atmel_sha_unregister_algs(sha_dd);
1563ebc82efaSNicolas Royer 
1564f56809c3SCyrille Pitchen 	tasklet_kill(&sha_dd->queue_task);
1565ebc82efaSNicolas Royer 	tasklet_kill(&sha_dd->done_task);
1566ebc82efaSNicolas Royer 
1567d4905b38SNicolas Royer 	if (sha_dd->caps.has_dma)
1568d4905b38SNicolas Royer 		atmel_sha_dma_cleanup(sha_dd);
1569d4905b38SNicolas Royer 
1570ebc82efaSNicolas Royer 	iounmap(sha_dd->io_base);
1571ebc82efaSNicolas Royer 
1572ebc82efaSNicolas Royer 	clk_put(sha_dd->iclk);
1573ebc82efaSNicolas Royer 
1574ebc82efaSNicolas Royer 	if (sha_dd->irq >= 0)
1575ebc82efaSNicolas Royer 		free_irq(sha_dd->irq, sha_dd);
1576ebc82efaSNicolas Royer 
1577ebc82efaSNicolas Royer 	return 0;
1578ebc82efaSNicolas Royer }
1579ebc82efaSNicolas Royer 
1580ebc82efaSNicolas Royer static struct platform_driver atmel_sha_driver = {
1581ebc82efaSNicolas Royer 	.probe		= atmel_sha_probe,
158249cfe4dbSGreg Kroah-Hartman 	.remove		= atmel_sha_remove,
1583ebc82efaSNicolas Royer 	.driver		= {
1584ebc82efaSNicolas Royer 		.name	= "atmel_sha",
1585abfe7ae4SNicolas Ferre 		.of_match_table	= of_match_ptr(atmel_sha_dt_ids),
1586ebc82efaSNicolas Royer 	},
1587ebc82efaSNicolas Royer };
1588ebc82efaSNicolas Royer 
1589ebc82efaSNicolas Royer module_platform_driver(atmel_sha_driver);
1590ebc82efaSNicolas Royer 
1591d4905b38SNicolas Royer MODULE_DESCRIPTION("Atmel SHA (1/256/224/384/512) hw acceleration support.");
1592ebc82efaSNicolas Royer MODULE_LICENSE("GPL v2");
1593ebc82efaSNicolas Royer MODULE_AUTHOR("Nicolas Royer - Eukréa Electromatique");
1594