18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Provide TDMA helper functions used by cipher and hash algorithm
48c2ecf20Sopenharmony_ci * implementations.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
78c2ecf20Sopenharmony_ci * Author: Arnaud Ebalard <arno@natisbad.org>
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * This work is based on an initial version written by
108c2ecf20Sopenharmony_ci * Sebastian Andrzej Siewior < sebastian at breakpoint dot cc >
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include "cesa.h"
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_cibool mv_cesa_req_dma_iter_next_transfer(struct mv_cesa_dma_iter *iter,
168c2ecf20Sopenharmony_ci					struct mv_cesa_sg_dma_iter *sgiter,
178c2ecf20Sopenharmony_ci					unsigned int len)
188c2ecf20Sopenharmony_ci{
198c2ecf20Sopenharmony_ci	if (!sgiter->sg)
208c2ecf20Sopenharmony_ci		return false;
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci	sgiter->op_offset += len;
238c2ecf20Sopenharmony_ci	sgiter->offset += len;
248c2ecf20Sopenharmony_ci	if (sgiter->offset == sg_dma_len(sgiter->sg)) {
258c2ecf20Sopenharmony_ci		if (sg_is_last(sgiter->sg))
268c2ecf20Sopenharmony_ci			return false;
278c2ecf20Sopenharmony_ci		sgiter->offset = 0;
288c2ecf20Sopenharmony_ci		sgiter->sg = sg_next(sgiter->sg);
298c2ecf20Sopenharmony_ci	}
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci	if (sgiter->op_offset == iter->op_len)
328c2ecf20Sopenharmony_ci		return false;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	return true;
358c2ecf20Sopenharmony_ci}
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_civoid mv_cesa_dma_step(struct mv_cesa_req *dreq)
388c2ecf20Sopenharmony_ci{
398c2ecf20Sopenharmony_ci	struct mv_cesa_engine *engine = dreq->engine;
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	writel_relaxed(0, engine->regs + CESA_SA_CFG);
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	mv_cesa_set_int_mask(engine, CESA_SA_INT_ACC0_IDMA_DONE);
448c2ecf20Sopenharmony_ci	writel_relaxed(CESA_TDMA_DST_BURST_128B | CESA_TDMA_SRC_BURST_128B |
458c2ecf20Sopenharmony_ci		       CESA_TDMA_NO_BYTE_SWAP | CESA_TDMA_EN,
468c2ecf20Sopenharmony_ci		       engine->regs + CESA_TDMA_CONTROL);
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	writel_relaxed(CESA_SA_CFG_ACT_CH0_IDMA | CESA_SA_CFG_MULTI_PKT |
498c2ecf20Sopenharmony_ci		       CESA_SA_CFG_CH0_W_IDMA | CESA_SA_CFG_PARA_DIS,
508c2ecf20Sopenharmony_ci		       engine->regs + CESA_SA_CFG);
518c2ecf20Sopenharmony_ci	writel_relaxed(dreq->chain.first->cur_dma,
528c2ecf20Sopenharmony_ci		       engine->regs + CESA_TDMA_NEXT_ADDR);
538c2ecf20Sopenharmony_ci	WARN_ON(readl(engine->regs + CESA_SA_CMD) &
548c2ecf20Sopenharmony_ci		CESA_SA_CMD_EN_CESA_SA_ACCL0);
558c2ecf20Sopenharmony_ci	writel(CESA_SA_CMD_EN_CESA_SA_ACCL0, engine->regs + CESA_SA_CMD);
568c2ecf20Sopenharmony_ci}
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_civoid mv_cesa_dma_cleanup(struct mv_cesa_req *dreq)
598c2ecf20Sopenharmony_ci{
608c2ecf20Sopenharmony_ci	struct mv_cesa_tdma_desc *tdma;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	for (tdma = dreq->chain.first; tdma;) {
638c2ecf20Sopenharmony_ci		struct mv_cesa_tdma_desc *old_tdma = tdma;
648c2ecf20Sopenharmony_ci		u32 type = tdma->flags & CESA_TDMA_TYPE_MSK;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci		if (type == CESA_TDMA_OP)
678c2ecf20Sopenharmony_ci			dma_pool_free(cesa_dev->dma->op_pool, tdma->op,
688c2ecf20Sopenharmony_ci				      le32_to_cpu(tdma->src));
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci		tdma = tdma->next;
718c2ecf20Sopenharmony_ci		dma_pool_free(cesa_dev->dma->tdma_desc_pool, old_tdma,
728c2ecf20Sopenharmony_ci			      old_tdma->cur_dma);
738c2ecf20Sopenharmony_ci	}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	dreq->chain.first = NULL;
768c2ecf20Sopenharmony_ci	dreq->chain.last = NULL;
778c2ecf20Sopenharmony_ci}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_civoid mv_cesa_dma_prepare(struct mv_cesa_req *dreq,
808c2ecf20Sopenharmony_ci			 struct mv_cesa_engine *engine)
818c2ecf20Sopenharmony_ci{
828c2ecf20Sopenharmony_ci	struct mv_cesa_tdma_desc *tdma;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	for (tdma = dreq->chain.first; tdma; tdma = tdma->next) {
858c2ecf20Sopenharmony_ci		if (tdma->flags & CESA_TDMA_DST_IN_SRAM)
868c2ecf20Sopenharmony_ci			tdma->dst = cpu_to_le32(tdma->dst_dma + engine->sram_dma);
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci		if (tdma->flags & CESA_TDMA_SRC_IN_SRAM)
898c2ecf20Sopenharmony_ci			tdma->src = cpu_to_le32(tdma->src_dma + engine->sram_dma);
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci		if ((tdma->flags & CESA_TDMA_TYPE_MSK) == CESA_TDMA_OP)
928c2ecf20Sopenharmony_ci			mv_cesa_adjust_op(engine, tdma->op);
938c2ecf20Sopenharmony_ci	}
948c2ecf20Sopenharmony_ci}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_civoid mv_cesa_tdma_chain(struct mv_cesa_engine *engine,
978c2ecf20Sopenharmony_ci			struct mv_cesa_req *dreq)
988c2ecf20Sopenharmony_ci{
998c2ecf20Sopenharmony_ci	if (engine->chain.first == NULL && engine->chain.last == NULL) {
1008c2ecf20Sopenharmony_ci		engine->chain.first = dreq->chain.first;
1018c2ecf20Sopenharmony_ci		engine->chain.last  = dreq->chain.last;
1028c2ecf20Sopenharmony_ci	} else {
1038c2ecf20Sopenharmony_ci		struct mv_cesa_tdma_desc *last;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci		last = engine->chain.last;
1068c2ecf20Sopenharmony_ci		last->next = dreq->chain.first;
1078c2ecf20Sopenharmony_ci		engine->chain.last = dreq->chain.last;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci		/*
1108c2ecf20Sopenharmony_ci		 * Break the DMA chain if the CESA_TDMA_BREAK_CHAIN is set on
1118c2ecf20Sopenharmony_ci		 * the last element of the current chain, or if the request
1128c2ecf20Sopenharmony_ci		 * being queued needs the IV regs to be set before lauching
1138c2ecf20Sopenharmony_ci		 * the request.
1148c2ecf20Sopenharmony_ci		 */
1158c2ecf20Sopenharmony_ci		if (!(last->flags & CESA_TDMA_BREAK_CHAIN) &&
1168c2ecf20Sopenharmony_ci		    !(dreq->chain.first->flags & CESA_TDMA_SET_STATE))
1178c2ecf20Sopenharmony_ci			last->next_dma = cpu_to_le32(dreq->chain.first->cur_dma);
1188c2ecf20Sopenharmony_ci	}
1198c2ecf20Sopenharmony_ci}
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ciint mv_cesa_tdma_process(struct mv_cesa_engine *engine, u32 status)
1228c2ecf20Sopenharmony_ci{
1238c2ecf20Sopenharmony_ci	struct crypto_async_request *req = NULL;
1248c2ecf20Sopenharmony_ci	struct mv_cesa_tdma_desc *tdma = NULL, *next = NULL;
1258c2ecf20Sopenharmony_ci	dma_addr_t tdma_cur;
1268c2ecf20Sopenharmony_ci	int res = 0;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	tdma_cur = readl(engine->regs + CESA_TDMA_CUR);
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	for (tdma = engine->chain.first; tdma; tdma = next) {
1318c2ecf20Sopenharmony_ci		spin_lock_bh(&engine->lock);
1328c2ecf20Sopenharmony_ci		next = tdma->next;
1338c2ecf20Sopenharmony_ci		spin_unlock_bh(&engine->lock);
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci		if (tdma->flags & CESA_TDMA_END_OF_REQ) {
1368c2ecf20Sopenharmony_ci			struct crypto_async_request *backlog = NULL;
1378c2ecf20Sopenharmony_ci			struct mv_cesa_ctx *ctx;
1388c2ecf20Sopenharmony_ci			u32 current_status;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci			spin_lock_bh(&engine->lock);
1418c2ecf20Sopenharmony_ci			/*
1428c2ecf20Sopenharmony_ci			 * if req is NULL, this means we're processing the
1438c2ecf20Sopenharmony_ci			 * request in engine->req.
1448c2ecf20Sopenharmony_ci			 */
1458c2ecf20Sopenharmony_ci			if (!req)
1468c2ecf20Sopenharmony_ci				req = engine->req;
1478c2ecf20Sopenharmony_ci			else
1488c2ecf20Sopenharmony_ci				req = mv_cesa_dequeue_req_locked(engine,
1498c2ecf20Sopenharmony_ci								 &backlog);
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci			/* Re-chaining to the next request */
1528c2ecf20Sopenharmony_ci			engine->chain.first = tdma->next;
1538c2ecf20Sopenharmony_ci			tdma->next = NULL;
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci			/* If this is the last request, clear the chain */
1568c2ecf20Sopenharmony_ci			if (engine->chain.first == NULL)
1578c2ecf20Sopenharmony_ci				engine->chain.last  = NULL;
1588c2ecf20Sopenharmony_ci			spin_unlock_bh(&engine->lock);
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci			ctx = crypto_tfm_ctx(req->tfm);
1618c2ecf20Sopenharmony_ci			current_status = (tdma->cur_dma == tdma_cur) ?
1628c2ecf20Sopenharmony_ci					  status : CESA_SA_INT_ACC0_IDMA_DONE;
1638c2ecf20Sopenharmony_ci			res = ctx->ops->process(req, current_status);
1648c2ecf20Sopenharmony_ci			ctx->ops->complete(req);
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci			if (res == 0)
1678c2ecf20Sopenharmony_ci				mv_cesa_engine_enqueue_complete_request(engine,
1688c2ecf20Sopenharmony_ci									req);
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci			if (backlog)
1718c2ecf20Sopenharmony_ci				backlog->complete(backlog, -EINPROGRESS);
1728c2ecf20Sopenharmony_ci		}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci		if (res || tdma->cur_dma == tdma_cur)
1758c2ecf20Sopenharmony_ci			break;
1768c2ecf20Sopenharmony_ci	}
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	/*
1798c2ecf20Sopenharmony_ci	 * Save the last request in error to engine->req, so that the core
1808c2ecf20Sopenharmony_ci	 * knows which request was fautly
1818c2ecf20Sopenharmony_ci	 */
1828c2ecf20Sopenharmony_ci	if (res) {
1838c2ecf20Sopenharmony_ci		spin_lock_bh(&engine->lock);
1848c2ecf20Sopenharmony_ci		engine->req = req;
1858c2ecf20Sopenharmony_ci		spin_unlock_bh(&engine->lock);
1868c2ecf20Sopenharmony_ci	}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	return res;
1898c2ecf20Sopenharmony_ci}
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_cistatic struct mv_cesa_tdma_desc *
1928c2ecf20Sopenharmony_cimv_cesa_dma_add_desc(struct mv_cesa_tdma_chain *chain, gfp_t flags)
1938c2ecf20Sopenharmony_ci{
1948c2ecf20Sopenharmony_ci	struct mv_cesa_tdma_desc *new_tdma = NULL;
1958c2ecf20Sopenharmony_ci	dma_addr_t dma_handle;
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	new_tdma = dma_pool_zalloc(cesa_dev->dma->tdma_desc_pool, flags,
1988c2ecf20Sopenharmony_ci				   &dma_handle);
1998c2ecf20Sopenharmony_ci	if (!new_tdma)
2008c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	new_tdma->cur_dma = dma_handle;
2038c2ecf20Sopenharmony_ci	if (chain->last) {
2048c2ecf20Sopenharmony_ci		chain->last->next_dma = cpu_to_le32(dma_handle);
2058c2ecf20Sopenharmony_ci		chain->last->next = new_tdma;
2068c2ecf20Sopenharmony_ci	} else {
2078c2ecf20Sopenharmony_ci		chain->first = new_tdma;
2088c2ecf20Sopenharmony_ci	}
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	chain->last = new_tdma;
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	return new_tdma;
2138c2ecf20Sopenharmony_ci}
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ciint mv_cesa_dma_add_result_op(struct mv_cesa_tdma_chain *chain, dma_addr_t src,
2168c2ecf20Sopenharmony_ci			  u32 size, u32 flags, gfp_t gfp_flags)
2178c2ecf20Sopenharmony_ci{
2188c2ecf20Sopenharmony_ci	struct mv_cesa_tdma_desc *tdma, *op_desc;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	tdma = mv_cesa_dma_add_desc(chain, gfp_flags);
2218c2ecf20Sopenharmony_ci	if (IS_ERR(tdma))
2228c2ecf20Sopenharmony_ci		return PTR_ERR(tdma);
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	/* We re-use an existing op_desc object to retrieve the context
2258c2ecf20Sopenharmony_ci	 * and result instead of allocating a new one.
2268c2ecf20Sopenharmony_ci	 * There is at least one object of this type in a CESA crypto
2278c2ecf20Sopenharmony_ci	 * req, just pick the first one in the chain.
2288c2ecf20Sopenharmony_ci	 */
2298c2ecf20Sopenharmony_ci	for (op_desc = chain->first; op_desc; op_desc = op_desc->next) {
2308c2ecf20Sopenharmony_ci		u32 type = op_desc->flags & CESA_TDMA_TYPE_MSK;
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci		if (type == CESA_TDMA_OP)
2338c2ecf20Sopenharmony_ci			break;
2348c2ecf20Sopenharmony_ci	}
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	if (!op_desc)
2378c2ecf20Sopenharmony_ci		return -EIO;
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	tdma->byte_cnt = cpu_to_le32(size | BIT(31));
2408c2ecf20Sopenharmony_ci	tdma->src_dma = src;
2418c2ecf20Sopenharmony_ci	tdma->dst_dma = op_desc->src_dma;
2428c2ecf20Sopenharmony_ci	tdma->op = op_desc->op;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	flags &= (CESA_TDMA_DST_IN_SRAM | CESA_TDMA_SRC_IN_SRAM);
2458c2ecf20Sopenharmony_ci	tdma->flags = flags | CESA_TDMA_RESULT;
2468c2ecf20Sopenharmony_ci	return 0;
2478c2ecf20Sopenharmony_ci}
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_cistruct mv_cesa_op_ctx *mv_cesa_dma_add_op(struct mv_cesa_tdma_chain *chain,
2508c2ecf20Sopenharmony_ci					const struct mv_cesa_op_ctx *op_templ,
2518c2ecf20Sopenharmony_ci					bool skip_ctx,
2528c2ecf20Sopenharmony_ci					gfp_t flags)
2538c2ecf20Sopenharmony_ci{
2548c2ecf20Sopenharmony_ci	struct mv_cesa_tdma_desc *tdma;
2558c2ecf20Sopenharmony_ci	struct mv_cesa_op_ctx *op;
2568c2ecf20Sopenharmony_ci	dma_addr_t dma_handle;
2578c2ecf20Sopenharmony_ci	unsigned int size;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	tdma = mv_cesa_dma_add_desc(chain, flags);
2608c2ecf20Sopenharmony_ci	if (IS_ERR(tdma))
2618c2ecf20Sopenharmony_ci		return ERR_CAST(tdma);
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	op = dma_pool_alloc(cesa_dev->dma->op_pool, flags, &dma_handle);
2648c2ecf20Sopenharmony_ci	if (!op)
2658c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	*op = *op_templ;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	size = skip_ctx ? sizeof(op->desc) : sizeof(*op);
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	tdma = chain->last;
2728c2ecf20Sopenharmony_ci	tdma->op = op;
2738c2ecf20Sopenharmony_ci	tdma->byte_cnt = cpu_to_le32(size | BIT(31));
2748c2ecf20Sopenharmony_ci	tdma->src = cpu_to_le32(dma_handle);
2758c2ecf20Sopenharmony_ci	tdma->dst_dma = CESA_SA_CFG_SRAM_OFFSET;
2768c2ecf20Sopenharmony_ci	tdma->flags = CESA_TDMA_DST_IN_SRAM | CESA_TDMA_OP;
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	return op;
2798c2ecf20Sopenharmony_ci}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ciint mv_cesa_dma_add_data_transfer(struct mv_cesa_tdma_chain *chain,
2828c2ecf20Sopenharmony_ci				  dma_addr_t dst, dma_addr_t src, u32 size,
2838c2ecf20Sopenharmony_ci				  u32 flags, gfp_t gfp_flags)
2848c2ecf20Sopenharmony_ci{
2858c2ecf20Sopenharmony_ci	struct mv_cesa_tdma_desc *tdma;
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	tdma = mv_cesa_dma_add_desc(chain, gfp_flags);
2888c2ecf20Sopenharmony_ci	if (IS_ERR(tdma))
2898c2ecf20Sopenharmony_ci		return PTR_ERR(tdma);
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	tdma->byte_cnt = cpu_to_le32(size | BIT(31));
2928c2ecf20Sopenharmony_ci	tdma->src_dma = src;
2938c2ecf20Sopenharmony_ci	tdma->dst_dma = dst;
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	flags &= (CESA_TDMA_DST_IN_SRAM | CESA_TDMA_SRC_IN_SRAM);
2968c2ecf20Sopenharmony_ci	tdma->flags = flags | CESA_TDMA_DATA;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	return 0;
2998c2ecf20Sopenharmony_ci}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ciint mv_cesa_dma_add_dummy_launch(struct mv_cesa_tdma_chain *chain, gfp_t flags)
3028c2ecf20Sopenharmony_ci{
3038c2ecf20Sopenharmony_ci	struct mv_cesa_tdma_desc *tdma;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	tdma = mv_cesa_dma_add_desc(chain, flags);
3068c2ecf20Sopenharmony_ci	return PTR_ERR_OR_ZERO(tdma);
3078c2ecf20Sopenharmony_ci}
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ciint mv_cesa_dma_add_dummy_end(struct mv_cesa_tdma_chain *chain, gfp_t flags)
3108c2ecf20Sopenharmony_ci{
3118c2ecf20Sopenharmony_ci	struct mv_cesa_tdma_desc *tdma;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	tdma = mv_cesa_dma_add_desc(chain, flags);
3148c2ecf20Sopenharmony_ci	if (IS_ERR(tdma))
3158c2ecf20Sopenharmony_ci		return PTR_ERR(tdma);
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	tdma->byte_cnt = cpu_to_le32(BIT(31));
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	return 0;
3208c2ecf20Sopenharmony_ci}
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ciint mv_cesa_dma_add_op_transfers(struct mv_cesa_tdma_chain *chain,
3238c2ecf20Sopenharmony_ci				 struct mv_cesa_dma_iter *dma_iter,
3248c2ecf20Sopenharmony_ci				 struct mv_cesa_sg_dma_iter *sgiter,
3258c2ecf20Sopenharmony_ci				 gfp_t gfp_flags)
3268c2ecf20Sopenharmony_ci{
3278c2ecf20Sopenharmony_ci	u32 flags = sgiter->dir == DMA_TO_DEVICE ?
3288c2ecf20Sopenharmony_ci		    CESA_TDMA_DST_IN_SRAM : CESA_TDMA_SRC_IN_SRAM;
3298c2ecf20Sopenharmony_ci	unsigned int len;
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	do {
3328c2ecf20Sopenharmony_ci		dma_addr_t dst, src;
3338c2ecf20Sopenharmony_ci		int ret;
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci		len = mv_cesa_req_dma_iter_transfer_len(dma_iter, sgiter);
3368c2ecf20Sopenharmony_ci		if (sgiter->dir == DMA_TO_DEVICE) {
3378c2ecf20Sopenharmony_ci			dst = CESA_SA_DATA_SRAM_OFFSET + sgiter->op_offset;
3388c2ecf20Sopenharmony_ci			src = sg_dma_address(sgiter->sg) + sgiter->offset;
3398c2ecf20Sopenharmony_ci		} else {
3408c2ecf20Sopenharmony_ci			dst = sg_dma_address(sgiter->sg) + sgiter->offset;
3418c2ecf20Sopenharmony_ci			src = CESA_SA_DATA_SRAM_OFFSET + sgiter->op_offset;
3428c2ecf20Sopenharmony_ci		}
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci		ret = mv_cesa_dma_add_data_transfer(chain, dst, src, len,
3458c2ecf20Sopenharmony_ci						    flags, gfp_flags);
3468c2ecf20Sopenharmony_ci		if (ret)
3478c2ecf20Sopenharmony_ci			return ret;
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	} while (mv_cesa_req_dma_iter_next_transfer(dma_iter, sgiter, len));
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	return 0;
3528c2ecf20Sopenharmony_ci}
353