18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (c) 2014 Imagination Technologies
48c2ecf20Sopenharmony_ci * Authors:  Will Thomas, James Hartley
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci *	Interface structure taken from omap-sham driver
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/clk.h>
108c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h>
118c2ecf20Sopenharmony_ci#include <linux/dmaengine.h>
128c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
138c2ecf20Sopenharmony_ci#include <linux/io.h>
148c2ecf20Sopenharmony_ci#include <linux/kernel.h>
158c2ecf20Sopenharmony_ci#include <linux/module.h>
168c2ecf20Sopenharmony_ci#include <linux/of_device.h>
178c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
188c2ecf20Sopenharmony_ci#include <linux/scatterlist.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include <crypto/internal/hash.h>
218c2ecf20Sopenharmony_ci#include <crypto/md5.h>
228c2ecf20Sopenharmony_ci#include <crypto/sha.h>
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#define CR_RESET			0
258c2ecf20Sopenharmony_ci#define CR_RESET_SET			1
268c2ecf20Sopenharmony_ci#define CR_RESET_UNSET			0
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#define CR_MESSAGE_LENGTH_H		0x4
298c2ecf20Sopenharmony_ci#define CR_MESSAGE_LENGTH_L		0x8
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#define CR_CONTROL			0xc
328c2ecf20Sopenharmony_ci#define CR_CONTROL_BYTE_ORDER_3210	0
338c2ecf20Sopenharmony_ci#define CR_CONTROL_BYTE_ORDER_0123	1
348c2ecf20Sopenharmony_ci#define CR_CONTROL_BYTE_ORDER_2310	2
358c2ecf20Sopenharmony_ci#define CR_CONTROL_BYTE_ORDER_1032	3
368c2ecf20Sopenharmony_ci#define CR_CONTROL_BYTE_ORDER_SHIFT	8
378c2ecf20Sopenharmony_ci#define CR_CONTROL_ALGO_MD5	0
388c2ecf20Sopenharmony_ci#define CR_CONTROL_ALGO_SHA1	1
398c2ecf20Sopenharmony_ci#define CR_CONTROL_ALGO_SHA224	2
408c2ecf20Sopenharmony_ci#define CR_CONTROL_ALGO_SHA256	3
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci#define CR_INTSTAT			0x10
438c2ecf20Sopenharmony_ci#define CR_INTENAB			0x14
448c2ecf20Sopenharmony_ci#define CR_INTCLEAR			0x18
458c2ecf20Sopenharmony_ci#define CR_INT_RESULTS_AVAILABLE	BIT(0)
468c2ecf20Sopenharmony_ci#define CR_INT_NEW_RESULTS_SET		BIT(1)
478c2ecf20Sopenharmony_ci#define CR_INT_RESULT_READ_ERR		BIT(2)
488c2ecf20Sopenharmony_ci#define CR_INT_MESSAGE_WRITE_ERROR	BIT(3)
498c2ecf20Sopenharmony_ci#define CR_INT_STATUS			BIT(8)
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci#define CR_RESULT_QUEUE		0x1c
528c2ecf20Sopenharmony_ci#define CR_RSD0				0x40
538c2ecf20Sopenharmony_ci#define CR_CORE_REV			0x50
548c2ecf20Sopenharmony_ci#define CR_CORE_DES1		0x60
558c2ecf20Sopenharmony_ci#define CR_CORE_DES2		0x70
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci#define DRIVER_FLAGS_BUSY		BIT(0)
588c2ecf20Sopenharmony_ci#define DRIVER_FLAGS_FINAL		BIT(1)
598c2ecf20Sopenharmony_ci#define DRIVER_FLAGS_DMA_ACTIVE		BIT(2)
608c2ecf20Sopenharmony_ci#define DRIVER_FLAGS_OUTPUT_READY	BIT(3)
618c2ecf20Sopenharmony_ci#define DRIVER_FLAGS_INIT		BIT(4)
628c2ecf20Sopenharmony_ci#define DRIVER_FLAGS_CPU		BIT(5)
638c2ecf20Sopenharmony_ci#define DRIVER_FLAGS_DMA_READY		BIT(6)
648c2ecf20Sopenharmony_ci#define DRIVER_FLAGS_ERROR		BIT(7)
658c2ecf20Sopenharmony_ci#define DRIVER_FLAGS_SG			BIT(8)
668c2ecf20Sopenharmony_ci#define DRIVER_FLAGS_SHA1		BIT(18)
678c2ecf20Sopenharmony_ci#define DRIVER_FLAGS_SHA224		BIT(19)
688c2ecf20Sopenharmony_ci#define DRIVER_FLAGS_SHA256		BIT(20)
698c2ecf20Sopenharmony_ci#define DRIVER_FLAGS_MD5		BIT(21)
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci#define IMG_HASH_QUEUE_LENGTH		20
728c2ecf20Sopenharmony_ci#define IMG_HASH_DMA_BURST		4
738c2ecf20Sopenharmony_ci#define IMG_HASH_DMA_THRESHOLD		64
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci#ifdef __LITTLE_ENDIAN
768c2ecf20Sopenharmony_ci#define IMG_HASH_BYTE_ORDER		CR_CONTROL_BYTE_ORDER_3210
778c2ecf20Sopenharmony_ci#else
788c2ecf20Sopenharmony_ci#define IMG_HASH_BYTE_ORDER		CR_CONTROL_BYTE_ORDER_0123
798c2ecf20Sopenharmony_ci#endif
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_cistruct img_hash_dev;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_cistruct img_hash_request_ctx {
848c2ecf20Sopenharmony_ci	struct img_hash_dev	*hdev;
858c2ecf20Sopenharmony_ci	u8 digest[SHA256_DIGEST_SIZE] __aligned(sizeof(u32));
868c2ecf20Sopenharmony_ci	unsigned long		flags;
878c2ecf20Sopenharmony_ci	size_t			digsize;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	dma_addr_t		dma_addr;
908c2ecf20Sopenharmony_ci	size_t			dma_ct;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	/* sg root */
938c2ecf20Sopenharmony_ci	struct scatterlist	*sgfirst;
948c2ecf20Sopenharmony_ci	/* walk state */
958c2ecf20Sopenharmony_ci	struct scatterlist	*sg;
968c2ecf20Sopenharmony_ci	size_t			nents;
978c2ecf20Sopenharmony_ci	size_t			offset;
988c2ecf20Sopenharmony_ci	unsigned int		total;
998c2ecf20Sopenharmony_ci	size_t			sent;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	unsigned long		op;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	size_t			bufcnt;
1048c2ecf20Sopenharmony_ci	struct ahash_request	fallback_req;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	/* Zero length buffer must remain last member of struct */
1078c2ecf20Sopenharmony_ci	u8 buffer[] __aligned(sizeof(u32));
1088c2ecf20Sopenharmony_ci};
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_cistruct img_hash_ctx {
1118c2ecf20Sopenharmony_ci	struct img_hash_dev	*hdev;
1128c2ecf20Sopenharmony_ci	unsigned long		flags;
1138c2ecf20Sopenharmony_ci	struct crypto_ahash	*fallback;
1148c2ecf20Sopenharmony_ci};
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_cistruct img_hash_dev {
1178c2ecf20Sopenharmony_ci	struct list_head	list;
1188c2ecf20Sopenharmony_ci	struct device		*dev;
1198c2ecf20Sopenharmony_ci	struct clk		*hash_clk;
1208c2ecf20Sopenharmony_ci	struct clk		*sys_clk;
1218c2ecf20Sopenharmony_ci	void __iomem		*io_base;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	phys_addr_t		bus_addr;
1248c2ecf20Sopenharmony_ci	void __iomem		*cpu_addr;
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	spinlock_t		lock;
1278c2ecf20Sopenharmony_ci	int			err;
1288c2ecf20Sopenharmony_ci	struct tasklet_struct	done_task;
1298c2ecf20Sopenharmony_ci	struct tasklet_struct	dma_task;
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	unsigned long		flags;
1328c2ecf20Sopenharmony_ci	struct crypto_queue	queue;
1338c2ecf20Sopenharmony_ci	struct ahash_request	*req;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	struct dma_chan		*dma_lch;
1368c2ecf20Sopenharmony_ci};
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_cistruct img_hash_drv {
1398c2ecf20Sopenharmony_ci	struct list_head dev_list;
1408c2ecf20Sopenharmony_ci	spinlock_t lock;
1418c2ecf20Sopenharmony_ci};
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cistatic struct img_hash_drv img_hash = {
1448c2ecf20Sopenharmony_ci	.dev_list = LIST_HEAD_INIT(img_hash.dev_list),
1458c2ecf20Sopenharmony_ci	.lock = __SPIN_LOCK_UNLOCKED(img_hash.lock),
1468c2ecf20Sopenharmony_ci};
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_cistatic inline u32 img_hash_read(struct img_hash_dev *hdev, u32 offset)
1498c2ecf20Sopenharmony_ci{
1508c2ecf20Sopenharmony_ci	return readl_relaxed(hdev->io_base + offset);
1518c2ecf20Sopenharmony_ci}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_cistatic inline void img_hash_write(struct img_hash_dev *hdev,
1548c2ecf20Sopenharmony_ci				  u32 offset, u32 value)
1558c2ecf20Sopenharmony_ci{
1568c2ecf20Sopenharmony_ci	writel_relaxed(value, hdev->io_base + offset);
1578c2ecf20Sopenharmony_ci}
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_cistatic inline u32 img_hash_read_result_queue(struct img_hash_dev *hdev)
1608c2ecf20Sopenharmony_ci{
1618c2ecf20Sopenharmony_ci	return be32_to_cpu(img_hash_read(hdev, CR_RESULT_QUEUE));
1628c2ecf20Sopenharmony_ci}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_cistatic void img_hash_start(struct img_hash_dev *hdev, bool dma)
1658c2ecf20Sopenharmony_ci{
1668c2ecf20Sopenharmony_ci	struct img_hash_request_ctx *ctx = ahash_request_ctx(hdev->req);
1678c2ecf20Sopenharmony_ci	u32 cr = IMG_HASH_BYTE_ORDER << CR_CONTROL_BYTE_ORDER_SHIFT;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	if (ctx->flags & DRIVER_FLAGS_MD5)
1708c2ecf20Sopenharmony_ci		cr |= CR_CONTROL_ALGO_MD5;
1718c2ecf20Sopenharmony_ci	else if (ctx->flags & DRIVER_FLAGS_SHA1)
1728c2ecf20Sopenharmony_ci		cr |= CR_CONTROL_ALGO_SHA1;
1738c2ecf20Sopenharmony_ci	else if (ctx->flags & DRIVER_FLAGS_SHA224)
1748c2ecf20Sopenharmony_ci		cr |= CR_CONTROL_ALGO_SHA224;
1758c2ecf20Sopenharmony_ci	else if (ctx->flags & DRIVER_FLAGS_SHA256)
1768c2ecf20Sopenharmony_ci		cr |= CR_CONTROL_ALGO_SHA256;
1778c2ecf20Sopenharmony_ci	dev_dbg(hdev->dev, "Starting hash process\n");
1788c2ecf20Sopenharmony_ci	img_hash_write(hdev, CR_CONTROL, cr);
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	/*
1818c2ecf20Sopenharmony_ci	 * The hardware block requires two cycles between writing the control
1828c2ecf20Sopenharmony_ci	 * register and writing the first word of data in non DMA mode, to
1838c2ecf20Sopenharmony_ci	 * ensure the first data write is not grouped in burst with the control
1848c2ecf20Sopenharmony_ci	 * register write a read is issued to 'flush' the bus.
1858c2ecf20Sopenharmony_ci	 */
1868c2ecf20Sopenharmony_ci	if (!dma)
1878c2ecf20Sopenharmony_ci		img_hash_read(hdev, CR_CONTROL);
1888c2ecf20Sopenharmony_ci}
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_cistatic int img_hash_xmit_cpu(struct img_hash_dev *hdev, const u8 *buf,
1918c2ecf20Sopenharmony_ci			     size_t length, int final)
1928c2ecf20Sopenharmony_ci{
1938c2ecf20Sopenharmony_ci	u32 count, len32;
1948c2ecf20Sopenharmony_ci	const u32 *buffer = (const u32 *)buf;
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	dev_dbg(hdev->dev, "xmit_cpu:  length: %zu bytes\n", length);
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	if (final)
1998c2ecf20Sopenharmony_ci		hdev->flags |= DRIVER_FLAGS_FINAL;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	len32 = DIV_ROUND_UP(length, sizeof(u32));
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	for (count = 0; count < len32; count++)
2048c2ecf20Sopenharmony_ci		writel_relaxed(buffer[count], hdev->cpu_addr);
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	return -EINPROGRESS;
2078c2ecf20Sopenharmony_ci}
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_cistatic void img_hash_dma_callback(void *data)
2108c2ecf20Sopenharmony_ci{
2118c2ecf20Sopenharmony_ci	struct img_hash_dev *hdev = (struct img_hash_dev *)data;
2128c2ecf20Sopenharmony_ci	struct img_hash_request_ctx *ctx = ahash_request_ctx(hdev->req);
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	if (ctx->bufcnt) {
2158c2ecf20Sopenharmony_ci		img_hash_xmit_cpu(hdev, ctx->buffer, ctx->bufcnt, 0);
2168c2ecf20Sopenharmony_ci		ctx->bufcnt = 0;
2178c2ecf20Sopenharmony_ci	}
2188c2ecf20Sopenharmony_ci	if (ctx->sg)
2198c2ecf20Sopenharmony_ci		tasklet_schedule(&hdev->dma_task);
2208c2ecf20Sopenharmony_ci}
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_cistatic int img_hash_xmit_dma(struct img_hash_dev *hdev, struct scatterlist *sg)
2238c2ecf20Sopenharmony_ci{
2248c2ecf20Sopenharmony_ci	struct dma_async_tx_descriptor *desc;
2258c2ecf20Sopenharmony_ci	struct img_hash_request_ctx *ctx = ahash_request_ctx(hdev->req);
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	ctx->dma_ct = dma_map_sg(hdev->dev, sg, 1, DMA_TO_DEVICE);
2288c2ecf20Sopenharmony_ci	if (ctx->dma_ct == 0) {
2298c2ecf20Sopenharmony_ci		dev_err(hdev->dev, "Invalid DMA sg\n");
2308c2ecf20Sopenharmony_ci		hdev->err = -EINVAL;
2318c2ecf20Sopenharmony_ci		return -EINVAL;
2328c2ecf20Sopenharmony_ci	}
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	desc = dmaengine_prep_slave_sg(hdev->dma_lch,
2358c2ecf20Sopenharmony_ci				       sg,
2368c2ecf20Sopenharmony_ci				       ctx->dma_ct,
2378c2ecf20Sopenharmony_ci				       DMA_MEM_TO_DEV,
2388c2ecf20Sopenharmony_ci				       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
2398c2ecf20Sopenharmony_ci	if (!desc) {
2408c2ecf20Sopenharmony_ci		dev_err(hdev->dev, "Null DMA descriptor\n");
2418c2ecf20Sopenharmony_ci		hdev->err = -EINVAL;
2428c2ecf20Sopenharmony_ci		dma_unmap_sg(hdev->dev, sg, 1, DMA_TO_DEVICE);
2438c2ecf20Sopenharmony_ci		return -EINVAL;
2448c2ecf20Sopenharmony_ci	}
2458c2ecf20Sopenharmony_ci	desc->callback = img_hash_dma_callback;
2468c2ecf20Sopenharmony_ci	desc->callback_param = hdev;
2478c2ecf20Sopenharmony_ci	dmaengine_submit(desc);
2488c2ecf20Sopenharmony_ci	dma_async_issue_pending(hdev->dma_lch);
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	return 0;
2518c2ecf20Sopenharmony_ci}
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_cistatic int img_hash_write_via_cpu(struct img_hash_dev *hdev)
2548c2ecf20Sopenharmony_ci{
2558c2ecf20Sopenharmony_ci	struct img_hash_request_ctx *ctx = ahash_request_ctx(hdev->req);
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	ctx->bufcnt = sg_copy_to_buffer(hdev->req->src, sg_nents(ctx->sg),
2588c2ecf20Sopenharmony_ci					ctx->buffer, hdev->req->nbytes);
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	ctx->total = hdev->req->nbytes;
2618c2ecf20Sopenharmony_ci	ctx->bufcnt = 0;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	hdev->flags |= (DRIVER_FLAGS_CPU | DRIVER_FLAGS_FINAL);
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	img_hash_start(hdev, false);
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	return img_hash_xmit_cpu(hdev, ctx->buffer, ctx->total, 1);
2688c2ecf20Sopenharmony_ci}
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_cistatic int img_hash_finish(struct ahash_request *req)
2718c2ecf20Sopenharmony_ci{
2728c2ecf20Sopenharmony_ci	struct img_hash_request_ctx *ctx = ahash_request_ctx(req);
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	if (!req->result)
2758c2ecf20Sopenharmony_ci		return -EINVAL;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	memcpy(req->result, ctx->digest, ctx->digsize);
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	return 0;
2808c2ecf20Sopenharmony_ci}
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_cistatic void img_hash_copy_hash(struct ahash_request *req)
2838c2ecf20Sopenharmony_ci{
2848c2ecf20Sopenharmony_ci	struct img_hash_request_ctx *ctx = ahash_request_ctx(req);
2858c2ecf20Sopenharmony_ci	u32 *hash = (u32 *)ctx->digest;
2868c2ecf20Sopenharmony_ci	int i;
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	for (i = (ctx->digsize / sizeof(u32)) - 1; i >= 0; i--)
2898c2ecf20Sopenharmony_ci		hash[i] = img_hash_read_result_queue(ctx->hdev);
2908c2ecf20Sopenharmony_ci}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_cistatic void img_hash_finish_req(struct ahash_request *req, int err)
2938c2ecf20Sopenharmony_ci{
2948c2ecf20Sopenharmony_ci	struct img_hash_request_ctx *ctx = ahash_request_ctx(req);
2958c2ecf20Sopenharmony_ci	struct img_hash_dev *hdev =  ctx->hdev;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	if (!err) {
2988c2ecf20Sopenharmony_ci		img_hash_copy_hash(req);
2998c2ecf20Sopenharmony_ci		if (DRIVER_FLAGS_FINAL & hdev->flags)
3008c2ecf20Sopenharmony_ci			err = img_hash_finish(req);
3018c2ecf20Sopenharmony_ci	} else {
3028c2ecf20Sopenharmony_ci		dev_warn(hdev->dev, "Hash failed with error %d\n", err);
3038c2ecf20Sopenharmony_ci		ctx->flags |= DRIVER_FLAGS_ERROR;
3048c2ecf20Sopenharmony_ci	}
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	hdev->flags &= ~(DRIVER_FLAGS_DMA_READY | DRIVER_FLAGS_OUTPUT_READY |
3078c2ecf20Sopenharmony_ci		DRIVER_FLAGS_CPU | DRIVER_FLAGS_BUSY | DRIVER_FLAGS_FINAL);
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	if (req->base.complete)
3108c2ecf20Sopenharmony_ci		req->base.complete(&req->base, err);
3118c2ecf20Sopenharmony_ci}
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_cistatic int img_hash_write_via_dma(struct img_hash_dev *hdev)
3148c2ecf20Sopenharmony_ci{
3158c2ecf20Sopenharmony_ci	struct img_hash_request_ctx *ctx = ahash_request_ctx(hdev->req);
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	img_hash_start(hdev, true);
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	dev_dbg(hdev->dev, "xmit dma size: %d\n", ctx->total);
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	if (!ctx->total)
3228c2ecf20Sopenharmony_ci		hdev->flags |= DRIVER_FLAGS_FINAL;
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	hdev->flags |= DRIVER_FLAGS_DMA_ACTIVE | DRIVER_FLAGS_FINAL;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	tasklet_schedule(&hdev->dma_task);
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	return -EINPROGRESS;
3298c2ecf20Sopenharmony_ci}
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_cistatic int img_hash_dma_init(struct img_hash_dev *hdev)
3328c2ecf20Sopenharmony_ci{
3338c2ecf20Sopenharmony_ci	struct dma_slave_config dma_conf;
3348c2ecf20Sopenharmony_ci	int err;
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	hdev->dma_lch = dma_request_chan(hdev->dev, "tx");
3378c2ecf20Sopenharmony_ci	if (IS_ERR(hdev->dma_lch)) {
3388c2ecf20Sopenharmony_ci		dev_err(hdev->dev, "Couldn't acquire a slave DMA channel.\n");
3398c2ecf20Sopenharmony_ci		return PTR_ERR(hdev->dma_lch);
3408c2ecf20Sopenharmony_ci	}
3418c2ecf20Sopenharmony_ci	dma_conf.direction = DMA_MEM_TO_DEV;
3428c2ecf20Sopenharmony_ci	dma_conf.dst_addr = hdev->bus_addr;
3438c2ecf20Sopenharmony_ci	dma_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
3448c2ecf20Sopenharmony_ci	dma_conf.dst_maxburst = IMG_HASH_DMA_BURST;
3458c2ecf20Sopenharmony_ci	dma_conf.device_fc = false;
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	err = dmaengine_slave_config(hdev->dma_lch,  &dma_conf);
3488c2ecf20Sopenharmony_ci	if (err) {
3498c2ecf20Sopenharmony_ci		dev_err(hdev->dev, "Couldn't configure DMA slave.\n");
3508c2ecf20Sopenharmony_ci		dma_release_channel(hdev->dma_lch);
3518c2ecf20Sopenharmony_ci		return err;
3528c2ecf20Sopenharmony_ci	}
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	return 0;
3558c2ecf20Sopenharmony_ci}
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_cistatic void img_hash_dma_task(unsigned long d)
3588c2ecf20Sopenharmony_ci{
3598c2ecf20Sopenharmony_ci	struct img_hash_dev *hdev = (struct img_hash_dev *)d;
3608c2ecf20Sopenharmony_ci	struct img_hash_request_ctx *ctx;
3618c2ecf20Sopenharmony_ci	u8 *addr;
3628c2ecf20Sopenharmony_ci	size_t nbytes, bleft, wsend, len, tbc;
3638c2ecf20Sopenharmony_ci	struct scatterlist tsg;
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	if (!hdev->req)
3668c2ecf20Sopenharmony_ci		return;
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	ctx = ahash_request_ctx(hdev->req);
3698c2ecf20Sopenharmony_ci	if (!ctx->sg)
3708c2ecf20Sopenharmony_ci		return;
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	addr = sg_virt(ctx->sg);
3738c2ecf20Sopenharmony_ci	nbytes = ctx->sg->length - ctx->offset;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	/*
3768c2ecf20Sopenharmony_ci	 * The hash accelerator does not support a data valid mask. This means
3778c2ecf20Sopenharmony_ci	 * that if each dma (i.e. per page) is not a multiple of 4 bytes, the
3788c2ecf20Sopenharmony_ci	 * padding bytes in the last word written by that dma would erroneously
3798c2ecf20Sopenharmony_ci	 * be included in the hash. To avoid this we round down the transfer,
3808c2ecf20Sopenharmony_ci	 * and add the excess to the start of the next dma. It does not matter
3818c2ecf20Sopenharmony_ci	 * that the final dma may not be a multiple of 4 bytes as the hashing
3828c2ecf20Sopenharmony_ci	 * block is programmed to accept the correct number of bytes.
3838c2ecf20Sopenharmony_ci	 */
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	bleft = nbytes % 4;
3868c2ecf20Sopenharmony_ci	wsend = (nbytes / 4);
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	if (wsend) {
3898c2ecf20Sopenharmony_ci		sg_init_one(&tsg, addr + ctx->offset, wsend * 4);
3908c2ecf20Sopenharmony_ci		if (img_hash_xmit_dma(hdev, &tsg)) {
3918c2ecf20Sopenharmony_ci			dev_err(hdev->dev, "DMA failed, falling back to CPU");
3928c2ecf20Sopenharmony_ci			ctx->flags |= DRIVER_FLAGS_CPU;
3938c2ecf20Sopenharmony_ci			hdev->err = 0;
3948c2ecf20Sopenharmony_ci			img_hash_xmit_cpu(hdev, addr + ctx->offset,
3958c2ecf20Sopenharmony_ci					  wsend * 4, 0);
3968c2ecf20Sopenharmony_ci			ctx->sent += wsend * 4;
3978c2ecf20Sopenharmony_ci			wsend = 0;
3988c2ecf20Sopenharmony_ci		} else {
3998c2ecf20Sopenharmony_ci			ctx->sent += wsend * 4;
4008c2ecf20Sopenharmony_ci		}
4018c2ecf20Sopenharmony_ci	}
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	if (bleft) {
4048c2ecf20Sopenharmony_ci		ctx->bufcnt = sg_pcopy_to_buffer(ctx->sgfirst, ctx->nents,
4058c2ecf20Sopenharmony_ci						 ctx->buffer, bleft, ctx->sent);
4068c2ecf20Sopenharmony_ci		tbc = 0;
4078c2ecf20Sopenharmony_ci		ctx->sg = sg_next(ctx->sg);
4088c2ecf20Sopenharmony_ci		while (ctx->sg && (ctx->bufcnt < 4)) {
4098c2ecf20Sopenharmony_ci			len = ctx->sg->length;
4108c2ecf20Sopenharmony_ci			if (likely(len > (4 - ctx->bufcnt)))
4118c2ecf20Sopenharmony_ci				len = 4 - ctx->bufcnt;
4128c2ecf20Sopenharmony_ci			tbc = sg_pcopy_to_buffer(ctx->sgfirst, ctx->nents,
4138c2ecf20Sopenharmony_ci						 ctx->buffer + ctx->bufcnt, len,
4148c2ecf20Sopenharmony_ci					ctx->sent + ctx->bufcnt);
4158c2ecf20Sopenharmony_ci			ctx->bufcnt += tbc;
4168c2ecf20Sopenharmony_ci			if (tbc >= ctx->sg->length) {
4178c2ecf20Sopenharmony_ci				ctx->sg = sg_next(ctx->sg);
4188c2ecf20Sopenharmony_ci				tbc = 0;
4198c2ecf20Sopenharmony_ci			}
4208c2ecf20Sopenharmony_ci		}
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci		ctx->sent += ctx->bufcnt;
4238c2ecf20Sopenharmony_ci		ctx->offset = tbc;
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci		if (!wsend)
4268c2ecf20Sopenharmony_ci			img_hash_dma_callback(hdev);
4278c2ecf20Sopenharmony_ci	} else {
4288c2ecf20Sopenharmony_ci		ctx->offset = 0;
4298c2ecf20Sopenharmony_ci		ctx->sg = sg_next(ctx->sg);
4308c2ecf20Sopenharmony_ci	}
4318c2ecf20Sopenharmony_ci}
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_cistatic int img_hash_write_via_dma_stop(struct img_hash_dev *hdev)
4348c2ecf20Sopenharmony_ci{
4358c2ecf20Sopenharmony_ci	struct img_hash_request_ctx *ctx = ahash_request_ctx(hdev->req);
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	if (ctx->flags & DRIVER_FLAGS_SG)
4388c2ecf20Sopenharmony_ci		dma_unmap_sg(hdev->dev, ctx->sg, ctx->dma_ct, DMA_TO_DEVICE);
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	return 0;
4418c2ecf20Sopenharmony_ci}
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_cistatic int img_hash_process_data(struct img_hash_dev *hdev)
4448c2ecf20Sopenharmony_ci{
4458c2ecf20Sopenharmony_ci	struct ahash_request *req = hdev->req;
4468c2ecf20Sopenharmony_ci	struct img_hash_request_ctx *ctx = ahash_request_ctx(req);
4478c2ecf20Sopenharmony_ci	int err = 0;
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	ctx->bufcnt = 0;
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	if (req->nbytes >= IMG_HASH_DMA_THRESHOLD) {
4528c2ecf20Sopenharmony_ci		dev_dbg(hdev->dev, "process data request(%d bytes) using DMA\n",
4538c2ecf20Sopenharmony_ci			req->nbytes);
4548c2ecf20Sopenharmony_ci		err = img_hash_write_via_dma(hdev);
4558c2ecf20Sopenharmony_ci	} else {
4568c2ecf20Sopenharmony_ci		dev_dbg(hdev->dev, "process data request(%d bytes) using CPU\n",
4578c2ecf20Sopenharmony_ci			req->nbytes);
4588c2ecf20Sopenharmony_ci		err = img_hash_write_via_cpu(hdev);
4598c2ecf20Sopenharmony_ci	}
4608c2ecf20Sopenharmony_ci	return err;
4618c2ecf20Sopenharmony_ci}
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_cistatic int img_hash_hw_init(struct img_hash_dev *hdev)
4648c2ecf20Sopenharmony_ci{
4658c2ecf20Sopenharmony_ci	unsigned long long nbits;
4668c2ecf20Sopenharmony_ci	u32 u, l;
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	img_hash_write(hdev, CR_RESET, CR_RESET_SET);
4698c2ecf20Sopenharmony_ci	img_hash_write(hdev, CR_RESET, CR_RESET_UNSET);
4708c2ecf20Sopenharmony_ci	img_hash_write(hdev, CR_INTENAB, CR_INT_NEW_RESULTS_SET);
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	nbits = (u64)hdev->req->nbytes << 3;
4738c2ecf20Sopenharmony_ci	u = nbits >> 32;
4748c2ecf20Sopenharmony_ci	l = nbits;
4758c2ecf20Sopenharmony_ci	img_hash_write(hdev, CR_MESSAGE_LENGTH_H, u);
4768c2ecf20Sopenharmony_ci	img_hash_write(hdev, CR_MESSAGE_LENGTH_L, l);
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	if (!(DRIVER_FLAGS_INIT & hdev->flags)) {
4798c2ecf20Sopenharmony_ci		hdev->flags |= DRIVER_FLAGS_INIT;
4808c2ecf20Sopenharmony_ci		hdev->err = 0;
4818c2ecf20Sopenharmony_ci	}
4828c2ecf20Sopenharmony_ci	dev_dbg(hdev->dev, "hw initialized, nbits: %llx\n", nbits);
4838c2ecf20Sopenharmony_ci	return 0;
4848c2ecf20Sopenharmony_ci}
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_cistatic int img_hash_init(struct ahash_request *req)
4878c2ecf20Sopenharmony_ci{
4888c2ecf20Sopenharmony_ci	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
4898c2ecf20Sopenharmony_ci	struct img_hash_request_ctx *rctx = ahash_request_ctx(req);
4908c2ecf20Sopenharmony_ci	struct img_hash_ctx *ctx = crypto_ahash_ctx(tfm);
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback);
4938c2ecf20Sopenharmony_ci	rctx->fallback_req.base.flags =	req->base.flags
4948c2ecf20Sopenharmony_ci		& CRYPTO_TFM_REQ_MAY_SLEEP;
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	return crypto_ahash_init(&rctx->fallback_req);
4978c2ecf20Sopenharmony_ci}
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_cistatic int img_hash_handle_queue(struct img_hash_dev *hdev,
5008c2ecf20Sopenharmony_ci				 struct ahash_request *req)
5018c2ecf20Sopenharmony_ci{
5028c2ecf20Sopenharmony_ci	struct crypto_async_request *async_req, *backlog;
5038c2ecf20Sopenharmony_ci	struct img_hash_request_ctx *ctx;
5048c2ecf20Sopenharmony_ci	unsigned long flags;
5058c2ecf20Sopenharmony_ci	int err = 0, res = 0;
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	spin_lock_irqsave(&hdev->lock, flags);
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	if (req)
5108c2ecf20Sopenharmony_ci		res = ahash_enqueue_request(&hdev->queue, req);
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	if (DRIVER_FLAGS_BUSY & hdev->flags) {
5138c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&hdev->lock, flags);
5148c2ecf20Sopenharmony_ci		return res;
5158c2ecf20Sopenharmony_ci	}
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	backlog = crypto_get_backlog(&hdev->queue);
5188c2ecf20Sopenharmony_ci	async_req = crypto_dequeue_request(&hdev->queue);
5198c2ecf20Sopenharmony_ci	if (async_req)
5208c2ecf20Sopenharmony_ci		hdev->flags |= DRIVER_FLAGS_BUSY;
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&hdev->lock, flags);
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	if (!async_req)
5258c2ecf20Sopenharmony_ci		return res;
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci	if (backlog)
5288c2ecf20Sopenharmony_ci		backlog->complete(backlog, -EINPROGRESS);
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci	req = ahash_request_cast(async_req);
5318c2ecf20Sopenharmony_ci	hdev->req = req;
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	ctx = ahash_request_ctx(req);
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	dev_info(hdev->dev, "processing req, op: %lu, bytes: %d\n",
5368c2ecf20Sopenharmony_ci		 ctx->op, req->nbytes);
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci	err = img_hash_hw_init(hdev);
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	if (!err)
5418c2ecf20Sopenharmony_ci		err = img_hash_process_data(hdev);
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	if (err != -EINPROGRESS) {
5448c2ecf20Sopenharmony_ci		/* done_task will not finish so do it here */
5458c2ecf20Sopenharmony_ci		img_hash_finish_req(req, err);
5468c2ecf20Sopenharmony_ci	}
5478c2ecf20Sopenharmony_ci	return res;
5488c2ecf20Sopenharmony_ci}
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_cistatic int img_hash_update(struct ahash_request *req)
5518c2ecf20Sopenharmony_ci{
5528c2ecf20Sopenharmony_ci	struct img_hash_request_ctx *rctx = ahash_request_ctx(req);
5538c2ecf20Sopenharmony_ci	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
5548c2ecf20Sopenharmony_ci	struct img_hash_ctx *ctx = crypto_ahash_ctx(tfm);
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback);
5578c2ecf20Sopenharmony_ci	rctx->fallback_req.base.flags = req->base.flags
5588c2ecf20Sopenharmony_ci		& CRYPTO_TFM_REQ_MAY_SLEEP;
5598c2ecf20Sopenharmony_ci	rctx->fallback_req.nbytes = req->nbytes;
5608c2ecf20Sopenharmony_ci	rctx->fallback_req.src = req->src;
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	return crypto_ahash_update(&rctx->fallback_req);
5638c2ecf20Sopenharmony_ci}
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_cistatic int img_hash_final(struct ahash_request *req)
5668c2ecf20Sopenharmony_ci{
5678c2ecf20Sopenharmony_ci	struct img_hash_request_ctx *rctx = ahash_request_ctx(req);
5688c2ecf20Sopenharmony_ci	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
5698c2ecf20Sopenharmony_ci	struct img_hash_ctx *ctx = crypto_ahash_ctx(tfm);
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci	ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback);
5728c2ecf20Sopenharmony_ci	rctx->fallback_req.base.flags = req->base.flags
5738c2ecf20Sopenharmony_ci		& CRYPTO_TFM_REQ_MAY_SLEEP;
5748c2ecf20Sopenharmony_ci	rctx->fallback_req.result = req->result;
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	return crypto_ahash_final(&rctx->fallback_req);
5778c2ecf20Sopenharmony_ci}
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_cistatic int img_hash_finup(struct ahash_request *req)
5808c2ecf20Sopenharmony_ci{
5818c2ecf20Sopenharmony_ci	struct img_hash_request_ctx *rctx = ahash_request_ctx(req);
5828c2ecf20Sopenharmony_ci	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
5838c2ecf20Sopenharmony_ci	struct img_hash_ctx *ctx = crypto_ahash_ctx(tfm);
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback);
5868c2ecf20Sopenharmony_ci	rctx->fallback_req.base.flags = req->base.flags
5878c2ecf20Sopenharmony_ci		& CRYPTO_TFM_REQ_MAY_SLEEP;
5888c2ecf20Sopenharmony_ci	rctx->fallback_req.nbytes = req->nbytes;
5898c2ecf20Sopenharmony_ci	rctx->fallback_req.src = req->src;
5908c2ecf20Sopenharmony_ci	rctx->fallback_req.result = req->result;
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	return crypto_ahash_finup(&rctx->fallback_req);
5938c2ecf20Sopenharmony_ci}
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_cistatic int img_hash_import(struct ahash_request *req, const void *in)
5968c2ecf20Sopenharmony_ci{
5978c2ecf20Sopenharmony_ci	struct img_hash_request_ctx *rctx = ahash_request_ctx(req);
5988c2ecf20Sopenharmony_ci	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
5998c2ecf20Sopenharmony_ci	struct img_hash_ctx *ctx = crypto_ahash_ctx(tfm);
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci	ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback);
6028c2ecf20Sopenharmony_ci	rctx->fallback_req.base.flags = req->base.flags
6038c2ecf20Sopenharmony_ci		& CRYPTO_TFM_REQ_MAY_SLEEP;
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci	return crypto_ahash_import(&rctx->fallback_req, in);
6068c2ecf20Sopenharmony_ci}
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_cistatic int img_hash_export(struct ahash_request *req, void *out)
6098c2ecf20Sopenharmony_ci{
6108c2ecf20Sopenharmony_ci	struct img_hash_request_ctx *rctx = ahash_request_ctx(req);
6118c2ecf20Sopenharmony_ci	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
6128c2ecf20Sopenharmony_ci	struct img_hash_ctx *ctx = crypto_ahash_ctx(tfm);
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback);
6158c2ecf20Sopenharmony_ci	rctx->fallback_req.base.flags = req->base.flags
6168c2ecf20Sopenharmony_ci		& CRYPTO_TFM_REQ_MAY_SLEEP;
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci	return crypto_ahash_export(&rctx->fallback_req, out);
6198c2ecf20Sopenharmony_ci}
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_cistatic int img_hash_digest(struct ahash_request *req)
6228c2ecf20Sopenharmony_ci{
6238c2ecf20Sopenharmony_ci	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
6248c2ecf20Sopenharmony_ci	struct img_hash_ctx *tctx = crypto_ahash_ctx(tfm);
6258c2ecf20Sopenharmony_ci	struct img_hash_request_ctx *ctx = ahash_request_ctx(req);
6268c2ecf20Sopenharmony_ci	struct img_hash_dev *hdev = NULL;
6278c2ecf20Sopenharmony_ci	struct img_hash_dev *tmp;
6288c2ecf20Sopenharmony_ci	int err;
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci	spin_lock(&img_hash.lock);
6318c2ecf20Sopenharmony_ci	if (!tctx->hdev) {
6328c2ecf20Sopenharmony_ci		list_for_each_entry(tmp, &img_hash.dev_list, list) {
6338c2ecf20Sopenharmony_ci			hdev = tmp;
6348c2ecf20Sopenharmony_ci			break;
6358c2ecf20Sopenharmony_ci		}
6368c2ecf20Sopenharmony_ci		tctx->hdev = hdev;
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	} else {
6398c2ecf20Sopenharmony_ci		hdev = tctx->hdev;
6408c2ecf20Sopenharmony_ci	}
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci	spin_unlock(&img_hash.lock);
6438c2ecf20Sopenharmony_ci	ctx->hdev = hdev;
6448c2ecf20Sopenharmony_ci	ctx->flags = 0;
6458c2ecf20Sopenharmony_ci	ctx->digsize = crypto_ahash_digestsize(tfm);
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	switch (ctx->digsize) {
6488c2ecf20Sopenharmony_ci	case SHA1_DIGEST_SIZE:
6498c2ecf20Sopenharmony_ci		ctx->flags |= DRIVER_FLAGS_SHA1;
6508c2ecf20Sopenharmony_ci		break;
6518c2ecf20Sopenharmony_ci	case SHA256_DIGEST_SIZE:
6528c2ecf20Sopenharmony_ci		ctx->flags |= DRIVER_FLAGS_SHA256;
6538c2ecf20Sopenharmony_ci		break;
6548c2ecf20Sopenharmony_ci	case SHA224_DIGEST_SIZE:
6558c2ecf20Sopenharmony_ci		ctx->flags |= DRIVER_FLAGS_SHA224;
6568c2ecf20Sopenharmony_ci		break;
6578c2ecf20Sopenharmony_ci	case MD5_DIGEST_SIZE:
6588c2ecf20Sopenharmony_ci		ctx->flags |= DRIVER_FLAGS_MD5;
6598c2ecf20Sopenharmony_ci		break;
6608c2ecf20Sopenharmony_ci	default:
6618c2ecf20Sopenharmony_ci		return -EINVAL;
6628c2ecf20Sopenharmony_ci	}
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ci	ctx->bufcnt = 0;
6658c2ecf20Sopenharmony_ci	ctx->offset = 0;
6668c2ecf20Sopenharmony_ci	ctx->sent = 0;
6678c2ecf20Sopenharmony_ci	ctx->total = req->nbytes;
6688c2ecf20Sopenharmony_ci	ctx->sg = req->src;
6698c2ecf20Sopenharmony_ci	ctx->sgfirst = req->src;
6708c2ecf20Sopenharmony_ci	ctx->nents = sg_nents(ctx->sg);
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	err = img_hash_handle_queue(tctx->hdev, req);
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ci	return err;
6758c2ecf20Sopenharmony_ci}
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_cistatic int img_hash_cra_init(struct crypto_tfm *tfm, const char *alg_name)
6788c2ecf20Sopenharmony_ci{
6798c2ecf20Sopenharmony_ci	struct img_hash_ctx *ctx = crypto_tfm_ctx(tfm);
6808c2ecf20Sopenharmony_ci	int err = -ENOMEM;
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci	ctx->fallback = crypto_alloc_ahash(alg_name, 0,
6838c2ecf20Sopenharmony_ci					   CRYPTO_ALG_NEED_FALLBACK);
6848c2ecf20Sopenharmony_ci	if (IS_ERR(ctx->fallback)) {
6858c2ecf20Sopenharmony_ci		pr_err("img_hash: Could not load fallback driver.\n");
6868c2ecf20Sopenharmony_ci		err = PTR_ERR(ctx->fallback);
6878c2ecf20Sopenharmony_ci		goto err;
6888c2ecf20Sopenharmony_ci	}
6898c2ecf20Sopenharmony_ci	crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
6908c2ecf20Sopenharmony_ci				 sizeof(struct img_hash_request_ctx) +
6918c2ecf20Sopenharmony_ci				 crypto_ahash_reqsize(ctx->fallback) +
6928c2ecf20Sopenharmony_ci				 IMG_HASH_DMA_THRESHOLD);
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci	return 0;
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_cierr:
6978c2ecf20Sopenharmony_ci	return err;
6988c2ecf20Sopenharmony_ci}
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_cistatic int img_hash_cra_md5_init(struct crypto_tfm *tfm)
7018c2ecf20Sopenharmony_ci{
7028c2ecf20Sopenharmony_ci	return img_hash_cra_init(tfm, "md5-generic");
7038c2ecf20Sopenharmony_ci}
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_cistatic int img_hash_cra_sha1_init(struct crypto_tfm *tfm)
7068c2ecf20Sopenharmony_ci{
7078c2ecf20Sopenharmony_ci	return img_hash_cra_init(tfm, "sha1-generic");
7088c2ecf20Sopenharmony_ci}
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_cistatic int img_hash_cra_sha224_init(struct crypto_tfm *tfm)
7118c2ecf20Sopenharmony_ci{
7128c2ecf20Sopenharmony_ci	return img_hash_cra_init(tfm, "sha224-generic");
7138c2ecf20Sopenharmony_ci}
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_cistatic int img_hash_cra_sha256_init(struct crypto_tfm *tfm)
7168c2ecf20Sopenharmony_ci{
7178c2ecf20Sopenharmony_ci	return img_hash_cra_init(tfm, "sha256-generic");
7188c2ecf20Sopenharmony_ci}
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_cistatic void img_hash_cra_exit(struct crypto_tfm *tfm)
7218c2ecf20Sopenharmony_ci{
7228c2ecf20Sopenharmony_ci	struct img_hash_ctx *tctx = crypto_tfm_ctx(tfm);
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci	crypto_free_ahash(tctx->fallback);
7258c2ecf20Sopenharmony_ci}
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_cistatic irqreturn_t img_irq_handler(int irq, void *dev_id)
7288c2ecf20Sopenharmony_ci{
7298c2ecf20Sopenharmony_ci	struct img_hash_dev *hdev = dev_id;
7308c2ecf20Sopenharmony_ci	u32 reg;
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci	reg = img_hash_read(hdev, CR_INTSTAT);
7338c2ecf20Sopenharmony_ci	img_hash_write(hdev, CR_INTCLEAR, reg);
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci	if (reg & CR_INT_NEW_RESULTS_SET) {
7368c2ecf20Sopenharmony_ci		dev_dbg(hdev->dev, "IRQ CR_INT_NEW_RESULTS_SET\n");
7378c2ecf20Sopenharmony_ci		if (DRIVER_FLAGS_BUSY & hdev->flags) {
7388c2ecf20Sopenharmony_ci			hdev->flags |= DRIVER_FLAGS_OUTPUT_READY;
7398c2ecf20Sopenharmony_ci			if (!(DRIVER_FLAGS_CPU & hdev->flags))
7408c2ecf20Sopenharmony_ci				hdev->flags |= DRIVER_FLAGS_DMA_READY;
7418c2ecf20Sopenharmony_ci			tasklet_schedule(&hdev->done_task);
7428c2ecf20Sopenharmony_ci		} else {
7438c2ecf20Sopenharmony_ci			dev_warn(hdev->dev,
7448c2ecf20Sopenharmony_ci				 "HASH interrupt when no active requests.\n");
7458c2ecf20Sopenharmony_ci		}
7468c2ecf20Sopenharmony_ci	} else if (reg & CR_INT_RESULTS_AVAILABLE) {
7478c2ecf20Sopenharmony_ci		dev_warn(hdev->dev,
7488c2ecf20Sopenharmony_ci			 "IRQ triggered before the hash had completed\n");
7498c2ecf20Sopenharmony_ci	} else if (reg & CR_INT_RESULT_READ_ERR) {
7508c2ecf20Sopenharmony_ci		dev_warn(hdev->dev,
7518c2ecf20Sopenharmony_ci			 "Attempt to read from an empty result queue\n");
7528c2ecf20Sopenharmony_ci	} else if (reg & CR_INT_MESSAGE_WRITE_ERROR) {
7538c2ecf20Sopenharmony_ci		dev_warn(hdev->dev,
7548c2ecf20Sopenharmony_ci			 "Data written before the hardware was configured\n");
7558c2ecf20Sopenharmony_ci	}
7568c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
7578c2ecf20Sopenharmony_ci}
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_cistatic struct ahash_alg img_algs[] = {
7608c2ecf20Sopenharmony_ci	{
7618c2ecf20Sopenharmony_ci		.init = img_hash_init,
7628c2ecf20Sopenharmony_ci		.update = img_hash_update,
7638c2ecf20Sopenharmony_ci		.final = img_hash_final,
7648c2ecf20Sopenharmony_ci		.finup = img_hash_finup,
7658c2ecf20Sopenharmony_ci		.export = img_hash_export,
7668c2ecf20Sopenharmony_ci		.import = img_hash_import,
7678c2ecf20Sopenharmony_ci		.digest = img_hash_digest,
7688c2ecf20Sopenharmony_ci		.halg = {
7698c2ecf20Sopenharmony_ci			.digestsize = MD5_DIGEST_SIZE,
7708c2ecf20Sopenharmony_ci			.statesize = sizeof(struct md5_state),
7718c2ecf20Sopenharmony_ci			.base = {
7728c2ecf20Sopenharmony_ci				.cra_name = "md5",
7738c2ecf20Sopenharmony_ci				.cra_driver_name = "img-md5",
7748c2ecf20Sopenharmony_ci				.cra_priority = 300,
7758c2ecf20Sopenharmony_ci				.cra_flags =
7768c2ecf20Sopenharmony_ci				CRYPTO_ALG_ASYNC |
7778c2ecf20Sopenharmony_ci				CRYPTO_ALG_NEED_FALLBACK,
7788c2ecf20Sopenharmony_ci				.cra_blocksize = MD5_HMAC_BLOCK_SIZE,
7798c2ecf20Sopenharmony_ci				.cra_ctxsize = sizeof(struct img_hash_ctx),
7808c2ecf20Sopenharmony_ci				.cra_init = img_hash_cra_md5_init,
7818c2ecf20Sopenharmony_ci				.cra_exit = img_hash_cra_exit,
7828c2ecf20Sopenharmony_ci				.cra_module = THIS_MODULE,
7838c2ecf20Sopenharmony_ci			}
7848c2ecf20Sopenharmony_ci		}
7858c2ecf20Sopenharmony_ci	},
7868c2ecf20Sopenharmony_ci	{
7878c2ecf20Sopenharmony_ci		.init = img_hash_init,
7888c2ecf20Sopenharmony_ci		.update = img_hash_update,
7898c2ecf20Sopenharmony_ci		.final = img_hash_final,
7908c2ecf20Sopenharmony_ci		.finup = img_hash_finup,
7918c2ecf20Sopenharmony_ci		.export = img_hash_export,
7928c2ecf20Sopenharmony_ci		.import = img_hash_import,
7938c2ecf20Sopenharmony_ci		.digest = img_hash_digest,
7948c2ecf20Sopenharmony_ci		.halg = {
7958c2ecf20Sopenharmony_ci			.digestsize = SHA1_DIGEST_SIZE,
7968c2ecf20Sopenharmony_ci			.statesize = sizeof(struct sha1_state),
7978c2ecf20Sopenharmony_ci			.base = {
7988c2ecf20Sopenharmony_ci				.cra_name = "sha1",
7998c2ecf20Sopenharmony_ci				.cra_driver_name = "img-sha1",
8008c2ecf20Sopenharmony_ci				.cra_priority = 300,
8018c2ecf20Sopenharmony_ci				.cra_flags =
8028c2ecf20Sopenharmony_ci				CRYPTO_ALG_ASYNC |
8038c2ecf20Sopenharmony_ci				CRYPTO_ALG_NEED_FALLBACK,
8048c2ecf20Sopenharmony_ci				.cra_blocksize = SHA1_BLOCK_SIZE,
8058c2ecf20Sopenharmony_ci				.cra_ctxsize = sizeof(struct img_hash_ctx),
8068c2ecf20Sopenharmony_ci				.cra_init = img_hash_cra_sha1_init,
8078c2ecf20Sopenharmony_ci				.cra_exit = img_hash_cra_exit,
8088c2ecf20Sopenharmony_ci				.cra_module = THIS_MODULE,
8098c2ecf20Sopenharmony_ci			}
8108c2ecf20Sopenharmony_ci		}
8118c2ecf20Sopenharmony_ci	},
8128c2ecf20Sopenharmony_ci	{
8138c2ecf20Sopenharmony_ci		.init = img_hash_init,
8148c2ecf20Sopenharmony_ci		.update = img_hash_update,
8158c2ecf20Sopenharmony_ci		.final = img_hash_final,
8168c2ecf20Sopenharmony_ci		.finup = img_hash_finup,
8178c2ecf20Sopenharmony_ci		.export = img_hash_export,
8188c2ecf20Sopenharmony_ci		.import = img_hash_import,
8198c2ecf20Sopenharmony_ci		.digest = img_hash_digest,
8208c2ecf20Sopenharmony_ci		.halg = {
8218c2ecf20Sopenharmony_ci			.digestsize = SHA224_DIGEST_SIZE,
8228c2ecf20Sopenharmony_ci			.statesize = sizeof(struct sha256_state),
8238c2ecf20Sopenharmony_ci			.base = {
8248c2ecf20Sopenharmony_ci				.cra_name = "sha224",
8258c2ecf20Sopenharmony_ci				.cra_driver_name = "img-sha224",
8268c2ecf20Sopenharmony_ci				.cra_priority = 300,
8278c2ecf20Sopenharmony_ci				.cra_flags =
8288c2ecf20Sopenharmony_ci				CRYPTO_ALG_ASYNC |
8298c2ecf20Sopenharmony_ci				CRYPTO_ALG_NEED_FALLBACK,
8308c2ecf20Sopenharmony_ci				.cra_blocksize = SHA224_BLOCK_SIZE,
8318c2ecf20Sopenharmony_ci				.cra_ctxsize = sizeof(struct img_hash_ctx),
8328c2ecf20Sopenharmony_ci				.cra_init = img_hash_cra_sha224_init,
8338c2ecf20Sopenharmony_ci				.cra_exit = img_hash_cra_exit,
8348c2ecf20Sopenharmony_ci				.cra_module = THIS_MODULE,
8358c2ecf20Sopenharmony_ci			}
8368c2ecf20Sopenharmony_ci		}
8378c2ecf20Sopenharmony_ci	},
8388c2ecf20Sopenharmony_ci	{
8398c2ecf20Sopenharmony_ci		.init = img_hash_init,
8408c2ecf20Sopenharmony_ci		.update = img_hash_update,
8418c2ecf20Sopenharmony_ci		.final = img_hash_final,
8428c2ecf20Sopenharmony_ci		.finup = img_hash_finup,
8438c2ecf20Sopenharmony_ci		.export = img_hash_export,
8448c2ecf20Sopenharmony_ci		.import = img_hash_import,
8458c2ecf20Sopenharmony_ci		.digest = img_hash_digest,
8468c2ecf20Sopenharmony_ci		.halg = {
8478c2ecf20Sopenharmony_ci			.digestsize = SHA256_DIGEST_SIZE,
8488c2ecf20Sopenharmony_ci			.statesize = sizeof(struct sha256_state),
8498c2ecf20Sopenharmony_ci			.base = {
8508c2ecf20Sopenharmony_ci				.cra_name = "sha256",
8518c2ecf20Sopenharmony_ci				.cra_driver_name = "img-sha256",
8528c2ecf20Sopenharmony_ci				.cra_priority = 300,
8538c2ecf20Sopenharmony_ci				.cra_flags =
8548c2ecf20Sopenharmony_ci				CRYPTO_ALG_ASYNC |
8558c2ecf20Sopenharmony_ci				CRYPTO_ALG_NEED_FALLBACK,
8568c2ecf20Sopenharmony_ci				.cra_blocksize = SHA256_BLOCK_SIZE,
8578c2ecf20Sopenharmony_ci				.cra_ctxsize = sizeof(struct img_hash_ctx),
8588c2ecf20Sopenharmony_ci				.cra_init = img_hash_cra_sha256_init,
8598c2ecf20Sopenharmony_ci				.cra_exit = img_hash_cra_exit,
8608c2ecf20Sopenharmony_ci				.cra_module = THIS_MODULE,
8618c2ecf20Sopenharmony_ci			}
8628c2ecf20Sopenharmony_ci		}
8638c2ecf20Sopenharmony_ci	}
8648c2ecf20Sopenharmony_ci};
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_cistatic int img_register_algs(struct img_hash_dev *hdev)
8678c2ecf20Sopenharmony_ci{
8688c2ecf20Sopenharmony_ci	int i, err;
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(img_algs); i++) {
8718c2ecf20Sopenharmony_ci		err = crypto_register_ahash(&img_algs[i]);
8728c2ecf20Sopenharmony_ci		if (err)
8738c2ecf20Sopenharmony_ci			goto err_reg;
8748c2ecf20Sopenharmony_ci	}
8758c2ecf20Sopenharmony_ci	return 0;
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_cierr_reg:
8788c2ecf20Sopenharmony_ci	for (; i--; )
8798c2ecf20Sopenharmony_ci		crypto_unregister_ahash(&img_algs[i]);
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_ci	return err;
8828c2ecf20Sopenharmony_ci}
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_cistatic int img_unregister_algs(struct img_hash_dev *hdev)
8858c2ecf20Sopenharmony_ci{
8868c2ecf20Sopenharmony_ci	int i;
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(img_algs); i++)
8898c2ecf20Sopenharmony_ci		crypto_unregister_ahash(&img_algs[i]);
8908c2ecf20Sopenharmony_ci	return 0;
8918c2ecf20Sopenharmony_ci}
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_cistatic void img_hash_done_task(unsigned long data)
8948c2ecf20Sopenharmony_ci{
8958c2ecf20Sopenharmony_ci	struct img_hash_dev *hdev = (struct img_hash_dev *)data;
8968c2ecf20Sopenharmony_ci	int err = 0;
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci	if (hdev->err == -EINVAL) {
8998c2ecf20Sopenharmony_ci		err = hdev->err;
9008c2ecf20Sopenharmony_ci		goto finish;
9018c2ecf20Sopenharmony_ci	}
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci	if (!(DRIVER_FLAGS_BUSY & hdev->flags)) {
9048c2ecf20Sopenharmony_ci		img_hash_handle_queue(hdev, NULL);
9058c2ecf20Sopenharmony_ci		return;
9068c2ecf20Sopenharmony_ci	}
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_ci	if (DRIVER_FLAGS_CPU & hdev->flags) {
9098c2ecf20Sopenharmony_ci		if (DRIVER_FLAGS_OUTPUT_READY & hdev->flags) {
9108c2ecf20Sopenharmony_ci			hdev->flags &= ~DRIVER_FLAGS_OUTPUT_READY;
9118c2ecf20Sopenharmony_ci			goto finish;
9128c2ecf20Sopenharmony_ci		}
9138c2ecf20Sopenharmony_ci	} else if (DRIVER_FLAGS_DMA_READY & hdev->flags) {
9148c2ecf20Sopenharmony_ci		if (DRIVER_FLAGS_DMA_ACTIVE & hdev->flags) {
9158c2ecf20Sopenharmony_ci			hdev->flags &= ~DRIVER_FLAGS_DMA_ACTIVE;
9168c2ecf20Sopenharmony_ci			img_hash_write_via_dma_stop(hdev);
9178c2ecf20Sopenharmony_ci			if (hdev->err) {
9188c2ecf20Sopenharmony_ci				err = hdev->err;
9198c2ecf20Sopenharmony_ci				goto finish;
9208c2ecf20Sopenharmony_ci			}
9218c2ecf20Sopenharmony_ci		}
9228c2ecf20Sopenharmony_ci		if (DRIVER_FLAGS_OUTPUT_READY & hdev->flags) {
9238c2ecf20Sopenharmony_ci			hdev->flags &= ~(DRIVER_FLAGS_DMA_READY |
9248c2ecf20Sopenharmony_ci					DRIVER_FLAGS_OUTPUT_READY);
9258c2ecf20Sopenharmony_ci			goto finish;
9268c2ecf20Sopenharmony_ci		}
9278c2ecf20Sopenharmony_ci	}
9288c2ecf20Sopenharmony_ci	return;
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_cifinish:
9318c2ecf20Sopenharmony_ci	img_hash_finish_req(hdev->req, err);
9328c2ecf20Sopenharmony_ci}
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_cistatic const struct of_device_id img_hash_match[] = {
9358c2ecf20Sopenharmony_ci	{ .compatible = "img,hash-accelerator" },
9368c2ecf20Sopenharmony_ci	{}
9378c2ecf20Sopenharmony_ci};
9388c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, img_hash_match);
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_cistatic int img_hash_probe(struct platform_device *pdev)
9418c2ecf20Sopenharmony_ci{
9428c2ecf20Sopenharmony_ci	struct img_hash_dev *hdev;
9438c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
9448c2ecf20Sopenharmony_ci	struct resource *hash_res;
9458c2ecf20Sopenharmony_ci	int	irq;
9468c2ecf20Sopenharmony_ci	int err;
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_ci	hdev = devm_kzalloc(dev, sizeof(*hdev), GFP_KERNEL);
9498c2ecf20Sopenharmony_ci	if (hdev == NULL)
9508c2ecf20Sopenharmony_ci		return -ENOMEM;
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_ci	spin_lock_init(&hdev->lock);
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_ci	hdev->dev = dev;
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, hdev);
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&hdev->list);
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_ci	tasklet_init(&hdev->done_task, img_hash_done_task, (unsigned long)hdev);
9618c2ecf20Sopenharmony_ci	tasklet_init(&hdev->dma_task, img_hash_dma_task, (unsigned long)hdev);
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci	crypto_init_queue(&hdev->queue, IMG_HASH_QUEUE_LENGTH);
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci	/* Register bank */
9668c2ecf20Sopenharmony_ci	hdev->io_base = devm_platform_ioremap_resource(pdev, 0);
9678c2ecf20Sopenharmony_ci	if (IS_ERR(hdev->io_base)) {
9688c2ecf20Sopenharmony_ci		err = PTR_ERR(hdev->io_base);
9698c2ecf20Sopenharmony_ci		dev_err(dev, "can't ioremap, returned %d\n", err);
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci		goto res_err;
9728c2ecf20Sopenharmony_ci	}
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_ci	/* Write port (DMA or CPU) */
9758c2ecf20Sopenharmony_ci	hash_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
9768c2ecf20Sopenharmony_ci	hdev->cpu_addr = devm_ioremap_resource(dev, hash_res);
9778c2ecf20Sopenharmony_ci	if (IS_ERR(hdev->cpu_addr)) {
9788c2ecf20Sopenharmony_ci		dev_err(dev, "can't ioremap write port\n");
9798c2ecf20Sopenharmony_ci		err = PTR_ERR(hdev->cpu_addr);
9808c2ecf20Sopenharmony_ci		goto res_err;
9818c2ecf20Sopenharmony_ci	}
9828c2ecf20Sopenharmony_ci	hdev->bus_addr = hash_res->start;
9838c2ecf20Sopenharmony_ci
9848c2ecf20Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
9858c2ecf20Sopenharmony_ci	if (irq < 0) {
9868c2ecf20Sopenharmony_ci		err = irq;
9878c2ecf20Sopenharmony_ci		goto res_err;
9888c2ecf20Sopenharmony_ci	}
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_ci	err = devm_request_irq(dev, irq, img_irq_handler, 0,
9918c2ecf20Sopenharmony_ci			       dev_name(dev), hdev);
9928c2ecf20Sopenharmony_ci	if (err) {
9938c2ecf20Sopenharmony_ci		dev_err(dev, "unable to request irq\n");
9948c2ecf20Sopenharmony_ci		goto res_err;
9958c2ecf20Sopenharmony_ci	}
9968c2ecf20Sopenharmony_ci	dev_dbg(dev, "using IRQ channel %d\n", irq);
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_ci	hdev->hash_clk = devm_clk_get(&pdev->dev, "hash");
9998c2ecf20Sopenharmony_ci	if (IS_ERR(hdev->hash_clk)) {
10008c2ecf20Sopenharmony_ci		dev_err(dev, "clock initialization failed.\n");
10018c2ecf20Sopenharmony_ci		err = PTR_ERR(hdev->hash_clk);
10028c2ecf20Sopenharmony_ci		goto res_err;
10038c2ecf20Sopenharmony_ci	}
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci	hdev->sys_clk = devm_clk_get(&pdev->dev, "sys");
10068c2ecf20Sopenharmony_ci	if (IS_ERR(hdev->sys_clk)) {
10078c2ecf20Sopenharmony_ci		dev_err(dev, "clock initialization failed.\n");
10088c2ecf20Sopenharmony_ci		err = PTR_ERR(hdev->sys_clk);
10098c2ecf20Sopenharmony_ci		goto res_err;
10108c2ecf20Sopenharmony_ci	}
10118c2ecf20Sopenharmony_ci
10128c2ecf20Sopenharmony_ci	err = clk_prepare_enable(hdev->hash_clk);
10138c2ecf20Sopenharmony_ci	if (err)
10148c2ecf20Sopenharmony_ci		goto res_err;
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci	err = clk_prepare_enable(hdev->sys_clk);
10178c2ecf20Sopenharmony_ci	if (err)
10188c2ecf20Sopenharmony_ci		goto clk_err;
10198c2ecf20Sopenharmony_ci
10208c2ecf20Sopenharmony_ci	err = img_hash_dma_init(hdev);
10218c2ecf20Sopenharmony_ci	if (err)
10228c2ecf20Sopenharmony_ci		goto dma_err;
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci	dev_dbg(dev, "using %s for DMA transfers\n",
10258c2ecf20Sopenharmony_ci		dma_chan_name(hdev->dma_lch));
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci	spin_lock(&img_hash.lock);
10288c2ecf20Sopenharmony_ci	list_add_tail(&hdev->list, &img_hash.dev_list);
10298c2ecf20Sopenharmony_ci	spin_unlock(&img_hash.lock);
10308c2ecf20Sopenharmony_ci
10318c2ecf20Sopenharmony_ci	err = img_register_algs(hdev);
10328c2ecf20Sopenharmony_ci	if (err)
10338c2ecf20Sopenharmony_ci		goto err_algs;
10348c2ecf20Sopenharmony_ci	dev_info(dev, "Img MD5/SHA1/SHA224/SHA256 Hardware accelerator initialized\n");
10358c2ecf20Sopenharmony_ci
10368c2ecf20Sopenharmony_ci	return 0;
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_cierr_algs:
10398c2ecf20Sopenharmony_ci	spin_lock(&img_hash.lock);
10408c2ecf20Sopenharmony_ci	list_del(&hdev->list);
10418c2ecf20Sopenharmony_ci	spin_unlock(&img_hash.lock);
10428c2ecf20Sopenharmony_ci	dma_release_channel(hdev->dma_lch);
10438c2ecf20Sopenharmony_cidma_err:
10448c2ecf20Sopenharmony_ci	clk_disable_unprepare(hdev->sys_clk);
10458c2ecf20Sopenharmony_ciclk_err:
10468c2ecf20Sopenharmony_ci	clk_disable_unprepare(hdev->hash_clk);
10478c2ecf20Sopenharmony_cires_err:
10488c2ecf20Sopenharmony_ci	tasklet_kill(&hdev->done_task);
10498c2ecf20Sopenharmony_ci	tasklet_kill(&hdev->dma_task);
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci	return err;
10528c2ecf20Sopenharmony_ci}
10538c2ecf20Sopenharmony_ci
10548c2ecf20Sopenharmony_cistatic int img_hash_remove(struct platform_device *pdev)
10558c2ecf20Sopenharmony_ci{
10568c2ecf20Sopenharmony_ci	struct img_hash_dev *hdev;
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_ci	hdev = platform_get_drvdata(pdev);
10598c2ecf20Sopenharmony_ci	spin_lock(&img_hash.lock);
10608c2ecf20Sopenharmony_ci	list_del(&hdev->list);
10618c2ecf20Sopenharmony_ci	spin_unlock(&img_hash.lock);
10628c2ecf20Sopenharmony_ci
10638c2ecf20Sopenharmony_ci	img_unregister_algs(hdev);
10648c2ecf20Sopenharmony_ci
10658c2ecf20Sopenharmony_ci	tasklet_kill(&hdev->done_task);
10668c2ecf20Sopenharmony_ci	tasklet_kill(&hdev->dma_task);
10678c2ecf20Sopenharmony_ci
10688c2ecf20Sopenharmony_ci	dma_release_channel(hdev->dma_lch);
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_ci	clk_disable_unprepare(hdev->hash_clk);
10718c2ecf20Sopenharmony_ci	clk_disable_unprepare(hdev->sys_clk);
10728c2ecf20Sopenharmony_ci
10738c2ecf20Sopenharmony_ci	return 0;
10748c2ecf20Sopenharmony_ci}
10758c2ecf20Sopenharmony_ci
10768c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
10778c2ecf20Sopenharmony_cistatic int img_hash_suspend(struct device *dev)
10788c2ecf20Sopenharmony_ci{
10798c2ecf20Sopenharmony_ci	struct img_hash_dev *hdev = dev_get_drvdata(dev);
10808c2ecf20Sopenharmony_ci
10818c2ecf20Sopenharmony_ci	clk_disable_unprepare(hdev->hash_clk);
10828c2ecf20Sopenharmony_ci	clk_disable_unprepare(hdev->sys_clk);
10838c2ecf20Sopenharmony_ci
10848c2ecf20Sopenharmony_ci	return 0;
10858c2ecf20Sopenharmony_ci}
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_cistatic int img_hash_resume(struct device *dev)
10888c2ecf20Sopenharmony_ci{
10898c2ecf20Sopenharmony_ci	struct img_hash_dev *hdev = dev_get_drvdata(dev);
10908c2ecf20Sopenharmony_ci	int ret;
10918c2ecf20Sopenharmony_ci
10928c2ecf20Sopenharmony_ci	ret = clk_prepare_enable(hdev->hash_clk);
10938c2ecf20Sopenharmony_ci	if (ret)
10948c2ecf20Sopenharmony_ci		return ret;
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_ci	ret = clk_prepare_enable(hdev->sys_clk);
10978c2ecf20Sopenharmony_ci	if (ret) {
10988c2ecf20Sopenharmony_ci		clk_disable_unprepare(hdev->hash_clk);
10998c2ecf20Sopenharmony_ci		return ret;
11008c2ecf20Sopenharmony_ci	}
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_ci	return 0;
11038c2ecf20Sopenharmony_ci}
11048c2ecf20Sopenharmony_ci#endif /* CONFIG_PM_SLEEP */
11058c2ecf20Sopenharmony_ci
11068c2ecf20Sopenharmony_cistatic const struct dev_pm_ops img_hash_pm_ops = {
11078c2ecf20Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(img_hash_suspend, img_hash_resume)
11088c2ecf20Sopenharmony_ci};
11098c2ecf20Sopenharmony_ci
11108c2ecf20Sopenharmony_cistatic struct platform_driver img_hash_driver = {
11118c2ecf20Sopenharmony_ci	.probe		= img_hash_probe,
11128c2ecf20Sopenharmony_ci	.remove		= img_hash_remove,
11138c2ecf20Sopenharmony_ci	.driver		= {
11148c2ecf20Sopenharmony_ci		.name	= "img-hash-accelerator",
11158c2ecf20Sopenharmony_ci		.pm	= &img_hash_pm_ops,
11168c2ecf20Sopenharmony_ci		.of_match_table	= of_match_ptr(img_hash_match),
11178c2ecf20Sopenharmony_ci	}
11188c2ecf20Sopenharmony_ci};
11198c2ecf20Sopenharmony_cimodule_platform_driver(img_hash_driver);
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
11228c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Imgtec SHA1/224/256 & MD5 hw accelerator driver");
11238c2ecf20Sopenharmony_ciMODULE_AUTHOR("Will Thomas.");
11248c2ecf20Sopenharmony_ciMODULE_AUTHOR("James Hartley <james.hartley@imgtec.com>");
1125