18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Freescale i.MX23/i.MX28 Data Co-Processor driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2013 Marek Vasut <marex@denx.de> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 98c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 108c2ecf20Sopenharmony_ci#include <linux/io.h> 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/kthread.h> 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <linux/of.h> 158c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 168c2ecf20Sopenharmony_ci#include <linux/stmp_device.h> 178c2ecf20Sopenharmony_ci#include <linux/clk.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <crypto/aes.h> 208c2ecf20Sopenharmony_ci#include <crypto/sha.h> 218c2ecf20Sopenharmony_ci#include <crypto/internal/hash.h> 228c2ecf20Sopenharmony_ci#include <crypto/internal/skcipher.h> 238c2ecf20Sopenharmony_ci#include <crypto/scatterwalk.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define DCP_MAX_CHANS 4 268c2ecf20Sopenharmony_ci#define DCP_BUF_SZ PAGE_SIZE 278c2ecf20Sopenharmony_ci#define DCP_SHA_PAY_SZ 64 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define DCP_ALIGNMENT 64 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/* 328c2ecf20Sopenharmony_ci * Null hashes to align with hw behavior on imx6sl and ull 338c2ecf20Sopenharmony_ci * these are flipped for consistency with hw output 348c2ecf20Sopenharmony_ci */ 358c2ecf20Sopenharmony_cistatic const uint8_t sha1_null_hash[] = 368c2ecf20Sopenharmony_ci "\x09\x07\xd8\xaf\x90\x18\x60\x95\xef\xbf" 378c2ecf20Sopenharmony_ci "\x55\x32\x0d\x4b\x6b\x5e\xee\xa3\x39\xda"; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic const uint8_t sha256_null_hash[] = 408c2ecf20Sopenharmony_ci "\x55\xb8\x52\x78\x1b\x99\x95\xa4" 418c2ecf20Sopenharmony_ci "\x4c\x93\x9b\x64\xe4\x41\xae\x27" 428c2ecf20Sopenharmony_ci "\x24\xb9\x6f\x99\xc8\xf4\xfb\x9a" 438c2ecf20Sopenharmony_ci "\x14\x1c\xfc\x98\x42\xc4\xb0\xe3"; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci/* DCP DMA descriptor. */ 468c2ecf20Sopenharmony_cistruct dcp_dma_desc { 478c2ecf20Sopenharmony_ci uint32_t next_cmd_addr; 488c2ecf20Sopenharmony_ci uint32_t control0; 498c2ecf20Sopenharmony_ci uint32_t control1; 508c2ecf20Sopenharmony_ci uint32_t source; 518c2ecf20Sopenharmony_ci uint32_t destination; 528c2ecf20Sopenharmony_ci uint32_t size; 538c2ecf20Sopenharmony_ci uint32_t payload; 548c2ecf20Sopenharmony_ci uint32_t status; 558c2ecf20Sopenharmony_ci}; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci/* Coherent aligned block for bounce buffering. */ 588c2ecf20Sopenharmony_cistruct dcp_coherent_block { 598c2ecf20Sopenharmony_ci uint8_t aes_in_buf[DCP_BUF_SZ]; 608c2ecf20Sopenharmony_ci uint8_t aes_out_buf[DCP_BUF_SZ]; 618c2ecf20Sopenharmony_ci uint8_t sha_in_buf[DCP_BUF_SZ]; 628c2ecf20Sopenharmony_ci uint8_t sha_out_buf[DCP_SHA_PAY_SZ]; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci uint8_t aes_key[2 * AES_KEYSIZE_128]; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci struct dcp_dma_desc desc[DCP_MAX_CHANS]; 678c2ecf20Sopenharmony_ci}; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistruct dcp { 708c2ecf20Sopenharmony_ci struct device *dev; 718c2ecf20Sopenharmony_ci void __iomem *base; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci uint32_t caps; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci struct dcp_coherent_block *coh; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci struct completion completion[DCP_MAX_CHANS]; 788c2ecf20Sopenharmony_ci spinlock_t lock[DCP_MAX_CHANS]; 798c2ecf20Sopenharmony_ci struct task_struct *thread[DCP_MAX_CHANS]; 808c2ecf20Sopenharmony_ci struct crypto_queue queue[DCP_MAX_CHANS]; 818c2ecf20Sopenharmony_ci struct clk *dcp_clk; 828c2ecf20Sopenharmony_ci}; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cienum dcp_chan { 858c2ecf20Sopenharmony_ci DCP_CHAN_HASH_SHA = 0, 868c2ecf20Sopenharmony_ci DCP_CHAN_CRYPTO = 2, 878c2ecf20Sopenharmony_ci}; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistruct dcp_async_ctx { 908c2ecf20Sopenharmony_ci /* Common context */ 918c2ecf20Sopenharmony_ci enum dcp_chan chan; 928c2ecf20Sopenharmony_ci uint32_t fill; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci /* SHA Hash-specific context */ 958c2ecf20Sopenharmony_ci struct mutex mutex; 968c2ecf20Sopenharmony_ci uint32_t alg; 978c2ecf20Sopenharmony_ci unsigned int hot:1; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci /* Crypto-specific context */ 1008c2ecf20Sopenharmony_ci struct crypto_skcipher *fallback; 1018c2ecf20Sopenharmony_ci unsigned int key_len; 1028c2ecf20Sopenharmony_ci uint8_t key[AES_KEYSIZE_128]; 1038c2ecf20Sopenharmony_ci}; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistruct dcp_aes_req_ctx { 1068c2ecf20Sopenharmony_ci unsigned int enc:1; 1078c2ecf20Sopenharmony_ci unsigned int ecb:1; 1088c2ecf20Sopenharmony_ci struct skcipher_request fallback_req; // keep at the end 1098c2ecf20Sopenharmony_ci}; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistruct dcp_sha_req_ctx { 1128c2ecf20Sopenharmony_ci unsigned int init:1; 1138c2ecf20Sopenharmony_ci unsigned int fini:1; 1148c2ecf20Sopenharmony_ci}; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistruct dcp_export_state { 1178c2ecf20Sopenharmony_ci struct dcp_sha_req_ctx req_ctx; 1188c2ecf20Sopenharmony_ci struct dcp_async_ctx async_ctx; 1198c2ecf20Sopenharmony_ci}; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci/* 1228c2ecf20Sopenharmony_ci * There can even be only one instance of the MXS DCP due to the 1238c2ecf20Sopenharmony_ci * design of Linux Crypto API. 1248c2ecf20Sopenharmony_ci */ 1258c2ecf20Sopenharmony_cistatic struct dcp *global_sdcp; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci/* DCP register layout. */ 1288c2ecf20Sopenharmony_ci#define MXS_DCP_CTRL 0x00 1298c2ecf20Sopenharmony_ci#define MXS_DCP_CTRL_GATHER_RESIDUAL_WRITES (1 << 23) 1308c2ecf20Sopenharmony_ci#define MXS_DCP_CTRL_ENABLE_CONTEXT_CACHING (1 << 22) 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci#define MXS_DCP_STAT 0x10 1338c2ecf20Sopenharmony_ci#define MXS_DCP_STAT_CLR 0x18 1348c2ecf20Sopenharmony_ci#define MXS_DCP_STAT_IRQ_MASK 0xf 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci#define MXS_DCP_CHANNELCTRL 0x20 1378c2ecf20Sopenharmony_ci#define MXS_DCP_CHANNELCTRL_ENABLE_CHANNEL_MASK 0xff 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci#define MXS_DCP_CAPABILITY1 0x40 1408c2ecf20Sopenharmony_ci#define MXS_DCP_CAPABILITY1_SHA256 (4 << 16) 1418c2ecf20Sopenharmony_ci#define MXS_DCP_CAPABILITY1_SHA1 (1 << 16) 1428c2ecf20Sopenharmony_ci#define MXS_DCP_CAPABILITY1_AES128 (1 << 0) 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci#define MXS_DCP_CONTEXT 0x50 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci#define MXS_DCP_CH_N_CMDPTR(n) (0x100 + ((n) * 0x40)) 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci#define MXS_DCP_CH_N_SEMA(n) (0x110 + ((n) * 0x40)) 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci#define MXS_DCP_CH_N_STAT(n) (0x120 + ((n) * 0x40)) 1518c2ecf20Sopenharmony_ci#define MXS_DCP_CH_N_STAT_CLR(n) (0x128 + ((n) * 0x40)) 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci/* DMA descriptor bits. */ 1548c2ecf20Sopenharmony_ci#define MXS_DCP_CONTROL0_HASH_TERM (1 << 13) 1558c2ecf20Sopenharmony_ci#define MXS_DCP_CONTROL0_HASH_INIT (1 << 12) 1568c2ecf20Sopenharmony_ci#define MXS_DCP_CONTROL0_PAYLOAD_KEY (1 << 11) 1578c2ecf20Sopenharmony_ci#define MXS_DCP_CONTROL0_CIPHER_ENCRYPT (1 << 8) 1588c2ecf20Sopenharmony_ci#define MXS_DCP_CONTROL0_CIPHER_INIT (1 << 9) 1598c2ecf20Sopenharmony_ci#define MXS_DCP_CONTROL0_ENABLE_HASH (1 << 6) 1608c2ecf20Sopenharmony_ci#define MXS_DCP_CONTROL0_ENABLE_CIPHER (1 << 5) 1618c2ecf20Sopenharmony_ci#define MXS_DCP_CONTROL0_DECR_SEMAPHORE (1 << 1) 1628c2ecf20Sopenharmony_ci#define MXS_DCP_CONTROL0_INTERRUPT (1 << 0) 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci#define MXS_DCP_CONTROL1_HASH_SELECT_SHA256 (2 << 16) 1658c2ecf20Sopenharmony_ci#define MXS_DCP_CONTROL1_HASH_SELECT_SHA1 (0 << 16) 1668c2ecf20Sopenharmony_ci#define MXS_DCP_CONTROL1_CIPHER_MODE_CBC (1 << 4) 1678c2ecf20Sopenharmony_ci#define MXS_DCP_CONTROL1_CIPHER_MODE_ECB (0 << 4) 1688c2ecf20Sopenharmony_ci#define MXS_DCP_CONTROL1_CIPHER_SELECT_AES128 (0 << 0) 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic int mxs_dcp_start_dma(struct dcp_async_ctx *actx) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci int dma_err; 1738c2ecf20Sopenharmony_ci struct dcp *sdcp = global_sdcp; 1748c2ecf20Sopenharmony_ci const int chan = actx->chan; 1758c2ecf20Sopenharmony_ci uint32_t stat; 1768c2ecf20Sopenharmony_ci unsigned long ret; 1778c2ecf20Sopenharmony_ci struct dcp_dma_desc *desc = &sdcp->coh->desc[actx->chan]; 1788c2ecf20Sopenharmony_ci dma_addr_t desc_phys = dma_map_single(sdcp->dev, desc, sizeof(*desc), 1798c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci dma_err = dma_mapping_error(sdcp->dev, desc_phys); 1828c2ecf20Sopenharmony_ci if (dma_err) 1838c2ecf20Sopenharmony_ci return dma_err; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci reinit_completion(&sdcp->completion[chan]); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci /* Clear status register. */ 1888c2ecf20Sopenharmony_ci writel(0xffffffff, sdcp->base + MXS_DCP_CH_N_STAT_CLR(chan)); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci /* Load the DMA descriptor. */ 1918c2ecf20Sopenharmony_ci writel(desc_phys, sdcp->base + MXS_DCP_CH_N_CMDPTR(chan)); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci /* Increment the semaphore to start the DMA transfer. */ 1948c2ecf20Sopenharmony_ci writel(1, sdcp->base + MXS_DCP_CH_N_SEMA(chan)); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci ret = wait_for_completion_timeout(&sdcp->completion[chan], 1978c2ecf20Sopenharmony_ci msecs_to_jiffies(1000)); 1988c2ecf20Sopenharmony_ci if (!ret) { 1998c2ecf20Sopenharmony_ci dev_err(sdcp->dev, "Channel %i timeout (DCP_STAT=0x%08x)\n", 2008c2ecf20Sopenharmony_ci chan, readl(sdcp->base + MXS_DCP_STAT)); 2018c2ecf20Sopenharmony_ci return -ETIMEDOUT; 2028c2ecf20Sopenharmony_ci } 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci stat = readl(sdcp->base + MXS_DCP_CH_N_STAT(chan)); 2058c2ecf20Sopenharmony_ci if (stat & 0xff) { 2068c2ecf20Sopenharmony_ci dev_err(sdcp->dev, "Channel %i error (CH_STAT=0x%08x)\n", 2078c2ecf20Sopenharmony_ci chan, stat); 2088c2ecf20Sopenharmony_ci return -EINVAL; 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci dma_unmap_single(sdcp->dev, desc_phys, sizeof(*desc), DMA_TO_DEVICE); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci return 0; 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci/* 2178c2ecf20Sopenharmony_ci * Encryption (AES128) 2188c2ecf20Sopenharmony_ci */ 2198c2ecf20Sopenharmony_cistatic int mxs_dcp_run_aes(struct dcp_async_ctx *actx, 2208c2ecf20Sopenharmony_ci struct skcipher_request *req, int init) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci dma_addr_t key_phys, src_phys, dst_phys; 2238c2ecf20Sopenharmony_ci struct dcp *sdcp = global_sdcp; 2248c2ecf20Sopenharmony_ci struct dcp_dma_desc *desc = &sdcp->coh->desc[actx->chan]; 2258c2ecf20Sopenharmony_ci struct dcp_aes_req_ctx *rctx = skcipher_request_ctx(req); 2268c2ecf20Sopenharmony_ci int ret; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci key_phys = dma_map_single(sdcp->dev, sdcp->coh->aes_key, 2298c2ecf20Sopenharmony_ci 2 * AES_KEYSIZE_128, DMA_TO_DEVICE); 2308c2ecf20Sopenharmony_ci ret = dma_mapping_error(sdcp->dev, key_phys); 2318c2ecf20Sopenharmony_ci if (ret) 2328c2ecf20Sopenharmony_ci return ret; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci src_phys = dma_map_single(sdcp->dev, sdcp->coh->aes_in_buf, 2358c2ecf20Sopenharmony_ci DCP_BUF_SZ, DMA_TO_DEVICE); 2368c2ecf20Sopenharmony_ci ret = dma_mapping_error(sdcp->dev, src_phys); 2378c2ecf20Sopenharmony_ci if (ret) 2388c2ecf20Sopenharmony_ci goto err_src; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci dst_phys = dma_map_single(sdcp->dev, sdcp->coh->aes_out_buf, 2418c2ecf20Sopenharmony_ci DCP_BUF_SZ, DMA_FROM_DEVICE); 2428c2ecf20Sopenharmony_ci ret = dma_mapping_error(sdcp->dev, dst_phys); 2438c2ecf20Sopenharmony_ci if (ret) 2448c2ecf20Sopenharmony_ci goto err_dst; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci if (actx->fill % AES_BLOCK_SIZE) { 2478c2ecf20Sopenharmony_ci dev_err(sdcp->dev, "Invalid block size!\n"); 2488c2ecf20Sopenharmony_ci ret = -EINVAL; 2498c2ecf20Sopenharmony_ci goto aes_done_run; 2508c2ecf20Sopenharmony_ci } 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci /* Fill in the DMA descriptor. */ 2538c2ecf20Sopenharmony_ci desc->control0 = MXS_DCP_CONTROL0_DECR_SEMAPHORE | 2548c2ecf20Sopenharmony_ci MXS_DCP_CONTROL0_INTERRUPT | 2558c2ecf20Sopenharmony_ci MXS_DCP_CONTROL0_ENABLE_CIPHER; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci /* Payload contains the key. */ 2588c2ecf20Sopenharmony_ci desc->control0 |= MXS_DCP_CONTROL0_PAYLOAD_KEY; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci if (rctx->enc) 2618c2ecf20Sopenharmony_ci desc->control0 |= MXS_DCP_CONTROL0_CIPHER_ENCRYPT; 2628c2ecf20Sopenharmony_ci if (init) 2638c2ecf20Sopenharmony_ci desc->control0 |= MXS_DCP_CONTROL0_CIPHER_INIT; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci desc->control1 = MXS_DCP_CONTROL1_CIPHER_SELECT_AES128; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci if (rctx->ecb) 2688c2ecf20Sopenharmony_ci desc->control1 |= MXS_DCP_CONTROL1_CIPHER_MODE_ECB; 2698c2ecf20Sopenharmony_ci else 2708c2ecf20Sopenharmony_ci desc->control1 |= MXS_DCP_CONTROL1_CIPHER_MODE_CBC; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci desc->next_cmd_addr = 0; 2738c2ecf20Sopenharmony_ci desc->source = src_phys; 2748c2ecf20Sopenharmony_ci desc->destination = dst_phys; 2758c2ecf20Sopenharmony_ci desc->size = actx->fill; 2768c2ecf20Sopenharmony_ci desc->payload = key_phys; 2778c2ecf20Sopenharmony_ci desc->status = 0; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci ret = mxs_dcp_start_dma(actx); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ciaes_done_run: 2828c2ecf20Sopenharmony_ci dma_unmap_single(sdcp->dev, dst_phys, DCP_BUF_SZ, DMA_FROM_DEVICE); 2838c2ecf20Sopenharmony_cierr_dst: 2848c2ecf20Sopenharmony_ci dma_unmap_single(sdcp->dev, src_phys, DCP_BUF_SZ, DMA_TO_DEVICE); 2858c2ecf20Sopenharmony_cierr_src: 2868c2ecf20Sopenharmony_ci dma_unmap_single(sdcp->dev, key_phys, 2 * AES_KEYSIZE_128, 2878c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci return ret; 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_cistatic int mxs_dcp_aes_block_crypt(struct crypto_async_request *arq) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci struct dcp *sdcp = global_sdcp; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci struct skcipher_request *req = skcipher_request_cast(arq); 2978c2ecf20Sopenharmony_ci struct dcp_async_ctx *actx = crypto_tfm_ctx(arq->tfm); 2988c2ecf20Sopenharmony_ci struct dcp_aes_req_ctx *rctx = skcipher_request_ctx(req); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci struct scatterlist *dst = req->dst; 3018c2ecf20Sopenharmony_ci struct scatterlist *src = req->src; 3028c2ecf20Sopenharmony_ci int dst_nents = sg_nents(dst); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci const int out_off = DCP_BUF_SZ; 3058c2ecf20Sopenharmony_ci uint8_t *in_buf = sdcp->coh->aes_in_buf; 3068c2ecf20Sopenharmony_ci uint8_t *out_buf = sdcp->coh->aes_out_buf; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci uint32_t dst_off = 0; 3098c2ecf20Sopenharmony_ci uint8_t *src_buf = NULL; 3108c2ecf20Sopenharmony_ci uint32_t last_out_len = 0; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci uint8_t *key = sdcp->coh->aes_key; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci int ret = 0; 3158c2ecf20Sopenharmony_ci unsigned int i, len, clen, tlen = 0; 3168c2ecf20Sopenharmony_ci int init = 0; 3178c2ecf20Sopenharmony_ci bool limit_hit = false; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci actx->fill = 0; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci /* Copy the key from the temporary location. */ 3228c2ecf20Sopenharmony_ci memcpy(key, actx->key, actx->key_len); 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci if (!rctx->ecb) { 3258c2ecf20Sopenharmony_ci /* Copy the CBC IV just past the key. */ 3268c2ecf20Sopenharmony_ci memcpy(key + AES_KEYSIZE_128, req->iv, AES_KEYSIZE_128); 3278c2ecf20Sopenharmony_ci /* CBC needs the INIT set. */ 3288c2ecf20Sopenharmony_ci init = 1; 3298c2ecf20Sopenharmony_ci } else { 3308c2ecf20Sopenharmony_ci memset(key + AES_KEYSIZE_128, 0, AES_KEYSIZE_128); 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci for_each_sg(req->src, src, sg_nents(req->src), i) { 3348c2ecf20Sopenharmony_ci src_buf = sg_virt(src); 3358c2ecf20Sopenharmony_ci len = sg_dma_len(src); 3368c2ecf20Sopenharmony_ci tlen += len; 3378c2ecf20Sopenharmony_ci limit_hit = tlen > req->cryptlen; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci if (limit_hit) 3408c2ecf20Sopenharmony_ci len = req->cryptlen - (tlen - len); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci do { 3438c2ecf20Sopenharmony_ci if (actx->fill + len > out_off) 3448c2ecf20Sopenharmony_ci clen = out_off - actx->fill; 3458c2ecf20Sopenharmony_ci else 3468c2ecf20Sopenharmony_ci clen = len; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci memcpy(in_buf + actx->fill, src_buf, clen); 3498c2ecf20Sopenharmony_ci len -= clen; 3508c2ecf20Sopenharmony_ci src_buf += clen; 3518c2ecf20Sopenharmony_ci actx->fill += clen; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci /* 3548c2ecf20Sopenharmony_ci * If we filled the buffer or this is the last SG, 3558c2ecf20Sopenharmony_ci * submit the buffer. 3568c2ecf20Sopenharmony_ci */ 3578c2ecf20Sopenharmony_ci if (actx->fill == out_off || sg_is_last(src) || 3588c2ecf20Sopenharmony_ci limit_hit) { 3598c2ecf20Sopenharmony_ci ret = mxs_dcp_run_aes(actx, req, init); 3608c2ecf20Sopenharmony_ci if (ret) 3618c2ecf20Sopenharmony_ci return ret; 3628c2ecf20Sopenharmony_ci init = 0; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci sg_pcopy_from_buffer(dst, dst_nents, out_buf, 3658c2ecf20Sopenharmony_ci actx->fill, dst_off); 3668c2ecf20Sopenharmony_ci dst_off += actx->fill; 3678c2ecf20Sopenharmony_ci last_out_len = actx->fill; 3688c2ecf20Sopenharmony_ci actx->fill = 0; 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci } while (len); 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci if (limit_hit) 3738c2ecf20Sopenharmony_ci break; 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci /* Copy the IV for CBC for chaining */ 3778c2ecf20Sopenharmony_ci if (!rctx->ecb) { 3788c2ecf20Sopenharmony_ci if (rctx->enc) 3798c2ecf20Sopenharmony_ci memcpy(req->iv, out_buf+(last_out_len-AES_BLOCK_SIZE), 3808c2ecf20Sopenharmony_ci AES_BLOCK_SIZE); 3818c2ecf20Sopenharmony_ci else 3828c2ecf20Sopenharmony_ci memcpy(req->iv, in_buf+(last_out_len-AES_BLOCK_SIZE), 3838c2ecf20Sopenharmony_ci AES_BLOCK_SIZE); 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci return ret; 3878c2ecf20Sopenharmony_ci} 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_cistatic int dcp_chan_thread_aes(void *data) 3908c2ecf20Sopenharmony_ci{ 3918c2ecf20Sopenharmony_ci struct dcp *sdcp = global_sdcp; 3928c2ecf20Sopenharmony_ci const int chan = DCP_CHAN_CRYPTO; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci struct crypto_async_request *backlog; 3958c2ecf20Sopenharmony_ci struct crypto_async_request *arq; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci int ret; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci while (!kthread_should_stop()) { 4008c2ecf20Sopenharmony_ci set_current_state(TASK_INTERRUPTIBLE); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci spin_lock(&sdcp->lock[chan]); 4038c2ecf20Sopenharmony_ci backlog = crypto_get_backlog(&sdcp->queue[chan]); 4048c2ecf20Sopenharmony_ci arq = crypto_dequeue_request(&sdcp->queue[chan]); 4058c2ecf20Sopenharmony_ci spin_unlock(&sdcp->lock[chan]); 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci if (!backlog && !arq) { 4088c2ecf20Sopenharmony_ci schedule(); 4098c2ecf20Sopenharmony_ci continue; 4108c2ecf20Sopenharmony_ci } 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci set_current_state(TASK_RUNNING); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci if (backlog) 4158c2ecf20Sopenharmony_ci backlog->complete(backlog, -EINPROGRESS); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci if (arq) { 4188c2ecf20Sopenharmony_ci ret = mxs_dcp_aes_block_crypt(arq); 4198c2ecf20Sopenharmony_ci arq->complete(arq, ret); 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci return 0; 4248c2ecf20Sopenharmony_ci} 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_cistatic int mxs_dcp_block_fallback(struct skcipher_request *req, int enc) 4278c2ecf20Sopenharmony_ci{ 4288c2ecf20Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 4298c2ecf20Sopenharmony_ci struct dcp_aes_req_ctx *rctx = skcipher_request_ctx(req); 4308c2ecf20Sopenharmony_ci struct dcp_async_ctx *ctx = crypto_skcipher_ctx(tfm); 4318c2ecf20Sopenharmony_ci int ret; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci skcipher_request_set_tfm(&rctx->fallback_req, ctx->fallback); 4348c2ecf20Sopenharmony_ci skcipher_request_set_callback(&rctx->fallback_req, req->base.flags, 4358c2ecf20Sopenharmony_ci req->base.complete, req->base.data); 4368c2ecf20Sopenharmony_ci skcipher_request_set_crypt(&rctx->fallback_req, req->src, req->dst, 4378c2ecf20Sopenharmony_ci req->cryptlen, req->iv); 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci if (enc) 4408c2ecf20Sopenharmony_ci ret = crypto_skcipher_encrypt(&rctx->fallback_req); 4418c2ecf20Sopenharmony_ci else 4428c2ecf20Sopenharmony_ci ret = crypto_skcipher_decrypt(&rctx->fallback_req); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci return ret; 4458c2ecf20Sopenharmony_ci} 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_cistatic int mxs_dcp_aes_enqueue(struct skcipher_request *req, int enc, int ecb) 4488c2ecf20Sopenharmony_ci{ 4498c2ecf20Sopenharmony_ci struct dcp *sdcp = global_sdcp; 4508c2ecf20Sopenharmony_ci struct crypto_async_request *arq = &req->base; 4518c2ecf20Sopenharmony_ci struct dcp_async_ctx *actx = crypto_tfm_ctx(arq->tfm); 4528c2ecf20Sopenharmony_ci struct dcp_aes_req_ctx *rctx = skcipher_request_ctx(req); 4538c2ecf20Sopenharmony_ci int ret; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci if (unlikely(actx->key_len != AES_KEYSIZE_128)) 4568c2ecf20Sopenharmony_ci return mxs_dcp_block_fallback(req, enc); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci rctx->enc = enc; 4598c2ecf20Sopenharmony_ci rctx->ecb = ecb; 4608c2ecf20Sopenharmony_ci actx->chan = DCP_CHAN_CRYPTO; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci spin_lock(&sdcp->lock[actx->chan]); 4638c2ecf20Sopenharmony_ci ret = crypto_enqueue_request(&sdcp->queue[actx->chan], &req->base); 4648c2ecf20Sopenharmony_ci spin_unlock(&sdcp->lock[actx->chan]); 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci wake_up_process(sdcp->thread[actx->chan]); 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci return ret; 4698c2ecf20Sopenharmony_ci} 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_cistatic int mxs_dcp_aes_ecb_decrypt(struct skcipher_request *req) 4728c2ecf20Sopenharmony_ci{ 4738c2ecf20Sopenharmony_ci return mxs_dcp_aes_enqueue(req, 0, 1); 4748c2ecf20Sopenharmony_ci} 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_cistatic int mxs_dcp_aes_ecb_encrypt(struct skcipher_request *req) 4778c2ecf20Sopenharmony_ci{ 4788c2ecf20Sopenharmony_ci return mxs_dcp_aes_enqueue(req, 1, 1); 4798c2ecf20Sopenharmony_ci} 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_cistatic int mxs_dcp_aes_cbc_decrypt(struct skcipher_request *req) 4828c2ecf20Sopenharmony_ci{ 4838c2ecf20Sopenharmony_ci return mxs_dcp_aes_enqueue(req, 0, 0); 4848c2ecf20Sopenharmony_ci} 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_cistatic int mxs_dcp_aes_cbc_encrypt(struct skcipher_request *req) 4878c2ecf20Sopenharmony_ci{ 4888c2ecf20Sopenharmony_ci return mxs_dcp_aes_enqueue(req, 1, 0); 4898c2ecf20Sopenharmony_ci} 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_cistatic int mxs_dcp_aes_setkey(struct crypto_skcipher *tfm, const u8 *key, 4928c2ecf20Sopenharmony_ci unsigned int len) 4938c2ecf20Sopenharmony_ci{ 4948c2ecf20Sopenharmony_ci struct dcp_async_ctx *actx = crypto_skcipher_ctx(tfm); 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci /* 4978c2ecf20Sopenharmony_ci * AES 128 is supposed by the hardware, store key into temporary 4988c2ecf20Sopenharmony_ci * buffer and exit. We must use the temporary buffer here, since 4998c2ecf20Sopenharmony_ci * there can still be an operation in progress. 5008c2ecf20Sopenharmony_ci */ 5018c2ecf20Sopenharmony_ci actx->key_len = len; 5028c2ecf20Sopenharmony_ci if (len == AES_KEYSIZE_128) { 5038c2ecf20Sopenharmony_ci memcpy(actx->key, key, len); 5048c2ecf20Sopenharmony_ci return 0; 5058c2ecf20Sopenharmony_ci } 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci /* 5088c2ecf20Sopenharmony_ci * If the requested AES key size is not supported by the hardware, 5098c2ecf20Sopenharmony_ci * but is supported by in-kernel software implementation, we use 5108c2ecf20Sopenharmony_ci * software fallback. 5118c2ecf20Sopenharmony_ci */ 5128c2ecf20Sopenharmony_ci crypto_skcipher_clear_flags(actx->fallback, CRYPTO_TFM_REQ_MASK); 5138c2ecf20Sopenharmony_ci crypto_skcipher_set_flags(actx->fallback, 5148c2ecf20Sopenharmony_ci tfm->base.crt_flags & CRYPTO_TFM_REQ_MASK); 5158c2ecf20Sopenharmony_ci return crypto_skcipher_setkey(actx->fallback, key, len); 5168c2ecf20Sopenharmony_ci} 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_cistatic int mxs_dcp_aes_fallback_init_tfm(struct crypto_skcipher *tfm) 5198c2ecf20Sopenharmony_ci{ 5208c2ecf20Sopenharmony_ci const char *name = crypto_tfm_alg_name(crypto_skcipher_tfm(tfm)); 5218c2ecf20Sopenharmony_ci struct dcp_async_ctx *actx = crypto_skcipher_ctx(tfm); 5228c2ecf20Sopenharmony_ci struct crypto_skcipher *blk; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci blk = crypto_alloc_skcipher(name, 0, CRYPTO_ALG_NEED_FALLBACK); 5258c2ecf20Sopenharmony_ci if (IS_ERR(blk)) 5268c2ecf20Sopenharmony_ci return PTR_ERR(blk); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci actx->fallback = blk; 5298c2ecf20Sopenharmony_ci crypto_skcipher_set_reqsize(tfm, sizeof(struct dcp_aes_req_ctx) + 5308c2ecf20Sopenharmony_ci crypto_skcipher_reqsize(blk)); 5318c2ecf20Sopenharmony_ci return 0; 5328c2ecf20Sopenharmony_ci} 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_cistatic void mxs_dcp_aes_fallback_exit_tfm(struct crypto_skcipher *tfm) 5358c2ecf20Sopenharmony_ci{ 5368c2ecf20Sopenharmony_ci struct dcp_async_ctx *actx = crypto_skcipher_ctx(tfm); 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci crypto_free_skcipher(actx->fallback); 5398c2ecf20Sopenharmony_ci} 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci/* 5428c2ecf20Sopenharmony_ci * Hashing (SHA1/SHA256) 5438c2ecf20Sopenharmony_ci */ 5448c2ecf20Sopenharmony_cistatic int mxs_dcp_run_sha(struct ahash_request *req) 5458c2ecf20Sopenharmony_ci{ 5468c2ecf20Sopenharmony_ci struct dcp *sdcp = global_sdcp; 5478c2ecf20Sopenharmony_ci int ret; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 5508c2ecf20Sopenharmony_ci struct dcp_async_ctx *actx = crypto_ahash_ctx(tfm); 5518c2ecf20Sopenharmony_ci struct dcp_sha_req_ctx *rctx = ahash_request_ctx(req); 5528c2ecf20Sopenharmony_ci struct dcp_dma_desc *desc = &sdcp->coh->desc[actx->chan]; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci dma_addr_t digest_phys = 0; 5558c2ecf20Sopenharmony_ci dma_addr_t buf_phys = dma_map_single(sdcp->dev, sdcp->coh->sha_in_buf, 5568c2ecf20Sopenharmony_ci DCP_BUF_SZ, DMA_TO_DEVICE); 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci ret = dma_mapping_error(sdcp->dev, buf_phys); 5598c2ecf20Sopenharmony_ci if (ret) 5608c2ecf20Sopenharmony_ci return ret; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci /* Fill in the DMA descriptor. */ 5638c2ecf20Sopenharmony_ci desc->control0 = MXS_DCP_CONTROL0_DECR_SEMAPHORE | 5648c2ecf20Sopenharmony_ci MXS_DCP_CONTROL0_INTERRUPT | 5658c2ecf20Sopenharmony_ci MXS_DCP_CONTROL0_ENABLE_HASH; 5668c2ecf20Sopenharmony_ci if (rctx->init) 5678c2ecf20Sopenharmony_ci desc->control0 |= MXS_DCP_CONTROL0_HASH_INIT; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci desc->control1 = actx->alg; 5708c2ecf20Sopenharmony_ci desc->next_cmd_addr = 0; 5718c2ecf20Sopenharmony_ci desc->source = buf_phys; 5728c2ecf20Sopenharmony_ci desc->destination = 0; 5738c2ecf20Sopenharmony_ci desc->size = actx->fill; 5748c2ecf20Sopenharmony_ci desc->payload = 0; 5758c2ecf20Sopenharmony_ci desc->status = 0; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci /* 5788c2ecf20Sopenharmony_ci * Align driver with hw behavior when generating null hashes 5798c2ecf20Sopenharmony_ci */ 5808c2ecf20Sopenharmony_ci if (rctx->init && rctx->fini && desc->size == 0) { 5818c2ecf20Sopenharmony_ci struct hash_alg_common *halg = crypto_hash_alg_common(tfm); 5828c2ecf20Sopenharmony_ci const uint8_t *sha_buf = 5838c2ecf20Sopenharmony_ci (actx->alg == MXS_DCP_CONTROL1_HASH_SELECT_SHA1) ? 5848c2ecf20Sopenharmony_ci sha1_null_hash : sha256_null_hash; 5858c2ecf20Sopenharmony_ci memcpy(sdcp->coh->sha_out_buf, sha_buf, halg->digestsize); 5868c2ecf20Sopenharmony_ci ret = 0; 5878c2ecf20Sopenharmony_ci goto done_run; 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci /* Set HASH_TERM bit for last transfer block. */ 5918c2ecf20Sopenharmony_ci if (rctx->fini) { 5928c2ecf20Sopenharmony_ci digest_phys = dma_map_single(sdcp->dev, sdcp->coh->sha_out_buf, 5938c2ecf20Sopenharmony_ci DCP_SHA_PAY_SZ, DMA_FROM_DEVICE); 5948c2ecf20Sopenharmony_ci ret = dma_mapping_error(sdcp->dev, digest_phys); 5958c2ecf20Sopenharmony_ci if (ret) 5968c2ecf20Sopenharmony_ci goto done_run; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci desc->control0 |= MXS_DCP_CONTROL0_HASH_TERM; 5998c2ecf20Sopenharmony_ci desc->payload = digest_phys; 6008c2ecf20Sopenharmony_ci } 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci ret = mxs_dcp_start_dma(actx); 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci if (rctx->fini) 6058c2ecf20Sopenharmony_ci dma_unmap_single(sdcp->dev, digest_phys, DCP_SHA_PAY_SZ, 6068c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_cidone_run: 6098c2ecf20Sopenharmony_ci dma_unmap_single(sdcp->dev, buf_phys, DCP_BUF_SZ, DMA_TO_DEVICE); 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci return ret; 6128c2ecf20Sopenharmony_ci} 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_cistatic int dcp_sha_req_to_buf(struct crypto_async_request *arq) 6158c2ecf20Sopenharmony_ci{ 6168c2ecf20Sopenharmony_ci struct dcp *sdcp = global_sdcp; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci struct ahash_request *req = ahash_request_cast(arq); 6198c2ecf20Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 6208c2ecf20Sopenharmony_ci struct dcp_async_ctx *actx = crypto_ahash_ctx(tfm); 6218c2ecf20Sopenharmony_ci struct dcp_sha_req_ctx *rctx = ahash_request_ctx(req); 6228c2ecf20Sopenharmony_ci struct hash_alg_common *halg = crypto_hash_alg_common(tfm); 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci uint8_t *in_buf = sdcp->coh->sha_in_buf; 6258c2ecf20Sopenharmony_ci uint8_t *out_buf = sdcp->coh->sha_out_buf; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci struct scatterlist *src; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci unsigned int i, len, clen, oft = 0; 6308c2ecf20Sopenharmony_ci int ret; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci int fin = rctx->fini; 6338c2ecf20Sopenharmony_ci if (fin) 6348c2ecf20Sopenharmony_ci rctx->fini = 0; 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci src = req->src; 6378c2ecf20Sopenharmony_ci len = req->nbytes; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci while (len) { 6408c2ecf20Sopenharmony_ci if (actx->fill + len > DCP_BUF_SZ) 6418c2ecf20Sopenharmony_ci clen = DCP_BUF_SZ - actx->fill; 6428c2ecf20Sopenharmony_ci else 6438c2ecf20Sopenharmony_ci clen = len; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci scatterwalk_map_and_copy(in_buf + actx->fill, src, oft, clen, 6468c2ecf20Sopenharmony_ci 0); 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci len -= clen; 6498c2ecf20Sopenharmony_ci oft += clen; 6508c2ecf20Sopenharmony_ci actx->fill += clen; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci /* 6538c2ecf20Sopenharmony_ci * If we filled the buffer and still have some 6548c2ecf20Sopenharmony_ci * more data, submit the buffer. 6558c2ecf20Sopenharmony_ci */ 6568c2ecf20Sopenharmony_ci if (len && actx->fill == DCP_BUF_SZ) { 6578c2ecf20Sopenharmony_ci ret = mxs_dcp_run_sha(req); 6588c2ecf20Sopenharmony_ci if (ret) 6598c2ecf20Sopenharmony_ci return ret; 6608c2ecf20Sopenharmony_ci actx->fill = 0; 6618c2ecf20Sopenharmony_ci rctx->init = 0; 6628c2ecf20Sopenharmony_ci } 6638c2ecf20Sopenharmony_ci } 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci if (fin) { 6668c2ecf20Sopenharmony_ci rctx->fini = 1; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci /* Submit whatever is left. */ 6698c2ecf20Sopenharmony_ci if (!req->result) 6708c2ecf20Sopenharmony_ci return -EINVAL; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci ret = mxs_dcp_run_sha(req); 6738c2ecf20Sopenharmony_ci if (ret) 6748c2ecf20Sopenharmony_ci return ret; 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci actx->fill = 0; 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci /* For some reason the result is flipped */ 6798c2ecf20Sopenharmony_ci for (i = 0; i < halg->digestsize; i++) 6808c2ecf20Sopenharmony_ci req->result[i] = out_buf[halg->digestsize - i - 1]; 6818c2ecf20Sopenharmony_ci } 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci return 0; 6848c2ecf20Sopenharmony_ci} 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_cistatic int dcp_chan_thread_sha(void *data) 6878c2ecf20Sopenharmony_ci{ 6888c2ecf20Sopenharmony_ci struct dcp *sdcp = global_sdcp; 6898c2ecf20Sopenharmony_ci const int chan = DCP_CHAN_HASH_SHA; 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci struct crypto_async_request *backlog; 6928c2ecf20Sopenharmony_ci struct crypto_async_request *arq; 6938c2ecf20Sopenharmony_ci int ret; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci while (!kthread_should_stop()) { 6968c2ecf20Sopenharmony_ci set_current_state(TASK_INTERRUPTIBLE); 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci spin_lock(&sdcp->lock[chan]); 6998c2ecf20Sopenharmony_ci backlog = crypto_get_backlog(&sdcp->queue[chan]); 7008c2ecf20Sopenharmony_ci arq = crypto_dequeue_request(&sdcp->queue[chan]); 7018c2ecf20Sopenharmony_ci spin_unlock(&sdcp->lock[chan]); 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci if (!backlog && !arq) { 7048c2ecf20Sopenharmony_ci schedule(); 7058c2ecf20Sopenharmony_ci continue; 7068c2ecf20Sopenharmony_ci } 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci set_current_state(TASK_RUNNING); 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci if (backlog) 7118c2ecf20Sopenharmony_ci backlog->complete(backlog, -EINPROGRESS); 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci if (arq) { 7148c2ecf20Sopenharmony_ci ret = dcp_sha_req_to_buf(arq); 7158c2ecf20Sopenharmony_ci arq->complete(arq, ret); 7168c2ecf20Sopenharmony_ci } 7178c2ecf20Sopenharmony_ci } 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci return 0; 7208c2ecf20Sopenharmony_ci} 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_cistatic int dcp_sha_init(struct ahash_request *req) 7238c2ecf20Sopenharmony_ci{ 7248c2ecf20Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 7258c2ecf20Sopenharmony_ci struct dcp_async_ctx *actx = crypto_ahash_ctx(tfm); 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci struct hash_alg_common *halg = crypto_hash_alg_common(tfm); 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci /* 7308c2ecf20Sopenharmony_ci * Start hashing session. The code below only inits the 7318c2ecf20Sopenharmony_ci * hashing session context, nothing more. 7328c2ecf20Sopenharmony_ci */ 7338c2ecf20Sopenharmony_ci memset(actx, 0, sizeof(*actx)); 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci if (strcmp(halg->base.cra_name, "sha1") == 0) 7368c2ecf20Sopenharmony_ci actx->alg = MXS_DCP_CONTROL1_HASH_SELECT_SHA1; 7378c2ecf20Sopenharmony_ci else 7388c2ecf20Sopenharmony_ci actx->alg = MXS_DCP_CONTROL1_HASH_SELECT_SHA256; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci actx->fill = 0; 7418c2ecf20Sopenharmony_ci actx->hot = 0; 7428c2ecf20Sopenharmony_ci actx->chan = DCP_CHAN_HASH_SHA; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci mutex_init(&actx->mutex); 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci return 0; 7478c2ecf20Sopenharmony_ci} 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_cistatic int dcp_sha_update_fx(struct ahash_request *req, int fini) 7508c2ecf20Sopenharmony_ci{ 7518c2ecf20Sopenharmony_ci struct dcp *sdcp = global_sdcp; 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci struct dcp_sha_req_ctx *rctx = ahash_request_ctx(req); 7548c2ecf20Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 7558c2ecf20Sopenharmony_ci struct dcp_async_ctx *actx = crypto_ahash_ctx(tfm); 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci int ret; 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci /* 7608c2ecf20Sopenharmony_ci * Ignore requests that have no data in them and are not 7618c2ecf20Sopenharmony_ci * the trailing requests in the stream of requests. 7628c2ecf20Sopenharmony_ci */ 7638c2ecf20Sopenharmony_ci if (!req->nbytes && !fini) 7648c2ecf20Sopenharmony_ci return 0; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci mutex_lock(&actx->mutex); 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci rctx->fini = fini; 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci if (!actx->hot) { 7718c2ecf20Sopenharmony_ci actx->hot = 1; 7728c2ecf20Sopenharmony_ci rctx->init = 1; 7738c2ecf20Sopenharmony_ci } 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci spin_lock(&sdcp->lock[actx->chan]); 7768c2ecf20Sopenharmony_ci ret = crypto_enqueue_request(&sdcp->queue[actx->chan], &req->base); 7778c2ecf20Sopenharmony_ci spin_unlock(&sdcp->lock[actx->chan]); 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci wake_up_process(sdcp->thread[actx->chan]); 7808c2ecf20Sopenharmony_ci mutex_unlock(&actx->mutex); 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci return ret; 7838c2ecf20Sopenharmony_ci} 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_cistatic int dcp_sha_update(struct ahash_request *req) 7868c2ecf20Sopenharmony_ci{ 7878c2ecf20Sopenharmony_ci return dcp_sha_update_fx(req, 0); 7888c2ecf20Sopenharmony_ci} 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_cistatic int dcp_sha_final(struct ahash_request *req) 7918c2ecf20Sopenharmony_ci{ 7928c2ecf20Sopenharmony_ci ahash_request_set_crypt(req, NULL, req->result, 0); 7938c2ecf20Sopenharmony_ci req->nbytes = 0; 7948c2ecf20Sopenharmony_ci return dcp_sha_update_fx(req, 1); 7958c2ecf20Sopenharmony_ci} 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_cistatic int dcp_sha_finup(struct ahash_request *req) 7988c2ecf20Sopenharmony_ci{ 7998c2ecf20Sopenharmony_ci return dcp_sha_update_fx(req, 1); 8008c2ecf20Sopenharmony_ci} 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_cistatic int dcp_sha_digest(struct ahash_request *req) 8038c2ecf20Sopenharmony_ci{ 8048c2ecf20Sopenharmony_ci int ret; 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci ret = dcp_sha_init(req); 8078c2ecf20Sopenharmony_ci if (ret) 8088c2ecf20Sopenharmony_ci return ret; 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci return dcp_sha_finup(req); 8118c2ecf20Sopenharmony_ci} 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_cistatic int dcp_sha_import(struct ahash_request *req, const void *in) 8148c2ecf20Sopenharmony_ci{ 8158c2ecf20Sopenharmony_ci struct dcp_sha_req_ctx *rctx = ahash_request_ctx(req); 8168c2ecf20Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 8178c2ecf20Sopenharmony_ci struct dcp_async_ctx *actx = crypto_ahash_ctx(tfm); 8188c2ecf20Sopenharmony_ci const struct dcp_export_state *export = in; 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci memset(rctx, 0, sizeof(struct dcp_sha_req_ctx)); 8218c2ecf20Sopenharmony_ci memset(actx, 0, sizeof(struct dcp_async_ctx)); 8228c2ecf20Sopenharmony_ci memcpy(rctx, &export->req_ctx, sizeof(struct dcp_sha_req_ctx)); 8238c2ecf20Sopenharmony_ci memcpy(actx, &export->async_ctx, sizeof(struct dcp_async_ctx)); 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci return 0; 8268c2ecf20Sopenharmony_ci} 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_cistatic int dcp_sha_export(struct ahash_request *req, void *out) 8298c2ecf20Sopenharmony_ci{ 8308c2ecf20Sopenharmony_ci struct dcp_sha_req_ctx *rctx_state = ahash_request_ctx(req); 8318c2ecf20Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 8328c2ecf20Sopenharmony_ci struct dcp_async_ctx *actx_state = crypto_ahash_ctx(tfm); 8338c2ecf20Sopenharmony_ci struct dcp_export_state *export = out; 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci memcpy(&export->req_ctx, rctx_state, sizeof(struct dcp_sha_req_ctx)); 8368c2ecf20Sopenharmony_ci memcpy(&export->async_ctx, actx_state, sizeof(struct dcp_async_ctx)); 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci return 0; 8398c2ecf20Sopenharmony_ci} 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_cistatic int dcp_sha_cra_init(struct crypto_tfm *tfm) 8428c2ecf20Sopenharmony_ci{ 8438c2ecf20Sopenharmony_ci crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), 8448c2ecf20Sopenharmony_ci sizeof(struct dcp_sha_req_ctx)); 8458c2ecf20Sopenharmony_ci return 0; 8468c2ecf20Sopenharmony_ci} 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_cistatic void dcp_sha_cra_exit(struct crypto_tfm *tfm) 8498c2ecf20Sopenharmony_ci{ 8508c2ecf20Sopenharmony_ci} 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci/* AES 128 ECB and AES 128 CBC */ 8538c2ecf20Sopenharmony_cistatic struct skcipher_alg dcp_aes_algs[] = { 8548c2ecf20Sopenharmony_ci { 8558c2ecf20Sopenharmony_ci .base.cra_name = "ecb(aes)", 8568c2ecf20Sopenharmony_ci .base.cra_driver_name = "ecb-aes-dcp", 8578c2ecf20Sopenharmony_ci .base.cra_priority = 400, 8588c2ecf20Sopenharmony_ci .base.cra_alignmask = 15, 8598c2ecf20Sopenharmony_ci .base.cra_flags = CRYPTO_ALG_ASYNC | 8608c2ecf20Sopenharmony_ci CRYPTO_ALG_NEED_FALLBACK, 8618c2ecf20Sopenharmony_ci .base.cra_blocksize = AES_BLOCK_SIZE, 8628c2ecf20Sopenharmony_ci .base.cra_ctxsize = sizeof(struct dcp_async_ctx), 8638c2ecf20Sopenharmony_ci .base.cra_module = THIS_MODULE, 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 8668c2ecf20Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 8678c2ecf20Sopenharmony_ci .setkey = mxs_dcp_aes_setkey, 8688c2ecf20Sopenharmony_ci .encrypt = mxs_dcp_aes_ecb_encrypt, 8698c2ecf20Sopenharmony_ci .decrypt = mxs_dcp_aes_ecb_decrypt, 8708c2ecf20Sopenharmony_ci .init = mxs_dcp_aes_fallback_init_tfm, 8718c2ecf20Sopenharmony_ci .exit = mxs_dcp_aes_fallback_exit_tfm, 8728c2ecf20Sopenharmony_ci }, { 8738c2ecf20Sopenharmony_ci .base.cra_name = "cbc(aes)", 8748c2ecf20Sopenharmony_ci .base.cra_driver_name = "cbc-aes-dcp", 8758c2ecf20Sopenharmony_ci .base.cra_priority = 400, 8768c2ecf20Sopenharmony_ci .base.cra_alignmask = 15, 8778c2ecf20Sopenharmony_ci .base.cra_flags = CRYPTO_ALG_ASYNC | 8788c2ecf20Sopenharmony_ci CRYPTO_ALG_NEED_FALLBACK, 8798c2ecf20Sopenharmony_ci .base.cra_blocksize = AES_BLOCK_SIZE, 8808c2ecf20Sopenharmony_ci .base.cra_ctxsize = sizeof(struct dcp_async_ctx), 8818c2ecf20Sopenharmony_ci .base.cra_module = THIS_MODULE, 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 8848c2ecf20Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 8858c2ecf20Sopenharmony_ci .setkey = mxs_dcp_aes_setkey, 8868c2ecf20Sopenharmony_ci .encrypt = mxs_dcp_aes_cbc_encrypt, 8878c2ecf20Sopenharmony_ci .decrypt = mxs_dcp_aes_cbc_decrypt, 8888c2ecf20Sopenharmony_ci .ivsize = AES_BLOCK_SIZE, 8898c2ecf20Sopenharmony_ci .init = mxs_dcp_aes_fallback_init_tfm, 8908c2ecf20Sopenharmony_ci .exit = mxs_dcp_aes_fallback_exit_tfm, 8918c2ecf20Sopenharmony_ci }, 8928c2ecf20Sopenharmony_ci}; 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci/* SHA1 */ 8958c2ecf20Sopenharmony_cistatic struct ahash_alg dcp_sha1_alg = { 8968c2ecf20Sopenharmony_ci .init = dcp_sha_init, 8978c2ecf20Sopenharmony_ci .update = dcp_sha_update, 8988c2ecf20Sopenharmony_ci .final = dcp_sha_final, 8998c2ecf20Sopenharmony_ci .finup = dcp_sha_finup, 9008c2ecf20Sopenharmony_ci .digest = dcp_sha_digest, 9018c2ecf20Sopenharmony_ci .import = dcp_sha_import, 9028c2ecf20Sopenharmony_ci .export = dcp_sha_export, 9038c2ecf20Sopenharmony_ci .halg = { 9048c2ecf20Sopenharmony_ci .digestsize = SHA1_DIGEST_SIZE, 9058c2ecf20Sopenharmony_ci .statesize = sizeof(struct dcp_export_state), 9068c2ecf20Sopenharmony_ci .base = { 9078c2ecf20Sopenharmony_ci .cra_name = "sha1", 9088c2ecf20Sopenharmony_ci .cra_driver_name = "sha1-dcp", 9098c2ecf20Sopenharmony_ci .cra_priority = 400, 9108c2ecf20Sopenharmony_ci .cra_alignmask = 63, 9118c2ecf20Sopenharmony_ci .cra_flags = CRYPTO_ALG_ASYNC, 9128c2ecf20Sopenharmony_ci .cra_blocksize = SHA1_BLOCK_SIZE, 9138c2ecf20Sopenharmony_ci .cra_ctxsize = sizeof(struct dcp_async_ctx), 9148c2ecf20Sopenharmony_ci .cra_module = THIS_MODULE, 9158c2ecf20Sopenharmony_ci .cra_init = dcp_sha_cra_init, 9168c2ecf20Sopenharmony_ci .cra_exit = dcp_sha_cra_exit, 9178c2ecf20Sopenharmony_ci }, 9188c2ecf20Sopenharmony_ci }, 9198c2ecf20Sopenharmony_ci}; 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci/* SHA256 */ 9228c2ecf20Sopenharmony_cistatic struct ahash_alg dcp_sha256_alg = { 9238c2ecf20Sopenharmony_ci .init = dcp_sha_init, 9248c2ecf20Sopenharmony_ci .update = dcp_sha_update, 9258c2ecf20Sopenharmony_ci .final = dcp_sha_final, 9268c2ecf20Sopenharmony_ci .finup = dcp_sha_finup, 9278c2ecf20Sopenharmony_ci .digest = dcp_sha_digest, 9288c2ecf20Sopenharmony_ci .import = dcp_sha_import, 9298c2ecf20Sopenharmony_ci .export = dcp_sha_export, 9308c2ecf20Sopenharmony_ci .halg = { 9318c2ecf20Sopenharmony_ci .digestsize = SHA256_DIGEST_SIZE, 9328c2ecf20Sopenharmony_ci .statesize = sizeof(struct dcp_export_state), 9338c2ecf20Sopenharmony_ci .base = { 9348c2ecf20Sopenharmony_ci .cra_name = "sha256", 9358c2ecf20Sopenharmony_ci .cra_driver_name = "sha256-dcp", 9368c2ecf20Sopenharmony_ci .cra_priority = 400, 9378c2ecf20Sopenharmony_ci .cra_alignmask = 63, 9388c2ecf20Sopenharmony_ci .cra_flags = CRYPTO_ALG_ASYNC, 9398c2ecf20Sopenharmony_ci .cra_blocksize = SHA256_BLOCK_SIZE, 9408c2ecf20Sopenharmony_ci .cra_ctxsize = sizeof(struct dcp_async_ctx), 9418c2ecf20Sopenharmony_ci .cra_module = THIS_MODULE, 9428c2ecf20Sopenharmony_ci .cra_init = dcp_sha_cra_init, 9438c2ecf20Sopenharmony_ci .cra_exit = dcp_sha_cra_exit, 9448c2ecf20Sopenharmony_ci }, 9458c2ecf20Sopenharmony_ci }, 9468c2ecf20Sopenharmony_ci}; 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_cistatic irqreturn_t mxs_dcp_irq(int irq, void *context) 9498c2ecf20Sopenharmony_ci{ 9508c2ecf20Sopenharmony_ci struct dcp *sdcp = context; 9518c2ecf20Sopenharmony_ci uint32_t stat; 9528c2ecf20Sopenharmony_ci int i; 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci stat = readl(sdcp->base + MXS_DCP_STAT); 9558c2ecf20Sopenharmony_ci stat &= MXS_DCP_STAT_IRQ_MASK; 9568c2ecf20Sopenharmony_ci if (!stat) 9578c2ecf20Sopenharmony_ci return IRQ_NONE; 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci /* Clear the interrupts. */ 9608c2ecf20Sopenharmony_ci writel(stat, sdcp->base + MXS_DCP_STAT_CLR); 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci /* Complete the DMA requests that finished. */ 9638c2ecf20Sopenharmony_ci for (i = 0; i < DCP_MAX_CHANS; i++) 9648c2ecf20Sopenharmony_ci if (stat & (1 << i)) 9658c2ecf20Sopenharmony_ci complete(&sdcp->completion[i]); 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci return IRQ_HANDLED; 9688c2ecf20Sopenharmony_ci} 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_cistatic int mxs_dcp_probe(struct platform_device *pdev) 9718c2ecf20Sopenharmony_ci{ 9728c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 9738c2ecf20Sopenharmony_ci struct dcp *sdcp = NULL; 9748c2ecf20Sopenharmony_ci int i, ret; 9758c2ecf20Sopenharmony_ci int dcp_vmi_irq, dcp_irq; 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci if (global_sdcp) { 9788c2ecf20Sopenharmony_ci dev_err(dev, "Only one DCP instance allowed!\n"); 9798c2ecf20Sopenharmony_ci return -ENODEV; 9808c2ecf20Sopenharmony_ci } 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci dcp_vmi_irq = platform_get_irq(pdev, 0); 9838c2ecf20Sopenharmony_ci if (dcp_vmi_irq < 0) 9848c2ecf20Sopenharmony_ci return dcp_vmi_irq; 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci dcp_irq = platform_get_irq(pdev, 1); 9878c2ecf20Sopenharmony_ci if (dcp_irq < 0) 9888c2ecf20Sopenharmony_ci return dcp_irq; 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci sdcp = devm_kzalloc(dev, sizeof(*sdcp), GFP_KERNEL); 9918c2ecf20Sopenharmony_ci if (!sdcp) 9928c2ecf20Sopenharmony_ci return -ENOMEM; 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci sdcp->dev = dev; 9958c2ecf20Sopenharmony_ci sdcp->base = devm_platform_ioremap_resource(pdev, 0); 9968c2ecf20Sopenharmony_ci if (IS_ERR(sdcp->base)) 9978c2ecf20Sopenharmony_ci return PTR_ERR(sdcp->base); 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci ret = devm_request_irq(dev, dcp_vmi_irq, mxs_dcp_irq, 0, 10018c2ecf20Sopenharmony_ci "dcp-vmi-irq", sdcp); 10028c2ecf20Sopenharmony_ci if (ret) { 10038c2ecf20Sopenharmony_ci dev_err(dev, "Failed to claim DCP VMI IRQ!\n"); 10048c2ecf20Sopenharmony_ci return ret; 10058c2ecf20Sopenharmony_ci } 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci ret = devm_request_irq(dev, dcp_irq, mxs_dcp_irq, 0, 10088c2ecf20Sopenharmony_ci "dcp-irq", sdcp); 10098c2ecf20Sopenharmony_ci if (ret) { 10108c2ecf20Sopenharmony_ci dev_err(dev, "Failed to claim DCP IRQ!\n"); 10118c2ecf20Sopenharmony_ci return ret; 10128c2ecf20Sopenharmony_ci } 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci /* Allocate coherent helper block. */ 10158c2ecf20Sopenharmony_ci sdcp->coh = devm_kzalloc(dev, sizeof(*sdcp->coh) + DCP_ALIGNMENT, 10168c2ecf20Sopenharmony_ci GFP_KERNEL); 10178c2ecf20Sopenharmony_ci if (!sdcp->coh) 10188c2ecf20Sopenharmony_ci return -ENOMEM; 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci /* Re-align the structure so it fits the DCP constraints. */ 10218c2ecf20Sopenharmony_ci sdcp->coh = PTR_ALIGN(sdcp->coh, DCP_ALIGNMENT); 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci /* DCP clock is optional, only used on some SOCs */ 10248c2ecf20Sopenharmony_ci sdcp->dcp_clk = devm_clk_get(dev, "dcp"); 10258c2ecf20Sopenharmony_ci if (IS_ERR(sdcp->dcp_clk)) { 10268c2ecf20Sopenharmony_ci if (sdcp->dcp_clk != ERR_PTR(-ENOENT)) 10278c2ecf20Sopenharmony_ci return PTR_ERR(sdcp->dcp_clk); 10288c2ecf20Sopenharmony_ci sdcp->dcp_clk = NULL; 10298c2ecf20Sopenharmony_ci } 10308c2ecf20Sopenharmony_ci ret = clk_prepare_enable(sdcp->dcp_clk); 10318c2ecf20Sopenharmony_ci if (ret) 10328c2ecf20Sopenharmony_ci return ret; 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci /* Restart the DCP block. */ 10358c2ecf20Sopenharmony_ci ret = stmp_reset_block(sdcp->base); 10368c2ecf20Sopenharmony_ci if (ret) { 10378c2ecf20Sopenharmony_ci dev_err(dev, "Failed reset\n"); 10388c2ecf20Sopenharmony_ci goto err_disable_unprepare_clk; 10398c2ecf20Sopenharmony_ci } 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci /* Initialize control register. */ 10428c2ecf20Sopenharmony_ci writel(MXS_DCP_CTRL_GATHER_RESIDUAL_WRITES | 10438c2ecf20Sopenharmony_ci MXS_DCP_CTRL_ENABLE_CONTEXT_CACHING | 0xf, 10448c2ecf20Sopenharmony_ci sdcp->base + MXS_DCP_CTRL); 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci /* Enable all DCP DMA channels. */ 10478c2ecf20Sopenharmony_ci writel(MXS_DCP_CHANNELCTRL_ENABLE_CHANNEL_MASK, 10488c2ecf20Sopenharmony_ci sdcp->base + MXS_DCP_CHANNELCTRL); 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci /* 10518c2ecf20Sopenharmony_ci * We do not enable context switching. Give the context buffer a 10528c2ecf20Sopenharmony_ci * pointer to an illegal address so if context switching is 10538c2ecf20Sopenharmony_ci * inadvertantly enabled, the DCP will return an error instead of 10548c2ecf20Sopenharmony_ci * trashing good memory. The DCP DMA cannot access ROM, so any ROM 10558c2ecf20Sopenharmony_ci * address will do. 10568c2ecf20Sopenharmony_ci */ 10578c2ecf20Sopenharmony_ci writel(0xffff0000, sdcp->base + MXS_DCP_CONTEXT); 10588c2ecf20Sopenharmony_ci for (i = 0; i < DCP_MAX_CHANS; i++) 10598c2ecf20Sopenharmony_ci writel(0xffffffff, sdcp->base + MXS_DCP_CH_N_STAT_CLR(i)); 10608c2ecf20Sopenharmony_ci writel(0xffffffff, sdcp->base + MXS_DCP_STAT_CLR); 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci global_sdcp = sdcp; 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, sdcp); 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci for (i = 0; i < DCP_MAX_CHANS; i++) { 10678c2ecf20Sopenharmony_ci spin_lock_init(&sdcp->lock[i]); 10688c2ecf20Sopenharmony_ci init_completion(&sdcp->completion[i]); 10698c2ecf20Sopenharmony_ci crypto_init_queue(&sdcp->queue[i], 50); 10708c2ecf20Sopenharmony_ci } 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci /* Create the SHA and AES handler threads. */ 10738c2ecf20Sopenharmony_ci sdcp->thread[DCP_CHAN_HASH_SHA] = kthread_run(dcp_chan_thread_sha, 10748c2ecf20Sopenharmony_ci NULL, "mxs_dcp_chan/sha"); 10758c2ecf20Sopenharmony_ci if (IS_ERR(sdcp->thread[DCP_CHAN_HASH_SHA])) { 10768c2ecf20Sopenharmony_ci dev_err(dev, "Error starting SHA thread!\n"); 10778c2ecf20Sopenharmony_ci ret = PTR_ERR(sdcp->thread[DCP_CHAN_HASH_SHA]); 10788c2ecf20Sopenharmony_ci goto err_disable_unprepare_clk; 10798c2ecf20Sopenharmony_ci } 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci sdcp->thread[DCP_CHAN_CRYPTO] = kthread_run(dcp_chan_thread_aes, 10828c2ecf20Sopenharmony_ci NULL, "mxs_dcp_chan/aes"); 10838c2ecf20Sopenharmony_ci if (IS_ERR(sdcp->thread[DCP_CHAN_CRYPTO])) { 10848c2ecf20Sopenharmony_ci dev_err(dev, "Error starting SHA thread!\n"); 10858c2ecf20Sopenharmony_ci ret = PTR_ERR(sdcp->thread[DCP_CHAN_CRYPTO]); 10868c2ecf20Sopenharmony_ci goto err_destroy_sha_thread; 10878c2ecf20Sopenharmony_ci } 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci /* Register the various crypto algorithms. */ 10908c2ecf20Sopenharmony_ci sdcp->caps = readl(sdcp->base + MXS_DCP_CAPABILITY1); 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci if (sdcp->caps & MXS_DCP_CAPABILITY1_AES128) { 10938c2ecf20Sopenharmony_ci ret = crypto_register_skciphers(dcp_aes_algs, 10948c2ecf20Sopenharmony_ci ARRAY_SIZE(dcp_aes_algs)); 10958c2ecf20Sopenharmony_ci if (ret) { 10968c2ecf20Sopenharmony_ci /* Failed to register algorithm. */ 10978c2ecf20Sopenharmony_ci dev_err(dev, "Failed to register AES crypto!\n"); 10988c2ecf20Sopenharmony_ci goto err_destroy_aes_thread; 10998c2ecf20Sopenharmony_ci } 11008c2ecf20Sopenharmony_ci } 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci if (sdcp->caps & MXS_DCP_CAPABILITY1_SHA1) { 11038c2ecf20Sopenharmony_ci ret = crypto_register_ahash(&dcp_sha1_alg); 11048c2ecf20Sopenharmony_ci if (ret) { 11058c2ecf20Sopenharmony_ci dev_err(dev, "Failed to register %s hash!\n", 11068c2ecf20Sopenharmony_ci dcp_sha1_alg.halg.base.cra_name); 11078c2ecf20Sopenharmony_ci goto err_unregister_aes; 11088c2ecf20Sopenharmony_ci } 11098c2ecf20Sopenharmony_ci } 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci if (sdcp->caps & MXS_DCP_CAPABILITY1_SHA256) { 11128c2ecf20Sopenharmony_ci ret = crypto_register_ahash(&dcp_sha256_alg); 11138c2ecf20Sopenharmony_ci if (ret) { 11148c2ecf20Sopenharmony_ci dev_err(dev, "Failed to register %s hash!\n", 11158c2ecf20Sopenharmony_ci dcp_sha256_alg.halg.base.cra_name); 11168c2ecf20Sopenharmony_ci goto err_unregister_sha1; 11178c2ecf20Sopenharmony_ci } 11188c2ecf20Sopenharmony_ci } 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci return 0; 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_cierr_unregister_sha1: 11238c2ecf20Sopenharmony_ci if (sdcp->caps & MXS_DCP_CAPABILITY1_SHA1) 11248c2ecf20Sopenharmony_ci crypto_unregister_ahash(&dcp_sha1_alg); 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_cierr_unregister_aes: 11278c2ecf20Sopenharmony_ci if (sdcp->caps & MXS_DCP_CAPABILITY1_AES128) 11288c2ecf20Sopenharmony_ci crypto_unregister_skciphers(dcp_aes_algs, ARRAY_SIZE(dcp_aes_algs)); 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_cierr_destroy_aes_thread: 11318c2ecf20Sopenharmony_ci kthread_stop(sdcp->thread[DCP_CHAN_CRYPTO]); 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_cierr_destroy_sha_thread: 11348c2ecf20Sopenharmony_ci kthread_stop(sdcp->thread[DCP_CHAN_HASH_SHA]); 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_cierr_disable_unprepare_clk: 11378c2ecf20Sopenharmony_ci clk_disable_unprepare(sdcp->dcp_clk); 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci return ret; 11408c2ecf20Sopenharmony_ci} 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_cistatic int mxs_dcp_remove(struct platform_device *pdev) 11438c2ecf20Sopenharmony_ci{ 11448c2ecf20Sopenharmony_ci struct dcp *sdcp = platform_get_drvdata(pdev); 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci if (sdcp->caps & MXS_DCP_CAPABILITY1_SHA256) 11478c2ecf20Sopenharmony_ci crypto_unregister_ahash(&dcp_sha256_alg); 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci if (sdcp->caps & MXS_DCP_CAPABILITY1_SHA1) 11508c2ecf20Sopenharmony_ci crypto_unregister_ahash(&dcp_sha1_alg); 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci if (sdcp->caps & MXS_DCP_CAPABILITY1_AES128) 11538c2ecf20Sopenharmony_ci crypto_unregister_skciphers(dcp_aes_algs, ARRAY_SIZE(dcp_aes_algs)); 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci kthread_stop(sdcp->thread[DCP_CHAN_HASH_SHA]); 11568c2ecf20Sopenharmony_ci kthread_stop(sdcp->thread[DCP_CHAN_CRYPTO]); 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci clk_disable_unprepare(sdcp->dcp_clk); 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, NULL); 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci global_sdcp = NULL; 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci return 0; 11658c2ecf20Sopenharmony_ci} 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_cistatic const struct of_device_id mxs_dcp_dt_ids[] = { 11688c2ecf20Sopenharmony_ci { .compatible = "fsl,imx23-dcp", .data = NULL, }, 11698c2ecf20Sopenharmony_ci { .compatible = "fsl,imx28-dcp", .data = NULL, }, 11708c2ecf20Sopenharmony_ci { /* sentinel */ } 11718c2ecf20Sopenharmony_ci}; 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, mxs_dcp_dt_ids); 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_cistatic struct platform_driver mxs_dcp_driver = { 11768c2ecf20Sopenharmony_ci .probe = mxs_dcp_probe, 11778c2ecf20Sopenharmony_ci .remove = mxs_dcp_remove, 11788c2ecf20Sopenharmony_ci .driver = { 11798c2ecf20Sopenharmony_ci .name = "mxs-dcp", 11808c2ecf20Sopenharmony_ci .of_match_table = mxs_dcp_dt_ids, 11818c2ecf20Sopenharmony_ci }, 11828c2ecf20Sopenharmony_ci}; 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_cimodule_platform_driver(mxs_dcp_driver); 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ciMODULE_AUTHOR("Marek Vasut <marex@denx.de>"); 11878c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Freescale MXS DCP Driver"); 11888c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 11898c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:mxs-dcp"); 1190