162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2014 Imagination Technologies
462306a36Sopenharmony_ci * Authors:  Will Thomas, James Hartley
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci *	Interface structure taken from omap-sham driver
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/clk.h>
1062306a36Sopenharmony_ci#include <linux/dma-mapping.h>
1162306a36Sopenharmony_ci#include <linux/dmaengine.h>
1262306a36Sopenharmony_ci#include <linux/interrupt.h>
1362306a36Sopenharmony_ci#include <linux/io.h>
1462306a36Sopenharmony_ci#include <linux/kernel.h>
1562306a36Sopenharmony_ci#include <linux/module.h>
1662306a36Sopenharmony_ci#include <linux/mod_devicetable.h>
1762306a36Sopenharmony_ci#include <linux/platform_device.h>
1862306a36Sopenharmony_ci#include <linux/scatterlist.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#include <crypto/internal/hash.h>
2162306a36Sopenharmony_ci#include <crypto/md5.h>
2262306a36Sopenharmony_ci#include <crypto/sha1.h>
2362306a36Sopenharmony_ci#include <crypto/sha2.h>
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#define CR_RESET			0
2662306a36Sopenharmony_ci#define CR_RESET_SET			1
2762306a36Sopenharmony_ci#define CR_RESET_UNSET			0
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#define CR_MESSAGE_LENGTH_H		0x4
3062306a36Sopenharmony_ci#define CR_MESSAGE_LENGTH_L		0x8
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#define CR_CONTROL			0xc
3362306a36Sopenharmony_ci#define CR_CONTROL_BYTE_ORDER_3210	0
3462306a36Sopenharmony_ci#define CR_CONTROL_BYTE_ORDER_0123	1
3562306a36Sopenharmony_ci#define CR_CONTROL_BYTE_ORDER_2310	2
3662306a36Sopenharmony_ci#define CR_CONTROL_BYTE_ORDER_1032	3
3762306a36Sopenharmony_ci#define CR_CONTROL_BYTE_ORDER_SHIFT	8
3862306a36Sopenharmony_ci#define CR_CONTROL_ALGO_MD5	0
3962306a36Sopenharmony_ci#define CR_CONTROL_ALGO_SHA1	1
4062306a36Sopenharmony_ci#define CR_CONTROL_ALGO_SHA224	2
4162306a36Sopenharmony_ci#define CR_CONTROL_ALGO_SHA256	3
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci#define CR_INTSTAT			0x10
4462306a36Sopenharmony_ci#define CR_INTENAB			0x14
4562306a36Sopenharmony_ci#define CR_INTCLEAR			0x18
4662306a36Sopenharmony_ci#define CR_INT_RESULTS_AVAILABLE	BIT(0)
4762306a36Sopenharmony_ci#define CR_INT_NEW_RESULTS_SET		BIT(1)
4862306a36Sopenharmony_ci#define CR_INT_RESULT_READ_ERR		BIT(2)
4962306a36Sopenharmony_ci#define CR_INT_MESSAGE_WRITE_ERROR	BIT(3)
5062306a36Sopenharmony_ci#define CR_INT_STATUS			BIT(8)
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci#define CR_RESULT_QUEUE		0x1c
5362306a36Sopenharmony_ci#define CR_RSD0				0x40
5462306a36Sopenharmony_ci#define CR_CORE_REV			0x50
5562306a36Sopenharmony_ci#define CR_CORE_DES1		0x60
5662306a36Sopenharmony_ci#define CR_CORE_DES2		0x70
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci#define DRIVER_FLAGS_BUSY		BIT(0)
5962306a36Sopenharmony_ci#define DRIVER_FLAGS_FINAL		BIT(1)
6062306a36Sopenharmony_ci#define DRIVER_FLAGS_DMA_ACTIVE		BIT(2)
6162306a36Sopenharmony_ci#define DRIVER_FLAGS_OUTPUT_READY	BIT(3)
6262306a36Sopenharmony_ci#define DRIVER_FLAGS_INIT		BIT(4)
6362306a36Sopenharmony_ci#define DRIVER_FLAGS_CPU		BIT(5)
6462306a36Sopenharmony_ci#define DRIVER_FLAGS_DMA_READY		BIT(6)
6562306a36Sopenharmony_ci#define DRIVER_FLAGS_ERROR		BIT(7)
6662306a36Sopenharmony_ci#define DRIVER_FLAGS_SG			BIT(8)
6762306a36Sopenharmony_ci#define DRIVER_FLAGS_SHA1		BIT(18)
6862306a36Sopenharmony_ci#define DRIVER_FLAGS_SHA224		BIT(19)
6962306a36Sopenharmony_ci#define DRIVER_FLAGS_SHA256		BIT(20)
7062306a36Sopenharmony_ci#define DRIVER_FLAGS_MD5		BIT(21)
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci#define IMG_HASH_QUEUE_LENGTH		20
7362306a36Sopenharmony_ci#define IMG_HASH_DMA_BURST		4
7462306a36Sopenharmony_ci#define IMG_HASH_DMA_THRESHOLD		64
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci#ifdef __LITTLE_ENDIAN
7762306a36Sopenharmony_ci#define IMG_HASH_BYTE_ORDER		CR_CONTROL_BYTE_ORDER_3210
7862306a36Sopenharmony_ci#else
7962306a36Sopenharmony_ci#define IMG_HASH_BYTE_ORDER		CR_CONTROL_BYTE_ORDER_0123
8062306a36Sopenharmony_ci#endif
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cistruct img_hash_dev;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistruct img_hash_request_ctx {
8562306a36Sopenharmony_ci	struct img_hash_dev	*hdev;
8662306a36Sopenharmony_ci	u8 digest[SHA256_DIGEST_SIZE] __aligned(sizeof(u32));
8762306a36Sopenharmony_ci	unsigned long		flags;
8862306a36Sopenharmony_ci	size_t			digsize;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	dma_addr_t		dma_addr;
9162306a36Sopenharmony_ci	size_t			dma_ct;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	/* sg root */
9462306a36Sopenharmony_ci	struct scatterlist	*sgfirst;
9562306a36Sopenharmony_ci	/* walk state */
9662306a36Sopenharmony_ci	struct scatterlist	*sg;
9762306a36Sopenharmony_ci	size_t			nents;
9862306a36Sopenharmony_ci	size_t			offset;
9962306a36Sopenharmony_ci	unsigned int		total;
10062306a36Sopenharmony_ci	size_t			sent;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	unsigned long		op;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	size_t			bufcnt;
10562306a36Sopenharmony_ci	struct ahash_request	fallback_req;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	/* Zero length buffer must remain last member of struct */
10862306a36Sopenharmony_ci	u8 buffer[] __aligned(sizeof(u32));
10962306a36Sopenharmony_ci};
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistruct img_hash_ctx {
11262306a36Sopenharmony_ci	struct img_hash_dev	*hdev;
11362306a36Sopenharmony_ci	unsigned long		flags;
11462306a36Sopenharmony_ci	struct crypto_ahash	*fallback;
11562306a36Sopenharmony_ci};
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_cistruct img_hash_dev {
11862306a36Sopenharmony_ci	struct list_head	list;
11962306a36Sopenharmony_ci	struct device		*dev;
12062306a36Sopenharmony_ci	struct clk		*hash_clk;
12162306a36Sopenharmony_ci	struct clk		*sys_clk;
12262306a36Sopenharmony_ci	void __iomem		*io_base;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	phys_addr_t		bus_addr;
12562306a36Sopenharmony_ci	void __iomem		*cpu_addr;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	spinlock_t		lock;
12862306a36Sopenharmony_ci	int			err;
12962306a36Sopenharmony_ci	struct tasklet_struct	done_task;
13062306a36Sopenharmony_ci	struct tasklet_struct	dma_task;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	unsigned long		flags;
13362306a36Sopenharmony_ci	struct crypto_queue	queue;
13462306a36Sopenharmony_ci	struct ahash_request	*req;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	struct dma_chan		*dma_lch;
13762306a36Sopenharmony_ci};
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_cistruct img_hash_drv {
14062306a36Sopenharmony_ci	struct list_head dev_list;
14162306a36Sopenharmony_ci	spinlock_t lock;
14262306a36Sopenharmony_ci};
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_cistatic struct img_hash_drv img_hash = {
14562306a36Sopenharmony_ci	.dev_list = LIST_HEAD_INIT(img_hash.dev_list),
14662306a36Sopenharmony_ci	.lock = __SPIN_LOCK_UNLOCKED(img_hash.lock),
14762306a36Sopenharmony_ci};
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cistatic inline u32 img_hash_read(struct img_hash_dev *hdev, u32 offset)
15062306a36Sopenharmony_ci{
15162306a36Sopenharmony_ci	return readl_relaxed(hdev->io_base + offset);
15262306a36Sopenharmony_ci}
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_cistatic inline void img_hash_write(struct img_hash_dev *hdev,
15562306a36Sopenharmony_ci				  u32 offset, u32 value)
15662306a36Sopenharmony_ci{
15762306a36Sopenharmony_ci	writel_relaxed(value, hdev->io_base + offset);
15862306a36Sopenharmony_ci}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cistatic inline __be32 img_hash_read_result_queue(struct img_hash_dev *hdev)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	return cpu_to_be32(img_hash_read(hdev, CR_RESULT_QUEUE));
16362306a36Sopenharmony_ci}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_cistatic void img_hash_start(struct img_hash_dev *hdev, bool dma)
16662306a36Sopenharmony_ci{
16762306a36Sopenharmony_ci	struct img_hash_request_ctx *ctx = ahash_request_ctx(hdev->req);
16862306a36Sopenharmony_ci	u32 cr = IMG_HASH_BYTE_ORDER << CR_CONTROL_BYTE_ORDER_SHIFT;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	if (ctx->flags & DRIVER_FLAGS_MD5)
17162306a36Sopenharmony_ci		cr |= CR_CONTROL_ALGO_MD5;
17262306a36Sopenharmony_ci	else if (ctx->flags & DRIVER_FLAGS_SHA1)
17362306a36Sopenharmony_ci		cr |= CR_CONTROL_ALGO_SHA1;
17462306a36Sopenharmony_ci	else if (ctx->flags & DRIVER_FLAGS_SHA224)
17562306a36Sopenharmony_ci		cr |= CR_CONTROL_ALGO_SHA224;
17662306a36Sopenharmony_ci	else if (ctx->flags & DRIVER_FLAGS_SHA256)
17762306a36Sopenharmony_ci		cr |= CR_CONTROL_ALGO_SHA256;
17862306a36Sopenharmony_ci	dev_dbg(hdev->dev, "Starting hash process\n");
17962306a36Sopenharmony_ci	img_hash_write(hdev, CR_CONTROL, cr);
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	/*
18262306a36Sopenharmony_ci	 * The hardware block requires two cycles between writing the control
18362306a36Sopenharmony_ci	 * register and writing the first word of data in non DMA mode, to
18462306a36Sopenharmony_ci	 * ensure the first data write is not grouped in burst with the control
18562306a36Sopenharmony_ci	 * register write a read is issued to 'flush' the bus.
18662306a36Sopenharmony_ci	 */
18762306a36Sopenharmony_ci	if (!dma)
18862306a36Sopenharmony_ci		img_hash_read(hdev, CR_CONTROL);
18962306a36Sopenharmony_ci}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_cistatic int img_hash_xmit_cpu(struct img_hash_dev *hdev, const u8 *buf,
19262306a36Sopenharmony_ci			     size_t length, int final)
19362306a36Sopenharmony_ci{
19462306a36Sopenharmony_ci	u32 count, len32;
19562306a36Sopenharmony_ci	const u32 *buffer = (const u32 *)buf;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	dev_dbg(hdev->dev, "xmit_cpu:  length: %zu bytes\n", length);
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	if (final)
20062306a36Sopenharmony_ci		hdev->flags |= DRIVER_FLAGS_FINAL;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	len32 = DIV_ROUND_UP(length, sizeof(u32));
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	for (count = 0; count < len32; count++)
20562306a36Sopenharmony_ci		writel_relaxed(buffer[count], hdev->cpu_addr);
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	return -EINPROGRESS;
20862306a36Sopenharmony_ci}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_cistatic void img_hash_dma_callback(void *data)
21162306a36Sopenharmony_ci{
21262306a36Sopenharmony_ci	struct img_hash_dev *hdev = data;
21362306a36Sopenharmony_ci	struct img_hash_request_ctx *ctx = ahash_request_ctx(hdev->req);
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	if (ctx->bufcnt) {
21662306a36Sopenharmony_ci		img_hash_xmit_cpu(hdev, ctx->buffer, ctx->bufcnt, 0);
21762306a36Sopenharmony_ci		ctx->bufcnt = 0;
21862306a36Sopenharmony_ci	}
21962306a36Sopenharmony_ci	if (ctx->sg)
22062306a36Sopenharmony_ci		tasklet_schedule(&hdev->dma_task);
22162306a36Sopenharmony_ci}
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_cistatic int img_hash_xmit_dma(struct img_hash_dev *hdev, struct scatterlist *sg)
22462306a36Sopenharmony_ci{
22562306a36Sopenharmony_ci	struct dma_async_tx_descriptor *desc;
22662306a36Sopenharmony_ci	struct img_hash_request_ctx *ctx = ahash_request_ctx(hdev->req);
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	ctx->dma_ct = dma_map_sg(hdev->dev, sg, 1, DMA_TO_DEVICE);
22962306a36Sopenharmony_ci	if (ctx->dma_ct == 0) {
23062306a36Sopenharmony_ci		dev_err(hdev->dev, "Invalid DMA sg\n");
23162306a36Sopenharmony_ci		hdev->err = -EINVAL;
23262306a36Sopenharmony_ci		return -EINVAL;
23362306a36Sopenharmony_ci	}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	desc = dmaengine_prep_slave_sg(hdev->dma_lch,
23662306a36Sopenharmony_ci				       sg,
23762306a36Sopenharmony_ci				       ctx->dma_ct,
23862306a36Sopenharmony_ci				       DMA_MEM_TO_DEV,
23962306a36Sopenharmony_ci				       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
24062306a36Sopenharmony_ci	if (!desc) {
24162306a36Sopenharmony_ci		dev_err(hdev->dev, "Null DMA descriptor\n");
24262306a36Sopenharmony_ci		hdev->err = -EINVAL;
24362306a36Sopenharmony_ci		dma_unmap_sg(hdev->dev, sg, 1, DMA_TO_DEVICE);
24462306a36Sopenharmony_ci		return -EINVAL;
24562306a36Sopenharmony_ci	}
24662306a36Sopenharmony_ci	desc->callback = img_hash_dma_callback;
24762306a36Sopenharmony_ci	desc->callback_param = hdev;
24862306a36Sopenharmony_ci	dmaengine_submit(desc);
24962306a36Sopenharmony_ci	dma_async_issue_pending(hdev->dma_lch);
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	return 0;
25262306a36Sopenharmony_ci}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_cistatic int img_hash_write_via_cpu(struct img_hash_dev *hdev)
25562306a36Sopenharmony_ci{
25662306a36Sopenharmony_ci	struct img_hash_request_ctx *ctx = ahash_request_ctx(hdev->req);
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	ctx->bufcnt = sg_copy_to_buffer(hdev->req->src, sg_nents(ctx->sg),
25962306a36Sopenharmony_ci					ctx->buffer, hdev->req->nbytes);
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	ctx->total = hdev->req->nbytes;
26262306a36Sopenharmony_ci	ctx->bufcnt = 0;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	hdev->flags |= (DRIVER_FLAGS_CPU | DRIVER_FLAGS_FINAL);
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	img_hash_start(hdev, false);
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	return img_hash_xmit_cpu(hdev, ctx->buffer, ctx->total, 1);
26962306a36Sopenharmony_ci}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_cistatic int img_hash_finish(struct ahash_request *req)
27262306a36Sopenharmony_ci{
27362306a36Sopenharmony_ci	struct img_hash_request_ctx *ctx = ahash_request_ctx(req);
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	if (!req->result)
27662306a36Sopenharmony_ci		return -EINVAL;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	memcpy(req->result, ctx->digest, ctx->digsize);
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	return 0;
28162306a36Sopenharmony_ci}
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_cistatic void img_hash_copy_hash(struct ahash_request *req)
28462306a36Sopenharmony_ci{
28562306a36Sopenharmony_ci	struct img_hash_request_ctx *ctx = ahash_request_ctx(req);
28662306a36Sopenharmony_ci	__be32 *hash = (__be32 *)ctx->digest;
28762306a36Sopenharmony_ci	int i;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	for (i = (ctx->digsize / sizeof(*hash)) - 1; i >= 0; i--)
29062306a36Sopenharmony_ci		hash[i] = img_hash_read_result_queue(ctx->hdev);
29162306a36Sopenharmony_ci}
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_cistatic void img_hash_finish_req(struct ahash_request *req, int err)
29462306a36Sopenharmony_ci{
29562306a36Sopenharmony_ci	struct img_hash_request_ctx *ctx = ahash_request_ctx(req);
29662306a36Sopenharmony_ci	struct img_hash_dev *hdev =  ctx->hdev;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	if (!err) {
29962306a36Sopenharmony_ci		img_hash_copy_hash(req);
30062306a36Sopenharmony_ci		if (DRIVER_FLAGS_FINAL & hdev->flags)
30162306a36Sopenharmony_ci			err = img_hash_finish(req);
30262306a36Sopenharmony_ci	} else {
30362306a36Sopenharmony_ci		dev_warn(hdev->dev, "Hash failed with error %d\n", err);
30462306a36Sopenharmony_ci		ctx->flags |= DRIVER_FLAGS_ERROR;
30562306a36Sopenharmony_ci	}
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	hdev->flags &= ~(DRIVER_FLAGS_DMA_READY | DRIVER_FLAGS_OUTPUT_READY |
30862306a36Sopenharmony_ci		DRIVER_FLAGS_CPU | DRIVER_FLAGS_BUSY | DRIVER_FLAGS_FINAL);
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	if (req->base.complete)
31162306a36Sopenharmony_ci		ahash_request_complete(req, err);
31262306a36Sopenharmony_ci}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_cistatic int img_hash_write_via_dma(struct img_hash_dev *hdev)
31562306a36Sopenharmony_ci{
31662306a36Sopenharmony_ci	struct img_hash_request_ctx *ctx = ahash_request_ctx(hdev->req);
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	img_hash_start(hdev, true);
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	dev_dbg(hdev->dev, "xmit dma size: %d\n", ctx->total);
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	if (!ctx->total)
32362306a36Sopenharmony_ci		hdev->flags |= DRIVER_FLAGS_FINAL;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	hdev->flags |= DRIVER_FLAGS_DMA_ACTIVE | DRIVER_FLAGS_FINAL;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	tasklet_schedule(&hdev->dma_task);
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	return -EINPROGRESS;
33062306a36Sopenharmony_ci}
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_cistatic int img_hash_dma_init(struct img_hash_dev *hdev)
33362306a36Sopenharmony_ci{
33462306a36Sopenharmony_ci	struct dma_slave_config dma_conf;
33562306a36Sopenharmony_ci	int err;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	hdev->dma_lch = dma_request_chan(hdev->dev, "tx");
33862306a36Sopenharmony_ci	if (IS_ERR(hdev->dma_lch)) {
33962306a36Sopenharmony_ci		dev_err(hdev->dev, "Couldn't acquire a slave DMA channel.\n");
34062306a36Sopenharmony_ci		return PTR_ERR(hdev->dma_lch);
34162306a36Sopenharmony_ci	}
34262306a36Sopenharmony_ci	dma_conf.direction = DMA_MEM_TO_DEV;
34362306a36Sopenharmony_ci	dma_conf.dst_addr = hdev->bus_addr;
34462306a36Sopenharmony_ci	dma_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
34562306a36Sopenharmony_ci	dma_conf.dst_maxburst = IMG_HASH_DMA_BURST;
34662306a36Sopenharmony_ci	dma_conf.device_fc = false;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	err = dmaengine_slave_config(hdev->dma_lch,  &dma_conf);
34962306a36Sopenharmony_ci	if (err) {
35062306a36Sopenharmony_ci		dev_err(hdev->dev, "Couldn't configure DMA slave.\n");
35162306a36Sopenharmony_ci		dma_release_channel(hdev->dma_lch);
35262306a36Sopenharmony_ci		return err;
35362306a36Sopenharmony_ci	}
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	return 0;
35662306a36Sopenharmony_ci}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_cistatic void img_hash_dma_task(unsigned long d)
35962306a36Sopenharmony_ci{
36062306a36Sopenharmony_ci	struct img_hash_dev *hdev = (struct img_hash_dev *)d;
36162306a36Sopenharmony_ci	struct img_hash_request_ctx *ctx;
36262306a36Sopenharmony_ci	u8 *addr;
36362306a36Sopenharmony_ci	size_t nbytes, bleft, wsend, len, tbc;
36462306a36Sopenharmony_ci	struct scatterlist tsg;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	if (!hdev->req)
36762306a36Sopenharmony_ci		return;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	ctx = ahash_request_ctx(hdev->req);
37062306a36Sopenharmony_ci	if (!ctx->sg)
37162306a36Sopenharmony_ci		return;
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	addr = sg_virt(ctx->sg);
37462306a36Sopenharmony_ci	nbytes = ctx->sg->length - ctx->offset;
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	/*
37762306a36Sopenharmony_ci	 * The hash accelerator does not support a data valid mask. This means
37862306a36Sopenharmony_ci	 * that if each dma (i.e. per page) is not a multiple of 4 bytes, the
37962306a36Sopenharmony_ci	 * padding bytes in the last word written by that dma would erroneously
38062306a36Sopenharmony_ci	 * be included in the hash. To avoid this we round down the transfer,
38162306a36Sopenharmony_ci	 * and add the excess to the start of the next dma. It does not matter
38262306a36Sopenharmony_ci	 * that the final dma may not be a multiple of 4 bytes as the hashing
38362306a36Sopenharmony_ci	 * block is programmed to accept the correct number of bytes.
38462306a36Sopenharmony_ci	 */
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	bleft = nbytes % 4;
38762306a36Sopenharmony_ci	wsend = (nbytes / 4);
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	if (wsend) {
39062306a36Sopenharmony_ci		sg_init_one(&tsg, addr + ctx->offset, wsend * 4);
39162306a36Sopenharmony_ci		if (img_hash_xmit_dma(hdev, &tsg)) {
39262306a36Sopenharmony_ci			dev_err(hdev->dev, "DMA failed, falling back to CPU");
39362306a36Sopenharmony_ci			ctx->flags |= DRIVER_FLAGS_CPU;
39462306a36Sopenharmony_ci			hdev->err = 0;
39562306a36Sopenharmony_ci			img_hash_xmit_cpu(hdev, addr + ctx->offset,
39662306a36Sopenharmony_ci					  wsend * 4, 0);
39762306a36Sopenharmony_ci			ctx->sent += wsend * 4;
39862306a36Sopenharmony_ci			wsend = 0;
39962306a36Sopenharmony_ci		} else {
40062306a36Sopenharmony_ci			ctx->sent += wsend * 4;
40162306a36Sopenharmony_ci		}
40262306a36Sopenharmony_ci	}
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	if (bleft) {
40562306a36Sopenharmony_ci		ctx->bufcnt = sg_pcopy_to_buffer(ctx->sgfirst, ctx->nents,
40662306a36Sopenharmony_ci						 ctx->buffer, bleft, ctx->sent);
40762306a36Sopenharmony_ci		tbc = 0;
40862306a36Sopenharmony_ci		ctx->sg = sg_next(ctx->sg);
40962306a36Sopenharmony_ci		while (ctx->sg && (ctx->bufcnt < 4)) {
41062306a36Sopenharmony_ci			len = ctx->sg->length;
41162306a36Sopenharmony_ci			if (likely(len > (4 - ctx->bufcnt)))
41262306a36Sopenharmony_ci				len = 4 - ctx->bufcnt;
41362306a36Sopenharmony_ci			tbc = sg_pcopy_to_buffer(ctx->sgfirst, ctx->nents,
41462306a36Sopenharmony_ci						 ctx->buffer + ctx->bufcnt, len,
41562306a36Sopenharmony_ci					ctx->sent + ctx->bufcnt);
41662306a36Sopenharmony_ci			ctx->bufcnt += tbc;
41762306a36Sopenharmony_ci			if (tbc >= ctx->sg->length) {
41862306a36Sopenharmony_ci				ctx->sg = sg_next(ctx->sg);
41962306a36Sopenharmony_ci				tbc = 0;
42062306a36Sopenharmony_ci			}
42162306a36Sopenharmony_ci		}
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci		ctx->sent += ctx->bufcnt;
42462306a36Sopenharmony_ci		ctx->offset = tbc;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci		if (!wsend)
42762306a36Sopenharmony_ci			img_hash_dma_callback(hdev);
42862306a36Sopenharmony_ci	} else {
42962306a36Sopenharmony_ci		ctx->offset = 0;
43062306a36Sopenharmony_ci		ctx->sg = sg_next(ctx->sg);
43162306a36Sopenharmony_ci	}
43262306a36Sopenharmony_ci}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_cistatic int img_hash_write_via_dma_stop(struct img_hash_dev *hdev)
43562306a36Sopenharmony_ci{
43662306a36Sopenharmony_ci	struct img_hash_request_ctx *ctx = ahash_request_ctx(hdev->req);
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	if (ctx->flags & DRIVER_FLAGS_SG)
43962306a36Sopenharmony_ci		dma_unmap_sg(hdev->dev, ctx->sg, ctx->dma_ct, DMA_TO_DEVICE);
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	return 0;
44262306a36Sopenharmony_ci}
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_cistatic int img_hash_process_data(struct img_hash_dev *hdev)
44562306a36Sopenharmony_ci{
44662306a36Sopenharmony_ci	struct ahash_request *req = hdev->req;
44762306a36Sopenharmony_ci	struct img_hash_request_ctx *ctx = ahash_request_ctx(req);
44862306a36Sopenharmony_ci	int err = 0;
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	ctx->bufcnt = 0;
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	if (req->nbytes >= IMG_HASH_DMA_THRESHOLD) {
45362306a36Sopenharmony_ci		dev_dbg(hdev->dev, "process data request(%d bytes) using DMA\n",
45462306a36Sopenharmony_ci			req->nbytes);
45562306a36Sopenharmony_ci		err = img_hash_write_via_dma(hdev);
45662306a36Sopenharmony_ci	} else {
45762306a36Sopenharmony_ci		dev_dbg(hdev->dev, "process data request(%d bytes) using CPU\n",
45862306a36Sopenharmony_ci			req->nbytes);
45962306a36Sopenharmony_ci		err = img_hash_write_via_cpu(hdev);
46062306a36Sopenharmony_ci	}
46162306a36Sopenharmony_ci	return err;
46262306a36Sopenharmony_ci}
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_cistatic int img_hash_hw_init(struct img_hash_dev *hdev)
46562306a36Sopenharmony_ci{
46662306a36Sopenharmony_ci	unsigned long long nbits;
46762306a36Sopenharmony_ci	u32 u, l;
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	img_hash_write(hdev, CR_RESET, CR_RESET_SET);
47062306a36Sopenharmony_ci	img_hash_write(hdev, CR_RESET, CR_RESET_UNSET);
47162306a36Sopenharmony_ci	img_hash_write(hdev, CR_INTENAB, CR_INT_NEW_RESULTS_SET);
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	nbits = (u64)hdev->req->nbytes << 3;
47462306a36Sopenharmony_ci	u = nbits >> 32;
47562306a36Sopenharmony_ci	l = nbits;
47662306a36Sopenharmony_ci	img_hash_write(hdev, CR_MESSAGE_LENGTH_H, u);
47762306a36Sopenharmony_ci	img_hash_write(hdev, CR_MESSAGE_LENGTH_L, l);
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	if (!(DRIVER_FLAGS_INIT & hdev->flags)) {
48062306a36Sopenharmony_ci		hdev->flags |= DRIVER_FLAGS_INIT;
48162306a36Sopenharmony_ci		hdev->err = 0;
48262306a36Sopenharmony_ci	}
48362306a36Sopenharmony_ci	dev_dbg(hdev->dev, "hw initialized, nbits: %llx\n", nbits);
48462306a36Sopenharmony_ci	return 0;
48562306a36Sopenharmony_ci}
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_cistatic int img_hash_init(struct ahash_request *req)
48862306a36Sopenharmony_ci{
48962306a36Sopenharmony_ci	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
49062306a36Sopenharmony_ci	struct img_hash_request_ctx *rctx = ahash_request_ctx(req);
49162306a36Sopenharmony_ci	struct img_hash_ctx *ctx = crypto_ahash_ctx(tfm);
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback);
49462306a36Sopenharmony_ci	rctx->fallback_req.base.flags =	req->base.flags
49562306a36Sopenharmony_ci		& CRYPTO_TFM_REQ_MAY_SLEEP;
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	return crypto_ahash_init(&rctx->fallback_req);
49862306a36Sopenharmony_ci}
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_cistatic int img_hash_handle_queue(struct img_hash_dev *hdev,
50162306a36Sopenharmony_ci				 struct ahash_request *req)
50262306a36Sopenharmony_ci{
50362306a36Sopenharmony_ci	struct crypto_async_request *async_req, *backlog;
50462306a36Sopenharmony_ci	struct img_hash_request_ctx *ctx;
50562306a36Sopenharmony_ci	unsigned long flags;
50662306a36Sopenharmony_ci	int err = 0, res = 0;
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	spin_lock_irqsave(&hdev->lock, flags);
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	if (req)
51162306a36Sopenharmony_ci		res = ahash_enqueue_request(&hdev->queue, req);
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	if (DRIVER_FLAGS_BUSY & hdev->flags) {
51462306a36Sopenharmony_ci		spin_unlock_irqrestore(&hdev->lock, flags);
51562306a36Sopenharmony_ci		return res;
51662306a36Sopenharmony_ci	}
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	backlog = crypto_get_backlog(&hdev->queue);
51962306a36Sopenharmony_ci	async_req = crypto_dequeue_request(&hdev->queue);
52062306a36Sopenharmony_ci	if (async_req)
52162306a36Sopenharmony_ci		hdev->flags |= DRIVER_FLAGS_BUSY;
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	spin_unlock_irqrestore(&hdev->lock, flags);
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	if (!async_req)
52662306a36Sopenharmony_ci		return res;
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	if (backlog)
52962306a36Sopenharmony_ci		crypto_request_complete(backlog, -EINPROGRESS);
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	req = ahash_request_cast(async_req);
53262306a36Sopenharmony_ci	hdev->req = req;
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	ctx = ahash_request_ctx(req);
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	dev_info(hdev->dev, "processing req, op: %lu, bytes: %d\n",
53762306a36Sopenharmony_ci		 ctx->op, req->nbytes);
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	err = img_hash_hw_init(hdev);
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	if (!err)
54262306a36Sopenharmony_ci		err = img_hash_process_data(hdev);
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	if (err != -EINPROGRESS) {
54562306a36Sopenharmony_ci		/* done_task will not finish so do it here */
54662306a36Sopenharmony_ci		img_hash_finish_req(req, err);
54762306a36Sopenharmony_ci	}
54862306a36Sopenharmony_ci	return res;
54962306a36Sopenharmony_ci}
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_cistatic int img_hash_update(struct ahash_request *req)
55262306a36Sopenharmony_ci{
55362306a36Sopenharmony_ci	struct img_hash_request_ctx *rctx = ahash_request_ctx(req);
55462306a36Sopenharmony_ci	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
55562306a36Sopenharmony_ci	struct img_hash_ctx *ctx = crypto_ahash_ctx(tfm);
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback);
55862306a36Sopenharmony_ci	rctx->fallback_req.base.flags = req->base.flags
55962306a36Sopenharmony_ci		& CRYPTO_TFM_REQ_MAY_SLEEP;
56062306a36Sopenharmony_ci	rctx->fallback_req.nbytes = req->nbytes;
56162306a36Sopenharmony_ci	rctx->fallback_req.src = req->src;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	return crypto_ahash_update(&rctx->fallback_req);
56462306a36Sopenharmony_ci}
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_cistatic int img_hash_final(struct ahash_request *req)
56762306a36Sopenharmony_ci{
56862306a36Sopenharmony_ci	struct img_hash_request_ctx *rctx = ahash_request_ctx(req);
56962306a36Sopenharmony_ci	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
57062306a36Sopenharmony_ci	struct img_hash_ctx *ctx = crypto_ahash_ctx(tfm);
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback);
57362306a36Sopenharmony_ci	rctx->fallback_req.base.flags = req->base.flags
57462306a36Sopenharmony_ci		& CRYPTO_TFM_REQ_MAY_SLEEP;
57562306a36Sopenharmony_ci	rctx->fallback_req.result = req->result;
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	return crypto_ahash_final(&rctx->fallback_req);
57862306a36Sopenharmony_ci}
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_cistatic int img_hash_finup(struct ahash_request *req)
58162306a36Sopenharmony_ci{
58262306a36Sopenharmony_ci	struct img_hash_request_ctx *rctx = ahash_request_ctx(req);
58362306a36Sopenharmony_ci	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
58462306a36Sopenharmony_ci	struct img_hash_ctx *ctx = crypto_ahash_ctx(tfm);
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback);
58762306a36Sopenharmony_ci	rctx->fallback_req.base.flags = req->base.flags
58862306a36Sopenharmony_ci		& CRYPTO_TFM_REQ_MAY_SLEEP;
58962306a36Sopenharmony_ci	rctx->fallback_req.nbytes = req->nbytes;
59062306a36Sopenharmony_ci	rctx->fallback_req.src = req->src;
59162306a36Sopenharmony_ci	rctx->fallback_req.result = req->result;
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	return crypto_ahash_finup(&rctx->fallback_req);
59462306a36Sopenharmony_ci}
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_cistatic int img_hash_import(struct ahash_request *req, const void *in)
59762306a36Sopenharmony_ci{
59862306a36Sopenharmony_ci	struct img_hash_request_ctx *rctx = ahash_request_ctx(req);
59962306a36Sopenharmony_ci	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
60062306a36Sopenharmony_ci	struct img_hash_ctx *ctx = crypto_ahash_ctx(tfm);
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback);
60362306a36Sopenharmony_ci	rctx->fallback_req.base.flags = req->base.flags
60462306a36Sopenharmony_ci		& CRYPTO_TFM_REQ_MAY_SLEEP;
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	return crypto_ahash_import(&rctx->fallback_req, in);
60762306a36Sopenharmony_ci}
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_cistatic int img_hash_export(struct ahash_request *req, void *out)
61062306a36Sopenharmony_ci{
61162306a36Sopenharmony_ci	struct img_hash_request_ctx *rctx = ahash_request_ctx(req);
61262306a36Sopenharmony_ci	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
61362306a36Sopenharmony_ci	struct img_hash_ctx *ctx = crypto_ahash_ctx(tfm);
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback);
61662306a36Sopenharmony_ci	rctx->fallback_req.base.flags = req->base.flags
61762306a36Sopenharmony_ci		& CRYPTO_TFM_REQ_MAY_SLEEP;
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	return crypto_ahash_export(&rctx->fallback_req, out);
62062306a36Sopenharmony_ci}
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_cistatic int img_hash_digest(struct ahash_request *req)
62362306a36Sopenharmony_ci{
62462306a36Sopenharmony_ci	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
62562306a36Sopenharmony_ci	struct img_hash_ctx *tctx = crypto_ahash_ctx(tfm);
62662306a36Sopenharmony_ci	struct img_hash_request_ctx *ctx = ahash_request_ctx(req);
62762306a36Sopenharmony_ci	struct img_hash_dev *hdev = NULL;
62862306a36Sopenharmony_ci	struct img_hash_dev *tmp;
62962306a36Sopenharmony_ci	int err;
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	spin_lock(&img_hash.lock);
63262306a36Sopenharmony_ci	if (!tctx->hdev) {
63362306a36Sopenharmony_ci		list_for_each_entry(tmp, &img_hash.dev_list, list) {
63462306a36Sopenharmony_ci			hdev = tmp;
63562306a36Sopenharmony_ci			break;
63662306a36Sopenharmony_ci		}
63762306a36Sopenharmony_ci		tctx->hdev = hdev;
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	} else {
64062306a36Sopenharmony_ci		hdev = tctx->hdev;
64162306a36Sopenharmony_ci	}
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	spin_unlock(&img_hash.lock);
64462306a36Sopenharmony_ci	ctx->hdev = hdev;
64562306a36Sopenharmony_ci	ctx->flags = 0;
64662306a36Sopenharmony_ci	ctx->digsize = crypto_ahash_digestsize(tfm);
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	switch (ctx->digsize) {
64962306a36Sopenharmony_ci	case SHA1_DIGEST_SIZE:
65062306a36Sopenharmony_ci		ctx->flags |= DRIVER_FLAGS_SHA1;
65162306a36Sopenharmony_ci		break;
65262306a36Sopenharmony_ci	case SHA256_DIGEST_SIZE:
65362306a36Sopenharmony_ci		ctx->flags |= DRIVER_FLAGS_SHA256;
65462306a36Sopenharmony_ci		break;
65562306a36Sopenharmony_ci	case SHA224_DIGEST_SIZE:
65662306a36Sopenharmony_ci		ctx->flags |= DRIVER_FLAGS_SHA224;
65762306a36Sopenharmony_ci		break;
65862306a36Sopenharmony_ci	case MD5_DIGEST_SIZE:
65962306a36Sopenharmony_ci		ctx->flags |= DRIVER_FLAGS_MD5;
66062306a36Sopenharmony_ci		break;
66162306a36Sopenharmony_ci	default:
66262306a36Sopenharmony_ci		return -EINVAL;
66362306a36Sopenharmony_ci	}
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	ctx->bufcnt = 0;
66662306a36Sopenharmony_ci	ctx->offset = 0;
66762306a36Sopenharmony_ci	ctx->sent = 0;
66862306a36Sopenharmony_ci	ctx->total = req->nbytes;
66962306a36Sopenharmony_ci	ctx->sg = req->src;
67062306a36Sopenharmony_ci	ctx->sgfirst = req->src;
67162306a36Sopenharmony_ci	ctx->nents = sg_nents(ctx->sg);
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	err = img_hash_handle_queue(tctx->hdev, req);
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	return err;
67662306a36Sopenharmony_ci}
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_cistatic int img_hash_cra_init(struct crypto_tfm *tfm, const char *alg_name)
67962306a36Sopenharmony_ci{
68062306a36Sopenharmony_ci	struct img_hash_ctx *ctx = crypto_tfm_ctx(tfm);
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	ctx->fallback = crypto_alloc_ahash(alg_name, 0,
68362306a36Sopenharmony_ci					   CRYPTO_ALG_NEED_FALLBACK);
68462306a36Sopenharmony_ci	if (IS_ERR(ctx->fallback)) {
68562306a36Sopenharmony_ci		pr_err("img_hash: Could not load fallback driver.\n");
68662306a36Sopenharmony_ci		return PTR_ERR(ctx->fallback);
68762306a36Sopenharmony_ci	}
68862306a36Sopenharmony_ci	crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
68962306a36Sopenharmony_ci				 sizeof(struct img_hash_request_ctx) +
69062306a36Sopenharmony_ci				 crypto_ahash_reqsize(ctx->fallback) +
69162306a36Sopenharmony_ci				 IMG_HASH_DMA_THRESHOLD);
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci	return 0;
69462306a36Sopenharmony_ci}
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_cistatic int img_hash_cra_md5_init(struct crypto_tfm *tfm)
69762306a36Sopenharmony_ci{
69862306a36Sopenharmony_ci	return img_hash_cra_init(tfm, "md5-generic");
69962306a36Sopenharmony_ci}
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_cistatic int img_hash_cra_sha1_init(struct crypto_tfm *tfm)
70262306a36Sopenharmony_ci{
70362306a36Sopenharmony_ci	return img_hash_cra_init(tfm, "sha1-generic");
70462306a36Sopenharmony_ci}
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_cistatic int img_hash_cra_sha224_init(struct crypto_tfm *tfm)
70762306a36Sopenharmony_ci{
70862306a36Sopenharmony_ci	return img_hash_cra_init(tfm, "sha224-generic");
70962306a36Sopenharmony_ci}
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_cistatic int img_hash_cra_sha256_init(struct crypto_tfm *tfm)
71262306a36Sopenharmony_ci{
71362306a36Sopenharmony_ci	return img_hash_cra_init(tfm, "sha256-generic");
71462306a36Sopenharmony_ci}
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_cistatic void img_hash_cra_exit(struct crypto_tfm *tfm)
71762306a36Sopenharmony_ci{
71862306a36Sopenharmony_ci	struct img_hash_ctx *tctx = crypto_tfm_ctx(tfm);
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	crypto_free_ahash(tctx->fallback);
72162306a36Sopenharmony_ci}
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_cistatic irqreturn_t img_irq_handler(int irq, void *dev_id)
72462306a36Sopenharmony_ci{
72562306a36Sopenharmony_ci	struct img_hash_dev *hdev = dev_id;
72662306a36Sopenharmony_ci	u32 reg;
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	reg = img_hash_read(hdev, CR_INTSTAT);
72962306a36Sopenharmony_ci	img_hash_write(hdev, CR_INTCLEAR, reg);
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	if (reg & CR_INT_NEW_RESULTS_SET) {
73262306a36Sopenharmony_ci		dev_dbg(hdev->dev, "IRQ CR_INT_NEW_RESULTS_SET\n");
73362306a36Sopenharmony_ci		if (DRIVER_FLAGS_BUSY & hdev->flags) {
73462306a36Sopenharmony_ci			hdev->flags |= DRIVER_FLAGS_OUTPUT_READY;
73562306a36Sopenharmony_ci			if (!(DRIVER_FLAGS_CPU & hdev->flags))
73662306a36Sopenharmony_ci				hdev->flags |= DRIVER_FLAGS_DMA_READY;
73762306a36Sopenharmony_ci			tasklet_schedule(&hdev->done_task);
73862306a36Sopenharmony_ci		} else {
73962306a36Sopenharmony_ci			dev_warn(hdev->dev,
74062306a36Sopenharmony_ci				 "HASH interrupt when no active requests.\n");
74162306a36Sopenharmony_ci		}
74262306a36Sopenharmony_ci	} else if (reg & CR_INT_RESULTS_AVAILABLE) {
74362306a36Sopenharmony_ci		dev_warn(hdev->dev,
74462306a36Sopenharmony_ci			 "IRQ triggered before the hash had completed\n");
74562306a36Sopenharmony_ci	} else if (reg & CR_INT_RESULT_READ_ERR) {
74662306a36Sopenharmony_ci		dev_warn(hdev->dev,
74762306a36Sopenharmony_ci			 "Attempt to read from an empty result queue\n");
74862306a36Sopenharmony_ci	} else if (reg & CR_INT_MESSAGE_WRITE_ERROR) {
74962306a36Sopenharmony_ci		dev_warn(hdev->dev,
75062306a36Sopenharmony_ci			 "Data written before the hardware was configured\n");
75162306a36Sopenharmony_ci	}
75262306a36Sopenharmony_ci	return IRQ_HANDLED;
75362306a36Sopenharmony_ci}
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_cistatic struct ahash_alg img_algs[] = {
75662306a36Sopenharmony_ci	{
75762306a36Sopenharmony_ci		.init = img_hash_init,
75862306a36Sopenharmony_ci		.update = img_hash_update,
75962306a36Sopenharmony_ci		.final = img_hash_final,
76062306a36Sopenharmony_ci		.finup = img_hash_finup,
76162306a36Sopenharmony_ci		.export = img_hash_export,
76262306a36Sopenharmony_ci		.import = img_hash_import,
76362306a36Sopenharmony_ci		.digest = img_hash_digest,
76462306a36Sopenharmony_ci		.halg = {
76562306a36Sopenharmony_ci			.digestsize = MD5_DIGEST_SIZE,
76662306a36Sopenharmony_ci			.statesize = sizeof(struct md5_state),
76762306a36Sopenharmony_ci			.base = {
76862306a36Sopenharmony_ci				.cra_name = "md5",
76962306a36Sopenharmony_ci				.cra_driver_name = "img-md5",
77062306a36Sopenharmony_ci				.cra_priority = 300,
77162306a36Sopenharmony_ci				.cra_flags =
77262306a36Sopenharmony_ci				CRYPTO_ALG_ASYNC |
77362306a36Sopenharmony_ci				CRYPTO_ALG_NEED_FALLBACK,
77462306a36Sopenharmony_ci				.cra_blocksize = MD5_HMAC_BLOCK_SIZE,
77562306a36Sopenharmony_ci				.cra_ctxsize = sizeof(struct img_hash_ctx),
77662306a36Sopenharmony_ci				.cra_init = img_hash_cra_md5_init,
77762306a36Sopenharmony_ci				.cra_exit = img_hash_cra_exit,
77862306a36Sopenharmony_ci				.cra_module = THIS_MODULE,
77962306a36Sopenharmony_ci			}
78062306a36Sopenharmony_ci		}
78162306a36Sopenharmony_ci	},
78262306a36Sopenharmony_ci	{
78362306a36Sopenharmony_ci		.init = img_hash_init,
78462306a36Sopenharmony_ci		.update = img_hash_update,
78562306a36Sopenharmony_ci		.final = img_hash_final,
78662306a36Sopenharmony_ci		.finup = img_hash_finup,
78762306a36Sopenharmony_ci		.export = img_hash_export,
78862306a36Sopenharmony_ci		.import = img_hash_import,
78962306a36Sopenharmony_ci		.digest = img_hash_digest,
79062306a36Sopenharmony_ci		.halg = {
79162306a36Sopenharmony_ci			.digestsize = SHA1_DIGEST_SIZE,
79262306a36Sopenharmony_ci			.statesize = sizeof(struct sha1_state),
79362306a36Sopenharmony_ci			.base = {
79462306a36Sopenharmony_ci				.cra_name = "sha1",
79562306a36Sopenharmony_ci				.cra_driver_name = "img-sha1",
79662306a36Sopenharmony_ci				.cra_priority = 300,
79762306a36Sopenharmony_ci				.cra_flags =
79862306a36Sopenharmony_ci				CRYPTO_ALG_ASYNC |
79962306a36Sopenharmony_ci				CRYPTO_ALG_NEED_FALLBACK,
80062306a36Sopenharmony_ci				.cra_blocksize = SHA1_BLOCK_SIZE,
80162306a36Sopenharmony_ci				.cra_ctxsize = sizeof(struct img_hash_ctx),
80262306a36Sopenharmony_ci				.cra_init = img_hash_cra_sha1_init,
80362306a36Sopenharmony_ci				.cra_exit = img_hash_cra_exit,
80462306a36Sopenharmony_ci				.cra_module = THIS_MODULE,
80562306a36Sopenharmony_ci			}
80662306a36Sopenharmony_ci		}
80762306a36Sopenharmony_ci	},
80862306a36Sopenharmony_ci	{
80962306a36Sopenharmony_ci		.init = img_hash_init,
81062306a36Sopenharmony_ci		.update = img_hash_update,
81162306a36Sopenharmony_ci		.final = img_hash_final,
81262306a36Sopenharmony_ci		.finup = img_hash_finup,
81362306a36Sopenharmony_ci		.export = img_hash_export,
81462306a36Sopenharmony_ci		.import = img_hash_import,
81562306a36Sopenharmony_ci		.digest = img_hash_digest,
81662306a36Sopenharmony_ci		.halg = {
81762306a36Sopenharmony_ci			.digestsize = SHA224_DIGEST_SIZE,
81862306a36Sopenharmony_ci			.statesize = sizeof(struct sha256_state),
81962306a36Sopenharmony_ci			.base = {
82062306a36Sopenharmony_ci				.cra_name = "sha224",
82162306a36Sopenharmony_ci				.cra_driver_name = "img-sha224",
82262306a36Sopenharmony_ci				.cra_priority = 300,
82362306a36Sopenharmony_ci				.cra_flags =
82462306a36Sopenharmony_ci				CRYPTO_ALG_ASYNC |
82562306a36Sopenharmony_ci				CRYPTO_ALG_NEED_FALLBACK,
82662306a36Sopenharmony_ci				.cra_blocksize = SHA224_BLOCK_SIZE,
82762306a36Sopenharmony_ci				.cra_ctxsize = sizeof(struct img_hash_ctx),
82862306a36Sopenharmony_ci				.cra_init = img_hash_cra_sha224_init,
82962306a36Sopenharmony_ci				.cra_exit = img_hash_cra_exit,
83062306a36Sopenharmony_ci				.cra_module = THIS_MODULE,
83162306a36Sopenharmony_ci			}
83262306a36Sopenharmony_ci		}
83362306a36Sopenharmony_ci	},
83462306a36Sopenharmony_ci	{
83562306a36Sopenharmony_ci		.init = img_hash_init,
83662306a36Sopenharmony_ci		.update = img_hash_update,
83762306a36Sopenharmony_ci		.final = img_hash_final,
83862306a36Sopenharmony_ci		.finup = img_hash_finup,
83962306a36Sopenharmony_ci		.export = img_hash_export,
84062306a36Sopenharmony_ci		.import = img_hash_import,
84162306a36Sopenharmony_ci		.digest = img_hash_digest,
84262306a36Sopenharmony_ci		.halg = {
84362306a36Sopenharmony_ci			.digestsize = SHA256_DIGEST_SIZE,
84462306a36Sopenharmony_ci			.statesize = sizeof(struct sha256_state),
84562306a36Sopenharmony_ci			.base = {
84662306a36Sopenharmony_ci				.cra_name = "sha256",
84762306a36Sopenharmony_ci				.cra_driver_name = "img-sha256",
84862306a36Sopenharmony_ci				.cra_priority = 300,
84962306a36Sopenharmony_ci				.cra_flags =
85062306a36Sopenharmony_ci				CRYPTO_ALG_ASYNC |
85162306a36Sopenharmony_ci				CRYPTO_ALG_NEED_FALLBACK,
85262306a36Sopenharmony_ci				.cra_blocksize = SHA256_BLOCK_SIZE,
85362306a36Sopenharmony_ci				.cra_ctxsize = sizeof(struct img_hash_ctx),
85462306a36Sopenharmony_ci				.cra_init = img_hash_cra_sha256_init,
85562306a36Sopenharmony_ci				.cra_exit = img_hash_cra_exit,
85662306a36Sopenharmony_ci				.cra_module = THIS_MODULE,
85762306a36Sopenharmony_ci			}
85862306a36Sopenharmony_ci		}
85962306a36Sopenharmony_ci	}
86062306a36Sopenharmony_ci};
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_cistatic int img_register_algs(struct img_hash_dev *hdev)
86362306a36Sopenharmony_ci{
86462306a36Sopenharmony_ci	int i, err;
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(img_algs); i++) {
86762306a36Sopenharmony_ci		err = crypto_register_ahash(&img_algs[i]);
86862306a36Sopenharmony_ci		if (err)
86962306a36Sopenharmony_ci			goto err_reg;
87062306a36Sopenharmony_ci	}
87162306a36Sopenharmony_ci	return 0;
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_cierr_reg:
87462306a36Sopenharmony_ci	for (; i--; )
87562306a36Sopenharmony_ci		crypto_unregister_ahash(&img_algs[i]);
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci	return err;
87862306a36Sopenharmony_ci}
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_cistatic int img_unregister_algs(struct img_hash_dev *hdev)
88162306a36Sopenharmony_ci{
88262306a36Sopenharmony_ci	int i;
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(img_algs); i++)
88562306a36Sopenharmony_ci		crypto_unregister_ahash(&img_algs[i]);
88662306a36Sopenharmony_ci	return 0;
88762306a36Sopenharmony_ci}
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_cistatic void img_hash_done_task(unsigned long data)
89062306a36Sopenharmony_ci{
89162306a36Sopenharmony_ci	struct img_hash_dev *hdev = (struct img_hash_dev *)data;
89262306a36Sopenharmony_ci	int err = 0;
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci	if (hdev->err == -EINVAL) {
89562306a36Sopenharmony_ci		err = hdev->err;
89662306a36Sopenharmony_ci		goto finish;
89762306a36Sopenharmony_ci	}
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci	if (!(DRIVER_FLAGS_BUSY & hdev->flags)) {
90062306a36Sopenharmony_ci		img_hash_handle_queue(hdev, NULL);
90162306a36Sopenharmony_ci		return;
90262306a36Sopenharmony_ci	}
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	if (DRIVER_FLAGS_CPU & hdev->flags) {
90562306a36Sopenharmony_ci		if (DRIVER_FLAGS_OUTPUT_READY & hdev->flags) {
90662306a36Sopenharmony_ci			hdev->flags &= ~DRIVER_FLAGS_OUTPUT_READY;
90762306a36Sopenharmony_ci			goto finish;
90862306a36Sopenharmony_ci		}
90962306a36Sopenharmony_ci	} else if (DRIVER_FLAGS_DMA_READY & hdev->flags) {
91062306a36Sopenharmony_ci		if (DRIVER_FLAGS_DMA_ACTIVE & hdev->flags) {
91162306a36Sopenharmony_ci			hdev->flags &= ~DRIVER_FLAGS_DMA_ACTIVE;
91262306a36Sopenharmony_ci			img_hash_write_via_dma_stop(hdev);
91362306a36Sopenharmony_ci			if (hdev->err) {
91462306a36Sopenharmony_ci				err = hdev->err;
91562306a36Sopenharmony_ci				goto finish;
91662306a36Sopenharmony_ci			}
91762306a36Sopenharmony_ci		}
91862306a36Sopenharmony_ci		if (DRIVER_FLAGS_OUTPUT_READY & hdev->flags) {
91962306a36Sopenharmony_ci			hdev->flags &= ~(DRIVER_FLAGS_DMA_READY |
92062306a36Sopenharmony_ci					DRIVER_FLAGS_OUTPUT_READY);
92162306a36Sopenharmony_ci			goto finish;
92262306a36Sopenharmony_ci		}
92362306a36Sopenharmony_ci	}
92462306a36Sopenharmony_ci	return;
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_cifinish:
92762306a36Sopenharmony_ci	img_hash_finish_req(hdev->req, err);
92862306a36Sopenharmony_ci}
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_cistatic const struct of_device_id img_hash_match[] __maybe_unused = {
93162306a36Sopenharmony_ci	{ .compatible = "img,hash-accelerator" },
93262306a36Sopenharmony_ci	{}
93362306a36Sopenharmony_ci};
93462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, img_hash_match);
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_cistatic int img_hash_probe(struct platform_device *pdev)
93762306a36Sopenharmony_ci{
93862306a36Sopenharmony_ci	struct img_hash_dev *hdev;
93962306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
94062306a36Sopenharmony_ci	struct resource *hash_res;
94162306a36Sopenharmony_ci	int	irq;
94262306a36Sopenharmony_ci	int err;
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci	hdev = devm_kzalloc(dev, sizeof(*hdev), GFP_KERNEL);
94562306a36Sopenharmony_ci	if (hdev == NULL)
94662306a36Sopenharmony_ci		return -ENOMEM;
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	spin_lock_init(&hdev->lock);
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci	hdev->dev = dev;
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci	platform_set_drvdata(pdev, hdev);
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci	INIT_LIST_HEAD(&hdev->list);
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	tasklet_init(&hdev->done_task, img_hash_done_task, (unsigned long)hdev);
95762306a36Sopenharmony_ci	tasklet_init(&hdev->dma_task, img_hash_dma_task, (unsigned long)hdev);
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci	crypto_init_queue(&hdev->queue, IMG_HASH_QUEUE_LENGTH);
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	/* Register bank */
96262306a36Sopenharmony_ci	hdev->io_base = devm_platform_ioremap_resource(pdev, 0);
96362306a36Sopenharmony_ci	if (IS_ERR(hdev->io_base)) {
96462306a36Sopenharmony_ci		err = PTR_ERR(hdev->io_base);
96562306a36Sopenharmony_ci		goto res_err;
96662306a36Sopenharmony_ci	}
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	/* Write port (DMA or CPU) */
96962306a36Sopenharmony_ci	hdev->cpu_addr = devm_platform_get_and_ioremap_resource(pdev, 1, &hash_res);
97062306a36Sopenharmony_ci	if (IS_ERR(hdev->cpu_addr)) {
97162306a36Sopenharmony_ci		err = PTR_ERR(hdev->cpu_addr);
97262306a36Sopenharmony_ci		goto res_err;
97362306a36Sopenharmony_ci	}
97462306a36Sopenharmony_ci	hdev->bus_addr = hash_res->start;
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
97762306a36Sopenharmony_ci	if (irq < 0) {
97862306a36Sopenharmony_ci		err = irq;
97962306a36Sopenharmony_ci		goto res_err;
98062306a36Sopenharmony_ci	}
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci	err = devm_request_irq(dev, irq, img_irq_handler, 0,
98362306a36Sopenharmony_ci			       dev_name(dev), hdev);
98462306a36Sopenharmony_ci	if (err) {
98562306a36Sopenharmony_ci		dev_err(dev, "unable to request irq\n");
98662306a36Sopenharmony_ci		goto res_err;
98762306a36Sopenharmony_ci	}
98862306a36Sopenharmony_ci	dev_dbg(dev, "using IRQ channel %d\n", irq);
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci	hdev->hash_clk = devm_clk_get(&pdev->dev, "hash");
99162306a36Sopenharmony_ci	if (IS_ERR(hdev->hash_clk)) {
99262306a36Sopenharmony_ci		dev_err(dev, "clock initialization failed.\n");
99362306a36Sopenharmony_ci		err = PTR_ERR(hdev->hash_clk);
99462306a36Sopenharmony_ci		goto res_err;
99562306a36Sopenharmony_ci	}
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	hdev->sys_clk = devm_clk_get(&pdev->dev, "sys");
99862306a36Sopenharmony_ci	if (IS_ERR(hdev->sys_clk)) {
99962306a36Sopenharmony_ci		dev_err(dev, "clock initialization failed.\n");
100062306a36Sopenharmony_ci		err = PTR_ERR(hdev->sys_clk);
100162306a36Sopenharmony_ci		goto res_err;
100262306a36Sopenharmony_ci	}
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci	err = clk_prepare_enable(hdev->hash_clk);
100562306a36Sopenharmony_ci	if (err)
100662306a36Sopenharmony_ci		goto res_err;
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	err = clk_prepare_enable(hdev->sys_clk);
100962306a36Sopenharmony_ci	if (err)
101062306a36Sopenharmony_ci		goto clk_err;
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci	err = img_hash_dma_init(hdev);
101362306a36Sopenharmony_ci	if (err)
101462306a36Sopenharmony_ci		goto dma_err;
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci	dev_dbg(dev, "using %s for DMA transfers\n",
101762306a36Sopenharmony_ci		dma_chan_name(hdev->dma_lch));
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci	spin_lock(&img_hash.lock);
102062306a36Sopenharmony_ci	list_add_tail(&hdev->list, &img_hash.dev_list);
102162306a36Sopenharmony_ci	spin_unlock(&img_hash.lock);
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ci	err = img_register_algs(hdev);
102462306a36Sopenharmony_ci	if (err)
102562306a36Sopenharmony_ci		goto err_algs;
102662306a36Sopenharmony_ci	dev_info(dev, "Img MD5/SHA1/SHA224/SHA256 Hardware accelerator initialized\n");
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci	return 0;
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_cierr_algs:
103162306a36Sopenharmony_ci	spin_lock(&img_hash.lock);
103262306a36Sopenharmony_ci	list_del(&hdev->list);
103362306a36Sopenharmony_ci	spin_unlock(&img_hash.lock);
103462306a36Sopenharmony_ci	dma_release_channel(hdev->dma_lch);
103562306a36Sopenharmony_cidma_err:
103662306a36Sopenharmony_ci	clk_disable_unprepare(hdev->sys_clk);
103762306a36Sopenharmony_ciclk_err:
103862306a36Sopenharmony_ci	clk_disable_unprepare(hdev->hash_clk);
103962306a36Sopenharmony_cires_err:
104062306a36Sopenharmony_ci	tasklet_kill(&hdev->done_task);
104162306a36Sopenharmony_ci	tasklet_kill(&hdev->dma_task);
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci	return err;
104462306a36Sopenharmony_ci}
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_cistatic int img_hash_remove(struct platform_device *pdev)
104762306a36Sopenharmony_ci{
104862306a36Sopenharmony_ci	struct img_hash_dev *hdev;
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ci	hdev = platform_get_drvdata(pdev);
105162306a36Sopenharmony_ci	spin_lock(&img_hash.lock);
105262306a36Sopenharmony_ci	list_del(&hdev->list);
105362306a36Sopenharmony_ci	spin_unlock(&img_hash.lock);
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci	img_unregister_algs(hdev);
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci	tasklet_kill(&hdev->done_task);
105862306a36Sopenharmony_ci	tasklet_kill(&hdev->dma_task);
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci	dma_release_channel(hdev->dma_lch);
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci	clk_disable_unprepare(hdev->hash_clk);
106362306a36Sopenharmony_ci	clk_disable_unprepare(hdev->sys_clk);
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	return 0;
106662306a36Sopenharmony_ci}
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
106962306a36Sopenharmony_cistatic int img_hash_suspend(struct device *dev)
107062306a36Sopenharmony_ci{
107162306a36Sopenharmony_ci	struct img_hash_dev *hdev = dev_get_drvdata(dev);
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	clk_disable_unprepare(hdev->hash_clk);
107462306a36Sopenharmony_ci	clk_disable_unprepare(hdev->sys_clk);
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci	return 0;
107762306a36Sopenharmony_ci}
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_cistatic int img_hash_resume(struct device *dev)
108062306a36Sopenharmony_ci{
108162306a36Sopenharmony_ci	struct img_hash_dev *hdev = dev_get_drvdata(dev);
108262306a36Sopenharmony_ci	int ret;
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ci	ret = clk_prepare_enable(hdev->hash_clk);
108562306a36Sopenharmony_ci	if (ret)
108662306a36Sopenharmony_ci		return ret;
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci	ret = clk_prepare_enable(hdev->sys_clk);
108962306a36Sopenharmony_ci	if (ret) {
109062306a36Sopenharmony_ci		clk_disable_unprepare(hdev->hash_clk);
109162306a36Sopenharmony_ci		return ret;
109262306a36Sopenharmony_ci	}
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci	return 0;
109562306a36Sopenharmony_ci}
109662306a36Sopenharmony_ci#endif /* CONFIG_PM_SLEEP */
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_cistatic const struct dev_pm_ops img_hash_pm_ops = {
109962306a36Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(img_hash_suspend, img_hash_resume)
110062306a36Sopenharmony_ci};
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_cistatic struct platform_driver img_hash_driver = {
110362306a36Sopenharmony_ci	.probe		= img_hash_probe,
110462306a36Sopenharmony_ci	.remove		= img_hash_remove,
110562306a36Sopenharmony_ci	.driver		= {
110662306a36Sopenharmony_ci		.name	= "img-hash-accelerator",
110762306a36Sopenharmony_ci		.pm	= &img_hash_pm_ops,
110862306a36Sopenharmony_ci		.of_match_table	= img_hash_match,
110962306a36Sopenharmony_ci	}
111062306a36Sopenharmony_ci};
111162306a36Sopenharmony_cimodule_platform_driver(img_hash_driver);
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
111462306a36Sopenharmony_ciMODULE_DESCRIPTION("Imgtec SHA1/224/256 & MD5 hw accelerator driver");
111562306a36Sopenharmony_ciMODULE_AUTHOR("Will Thomas.");
111662306a36Sopenharmony_ciMODULE_AUTHOR("James Hartley <james.hartley@imgtec.com>");
1117