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