1537559a5SDmitry Kasatkin /* 2537559a5SDmitry Kasatkin * Cryptographic API. 3537559a5SDmitry Kasatkin * 4537559a5SDmitry Kasatkin * Support for OMAP AES HW acceleration. 5537559a5SDmitry Kasatkin * 6537559a5SDmitry Kasatkin * Copyright (c) 2010 Nokia Corporation 7537559a5SDmitry Kasatkin * Author: Dmitry Kasatkin <dmitry.kasatkin@nokia.com> 80d35583aSMark A. Greer * Copyright (c) 2011 Texas Instruments Incorporated 9537559a5SDmitry Kasatkin * 10537559a5SDmitry Kasatkin * This program is free software; you can redistribute it and/or modify 11537559a5SDmitry Kasatkin * it under the terms of the GNU General Public License version 2 as published 12537559a5SDmitry Kasatkin * by the Free Software Foundation. 13537559a5SDmitry Kasatkin * 14537559a5SDmitry Kasatkin */ 15537559a5SDmitry Kasatkin 16016af9b5SJoel Fernandes #define pr_fmt(fmt) "%20s: " fmt, __func__ 17016af9b5SJoel Fernandes #define prn(num) pr_debug(#num "=%d\n", num) 18016af9b5SJoel Fernandes #define prx(num) pr_debug(#num "=%x\n", num) 19537559a5SDmitry Kasatkin 20537559a5SDmitry Kasatkin #include <linux/err.h> 21537559a5SDmitry Kasatkin #include <linux/module.h> 22537559a5SDmitry Kasatkin #include <linux/init.h> 23537559a5SDmitry Kasatkin #include <linux/errno.h> 24537559a5SDmitry Kasatkin #include <linux/kernel.h> 25537559a5SDmitry Kasatkin #include <linux/platform_device.h> 26537559a5SDmitry Kasatkin #include <linux/scatterlist.h> 27537559a5SDmitry Kasatkin #include <linux/dma-mapping.h> 28ebedbf79SMark A. Greer #include <linux/dmaengine.h> 29ebedbf79SMark A. Greer #include <linux/omap-dma.h> 305946c4a5SMark A. Greer #include <linux/pm_runtime.h> 31bc69d124SMark A. Greer #include <linux/of.h> 32bc69d124SMark A. Greer #include <linux/of_device.h> 33bc69d124SMark A. Greer #include <linux/of_address.h> 34537559a5SDmitry Kasatkin #include <linux/io.h> 35537559a5SDmitry Kasatkin #include <linux/crypto.h> 36537559a5SDmitry Kasatkin #include <linux/interrupt.h> 37537559a5SDmitry Kasatkin #include <crypto/scatterwalk.h> 38537559a5SDmitry Kasatkin #include <crypto/aes.h> 39537559a5SDmitry Kasatkin 40ebedbf79SMark A. Greer #define DST_MAXBURST 4 41ebedbf79SMark A. Greer #define DMA_MIN (DST_MAXBURST * sizeof(u32)) 42537559a5SDmitry Kasatkin 43537559a5SDmitry Kasatkin /* OMAP TRM gives bitfields as start:end, where start is the higher bit 44537559a5SDmitry Kasatkin number. For example 7:0 */ 45537559a5SDmitry Kasatkin #define FLD_MASK(start, end) (((1 << ((start) - (end) + 1)) - 1) << (end)) 46537559a5SDmitry Kasatkin #define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end)) 47537559a5SDmitry Kasatkin 480d35583aSMark A. Greer #define AES_REG_KEY(dd, x) ((dd)->pdata->key_ofs - \ 490d35583aSMark A. Greer ((x ^ 0x01) * 0x04)) 500d35583aSMark A. Greer #define AES_REG_IV(dd, x) ((dd)->pdata->iv_ofs + ((x) * 0x04)) 51537559a5SDmitry Kasatkin 520d35583aSMark A. Greer #define AES_REG_CTRL(dd) ((dd)->pdata->ctrl_ofs) 53f9fb69e7SMark A. Greer #define AES_REG_CTRL_CTR_WIDTH_MASK (3 << 7) 54f9fb69e7SMark A. Greer #define AES_REG_CTRL_CTR_WIDTH_32 (0 << 7) 55f9fb69e7SMark A. Greer #define AES_REG_CTRL_CTR_WIDTH_64 (1 << 7) 56f9fb69e7SMark A. Greer #define AES_REG_CTRL_CTR_WIDTH_96 (2 << 7) 57f9fb69e7SMark A. Greer #define AES_REG_CTRL_CTR_WIDTH_128 (3 << 7) 58537559a5SDmitry Kasatkin #define AES_REG_CTRL_CTR (1 << 6) 59537559a5SDmitry Kasatkin #define AES_REG_CTRL_CBC (1 << 5) 60537559a5SDmitry Kasatkin #define AES_REG_CTRL_KEY_SIZE (3 << 3) 61537559a5SDmitry Kasatkin #define AES_REG_CTRL_DIRECTION (1 << 2) 62537559a5SDmitry Kasatkin #define AES_REG_CTRL_INPUT_READY (1 << 1) 63537559a5SDmitry Kasatkin #define AES_REG_CTRL_OUTPUT_READY (1 << 0) 64537559a5SDmitry Kasatkin 650d35583aSMark A. Greer #define AES_REG_DATA_N(dd, x) ((dd)->pdata->data_ofs + ((x) * 0x04)) 66537559a5SDmitry Kasatkin 670d35583aSMark A. Greer #define AES_REG_REV(dd) ((dd)->pdata->rev_ofs) 68537559a5SDmitry Kasatkin 690d35583aSMark A. Greer #define AES_REG_MASK(dd) ((dd)->pdata->mask_ofs) 70537559a5SDmitry Kasatkin #define AES_REG_MASK_SIDLE (1 << 6) 71537559a5SDmitry Kasatkin #define AES_REG_MASK_START (1 << 5) 72537559a5SDmitry Kasatkin #define AES_REG_MASK_DMA_OUT_EN (1 << 3) 73537559a5SDmitry Kasatkin #define AES_REG_MASK_DMA_IN_EN (1 << 2) 74537559a5SDmitry Kasatkin #define AES_REG_MASK_SOFTRESET (1 << 1) 75537559a5SDmitry Kasatkin #define AES_REG_AUTOIDLE (1 << 0) 76537559a5SDmitry Kasatkin 770d35583aSMark A. Greer #define AES_REG_LENGTH_N(x) (0x54 + ((x) * 0x04)) 78537559a5SDmitry Kasatkin 79537559a5SDmitry Kasatkin #define DEFAULT_TIMEOUT (5*HZ) 80537559a5SDmitry Kasatkin 81537559a5SDmitry Kasatkin #define FLAGS_MODE_MASK 0x000f 82537559a5SDmitry Kasatkin #define FLAGS_ENCRYPT BIT(0) 83537559a5SDmitry Kasatkin #define FLAGS_CBC BIT(1) 84537559a5SDmitry Kasatkin #define FLAGS_GIV BIT(2) 85f9fb69e7SMark A. Greer #define FLAGS_CTR BIT(3) 86537559a5SDmitry Kasatkin 8767a730ceSDmitry Kasatkin #define FLAGS_INIT BIT(4) 8867a730ceSDmitry Kasatkin #define FLAGS_FAST BIT(5) 8967a730ceSDmitry Kasatkin #define FLAGS_BUSY BIT(6) 90537559a5SDmitry Kasatkin 91537559a5SDmitry Kasatkin struct omap_aes_ctx { 92537559a5SDmitry Kasatkin struct omap_aes_dev *dd; 93537559a5SDmitry Kasatkin 94537559a5SDmitry Kasatkin int keylen; 95537559a5SDmitry Kasatkin u32 key[AES_KEYSIZE_256 / sizeof(u32)]; 96537559a5SDmitry Kasatkin unsigned long flags; 97537559a5SDmitry Kasatkin }; 98537559a5SDmitry Kasatkin 99537559a5SDmitry Kasatkin struct omap_aes_reqctx { 100537559a5SDmitry Kasatkin unsigned long mode; 101537559a5SDmitry Kasatkin }; 102537559a5SDmitry Kasatkin 103537559a5SDmitry Kasatkin #define OMAP_AES_QUEUE_LENGTH 1 104537559a5SDmitry Kasatkin #define OMAP_AES_CACHE_SIZE 0 105537559a5SDmitry Kasatkin 106f9fb69e7SMark A. Greer struct omap_aes_algs_info { 107f9fb69e7SMark A. Greer struct crypto_alg *algs_list; 108f9fb69e7SMark A. Greer unsigned int size; 109f9fb69e7SMark A. Greer unsigned int registered; 110f9fb69e7SMark A. Greer }; 111f9fb69e7SMark A. Greer 1120d35583aSMark A. Greer struct omap_aes_pdata { 113f9fb69e7SMark A. Greer struct omap_aes_algs_info *algs_info; 114f9fb69e7SMark A. Greer unsigned int algs_info_size; 115f9fb69e7SMark A. Greer 1160d35583aSMark A. Greer void (*trigger)(struct omap_aes_dev *dd, int length); 1170d35583aSMark A. Greer 1180d35583aSMark A. Greer u32 key_ofs; 1190d35583aSMark A. Greer u32 iv_ofs; 1200d35583aSMark A. Greer u32 ctrl_ofs; 1210d35583aSMark A. Greer u32 data_ofs; 1220d35583aSMark A. Greer u32 rev_ofs; 1230d35583aSMark A. Greer u32 mask_ofs; 1240d35583aSMark A. Greer 1250d35583aSMark A. Greer u32 dma_enable_in; 1260d35583aSMark A. Greer u32 dma_enable_out; 1270d35583aSMark A. Greer u32 dma_start; 1280d35583aSMark A. Greer 1290d35583aSMark A. Greer u32 major_mask; 1300d35583aSMark A. Greer u32 major_shift; 1310d35583aSMark A. Greer u32 minor_mask; 1320d35583aSMark A. Greer u32 minor_shift; 1330d35583aSMark A. Greer }; 1340d35583aSMark A. Greer 135537559a5SDmitry Kasatkin struct omap_aes_dev { 136537559a5SDmitry Kasatkin struct list_head list; 137537559a5SDmitry Kasatkin unsigned long phys_base; 138537559a5SDmitry Kasatkin void __iomem *io_base; 139537559a5SDmitry Kasatkin struct omap_aes_ctx *ctx; 140537559a5SDmitry Kasatkin struct device *dev; 141537559a5SDmitry Kasatkin unsigned long flags; 14221fe9767SDmitry Kasatkin int err; 143537559a5SDmitry Kasatkin 144537559a5SDmitry Kasatkin spinlock_t lock; 145537559a5SDmitry Kasatkin struct crypto_queue queue; 146537559a5SDmitry Kasatkin 14721fe9767SDmitry Kasatkin struct tasklet_struct done_task; 14821fe9767SDmitry Kasatkin struct tasklet_struct queue_task; 149537559a5SDmitry Kasatkin 150537559a5SDmitry Kasatkin struct ablkcipher_request *req; 151537559a5SDmitry Kasatkin size_t total; 152537559a5SDmitry Kasatkin struct scatterlist *in_sg; 153ebedbf79SMark A. Greer struct scatterlist in_sgl; 154537559a5SDmitry Kasatkin size_t in_offset; 155537559a5SDmitry Kasatkin struct scatterlist *out_sg; 156ebedbf79SMark A. Greer struct scatterlist out_sgl; 157537559a5SDmitry Kasatkin size_t out_offset; 158537559a5SDmitry Kasatkin 159537559a5SDmitry Kasatkin size_t buflen; 160537559a5SDmitry Kasatkin void *buf_in; 161537559a5SDmitry Kasatkin size_t dma_size; 162537559a5SDmitry Kasatkin int dma_in; 163ebedbf79SMark A. Greer struct dma_chan *dma_lch_in; 164537559a5SDmitry Kasatkin dma_addr_t dma_addr_in; 165537559a5SDmitry Kasatkin void *buf_out; 166537559a5SDmitry Kasatkin int dma_out; 167ebedbf79SMark A. Greer struct dma_chan *dma_lch_out; 168e77c756eSJoel Fernandes int in_sg_len; 169e77c756eSJoel Fernandes int out_sg_len; 170537559a5SDmitry Kasatkin dma_addr_t dma_addr_out; 1710d35583aSMark A. Greer 1720d35583aSMark A. Greer const struct omap_aes_pdata *pdata; 173537559a5SDmitry Kasatkin }; 174537559a5SDmitry Kasatkin 175537559a5SDmitry Kasatkin /* keep registered devices data here */ 176537559a5SDmitry Kasatkin static LIST_HEAD(dev_list); 177537559a5SDmitry Kasatkin static DEFINE_SPINLOCK(list_lock); 178537559a5SDmitry Kasatkin 179016af9b5SJoel Fernandes #ifdef DEBUG 180016af9b5SJoel Fernandes #define omap_aes_read(dd, offset) \ 181016af9b5SJoel Fernandes ({ \ 182016af9b5SJoel Fernandes int _read_ret; \ 183016af9b5SJoel Fernandes _read_ret = __raw_readl(dd->io_base + offset); \ 184016af9b5SJoel Fernandes pr_debug("omap_aes_read(" #offset "=%#x)= %#x\n", \ 185016af9b5SJoel Fernandes offset, _read_ret); \ 186016af9b5SJoel Fernandes _read_ret; \ 187016af9b5SJoel Fernandes }) 188016af9b5SJoel Fernandes #else 189537559a5SDmitry Kasatkin static inline u32 omap_aes_read(struct omap_aes_dev *dd, u32 offset) 190537559a5SDmitry Kasatkin { 191537559a5SDmitry Kasatkin return __raw_readl(dd->io_base + offset); 192537559a5SDmitry Kasatkin } 193016af9b5SJoel Fernandes #endif 194537559a5SDmitry Kasatkin 195016af9b5SJoel Fernandes #ifdef DEBUG 196016af9b5SJoel Fernandes #define omap_aes_write(dd, offset, value) \ 197016af9b5SJoel Fernandes do { \ 198016af9b5SJoel Fernandes pr_debug("omap_aes_write(" #offset "=%#x) value=%#x\n", \ 199016af9b5SJoel Fernandes offset, value); \ 200016af9b5SJoel Fernandes __raw_writel(value, dd->io_base + offset); \ 201016af9b5SJoel Fernandes } while (0) 202016af9b5SJoel Fernandes #else 203537559a5SDmitry Kasatkin static inline void omap_aes_write(struct omap_aes_dev *dd, u32 offset, 204537559a5SDmitry Kasatkin u32 value) 205537559a5SDmitry Kasatkin { 206537559a5SDmitry Kasatkin __raw_writel(value, dd->io_base + offset); 207537559a5SDmitry Kasatkin } 208016af9b5SJoel Fernandes #endif 209537559a5SDmitry Kasatkin 210537559a5SDmitry Kasatkin static inline void omap_aes_write_mask(struct omap_aes_dev *dd, u32 offset, 211537559a5SDmitry Kasatkin u32 value, u32 mask) 212537559a5SDmitry Kasatkin { 213537559a5SDmitry Kasatkin u32 val; 214537559a5SDmitry Kasatkin 215537559a5SDmitry Kasatkin val = omap_aes_read(dd, offset); 216537559a5SDmitry Kasatkin val &= ~mask; 217537559a5SDmitry Kasatkin val |= value; 218537559a5SDmitry Kasatkin omap_aes_write(dd, offset, val); 219537559a5SDmitry Kasatkin } 220537559a5SDmitry Kasatkin 221537559a5SDmitry Kasatkin static void omap_aes_write_n(struct omap_aes_dev *dd, u32 offset, 222537559a5SDmitry Kasatkin u32 *value, int count) 223537559a5SDmitry Kasatkin { 224537559a5SDmitry Kasatkin for (; count--; value++, offset += 4) 225537559a5SDmitry Kasatkin omap_aes_write(dd, offset, *value); 226537559a5SDmitry Kasatkin } 227537559a5SDmitry Kasatkin 228537559a5SDmitry Kasatkin static int omap_aes_hw_init(struct omap_aes_dev *dd) 229537559a5SDmitry Kasatkin { 230537559a5SDmitry Kasatkin if (!(dd->flags & FLAGS_INIT)) { 231537559a5SDmitry Kasatkin dd->flags |= FLAGS_INIT; 23221fe9767SDmitry Kasatkin dd->err = 0; 233537559a5SDmitry Kasatkin } 234537559a5SDmitry Kasatkin 235eeb2b202SDmitry Kasatkin return 0; 236537559a5SDmitry Kasatkin } 237537559a5SDmitry Kasatkin 23821fe9767SDmitry Kasatkin static int omap_aes_write_ctrl(struct omap_aes_dev *dd) 239537559a5SDmitry Kasatkin { 240537559a5SDmitry Kasatkin unsigned int key32; 24167a730ceSDmitry Kasatkin int i, err; 242f9fb69e7SMark A. Greer u32 val, mask = 0; 243537559a5SDmitry Kasatkin 24421fe9767SDmitry Kasatkin err = omap_aes_hw_init(dd); 24521fe9767SDmitry Kasatkin if (err) 24621fe9767SDmitry Kasatkin return err; 24721fe9767SDmitry Kasatkin 248537559a5SDmitry Kasatkin key32 = dd->ctx->keylen / sizeof(u32); 24967a730ceSDmitry Kasatkin 25067a730ceSDmitry Kasatkin /* it seems a key should always be set even if it has not changed */ 251537559a5SDmitry Kasatkin for (i = 0; i < key32; i++) { 2520d35583aSMark A. Greer omap_aes_write(dd, AES_REG_KEY(dd, i), 253537559a5SDmitry Kasatkin __le32_to_cpu(dd->ctx->key[i])); 254537559a5SDmitry Kasatkin } 255537559a5SDmitry Kasatkin 256f9fb69e7SMark A. Greer if ((dd->flags & (FLAGS_CBC | FLAGS_CTR)) && dd->req->info) 2570d35583aSMark A. Greer omap_aes_write_n(dd, AES_REG_IV(dd, 0), dd->req->info, 4); 25867a730ceSDmitry Kasatkin 25967a730ceSDmitry Kasatkin val = FLD_VAL(((dd->ctx->keylen >> 3) - 1), 4, 3); 26067a730ceSDmitry Kasatkin if (dd->flags & FLAGS_CBC) 26167a730ceSDmitry Kasatkin val |= AES_REG_CTRL_CBC; 262f9fb69e7SMark A. Greer if (dd->flags & FLAGS_CTR) { 263f9fb69e7SMark A. Greer val |= AES_REG_CTRL_CTR | AES_REG_CTRL_CTR_WIDTH_32; 264f9fb69e7SMark A. Greer mask = AES_REG_CTRL_CTR | AES_REG_CTRL_CTR_WIDTH_MASK; 265f9fb69e7SMark A. Greer } 26667a730ceSDmitry Kasatkin if (dd->flags & FLAGS_ENCRYPT) 26767a730ceSDmitry Kasatkin val |= AES_REG_CTRL_DIRECTION; 268537559a5SDmitry Kasatkin 269f9fb69e7SMark A. Greer mask |= AES_REG_CTRL_CBC | AES_REG_CTRL_DIRECTION | 270537559a5SDmitry Kasatkin AES_REG_CTRL_KEY_SIZE; 271537559a5SDmitry Kasatkin 2720d35583aSMark A. Greer omap_aes_write_mask(dd, AES_REG_CTRL(dd), val, mask); 273537559a5SDmitry Kasatkin 27421fe9767SDmitry Kasatkin return 0; 275537559a5SDmitry Kasatkin } 276537559a5SDmitry Kasatkin 2770d35583aSMark A. Greer static void omap_aes_dma_trigger_omap2(struct omap_aes_dev *dd, int length) 2780d35583aSMark A. Greer { 2790d35583aSMark A. Greer u32 mask, val; 2800d35583aSMark A. Greer 2810d35583aSMark A. Greer val = dd->pdata->dma_start; 2820d35583aSMark A. Greer 2830d35583aSMark A. Greer if (dd->dma_lch_out != NULL) 2840d35583aSMark A. Greer val |= dd->pdata->dma_enable_out; 2850d35583aSMark A. Greer if (dd->dma_lch_in != NULL) 2860d35583aSMark A. Greer val |= dd->pdata->dma_enable_in; 2870d35583aSMark A. Greer 2880d35583aSMark A. Greer mask = dd->pdata->dma_enable_out | dd->pdata->dma_enable_in | 2890d35583aSMark A. Greer dd->pdata->dma_start; 2900d35583aSMark A. Greer 2910d35583aSMark A. Greer omap_aes_write_mask(dd, AES_REG_MASK(dd), val, mask); 2920d35583aSMark A. Greer 2930d35583aSMark A. Greer } 2940d35583aSMark A. Greer 2950d35583aSMark A. Greer static void omap_aes_dma_trigger_omap4(struct omap_aes_dev *dd, int length) 2960d35583aSMark A. Greer { 2970d35583aSMark A. Greer omap_aes_write(dd, AES_REG_LENGTH_N(0), length); 2980d35583aSMark A. Greer omap_aes_write(dd, AES_REG_LENGTH_N(1), 0); 2990d35583aSMark A. Greer 3000d35583aSMark A. Greer omap_aes_dma_trigger_omap2(dd, length); 3010d35583aSMark A. Greer } 3020d35583aSMark A. Greer 3030d35583aSMark A. Greer static void omap_aes_dma_stop(struct omap_aes_dev *dd) 3040d35583aSMark A. Greer { 3050d35583aSMark A. Greer u32 mask; 3060d35583aSMark A. Greer 3070d35583aSMark A. Greer mask = dd->pdata->dma_enable_out | dd->pdata->dma_enable_in | 3080d35583aSMark A. Greer dd->pdata->dma_start; 3090d35583aSMark A. Greer 3100d35583aSMark A. Greer omap_aes_write_mask(dd, AES_REG_MASK(dd), 0, mask); 3110d35583aSMark A. Greer } 3120d35583aSMark A. Greer 313537559a5SDmitry Kasatkin static struct omap_aes_dev *omap_aes_find_dev(struct omap_aes_ctx *ctx) 314537559a5SDmitry Kasatkin { 315537559a5SDmitry Kasatkin struct omap_aes_dev *dd = NULL, *tmp; 316537559a5SDmitry Kasatkin 317537559a5SDmitry Kasatkin spin_lock_bh(&list_lock); 318537559a5SDmitry Kasatkin if (!ctx->dd) { 319537559a5SDmitry Kasatkin list_for_each_entry(tmp, &dev_list, list) { 320537559a5SDmitry Kasatkin /* FIXME: take fist available aes core */ 321537559a5SDmitry Kasatkin dd = tmp; 322537559a5SDmitry Kasatkin break; 323537559a5SDmitry Kasatkin } 324537559a5SDmitry Kasatkin ctx->dd = dd; 325537559a5SDmitry Kasatkin } else { 326537559a5SDmitry Kasatkin /* already found before */ 327537559a5SDmitry Kasatkin dd = ctx->dd; 328537559a5SDmitry Kasatkin } 329537559a5SDmitry Kasatkin spin_unlock_bh(&list_lock); 330537559a5SDmitry Kasatkin 331537559a5SDmitry Kasatkin return dd; 332537559a5SDmitry Kasatkin } 333537559a5SDmitry Kasatkin 334ebedbf79SMark A. Greer static void omap_aes_dma_out_callback(void *data) 335ebedbf79SMark A. Greer { 336ebedbf79SMark A. Greer struct omap_aes_dev *dd = data; 337ebedbf79SMark A. Greer 338ebedbf79SMark A. Greer /* dma_lch_out - completed */ 339ebedbf79SMark A. Greer tasklet_schedule(&dd->done_task); 340ebedbf79SMark A. Greer } 341537559a5SDmitry Kasatkin 342537559a5SDmitry Kasatkin static int omap_aes_dma_init(struct omap_aes_dev *dd) 343537559a5SDmitry Kasatkin { 344537559a5SDmitry Kasatkin int err = -ENOMEM; 345ebedbf79SMark A. Greer dma_cap_mask_t mask; 346537559a5SDmitry Kasatkin 347ebedbf79SMark A. Greer dd->dma_lch_out = NULL; 348ebedbf79SMark A. Greer dd->dma_lch_in = NULL; 349537559a5SDmitry Kasatkin 350537559a5SDmitry Kasatkin dd->buf_in = (void *)__get_free_pages(GFP_KERNEL, OMAP_AES_CACHE_SIZE); 351537559a5SDmitry Kasatkin dd->buf_out = (void *)__get_free_pages(GFP_KERNEL, OMAP_AES_CACHE_SIZE); 352537559a5SDmitry Kasatkin dd->buflen = PAGE_SIZE << OMAP_AES_CACHE_SIZE; 353537559a5SDmitry Kasatkin dd->buflen &= ~(AES_BLOCK_SIZE - 1); 354537559a5SDmitry Kasatkin 355537559a5SDmitry Kasatkin if (!dd->buf_in || !dd->buf_out) { 356537559a5SDmitry Kasatkin dev_err(dd->dev, "unable to alloc pages.\n"); 357537559a5SDmitry Kasatkin goto err_alloc; 358537559a5SDmitry Kasatkin } 359537559a5SDmitry Kasatkin 360537559a5SDmitry Kasatkin /* MAP here */ 361537559a5SDmitry Kasatkin dd->dma_addr_in = dma_map_single(dd->dev, dd->buf_in, dd->buflen, 362537559a5SDmitry Kasatkin DMA_TO_DEVICE); 363537559a5SDmitry Kasatkin if (dma_mapping_error(dd->dev, dd->dma_addr_in)) { 364537559a5SDmitry Kasatkin dev_err(dd->dev, "dma %d bytes error\n", dd->buflen); 365537559a5SDmitry Kasatkin err = -EINVAL; 366537559a5SDmitry Kasatkin goto err_map_in; 367537559a5SDmitry Kasatkin } 368537559a5SDmitry Kasatkin 369537559a5SDmitry Kasatkin dd->dma_addr_out = dma_map_single(dd->dev, dd->buf_out, dd->buflen, 370537559a5SDmitry Kasatkin DMA_FROM_DEVICE); 371537559a5SDmitry Kasatkin if (dma_mapping_error(dd->dev, dd->dma_addr_out)) { 372537559a5SDmitry Kasatkin dev_err(dd->dev, "dma %d bytes error\n", dd->buflen); 373537559a5SDmitry Kasatkin err = -EINVAL; 374537559a5SDmitry Kasatkin goto err_map_out; 375537559a5SDmitry Kasatkin } 376537559a5SDmitry Kasatkin 377ebedbf79SMark A. Greer dma_cap_zero(mask); 378ebedbf79SMark A. Greer dma_cap_set(DMA_SLAVE, mask); 379ebedbf79SMark A. Greer 380b4b87a93SMark A. Greer dd->dma_lch_in = dma_request_slave_channel_compat(mask, 381b4b87a93SMark A. Greer omap_dma_filter_fn, 382b4b87a93SMark A. Greer &dd->dma_in, 383b4b87a93SMark A. Greer dd->dev, "rx"); 384ebedbf79SMark A. Greer if (!dd->dma_lch_in) { 385ebedbf79SMark A. Greer dev_err(dd->dev, "Unable to request in DMA channel\n"); 386ebedbf79SMark A. Greer goto err_dma_in; 387ebedbf79SMark A. Greer } 388ebedbf79SMark A. Greer 389b4b87a93SMark A. Greer dd->dma_lch_out = dma_request_slave_channel_compat(mask, 390b4b87a93SMark A. Greer omap_dma_filter_fn, 391b4b87a93SMark A. Greer &dd->dma_out, 392b4b87a93SMark A. Greer dd->dev, "tx"); 393ebedbf79SMark A. Greer if (!dd->dma_lch_out) { 394ebedbf79SMark A. Greer dev_err(dd->dev, "Unable to request out DMA channel\n"); 395ebedbf79SMark A. Greer goto err_dma_out; 396ebedbf79SMark A. Greer } 397537559a5SDmitry Kasatkin 398537559a5SDmitry Kasatkin return 0; 399537559a5SDmitry Kasatkin 400537559a5SDmitry Kasatkin err_dma_out: 401ebedbf79SMark A. Greer dma_release_channel(dd->dma_lch_in); 402537559a5SDmitry Kasatkin err_dma_in: 403537559a5SDmitry Kasatkin dma_unmap_single(dd->dev, dd->dma_addr_out, dd->buflen, 404537559a5SDmitry Kasatkin DMA_FROM_DEVICE); 405537559a5SDmitry Kasatkin err_map_out: 406537559a5SDmitry Kasatkin dma_unmap_single(dd->dev, dd->dma_addr_in, dd->buflen, DMA_TO_DEVICE); 407537559a5SDmitry Kasatkin err_map_in: 408537559a5SDmitry Kasatkin free_pages((unsigned long)dd->buf_out, OMAP_AES_CACHE_SIZE); 409537559a5SDmitry Kasatkin free_pages((unsigned long)dd->buf_in, OMAP_AES_CACHE_SIZE); 410537559a5SDmitry Kasatkin err_alloc: 411537559a5SDmitry Kasatkin if (err) 412537559a5SDmitry Kasatkin pr_err("error: %d\n", err); 413537559a5SDmitry Kasatkin return err; 414537559a5SDmitry Kasatkin } 415537559a5SDmitry Kasatkin 416537559a5SDmitry Kasatkin static void omap_aes_dma_cleanup(struct omap_aes_dev *dd) 417537559a5SDmitry Kasatkin { 418ebedbf79SMark A. Greer dma_release_channel(dd->dma_lch_out); 419ebedbf79SMark A. Greer dma_release_channel(dd->dma_lch_in); 420537559a5SDmitry Kasatkin dma_unmap_single(dd->dev, dd->dma_addr_out, dd->buflen, 421537559a5SDmitry Kasatkin DMA_FROM_DEVICE); 422537559a5SDmitry Kasatkin dma_unmap_single(dd->dev, dd->dma_addr_in, dd->buflen, DMA_TO_DEVICE); 423537559a5SDmitry Kasatkin free_pages((unsigned long)dd->buf_out, OMAP_AES_CACHE_SIZE); 424537559a5SDmitry Kasatkin free_pages((unsigned long)dd->buf_in, OMAP_AES_CACHE_SIZE); 425537559a5SDmitry Kasatkin } 426537559a5SDmitry Kasatkin 427537559a5SDmitry Kasatkin static void sg_copy_buf(void *buf, struct scatterlist *sg, 428537559a5SDmitry Kasatkin unsigned int start, unsigned int nbytes, int out) 429537559a5SDmitry Kasatkin { 430537559a5SDmitry Kasatkin struct scatter_walk walk; 431537559a5SDmitry Kasatkin 432537559a5SDmitry Kasatkin if (!nbytes) 433537559a5SDmitry Kasatkin return; 434537559a5SDmitry Kasatkin 435537559a5SDmitry Kasatkin scatterwalk_start(&walk, sg); 436537559a5SDmitry Kasatkin scatterwalk_advance(&walk, start); 437537559a5SDmitry Kasatkin scatterwalk_copychunks(buf, &walk, nbytes, out); 438537559a5SDmitry Kasatkin scatterwalk_done(&walk, out, 0); 439537559a5SDmitry Kasatkin } 440537559a5SDmitry Kasatkin 441537559a5SDmitry Kasatkin static int sg_copy(struct scatterlist **sg, size_t *offset, void *buf, 442537559a5SDmitry Kasatkin size_t buflen, size_t total, int out) 443537559a5SDmitry Kasatkin { 444537559a5SDmitry Kasatkin unsigned int count, off = 0; 445537559a5SDmitry Kasatkin 446537559a5SDmitry Kasatkin while (buflen && total) { 447537559a5SDmitry Kasatkin count = min((*sg)->length - *offset, total); 448537559a5SDmitry Kasatkin count = min(count, buflen); 449537559a5SDmitry Kasatkin 450537559a5SDmitry Kasatkin if (!count) 451537559a5SDmitry Kasatkin return off; 452537559a5SDmitry Kasatkin 45321fe9767SDmitry Kasatkin /* 45421fe9767SDmitry Kasatkin * buflen and total are AES_BLOCK_SIZE size aligned, 45521fe9767SDmitry Kasatkin * so count should be also aligned 45621fe9767SDmitry Kasatkin */ 45721fe9767SDmitry Kasatkin 458537559a5SDmitry Kasatkin sg_copy_buf(buf + off, *sg, *offset, count, out); 459537559a5SDmitry Kasatkin 460537559a5SDmitry Kasatkin off += count; 461537559a5SDmitry Kasatkin buflen -= count; 462537559a5SDmitry Kasatkin *offset += count; 463537559a5SDmitry Kasatkin total -= count; 464537559a5SDmitry Kasatkin 465537559a5SDmitry Kasatkin if (*offset == (*sg)->length) { 466537559a5SDmitry Kasatkin *sg = sg_next(*sg); 467537559a5SDmitry Kasatkin if (*sg) 468537559a5SDmitry Kasatkin *offset = 0; 469537559a5SDmitry Kasatkin else 470537559a5SDmitry Kasatkin total = 0; 471537559a5SDmitry Kasatkin } 472537559a5SDmitry Kasatkin } 473537559a5SDmitry Kasatkin 474537559a5SDmitry Kasatkin return off; 475537559a5SDmitry Kasatkin } 476537559a5SDmitry Kasatkin 477ebedbf79SMark A. Greer static int omap_aes_crypt_dma(struct crypto_tfm *tfm, 478ebedbf79SMark A. Greer struct scatterlist *in_sg, struct scatterlist *out_sg) 479537559a5SDmitry Kasatkin { 480537559a5SDmitry Kasatkin struct omap_aes_ctx *ctx = crypto_tfm_ctx(tfm); 481537559a5SDmitry Kasatkin struct omap_aes_dev *dd = ctx->dd; 482ebedbf79SMark A. Greer struct dma_async_tx_descriptor *tx_in, *tx_out; 483ebedbf79SMark A. Greer struct dma_slave_config cfg; 484ebedbf79SMark A. Greer dma_addr_t dma_addr_in = sg_dma_address(in_sg); 485ebedbf79SMark A. Greer int ret, length = sg_dma_len(in_sg); 486537559a5SDmitry Kasatkin 487537559a5SDmitry Kasatkin pr_debug("len: %d\n", length); 488537559a5SDmitry Kasatkin 489537559a5SDmitry Kasatkin dd->dma_size = length; 490537559a5SDmitry Kasatkin 491537559a5SDmitry Kasatkin if (!(dd->flags & FLAGS_FAST)) 492537559a5SDmitry Kasatkin dma_sync_single_for_device(dd->dev, dma_addr_in, length, 493537559a5SDmitry Kasatkin DMA_TO_DEVICE); 494537559a5SDmitry Kasatkin 495ebedbf79SMark A. Greer memset(&cfg, 0, sizeof(cfg)); 496ebedbf79SMark A. Greer 4970d35583aSMark A. Greer cfg.src_addr = dd->phys_base + AES_REG_DATA_N(dd, 0); 4980d35583aSMark A. Greer cfg.dst_addr = dd->phys_base + AES_REG_DATA_N(dd, 0); 499ebedbf79SMark A. Greer cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 500ebedbf79SMark A. Greer cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 501ebedbf79SMark A. Greer cfg.src_maxburst = DST_MAXBURST; 502ebedbf79SMark A. Greer cfg.dst_maxburst = DST_MAXBURST; 503ebedbf79SMark A. Greer 504ebedbf79SMark A. Greer /* IN */ 505ebedbf79SMark A. Greer ret = dmaengine_slave_config(dd->dma_lch_in, &cfg); 506ebedbf79SMark A. Greer if (ret) { 507ebedbf79SMark A. Greer dev_err(dd->dev, "can't configure IN dmaengine slave: %d\n", 508ebedbf79SMark A. Greer ret); 509ebedbf79SMark A. Greer return ret; 510ebedbf79SMark A. Greer } 511ebedbf79SMark A. Greer 512ebedbf79SMark A. Greer tx_in = dmaengine_prep_slave_sg(dd->dma_lch_in, in_sg, 1, 513ebedbf79SMark A. Greer DMA_MEM_TO_DEV, 514ebedbf79SMark A. Greer DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 515ebedbf79SMark A. Greer if (!tx_in) { 516ebedbf79SMark A. Greer dev_err(dd->dev, "IN prep_slave_sg() failed\n"); 517ebedbf79SMark A. Greer return -EINVAL; 518ebedbf79SMark A. Greer } 519ebedbf79SMark A. Greer 520ebedbf79SMark A. Greer /* No callback necessary */ 521ebedbf79SMark A. Greer tx_in->callback_param = dd; 522ebedbf79SMark A. Greer 523ebedbf79SMark A. Greer /* OUT */ 524ebedbf79SMark A. Greer ret = dmaengine_slave_config(dd->dma_lch_out, &cfg); 525ebedbf79SMark A. Greer if (ret) { 526ebedbf79SMark A. Greer dev_err(dd->dev, "can't configure OUT dmaengine slave: %d\n", 527ebedbf79SMark A. Greer ret); 528ebedbf79SMark A. Greer return ret; 529ebedbf79SMark A. Greer } 530ebedbf79SMark A. Greer 531ebedbf79SMark A. Greer tx_out = dmaengine_prep_slave_sg(dd->dma_lch_out, out_sg, 1, 532ebedbf79SMark A. Greer DMA_DEV_TO_MEM, 533ebedbf79SMark A. Greer DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 534ebedbf79SMark A. Greer if (!tx_out) { 535ebedbf79SMark A. Greer dev_err(dd->dev, "OUT prep_slave_sg() failed\n"); 536ebedbf79SMark A. Greer return -EINVAL; 537ebedbf79SMark A. Greer } 538ebedbf79SMark A. Greer 539ebedbf79SMark A. Greer tx_out->callback = omap_aes_dma_out_callback; 540ebedbf79SMark A. Greer tx_out->callback_param = dd; 541ebedbf79SMark A. Greer 542ebedbf79SMark A. Greer dmaengine_submit(tx_in); 543ebedbf79SMark A. Greer dmaengine_submit(tx_out); 544ebedbf79SMark A. Greer 545ebedbf79SMark A. Greer dma_async_issue_pending(dd->dma_lch_in); 546ebedbf79SMark A. Greer dma_async_issue_pending(dd->dma_lch_out); 547537559a5SDmitry Kasatkin 5480d35583aSMark A. Greer /* start DMA */ 5490d35583aSMark A. Greer dd->pdata->trigger(dd, length); 55083ea7e0fSDmitry Kasatkin 551537559a5SDmitry Kasatkin return 0; 552537559a5SDmitry Kasatkin } 553537559a5SDmitry Kasatkin 554537559a5SDmitry Kasatkin static int omap_aes_crypt_dma_start(struct omap_aes_dev *dd) 555537559a5SDmitry Kasatkin { 556537559a5SDmitry Kasatkin struct crypto_tfm *tfm = crypto_ablkcipher_tfm( 557537559a5SDmitry Kasatkin crypto_ablkcipher_reqtfm(dd->req)); 558537559a5SDmitry Kasatkin int err, fast = 0, in, out; 559537559a5SDmitry Kasatkin size_t count; 560537559a5SDmitry Kasatkin dma_addr_t addr_in, addr_out; 561ebedbf79SMark A. Greer struct scatterlist *in_sg, *out_sg; 562ebedbf79SMark A. Greer int len32; 563537559a5SDmitry Kasatkin 564537559a5SDmitry Kasatkin pr_debug("total: %d\n", dd->total); 565537559a5SDmitry Kasatkin 566537559a5SDmitry Kasatkin if (sg_is_last(dd->in_sg) && sg_is_last(dd->out_sg)) { 567537559a5SDmitry Kasatkin /* check for alignment */ 568537559a5SDmitry Kasatkin in = IS_ALIGNED((u32)dd->in_sg->offset, sizeof(u32)); 569537559a5SDmitry Kasatkin out = IS_ALIGNED((u32)dd->out_sg->offset, sizeof(u32)); 570537559a5SDmitry Kasatkin 571537559a5SDmitry Kasatkin fast = in && out; 572537559a5SDmitry Kasatkin } 573537559a5SDmitry Kasatkin 574537559a5SDmitry Kasatkin if (fast) { 575537559a5SDmitry Kasatkin count = min(dd->total, sg_dma_len(dd->in_sg)); 576537559a5SDmitry Kasatkin count = min(count, sg_dma_len(dd->out_sg)); 577537559a5SDmitry Kasatkin 57821fe9767SDmitry Kasatkin if (count != dd->total) { 57921fe9767SDmitry Kasatkin pr_err("request length != buffer length\n"); 580537559a5SDmitry Kasatkin return -EINVAL; 58121fe9767SDmitry Kasatkin } 582537559a5SDmitry Kasatkin 583537559a5SDmitry Kasatkin pr_debug("fast\n"); 584537559a5SDmitry Kasatkin 585537559a5SDmitry Kasatkin err = dma_map_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE); 586537559a5SDmitry Kasatkin if (!err) { 587537559a5SDmitry Kasatkin dev_err(dd->dev, "dma_map_sg() error\n"); 588537559a5SDmitry Kasatkin return -EINVAL; 589537559a5SDmitry Kasatkin } 590537559a5SDmitry Kasatkin 591537559a5SDmitry Kasatkin err = dma_map_sg(dd->dev, dd->out_sg, 1, DMA_FROM_DEVICE); 592537559a5SDmitry Kasatkin if (!err) { 593537559a5SDmitry Kasatkin dev_err(dd->dev, "dma_map_sg() error\n"); 594537559a5SDmitry Kasatkin dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE); 595537559a5SDmitry Kasatkin return -EINVAL; 596537559a5SDmitry Kasatkin } 597537559a5SDmitry Kasatkin 598537559a5SDmitry Kasatkin addr_in = sg_dma_address(dd->in_sg); 599537559a5SDmitry Kasatkin addr_out = sg_dma_address(dd->out_sg); 600537559a5SDmitry Kasatkin 601ebedbf79SMark A. Greer in_sg = dd->in_sg; 602ebedbf79SMark A. Greer out_sg = dd->out_sg; 603ebedbf79SMark A. Greer 604537559a5SDmitry Kasatkin dd->flags |= FLAGS_FAST; 605537559a5SDmitry Kasatkin 606537559a5SDmitry Kasatkin } else { 607537559a5SDmitry Kasatkin /* use cache buffers */ 608537559a5SDmitry Kasatkin count = sg_copy(&dd->in_sg, &dd->in_offset, dd->buf_in, 609537559a5SDmitry Kasatkin dd->buflen, dd->total, 0); 610537559a5SDmitry Kasatkin 611ebedbf79SMark A. Greer len32 = DIV_ROUND_UP(count, DMA_MIN) * DMA_MIN; 612ebedbf79SMark A. Greer 613ebedbf79SMark A. Greer /* 614ebedbf79SMark A. Greer * The data going into the AES module has been copied 615ebedbf79SMark A. Greer * to a local buffer and the data coming out will go 616ebedbf79SMark A. Greer * into a local buffer so set up local SG entries for 617ebedbf79SMark A. Greer * both. 618ebedbf79SMark A. Greer */ 619ebedbf79SMark A. Greer sg_init_table(&dd->in_sgl, 1); 620ebedbf79SMark A. Greer dd->in_sgl.offset = dd->in_offset; 621ebedbf79SMark A. Greer sg_dma_len(&dd->in_sgl) = len32; 622ebedbf79SMark A. Greer sg_dma_address(&dd->in_sgl) = dd->dma_addr_in; 623ebedbf79SMark A. Greer 624ebedbf79SMark A. Greer sg_init_table(&dd->out_sgl, 1); 625ebedbf79SMark A. Greer dd->out_sgl.offset = dd->out_offset; 626ebedbf79SMark A. Greer sg_dma_len(&dd->out_sgl) = len32; 627ebedbf79SMark A. Greer sg_dma_address(&dd->out_sgl) = dd->dma_addr_out; 628ebedbf79SMark A. Greer 629ebedbf79SMark A. Greer in_sg = &dd->in_sgl; 630ebedbf79SMark A. Greer out_sg = &dd->out_sgl; 631ebedbf79SMark A. Greer 632537559a5SDmitry Kasatkin addr_in = dd->dma_addr_in; 633537559a5SDmitry Kasatkin addr_out = dd->dma_addr_out; 634537559a5SDmitry Kasatkin 635537559a5SDmitry Kasatkin dd->flags &= ~FLAGS_FAST; 636537559a5SDmitry Kasatkin 637537559a5SDmitry Kasatkin } 638537559a5SDmitry Kasatkin 639537559a5SDmitry Kasatkin dd->total -= count; 640537559a5SDmitry Kasatkin 641ebedbf79SMark A. Greer err = omap_aes_crypt_dma(tfm, in_sg, out_sg); 64221fe9767SDmitry Kasatkin if (err) { 64321fe9767SDmitry Kasatkin dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE); 64421fe9767SDmitry Kasatkin dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_TO_DEVICE); 64521fe9767SDmitry Kasatkin } 646537559a5SDmitry Kasatkin 647537559a5SDmitry Kasatkin return err; 648537559a5SDmitry Kasatkin } 649537559a5SDmitry Kasatkin 650537559a5SDmitry Kasatkin static void omap_aes_finish_req(struct omap_aes_dev *dd, int err) 651537559a5SDmitry Kasatkin { 65221fe9767SDmitry Kasatkin struct ablkcipher_request *req = dd->req; 653537559a5SDmitry Kasatkin 654537559a5SDmitry Kasatkin pr_debug("err: %d\n", err); 655537559a5SDmitry Kasatkin 656eeb2b202SDmitry Kasatkin dd->flags &= ~FLAGS_BUSY; 657eeb2b202SDmitry Kasatkin 65821fe9767SDmitry Kasatkin req->base.complete(&req->base, err); 659537559a5SDmitry Kasatkin } 660537559a5SDmitry Kasatkin 661537559a5SDmitry Kasatkin static int omap_aes_crypt_dma_stop(struct omap_aes_dev *dd) 662537559a5SDmitry Kasatkin { 663537559a5SDmitry Kasatkin int err = 0; 664537559a5SDmitry Kasatkin size_t count; 665537559a5SDmitry Kasatkin 666537559a5SDmitry Kasatkin pr_debug("total: %d\n", dd->total); 667537559a5SDmitry Kasatkin 6680d35583aSMark A. Greer omap_aes_dma_stop(dd); 669537559a5SDmitry Kasatkin 670ebedbf79SMark A. Greer dmaengine_terminate_all(dd->dma_lch_in); 671ebedbf79SMark A. Greer dmaengine_terminate_all(dd->dma_lch_out); 672537559a5SDmitry Kasatkin 673537559a5SDmitry Kasatkin if (dd->flags & FLAGS_FAST) { 674537559a5SDmitry Kasatkin dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_FROM_DEVICE); 675537559a5SDmitry Kasatkin dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE); 676537559a5SDmitry Kasatkin } else { 677537559a5SDmitry Kasatkin dma_sync_single_for_device(dd->dev, dd->dma_addr_out, 678537559a5SDmitry Kasatkin dd->dma_size, DMA_FROM_DEVICE); 679537559a5SDmitry Kasatkin 680537559a5SDmitry Kasatkin /* copy data */ 681537559a5SDmitry Kasatkin count = sg_copy(&dd->out_sg, &dd->out_offset, dd->buf_out, 682537559a5SDmitry Kasatkin dd->buflen, dd->dma_size, 1); 683537559a5SDmitry Kasatkin if (count != dd->dma_size) { 684537559a5SDmitry Kasatkin err = -EINVAL; 685537559a5SDmitry Kasatkin pr_err("not all data converted: %u\n", count); 686537559a5SDmitry Kasatkin } 687537559a5SDmitry Kasatkin } 688537559a5SDmitry Kasatkin 689537559a5SDmitry Kasatkin return err; 690537559a5SDmitry Kasatkin } 691537559a5SDmitry Kasatkin 69221fe9767SDmitry Kasatkin static int omap_aes_handle_queue(struct omap_aes_dev *dd, 693eeb2b202SDmitry Kasatkin struct ablkcipher_request *req) 694537559a5SDmitry Kasatkin { 695537559a5SDmitry Kasatkin struct crypto_async_request *async_req, *backlog; 696537559a5SDmitry Kasatkin struct omap_aes_ctx *ctx; 697537559a5SDmitry Kasatkin struct omap_aes_reqctx *rctx; 698537559a5SDmitry Kasatkin unsigned long flags; 69921fe9767SDmitry Kasatkin int err, ret = 0; 700537559a5SDmitry Kasatkin 701537559a5SDmitry Kasatkin spin_lock_irqsave(&dd->lock, flags); 702eeb2b202SDmitry Kasatkin if (req) 70321fe9767SDmitry Kasatkin ret = ablkcipher_enqueue_request(&dd->queue, req); 704eeb2b202SDmitry Kasatkin if (dd->flags & FLAGS_BUSY) { 705eeb2b202SDmitry Kasatkin spin_unlock_irqrestore(&dd->lock, flags); 70621fe9767SDmitry Kasatkin return ret; 707eeb2b202SDmitry Kasatkin } 708537559a5SDmitry Kasatkin backlog = crypto_get_backlog(&dd->queue); 709537559a5SDmitry Kasatkin async_req = crypto_dequeue_request(&dd->queue); 710eeb2b202SDmitry Kasatkin if (async_req) 711eeb2b202SDmitry Kasatkin dd->flags |= FLAGS_BUSY; 712537559a5SDmitry Kasatkin spin_unlock_irqrestore(&dd->lock, flags); 713537559a5SDmitry Kasatkin 714537559a5SDmitry Kasatkin if (!async_req) 71521fe9767SDmitry Kasatkin return ret; 716537559a5SDmitry Kasatkin 717537559a5SDmitry Kasatkin if (backlog) 718537559a5SDmitry Kasatkin backlog->complete(backlog, -EINPROGRESS); 719537559a5SDmitry Kasatkin 720537559a5SDmitry Kasatkin req = ablkcipher_request_cast(async_req); 721537559a5SDmitry Kasatkin 722537559a5SDmitry Kasatkin /* assign new request to device */ 723537559a5SDmitry Kasatkin dd->req = req; 724537559a5SDmitry Kasatkin dd->total = req->nbytes; 725537559a5SDmitry Kasatkin dd->in_offset = 0; 726537559a5SDmitry Kasatkin dd->in_sg = req->src; 727537559a5SDmitry Kasatkin dd->out_offset = 0; 728537559a5SDmitry Kasatkin dd->out_sg = req->dst; 729537559a5SDmitry Kasatkin 730e77c756eSJoel Fernandes dd->in_sg_len = scatterwalk_bytes_sglen(dd->in_sg, dd->total); 731e77c756eSJoel Fernandes dd->out_sg_len = scatterwalk_bytes_sglen(dd->out_sg, dd->total); 732e77c756eSJoel Fernandes BUG_ON(dd->in_sg_len < 0 || dd->out_sg_len < 0); 733e77c756eSJoel Fernandes 734537559a5SDmitry Kasatkin rctx = ablkcipher_request_ctx(req); 735537559a5SDmitry Kasatkin ctx = crypto_ablkcipher_ctx(crypto_ablkcipher_reqtfm(req)); 736537559a5SDmitry Kasatkin rctx->mode &= FLAGS_MODE_MASK; 737537559a5SDmitry Kasatkin dd->flags = (dd->flags & ~FLAGS_MODE_MASK) | rctx->mode; 738537559a5SDmitry Kasatkin 739537559a5SDmitry Kasatkin dd->ctx = ctx; 74067a730ceSDmitry Kasatkin ctx->dd = dd; 741537559a5SDmitry Kasatkin 74283ea7e0fSDmitry Kasatkin err = omap_aes_write_ctrl(dd); 74383ea7e0fSDmitry Kasatkin if (!err) 74421fe9767SDmitry Kasatkin err = omap_aes_crypt_dma_start(dd); 74521fe9767SDmitry Kasatkin if (err) { 74621fe9767SDmitry Kasatkin /* aes_task will not finish it, so do it here */ 74721fe9767SDmitry Kasatkin omap_aes_finish_req(dd, err); 74821fe9767SDmitry Kasatkin tasklet_schedule(&dd->queue_task); 749537559a5SDmitry Kasatkin } 750537559a5SDmitry Kasatkin 75121fe9767SDmitry Kasatkin return ret; /* return ret, which is enqueue return value */ 75221fe9767SDmitry Kasatkin } 75321fe9767SDmitry Kasatkin 75421fe9767SDmitry Kasatkin static void omap_aes_done_task(unsigned long data) 755537559a5SDmitry Kasatkin { 756537559a5SDmitry Kasatkin struct omap_aes_dev *dd = (struct omap_aes_dev *)data; 75721fe9767SDmitry Kasatkin int err; 758537559a5SDmitry Kasatkin 759537559a5SDmitry Kasatkin pr_debug("enter\n"); 760537559a5SDmitry Kasatkin 76121fe9767SDmitry Kasatkin err = omap_aes_crypt_dma_stop(dd); 762537559a5SDmitry Kasatkin 76321fe9767SDmitry Kasatkin err = dd->err ? : err; 76421fe9767SDmitry Kasatkin 76521fe9767SDmitry Kasatkin if (dd->total && !err) { 76621fe9767SDmitry Kasatkin err = omap_aes_crypt_dma_start(dd); 76721fe9767SDmitry Kasatkin if (!err) 76821fe9767SDmitry Kasatkin return; /* DMA started. Not fininishing. */ 76921fe9767SDmitry Kasatkin } 77021fe9767SDmitry Kasatkin 77121fe9767SDmitry Kasatkin omap_aes_finish_req(dd, err); 77221fe9767SDmitry Kasatkin omap_aes_handle_queue(dd, NULL); 773537559a5SDmitry Kasatkin 774537559a5SDmitry Kasatkin pr_debug("exit\n"); 775537559a5SDmitry Kasatkin } 776537559a5SDmitry Kasatkin 77721fe9767SDmitry Kasatkin static void omap_aes_queue_task(unsigned long data) 77821fe9767SDmitry Kasatkin { 77921fe9767SDmitry Kasatkin struct omap_aes_dev *dd = (struct omap_aes_dev *)data; 78021fe9767SDmitry Kasatkin 78121fe9767SDmitry Kasatkin omap_aes_handle_queue(dd, NULL); 78221fe9767SDmitry Kasatkin } 78321fe9767SDmitry Kasatkin 784537559a5SDmitry Kasatkin static int omap_aes_crypt(struct ablkcipher_request *req, unsigned long mode) 785537559a5SDmitry Kasatkin { 786537559a5SDmitry Kasatkin struct omap_aes_ctx *ctx = crypto_ablkcipher_ctx( 787537559a5SDmitry Kasatkin crypto_ablkcipher_reqtfm(req)); 788537559a5SDmitry Kasatkin struct omap_aes_reqctx *rctx = ablkcipher_request_ctx(req); 789537559a5SDmitry Kasatkin struct omap_aes_dev *dd; 790537559a5SDmitry Kasatkin 791537559a5SDmitry Kasatkin pr_debug("nbytes: %d, enc: %d, cbc: %d\n", req->nbytes, 792537559a5SDmitry Kasatkin !!(mode & FLAGS_ENCRYPT), 793537559a5SDmitry Kasatkin !!(mode & FLAGS_CBC)); 794537559a5SDmitry Kasatkin 79521fe9767SDmitry Kasatkin if (!IS_ALIGNED(req->nbytes, AES_BLOCK_SIZE)) { 79621fe9767SDmitry Kasatkin pr_err("request size is not exact amount of AES blocks\n"); 79721fe9767SDmitry Kasatkin return -EINVAL; 79821fe9767SDmitry Kasatkin } 79921fe9767SDmitry Kasatkin 800537559a5SDmitry Kasatkin dd = omap_aes_find_dev(ctx); 801537559a5SDmitry Kasatkin if (!dd) 802537559a5SDmitry Kasatkin return -ENODEV; 803537559a5SDmitry Kasatkin 804537559a5SDmitry Kasatkin rctx->mode = mode; 805537559a5SDmitry Kasatkin 80621fe9767SDmitry Kasatkin return omap_aes_handle_queue(dd, req); 807537559a5SDmitry Kasatkin } 808537559a5SDmitry Kasatkin 809537559a5SDmitry Kasatkin /* ********************** ALG API ************************************ */ 810537559a5SDmitry Kasatkin 811537559a5SDmitry Kasatkin static int omap_aes_setkey(struct crypto_ablkcipher *tfm, const u8 *key, 812537559a5SDmitry Kasatkin unsigned int keylen) 813537559a5SDmitry Kasatkin { 814537559a5SDmitry Kasatkin struct omap_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm); 815537559a5SDmitry Kasatkin 816537559a5SDmitry Kasatkin if (keylen != AES_KEYSIZE_128 && keylen != AES_KEYSIZE_192 && 817537559a5SDmitry Kasatkin keylen != AES_KEYSIZE_256) 818537559a5SDmitry Kasatkin return -EINVAL; 819537559a5SDmitry Kasatkin 820537559a5SDmitry Kasatkin pr_debug("enter, keylen: %d\n", keylen); 821537559a5SDmitry Kasatkin 822537559a5SDmitry Kasatkin memcpy(ctx->key, key, keylen); 823537559a5SDmitry Kasatkin ctx->keylen = keylen; 824537559a5SDmitry Kasatkin 825537559a5SDmitry Kasatkin return 0; 826537559a5SDmitry Kasatkin } 827537559a5SDmitry Kasatkin 828537559a5SDmitry Kasatkin static int omap_aes_ecb_encrypt(struct ablkcipher_request *req) 829537559a5SDmitry Kasatkin { 830537559a5SDmitry Kasatkin return omap_aes_crypt(req, FLAGS_ENCRYPT); 831537559a5SDmitry Kasatkin } 832537559a5SDmitry Kasatkin 833537559a5SDmitry Kasatkin static int omap_aes_ecb_decrypt(struct ablkcipher_request *req) 834537559a5SDmitry Kasatkin { 835537559a5SDmitry Kasatkin return omap_aes_crypt(req, 0); 836537559a5SDmitry Kasatkin } 837537559a5SDmitry Kasatkin 838537559a5SDmitry Kasatkin static int omap_aes_cbc_encrypt(struct ablkcipher_request *req) 839537559a5SDmitry Kasatkin { 840537559a5SDmitry Kasatkin return omap_aes_crypt(req, FLAGS_ENCRYPT | FLAGS_CBC); 841537559a5SDmitry Kasatkin } 842537559a5SDmitry Kasatkin 843537559a5SDmitry Kasatkin static int omap_aes_cbc_decrypt(struct ablkcipher_request *req) 844537559a5SDmitry Kasatkin { 845537559a5SDmitry Kasatkin return omap_aes_crypt(req, FLAGS_CBC); 846537559a5SDmitry Kasatkin } 847537559a5SDmitry Kasatkin 848f9fb69e7SMark A. Greer static int omap_aes_ctr_encrypt(struct ablkcipher_request *req) 849f9fb69e7SMark A. Greer { 850f9fb69e7SMark A. Greer return omap_aes_crypt(req, FLAGS_ENCRYPT | FLAGS_CTR); 851f9fb69e7SMark A. Greer } 852f9fb69e7SMark A. Greer 853f9fb69e7SMark A. Greer static int omap_aes_ctr_decrypt(struct ablkcipher_request *req) 854f9fb69e7SMark A. Greer { 855f9fb69e7SMark A. Greer return omap_aes_crypt(req, FLAGS_CTR); 856f9fb69e7SMark A. Greer } 857f9fb69e7SMark A. Greer 858537559a5SDmitry Kasatkin static int omap_aes_cra_init(struct crypto_tfm *tfm) 859537559a5SDmitry Kasatkin { 860a3485e68SJoel A Fernandes struct omap_aes_dev *dd = NULL; 861537559a5SDmitry Kasatkin 862a3485e68SJoel A Fernandes /* Find AES device, currently picks the first device */ 863a3485e68SJoel A Fernandes spin_lock_bh(&list_lock); 864a3485e68SJoel A Fernandes list_for_each_entry(dd, &dev_list, list) { 865a3485e68SJoel A Fernandes break; 866a3485e68SJoel A Fernandes } 867a3485e68SJoel A Fernandes spin_unlock_bh(&list_lock); 868a3485e68SJoel A Fernandes 869a3485e68SJoel A Fernandes pm_runtime_get_sync(dd->dev); 870537559a5SDmitry Kasatkin tfm->crt_ablkcipher.reqsize = sizeof(struct omap_aes_reqctx); 871537559a5SDmitry Kasatkin 872537559a5SDmitry Kasatkin return 0; 873537559a5SDmitry Kasatkin } 874537559a5SDmitry Kasatkin 875537559a5SDmitry Kasatkin static void omap_aes_cra_exit(struct crypto_tfm *tfm) 876537559a5SDmitry Kasatkin { 877a3485e68SJoel A Fernandes struct omap_aes_dev *dd = NULL; 878a3485e68SJoel A Fernandes 879a3485e68SJoel A Fernandes /* Find AES device, currently picks the first device */ 880a3485e68SJoel A Fernandes spin_lock_bh(&list_lock); 881a3485e68SJoel A Fernandes list_for_each_entry(dd, &dev_list, list) { 882a3485e68SJoel A Fernandes break; 883a3485e68SJoel A Fernandes } 884a3485e68SJoel A Fernandes spin_unlock_bh(&list_lock); 885a3485e68SJoel A Fernandes 886a3485e68SJoel A Fernandes pm_runtime_put_sync(dd->dev); 887537559a5SDmitry Kasatkin } 888537559a5SDmitry Kasatkin 889537559a5SDmitry Kasatkin /* ********************** ALGS ************************************ */ 890537559a5SDmitry Kasatkin 891f9fb69e7SMark A. Greer static struct crypto_alg algs_ecb_cbc[] = { 892537559a5SDmitry Kasatkin { 893537559a5SDmitry Kasatkin .cra_name = "ecb(aes)", 894537559a5SDmitry Kasatkin .cra_driver_name = "ecb-aes-omap", 895537559a5SDmitry Kasatkin .cra_priority = 100, 896d912bb76SNikos Mavrogiannopoulos .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | 897d912bb76SNikos Mavrogiannopoulos CRYPTO_ALG_KERN_DRIVER_ONLY | 898d912bb76SNikos Mavrogiannopoulos CRYPTO_ALG_ASYNC, 899537559a5SDmitry Kasatkin .cra_blocksize = AES_BLOCK_SIZE, 900537559a5SDmitry Kasatkin .cra_ctxsize = sizeof(struct omap_aes_ctx), 901537559a5SDmitry Kasatkin .cra_alignmask = 0, 902537559a5SDmitry Kasatkin .cra_type = &crypto_ablkcipher_type, 903537559a5SDmitry Kasatkin .cra_module = THIS_MODULE, 904537559a5SDmitry Kasatkin .cra_init = omap_aes_cra_init, 905537559a5SDmitry Kasatkin .cra_exit = omap_aes_cra_exit, 906537559a5SDmitry Kasatkin .cra_u.ablkcipher = { 907537559a5SDmitry Kasatkin .min_keysize = AES_MIN_KEY_SIZE, 908537559a5SDmitry Kasatkin .max_keysize = AES_MAX_KEY_SIZE, 909537559a5SDmitry Kasatkin .setkey = omap_aes_setkey, 910537559a5SDmitry Kasatkin .encrypt = omap_aes_ecb_encrypt, 911537559a5SDmitry Kasatkin .decrypt = omap_aes_ecb_decrypt, 912537559a5SDmitry Kasatkin } 913537559a5SDmitry Kasatkin }, 914537559a5SDmitry Kasatkin { 915537559a5SDmitry Kasatkin .cra_name = "cbc(aes)", 916537559a5SDmitry Kasatkin .cra_driver_name = "cbc-aes-omap", 917537559a5SDmitry Kasatkin .cra_priority = 100, 918d912bb76SNikos Mavrogiannopoulos .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | 919d912bb76SNikos Mavrogiannopoulos CRYPTO_ALG_KERN_DRIVER_ONLY | 920d912bb76SNikos Mavrogiannopoulos CRYPTO_ALG_ASYNC, 921537559a5SDmitry Kasatkin .cra_blocksize = AES_BLOCK_SIZE, 922537559a5SDmitry Kasatkin .cra_ctxsize = sizeof(struct omap_aes_ctx), 923537559a5SDmitry Kasatkin .cra_alignmask = 0, 924537559a5SDmitry Kasatkin .cra_type = &crypto_ablkcipher_type, 925537559a5SDmitry Kasatkin .cra_module = THIS_MODULE, 926537559a5SDmitry Kasatkin .cra_init = omap_aes_cra_init, 927537559a5SDmitry Kasatkin .cra_exit = omap_aes_cra_exit, 928537559a5SDmitry Kasatkin .cra_u.ablkcipher = { 929537559a5SDmitry Kasatkin .min_keysize = AES_MIN_KEY_SIZE, 930537559a5SDmitry Kasatkin .max_keysize = AES_MAX_KEY_SIZE, 931537559a5SDmitry Kasatkin .ivsize = AES_BLOCK_SIZE, 932537559a5SDmitry Kasatkin .setkey = omap_aes_setkey, 933537559a5SDmitry Kasatkin .encrypt = omap_aes_cbc_encrypt, 934537559a5SDmitry Kasatkin .decrypt = omap_aes_cbc_decrypt, 935537559a5SDmitry Kasatkin } 936537559a5SDmitry Kasatkin } 937537559a5SDmitry Kasatkin }; 938537559a5SDmitry Kasatkin 939f9fb69e7SMark A. Greer static struct crypto_alg algs_ctr[] = { 940f9fb69e7SMark A. Greer { 941f9fb69e7SMark A. Greer .cra_name = "ctr(aes)", 942f9fb69e7SMark A. Greer .cra_driver_name = "ctr-aes-omap", 943f9fb69e7SMark A. Greer .cra_priority = 100, 944f9fb69e7SMark A. Greer .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | 945f9fb69e7SMark A. Greer CRYPTO_ALG_KERN_DRIVER_ONLY | 946f9fb69e7SMark A. Greer CRYPTO_ALG_ASYNC, 947f9fb69e7SMark A. Greer .cra_blocksize = AES_BLOCK_SIZE, 948f9fb69e7SMark A. Greer .cra_ctxsize = sizeof(struct omap_aes_ctx), 949f9fb69e7SMark A. Greer .cra_alignmask = 0, 950f9fb69e7SMark A. Greer .cra_type = &crypto_ablkcipher_type, 951f9fb69e7SMark A. Greer .cra_module = THIS_MODULE, 952f9fb69e7SMark A. Greer .cra_init = omap_aes_cra_init, 953f9fb69e7SMark A. Greer .cra_exit = omap_aes_cra_exit, 954f9fb69e7SMark A. Greer .cra_u.ablkcipher = { 955f9fb69e7SMark A. Greer .min_keysize = AES_MIN_KEY_SIZE, 956f9fb69e7SMark A. Greer .max_keysize = AES_MAX_KEY_SIZE, 957f9fb69e7SMark A. Greer .geniv = "eseqiv", 958f9fb69e7SMark A. Greer .ivsize = AES_BLOCK_SIZE, 959f9fb69e7SMark A. Greer .setkey = omap_aes_setkey, 960f9fb69e7SMark A. Greer .encrypt = omap_aes_ctr_encrypt, 961f9fb69e7SMark A. Greer .decrypt = omap_aes_ctr_decrypt, 962f9fb69e7SMark A. Greer } 963f9fb69e7SMark A. Greer } , 964f9fb69e7SMark A. Greer }; 965f9fb69e7SMark A. Greer 966f9fb69e7SMark A. Greer static struct omap_aes_algs_info omap_aes_algs_info_ecb_cbc[] = { 967f9fb69e7SMark A. Greer { 968f9fb69e7SMark A. Greer .algs_list = algs_ecb_cbc, 969f9fb69e7SMark A. Greer .size = ARRAY_SIZE(algs_ecb_cbc), 970f9fb69e7SMark A. Greer }, 971f9fb69e7SMark A. Greer }; 972f9fb69e7SMark A. Greer 9730d35583aSMark A. Greer static const struct omap_aes_pdata omap_aes_pdata_omap2 = { 974f9fb69e7SMark A. Greer .algs_info = omap_aes_algs_info_ecb_cbc, 975f9fb69e7SMark A. Greer .algs_info_size = ARRAY_SIZE(omap_aes_algs_info_ecb_cbc), 9760d35583aSMark A. Greer .trigger = omap_aes_dma_trigger_omap2, 9770d35583aSMark A. Greer .key_ofs = 0x1c, 9780d35583aSMark A. Greer .iv_ofs = 0x20, 9790d35583aSMark A. Greer .ctrl_ofs = 0x30, 9800d35583aSMark A. Greer .data_ofs = 0x34, 9810d35583aSMark A. Greer .rev_ofs = 0x44, 9820d35583aSMark A. Greer .mask_ofs = 0x48, 9830d35583aSMark A. Greer .dma_enable_in = BIT(2), 9840d35583aSMark A. Greer .dma_enable_out = BIT(3), 9850d35583aSMark A. Greer .dma_start = BIT(5), 9860d35583aSMark A. Greer .major_mask = 0xf0, 9870d35583aSMark A. Greer .major_shift = 4, 9880d35583aSMark A. Greer .minor_mask = 0x0f, 9890d35583aSMark A. Greer .minor_shift = 0, 9900d35583aSMark A. Greer }; 9910d35583aSMark A. Greer 992bc69d124SMark A. Greer #ifdef CONFIG_OF 993f9fb69e7SMark A. Greer static struct omap_aes_algs_info omap_aes_algs_info_ecb_cbc_ctr[] = { 994f9fb69e7SMark A. Greer { 995f9fb69e7SMark A. Greer .algs_list = algs_ecb_cbc, 996f9fb69e7SMark A. Greer .size = ARRAY_SIZE(algs_ecb_cbc), 997f9fb69e7SMark A. Greer }, 998f9fb69e7SMark A. Greer { 999f9fb69e7SMark A. Greer .algs_list = algs_ctr, 1000f9fb69e7SMark A. Greer .size = ARRAY_SIZE(algs_ctr), 1001f9fb69e7SMark A. Greer }, 1002f9fb69e7SMark A. Greer }; 1003f9fb69e7SMark A. Greer 1004f9fb69e7SMark A. Greer static const struct omap_aes_pdata omap_aes_pdata_omap3 = { 1005f9fb69e7SMark A. Greer .algs_info = omap_aes_algs_info_ecb_cbc_ctr, 1006f9fb69e7SMark A. Greer .algs_info_size = ARRAY_SIZE(omap_aes_algs_info_ecb_cbc_ctr), 1007f9fb69e7SMark A. Greer .trigger = omap_aes_dma_trigger_omap2, 1008f9fb69e7SMark A. Greer .key_ofs = 0x1c, 1009f9fb69e7SMark A. Greer .iv_ofs = 0x20, 1010f9fb69e7SMark A. Greer .ctrl_ofs = 0x30, 1011f9fb69e7SMark A. Greer .data_ofs = 0x34, 1012f9fb69e7SMark A. Greer .rev_ofs = 0x44, 1013f9fb69e7SMark A. Greer .mask_ofs = 0x48, 1014f9fb69e7SMark A. Greer .dma_enable_in = BIT(2), 1015f9fb69e7SMark A. Greer .dma_enable_out = BIT(3), 1016f9fb69e7SMark A. Greer .dma_start = BIT(5), 1017f9fb69e7SMark A. Greer .major_mask = 0xf0, 1018f9fb69e7SMark A. Greer .major_shift = 4, 1019f9fb69e7SMark A. Greer .minor_mask = 0x0f, 1020f9fb69e7SMark A. Greer .minor_shift = 0, 1021f9fb69e7SMark A. Greer }; 1022f9fb69e7SMark A. Greer 10230d35583aSMark A. Greer static const struct omap_aes_pdata omap_aes_pdata_omap4 = { 1024f9fb69e7SMark A. Greer .algs_info = omap_aes_algs_info_ecb_cbc_ctr, 1025f9fb69e7SMark A. Greer .algs_info_size = ARRAY_SIZE(omap_aes_algs_info_ecb_cbc_ctr), 10260d35583aSMark A. Greer .trigger = omap_aes_dma_trigger_omap4, 10270d35583aSMark A. Greer .key_ofs = 0x3c, 10280d35583aSMark A. Greer .iv_ofs = 0x40, 10290d35583aSMark A. Greer .ctrl_ofs = 0x50, 10300d35583aSMark A. Greer .data_ofs = 0x60, 10310d35583aSMark A. Greer .rev_ofs = 0x80, 10320d35583aSMark A. Greer .mask_ofs = 0x84, 10330d35583aSMark A. Greer .dma_enable_in = BIT(5), 10340d35583aSMark A. Greer .dma_enable_out = BIT(6), 10350d35583aSMark A. Greer .major_mask = 0x0700, 10360d35583aSMark A. Greer .major_shift = 8, 10370d35583aSMark A. Greer .minor_mask = 0x003f, 10380d35583aSMark A. Greer .minor_shift = 0, 10390d35583aSMark A. Greer }; 10400d35583aSMark A. Greer 1041bc69d124SMark A. Greer static const struct of_device_id omap_aes_of_match[] = { 1042bc69d124SMark A. Greer { 1043bc69d124SMark A. Greer .compatible = "ti,omap2-aes", 10440d35583aSMark A. Greer .data = &omap_aes_pdata_omap2, 10450d35583aSMark A. Greer }, 10460d35583aSMark A. Greer { 1047f9fb69e7SMark A. Greer .compatible = "ti,omap3-aes", 1048f9fb69e7SMark A. Greer .data = &omap_aes_pdata_omap3, 1049f9fb69e7SMark A. Greer }, 1050f9fb69e7SMark A. Greer { 10510d35583aSMark A. Greer .compatible = "ti,omap4-aes", 10520d35583aSMark A. Greer .data = &omap_aes_pdata_omap4, 1053bc69d124SMark A. Greer }, 1054bc69d124SMark A. Greer {}, 1055bc69d124SMark A. Greer }; 1056bc69d124SMark A. Greer MODULE_DEVICE_TABLE(of, omap_aes_of_match); 1057bc69d124SMark A. Greer 1058bc69d124SMark A. Greer static int omap_aes_get_res_of(struct omap_aes_dev *dd, 1059bc69d124SMark A. Greer struct device *dev, struct resource *res) 1060bc69d124SMark A. Greer { 1061bc69d124SMark A. Greer struct device_node *node = dev->of_node; 1062bc69d124SMark A. Greer const struct of_device_id *match; 1063bc69d124SMark A. Greer int err = 0; 1064bc69d124SMark A. Greer 1065bc69d124SMark A. Greer match = of_match_device(of_match_ptr(omap_aes_of_match), dev); 1066bc69d124SMark A. Greer if (!match) { 1067bc69d124SMark A. Greer dev_err(dev, "no compatible OF match\n"); 1068bc69d124SMark A. Greer err = -EINVAL; 1069bc69d124SMark A. Greer goto err; 1070bc69d124SMark A. Greer } 1071bc69d124SMark A. Greer 1072bc69d124SMark A. Greer err = of_address_to_resource(node, 0, res); 1073bc69d124SMark A. Greer if (err < 0) { 1074bc69d124SMark A. Greer dev_err(dev, "can't translate OF node address\n"); 1075bc69d124SMark A. Greer err = -EINVAL; 1076bc69d124SMark A. Greer goto err; 1077bc69d124SMark A. Greer } 1078bc69d124SMark A. Greer 1079bc69d124SMark A. Greer dd->dma_out = -1; /* Dummy value that's unused */ 1080bc69d124SMark A. Greer dd->dma_in = -1; /* Dummy value that's unused */ 1081bc69d124SMark A. Greer 10820d35583aSMark A. Greer dd->pdata = match->data; 10830d35583aSMark A. Greer 1084bc69d124SMark A. Greer err: 1085bc69d124SMark A. Greer return err; 1086bc69d124SMark A. Greer } 1087bc69d124SMark A. Greer #else 1088bc69d124SMark A. Greer static const struct of_device_id omap_aes_of_match[] = { 1089bc69d124SMark A. Greer {}, 1090bc69d124SMark A. Greer }; 1091bc69d124SMark A. Greer 1092bc69d124SMark A. Greer static int omap_aes_get_res_of(struct omap_aes_dev *dd, 1093bc69d124SMark A. Greer struct device *dev, struct resource *res) 1094bc69d124SMark A. Greer { 1095bc69d124SMark A. Greer return -EINVAL; 1096bc69d124SMark A. Greer } 1097bc69d124SMark A. Greer #endif 1098bc69d124SMark A. Greer 1099bc69d124SMark A. Greer static int omap_aes_get_res_pdev(struct omap_aes_dev *dd, 1100bc69d124SMark A. Greer struct platform_device *pdev, struct resource *res) 1101bc69d124SMark A. Greer { 1102bc69d124SMark A. Greer struct device *dev = &pdev->dev; 1103bc69d124SMark A. Greer struct resource *r; 1104bc69d124SMark A. Greer int err = 0; 1105bc69d124SMark A. Greer 1106bc69d124SMark A. Greer /* Get the base address */ 1107bc69d124SMark A. Greer r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1108bc69d124SMark A. Greer if (!r) { 1109bc69d124SMark A. Greer dev_err(dev, "no MEM resource info\n"); 1110bc69d124SMark A. Greer err = -ENODEV; 1111bc69d124SMark A. Greer goto err; 1112bc69d124SMark A. Greer } 1113bc69d124SMark A. Greer memcpy(res, r, sizeof(*res)); 1114bc69d124SMark A. Greer 1115bc69d124SMark A. Greer /* Get the DMA out channel */ 1116bc69d124SMark A. Greer r = platform_get_resource(pdev, IORESOURCE_DMA, 0); 1117bc69d124SMark A. Greer if (!r) { 1118bc69d124SMark A. Greer dev_err(dev, "no DMA out resource info\n"); 1119bc69d124SMark A. Greer err = -ENODEV; 1120bc69d124SMark A. Greer goto err; 1121bc69d124SMark A. Greer } 1122bc69d124SMark A. Greer dd->dma_out = r->start; 1123bc69d124SMark A. Greer 1124bc69d124SMark A. Greer /* Get the DMA in channel */ 1125bc69d124SMark A. Greer r = platform_get_resource(pdev, IORESOURCE_DMA, 1); 1126bc69d124SMark A. Greer if (!r) { 1127bc69d124SMark A. Greer dev_err(dev, "no DMA in resource info\n"); 1128bc69d124SMark A. Greer err = -ENODEV; 1129bc69d124SMark A. Greer goto err; 1130bc69d124SMark A. Greer } 1131bc69d124SMark A. Greer dd->dma_in = r->start; 1132bc69d124SMark A. Greer 11330d35583aSMark A. Greer /* Only OMAP2/3 can be non-DT */ 11340d35583aSMark A. Greer dd->pdata = &omap_aes_pdata_omap2; 11350d35583aSMark A. Greer 1136bc69d124SMark A. Greer err: 1137bc69d124SMark A. Greer return err; 1138bc69d124SMark A. Greer } 1139bc69d124SMark A. Greer 1140537559a5SDmitry Kasatkin static int omap_aes_probe(struct platform_device *pdev) 1141537559a5SDmitry Kasatkin { 1142537559a5SDmitry Kasatkin struct device *dev = &pdev->dev; 1143537559a5SDmitry Kasatkin struct omap_aes_dev *dd; 1144f9fb69e7SMark A. Greer struct crypto_alg *algp; 1145bc69d124SMark A. Greer struct resource res; 1146537559a5SDmitry Kasatkin int err = -ENOMEM, i, j; 1147537559a5SDmitry Kasatkin u32 reg; 1148537559a5SDmitry Kasatkin 1149537559a5SDmitry Kasatkin dd = kzalloc(sizeof(struct omap_aes_dev), GFP_KERNEL); 1150537559a5SDmitry Kasatkin if (dd == NULL) { 1151537559a5SDmitry Kasatkin dev_err(dev, "unable to alloc data struct.\n"); 1152537559a5SDmitry Kasatkin goto err_data; 1153537559a5SDmitry Kasatkin } 1154537559a5SDmitry Kasatkin dd->dev = dev; 1155537559a5SDmitry Kasatkin platform_set_drvdata(pdev, dd); 1156537559a5SDmitry Kasatkin 1157537559a5SDmitry Kasatkin spin_lock_init(&dd->lock); 1158537559a5SDmitry Kasatkin crypto_init_queue(&dd->queue, OMAP_AES_QUEUE_LENGTH); 1159537559a5SDmitry Kasatkin 1160bc69d124SMark A. Greer err = (dev->of_node) ? omap_aes_get_res_of(dd, dev, &res) : 1161bc69d124SMark A. Greer omap_aes_get_res_pdev(dd, pdev, &res); 1162bc69d124SMark A. Greer if (err) 1163537559a5SDmitry Kasatkin goto err_res; 1164537559a5SDmitry Kasatkin 116530862281SLaurent Navet dd->io_base = devm_ioremap_resource(dev, &res); 116630862281SLaurent Navet if (IS_ERR(dd->io_base)) { 116730862281SLaurent Navet err = PTR_ERR(dd->io_base); 11685946c4a5SMark A. Greer goto err_res; 1169537559a5SDmitry Kasatkin } 1170bc69d124SMark A. Greer dd->phys_base = res.start; 1171537559a5SDmitry Kasatkin 11725946c4a5SMark A. Greer pm_runtime_enable(dev); 11735946c4a5SMark A. Greer pm_runtime_get_sync(dev); 11745946c4a5SMark A. Greer 11750d35583aSMark A. Greer omap_aes_dma_stop(dd); 11760d35583aSMark A. Greer 11770d35583aSMark A. Greer reg = omap_aes_read(dd, AES_REG_REV(dd)); 11785946c4a5SMark A. Greer 11795946c4a5SMark A. Greer pm_runtime_put_sync(dev); 1180537559a5SDmitry Kasatkin 11810d35583aSMark A. Greer dev_info(dev, "OMAP AES hw accel rev: %u.%u\n", 11820d35583aSMark A. Greer (reg & dd->pdata->major_mask) >> dd->pdata->major_shift, 11830d35583aSMark A. Greer (reg & dd->pdata->minor_mask) >> dd->pdata->minor_shift); 11840d35583aSMark A. Greer 118521fe9767SDmitry Kasatkin tasklet_init(&dd->done_task, omap_aes_done_task, (unsigned long)dd); 118621fe9767SDmitry Kasatkin tasklet_init(&dd->queue_task, omap_aes_queue_task, (unsigned long)dd); 1187537559a5SDmitry Kasatkin 1188537559a5SDmitry Kasatkin err = omap_aes_dma_init(dd); 1189537559a5SDmitry Kasatkin if (err) 1190537559a5SDmitry Kasatkin goto err_dma; 1191537559a5SDmitry Kasatkin 1192537559a5SDmitry Kasatkin INIT_LIST_HEAD(&dd->list); 1193537559a5SDmitry Kasatkin spin_lock(&list_lock); 1194537559a5SDmitry Kasatkin list_add_tail(&dd->list, &dev_list); 1195537559a5SDmitry Kasatkin spin_unlock(&list_lock); 1196537559a5SDmitry Kasatkin 1197f9fb69e7SMark A. Greer for (i = 0; i < dd->pdata->algs_info_size; i++) { 1198f9fb69e7SMark A. Greer for (j = 0; j < dd->pdata->algs_info[i].size; j++) { 1199f9fb69e7SMark A. Greer algp = &dd->pdata->algs_info[i].algs_list[j]; 1200f9fb69e7SMark A. Greer 1201f9fb69e7SMark A. Greer pr_debug("reg alg: %s\n", algp->cra_name); 1202f9fb69e7SMark A. Greer INIT_LIST_HEAD(&algp->cra_list); 1203f9fb69e7SMark A. Greer 1204f9fb69e7SMark A. Greer err = crypto_register_alg(algp); 1205537559a5SDmitry Kasatkin if (err) 1206537559a5SDmitry Kasatkin goto err_algs; 1207f9fb69e7SMark A. Greer 1208f9fb69e7SMark A. Greer dd->pdata->algs_info[i].registered++; 1209f9fb69e7SMark A. Greer } 1210537559a5SDmitry Kasatkin } 1211537559a5SDmitry Kasatkin 1212537559a5SDmitry Kasatkin return 0; 1213537559a5SDmitry Kasatkin err_algs: 1214f9fb69e7SMark A. Greer for (i = dd->pdata->algs_info_size - 1; i >= 0; i--) 1215f9fb69e7SMark A. Greer for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--) 1216f9fb69e7SMark A. Greer crypto_unregister_alg( 1217f9fb69e7SMark A. Greer &dd->pdata->algs_info[i].algs_list[j]); 1218537559a5SDmitry Kasatkin omap_aes_dma_cleanup(dd); 1219537559a5SDmitry Kasatkin err_dma: 122021fe9767SDmitry Kasatkin tasklet_kill(&dd->done_task); 122121fe9767SDmitry Kasatkin tasklet_kill(&dd->queue_task); 12225946c4a5SMark A. Greer pm_runtime_disable(dev); 1223537559a5SDmitry Kasatkin err_res: 1224537559a5SDmitry Kasatkin kfree(dd); 1225537559a5SDmitry Kasatkin dd = NULL; 1226537559a5SDmitry Kasatkin err_data: 1227537559a5SDmitry Kasatkin dev_err(dev, "initialization failed.\n"); 1228537559a5SDmitry Kasatkin return err; 1229537559a5SDmitry Kasatkin } 1230537559a5SDmitry Kasatkin 1231537559a5SDmitry Kasatkin static int omap_aes_remove(struct platform_device *pdev) 1232537559a5SDmitry Kasatkin { 1233537559a5SDmitry Kasatkin struct omap_aes_dev *dd = platform_get_drvdata(pdev); 1234f9fb69e7SMark A. Greer int i, j; 1235537559a5SDmitry Kasatkin 1236537559a5SDmitry Kasatkin if (!dd) 1237537559a5SDmitry Kasatkin return -ENODEV; 1238537559a5SDmitry Kasatkin 1239537559a5SDmitry Kasatkin spin_lock(&list_lock); 1240537559a5SDmitry Kasatkin list_del(&dd->list); 1241537559a5SDmitry Kasatkin spin_unlock(&list_lock); 1242537559a5SDmitry Kasatkin 1243f9fb69e7SMark A. Greer for (i = dd->pdata->algs_info_size - 1; i >= 0; i--) 1244f9fb69e7SMark A. Greer for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--) 1245f9fb69e7SMark A. Greer crypto_unregister_alg( 1246f9fb69e7SMark A. Greer &dd->pdata->algs_info[i].algs_list[j]); 1247537559a5SDmitry Kasatkin 124821fe9767SDmitry Kasatkin tasklet_kill(&dd->done_task); 124921fe9767SDmitry Kasatkin tasklet_kill(&dd->queue_task); 1250537559a5SDmitry Kasatkin omap_aes_dma_cleanup(dd); 12515946c4a5SMark A. Greer pm_runtime_disable(dd->dev); 1252537559a5SDmitry Kasatkin kfree(dd); 1253537559a5SDmitry Kasatkin dd = NULL; 1254537559a5SDmitry Kasatkin 1255537559a5SDmitry Kasatkin return 0; 1256537559a5SDmitry Kasatkin } 1257537559a5SDmitry Kasatkin 12580635fb3aSMark A. Greer #ifdef CONFIG_PM_SLEEP 12590635fb3aSMark A. Greer static int omap_aes_suspend(struct device *dev) 12600635fb3aSMark A. Greer { 12610635fb3aSMark A. Greer pm_runtime_put_sync(dev); 12620635fb3aSMark A. Greer return 0; 12630635fb3aSMark A. Greer } 12640635fb3aSMark A. Greer 12650635fb3aSMark A. Greer static int omap_aes_resume(struct device *dev) 12660635fb3aSMark A. Greer { 12670635fb3aSMark A. Greer pm_runtime_get_sync(dev); 12680635fb3aSMark A. Greer return 0; 12690635fb3aSMark A. Greer } 12700635fb3aSMark A. Greer #endif 12710635fb3aSMark A. Greer 12720635fb3aSMark A. Greer static const struct dev_pm_ops omap_aes_pm_ops = { 12730635fb3aSMark A. Greer SET_SYSTEM_SLEEP_PM_OPS(omap_aes_suspend, omap_aes_resume) 12740635fb3aSMark A. Greer }; 12750635fb3aSMark A. Greer 1276537559a5SDmitry Kasatkin static struct platform_driver omap_aes_driver = { 1277537559a5SDmitry Kasatkin .probe = omap_aes_probe, 1278537559a5SDmitry Kasatkin .remove = omap_aes_remove, 1279537559a5SDmitry Kasatkin .driver = { 1280537559a5SDmitry Kasatkin .name = "omap-aes", 1281537559a5SDmitry Kasatkin .owner = THIS_MODULE, 12820635fb3aSMark A. Greer .pm = &omap_aes_pm_ops, 1283bc69d124SMark A. Greer .of_match_table = omap_aes_of_match, 1284537559a5SDmitry Kasatkin }, 1285537559a5SDmitry Kasatkin }; 1286537559a5SDmitry Kasatkin 128794e51df9SSachin Kamat module_platform_driver(omap_aes_driver); 1288537559a5SDmitry Kasatkin 1289537559a5SDmitry Kasatkin MODULE_DESCRIPTION("OMAP AES hw acceleration support."); 1290537559a5SDmitry Kasatkin MODULE_LICENSE("GPL v2"); 1291537559a5SDmitry Kasatkin MODULE_AUTHOR("Dmitry Kasatkin"); 1292537559a5SDmitry Kasatkin 1293