162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * sl3516-ce-core.c - hardware cryptographic offloader for Storlink SL3516 SoC
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2021 Corentin Labbe <clabbe@baylibre.com>
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Core file which registers crypto algorithms supported by the CryptoEngine
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <crypto/engine.h>
1162306a36Sopenharmony_ci#include <crypto/internal/rng.h>
1262306a36Sopenharmony_ci#include <crypto/internal/skcipher.h>
1362306a36Sopenharmony_ci#include <linux/clk.h>
1462306a36Sopenharmony_ci#include <linux/debugfs.h>
1562306a36Sopenharmony_ci#include <linux/dev_printk.h>
1662306a36Sopenharmony_ci#include <linux/dma-mapping.h>
1762306a36Sopenharmony_ci#include <linux/err.h>
1862306a36Sopenharmony_ci#include <linux/interrupt.h>
1962306a36Sopenharmony_ci#include <linux/io.h>
2062306a36Sopenharmony_ci#include <linux/irq.h>
2162306a36Sopenharmony_ci#include <linux/kernel.h>
2262306a36Sopenharmony_ci#include <linux/module.h>
2362306a36Sopenharmony_ci#include <linux/of.h>
2462306a36Sopenharmony_ci#include <linux/platform_device.h>
2562306a36Sopenharmony_ci#include <linux/pm_runtime.h>
2662306a36Sopenharmony_ci#include <linux/reset.h>
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#include "sl3516-ce.h"
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistatic int sl3516_ce_desc_init(struct sl3516_ce_dev *ce)
3162306a36Sopenharmony_ci{
3262306a36Sopenharmony_ci	const size_t sz = sizeof(struct descriptor) * MAXDESC;
3362306a36Sopenharmony_ci	int i;
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	ce->tx = dma_alloc_coherent(ce->dev, sz, &ce->dtx, GFP_KERNEL);
3662306a36Sopenharmony_ci	if (!ce->tx)
3762306a36Sopenharmony_ci		return -ENOMEM;
3862306a36Sopenharmony_ci	ce->rx = dma_alloc_coherent(ce->dev, sz, &ce->drx, GFP_KERNEL);
3962306a36Sopenharmony_ci	if (!ce->rx)
4062306a36Sopenharmony_ci		goto err_rx;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	for (i = 0; i < MAXDESC; i++) {
4362306a36Sopenharmony_ci		ce->tx[i].frame_ctrl.bits.own = CE_CPU;
4462306a36Sopenharmony_ci		ce->tx[i].next_desc.next_descriptor = ce->dtx + (i + 1) * sizeof(struct descriptor);
4562306a36Sopenharmony_ci	}
4662306a36Sopenharmony_ci	ce->tx[MAXDESC - 1].next_desc.next_descriptor = ce->dtx;
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	for (i = 0; i < MAXDESC; i++) {
4962306a36Sopenharmony_ci		ce->rx[i].frame_ctrl.bits.own = CE_CPU;
5062306a36Sopenharmony_ci		ce->rx[i].next_desc.next_descriptor = ce->drx + (i + 1) * sizeof(struct descriptor);
5162306a36Sopenharmony_ci	}
5262306a36Sopenharmony_ci	ce->rx[MAXDESC - 1].next_desc.next_descriptor = ce->drx;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	ce->pctrl = dma_alloc_coherent(ce->dev, sizeof(struct pkt_control_ecb),
5562306a36Sopenharmony_ci				       &ce->dctrl, GFP_KERNEL);
5662306a36Sopenharmony_ci	if (!ce->pctrl)
5762306a36Sopenharmony_ci		goto err_pctrl;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	return 0;
6062306a36Sopenharmony_cierr_pctrl:
6162306a36Sopenharmony_ci	dma_free_coherent(ce->dev, sz, ce->rx, ce->drx);
6262306a36Sopenharmony_cierr_rx:
6362306a36Sopenharmony_ci	dma_free_coherent(ce->dev, sz, ce->tx, ce->dtx);
6462306a36Sopenharmony_ci	return -ENOMEM;
6562306a36Sopenharmony_ci}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistatic void sl3516_ce_free_descs(struct sl3516_ce_dev *ce)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	const size_t sz = sizeof(struct descriptor) * MAXDESC;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	dma_free_coherent(ce->dev, sz, ce->tx, ce->dtx);
7262306a36Sopenharmony_ci	dma_free_coherent(ce->dev, sz, ce->rx, ce->drx);
7362306a36Sopenharmony_ci	dma_free_coherent(ce->dev, sizeof(struct pkt_control_ecb), ce->pctrl,
7462306a36Sopenharmony_ci			  ce->dctrl);
7562306a36Sopenharmony_ci}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistatic void start_dma_tx(struct sl3516_ce_dev *ce)
7862306a36Sopenharmony_ci{
7962306a36Sopenharmony_ci	u32 v;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	v = TXDMA_CTRL_START | TXDMA_CTRL_CHAIN_MODE | TXDMA_CTRL_CONTINUE | \
8262306a36Sopenharmony_ci		TXDMA_CTRL_INT_FAIL | TXDMA_CTRL_INT_PERR | TXDMA_CTRL_BURST_UNK;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	writel(v, ce->base + IPSEC_TXDMA_CTRL);
8562306a36Sopenharmony_ci}
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cistatic void start_dma_rx(struct sl3516_ce_dev *ce)
8862306a36Sopenharmony_ci{
8962306a36Sopenharmony_ci	u32 v;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	v = RXDMA_CTRL_START | RXDMA_CTRL_CHAIN_MODE | RXDMA_CTRL_CONTINUE | \
9262306a36Sopenharmony_ci		RXDMA_CTRL_BURST_UNK | RXDMA_CTRL_INT_FINISH | \
9362306a36Sopenharmony_ci		RXDMA_CTRL_INT_FAIL | RXDMA_CTRL_INT_PERR | \
9462306a36Sopenharmony_ci		RXDMA_CTRL_INT_EOD | RXDMA_CTRL_INT_EOF;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	writel(v, ce->base + IPSEC_RXDMA_CTRL);
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_cistatic struct descriptor *get_desc_tx(struct sl3516_ce_dev *ce)
10062306a36Sopenharmony_ci{
10162306a36Sopenharmony_ci	struct descriptor *dd;
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	dd = &ce->tx[ce->ctx];
10462306a36Sopenharmony_ci	ce->ctx++;
10562306a36Sopenharmony_ci	if (ce->ctx >= MAXDESC)
10662306a36Sopenharmony_ci		ce->ctx = 0;
10762306a36Sopenharmony_ci	return dd;
10862306a36Sopenharmony_ci}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_cistatic struct descriptor *get_desc_rx(struct sl3516_ce_dev *ce)
11162306a36Sopenharmony_ci{
11262306a36Sopenharmony_ci	struct descriptor *rdd;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	rdd = &ce->rx[ce->crx];
11562306a36Sopenharmony_ci	ce->crx++;
11662306a36Sopenharmony_ci	if (ce->crx >= MAXDESC)
11762306a36Sopenharmony_ci		ce->crx = 0;
11862306a36Sopenharmony_ci	return rdd;
11962306a36Sopenharmony_ci}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ciint sl3516_ce_run_task(struct sl3516_ce_dev *ce, struct sl3516_ce_cipher_req_ctx *rctx,
12262306a36Sopenharmony_ci		       const char *name)
12362306a36Sopenharmony_ci{
12462306a36Sopenharmony_ci	struct descriptor *dd, *rdd = NULL;
12562306a36Sopenharmony_ci	u32 v;
12662306a36Sopenharmony_ci	int i, err = 0;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	ce->stat_req++;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	reinit_completion(&ce->complete);
13162306a36Sopenharmony_ci	ce->status = 0;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	for (i = 0; i < rctx->nr_sgd; i++) {
13462306a36Sopenharmony_ci		dev_dbg(ce->dev, "%s handle DST SG %d/%d len=%d\n", __func__,
13562306a36Sopenharmony_ci			i, rctx->nr_sgd, rctx->t_dst[i].len);
13662306a36Sopenharmony_ci		rdd = get_desc_rx(ce);
13762306a36Sopenharmony_ci		rdd->buf_adr = rctx->t_dst[i].addr;
13862306a36Sopenharmony_ci		rdd->frame_ctrl.bits.buffer_size = rctx->t_dst[i].len;
13962306a36Sopenharmony_ci		rdd->frame_ctrl.bits.own = CE_DMA;
14062306a36Sopenharmony_ci	}
14162306a36Sopenharmony_ci	rdd->next_desc.bits.eofie = 1;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	for (i = 0; i < rctx->nr_sgs; i++) {
14462306a36Sopenharmony_ci		dev_dbg(ce->dev, "%s handle SRC SG %d/%d len=%d\n", __func__,
14562306a36Sopenharmony_ci			i, rctx->nr_sgs, rctx->t_src[i].len);
14662306a36Sopenharmony_ci		rctx->h->algorithm_len = rctx->t_src[i].len;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci		dd = get_desc_tx(ce);
14962306a36Sopenharmony_ci		dd->frame_ctrl.raw = 0;
15062306a36Sopenharmony_ci		dd->flag_status.raw = 0;
15162306a36Sopenharmony_ci		dd->frame_ctrl.bits.buffer_size = rctx->pctrllen;
15262306a36Sopenharmony_ci		dd->buf_adr = ce->dctrl;
15362306a36Sopenharmony_ci		dd->flag_status.tx_flag.tqflag = rctx->tqflag;
15462306a36Sopenharmony_ci		dd->next_desc.bits.eofie = 0;
15562306a36Sopenharmony_ci		dd->next_desc.bits.dec = 0;
15662306a36Sopenharmony_ci		dd->next_desc.bits.sof_eof = DESC_FIRST | DESC_LAST;
15762306a36Sopenharmony_ci		dd->frame_ctrl.bits.own = CE_DMA;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci		dd = get_desc_tx(ce);
16062306a36Sopenharmony_ci		dd->frame_ctrl.raw = 0;
16162306a36Sopenharmony_ci		dd->flag_status.raw = 0;
16262306a36Sopenharmony_ci		dd->frame_ctrl.bits.buffer_size = rctx->t_src[i].len;
16362306a36Sopenharmony_ci		dd->buf_adr = rctx->t_src[i].addr;
16462306a36Sopenharmony_ci		dd->flag_status.tx_flag.tqflag = 0;
16562306a36Sopenharmony_ci		dd->next_desc.bits.eofie = 0;
16662306a36Sopenharmony_ci		dd->next_desc.bits.dec = 0;
16762306a36Sopenharmony_ci		dd->next_desc.bits.sof_eof = DESC_FIRST | DESC_LAST;
16862306a36Sopenharmony_ci		dd->frame_ctrl.bits.own = CE_DMA;
16962306a36Sopenharmony_ci		start_dma_tx(ce);
17062306a36Sopenharmony_ci		start_dma_rx(ce);
17162306a36Sopenharmony_ci	}
17262306a36Sopenharmony_ci	wait_for_completion_interruptible_timeout(&ce->complete,
17362306a36Sopenharmony_ci						  msecs_to_jiffies(5000));
17462306a36Sopenharmony_ci	if (ce->status == 0) {
17562306a36Sopenharmony_ci		dev_err(ce->dev, "DMA timeout for %s\n", name);
17662306a36Sopenharmony_ci		err = -EFAULT;
17762306a36Sopenharmony_ci	}
17862306a36Sopenharmony_ci	v = readl(ce->base + IPSEC_STATUS_REG);
17962306a36Sopenharmony_ci	if (v & 0xFFF) {
18062306a36Sopenharmony_ci		dev_err(ce->dev, "IPSEC_STATUS_REG %x\n", v);
18162306a36Sopenharmony_ci		err = -EFAULT;
18262306a36Sopenharmony_ci	}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	return err;
18562306a36Sopenharmony_ci}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_cistatic irqreturn_t ce_irq_handler(int irq, void *data)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci	struct sl3516_ce_dev *ce = (struct sl3516_ce_dev *)data;
19062306a36Sopenharmony_ci	u32 v;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	ce->stat_irq++;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	v = readl(ce->base + IPSEC_DMA_STATUS);
19562306a36Sopenharmony_ci	writel(v, ce->base + IPSEC_DMA_STATUS);
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	if (v & DMA_STATUS_TS_DERR)
19862306a36Sopenharmony_ci		dev_err(ce->dev, "AHB bus Error While Tx !!!\n");
19962306a36Sopenharmony_ci	if (v & DMA_STATUS_TS_PERR)
20062306a36Sopenharmony_ci		dev_err(ce->dev, "Tx Descriptor Protocol Error !!!\n");
20162306a36Sopenharmony_ci	if (v & DMA_STATUS_RS_DERR)
20262306a36Sopenharmony_ci		dev_err(ce->dev, "AHB bus Error While Rx !!!\n");
20362306a36Sopenharmony_ci	if (v & DMA_STATUS_RS_PERR)
20462306a36Sopenharmony_ci		dev_err(ce->dev, "Rx Descriptor Protocol Error !!!\n");
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	if (v & DMA_STATUS_TS_EOFI)
20762306a36Sopenharmony_ci		ce->stat_irq_tx++;
20862306a36Sopenharmony_ci	if (v & DMA_STATUS_RS_EOFI) {
20962306a36Sopenharmony_ci		ce->status = 1;
21062306a36Sopenharmony_ci		complete(&ce->complete);
21162306a36Sopenharmony_ci		ce->stat_irq_rx++;
21262306a36Sopenharmony_ci		return IRQ_HANDLED;
21362306a36Sopenharmony_ci	}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	return IRQ_HANDLED;
21662306a36Sopenharmony_ci}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_cistatic struct sl3516_ce_alg_template ce_algs[] = {
21962306a36Sopenharmony_ci{
22062306a36Sopenharmony_ci	.type = CRYPTO_ALG_TYPE_SKCIPHER,
22162306a36Sopenharmony_ci	.mode = ECB_AES,
22262306a36Sopenharmony_ci	.alg.skcipher.base = {
22362306a36Sopenharmony_ci		.base = {
22462306a36Sopenharmony_ci			.cra_name = "ecb(aes)",
22562306a36Sopenharmony_ci			.cra_driver_name = "ecb-aes-sl3516",
22662306a36Sopenharmony_ci			.cra_priority = 400,
22762306a36Sopenharmony_ci			.cra_blocksize = AES_BLOCK_SIZE,
22862306a36Sopenharmony_ci			.cra_flags = CRYPTO_ALG_TYPE_SKCIPHER |
22962306a36Sopenharmony_ci				CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK,
23062306a36Sopenharmony_ci			.cra_ctxsize = sizeof(struct sl3516_ce_cipher_tfm_ctx),
23162306a36Sopenharmony_ci			.cra_module = THIS_MODULE,
23262306a36Sopenharmony_ci			.cra_alignmask = 0xf,
23362306a36Sopenharmony_ci			.cra_init = sl3516_ce_cipher_init,
23462306a36Sopenharmony_ci			.cra_exit = sl3516_ce_cipher_exit,
23562306a36Sopenharmony_ci		},
23662306a36Sopenharmony_ci		.min_keysize	= AES_MIN_KEY_SIZE,
23762306a36Sopenharmony_ci		.max_keysize	= AES_MAX_KEY_SIZE,
23862306a36Sopenharmony_ci		.setkey		= sl3516_ce_aes_setkey,
23962306a36Sopenharmony_ci		.encrypt	= sl3516_ce_skencrypt,
24062306a36Sopenharmony_ci		.decrypt	= sl3516_ce_skdecrypt,
24162306a36Sopenharmony_ci	},
24262306a36Sopenharmony_ci	.alg.skcipher.op = {
24362306a36Sopenharmony_ci		.do_one_request = sl3516_ce_handle_cipher_request,
24462306a36Sopenharmony_ci	},
24562306a36Sopenharmony_ci},
24662306a36Sopenharmony_ci};
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_cistatic int sl3516_ce_debugfs_show(struct seq_file *seq, void *v)
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci	struct sl3516_ce_dev *ce = seq->private;
25162306a36Sopenharmony_ci	unsigned int i;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	seq_printf(seq, "HWRNG %lu %lu\n",
25462306a36Sopenharmony_ci		   ce->hwrng_stat_req, ce->hwrng_stat_bytes);
25562306a36Sopenharmony_ci	seq_printf(seq, "IRQ %lu\n", ce->stat_irq);
25662306a36Sopenharmony_ci	seq_printf(seq, "IRQ TX %lu\n", ce->stat_irq_tx);
25762306a36Sopenharmony_ci	seq_printf(seq, "IRQ RX %lu\n", ce->stat_irq_rx);
25862306a36Sopenharmony_ci	seq_printf(seq, "nreq %lu\n", ce->stat_req);
25962306a36Sopenharmony_ci	seq_printf(seq, "fallback SG count TX %lu\n", ce->fallback_sg_count_tx);
26062306a36Sopenharmony_ci	seq_printf(seq, "fallback SG count RX %lu\n", ce->fallback_sg_count_rx);
26162306a36Sopenharmony_ci	seq_printf(seq, "fallback modulo16 %lu\n", ce->fallback_mod16);
26262306a36Sopenharmony_ci	seq_printf(seq, "fallback align16 %lu\n", ce->fallback_align16);
26362306a36Sopenharmony_ci	seq_printf(seq, "fallback not same len %lu\n", ce->fallback_not_same_len);
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(ce_algs); i++) {
26662306a36Sopenharmony_ci		if (!ce_algs[i].ce)
26762306a36Sopenharmony_ci			continue;
26862306a36Sopenharmony_ci		switch (ce_algs[i].type) {
26962306a36Sopenharmony_ci		case CRYPTO_ALG_TYPE_SKCIPHER:
27062306a36Sopenharmony_ci			seq_printf(seq, "%s %s reqs=%lu fallback=%lu\n",
27162306a36Sopenharmony_ci				   ce_algs[i].alg.skcipher.base.base.cra_driver_name,
27262306a36Sopenharmony_ci				   ce_algs[i].alg.skcipher.base.base.cra_name,
27362306a36Sopenharmony_ci				   ce_algs[i].stat_req, ce_algs[i].stat_fb);
27462306a36Sopenharmony_ci			break;
27562306a36Sopenharmony_ci		}
27662306a36Sopenharmony_ci	}
27762306a36Sopenharmony_ci	return 0;
27862306a36Sopenharmony_ci}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(sl3516_ce_debugfs);
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_cistatic int sl3516_ce_register_algs(struct sl3516_ce_dev *ce)
28362306a36Sopenharmony_ci{
28462306a36Sopenharmony_ci	int err;
28562306a36Sopenharmony_ci	unsigned int i;
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(ce_algs); i++) {
28862306a36Sopenharmony_ci		ce_algs[i].ce = ce;
28962306a36Sopenharmony_ci		switch (ce_algs[i].type) {
29062306a36Sopenharmony_ci		case CRYPTO_ALG_TYPE_SKCIPHER:
29162306a36Sopenharmony_ci			dev_info(ce->dev, "DEBUG: Register %s\n",
29262306a36Sopenharmony_ci				 ce_algs[i].alg.skcipher.base.base.cra_name);
29362306a36Sopenharmony_ci			err = crypto_engine_register_skcipher(&ce_algs[i].alg.skcipher);
29462306a36Sopenharmony_ci			if (err) {
29562306a36Sopenharmony_ci				dev_err(ce->dev, "Fail to register %s\n",
29662306a36Sopenharmony_ci					ce_algs[i].alg.skcipher.base.base.cra_name);
29762306a36Sopenharmony_ci				ce_algs[i].ce = NULL;
29862306a36Sopenharmony_ci				return err;
29962306a36Sopenharmony_ci			}
30062306a36Sopenharmony_ci			break;
30162306a36Sopenharmony_ci		default:
30262306a36Sopenharmony_ci			ce_algs[i].ce = NULL;
30362306a36Sopenharmony_ci			dev_err(ce->dev, "ERROR: tried to register an unknown algo\n");
30462306a36Sopenharmony_ci		}
30562306a36Sopenharmony_ci	}
30662306a36Sopenharmony_ci	return 0;
30762306a36Sopenharmony_ci}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_cistatic void sl3516_ce_unregister_algs(struct sl3516_ce_dev *ce)
31062306a36Sopenharmony_ci{
31162306a36Sopenharmony_ci	unsigned int i;
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(ce_algs); i++) {
31462306a36Sopenharmony_ci		if (!ce_algs[i].ce)
31562306a36Sopenharmony_ci			continue;
31662306a36Sopenharmony_ci		switch (ce_algs[i].type) {
31762306a36Sopenharmony_ci		case CRYPTO_ALG_TYPE_SKCIPHER:
31862306a36Sopenharmony_ci			dev_info(ce->dev, "Unregister %d %s\n", i,
31962306a36Sopenharmony_ci				 ce_algs[i].alg.skcipher.base.base.cra_name);
32062306a36Sopenharmony_ci			crypto_engine_unregister_skcipher(&ce_algs[i].alg.skcipher);
32162306a36Sopenharmony_ci			break;
32262306a36Sopenharmony_ci		}
32362306a36Sopenharmony_ci	}
32462306a36Sopenharmony_ci}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_cistatic void sl3516_ce_start(struct sl3516_ce_dev *ce)
32762306a36Sopenharmony_ci{
32862306a36Sopenharmony_ci	ce->ctx = 0;
32962306a36Sopenharmony_ci	ce->crx = 0;
33062306a36Sopenharmony_ci	writel(ce->dtx, ce->base + IPSEC_TXDMA_CURR_DESC);
33162306a36Sopenharmony_ci	writel(ce->drx, ce->base + IPSEC_RXDMA_CURR_DESC);
33262306a36Sopenharmony_ci	writel(0, ce->base + IPSEC_DMA_STATUS);
33362306a36Sopenharmony_ci}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci/*
33662306a36Sopenharmony_ci * Power management strategy: The device is suspended unless a TFM exists for
33762306a36Sopenharmony_ci * one of the algorithms proposed by this driver.
33862306a36Sopenharmony_ci */
33962306a36Sopenharmony_cistatic int sl3516_ce_pm_suspend(struct device *dev)
34062306a36Sopenharmony_ci{
34162306a36Sopenharmony_ci	struct sl3516_ce_dev *ce = dev_get_drvdata(dev);
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	reset_control_assert(ce->reset);
34462306a36Sopenharmony_ci	clk_disable_unprepare(ce->clks);
34562306a36Sopenharmony_ci	return 0;
34662306a36Sopenharmony_ci}
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_cistatic int sl3516_ce_pm_resume(struct device *dev)
34962306a36Sopenharmony_ci{
35062306a36Sopenharmony_ci	struct sl3516_ce_dev *ce = dev_get_drvdata(dev);
35162306a36Sopenharmony_ci	int err;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	err = clk_prepare_enable(ce->clks);
35462306a36Sopenharmony_ci	if (err) {
35562306a36Sopenharmony_ci		dev_err(ce->dev, "Cannot prepare_enable\n");
35662306a36Sopenharmony_ci		goto error;
35762306a36Sopenharmony_ci	}
35862306a36Sopenharmony_ci	err = reset_control_deassert(ce->reset);
35962306a36Sopenharmony_ci	if (err) {
36062306a36Sopenharmony_ci		dev_err(ce->dev, "Cannot deassert reset control\n");
36162306a36Sopenharmony_ci		goto error;
36262306a36Sopenharmony_ci	}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	sl3516_ce_start(ce);
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	return 0;
36762306a36Sopenharmony_cierror:
36862306a36Sopenharmony_ci	sl3516_ce_pm_suspend(dev);
36962306a36Sopenharmony_ci	return err;
37062306a36Sopenharmony_ci}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_cistatic const struct dev_pm_ops sl3516_ce_pm_ops = {
37362306a36Sopenharmony_ci	SET_RUNTIME_PM_OPS(sl3516_ce_pm_suspend, sl3516_ce_pm_resume, NULL)
37462306a36Sopenharmony_ci};
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_cistatic int sl3516_ce_pm_init(struct sl3516_ce_dev *ce)
37762306a36Sopenharmony_ci{
37862306a36Sopenharmony_ci	int err;
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	pm_runtime_use_autosuspend(ce->dev);
38162306a36Sopenharmony_ci	pm_runtime_set_autosuspend_delay(ce->dev, 2000);
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	err = pm_runtime_set_suspended(ce->dev);
38462306a36Sopenharmony_ci	if (err)
38562306a36Sopenharmony_ci		return err;
38662306a36Sopenharmony_ci	pm_runtime_enable(ce->dev);
38762306a36Sopenharmony_ci	return err;
38862306a36Sopenharmony_ci}
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_cistatic void sl3516_ce_pm_exit(struct sl3516_ce_dev *ce)
39162306a36Sopenharmony_ci{
39262306a36Sopenharmony_ci	pm_runtime_disable(ce->dev);
39362306a36Sopenharmony_ci}
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_cistatic int sl3516_ce_probe(struct platform_device *pdev)
39662306a36Sopenharmony_ci{
39762306a36Sopenharmony_ci	struct sl3516_ce_dev *ce;
39862306a36Sopenharmony_ci	int err, irq;
39962306a36Sopenharmony_ci	u32 v;
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	ce = devm_kzalloc(&pdev->dev, sizeof(*ce), GFP_KERNEL);
40262306a36Sopenharmony_ci	if (!ce)
40362306a36Sopenharmony_ci		return -ENOMEM;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	ce->dev = &pdev->dev;
40662306a36Sopenharmony_ci	platform_set_drvdata(pdev, ce);
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	ce->base = devm_platform_ioremap_resource(pdev, 0);
40962306a36Sopenharmony_ci	if (IS_ERR(ce->base))
41062306a36Sopenharmony_ci		return PTR_ERR(ce->base);
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
41362306a36Sopenharmony_ci	if (irq < 0)
41462306a36Sopenharmony_ci		return irq;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	err = devm_request_irq(&pdev->dev, irq, ce_irq_handler, 0, "crypto", ce);
41762306a36Sopenharmony_ci	if (err) {
41862306a36Sopenharmony_ci		dev_err(ce->dev, "Cannot request Crypto Engine IRQ (err=%d)\n", err);
41962306a36Sopenharmony_ci		return err;
42062306a36Sopenharmony_ci	}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	ce->reset = devm_reset_control_get(&pdev->dev, NULL);
42362306a36Sopenharmony_ci	if (IS_ERR(ce->reset))
42462306a36Sopenharmony_ci		return dev_err_probe(&pdev->dev, PTR_ERR(ce->reset),
42562306a36Sopenharmony_ci				     "No reset control found\n");
42662306a36Sopenharmony_ci	ce->clks = devm_clk_get(ce->dev, NULL);
42762306a36Sopenharmony_ci	if (IS_ERR(ce->clks)) {
42862306a36Sopenharmony_ci		err = PTR_ERR(ce->clks);
42962306a36Sopenharmony_ci		dev_err(ce->dev, "Cannot get clock err=%d\n", err);
43062306a36Sopenharmony_ci		return err;
43162306a36Sopenharmony_ci	}
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	err = sl3516_ce_desc_init(ce);
43462306a36Sopenharmony_ci	if (err)
43562306a36Sopenharmony_ci		return err;
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	err = sl3516_ce_pm_init(ce);
43862306a36Sopenharmony_ci	if (err)
43962306a36Sopenharmony_ci		goto error_pm;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	init_completion(&ce->complete);
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	ce->engine = crypto_engine_alloc_init(ce->dev, true);
44462306a36Sopenharmony_ci	if (!ce->engine) {
44562306a36Sopenharmony_ci		dev_err(ce->dev, "Cannot allocate engine\n");
44662306a36Sopenharmony_ci		err = -ENOMEM;
44762306a36Sopenharmony_ci		goto error_engine;
44862306a36Sopenharmony_ci	}
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	err = crypto_engine_start(ce->engine);
45162306a36Sopenharmony_ci	if (err) {
45262306a36Sopenharmony_ci		dev_err(ce->dev, "Cannot start engine\n");
45362306a36Sopenharmony_ci		goto error_engine;
45462306a36Sopenharmony_ci	}
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	err = sl3516_ce_register_algs(ce);
45762306a36Sopenharmony_ci	if (err)
45862306a36Sopenharmony_ci		goto error_alg;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	err = sl3516_ce_rng_register(ce);
46162306a36Sopenharmony_ci	if (err)
46262306a36Sopenharmony_ci		goto error_rng;
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	err = pm_runtime_resume_and_get(ce->dev);
46562306a36Sopenharmony_ci	if (err < 0)
46662306a36Sopenharmony_ci		goto error_pmuse;
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	v = readl(ce->base + IPSEC_ID);
46962306a36Sopenharmony_ci	dev_info(ce->dev, "SL3516 dev %lx rev %lx\n",
47062306a36Sopenharmony_ci		 v & GENMASK(31, 4),
47162306a36Sopenharmony_ci		 v & GENMASK(3, 0));
47262306a36Sopenharmony_ci	v = readl(ce->base + IPSEC_DMA_DEVICE_ID);
47362306a36Sopenharmony_ci	dev_info(ce->dev, "SL3516 DMA dev %lx rev %lx\n",
47462306a36Sopenharmony_ci		 v & GENMASK(15, 4),
47562306a36Sopenharmony_ci		 v & GENMASK(3, 0));
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	pm_runtime_put_sync(ce->dev);
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_CRYPTO_DEV_SL3516_DEBUG)) {
48062306a36Sopenharmony_ci		struct dentry *dbgfs_dir __maybe_unused;
48162306a36Sopenharmony_ci		struct dentry *dbgfs_stats __maybe_unused;
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci		/* Ignore error of debugfs */
48462306a36Sopenharmony_ci		dbgfs_dir = debugfs_create_dir("sl3516", NULL);
48562306a36Sopenharmony_ci		dbgfs_stats = debugfs_create_file("stats", 0444,
48662306a36Sopenharmony_ci						  dbgfs_dir, ce,
48762306a36Sopenharmony_ci						  &sl3516_ce_debugfs_fops);
48862306a36Sopenharmony_ci#ifdef CONFIG_CRYPTO_DEV_SL3516_DEBUG
48962306a36Sopenharmony_ci		ce->dbgfs_dir = dbgfs_dir;
49062306a36Sopenharmony_ci		ce->dbgfs_stats = dbgfs_stats;
49162306a36Sopenharmony_ci#endif
49262306a36Sopenharmony_ci	}
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	return 0;
49562306a36Sopenharmony_cierror_pmuse:
49662306a36Sopenharmony_ci	sl3516_ce_rng_unregister(ce);
49762306a36Sopenharmony_cierror_rng:
49862306a36Sopenharmony_ci	sl3516_ce_unregister_algs(ce);
49962306a36Sopenharmony_cierror_alg:
50062306a36Sopenharmony_ci	crypto_engine_exit(ce->engine);
50162306a36Sopenharmony_cierror_engine:
50262306a36Sopenharmony_ci	sl3516_ce_pm_exit(ce);
50362306a36Sopenharmony_cierror_pm:
50462306a36Sopenharmony_ci	sl3516_ce_free_descs(ce);
50562306a36Sopenharmony_ci	return err;
50662306a36Sopenharmony_ci}
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_cistatic int sl3516_ce_remove(struct platform_device *pdev)
50962306a36Sopenharmony_ci{
51062306a36Sopenharmony_ci	struct sl3516_ce_dev *ce = platform_get_drvdata(pdev);
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	sl3516_ce_rng_unregister(ce);
51362306a36Sopenharmony_ci	sl3516_ce_unregister_algs(ce);
51462306a36Sopenharmony_ci	crypto_engine_exit(ce->engine);
51562306a36Sopenharmony_ci	sl3516_ce_pm_exit(ce);
51662306a36Sopenharmony_ci	sl3516_ce_free_descs(ce);
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci#ifdef CONFIG_CRYPTO_DEV_SL3516_DEBUG
51962306a36Sopenharmony_ci	debugfs_remove_recursive(ce->dbgfs_dir);
52062306a36Sopenharmony_ci#endif
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	return 0;
52362306a36Sopenharmony_ci}
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_cistatic const struct of_device_id sl3516_ce_crypto_of_match_table[] = {
52662306a36Sopenharmony_ci	{ .compatible = "cortina,sl3516-crypto"},
52762306a36Sopenharmony_ci	{}
52862306a36Sopenharmony_ci};
52962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, sl3516_ce_crypto_of_match_table);
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_cistatic struct platform_driver sl3516_ce_driver = {
53262306a36Sopenharmony_ci	.probe		 = sl3516_ce_probe,
53362306a36Sopenharmony_ci	.remove		 = sl3516_ce_remove,
53462306a36Sopenharmony_ci	.driver		 = {
53562306a36Sopenharmony_ci		.name		= "sl3516-crypto",
53662306a36Sopenharmony_ci		.pm		= &sl3516_ce_pm_ops,
53762306a36Sopenharmony_ci		.of_match_table	= sl3516_ce_crypto_of_match_table,
53862306a36Sopenharmony_ci	},
53962306a36Sopenharmony_ci};
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_cimodule_platform_driver(sl3516_ce_driver);
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ciMODULE_DESCRIPTION("SL3516 cryptographic offloader");
54462306a36Sopenharmony_ciMODULE_LICENSE("GPL");
54562306a36Sopenharmony_ciMODULE_AUTHOR("Corentin Labbe <clabbe@baylibre.com>");
546