18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Support for OMAP DES and Triple DES HW acceleration. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2013 Texas Instruments Incorporated 68c2ecf20Sopenharmony_ci * Author: Joel Fernandes <joelf@ti.com> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "%s: " fmt, __func__ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#ifdef DEBUG 128c2ecf20Sopenharmony_ci#define prn(num) printk(#num "=%d\n", num) 138c2ecf20Sopenharmony_ci#define prx(num) printk(#num "=%x\n", num) 148c2ecf20Sopenharmony_ci#else 158c2ecf20Sopenharmony_ci#define prn(num) do { } while (0) 168c2ecf20Sopenharmony_ci#define prx(num) do { } while (0) 178c2ecf20Sopenharmony_ci#endif 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <linux/err.h> 208c2ecf20Sopenharmony_ci#include <linux/module.h> 218c2ecf20Sopenharmony_ci#include <linux/init.h> 228c2ecf20Sopenharmony_ci#include <linux/errno.h> 238c2ecf20Sopenharmony_ci#include <linux/kernel.h> 248c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 258c2ecf20Sopenharmony_ci#include <linux/scatterlist.h> 268c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 278c2ecf20Sopenharmony_ci#include <linux/dmaengine.h> 288c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 298c2ecf20Sopenharmony_ci#include <linux/of.h> 308c2ecf20Sopenharmony_ci#include <linux/of_device.h> 318c2ecf20Sopenharmony_ci#include <linux/of_address.h> 328c2ecf20Sopenharmony_ci#include <linux/io.h> 338c2ecf20Sopenharmony_ci#include <linux/crypto.h> 348c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 358c2ecf20Sopenharmony_ci#include <crypto/scatterwalk.h> 368c2ecf20Sopenharmony_ci#include <crypto/internal/des.h> 378c2ecf20Sopenharmony_ci#include <crypto/internal/skcipher.h> 388c2ecf20Sopenharmony_ci#include <crypto/algapi.h> 398c2ecf20Sopenharmony_ci#include <crypto/engine.h> 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#include "omap-crypto.h" 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#define DST_MAXBURST 2 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#define DES_BLOCK_WORDS (DES_BLOCK_SIZE >> 2) 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#define _calc_walked(inout) (dd->inout##_walk.offset - dd->inout##_sg->offset) 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#define DES_REG_KEY(dd, x) ((dd)->pdata->key_ofs - \ 508c2ecf20Sopenharmony_ci ((x ^ 0x01) * 0x04)) 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci#define DES_REG_IV(dd, x) ((dd)->pdata->iv_ofs + ((x) * 0x04)) 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci#define DES_REG_CTRL(dd) ((dd)->pdata->ctrl_ofs) 558c2ecf20Sopenharmony_ci#define DES_REG_CTRL_CBC BIT(4) 568c2ecf20Sopenharmony_ci#define DES_REG_CTRL_TDES BIT(3) 578c2ecf20Sopenharmony_ci#define DES_REG_CTRL_DIRECTION BIT(2) 588c2ecf20Sopenharmony_ci#define DES_REG_CTRL_INPUT_READY BIT(1) 598c2ecf20Sopenharmony_ci#define DES_REG_CTRL_OUTPUT_READY BIT(0) 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci#define DES_REG_DATA_N(dd, x) ((dd)->pdata->data_ofs + ((x) * 0x04)) 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci#define DES_REG_REV(dd) ((dd)->pdata->rev_ofs) 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci#define DES_REG_MASK(dd) ((dd)->pdata->mask_ofs) 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci#define DES_REG_LENGTH_N(x) (0x24 + ((x) * 0x04)) 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci#define DES_REG_IRQ_STATUS(dd) ((dd)->pdata->irq_status_ofs) 708c2ecf20Sopenharmony_ci#define DES_REG_IRQ_ENABLE(dd) ((dd)->pdata->irq_enable_ofs) 718c2ecf20Sopenharmony_ci#define DES_REG_IRQ_DATA_IN BIT(1) 728c2ecf20Sopenharmony_ci#define DES_REG_IRQ_DATA_OUT BIT(2) 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci#define FLAGS_MODE_MASK 0x000f 758c2ecf20Sopenharmony_ci#define FLAGS_ENCRYPT BIT(0) 768c2ecf20Sopenharmony_ci#define FLAGS_CBC BIT(1) 778c2ecf20Sopenharmony_ci#define FLAGS_INIT BIT(4) 788c2ecf20Sopenharmony_ci#define FLAGS_BUSY BIT(6) 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci#define DEFAULT_AUTOSUSPEND_DELAY 1000 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci#define FLAGS_IN_DATA_ST_SHIFT 8 838c2ecf20Sopenharmony_ci#define FLAGS_OUT_DATA_ST_SHIFT 10 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistruct omap_des_ctx { 868c2ecf20Sopenharmony_ci struct crypto_engine_ctx enginectx; 878c2ecf20Sopenharmony_ci struct omap_des_dev *dd; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci int keylen; 908c2ecf20Sopenharmony_ci __le32 key[(3 * DES_KEY_SIZE) / sizeof(u32)]; 918c2ecf20Sopenharmony_ci unsigned long flags; 928c2ecf20Sopenharmony_ci}; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistruct omap_des_reqctx { 958c2ecf20Sopenharmony_ci unsigned long mode; 968c2ecf20Sopenharmony_ci}; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci#define OMAP_DES_QUEUE_LENGTH 1 998c2ecf20Sopenharmony_ci#define OMAP_DES_CACHE_SIZE 0 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistruct omap_des_algs_info { 1028c2ecf20Sopenharmony_ci struct skcipher_alg *algs_list; 1038c2ecf20Sopenharmony_ci unsigned int size; 1048c2ecf20Sopenharmony_ci unsigned int registered; 1058c2ecf20Sopenharmony_ci}; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistruct omap_des_pdata { 1088c2ecf20Sopenharmony_ci struct omap_des_algs_info *algs_info; 1098c2ecf20Sopenharmony_ci unsigned int algs_info_size; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci void (*trigger)(struct omap_des_dev *dd, int length); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci u32 key_ofs; 1148c2ecf20Sopenharmony_ci u32 iv_ofs; 1158c2ecf20Sopenharmony_ci u32 ctrl_ofs; 1168c2ecf20Sopenharmony_ci u32 data_ofs; 1178c2ecf20Sopenharmony_ci u32 rev_ofs; 1188c2ecf20Sopenharmony_ci u32 mask_ofs; 1198c2ecf20Sopenharmony_ci u32 irq_enable_ofs; 1208c2ecf20Sopenharmony_ci u32 irq_status_ofs; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci u32 dma_enable_in; 1238c2ecf20Sopenharmony_ci u32 dma_enable_out; 1248c2ecf20Sopenharmony_ci u32 dma_start; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci u32 major_mask; 1278c2ecf20Sopenharmony_ci u32 major_shift; 1288c2ecf20Sopenharmony_ci u32 minor_mask; 1298c2ecf20Sopenharmony_ci u32 minor_shift; 1308c2ecf20Sopenharmony_ci}; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistruct omap_des_dev { 1338c2ecf20Sopenharmony_ci struct list_head list; 1348c2ecf20Sopenharmony_ci unsigned long phys_base; 1358c2ecf20Sopenharmony_ci void __iomem *io_base; 1368c2ecf20Sopenharmony_ci struct omap_des_ctx *ctx; 1378c2ecf20Sopenharmony_ci struct device *dev; 1388c2ecf20Sopenharmony_ci unsigned long flags; 1398c2ecf20Sopenharmony_ci int err; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci struct tasklet_struct done_task; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci struct skcipher_request *req; 1448c2ecf20Sopenharmony_ci struct crypto_engine *engine; 1458c2ecf20Sopenharmony_ci /* 1468c2ecf20Sopenharmony_ci * total is used by PIO mode for book keeping so introduce 1478c2ecf20Sopenharmony_ci * variable total_save as need it to calc page_order 1488c2ecf20Sopenharmony_ci */ 1498c2ecf20Sopenharmony_ci size_t total; 1508c2ecf20Sopenharmony_ci size_t total_save; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci struct scatterlist *in_sg; 1538c2ecf20Sopenharmony_ci struct scatterlist *out_sg; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci /* Buffers for copying for unaligned cases */ 1568c2ecf20Sopenharmony_ci struct scatterlist in_sgl; 1578c2ecf20Sopenharmony_ci struct scatterlist out_sgl; 1588c2ecf20Sopenharmony_ci struct scatterlist *orig_out; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci struct scatter_walk in_walk; 1618c2ecf20Sopenharmony_ci struct scatter_walk out_walk; 1628c2ecf20Sopenharmony_ci struct dma_chan *dma_lch_in; 1638c2ecf20Sopenharmony_ci struct dma_chan *dma_lch_out; 1648c2ecf20Sopenharmony_ci int in_sg_len; 1658c2ecf20Sopenharmony_ci int out_sg_len; 1668c2ecf20Sopenharmony_ci int pio_only; 1678c2ecf20Sopenharmony_ci const struct omap_des_pdata *pdata; 1688c2ecf20Sopenharmony_ci}; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci/* keep registered devices data here */ 1718c2ecf20Sopenharmony_cistatic LIST_HEAD(dev_list); 1728c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(list_lock); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci#ifdef DEBUG 1758c2ecf20Sopenharmony_ci#define omap_des_read(dd, offset) \ 1768c2ecf20Sopenharmony_ci ({ \ 1778c2ecf20Sopenharmony_ci int _read_ret; \ 1788c2ecf20Sopenharmony_ci _read_ret = __raw_readl(dd->io_base + offset); \ 1798c2ecf20Sopenharmony_ci pr_err("omap_des_read(" #offset "=%#x)= %#x\n", \ 1808c2ecf20Sopenharmony_ci offset, _read_ret); \ 1818c2ecf20Sopenharmony_ci _read_ret; \ 1828c2ecf20Sopenharmony_ci }) 1838c2ecf20Sopenharmony_ci#else 1848c2ecf20Sopenharmony_cistatic inline u32 omap_des_read(struct omap_des_dev *dd, u32 offset) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci return __raw_readl(dd->io_base + offset); 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci#endif 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci#ifdef DEBUG 1918c2ecf20Sopenharmony_ci#define omap_des_write(dd, offset, value) \ 1928c2ecf20Sopenharmony_ci do { \ 1938c2ecf20Sopenharmony_ci pr_err("omap_des_write(" #offset "=%#x) value=%#x\n", \ 1948c2ecf20Sopenharmony_ci offset, value); \ 1958c2ecf20Sopenharmony_ci __raw_writel(value, dd->io_base + offset); \ 1968c2ecf20Sopenharmony_ci } while (0) 1978c2ecf20Sopenharmony_ci#else 1988c2ecf20Sopenharmony_cistatic inline void omap_des_write(struct omap_des_dev *dd, u32 offset, 1998c2ecf20Sopenharmony_ci u32 value) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci __raw_writel(value, dd->io_base + offset); 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci#endif 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cistatic inline void omap_des_write_mask(struct omap_des_dev *dd, u32 offset, 2068c2ecf20Sopenharmony_ci u32 value, u32 mask) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci u32 val; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci val = omap_des_read(dd, offset); 2118c2ecf20Sopenharmony_ci val &= ~mask; 2128c2ecf20Sopenharmony_ci val |= value; 2138c2ecf20Sopenharmony_ci omap_des_write(dd, offset, val); 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic void omap_des_write_n(struct omap_des_dev *dd, u32 offset, 2178c2ecf20Sopenharmony_ci u32 *value, int count) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci for (; count--; value++, offset += 4) 2208c2ecf20Sopenharmony_ci omap_des_write(dd, offset, *value); 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cistatic int omap_des_hw_init(struct omap_des_dev *dd) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci int err; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci /* 2288c2ecf20Sopenharmony_ci * clocks are enabled when request starts and disabled when finished. 2298c2ecf20Sopenharmony_ci * It may be long delays between requests. 2308c2ecf20Sopenharmony_ci * Device might go to off mode to save power. 2318c2ecf20Sopenharmony_ci */ 2328c2ecf20Sopenharmony_ci err = pm_runtime_get_sync(dd->dev); 2338c2ecf20Sopenharmony_ci if (err < 0) { 2348c2ecf20Sopenharmony_ci pm_runtime_put_noidle(dd->dev); 2358c2ecf20Sopenharmony_ci dev_err(dd->dev, "%s: failed to get_sync(%d)\n", __func__, err); 2368c2ecf20Sopenharmony_ci return err; 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci if (!(dd->flags & FLAGS_INIT)) { 2408c2ecf20Sopenharmony_ci dd->flags |= FLAGS_INIT; 2418c2ecf20Sopenharmony_ci dd->err = 0; 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci return 0; 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistatic int omap_des_write_ctrl(struct omap_des_dev *dd) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci unsigned int key32; 2508c2ecf20Sopenharmony_ci int i, err; 2518c2ecf20Sopenharmony_ci u32 val = 0, mask = 0; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci err = omap_des_hw_init(dd); 2548c2ecf20Sopenharmony_ci if (err) 2558c2ecf20Sopenharmony_ci return err; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci key32 = dd->ctx->keylen / sizeof(u32); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci /* it seems a key should always be set even if it has not changed */ 2608c2ecf20Sopenharmony_ci for (i = 0; i < key32; i++) { 2618c2ecf20Sopenharmony_ci omap_des_write(dd, DES_REG_KEY(dd, i), 2628c2ecf20Sopenharmony_ci __le32_to_cpu(dd->ctx->key[i])); 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci if ((dd->flags & FLAGS_CBC) && dd->req->iv) 2668c2ecf20Sopenharmony_ci omap_des_write_n(dd, DES_REG_IV(dd, 0), (void *)dd->req->iv, 2); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci if (dd->flags & FLAGS_CBC) 2698c2ecf20Sopenharmony_ci val |= DES_REG_CTRL_CBC; 2708c2ecf20Sopenharmony_ci if (dd->flags & FLAGS_ENCRYPT) 2718c2ecf20Sopenharmony_ci val |= DES_REG_CTRL_DIRECTION; 2728c2ecf20Sopenharmony_ci if (key32 == 6) 2738c2ecf20Sopenharmony_ci val |= DES_REG_CTRL_TDES; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci mask |= DES_REG_CTRL_CBC | DES_REG_CTRL_DIRECTION | DES_REG_CTRL_TDES; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci omap_des_write_mask(dd, DES_REG_CTRL(dd), val, mask); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci return 0; 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_cistatic void omap_des_dma_trigger_omap4(struct omap_des_dev *dd, int length) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci u32 mask, val; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci omap_des_write(dd, DES_REG_LENGTH_N(0), length); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci val = dd->pdata->dma_start; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci if (dd->dma_lch_out != NULL) 2918c2ecf20Sopenharmony_ci val |= dd->pdata->dma_enable_out; 2928c2ecf20Sopenharmony_ci if (dd->dma_lch_in != NULL) 2938c2ecf20Sopenharmony_ci val |= dd->pdata->dma_enable_in; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci mask = dd->pdata->dma_enable_out | dd->pdata->dma_enable_in | 2968c2ecf20Sopenharmony_ci dd->pdata->dma_start; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci omap_des_write_mask(dd, DES_REG_MASK(dd), val, mask); 2998c2ecf20Sopenharmony_ci} 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_cistatic void omap_des_dma_stop(struct omap_des_dev *dd) 3028c2ecf20Sopenharmony_ci{ 3038c2ecf20Sopenharmony_ci u32 mask; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci mask = dd->pdata->dma_enable_out | dd->pdata->dma_enable_in | 3068c2ecf20Sopenharmony_ci dd->pdata->dma_start; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci omap_des_write_mask(dd, DES_REG_MASK(dd), 0, mask); 3098c2ecf20Sopenharmony_ci} 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_cistatic struct omap_des_dev *omap_des_find_dev(struct omap_des_ctx *ctx) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci struct omap_des_dev *dd = NULL, *tmp; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci spin_lock_bh(&list_lock); 3168c2ecf20Sopenharmony_ci if (!ctx->dd) { 3178c2ecf20Sopenharmony_ci list_for_each_entry(tmp, &dev_list, list) { 3188c2ecf20Sopenharmony_ci /* FIXME: take fist available des core */ 3198c2ecf20Sopenharmony_ci dd = tmp; 3208c2ecf20Sopenharmony_ci break; 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci ctx->dd = dd; 3238c2ecf20Sopenharmony_ci } else { 3248c2ecf20Sopenharmony_ci /* already found before */ 3258c2ecf20Sopenharmony_ci dd = ctx->dd; 3268c2ecf20Sopenharmony_ci } 3278c2ecf20Sopenharmony_ci spin_unlock_bh(&list_lock); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci return dd; 3308c2ecf20Sopenharmony_ci} 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_cistatic void omap_des_dma_out_callback(void *data) 3338c2ecf20Sopenharmony_ci{ 3348c2ecf20Sopenharmony_ci struct omap_des_dev *dd = data; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci /* dma_lch_out - completed */ 3378c2ecf20Sopenharmony_ci tasklet_schedule(&dd->done_task); 3388c2ecf20Sopenharmony_ci} 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_cistatic int omap_des_dma_init(struct omap_des_dev *dd) 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci int err; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci dd->dma_lch_out = NULL; 3458c2ecf20Sopenharmony_ci dd->dma_lch_in = NULL; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci dd->dma_lch_in = dma_request_chan(dd->dev, "rx"); 3488c2ecf20Sopenharmony_ci if (IS_ERR(dd->dma_lch_in)) { 3498c2ecf20Sopenharmony_ci dev_err(dd->dev, "Unable to request in DMA channel\n"); 3508c2ecf20Sopenharmony_ci return PTR_ERR(dd->dma_lch_in); 3518c2ecf20Sopenharmony_ci } 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci dd->dma_lch_out = dma_request_chan(dd->dev, "tx"); 3548c2ecf20Sopenharmony_ci if (IS_ERR(dd->dma_lch_out)) { 3558c2ecf20Sopenharmony_ci dev_err(dd->dev, "Unable to request out DMA channel\n"); 3568c2ecf20Sopenharmony_ci err = PTR_ERR(dd->dma_lch_out); 3578c2ecf20Sopenharmony_ci goto err_dma_out; 3588c2ecf20Sopenharmony_ci } 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci return 0; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_cierr_dma_out: 3638c2ecf20Sopenharmony_ci dma_release_channel(dd->dma_lch_in); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci return err; 3668c2ecf20Sopenharmony_ci} 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_cistatic void omap_des_dma_cleanup(struct omap_des_dev *dd) 3698c2ecf20Sopenharmony_ci{ 3708c2ecf20Sopenharmony_ci if (dd->pio_only) 3718c2ecf20Sopenharmony_ci return; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci dma_release_channel(dd->dma_lch_out); 3748c2ecf20Sopenharmony_ci dma_release_channel(dd->dma_lch_in); 3758c2ecf20Sopenharmony_ci} 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_cistatic int omap_des_crypt_dma(struct crypto_tfm *tfm, 3788c2ecf20Sopenharmony_ci struct scatterlist *in_sg, struct scatterlist *out_sg, 3798c2ecf20Sopenharmony_ci int in_sg_len, int out_sg_len) 3808c2ecf20Sopenharmony_ci{ 3818c2ecf20Sopenharmony_ci struct omap_des_ctx *ctx = crypto_tfm_ctx(tfm); 3828c2ecf20Sopenharmony_ci struct omap_des_dev *dd = ctx->dd; 3838c2ecf20Sopenharmony_ci struct dma_async_tx_descriptor *tx_in, *tx_out; 3848c2ecf20Sopenharmony_ci struct dma_slave_config cfg; 3858c2ecf20Sopenharmony_ci int ret; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci if (dd->pio_only) { 3888c2ecf20Sopenharmony_ci scatterwalk_start(&dd->in_walk, dd->in_sg); 3898c2ecf20Sopenharmony_ci scatterwalk_start(&dd->out_walk, dd->out_sg); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci /* Enable DATAIN interrupt and let it take 3928c2ecf20Sopenharmony_ci care of the rest */ 3938c2ecf20Sopenharmony_ci omap_des_write(dd, DES_REG_IRQ_ENABLE(dd), 0x2); 3948c2ecf20Sopenharmony_ci return 0; 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci dma_sync_sg_for_device(dd->dev, dd->in_sg, in_sg_len, DMA_TO_DEVICE); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci memset(&cfg, 0, sizeof(cfg)); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci cfg.src_addr = dd->phys_base + DES_REG_DATA_N(dd, 0); 4028c2ecf20Sopenharmony_ci cfg.dst_addr = dd->phys_base + DES_REG_DATA_N(dd, 0); 4038c2ecf20Sopenharmony_ci cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 4048c2ecf20Sopenharmony_ci cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 4058c2ecf20Sopenharmony_ci cfg.src_maxburst = DST_MAXBURST; 4068c2ecf20Sopenharmony_ci cfg.dst_maxburst = DST_MAXBURST; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci /* IN */ 4098c2ecf20Sopenharmony_ci ret = dmaengine_slave_config(dd->dma_lch_in, &cfg); 4108c2ecf20Sopenharmony_ci if (ret) { 4118c2ecf20Sopenharmony_ci dev_err(dd->dev, "can't configure IN dmaengine slave: %d\n", 4128c2ecf20Sopenharmony_ci ret); 4138c2ecf20Sopenharmony_ci return ret; 4148c2ecf20Sopenharmony_ci } 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci tx_in = dmaengine_prep_slave_sg(dd->dma_lch_in, in_sg, in_sg_len, 4178c2ecf20Sopenharmony_ci DMA_MEM_TO_DEV, 4188c2ecf20Sopenharmony_ci DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 4198c2ecf20Sopenharmony_ci if (!tx_in) { 4208c2ecf20Sopenharmony_ci dev_err(dd->dev, "IN prep_slave_sg() failed\n"); 4218c2ecf20Sopenharmony_ci return -EINVAL; 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci /* No callback necessary */ 4258c2ecf20Sopenharmony_ci tx_in->callback_param = dd; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci /* OUT */ 4288c2ecf20Sopenharmony_ci ret = dmaengine_slave_config(dd->dma_lch_out, &cfg); 4298c2ecf20Sopenharmony_ci if (ret) { 4308c2ecf20Sopenharmony_ci dev_err(dd->dev, "can't configure OUT dmaengine slave: %d\n", 4318c2ecf20Sopenharmony_ci ret); 4328c2ecf20Sopenharmony_ci return ret; 4338c2ecf20Sopenharmony_ci } 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci tx_out = dmaengine_prep_slave_sg(dd->dma_lch_out, out_sg, out_sg_len, 4368c2ecf20Sopenharmony_ci DMA_DEV_TO_MEM, 4378c2ecf20Sopenharmony_ci DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 4388c2ecf20Sopenharmony_ci if (!tx_out) { 4398c2ecf20Sopenharmony_ci dev_err(dd->dev, "OUT prep_slave_sg() failed\n"); 4408c2ecf20Sopenharmony_ci return -EINVAL; 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci tx_out->callback = omap_des_dma_out_callback; 4448c2ecf20Sopenharmony_ci tx_out->callback_param = dd; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci dmaengine_submit(tx_in); 4478c2ecf20Sopenharmony_ci dmaengine_submit(tx_out); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci dma_async_issue_pending(dd->dma_lch_in); 4508c2ecf20Sopenharmony_ci dma_async_issue_pending(dd->dma_lch_out); 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci /* start DMA */ 4538c2ecf20Sopenharmony_ci dd->pdata->trigger(dd, dd->total); 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci return 0; 4568c2ecf20Sopenharmony_ci} 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_cistatic int omap_des_crypt_dma_start(struct omap_des_dev *dd) 4598c2ecf20Sopenharmony_ci{ 4608c2ecf20Sopenharmony_ci struct crypto_tfm *tfm = crypto_skcipher_tfm( 4618c2ecf20Sopenharmony_ci crypto_skcipher_reqtfm(dd->req)); 4628c2ecf20Sopenharmony_ci int err; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci pr_debug("total: %zd\n", dd->total); 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci if (!dd->pio_only) { 4678c2ecf20Sopenharmony_ci err = dma_map_sg(dd->dev, dd->in_sg, dd->in_sg_len, 4688c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 4698c2ecf20Sopenharmony_ci if (!err) { 4708c2ecf20Sopenharmony_ci dev_err(dd->dev, "dma_map_sg() error\n"); 4718c2ecf20Sopenharmony_ci return -EINVAL; 4728c2ecf20Sopenharmony_ci } 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci err = dma_map_sg(dd->dev, dd->out_sg, dd->out_sg_len, 4758c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 4768c2ecf20Sopenharmony_ci if (!err) { 4778c2ecf20Sopenharmony_ci dev_err(dd->dev, "dma_map_sg() error\n"); 4788c2ecf20Sopenharmony_ci return -EINVAL; 4798c2ecf20Sopenharmony_ci } 4808c2ecf20Sopenharmony_ci } 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci err = omap_des_crypt_dma(tfm, dd->in_sg, dd->out_sg, dd->in_sg_len, 4838c2ecf20Sopenharmony_ci dd->out_sg_len); 4848c2ecf20Sopenharmony_ci if (err && !dd->pio_only) { 4858c2ecf20Sopenharmony_ci dma_unmap_sg(dd->dev, dd->in_sg, dd->in_sg_len, DMA_TO_DEVICE); 4868c2ecf20Sopenharmony_ci dma_unmap_sg(dd->dev, dd->out_sg, dd->out_sg_len, 4878c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 4888c2ecf20Sopenharmony_ci } 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci return err; 4918c2ecf20Sopenharmony_ci} 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_cistatic void omap_des_finish_req(struct omap_des_dev *dd, int err) 4948c2ecf20Sopenharmony_ci{ 4958c2ecf20Sopenharmony_ci struct skcipher_request *req = dd->req; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci pr_debug("err: %d\n", err); 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci crypto_finalize_skcipher_request(dd->engine, req, err); 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(dd->dev); 5028c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(dd->dev); 5038c2ecf20Sopenharmony_ci} 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_cistatic int omap_des_crypt_dma_stop(struct omap_des_dev *dd) 5068c2ecf20Sopenharmony_ci{ 5078c2ecf20Sopenharmony_ci pr_debug("total: %zd\n", dd->total); 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci omap_des_dma_stop(dd); 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci dmaengine_terminate_all(dd->dma_lch_in); 5128c2ecf20Sopenharmony_ci dmaengine_terminate_all(dd->dma_lch_out); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci return 0; 5158c2ecf20Sopenharmony_ci} 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_cistatic int omap_des_handle_queue(struct omap_des_dev *dd, 5188c2ecf20Sopenharmony_ci struct skcipher_request *req) 5198c2ecf20Sopenharmony_ci{ 5208c2ecf20Sopenharmony_ci if (req) 5218c2ecf20Sopenharmony_ci return crypto_transfer_skcipher_request_to_engine(dd->engine, req); 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci return 0; 5248c2ecf20Sopenharmony_ci} 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_cistatic int omap_des_prepare_req(struct crypto_engine *engine, 5278c2ecf20Sopenharmony_ci void *areq) 5288c2ecf20Sopenharmony_ci{ 5298c2ecf20Sopenharmony_ci struct skcipher_request *req = container_of(areq, struct skcipher_request, base); 5308c2ecf20Sopenharmony_ci struct omap_des_ctx *ctx = crypto_skcipher_ctx( 5318c2ecf20Sopenharmony_ci crypto_skcipher_reqtfm(req)); 5328c2ecf20Sopenharmony_ci struct omap_des_dev *dd = omap_des_find_dev(ctx); 5338c2ecf20Sopenharmony_ci struct omap_des_reqctx *rctx; 5348c2ecf20Sopenharmony_ci int ret; 5358c2ecf20Sopenharmony_ci u16 flags; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci if (!dd) 5388c2ecf20Sopenharmony_ci return -ENODEV; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci /* assign new request to device */ 5418c2ecf20Sopenharmony_ci dd->req = req; 5428c2ecf20Sopenharmony_ci dd->total = req->cryptlen; 5438c2ecf20Sopenharmony_ci dd->total_save = req->cryptlen; 5448c2ecf20Sopenharmony_ci dd->in_sg = req->src; 5458c2ecf20Sopenharmony_ci dd->out_sg = req->dst; 5468c2ecf20Sopenharmony_ci dd->orig_out = req->dst; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci flags = OMAP_CRYPTO_COPY_DATA; 5498c2ecf20Sopenharmony_ci if (req->src == req->dst) 5508c2ecf20Sopenharmony_ci flags |= OMAP_CRYPTO_FORCE_COPY; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci ret = omap_crypto_align_sg(&dd->in_sg, dd->total, DES_BLOCK_SIZE, 5538c2ecf20Sopenharmony_ci &dd->in_sgl, flags, 5548c2ecf20Sopenharmony_ci FLAGS_IN_DATA_ST_SHIFT, &dd->flags); 5558c2ecf20Sopenharmony_ci if (ret) 5568c2ecf20Sopenharmony_ci return ret; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci ret = omap_crypto_align_sg(&dd->out_sg, dd->total, DES_BLOCK_SIZE, 5598c2ecf20Sopenharmony_ci &dd->out_sgl, 0, 5608c2ecf20Sopenharmony_ci FLAGS_OUT_DATA_ST_SHIFT, &dd->flags); 5618c2ecf20Sopenharmony_ci if (ret) 5628c2ecf20Sopenharmony_ci return ret; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci dd->in_sg_len = sg_nents_for_len(dd->in_sg, dd->total); 5658c2ecf20Sopenharmony_ci if (dd->in_sg_len < 0) 5668c2ecf20Sopenharmony_ci return dd->in_sg_len; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci dd->out_sg_len = sg_nents_for_len(dd->out_sg, dd->total); 5698c2ecf20Sopenharmony_ci if (dd->out_sg_len < 0) 5708c2ecf20Sopenharmony_ci return dd->out_sg_len; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci rctx = skcipher_request_ctx(req); 5738c2ecf20Sopenharmony_ci ctx = crypto_skcipher_ctx(crypto_skcipher_reqtfm(req)); 5748c2ecf20Sopenharmony_ci rctx->mode &= FLAGS_MODE_MASK; 5758c2ecf20Sopenharmony_ci dd->flags = (dd->flags & ~FLAGS_MODE_MASK) | rctx->mode; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci dd->ctx = ctx; 5788c2ecf20Sopenharmony_ci ctx->dd = dd; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci return omap_des_write_ctrl(dd); 5818c2ecf20Sopenharmony_ci} 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_cistatic int omap_des_crypt_req(struct crypto_engine *engine, 5848c2ecf20Sopenharmony_ci void *areq) 5858c2ecf20Sopenharmony_ci{ 5868c2ecf20Sopenharmony_ci struct skcipher_request *req = container_of(areq, struct skcipher_request, base); 5878c2ecf20Sopenharmony_ci struct omap_des_ctx *ctx = crypto_skcipher_ctx( 5888c2ecf20Sopenharmony_ci crypto_skcipher_reqtfm(req)); 5898c2ecf20Sopenharmony_ci struct omap_des_dev *dd = omap_des_find_dev(ctx); 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci if (!dd) 5928c2ecf20Sopenharmony_ci return -ENODEV; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci return omap_des_crypt_dma_start(dd); 5958c2ecf20Sopenharmony_ci} 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_cistatic void omap_des_done_task(unsigned long data) 5988c2ecf20Sopenharmony_ci{ 5998c2ecf20Sopenharmony_ci struct omap_des_dev *dd = (struct omap_des_dev *)data; 6008c2ecf20Sopenharmony_ci int i; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci pr_debug("enter done_task\n"); 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci if (!dd->pio_only) { 6058c2ecf20Sopenharmony_ci dma_sync_sg_for_device(dd->dev, dd->out_sg, dd->out_sg_len, 6068c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 6078c2ecf20Sopenharmony_ci dma_unmap_sg(dd->dev, dd->in_sg, dd->in_sg_len, DMA_TO_DEVICE); 6088c2ecf20Sopenharmony_ci dma_unmap_sg(dd->dev, dd->out_sg, dd->out_sg_len, 6098c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 6108c2ecf20Sopenharmony_ci omap_des_crypt_dma_stop(dd); 6118c2ecf20Sopenharmony_ci } 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci omap_crypto_cleanup(&dd->in_sgl, NULL, 0, dd->total_save, 6148c2ecf20Sopenharmony_ci FLAGS_IN_DATA_ST_SHIFT, dd->flags); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci omap_crypto_cleanup(&dd->out_sgl, dd->orig_out, 0, dd->total_save, 6178c2ecf20Sopenharmony_ci FLAGS_OUT_DATA_ST_SHIFT, dd->flags); 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci if ((dd->flags & FLAGS_CBC) && dd->req->iv) 6208c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) 6218c2ecf20Sopenharmony_ci ((u32 *)dd->req->iv)[i] = 6228c2ecf20Sopenharmony_ci omap_des_read(dd, DES_REG_IV(dd, i)); 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci omap_des_finish_req(dd, 0); 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci pr_debug("exit\n"); 6278c2ecf20Sopenharmony_ci} 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_cistatic int omap_des_crypt(struct skcipher_request *req, unsigned long mode) 6308c2ecf20Sopenharmony_ci{ 6318c2ecf20Sopenharmony_ci struct omap_des_ctx *ctx = crypto_skcipher_ctx( 6328c2ecf20Sopenharmony_ci crypto_skcipher_reqtfm(req)); 6338c2ecf20Sopenharmony_ci struct omap_des_reqctx *rctx = skcipher_request_ctx(req); 6348c2ecf20Sopenharmony_ci struct omap_des_dev *dd; 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci pr_debug("nbytes: %d, enc: %d, cbc: %d\n", req->cryptlen, 6378c2ecf20Sopenharmony_ci !!(mode & FLAGS_ENCRYPT), 6388c2ecf20Sopenharmony_ci !!(mode & FLAGS_CBC)); 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci if (!req->cryptlen) 6418c2ecf20Sopenharmony_ci return 0; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci if (!IS_ALIGNED(req->cryptlen, DES_BLOCK_SIZE)) 6448c2ecf20Sopenharmony_ci return -EINVAL; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci dd = omap_des_find_dev(ctx); 6478c2ecf20Sopenharmony_ci if (!dd) 6488c2ecf20Sopenharmony_ci return -ENODEV; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci rctx->mode = mode; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci return omap_des_handle_queue(dd, req); 6538c2ecf20Sopenharmony_ci} 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci/* ********************** ALG API ************************************ */ 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_cistatic int omap_des_setkey(struct crypto_skcipher *cipher, const u8 *key, 6588c2ecf20Sopenharmony_ci unsigned int keylen) 6598c2ecf20Sopenharmony_ci{ 6608c2ecf20Sopenharmony_ci struct omap_des_ctx *ctx = crypto_skcipher_ctx(cipher); 6618c2ecf20Sopenharmony_ci int err; 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci pr_debug("enter, keylen: %d\n", keylen); 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci err = verify_skcipher_des_key(cipher, key); 6668c2ecf20Sopenharmony_ci if (err) 6678c2ecf20Sopenharmony_ci return err; 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci memcpy(ctx->key, key, keylen); 6708c2ecf20Sopenharmony_ci ctx->keylen = keylen; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci return 0; 6738c2ecf20Sopenharmony_ci} 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_cistatic int omap_des3_setkey(struct crypto_skcipher *cipher, const u8 *key, 6768c2ecf20Sopenharmony_ci unsigned int keylen) 6778c2ecf20Sopenharmony_ci{ 6788c2ecf20Sopenharmony_ci struct omap_des_ctx *ctx = crypto_skcipher_ctx(cipher); 6798c2ecf20Sopenharmony_ci int err; 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci pr_debug("enter, keylen: %d\n", keylen); 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci err = verify_skcipher_des3_key(cipher, key); 6848c2ecf20Sopenharmony_ci if (err) 6858c2ecf20Sopenharmony_ci return err; 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci memcpy(ctx->key, key, keylen); 6888c2ecf20Sopenharmony_ci ctx->keylen = keylen; 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci return 0; 6918c2ecf20Sopenharmony_ci} 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_cistatic int omap_des_ecb_encrypt(struct skcipher_request *req) 6948c2ecf20Sopenharmony_ci{ 6958c2ecf20Sopenharmony_ci return omap_des_crypt(req, FLAGS_ENCRYPT); 6968c2ecf20Sopenharmony_ci} 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_cistatic int omap_des_ecb_decrypt(struct skcipher_request *req) 6998c2ecf20Sopenharmony_ci{ 7008c2ecf20Sopenharmony_ci return omap_des_crypt(req, 0); 7018c2ecf20Sopenharmony_ci} 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_cistatic int omap_des_cbc_encrypt(struct skcipher_request *req) 7048c2ecf20Sopenharmony_ci{ 7058c2ecf20Sopenharmony_ci return omap_des_crypt(req, FLAGS_ENCRYPT | FLAGS_CBC); 7068c2ecf20Sopenharmony_ci} 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_cistatic int omap_des_cbc_decrypt(struct skcipher_request *req) 7098c2ecf20Sopenharmony_ci{ 7108c2ecf20Sopenharmony_ci return omap_des_crypt(req, FLAGS_CBC); 7118c2ecf20Sopenharmony_ci} 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_cistatic int omap_des_prepare_req(struct crypto_engine *engine, 7148c2ecf20Sopenharmony_ci void *areq); 7158c2ecf20Sopenharmony_cistatic int omap_des_crypt_req(struct crypto_engine *engine, 7168c2ecf20Sopenharmony_ci void *areq); 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_cistatic int omap_des_init_tfm(struct crypto_skcipher *tfm) 7198c2ecf20Sopenharmony_ci{ 7208c2ecf20Sopenharmony_ci struct omap_des_ctx *ctx = crypto_skcipher_ctx(tfm); 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci pr_debug("enter\n"); 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci crypto_skcipher_set_reqsize(tfm, sizeof(struct omap_des_reqctx)); 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci ctx->enginectx.op.prepare_request = omap_des_prepare_req; 7278c2ecf20Sopenharmony_ci ctx->enginectx.op.unprepare_request = NULL; 7288c2ecf20Sopenharmony_ci ctx->enginectx.op.do_one_request = omap_des_crypt_req; 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci return 0; 7318c2ecf20Sopenharmony_ci} 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci/* ********************** ALGS ************************************ */ 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_cistatic struct skcipher_alg algs_ecb_cbc[] = { 7368c2ecf20Sopenharmony_ci{ 7378c2ecf20Sopenharmony_ci .base.cra_name = "ecb(des)", 7388c2ecf20Sopenharmony_ci .base.cra_driver_name = "ecb-des-omap", 7398c2ecf20Sopenharmony_ci .base.cra_priority = 100, 7408c2ecf20Sopenharmony_ci .base.cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | 7418c2ecf20Sopenharmony_ci CRYPTO_ALG_ASYNC, 7428c2ecf20Sopenharmony_ci .base.cra_blocksize = DES_BLOCK_SIZE, 7438c2ecf20Sopenharmony_ci .base.cra_ctxsize = sizeof(struct omap_des_ctx), 7448c2ecf20Sopenharmony_ci .base.cra_module = THIS_MODULE, 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci .min_keysize = DES_KEY_SIZE, 7478c2ecf20Sopenharmony_ci .max_keysize = DES_KEY_SIZE, 7488c2ecf20Sopenharmony_ci .setkey = omap_des_setkey, 7498c2ecf20Sopenharmony_ci .encrypt = omap_des_ecb_encrypt, 7508c2ecf20Sopenharmony_ci .decrypt = omap_des_ecb_decrypt, 7518c2ecf20Sopenharmony_ci .init = omap_des_init_tfm, 7528c2ecf20Sopenharmony_ci}, 7538c2ecf20Sopenharmony_ci{ 7548c2ecf20Sopenharmony_ci .base.cra_name = "cbc(des)", 7558c2ecf20Sopenharmony_ci .base.cra_driver_name = "cbc-des-omap", 7568c2ecf20Sopenharmony_ci .base.cra_priority = 100, 7578c2ecf20Sopenharmony_ci .base.cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | 7588c2ecf20Sopenharmony_ci CRYPTO_ALG_ASYNC, 7598c2ecf20Sopenharmony_ci .base.cra_blocksize = DES_BLOCK_SIZE, 7608c2ecf20Sopenharmony_ci .base.cra_ctxsize = sizeof(struct omap_des_ctx), 7618c2ecf20Sopenharmony_ci .base.cra_module = THIS_MODULE, 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci .min_keysize = DES_KEY_SIZE, 7648c2ecf20Sopenharmony_ci .max_keysize = DES_KEY_SIZE, 7658c2ecf20Sopenharmony_ci .ivsize = DES_BLOCK_SIZE, 7668c2ecf20Sopenharmony_ci .setkey = omap_des_setkey, 7678c2ecf20Sopenharmony_ci .encrypt = omap_des_cbc_encrypt, 7688c2ecf20Sopenharmony_ci .decrypt = omap_des_cbc_decrypt, 7698c2ecf20Sopenharmony_ci .init = omap_des_init_tfm, 7708c2ecf20Sopenharmony_ci}, 7718c2ecf20Sopenharmony_ci{ 7728c2ecf20Sopenharmony_ci .base.cra_name = "ecb(des3_ede)", 7738c2ecf20Sopenharmony_ci .base.cra_driver_name = "ecb-des3-omap", 7748c2ecf20Sopenharmony_ci .base.cra_priority = 100, 7758c2ecf20Sopenharmony_ci .base.cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | 7768c2ecf20Sopenharmony_ci CRYPTO_ALG_ASYNC, 7778c2ecf20Sopenharmony_ci .base.cra_blocksize = DES3_EDE_BLOCK_SIZE, 7788c2ecf20Sopenharmony_ci .base.cra_ctxsize = sizeof(struct omap_des_ctx), 7798c2ecf20Sopenharmony_ci .base.cra_module = THIS_MODULE, 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci .min_keysize = DES3_EDE_KEY_SIZE, 7828c2ecf20Sopenharmony_ci .max_keysize = DES3_EDE_KEY_SIZE, 7838c2ecf20Sopenharmony_ci .setkey = omap_des3_setkey, 7848c2ecf20Sopenharmony_ci .encrypt = omap_des_ecb_encrypt, 7858c2ecf20Sopenharmony_ci .decrypt = omap_des_ecb_decrypt, 7868c2ecf20Sopenharmony_ci .init = omap_des_init_tfm, 7878c2ecf20Sopenharmony_ci}, 7888c2ecf20Sopenharmony_ci{ 7898c2ecf20Sopenharmony_ci .base.cra_name = "cbc(des3_ede)", 7908c2ecf20Sopenharmony_ci .base.cra_driver_name = "cbc-des3-omap", 7918c2ecf20Sopenharmony_ci .base.cra_priority = 100, 7928c2ecf20Sopenharmony_ci .base.cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | 7938c2ecf20Sopenharmony_ci CRYPTO_ALG_ASYNC, 7948c2ecf20Sopenharmony_ci .base.cra_blocksize = DES3_EDE_BLOCK_SIZE, 7958c2ecf20Sopenharmony_ci .base.cra_ctxsize = sizeof(struct omap_des_ctx), 7968c2ecf20Sopenharmony_ci .base.cra_module = THIS_MODULE, 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci .min_keysize = DES3_EDE_KEY_SIZE, 7998c2ecf20Sopenharmony_ci .max_keysize = DES3_EDE_KEY_SIZE, 8008c2ecf20Sopenharmony_ci .ivsize = DES3_EDE_BLOCK_SIZE, 8018c2ecf20Sopenharmony_ci .setkey = omap_des3_setkey, 8028c2ecf20Sopenharmony_ci .encrypt = omap_des_cbc_encrypt, 8038c2ecf20Sopenharmony_ci .decrypt = omap_des_cbc_decrypt, 8048c2ecf20Sopenharmony_ci .init = omap_des_init_tfm, 8058c2ecf20Sopenharmony_ci} 8068c2ecf20Sopenharmony_ci}; 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_cistatic struct omap_des_algs_info omap_des_algs_info_ecb_cbc[] = { 8098c2ecf20Sopenharmony_ci { 8108c2ecf20Sopenharmony_ci .algs_list = algs_ecb_cbc, 8118c2ecf20Sopenharmony_ci .size = ARRAY_SIZE(algs_ecb_cbc), 8128c2ecf20Sopenharmony_ci }, 8138c2ecf20Sopenharmony_ci}; 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci#ifdef CONFIG_OF 8168c2ecf20Sopenharmony_cistatic const struct omap_des_pdata omap_des_pdata_omap4 = { 8178c2ecf20Sopenharmony_ci .algs_info = omap_des_algs_info_ecb_cbc, 8188c2ecf20Sopenharmony_ci .algs_info_size = ARRAY_SIZE(omap_des_algs_info_ecb_cbc), 8198c2ecf20Sopenharmony_ci .trigger = omap_des_dma_trigger_omap4, 8208c2ecf20Sopenharmony_ci .key_ofs = 0x14, 8218c2ecf20Sopenharmony_ci .iv_ofs = 0x18, 8228c2ecf20Sopenharmony_ci .ctrl_ofs = 0x20, 8238c2ecf20Sopenharmony_ci .data_ofs = 0x28, 8248c2ecf20Sopenharmony_ci .rev_ofs = 0x30, 8258c2ecf20Sopenharmony_ci .mask_ofs = 0x34, 8268c2ecf20Sopenharmony_ci .irq_status_ofs = 0x3c, 8278c2ecf20Sopenharmony_ci .irq_enable_ofs = 0x40, 8288c2ecf20Sopenharmony_ci .dma_enable_in = BIT(5), 8298c2ecf20Sopenharmony_ci .dma_enable_out = BIT(6), 8308c2ecf20Sopenharmony_ci .major_mask = 0x0700, 8318c2ecf20Sopenharmony_ci .major_shift = 8, 8328c2ecf20Sopenharmony_ci .minor_mask = 0x003f, 8338c2ecf20Sopenharmony_ci .minor_shift = 0, 8348c2ecf20Sopenharmony_ci}; 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_cistatic irqreturn_t omap_des_irq(int irq, void *dev_id) 8378c2ecf20Sopenharmony_ci{ 8388c2ecf20Sopenharmony_ci struct omap_des_dev *dd = dev_id; 8398c2ecf20Sopenharmony_ci u32 status, i; 8408c2ecf20Sopenharmony_ci u32 *src, *dst; 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci status = omap_des_read(dd, DES_REG_IRQ_STATUS(dd)); 8438c2ecf20Sopenharmony_ci if (status & DES_REG_IRQ_DATA_IN) { 8448c2ecf20Sopenharmony_ci omap_des_write(dd, DES_REG_IRQ_ENABLE(dd), 0x0); 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci BUG_ON(!dd->in_sg); 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci BUG_ON(_calc_walked(in) > dd->in_sg->length); 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci src = sg_virt(dd->in_sg) + _calc_walked(in); 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci for (i = 0; i < DES_BLOCK_WORDS; i++) { 8538c2ecf20Sopenharmony_ci omap_des_write(dd, DES_REG_DATA_N(dd, i), *src); 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci scatterwalk_advance(&dd->in_walk, 4); 8568c2ecf20Sopenharmony_ci if (dd->in_sg->length == _calc_walked(in)) { 8578c2ecf20Sopenharmony_ci dd->in_sg = sg_next(dd->in_sg); 8588c2ecf20Sopenharmony_ci if (dd->in_sg) { 8598c2ecf20Sopenharmony_ci scatterwalk_start(&dd->in_walk, 8608c2ecf20Sopenharmony_ci dd->in_sg); 8618c2ecf20Sopenharmony_ci src = sg_virt(dd->in_sg) + 8628c2ecf20Sopenharmony_ci _calc_walked(in); 8638c2ecf20Sopenharmony_ci } 8648c2ecf20Sopenharmony_ci } else { 8658c2ecf20Sopenharmony_ci src++; 8668c2ecf20Sopenharmony_ci } 8678c2ecf20Sopenharmony_ci } 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci /* Clear IRQ status */ 8708c2ecf20Sopenharmony_ci status &= ~DES_REG_IRQ_DATA_IN; 8718c2ecf20Sopenharmony_ci omap_des_write(dd, DES_REG_IRQ_STATUS(dd), status); 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci /* Enable DATA_OUT interrupt */ 8748c2ecf20Sopenharmony_ci omap_des_write(dd, DES_REG_IRQ_ENABLE(dd), 0x4); 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci } else if (status & DES_REG_IRQ_DATA_OUT) { 8778c2ecf20Sopenharmony_ci omap_des_write(dd, DES_REG_IRQ_ENABLE(dd), 0x0); 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci BUG_ON(!dd->out_sg); 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci BUG_ON(_calc_walked(out) > dd->out_sg->length); 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci dst = sg_virt(dd->out_sg) + _calc_walked(out); 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci for (i = 0; i < DES_BLOCK_WORDS; i++) { 8868c2ecf20Sopenharmony_ci *dst = omap_des_read(dd, DES_REG_DATA_N(dd, i)); 8878c2ecf20Sopenharmony_ci scatterwalk_advance(&dd->out_walk, 4); 8888c2ecf20Sopenharmony_ci if (dd->out_sg->length == _calc_walked(out)) { 8898c2ecf20Sopenharmony_ci dd->out_sg = sg_next(dd->out_sg); 8908c2ecf20Sopenharmony_ci if (dd->out_sg) { 8918c2ecf20Sopenharmony_ci scatterwalk_start(&dd->out_walk, 8928c2ecf20Sopenharmony_ci dd->out_sg); 8938c2ecf20Sopenharmony_ci dst = sg_virt(dd->out_sg) + 8948c2ecf20Sopenharmony_ci _calc_walked(out); 8958c2ecf20Sopenharmony_ci } 8968c2ecf20Sopenharmony_ci } else { 8978c2ecf20Sopenharmony_ci dst++; 8988c2ecf20Sopenharmony_ci } 8998c2ecf20Sopenharmony_ci } 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci BUG_ON(dd->total < DES_BLOCK_SIZE); 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci dd->total -= DES_BLOCK_SIZE; 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci /* Clear IRQ status */ 9068c2ecf20Sopenharmony_ci status &= ~DES_REG_IRQ_DATA_OUT; 9078c2ecf20Sopenharmony_ci omap_des_write(dd, DES_REG_IRQ_STATUS(dd), status); 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci if (!dd->total) 9108c2ecf20Sopenharmony_ci /* All bytes read! */ 9118c2ecf20Sopenharmony_ci tasklet_schedule(&dd->done_task); 9128c2ecf20Sopenharmony_ci else 9138c2ecf20Sopenharmony_ci /* Enable DATA_IN interrupt for next block */ 9148c2ecf20Sopenharmony_ci omap_des_write(dd, DES_REG_IRQ_ENABLE(dd), 0x2); 9158c2ecf20Sopenharmony_ci } 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci return IRQ_HANDLED; 9188c2ecf20Sopenharmony_ci} 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_cistatic const struct of_device_id omap_des_of_match[] = { 9218c2ecf20Sopenharmony_ci { 9228c2ecf20Sopenharmony_ci .compatible = "ti,omap4-des", 9238c2ecf20Sopenharmony_ci .data = &omap_des_pdata_omap4, 9248c2ecf20Sopenharmony_ci }, 9258c2ecf20Sopenharmony_ci {}, 9268c2ecf20Sopenharmony_ci}; 9278c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, omap_des_of_match); 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_cistatic int omap_des_get_of(struct omap_des_dev *dd, 9308c2ecf20Sopenharmony_ci struct platform_device *pdev) 9318c2ecf20Sopenharmony_ci{ 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci dd->pdata = of_device_get_match_data(&pdev->dev); 9348c2ecf20Sopenharmony_ci if (!dd->pdata) { 9358c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "no compatible OF match\n"); 9368c2ecf20Sopenharmony_ci return -EINVAL; 9378c2ecf20Sopenharmony_ci } 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci return 0; 9408c2ecf20Sopenharmony_ci} 9418c2ecf20Sopenharmony_ci#else 9428c2ecf20Sopenharmony_cistatic int omap_des_get_of(struct omap_des_dev *dd, 9438c2ecf20Sopenharmony_ci struct device *dev) 9448c2ecf20Sopenharmony_ci{ 9458c2ecf20Sopenharmony_ci return -EINVAL; 9468c2ecf20Sopenharmony_ci} 9478c2ecf20Sopenharmony_ci#endif 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_cistatic int omap_des_get_pdev(struct omap_des_dev *dd, 9508c2ecf20Sopenharmony_ci struct platform_device *pdev) 9518c2ecf20Sopenharmony_ci{ 9528c2ecf20Sopenharmony_ci /* non-DT devices get pdata from pdev */ 9538c2ecf20Sopenharmony_ci dd->pdata = pdev->dev.platform_data; 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci return 0; 9568c2ecf20Sopenharmony_ci} 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_cistatic int omap_des_probe(struct platform_device *pdev) 9598c2ecf20Sopenharmony_ci{ 9608c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 9618c2ecf20Sopenharmony_ci struct omap_des_dev *dd; 9628c2ecf20Sopenharmony_ci struct skcipher_alg *algp; 9638c2ecf20Sopenharmony_ci struct resource *res; 9648c2ecf20Sopenharmony_ci int err = -ENOMEM, i, j, irq = -1; 9658c2ecf20Sopenharmony_ci u32 reg; 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci dd = devm_kzalloc(dev, sizeof(struct omap_des_dev), GFP_KERNEL); 9688c2ecf20Sopenharmony_ci if (dd == NULL) { 9698c2ecf20Sopenharmony_ci dev_err(dev, "unable to alloc data struct.\n"); 9708c2ecf20Sopenharmony_ci goto err_data; 9718c2ecf20Sopenharmony_ci } 9728c2ecf20Sopenharmony_ci dd->dev = dev; 9738c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, dd); 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 9768c2ecf20Sopenharmony_ci if (!res) { 9778c2ecf20Sopenharmony_ci dev_err(dev, "no MEM resource info\n"); 9788c2ecf20Sopenharmony_ci goto err_res; 9798c2ecf20Sopenharmony_ci } 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci err = (dev->of_node) ? omap_des_get_of(dd, pdev) : 9828c2ecf20Sopenharmony_ci omap_des_get_pdev(dd, pdev); 9838c2ecf20Sopenharmony_ci if (err) 9848c2ecf20Sopenharmony_ci goto err_res; 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci dd->io_base = devm_ioremap_resource(dev, res); 9878c2ecf20Sopenharmony_ci if (IS_ERR(dd->io_base)) { 9888c2ecf20Sopenharmony_ci err = PTR_ERR(dd->io_base); 9898c2ecf20Sopenharmony_ci goto err_res; 9908c2ecf20Sopenharmony_ci } 9918c2ecf20Sopenharmony_ci dd->phys_base = res->start; 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci pm_runtime_use_autosuspend(dev); 9948c2ecf20Sopenharmony_ci pm_runtime_set_autosuspend_delay(dev, DEFAULT_AUTOSUSPEND_DELAY); 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci pm_runtime_enable(dev); 9978c2ecf20Sopenharmony_ci err = pm_runtime_get_sync(dev); 9988c2ecf20Sopenharmony_ci if (err < 0) { 9998c2ecf20Sopenharmony_ci pm_runtime_put_noidle(dev); 10008c2ecf20Sopenharmony_ci dev_err(dd->dev, "%s: failed to get_sync(%d)\n", __func__, err); 10018c2ecf20Sopenharmony_ci goto err_get; 10028c2ecf20Sopenharmony_ci } 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci omap_des_dma_stop(dd); 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci reg = omap_des_read(dd, DES_REG_REV(dd)); 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci pm_runtime_put_sync(dev); 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci dev_info(dev, "OMAP DES hw accel rev: %u.%u\n", 10118c2ecf20Sopenharmony_ci (reg & dd->pdata->major_mask) >> dd->pdata->major_shift, 10128c2ecf20Sopenharmony_ci (reg & dd->pdata->minor_mask) >> dd->pdata->minor_shift); 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci tasklet_init(&dd->done_task, omap_des_done_task, (unsigned long)dd); 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci err = omap_des_dma_init(dd); 10178c2ecf20Sopenharmony_ci if (err == -EPROBE_DEFER) { 10188c2ecf20Sopenharmony_ci goto err_irq; 10198c2ecf20Sopenharmony_ci } else if (err && DES_REG_IRQ_STATUS(dd) && DES_REG_IRQ_ENABLE(dd)) { 10208c2ecf20Sopenharmony_ci dd->pio_only = 1; 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci irq = platform_get_irq(pdev, 0); 10238c2ecf20Sopenharmony_ci if (irq < 0) { 10248c2ecf20Sopenharmony_ci err = irq; 10258c2ecf20Sopenharmony_ci goto err_irq; 10268c2ecf20Sopenharmony_ci } 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci err = devm_request_irq(dev, irq, omap_des_irq, 0, 10298c2ecf20Sopenharmony_ci dev_name(dev), dd); 10308c2ecf20Sopenharmony_ci if (err) { 10318c2ecf20Sopenharmony_ci dev_err(dev, "Unable to grab omap-des IRQ\n"); 10328c2ecf20Sopenharmony_ci goto err_irq; 10338c2ecf20Sopenharmony_ci } 10348c2ecf20Sopenharmony_ci } 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dd->list); 10388c2ecf20Sopenharmony_ci spin_lock_bh(&list_lock); 10398c2ecf20Sopenharmony_ci list_add_tail(&dd->list, &dev_list); 10408c2ecf20Sopenharmony_ci spin_unlock_bh(&list_lock); 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci /* Initialize des crypto engine */ 10438c2ecf20Sopenharmony_ci dd->engine = crypto_engine_alloc_init(dev, 1); 10448c2ecf20Sopenharmony_ci if (!dd->engine) { 10458c2ecf20Sopenharmony_ci err = -ENOMEM; 10468c2ecf20Sopenharmony_ci goto err_engine; 10478c2ecf20Sopenharmony_ci } 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci err = crypto_engine_start(dd->engine); 10508c2ecf20Sopenharmony_ci if (err) 10518c2ecf20Sopenharmony_ci goto err_engine; 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci for (i = 0; i < dd->pdata->algs_info_size; i++) { 10548c2ecf20Sopenharmony_ci for (j = 0; j < dd->pdata->algs_info[i].size; j++) { 10558c2ecf20Sopenharmony_ci algp = &dd->pdata->algs_info[i].algs_list[j]; 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci pr_debug("reg alg: %s\n", algp->base.cra_name); 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci err = crypto_register_skcipher(algp); 10608c2ecf20Sopenharmony_ci if (err) 10618c2ecf20Sopenharmony_ci goto err_algs; 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci dd->pdata->algs_info[i].registered++; 10648c2ecf20Sopenharmony_ci } 10658c2ecf20Sopenharmony_ci } 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci return 0; 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_cierr_algs: 10708c2ecf20Sopenharmony_ci for (i = dd->pdata->algs_info_size - 1; i >= 0; i--) 10718c2ecf20Sopenharmony_ci for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--) 10728c2ecf20Sopenharmony_ci crypto_unregister_skcipher( 10738c2ecf20Sopenharmony_ci &dd->pdata->algs_info[i].algs_list[j]); 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_cierr_engine: 10768c2ecf20Sopenharmony_ci if (dd->engine) 10778c2ecf20Sopenharmony_ci crypto_engine_exit(dd->engine); 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci omap_des_dma_cleanup(dd); 10808c2ecf20Sopenharmony_cierr_irq: 10818c2ecf20Sopenharmony_ci tasklet_kill(&dd->done_task); 10828c2ecf20Sopenharmony_cierr_get: 10838c2ecf20Sopenharmony_ci pm_runtime_disable(dev); 10848c2ecf20Sopenharmony_cierr_res: 10858c2ecf20Sopenharmony_ci dd = NULL; 10868c2ecf20Sopenharmony_cierr_data: 10878c2ecf20Sopenharmony_ci dev_err(dev, "initialization failed.\n"); 10888c2ecf20Sopenharmony_ci return err; 10898c2ecf20Sopenharmony_ci} 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_cistatic int omap_des_remove(struct platform_device *pdev) 10928c2ecf20Sopenharmony_ci{ 10938c2ecf20Sopenharmony_ci struct omap_des_dev *dd = platform_get_drvdata(pdev); 10948c2ecf20Sopenharmony_ci int i, j; 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci if (!dd) 10978c2ecf20Sopenharmony_ci return -ENODEV; 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci spin_lock_bh(&list_lock); 11008c2ecf20Sopenharmony_ci list_del(&dd->list); 11018c2ecf20Sopenharmony_ci spin_unlock_bh(&list_lock); 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci for (i = dd->pdata->algs_info_size - 1; i >= 0; i--) 11048c2ecf20Sopenharmony_ci for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--) 11058c2ecf20Sopenharmony_ci crypto_unregister_skcipher( 11068c2ecf20Sopenharmony_ci &dd->pdata->algs_info[i].algs_list[j]); 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci tasklet_kill(&dd->done_task); 11098c2ecf20Sopenharmony_ci omap_des_dma_cleanup(dd); 11108c2ecf20Sopenharmony_ci pm_runtime_disable(dd->dev); 11118c2ecf20Sopenharmony_ci dd = NULL; 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci return 0; 11148c2ecf20Sopenharmony_ci} 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 11178c2ecf20Sopenharmony_cistatic int omap_des_suspend(struct device *dev) 11188c2ecf20Sopenharmony_ci{ 11198c2ecf20Sopenharmony_ci pm_runtime_put_sync(dev); 11208c2ecf20Sopenharmony_ci return 0; 11218c2ecf20Sopenharmony_ci} 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_cistatic int omap_des_resume(struct device *dev) 11248c2ecf20Sopenharmony_ci{ 11258c2ecf20Sopenharmony_ci int err; 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci err = pm_runtime_get_sync(dev); 11288c2ecf20Sopenharmony_ci if (err < 0) { 11298c2ecf20Sopenharmony_ci pm_runtime_put_noidle(dev); 11308c2ecf20Sopenharmony_ci dev_err(dev, "%s: failed to get_sync(%d)\n", __func__, err); 11318c2ecf20Sopenharmony_ci return err; 11328c2ecf20Sopenharmony_ci } 11338c2ecf20Sopenharmony_ci return 0; 11348c2ecf20Sopenharmony_ci} 11358c2ecf20Sopenharmony_ci#endif 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(omap_des_pm_ops, omap_des_suspend, omap_des_resume); 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_cistatic struct platform_driver omap_des_driver = { 11408c2ecf20Sopenharmony_ci .probe = omap_des_probe, 11418c2ecf20Sopenharmony_ci .remove = omap_des_remove, 11428c2ecf20Sopenharmony_ci .driver = { 11438c2ecf20Sopenharmony_ci .name = "omap-des", 11448c2ecf20Sopenharmony_ci .pm = &omap_des_pm_ops, 11458c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(omap_des_of_match), 11468c2ecf20Sopenharmony_ci }, 11478c2ecf20Sopenharmony_ci}; 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_cimodule_platform_driver(omap_des_driver); 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("OMAP DES hw acceleration support."); 11528c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 11538c2ecf20Sopenharmony_ciMODULE_AUTHOR("Joel Fernandes <joelf@ti.com>"); 1154