162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Freescale i.MX23/i.MX28 Data Co-Processor driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2013 Marek Vasut <marex@denx.de> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/dma-mapping.h> 962306a36Sopenharmony_ci#include <linux/interrupt.h> 1062306a36Sopenharmony_ci#include <linux/io.h> 1162306a36Sopenharmony_ci#include <linux/kernel.h> 1262306a36Sopenharmony_ci#include <linux/kthread.h> 1362306a36Sopenharmony_ci#include <linux/module.h> 1462306a36Sopenharmony_ci#include <linux/of.h> 1562306a36Sopenharmony_ci#include <linux/platform_device.h> 1662306a36Sopenharmony_ci#include <linux/stmp_device.h> 1762306a36Sopenharmony_ci#include <linux/clk.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <crypto/aes.h> 2062306a36Sopenharmony_ci#include <crypto/sha1.h> 2162306a36Sopenharmony_ci#include <crypto/sha2.h> 2262306a36Sopenharmony_ci#include <crypto/internal/hash.h> 2362306a36Sopenharmony_ci#include <crypto/internal/skcipher.h> 2462306a36Sopenharmony_ci#include <crypto/scatterwalk.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#define DCP_MAX_CHANS 4 2762306a36Sopenharmony_ci#define DCP_BUF_SZ PAGE_SIZE 2862306a36Sopenharmony_ci#define DCP_SHA_PAY_SZ 64 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#define DCP_ALIGNMENT 64 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci/* 3362306a36Sopenharmony_ci * Null hashes to align with hw behavior on imx6sl and ull 3462306a36Sopenharmony_ci * these are flipped for consistency with hw output 3562306a36Sopenharmony_ci */ 3662306a36Sopenharmony_cistatic const uint8_t sha1_null_hash[] = 3762306a36Sopenharmony_ci "\x09\x07\xd8\xaf\x90\x18\x60\x95\xef\xbf" 3862306a36Sopenharmony_ci "\x55\x32\x0d\x4b\x6b\x5e\xee\xa3\x39\xda"; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic const uint8_t sha256_null_hash[] = 4162306a36Sopenharmony_ci "\x55\xb8\x52\x78\x1b\x99\x95\xa4" 4262306a36Sopenharmony_ci "\x4c\x93\x9b\x64\xe4\x41\xae\x27" 4362306a36Sopenharmony_ci "\x24\xb9\x6f\x99\xc8\xf4\xfb\x9a" 4462306a36Sopenharmony_ci "\x14\x1c\xfc\x98\x42\xc4\xb0\xe3"; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci/* DCP DMA descriptor. */ 4762306a36Sopenharmony_cistruct dcp_dma_desc { 4862306a36Sopenharmony_ci uint32_t next_cmd_addr; 4962306a36Sopenharmony_ci uint32_t control0; 5062306a36Sopenharmony_ci uint32_t control1; 5162306a36Sopenharmony_ci uint32_t source; 5262306a36Sopenharmony_ci uint32_t destination; 5362306a36Sopenharmony_ci uint32_t size; 5462306a36Sopenharmony_ci uint32_t payload; 5562306a36Sopenharmony_ci uint32_t status; 5662306a36Sopenharmony_ci}; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci/* Coherent aligned block for bounce buffering. */ 5962306a36Sopenharmony_cistruct dcp_coherent_block { 6062306a36Sopenharmony_ci uint8_t aes_in_buf[DCP_BUF_SZ]; 6162306a36Sopenharmony_ci uint8_t aes_out_buf[DCP_BUF_SZ]; 6262306a36Sopenharmony_ci uint8_t sha_in_buf[DCP_BUF_SZ]; 6362306a36Sopenharmony_ci uint8_t sha_out_buf[DCP_SHA_PAY_SZ]; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci uint8_t aes_key[2 * AES_KEYSIZE_128]; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci struct dcp_dma_desc desc[DCP_MAX_CHANS]; 6862306a36Sopenharmony_ci}; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistruct dcp { 7162306a36Sopenharmony_ci struct device *dev; 7262306a36Sopenharmony_ci void __iomem *base; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci uint32_t caps; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci struct dcp_coherent_block *coh; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci struct completion completion[DCP_MAX_CHANS]; 7962306a36Sopenharmony_ci spinlock_t lock[DCP_MAX_CHANS]; 8062306a36Sopenharmony_ci struct task_struct *thread[DCP_MAX_CHANS]; 8162306a36Sopenharmony_ci struct crypto_queue queue[DCP_MAX_CHANS]; 8262306a36Sopenharmony_ci struct clk *dcp_clk; 8362306a36Sopenharmony_ci}; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cienum dcp_chan { 8662306a36Sopenharmony_ci DCP_CHAN_HASH_SHA = 0, 8762306a36Sopenharmony_ci DCP_CHAN_CRYPTO = 2, 8862306a36Sopenharmony_ci}; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistruct dcp_async_ctx { 9162306a36Sopenharmony_ci /* Common context */ 9262306a36Sopenharmony_ci enum dcp_chan chan; 9362306a36Sopenharmony_ci uint32_t fill; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci /* SHA Hash-specific context */ 9662306a36Sopenharmony_ci struct mutex mutex; 9762306a36Sopenharmony_ci uint32_t alg; 9862306a36Sopenharmony_ci unsigned int hot:1; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci /* Crypto-specific context */ 10162306a36Sopenharmony_ci struct crypto_skcipher *fallback; 10262306a36Sopenharmony_ci unsigned int key_len; 10362306a36Sopenharmony_ci uint8_t key[AES_KEYSIZE_128]; 10462306a36Sopenharmony_ci}; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistruct dcp_aes_req_ctx { 10762306a36Sopenharmony_ci unsigned int enc:1; 10862306a36Sopenharmony_ci unsigned int ecb:1; 10962306a36Sopenharmony_ci struct skcipher_request fallback_req; // keep at the end 11062306a36Sopenharmony_ci}; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistruct dcp_sha_req_ctx { 11362306a36Sopenharmony_ci unsigned int init:1; 11462306a36Sopenharmony_ci unsigned int fini:1; 11562306a36Sopenharmony_ci}; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistruct dcp_export_state { 11862306a36Sopenharmony_ci struct dcp_sha_req_ctx req_ctx; 11962306a36Sopenharmony_ci struct dcp_async_ctx async_ctx; 12062306a36Sopenharmony_ci}; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci/* 12362306a36Sopenharmony_ci * There can even be only one instance of the MXS DCP due to the 12462306a36Sopenharmony_ci * design of Linux Crypto API. 12562306a36Sopenharmony_ci */ 12662306a36Sopenharmony_cistatic struct dcp *global_sdcp; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci/* DCP register layout. */ 12962306a36Sopenharmony_ci#define MXS_DCP_CTRL 0x00 13062306a36Sopenharmony_ci#define MXS_DCP_CTRL_GATHER_RESIDUAL_WRITES (1 << 23) 13162306a36Sopenharmony_ci#define MXS_DCP_CTRL_ENABLE_CONTEXT_CACHING (1 << 22) 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci#define MXS_DCP_STAT 0x10 13462306a36Sopenharmony_ci#define MXS_DCP_STAT_CLR 0x18 13562306a36Sopenharmony_ci#define MXS_DCP_STAT_IRQ_MASK 0xf 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci#define MXS_DCP_CHANNELCTRL 0x20 13862306a36Sopenharmony_ci#define MXS_DCP_CHANNELCTRL_ENABLE_CHANNEL_MASK 0xff 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci#define MXS_DCP_CAPABILITY1 0x40 14162306a36Sopenharmony_ci#define MXS_DCP_CAPABILITY1_SHA256 (4 << 16) 14262306a36Sopenharmony_ci#define MXS_DCP_CAPABILITY1_SHA1 (1 << 16) 14362306a36Sopenharmony_ci#define MXS_DCP_CAPABILITY1_AES128 (1 << 0) 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci#define MXS_DCP_CONTEXT 0x50 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci#define MXS_DCP_CH_N_CMDPTR(n) (0x100 + ((n) * 0x40)) 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci#define MXS_DCP_CH_N_SEMA(n) (0x110 + ((n) * 0x40)) 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci#define MXS_DCP_CH_N_STAT(n) (0x120 + ((n) * 0x40)) 15262306a36Sopenharmony_ci#define MXS_DCP_CH_N_STAT_CLR(n) (0x128 + ((n) * 0x40)) 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci/* DMA descriptor bits. */ 15562306a36Sopenharmony_ci#define MXS_DCP_CONTROL0_HASH_TERM (1 << 13) 15662306a36Sopenharmony_ci#define MXS_DCP_CONTROL0_HASH_INIT (1 << 12) 15762306a36Sopenharmony_ci#define MXS_DCP_CONTROL0_PAYLOAD_KEY (1 << 11) 15862306a36Sopenharmony_ci#define MXS_DCP_CONTROL0_CIPHER_ENCRYPT (1 << 8) 15962306a36Sopenharmony_ci#define MXS_DCP_CONTROL0_CIPHER_INIT (1 << 9) 16062306a36Sopenharmony_ci#define MXS_DCP_CONTROL0_ENABLE_HASH (1 << 6) 16162306a36Sopenharmony_ci#define MXS_DCP_CONTROL0_ENABLE_CIPHER (1 << 5) 16262306a36Sopenharmony_ci#define MXS_DCP_CONTROL0_DECR_SEMAPHORE (1 << 1) 16362306a36Sopenharmony_ci#define MXS_DCP_CONTROL0_INTERRUPT (1 << 0) 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci#define MXS_DCP_CONTROL1_HASH_SELECT_SHA256 (2 << 16) 16662306a36Sopenharmony_ci#define MXS_DCP_CONTROL1_HASH_SELECT_SHA1 (0 << 16) 16762306a36Sopenharmony_ci#define MXS_DCP_CONTROL1_CIPHER_MODE_CBC (1 << 4) 16862306a36Sopenharmony_ci#define MXS_DCP_CONTROL1_CIPHER_MODE_ECB (0 << 4) 16962306a36Sopenharmony_ci#define MXS_DCP_CONTROL1_CIPHER_SELECT_AES128 (0 << 0) 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistatic int mxs_dcp_start_dma(struct dcp_async_ctx *actx) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci int dma_err; 17462306a36Sopenharmony_ci struct dcp *sdcp = global_sdcp; 17562306a36Sopenharmony_ci const int chan = actx->chan; 17662306a36Sopenharmony_ci uint32_t stat; 17762306a36Sopenharmony_ci unsigned long ret; 17862306a36Sopenharmony_ci struct dcp_dma_desc *desc = &sdcp->coh->desc[actx->chan]; 17962306a36Sopenharmony_ci dma_addr_t desc_phys = dma_map_single(sdcp->dev, desc, sizeof(*desc), 18062306a36Sopenharmony_ci DMA_TO_DEVICE); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci dma_err = dma_mapping_error(sdcp->dev, desc_phys); 18362306a36Sopenharmony_ci if (dma_err) 18462306a36Sopenharmony_ci return dma_err; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci reinit_completion(&sdcp->completion[chan]); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci /* Clear status register. */ 18962306a36Sopenharmony_ci writel(0xffffffff, sdcp->base + MXS_DCP_CH_N_STAT_CLR(chan)); 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci /* Load the DMA descriptor. */ 19262306a36Sopenharmony_ci writel(desc_phys, sdcp->base + MXS_DCP_CH_N_CMDPTR(chan)); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci /* Increment the semaphore to start the DMA transfer. */ 19562306a36Sopenharmony_ci writel(1, sdcp->base + MXS_DCP_CH_N_SEMA(chan)); 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci ret = wait_for_completion_timeout(&sdcp->completion[chan], 19862306a36Sopenharmony_ci msecs_to_jiffies(1000)); 19962306a36Sopenharmony_ci if (!ret) { 20062306a36Sopenharmony_ci dev_err(sdcp->dev, "Channel %i timeout (DCP_STAT=0x%08x)\n", 20162306a36Sopenharmony_ci chan, readl(sdcp->base + MXS_DCP_STAT)); 20262306a36Sopenharmony_ci return -ETIMEDOUT; 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci stat = readl(sdcp->base + MXS_DCP_CH_N_STAT(chan)); 20662306a36Sopenharmony_ci if (stat & 0xff) { 20762306a36Sopenharmony_ci dev_err(sdcp->dev, "Channel %i error (CH_STAT=0x%08x)\n", 20862306a36Sopenharmony_ci chan, stat); 20962306a36Sopenharmony_ci return -EINVAL; 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci dma_unmap_single(sdcp->dev, desc_phys, sizeof(*desc), DMA_TO_DEVICE); 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci return 0; 21562306a36Sopenharmony_ci} 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci/* 21862306a36Sopenharmony_ci * Encryption (AES128) 21962306a36Sopenharmony_ci */ 22062306a36Sopenharmony_cistatic int mxs_dcp_run_aes(struct dcp_async_ctx *actx, 22162306a36Sopenharmony_ci struct skcipher_request *req, int init) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci dma_addr_t key_phys, src_phys, dst_phys; 22462306a36Sopenharmony_ci struct dcp *sdcp = global_sdcp; 22562306a36Sopenharmony_ci struct dcp_dma_desc *desc = &sdcp->coh->desc[actx->chan]; 22662306a36Sopenharmony_ci struct dcp_aes_req_ctx *rctx = skcipher_request_ctx(req); 22762306a36Sopenharmony_ci int ret; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci key_phys = dma_map_single(sdcp->dev, sdcp->coh->aes_key, 23062306a36Sopenharmony_ci 2 * AES_KEYSIZE_128, DMA_TO_DEVICE); 23162306a36Sopenharmony_ci ret = dma_mapping_error(sdcp->dev, key_phys); 23262306a36Sopenharmony_ci if (ret) 23362306a36Sopenharmony_ci return ret; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci src_phys = dma_map_single(sdcp->dev, sdcp->coh->aes_in_buf, 23662306a36Sopenharmony_ci DCP_BUF_SZ, DMA_TO_DEVICE); 23762306a36Sopenharmony_ci ret = dma_mapping_error(sdcp->dev, src_phys); 23862306a36Sopenharmony_ci if (ret) 23962306a36Sopenharmony_ci goto err_src; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci dst_phys = dma_map_single(sdcp->dev, sdcp->coh->aes_out_buf, 24262306a36Sopenharmony_ci DCP_BUF_SZ, DMA_FROM_DEVICE); 24362306a36Sopenharmony_ci ret = dma_mapping_error(sdcp->dev, dst_phys); 24462306a36Sopenharmony_ci if (ret) 24562306a36Sopenharmony_ci goto err_dst; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci if (actx->fill % AES_BLOCK_SIZE) { 24862306a36Sopenharmony_ci dev_err(sdcp->dev, "Invalid block size!\n"); 24962306a36Sopenharmony_ci ret = -EINVAL; 25062306a36Sopenharmony_ci goto aes_done_run; 25162306a36Sopenharmony_ci } 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci /* Fill in the DMA descriptor. */ 25462306a36Sopenharmony_ci desc->control0 = MXS_DCP_CONTROL0_DECR_SEMAPHORE | 25562306a36Sopenharmony_ci MXS_DCP_CONTROL0_INTERRUPT | 25662306a36Sopenharmony_ci MXS_DCP_CONTROL0_ENABLE_CIPHER; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci /* Payload contains the key. */ 25962306a36Sopenharmony_ci desc->control0 |= MXS_DCP_CONTROL0_PAYLOAD_KEY; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci if (rctx->enc) 26262306a36Sopenharmony_ci desc->control0 |= MXS_DCP_CONTROL0_CIPHER_ENCRYPT; 26362306a36Sopenharmony_ci if (init) 26462306a36Sopenharmony_ci desc->control0 |= MXS_DCP_CONTROL0_CIPHER_INIT; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci desc->control1 = MXS_DCP_CONTROL1_CIPHER_SELECT_AES128; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci if (rctx->ecb) 26962306a36Sopenharmony_ci desc->control1 |= MXS_DCP_CONTROL1_CIPHER_MODE_ECB; 27062306a36Sopenharmony_ci else 27162306a36Sopenharmony_ci desc->control1 |= MXS_DCP_CONTROL1_CIPHER_MODE_CBC; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci desc->next_cmd_addr = 0; 27462306a36Sopenharmony_ci desc->source = src_phys; 27562306a36Sopenharmony_ci desc->destination = dst_phys; 27662306a36Sopenharmony_ci desc->size = actx->fill; 27762306a36Sopenharmony_ci desc->payload = key_phys; 27862306a36Sopenharmony_ci desc->status = 0; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci ret = mxs_dcp_start_dma(actx); 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ciaes_done_run: 28362306a36Sopenharmony_ci dma_unmap_single(sdcp->dev, dst_phys, DCP_BUF_SZ, DMA_FROM_DEVICE); 28462306a36Sopenharmony_cierr_dst: 28562306a36Sopenharmony_ci dma_unmap_single(sdcp->dev, src_phys, DCP_BUF_SZ, DMA_TO_DEVICE); 28662306a36Sopenharmony_cierr_src: 28762306a36Sopenharmony_ci dma_unmap_single(sdcp->dev, key_phys, 2 * AES_KEYSIZE_128, 28862306a36Sopenharmony_ci DMA_TO_DEVICE); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci return ret; 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_cistatic int mxs_dcp_aes_block_crypt(struct crypto_async_request *arq) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci struct dcp *sdcp = global_sdcp; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci struct skcipher_request *req = skcipher_request_cast(arq); 29862306a36Sopenharmony_ci struct dcp_async_ctx *actx = crypto_tfm_ctx(arq->tfm); 29962306a36Sopenharmony_ci struct dcp_aes_req_ctx *rctx = skcipher_request_ctx(req); 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci struct scatterlist *dst = req->dst; 30262306a36Sopenharmony_ci struct scatterlist *src = req->src; 30362306a36Sopenharmony_ci int dst_nents = sg_nents(dst); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci const int out_off = DCP_BUF_SZ; 30662306a36Sopenharmony_ci uint8_t *in_buf = sdcp->coh->aes_in_buf; 30762306a36Sopenharmony_ci uint8_t *out_buf = sdcp->coh->aes_out_buf; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci uint32_t dst_off = 0; 31062306a36Sopenharmony_ci uint8_t *src_buf = NULL; 31162306a36Sopenharmony_ci uint32_t last_out_len = 0; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci uint8_t *key = sdcp->coh->aes_key; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci int ret = 0; 31662306a36Sopenharmony_ci unsigned int i, len, clen, tlen = 0; 31762306a36Sopenharmony_ci int init = 0; 31862306a36Sopenharmony_ci bool limit_hit = false; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci actx->fill = 0; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci /* Copy the key from the temporary location. */ 32362306a36Sopenharmony_ci memcpy(key, actx->key, actx->key_len); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci if (!rctx->ecb) { 32662306a36Sopenharmony_ci /* Copy the CBC IV just past the key. */ 32762306a36Sopenharmony_ci memcpy(key + AES_KEYSIZE_128, req->iv, AES_KEYSIZE_128); 32862306a36Sopenharmony_ci /* CBC needs the INIT set. */ 32962306a36Sopenharmony_ci init = 1; 33062306a36Sopenharmony_ci } else { 33162306a36Sopenharmony_ci memset(key + AES_KEYSIZE_128, 0, AES_KEYSIZE_128); 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci for_each_sg(req->src, src, sg_nents(req->src), i) { 33562306a36Sopenharmony_ci src_buf = sg_virt(src); 33662306a36Sopenharmony_ci len = sg_dma_len(src); 33762306a36Sopenharmony_ci tlen += len; 33862306a36Sopenharmony_ci limit_hit = tlen > req->cryptlen; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci if (limit_hit) 34162306a36Sopenharmony_ci len = req->cryptlen - (tlen - len); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci do { 34462306a36Sopenharmony_ci if (actx->fill + len > out_off) 34562306a36Sopenharmony_ci clen = out_off - actx->fill; 34662306a36Sopenharmony_ci else 34762306a36Sopenharmony_ci clen = len; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci memcpy(in_buf + actx->fill, src_buf, clen); 35062306a36Sopenharmony_ci len -= clen; 35162306a36Sopenharmony_ci src_buf += clen; 35262306a36Sopenharmony_ci actx->fill += clen; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci /* 35562306a36Sopenharmony_ci * If we filled the buffer or this is the last SG, 35662306a36Sopenharmony_ci * submit the buffer. 35762306a36Sopenharmony_ci */ 35862306a36Sopenharmony_ci if (actx->fill == out_off || sg_is_last(src) || 35962306a36Sopenharmony_ci limit_hit) { 36062306a36Sopenharmony_ci ret = mxs_dcp_run_aes(actx, req, init); 36162306a36Sopenharmony_ci if (ret) 36262306a36Sopenharmony_ci return ret; 36362306a36Sopenharmony_ci init = 0; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci sg_pcopy_from_buffer(dst, dst_nents, out_buf, 36662306a36Sopenharmony_ci actx->fill, dst_off); 36762306a36Sopenharmony_ci dst_off += actx->fill; 36862306a36Sopenharmony_ci last_out_len = actx->fill; 36962306a36Sopenharmony_ci actx->fill = 0; 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci } while (len); 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci if (limit_hit) 37462306a36Sopenharmony_ci break; 37562306a36Sopenharmony_ci } 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci /* Copy the IV for CBC for chaining */ 37862306a36Sopenharmony_ci if (!rctx->ecb) { 37962306a36Sopenharmony_ci if (rctx->enc) 38062306a36Sopenharmony_ci memcpy(req->iv, out_buf+(last_out_len-AES_BLOCK_SIZE), 38162306a36Sopenharmony_ci AES_BLOCK_SIZE); 38262306a36Sopenharmony_ci else 38362306a36Sopenharmony_ci memcpy(req->iv, in_buf+(last_out_len-AES_BLOCK_SIZE), 38462306a36Sopenharmony_ci AES_BLOCK_SIZE); 38562306a36Sopenharmony_ci } 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci return ret; 38862306a36Sopenharmony_ci} 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_cistatic int dcp_chan_thread_aes(void *data) 39162306a36Sopenharmony_ci{ 39262306a36Sopenharmony_ci struct dcp *sdcp = global_sdcp; 39362306a36Sopenharmony_ci const int chan = DCP_CHAN_CRYPTO; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci struct crypto_async_request *backlog; 39662306a36Sopenharmony_ci struct crypto_async_request *arq; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci int ret; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci while (!kthread_should_stop()) { 40162306a36Sopenharmony_ci set_current_state(TASK_INTERRUPTIBLE); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci spin_lock(&sdcp->lock[chan]); 40462306a36Sopenharmony_ci backlog = crypto_get_backlog(&sdcp->queue[chan]); 40562306a36Sopenharmony_ci arq = crypto_dequeue_request(&sdcp->queue[chan]); 40662306a36Sopenharmony_ci spin_unlock(&sdcp->lock[chan]); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci if (!backlog && !arq) { 40962306a36Sopenharmony_ci schedule(); 41062306a36Sopenharmony_ci continue; 41162306a36Sopenharmony_ci } 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci set_current_state(TASK_RUNNING); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci if (backlog) 41662306a36Sopenharmony_ci crypto_request_complete(backlog, -EINPROGRESS); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci if (arq) { 41962306a36Sopenharmony_ci ret = mxs_dcp_aes_block_crypt(arq); 42062306a36Sopenharmony_ci crypto_request_complete(arq, ret); 42162306a36Sopenharmony_ci } 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci return 0; 42562306a36Sopenharmony_ci} 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_cistatic int mxs_dcp_block_fallback(struct skcipher_request *req, int enc) 42862306a36Sopenharmony_ci{ 42962306a36Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 43062306a36Sopenharmony_ci struct dcp_aes_req_ctx *rctx = skcipher_request_ctx(req); 43162306a36Sopenharmony_ci struct dcp_async_ctx *ctx = crypto_skcipher_ctx(tfm); 43262306a36Sopenharmony_ci int ret; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci skcipher_request_set_tfm(&rctx->fallback_req, ctx->fallback); 43562306a36Sopenharmony_ci skcipher_request_set_callback(&rctx->fallback_req, req->base.flags, 43662306a36Sopenharmony_ci req->base.complete, req->base.data); 43762306a36Sopenharmony_ci skcipher_request_set_crypt(&rctx->fallback_req, req->src, req->dst, 43862306a36Sopenharmony_ci req->cryptlen, req->iv); 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci if (enc) 44162306a36Sopenharmony_ci ret = crypto_skcipher_encrypt(&rctx->fallback_req); 44262306a36Sopenharmony_ci else 44362306a36Sopenharmony_ci ret = crypto_skcipher_decrypt(&rctx->fallback_req); 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci return ret; 44662306a36Sopenharmony_ci} 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_cistatic int mxs_dcp_aes_enqueue(struct skcipher_request *req, int enc, int ecb) 44962306a36Sopenharmony_ci{ 45062306a36Sopenharmony_ci struct dcp *sdcp = global_sdcp; 45162306a36Sopenharmony_ci struct crypto_async_request *arq = &req->base; 45262306a36Sopenharmony_ci struct dcp_async_ctx *actx = crypto_tfm_ctx(arq->tfm); 45362306a36Sopenharmony_ci struct dcp_aes_req_ctx *rctx = skcipher_request_ctx(req); 45462306a36Sopenharmony_ci int ret; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci if (unlikely(actx->key_len != AES_KEYSIZE_128)) 45762306a36Sopenharmony_ci return mxs_dcp_block_fallback(req, enc); 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci rctx->enc = enc; 46062306a36Sopenharmony_ci rctx->ecb = ecb; 46162306a36Sopenharmony_ci actx->chan = DCP_CHAN_CRYPTO; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci spin_lock(&sdcp->lock[actx->chan]); 46462306a36Sopenharmony_ci ret = crypto_enqueue_request(&sdcp->queue[actx->chan], &req->base); 46562306a36Sopenharmony_ci spin_unlock(&sdcp->lock[actx->chan]); 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci wake_up_process(sdcp->thread[actx->chan]); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci return ret; 47062306a36Sopenharmony_ci} 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_cistatic int mxs_dcp_aes_ecb_decrypt(struct skcipher_request *req) 47362306a36Sopenharmony_ci{ 47462306a36Sopenharmony_ci return mxs_dcp_aes_enqueue(req, 0, 1); 47562306a36Sopenharmony_ci} 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_cistatic int mxs_dcp_aes_ecb_encrypt(struct skcipher_request *req) 47862306a36Sopenharmony_ci{ 47962306a36Sopenharmony_ci return mxs_dcp_aes_enqueue(req, 1, 1); 48062306a36Sopenharmony_ci} 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_cistatic int mxs_dcp_aes_cbc_decrypt(struct skcipher_request *req) 48362306a36Sopenharmony_ci{ 48462306a36Sopenharmony_ci return mxs_dcp_aes_enqueue(req, 0, 0); 48562306a36Sopenharmony_ci} 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_cistatic int mxs_dcp_aes_cbc_encrypt(struct skcipher_request *req) 48862306a36Sopenharmony_ci{ 48962306a36Sopenharmony_ci return mxs_dcp_aes_enqueue(req, 1, 0); 49062306a36Sopenharmony_ci} 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_cistatic int mxs_dcp_aes_setkey(struct crypto_skcipher *tfm, const u8 *key, 49362306a36Sopenharmony_ci unsigned int len) 49462306a36Sopenharmony_ci{ 49562306a36Sopenharmony_ci struct dcp_async_ctx *actx = crypto_skcipher_ctx(tfm); 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci /* 49862306a36Sopenharmony_ci * AES 128 is supposed by the hardware, store key into temporary 49962306a36Sopenharmony_ci * buffer and exit. We must use the temporary buffer here, since 50062306a36Sopenharmony_ci * there can still be an operation in progress. 50162306a36Sopenharmony_ci */ 50262306a36Sopenharmony_ci actx->key_len = len; 50362306a36Sopenharmony_ci if (len == AES_KEYSIZE_128) { 50462306a36Sopenharmony_ci memcpy(actx->key, key, len); 50562306a36Sopenharmony_ci return 0; 50662306a36Sopenharmony_ci } 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci /* 50962306a36Sopenharmony_ci * If the requested AES key size is not supported by the hardware, 51062306a36Sopenharmony_ci * but is supported by in-kernel software implementation, we use 51162306a36Sopenharmony_ci * software fallback. 51262306a36Sopenharmony_ci */ 51362306a36Sopenharmony_ci crypto_skcipher_clear_flags(actx->fallback, CRYPTO_TFM_REQ_MASK); 51462306a36Sopenharmony_ci crypto_skcipher_set_flags(actx->fallback, 51562306a36Sopenharmony_ci tfm->base.crt_flags & CRYPTO_TFM_REQ_MASK); 51662306a36Sopenharmony_ci return crypto_skcipher_setkey(actx->fallback, key, len); 51762306a36Sopenharmony_ci} 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_cistatic int mxs_dcp_aes_fallback_init_tfm(struct crypto_skcipher *tfm) 52062306a36Sopenharmony_ci{ 52162306a36Sopenharmony_ci const char *name = crypto_tfm_alg_name(crypto_skcipher_tfm(tfm)); 52262306a36Sopenharmony_ci struct dcp_async_ctx *actx = crypto_skcipher_ctx(tfm); 52362306a36Sopenharmony_ci struct crypto_skcipher *blk; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci blk = crypto_alloc_skcipher(name, 0, CRYPTO_ALG_NEED_FALLBACK); 52662306a36Sopenharmony_ci if (IS_ERR(blk)) 52762306a36Sopenharmony_ci return PTR_ERR(blk); 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci actx->fallback = blk; 53062306a36Sopenharmony_ci crypto_skcipher_set_reqsize(tfm, sizeof(struct dcp_aes_req_ctx) + 53162306a36Sopenharmony_ci crypto_skcipher_reqsize(blk)); 53262306a36Sopenharmony_ci return 0; 53362306a36Sopenharmony_ci} 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_cistatic void mxs_dcp_aes_fallback_exit_tfm(struct crypto_skcipher *tfm) 53662306a36Sopenharmony_ci{ 53762306a36Sopenharmony_ci struct dcp_async_ctx *actx = crypto_skcipher_ctx(tfm); 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci crypto_free_skcipher(actx->fallback); 54062306a36Sopenharmony_ci} 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci/* 54362306a36Sopenharmony_ci * Hashing (SHA1/SHA256) 54462306a36Sopenharmony_ci */ 54562306a36Sopenharmony_cistatic int mxs_dcp_run_sha(struct ahash_request *req) 54662306a36Sopenharmony_ci{ 54762306a36Sopenharmony_ci struct dcp *sdcp = global_sdcp; 54862306a36Sopenharmony_ci int ret; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 55162306a36Sopenharmony_ci struct dcp_async_ctx *actx = crypto_ahash_ctx(tfm); 55262306a36Sopenharmony_ci struct dcp_sha_req_ctx *rctx = ahash_request_ctx(req); 55362306a36Sopenharmony_ci struct dcp_dma_desc *desc = &sdcp->coh->desc[actx->chan]; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci dma_addr_t digest_phys = 0; 55662306a36Sopenharmony_ci dma_addr_t buf_phys = dma_map_single(sdcp->dev, sdcp->coh->sha_in_buf, 55762306a36Sopenharmony_ci DCP_BUF_SZ, DMA_TO_DEVICE); 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci ret = dma_mapping_error(sdcp->dev, buf_phys); 56062306a36Sopenharmony_ci if (ret) 56162306a36Sopenharmony_ci return ret; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci /* Fill in the DMA descriptor. */ 56462306a36Sopenharmony_ci desc->control0 = MXS_DCP_CONTROL0_DECR_SEMAPHORE | 56562306a36Sopenharmony_ci MXS_DCP_CONTROL0_INTERRUPT | 56662306a36Sopenharmony_ci MXS_DCP_CONTROL0_ENABLE_HASH; 56762306a36Sopenharmony_ci if (rctx->init) 56862306a36Sopenharmony_ci desc->control0 |= MXS_DCP_CONTROL0_HASH_INIT; 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci desc->control1 = actx->alg; 57162306a36Sopenharmony_ci desc->next_cmd_addr = 0; 57262306a36Sopenharmony_ci desc->source = buf_phys; 57362306a36Sopenharmony_ci desc->destination = 0; 57462306a36Sopenharmony_ci desc->size = actx->fill; 57562306a36Sopenharmony_ci desc->payload = 0; 57662306a36Sopenharmony_ci desc->status = 0; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci /* 57962306a36Sopenharmony_ci * Align driver with hw behavior when generating null hashes 58062306a36Sopenharmony_ci */ 58162306a36Sopenharmony_ci if (rctx->init && rctx->fini && desc->size == 0) { 58262306a36Sopenharmony_ci struct hash_alg_common *halg = crypto_hash_alg_common(tfm); 58362306a36Sopenharmony_ci const uint8_t *sha_buf = 58462306a36Sopenharmony_ci (actx->alg == MXS_DCP_CONTROL1_HASH_SELECT_SHA1) ? 58562306a36Sopenharmony_ci sha1_null_hash : sha256_null_hash; 58662306a36Sopenharmony_ci memcpy(sdcp->coh->sha_out_buf, sha_buf, halg->digestsize); 58762306a36Sopenharmony_ci ret = 0; 58862306a36Sopenharmony_ci goto done_run; 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci /* Set HASH_TERM bit for last transfer block. */ 59262306a36Sopenharmony_ci if (rctx->fini) { 59362306a36Sopenharmony_ci digest_phys = dma_map_single(sdcp->dev, sdcp->coh->sha_out_buf, 59462306a36Sopenharmony_ci DCP_SHA_PAY_SZ, DMA_FROM_DEVICE); 59562306a36Sopenharmony_ci ret = dma_mapping_error(sdcp->dev, digest_phys); 59662306a36Sopenharmony_ci if (ret) 59762306a36Sopenharmony_ci goto done_run; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci desc->control0 |= MXS_DCP_CONTROL0_HASH_TERM; 60062306a36Sopenharmony_ci desc->payload = digest_phys; 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci ret = mxs_dcp_start_dma(actx); 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci if (rctx->fini) 60662306a36Sopenharmony_ci dma_unmap_single(sdcp->dev, digest_phys, DCP_SHA_PAY_SZ, 60762306a36Sopenharmony_ci DMA_FROM_DEVICE); 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_cidone_run: 61062306a36Sopenharmony_ci dma_unmap_single(sdcp->dev, buf_phys, DCP_BUF_SZ, DMA_TO_DEVICE); 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci return ret; 61362306a36Sopenharmony_ci} 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_cistatic int dcp_sha_req_to_buf(struct crypto_async_request *arq) 61662306a36Sopenharmony_ci{ 61762306a36Sopenharmony_ci struct dcp *sdcp = global_sdcp; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci struct ahash_request *req = ahash_request_cast(arq); 62062306a36Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 62162306a36Sopenharmony_ci struct dcp_async_ctx *actx = crypto_ahash_ctx(tfm); 62262306a36Sopenharmony_ci struct dcp_sha_req_ctx *rctx = ahash_request_ctx(req); 62362306a36Sopenharmony_ci struct hash_alg_common *halg = crypto_hash_alg_common(tfm); 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci uint8_t *in_buf = sdcp->coh->sha_in_buf; 62662306a36Sopenharmony_ci uint8_t *out_buf = sdcp->coh->sha_out_buf; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci struct scatterlist *src; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci unsigned int i, len, clen, oft = 0; 63162306a36Sopenharmony_ci int ret; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci int fin = rctx->fini; 63462306a36Sopenharmony_ci if (fin) 63562306a36Sopenharmony_ci rctx->fini = 0; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci src = req->src; 63862306a36Sopenharmony_ci len = req->nbytes; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci while (len) { 64162306a36Sopenharmony_ci if (actx->fill + len > DCP_BUF_SZ) 64262306a36Sopenharmony_ci clen = DCP_BUF_SZ - actx->fill; 64362306a36Sopenharmony_ci else 64462306a36Sopenharmony_ci clen = len; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci scatterwalk_map_and_copy(in_buf + actx->fill, src, oft, clen, 64762306a36Sopenharmony_ci 0); 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci len -= clen; 65062306a36Sopenharmony_ci oft += clen; 65162306a36Sopenharmony_ci actx->fill += clen; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci /* 65462306a36Sopenharmony_ci * If we filled the buffer and still have some 65562306a36Sopenharmony_ci * more data, submit the buffer. 65662306a36Sopenharmony_ci */ 65762306a36Sopenharmony_ci if (len && actx->fill == DCP_BUF_SZ) { 65862306a36Sopenharmony_ci ret = mxs_dcp_run_sha(req); 65962306a36Sopenharmony_ci if (ret) 66062306a36Sopenharmony_ci return ret; 66162306a36Sopenharmony_ci actx->fill = 0; 66262306a36Sopenharmony_ci rctx->init = 0; 66362306a36Sopenharmony_ci } 66462306a36Sopenharmony_ci } 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci if (fin) { 66762306a36Sopenharmony_ci rctx->fini = 1; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci /* Submit whatever is left. */ 67062306a36Sopenharmony_ci if (!req->result) 67162306a36Sopenharmony_ci return -EINVAL; 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci ret = mxs_dcp_run_sha(req); 67462306a36Sopenharmony_ci if (ret) 67562306a36Sopenharmony_ci return ret; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci actx->fill = 0; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci /* For some reason the result is flipped */ 68062306a36Sopenharmony_ci for (i = 0; i < halg->digestsize; i++) 68162306a36Sopenharmony_ci req->result[i] = out_buf[halg->digestsize - i - 1]; 68262306a36Sopenharmony_ci } 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci return 0; 68562306a36Sopenharmony_ci} 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_cistatic int dcp_chan_thread_sha(void *data) 68862306a36Sopenharmony_ci{ 68962306a36Sopenharmony_ci struct dcp *sdcp = global_sdcp; 69062306a36Sopenharmony_ci const int chan = DCP_CHAN_HASH_SHA; 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci struct crypto_async_request *backlog; 69362306a36Sopenharmony_ci struct crypto_async_request *arq; 69462306a36Sopenharmony_ci int ret; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci while (!kthread_should_stop()) { 69762306a36Sopenharmony_ci set_current_state(TASK_INTERRUPTIBLE); 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci spin_lock(&sdcp->lock[chan]); 70062306a36Sopenharmony_ci backlog = crypto_get_backlog(&sdcp->queue[chan]); 70162306a36Sopenharmony_ci arq = crypto_dequeue_request(&sdcp->queue[chan]); 70262306a36Sopenharmony_ci spin_unlock(&sdcp->lock[chan]); 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci if (!backlog && !arq) { 70562306a36Sopenharmony_ci schedule(); 70662306a36Sopenharmony_ci continue; 70762306a36Sopenharmony_ci } 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci set_current_state(TASK_RUNNING); 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci if (backlog) 71262306a36Sopenharmony_ci crypto_request_complete(backlog, -EINPROGRESS); 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci if (arq) { 71562306a36Sopenharmony_ci ret = dcp_sha_req_to_buf(arq); 71662306a36Sopenharmony_ci crypto_request_complete(arq, ret); 71762306a36Sopenharmony_ci } 71862306a36Sopenharmony_ci } 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci return 0; 72162306a36Sopenharmony_ci} 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_cistatic int dcp_sha_init(struct ahash_request *req) 72462306a36Sopenharmony_ci{ 72562306a36Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 72662306a36Sopenharmony_ci struct dcp_async_ctx *actx = crypto_ahash_ctx(tfm); 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci struct hash_alg_common *halg = crypto_hash_alg_common(tfm); 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci /* 73162306a36Sopenharmony_ci * Start hashing session. The code below only inits the 73262306a36Sopenharmony_ci * hashing session context, nothing more. 73362306a36Sopenharmony_ci */ 73462306a36Sopenharmony_ci memset(actx, 0, sizeof(*actx)); 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci if (strcmp(halg->base.cra_name, "sha1") == 0) 73762306a36Sopenharmony_ci actx->alg = MXS_DCP_CONTROL1_HASH_SELECT_SHA1; 73862306a36Sopenharmony_ci else 73962306a36Sopenharmony_ci actx->alg = MXS_DCP_CONTROL1_HASH_SELECT_SHA256; 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci actx->fill = 0; 74262306a36Sopenharmony_ci actx->hot = 0; 74362306a36Sopenharmony_ci actx->chan = DCP_CHAN_HASH_SHA; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci mutex_init(&actx->mutex); 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci return 0; 74862306a36Sopenharmony_ci} 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_cistatic int dcp_sha_update_fx(struct ahash_request *req, int fini) 75162306a36Sopenharmony_ci{ 75262306a36Sopenharmony_ci struct dcp *sdcp = global_sdcp; 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci struct dcp_sha_req_ctx *rctx = ahash_request_ctx(req); 75562306a36Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 75662306a36Sopenharmony_ci struct dcp_async_ctx *actx = crypto_ahash_ctx(tfm); 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci int ret; 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci /* 76162306a36Sopenharmony_ci * Ignore requests that have no data in them and are not 76262306a36Sopenharmony_ci * the trailing requests in the stream of requests. 76362306a36Sopenharmony_ci */ 76462306a36Sopenharmony_ci if (!req->nbytes && !fini) 76562306a36Sopenharmony_ci return 0; 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci mutex_lock(&actx->mutex); 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci rctx->fini = fini; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci if (!actx->hot) { 77262306a36Sopenharmony_ci actx->hot = 1; 77362306a36Sopenharmony_ci rctx->init = 1; 77462306a36Sopenharmony_ci } 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci spin_lock(&sdcp->lock[actx->chan]); 77762306a36Sopenharmony_ci ret = crypto_enqueue_request(&sdcp->queue[actx->chan], &req->base); 77862306a36Sopenharmony_ci spin_unlock(&sdcp->lock[actx->chan]); 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci wake_up_process(sdcp->thread[actx->chan]); 78162306a36Sopenharmony_ci mutex_unlock(&actx->mutex); 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci return ret; 78462306a36Sopenharmony_ci} 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_cistatic int dcp_sha_update(struct ahash_request *req) 78762306a36Sopenharmony_ci{ 78862306a36Sopenharmony_ci return dcp_sha_update_fx(req, 0); 78962306a36Sopenharmony_ci} 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_cistatic int dcp_sha_final(struct ahash_request *req) 79262306a36Sopenharmony_ci{ 79362306a36Sopenharmony_ci ahash_request_set_crypt(req, NULL, req->result, 0); 79462306a36Sopenharmony_ci req->nbytes = 0; 79562306a36Sopenharmony_ci return dcp_sha_update_fx(req, 1); 79662306a36Sopenharmony_ci} 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_cistatic int dcp_sha_finup(struct ahash_request *req) 79962306a36Sopenharmony_ci{ 80062306a36Sopenharmony_ci return dcp_sha_update_fx(req, 1); 80162306a36Sopenharmony_ci} 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_cistatic int dcp_sha_digest(struct ahash_request *req) 80462306a36Sopenharmony_ci{ 80562306a36Sopenharmony_ci int ret; 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci ret = dcp_sha_init(req); 80862306a36Sopenharmony_ci if (ret) 80962306a36Sopenharmony_ci return ret; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci return dcp_sha_finup(req); 81262306a36Sopenharmony_ci} 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_cistatic int dcp_sha_import(struct ahash_request *req, const void *in) 81562306a36Sopenharmony_ci{ 81662306a36Sopenharmony_ci struct dcp_sha_req_ctx *rctx = ahash_request_ctx(req); 81762306a36Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 81862306a36Sopenharmony_ci struct dcp_async_ctx *actx = crypto_ahash_ctx(tfm); 81962306a36Sopenharmony_ci const struct dcp_export_state *export = in; 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci memset(rctx, 0, sizeof(struct dcp_sha_req_ctx)); 82262306a36Sopenharmony_ci memset(actx, 0, sizeof(struct dcp_async_ctx)); 82362306a36Sopenharmony_ci memcpy(rctx, &export->req_ctx, sizeof(struct dcp_sha_req_ctx)); 82462306a36Sopenharmony_ci memcpy(actx, &export->async_ctx, sizeof(struct dcp_async_ctx)); 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci return 0; 82762306a36Sopenharmony_ci} 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_cistatic int dcp_sha_export(struct ahash_request *req, void *out) 83062306a36Sopenharmony_ci{ 83162306a36Sopenharmony_ci struct dcp_sha_req_ctx *rctx_state = ahash_request_ctx(req); 83262306a36Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 83362306a36Sopenharmony_ci struct dcp_async_ctx *actx_state = crypto_ahash_ctx(tfm); 83462306a36Sopenharmony_ci struct dcp_export_state *export = out; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci memcpy(&export->req_ctx, rctx_state, sizeof(struct dcp_sha_req_ctx)); 83762306a36Sopenharmony_ci memcpy(&export->async_ctx, actx_state, sizeof(struct dcp_async_ctx)); 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci return 0; 84062306a36Sopenharmony_ci} 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_cistatic int dcp_sha_cra_init(struct crypto_tfm *tfm) 84362306a36Sopenharmony_ci{ 84462306a36Sopenharmony_ci crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), 84562306a36Sopenharmony_ci sizeof(struct dcp_sha_req_ctx)); 84662306a36Sopenharmony_ci return 0; 84762306a36Sopenharmony_ci} 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_cistatic void dcp_sha_cra_exit(struct crypto_tfm *tfm) 85062306a36Sopenharmony_ci{ 85162306a36Sopenharmony_ci} 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci/* AES 128 ECB and AES 128 CBC */ 85462306a36Sopenharmony_cistatic struct skcipher_alg dcp_aes_algs[] = { 85562306a36Sopenharmony_ci { 85662306a36Sopenharmony_ci .base.cra_name = "ecb(aes)", 85762306a36Sopenharmony_ci .base.cra_driver_name = "ecb-aes-dcp", 85862306a36Sopenharmony_ci .base.cra_priority = 400, 85962306a36Sopenharmony_ci .base.cra_alignmask = 15, 86062306a36Sopenharmony_ci .base.cra_flags = CRYPTO_ALG_ASYNC | 86162306a36Sopenharmony_ci CRYPTO_ALG_NEED_FALLBACK, 86262306a36Sopenharmony_ci .base.cra_blocksize = AES_BLOCK_SIZE, 86362306a36Sopenharmony_ci .base.cra_ctxsize = sizeof(struct dcp_async_ctx), 86462306a36Sopenharmony_ci .base.cra_module = THIS_MODULE, 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 86762306a36Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 86862306a36Sopenharmony_ci .setkey = mxs_dcp_aes_setkey, 86962306a36Sopenharmony_ci .encrypt = mxs_dcp_aes_ecb_encrypt, 87062306a36Sopenharmony_ci .decrypt = mxs_dcp_aes_ecb_decrypt, 87162306a36Sopenharmony_ci .init = mxs_dcp_aes_fallback_init_tfm, 87262306a36Sopenharmony_ci .exit = mxs_dcp_aes_fallback_exit_tfm, 87362306a36Sopenharmony_ci }, { 87462306a36Sopenharmony_ci .base.cra_name = "cbc(aes)", 87562306a36Sopenharmony_ci .base.cra_driver_name = "cbc-aes-dcp", 87662306a36Sopenharmony_ci .base.cra_priority = 400, 87762306a36Sopenharmony_ci .base.cra_alignmask = 15, 87862306a36Sopenharmony_ci .base.cra_flags = CRYPTO_ALG_ASYNC | 87962306a36Sopenharmony_ci CRYPTO_ALG_NEED_FALLBACK, 88062306a36Sopenharmony_ci .base.cra_blocksize = AES_BLOCK_SIZE, 88162306a36Sopenharmony_ci .base.cra_ctxsize = sizeof(struct dcp_async_ctx), 88262306a36Sopenharmony_ci .base.cra_module = THIS_MODULE, 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 88562306a36Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 88662306a36Sopenharmony_ci .setkey = mxs_dcp_aes_setkey, 88762306a36Sopenharmony_ci .encrypt = mxs_dcp_aes_cbc_encrypt, 88862306a36Sopenharmony_ci .decrypt = mxs_dcp_aes_cbc_decrypt, 88962306a36Sopenharmony_ci .ivsize = AES_BLOCK_SIZE, 89062306a36Sopenharmony_ci .init = mxs_dcp_aes_fallback_init_tfm, 89162306a36Sopenharmony_ci .exit = mxs_dcp_aes_fallback_exit_tfm, 89262306a36Sopenharmony_ci }, 89362306a36Sopenharmony_ci}; 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci/* SHA1 */ 89662306a36Sopenharmony_cistatic struct ahash_alg dcp_sha1_alg = { 89762306a36Sopenharmony_ci .init = dcp_sha_init, 89862306a36Sopenharmony_ci .update = dcp_sha_update, 89962306a36Sopenharmony_ci .final = dcp_sha_final, 90062306a36Sopenharmony_ci .finup = dcp_sha_finup, 90162306a36Sopenharmony_ci .digest = dcp_sha_digest, 90262306a36Sopenharmony_ci .import = dcp_sha_import, 90362306a36Sopenharmony_ci .export = dcp_sha_export, 90462306a36Sopenharmony_ci .halg = { 90562306a36Sopenharmony_ci .digestsize = SHA1_DIGEST_SIZE, 90662306a36Sopenharmony_ci .statesize = sizeof(struct dcp_export_state), 90762306a36Sopenharmony_ci .base = { 90862306a36Sopenharmony_ci .cra_name = "sha1", 90962306a36Sopenharmony_ci .cra_driver_name = "sha1-dcp", 91062306a36Sopenharmony_ci .cra_priority = 400, 91162306a36Sopenharmony_ci .cra_alignmask = 63, 91262306a36Sopenharmony_ci .cra_flags = CRYPTO_ALG_ASYNC, 91362306a36Sopenharmony_ci .cra_blocksize = SHA1_BLOCK_SIZE, 91462306a36Sopenharmony_ci .cra_ctxsize = sizeof(struct dcp_async_ctx), 91562306a36Sopenharmony_ci .cra_module = THIS_MODULE, 91662306a36Sopenharmony_ci .cra_init = dcp_sha_cra_init, 91762306a36Sopenharmony_ci .cra_exit = dcp_sha_cra_exit, 91862306a36Sopenharmony_ci }, 91962306a36Sopenharmony_ci }, 92062306a36Sopenharmony_ci}; 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci/* SHA256 */ 92362306a36Sopenharmony_cistatic struct ahash_alg dcp_sha256_alg = { 92462306a36Sopenharmony_ci .init = dcp_sha_init, 92562306a36Sopenharmony_ci .update = dcp_sha_update, 92662306a36Sopenharmony_ci .final = dcp_sha_final, 92762306a36Sopenharmony_ci .finup = dcp_sha_finup, 92862306a36Sopenharmony_ci .digest = dcp_sha_digest, 92962306a36Sopenharmony_ci .import = dcp_sha_import, 93062306a36Sopenharmony_ci .export = dcp_sha_export, 93162306a36Sopenharmony_ci .halg = { 93262306a36Sopenharmony_ci .digestsize = SHA256_DIGEST_SIZE, 93362306a36Sopenharmony_ci .statesize = sizeof(struct dcp_export_state), 93462306a36Sopenharmony_ci .base = { 93562306a36Sopenharmony_ci .cra_name = "sha256", 93662306a36Sopenharmony_ci .cra_driver_name = "sha256-dcp", 93762306a36Sopenharmony_ci .cra_priority = 400, 93862306a36Sopenharmony_ci .cra_alignmask = 63, 93962306a36Sopenharmony_ci .cra_flags = CRYPTO_ALG_ASYNC, 94062306a36Sopenharmony_ci .cra_blocksize = SHA256_BLOCK_SIZE, 94162306a36Sopenharmony_ci .cra_ctxsize = sizeof(struct dcp_async_ctx), 94262306a36Sopenharmony_ci .cra_module = THIS_MODULE, 94362306a36Sopenharmony_ci .cra_init = dcp_sha_cra_init, 94462306a36Sopenharmony_ci .cra_exit = dcp_sha_cra_exit, 94562306a36Sopenharmony_ci }, 94662306a36Sopenharmony_ci }, 94762306a36Sopenharmony_ci}; 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_cistatic irqreturn_t mxs_dcp_irq(int irq, void *context) 95062306a36Sopenharmony_ci{ 95162306a36Sopenharmony_ci struct dcp *sdcp = context; 95262306a36Sopenharmony_ci uint32_t stat; 95362306a36Sopenharmony_ci int i; 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci stat = readl(sdcp->base + MXS_DCP_STAT); 95662306a36Sopenharmony_ci stat &= MXS_DCP_STAT_IRQ_MASK; 95762306a36Sopenharmony_ci if (!stat) 95862306a36Sopenharmony_ci return IRQ_NONE; 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci /* Clear the interrupts. */ 96162306a36Sopenharmony_ci writel(stat, sdcp->base + MXS_DCP_STAT_CLR); 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci /* Complete the DMA requests that finished. */ 96462306a36Sopenharmony_ci for (i = 0; i < DCP_MAX_CHANS; i++) 96562306a36Sopenharmony_ci if (stat & (1 << i)) 96662306a36Sopenharmony_ci complete(&sdcp->completion[i]); 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci return IRQ_HANDLED; 96962306a36Sopenharmony_ci} 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_cistatic int mxs_dcp_probe(struct platform_device *pdev) 97262306a36Sopenharmony_ci{ 97362306a36Sopenharmony_ci struct device *dev = &pdev->dev; 97462306a36Sopenharmony_ci struct dcp *sdcp = NULL; 97562306a36Sopenharmony_ci int i, ret; 97662306a36Sopenharmony_ci int dcp_vmi_irq, dcp_irq; 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci if (global_sdcp) { 97962306a36Sopenharmony_ci dev_err(dev, "Only one DCP instance allowed!\n"); 98062306a36Sopenharmony_ci return -ENODEV; 98162306a36Sopenharmony_ci } 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci dcp_vmi_irq = platform_get_irq(pdev, 0); 98462306a36Sopenharmony_ci if (dcp_vmi_irq < 0) 98562306a36Sopenharmony_ci return dcp_vmi_irq; 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci dcp_irq = platform_get_irq(pdev, 1); 98862306a36Sopenharmony_ci if (dcp_irq < 0) 98962306a36Sopenharmony_ci return dcp_irq; 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci sdcp = devm_kzalloc(dev, sizeof(*sdcp), GFP_KERNEL); 99262306a36Sopenharmony_ci if (!sdcp) 99362306a36Sopenharmony_ci return -ENOMEM; 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci sdcp->dev = dev; 99662306a36Sopenharmony_ci sdcp->base = devm_platform_ioremap_resource(pdev, 0); 99762306a36Sopenharmony_ci if (IS_ERR(sdcp->base)) 99862306a36Sopenharmony_ci return PTR_ERR(sdcp->base); 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci ret = devm_request_irq(dev, dcp_vmi_irq, mxs_dcp_irq, 0, 100262306a36Sopenharmony_ci "dcp-vmi-irq", sdcp); 100362306a36Sopenharmony_ci if (ret) { 100462306a36Sopenharmony_ci dev_err(dev, "Failed to claim DCP VMI IRQ!\n"); 100562306a36Sopenharmony_ci return ret; 100662306a36Sopenharmony_ci } 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci ret = devm_request_irq(dev, dcp_irq, mxs_dcp_irq, 0, 100962306a36Sopenharmony_ci "dcp-irq", sdcp); 101062306a36Sopenharmony_ci if (ret) { 101162306a36Sopenharmony_ci dev_err(dev, "Failed to claim DCP IRQ!\n"); 101262306a36Sopenharmony_ci return ret; 101362306a36Sopenharmony_ci } 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci /* Allocate coherent helper block. */ 101662306a36Sopenharmony_ci sdcp->coh = devm_kzalloc(dev, sizeof(*sdcp->coh) + DCP_ALIGNMENT, 101762306a36Sopenharmony_ci GFP_KERNEL); 101862306a36Sopenharmony_ci if (!sdcp->coh) 101962306a36Sopenharmony_ci return -ENOMEM; 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci /* Re-align the structure so it fits the DCP constraints. */ 102262306a36Sopenharmony_ci sdcp->coh = PTR_ALIGN(sdcp->coh, DCP_ALIGNMENT); 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci /* DCP clock is optional, only used on some SOCs */ 102562306a36Sopenharmony_ci sdcp->dcp_clk = devm_clk_get_optional_enabled(dev, "dcp"); 102662306a36Sopenharmony_ci if (IS_ERR(sdcp->dcp_clk)) 102762306a36Sopenharmony_ci return PTR_ERR(sdcp->dcp_clk); 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci /* Restart the DCP block. */ 103062306a36Sopenharmony_ci ret = stmp_reset_block(sdcp->base); 103162306a36Sopenharmony_ci if (ret) { 103262306a36Sopenharmony_ci dev_err(dev, "Failed reset\n"); 103362306a36Sopenharmony_ci return ret; 103462306a36Sopenharmony_ci } 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci /* Initialize control register. */ 103762306a36Sopenharmony_ci writel(MXS_DCP_CTRL_GATHER_RESIDUAL_WRITES | 103862306a36Sopenharmony_ci MXS_DCP_CTRL_ENABLE_CONTEXT_CACHING | 0xf, 103962306a36Sopenharmony_ci sdcp->base + MXS_DCP_CTRL); 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci /* Enable all DCP DMA channels. */ 104262306a36Sopenharmony_ci writel(MXS_DCP_CHANNELCTRL_ENABLE_CHANNEL_MASK, 104362306a36Sopenharmony_ci sdcp->base + MXS_DCP_CHANNELCTRL); 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci /* 104662306a36Sopenharmony_ci * We do not enable context switching. Give the context buffer a 104762306a36Sopenharmony_ci * pointer to an illegal address so if context switching is 104862306a36Sopenharmony_ci * inadvertantly enabled, the DCP will return an error instead of 104962306a36Sopenharmony_ci * trashing good memory. The DCP DMA cannot access ROM, so any ROM 105062306a36Sopenharmony_ci * address will do. 105162306a36Sopenharmony_ci */ 105262306a36Sopenharmony_ci writel(0xffff0000, sdcp->base + MXS_DCP_CONTEXT); 105362306a36Sopenharmony_ci for (i = 0; i < DCP_MAX_CHANS; i++) 105462306a36Sopenharmony_ci writel(0xffffffff, sdcp->base + MXS_DCP_CH_N_STAT_CLR(i)); 105562306a36Sopenharmony_ci writel(0xffffffff, sdcp->base + MXS_DCP_STAT_CLR); 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci global_sdcp = sdcp; 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci platform_set_drvdata(pdev, sdcp); 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci for (i = 0; i < DCP_MAX_CHANS; i++) { 106262306a36Sopenharmony_ci spin_lock_init(&sdcp->lock[i]); 106362306a36Sopenharmony_ci init_completion(&sdcp->completion[i]); 106462306a36Sopenharmony_ci crypto_init_queue(&sdcp->queue[i], 50); 106562306a36Sopenharmony_ci } 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci /* Create the SHA and AES handler threads. */ 106862306a36Sopenharmony_ci sdcp->thread[DCP_CHAN_HASH_SHA] = kthread_run(dcp_chan_thread_sha, 106962306a36Sopenharmony_ci NULL, "mxs_dcp_chan/sha"); 107062306a36Sopenharmony_ci if (IS_ERR(sdcp->thread[DCP_CHAN_HASH_SHA])) { 107162306a36Sopenharmony_ci dev_err(dev, "Error starting SHA thread!\n"); 107262306a36Sopenharmony_ci ret = PTR_ERR(sdcp->thread[DCP_CHAN_HASH_SHA]); 107362306a36Sopenharmony_ci return ret; 107462306a36Sopenharmony_ci } 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci sdcp->thread[DCP_CHAN_CRYPTO] = kthread_run(dcp_chan_thread_aes, 107762306a36Sopenharmony_ci NULL, "mxs_dcp_chan/aes"); 107862306a36Sopenharmony_ci if (IS_ERR(sdcp->thread[DCP_CHAN_CRYPTO])) { 107962306a36Sopenharmony_ci dev_err(dev, "Error starting SHA thread!\n"); 108062306a36Sopenharmony_ci ret = PTR_ERR(sdcp->thread[DCP_CHAN_CRYPTO]); 108162306a36Sopenharmony_ci goto err_destroy_sha_thread; 108262306a36Sopenharmony_ci } 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci /* Register the various crypto algorithms. */ 108562306a36Sopenharmony_ci sdcp->caps = readl(sdcp->base + MXS_DCP_CAPABILITY1); 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci if (sdcp->caps & MXS_DCP_CAPABILITY1_AES128) { 108862306a36Sopenharmony_ci ret = crypto_register_skciphers(dcp_aes_algs, 108962306a36Sopenharmony_ci ARRAY_SIZE(dcp_aes_algs)); 109062306a36Sopenharmony_ci if (ret) { 109162306a36Sopenharmony_ci /* Failed to register algorithm. */ 109262306a36Sopenharmony_ci dev_err(dev, "Failed to register AES crypto!\n"); 109362306a36Sopenharmony_ci goto err_destroy_aes_thread; 109462306a36Sopenharmony_ci } 109562306a36Sopenharmony_ci } 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci if (sdcp->caps & MXS_DCP_CAPABILITY1_SHA1) { 109862306a36Sopenharmony_ci ret = crypto_register_ahash(&dcp_sha1_alg); 109962306a36Sopenharmony_ci if (ret) { 110062306a36Sopenharmony_ci dev_err(dev, "Failed to register %s hash!\n", 110162306a36Sopenharmony_ci dcp_sha1_alg.halg.base.cra_name); 110262306a36Sopenharmony_ci goto err_unregister_aes; 110362306a36Sopenharmony_ci } 110462306a36Sopenharmony_ci } 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci if (sdcp->caps & MXS_DCP_CAPABILITY1_SHA256) { 110762306a36Sopenharmony_ci ret = crypto_register_ahash(&dcp_sha256_alg); 110862306a36Sopenharmony_ci if (ret) { 110962306a36Sopenharmony_ci dev_err(dev, "Failed to register %s hash!\n", 111062306a36Sopenharmony_ci dcp_sha256_alg.halg.base.cra_name); 111162306a36Sopenharmony_ci goto err_unregister_sha1; 111262306a36Sopenharmony_ci } 111362306a36Sopenharmony_ci } 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci return 0; 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_cierr_unregister_sha1: 111862306a36Sopenharmony_ci if (sdcp->caps & MXS_DCP_CAPABILITY1_SHA1) 111962306a36Sopenharmony_ci crypto_unregister_ahash(&dcp_sha1_alg); 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_cierr_unregister_aes: 112262306a36Sopenharmony_ci if (sdcp->caps & MXS_DCP_CAPABILITY1_AES128) 112362306a36Sopenharmony_ci crypto_unregister_skciphers(dcp_aes_algs, ARRAY_SIZE(dcp_aes_algs)); 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_cierr_destroy_aes_thread: 112662306a36Sopenharmony_ci kthread_stop(sdcp->thread[DCP_CHAN_CRYPTO]); 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_cierr_destroy_sha_thread: 112962306a36Sopenharmony_ci kthread_stop(sdcp->thread[DCP_CHAN_HASH_SHA]); 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci return ret; 113262306a36Sopenharmony_ci} 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_cistatic int mxs_dcp_remove(struct platform_device *pdev) 113562306a36Sopenharmony_ci{ 113662306a36Sopenharmony_ci struct dcp *sdcp = platform_get_drvdata(pdev); 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci if (sdcp->caps & MXS_DCP_CAPABILITY1_SHA256) 113962306a36Sopenharmony_ci crypto_unregister_ahash(&dcp_sha256_alg); 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci if (sdcp->caps & MXS_DCP_CAPABILITY1_SHA1) 114262306a36Sopenharmony_ci crypto_unregister_ahash(&dcp_sha1_alg); 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci if (sdcp->caps & MXS_DCP_CAPABILITY1_AES128) 114562306a36Sopenharmony_ci crypto_unregister_skciphers(dcp_aes_algs, ARRAY_SIZE(dcp_aes_algs)); 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci kthread_stop(sdcp->thread[DCP_CHAN_HASH_SHA]); 114862306a36Sopenharmony_ci kthread_stop(sdcp->thread[DCP_CHAN_CRYPTO]); 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci platform_set_drvdata(pdev, NULL); 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci global_sdcp = NULL; 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci return 0; 115562306a36Sopenharmony_ci} 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_cistatic const struct of_device_id mxs_dcp_dt_ids[] = { 115862306a36Sopenharmony_ci { .compatible = "fsl,imx23-dcp", .data = NULL, }, 115962306a36Sopenharmony_ci { .compatible = "fsl,imx28-dcp", .data = NULL, }, 116062306a36Sopenharmony_ci { /* sentinel */ } 116162306a36Sopenharmony_ci}; 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, mxs_dcp_dt_ids); 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_cistatic struct platform_driver mxs_dcp_driver = { 116662306a36Sopenharmony_ci .probe = mxs_dcp_probe, 116762306a36Sopenharmony_ci .remove = mxs_dcp_remove, 116862306a36Sopenharmony_ci .driver = { 116962306a36Sopenharmony_ci .name = "mxs-dcp", 117062306a36Sopenharmony_ci .of_match_table = mxs_dcp_dt_ids, 117162306a36Sopenharmony_ci }, 117262306a36Sopenharmony_ci}; 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_cimodule_platform_driver(mxs_dcp_driver); 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ciMODULE_AUTHOR("Marek Vasut <marex@denx.de>"); 117762306a36Sopenharmony_ciMODULE_DESCRIPTION("Freescale MXS DCP Driver"); 117862306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 117962306a36Sopenharmony_ciMODULE_ALIAS("platform:mxs-dcp"); 1180