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 431bf95ccaSJoel Fernandes #define _calc_walked(inout) (dd->inout##_walk.offset - dd->inout##_sg->offset) 441bf95ccaSJoel Fernandes 45537559a5SDmitry Kasatkin /* OMAP TRM gives bitfields as start:end, where start is the higher bit 46537559a5SDmitry Kasatkin number. For example 7:0 */ 47537559a5SDmitry Kasatkin #define FLD_MASK(start, end) (((1 << ((start) - (end) + 1)) - 1) << (end)) 48537559a5SDmitry Kasatkin #define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end)) 49537559a5SDmitry Kasatkin 500d35583aSMark A. Greer #define AES_REG_KEY(dd, x) ((dd)->pdata->key_ofs - \ 510d35583aSMark A. Greer ((x ^ 0x01) * 0x04)) 520d35583aSMark A. Greer #define AES_REG_IV(dd, x) ((dd)->pdata->iv_ofs + ((x) * 0x04)) 53537559a5SDmitry Kasatkin 540d35583aSMark A. Greer #define AES_REG_CTRL(dd) ((dd)->pdata->ctrl_ofs) 55f9fb69e7SMark A. Greer #define AES_REG_CTRL_CTR_WIDTH_MASK (3 << 7) 56f9fb69e7SMark A. Greer #define AES_REG_CTRL_CTR_WIDTH_32 (0 << 7) 57f9fb69e7SMark A. Greer #define AES_REG_CTRL_CTR_WIDTH_64 (1 << 7) 58f9fb69e7SMark A. Greer #define AES_REG_CTRL_CTR_WIDTH_96 (2 << 7) 59f9fb69e7SMark A. Greer #define AES_REG_CTRL_CTR_WIDTH_128 (3 << 7) 60537559a5SDmitry Kasatkin #define AES_REG_CTRL_CTR (1 << 6) 61537559a5SDmitry Kasatkin #define AES_REG_CTRL_CBC (1 << 5) 62537559a5SDmitry Kasatkin #define AES_REG_CTRL_KEY_SIZE (3 << 3) 63537559a5SDmitry Kasatkin #define AES_REG_CTRL_DIRECTION (1 << 2) 64537559a5SDmitry Kasatkin #define AES_REG_CTRL_INPUT_READY (1 << 1) 65537559a5SDmitry Kasatkin #define AES_REG_CTRL_OUTPUT_READY (1 << 0) 66537559a5SDmitry Kasatkin 670d35583aSMark A. Greer #define AES_REG_DATA_N(dd, x) ((dd)->pdata->data_ofs + ((x) * 0x04)) 68537559a5SDmitry Kasatkin 690d35583aSMark A. Greer #define AES_REG_REV(dd) ((dd)->pdata->rev_ofs) 70537559a5SDmitry Kasatkin 710d35583aSMark A. Greer #define AES_REG_MASK(dd) ((dd)->pdata->mask_ofs) 72537559a5SDmitry Kasatkin #define AES_REG_MASK_SIDLE (1 << 6) 73537559a5SDmitry Kasatkin #define AES_REG_MASK_START (1 << 5) 74537559a5SDmitry Kasatkin #define AES_REG_MASK_DMA_OUT_EN (1 << 3) 75537559a5SDmitry Kasatkin #define AES_REG_MASK_DMA_IN_EN (1 << 2) 76537559a5SDmitry Kasatkin #define AES_REG_MASK_SOFTRESET (1 << 1) 77537559a5SDmitry Kasatkin #define AES_REG_AUTOIDLE (1 << 0) 78537559a5SDmitry Kasatkin 790d35583aSMark A. Greer #define AES_REG_LENGTH_N(x) (0x54 + ((x) * 0x04)) 80537559a5SDmitry Kasatkin 8167216756SJoel Fernandes #define AES_REG_IRQ_STATUS(dd) ((dd)->pdata->irq_status_ofs) 8267216756SJoel Fernandes #define AES_REG_IRQ_ENABLE(dd) ((dd)->pdata->irq_enable_ofs) 8367216756SJoel Fernandes #define AES_REG_IRQ_DATA_IN BIT(1) 8467216756SJoel Fernandes #define AES_REG_IRQ_DATA_OUT BIT(2) 85537559a5SDmitry Kasatkin #define DEFAULT_TIMEOUT (5*HZ) 86537559a5SDmitry Kasatkin 87537559a5SDmitry Kasatkin #define FLAGS_MODE_MASK 0x000f 88537559a5SDmitry Kasatkin #define FLAGS_ENCRYPT BIT(0) 89537559a5SDmitry Kasatkin #define FLAGS_CBC BIT(1) 90537559a5SDmitry Kasatkin #define FLAGS_GIV BIT(2) 91f9fb69e7SMark A. Greer #define FLAGS_CTR BIT(3) 92537559a5SDmitry Kasatkin 9367a730ceSDmitry Kasatkin #define FLAGS_INIT BIT(4) 9467a730ceSDmitry Kasatkin #define FLAGS_FAST BIT(5) 9567a730ceSDmitry Kasatkin #define FLAGS_BUSY BIT(6) 96537559a5SDmitry Kasatkin 971bf95ccaSJoel Fernandes #define AES_BLOCK_WORDS (AES_BLOCK_SIZE >> 2) 981bf95ccaSJoel Fernandes 99537559a5SDmitry Kasatkin struct omap_aes_ctx { 100537559a5SDmitry Kasatkin struct omap_aes_dev *dd; 101537559a5SDmitry Kasatkin 102537559a5SDmitry Kasatkin int keylen; 103537559a5SDmitry Kasatkin u32 key[AES_KEYSIZE_256 / sizeof(u32)]; 104537559a5SDmitry Kasatkin unsigned long flags; 105537559a5SDmitry Kasatkin }; 106537559a5SDmitry Kasatkin 107537559a5SDmitry Kasatkin struct omap_aes_reqctx { 108537559a5SDmitry Kasatkin unsigned long mode; 109537559a5SDmitry Kasatkin }; 110537559a5SDmitry Kasatkin 111537559a5SDmitry Kasatkin #define OMAP_AES_QUEUE_LENGTH 1 112537559a5SDmitry Kasatkin #define OMAP_AES_CACHE_SIZE 0 113537559a5SDmitry Kasatkin 114f9fb69e7SMark A. Greer struct omap_aes_algs_info { 115f9fb69e7SMark A. Greer struct crypto_alg *algs_list; 116f9fb69e7SMark A. Greer unsigned int size; 117f9fb69e7SMark A. Greer unsigned int registered; 118f9fb69e7SMark A. Greer }; 119f9fb69e7SMark A. Greer 1200d35583aSMark A. Greer struct omap_aes_pdata { 121f9fb69e7SMark A. Greer struct omap_aes_algs_info *algs_info; 122f9fb69e7SMark A. Greer unsigned int algs_info_size; 123f9fb69e7SMark A. Greer 1240d35583aSMark A. Greer void (*trigger)(struct omap_aes_dev *dd, int length); 1250d35583aSMark A. Greer 1260d35583aSMark A. Greer u32 key_ofs; 1270d35583aSMark A. Greer u32 iv_ofs; 1280d35583aSMark A. Greer u32 ctrl_ofs; 1290d35583aSMark A. Greer u32 data_ofs; 1300d35583aSMark A. Greer u32 rev_ofs; 1310d35583aSMark A. Greer u32 mask_ofs; 13267216756SJoel Fernandes u32 irq_enable_ofs; 13367216756SJoel Fernandes u32 irq_status_ofs; 1340d35583aSMark A. Greer 1350d35583aSMark A. Greer u32 dma_enable_in; 1360d35583aSMark A. Greer u32 dma_enable_out; 1370d35583aSMark A. Greer u32 dma_start; 1380d35583aSMark A. Greer 1390d35583aSMark A. Greer u32 major_mask; 1400d35583aSMark A. Greer u32 major_shift; 1410d35583aSMark A. Greer u32 minor_mask; 1420d35583aSMark A. Greer u32 minor_shift; 1430d35583aSMark A. Greer }; 1440d35583aSMark A. Greer 145537559a5SDmitry Kasatkin struct omap_aes_dev { 146537559a5SDmitry Kasatkin struct list_head list; 147537559a5SDmitry Kasatkin unsigned long phys_base; 148537559a5SDmitry Kasatkin void __iomem *io_base; 149537559a5SDmitry Kasatkin struct omap_aes_ctx *ctx; 150537559a5SDmitry Kasatkin struct device *dev; 151537559a5SDmitry Kasatkin unsigned long flags; 15221fe9767SDmitry Kasatkin int err; 153537559a5SDmitry Kasatkin 154537559a5SDmitry Kasatkin spinlock_t lock; 155537559a5SDmitry Kasatkin struct crypto_queue queue; 156537559a5SDmitry Kasatkin 15721fe9767SDmitry Kasatkin struct tasklet_struct done_task; 15821fe9767SDmitry Kasatkin struct tasklet_struct queue_task; 159537559a5SDmitry Kasatkin 160537559a5SDmitry Kasatkin struct ablkcipher_request *req; 161537559a5SDmitry Kasatkin size_t total; 162537559a5SDmitry Kasatkin struct scatterlist *in_sg; 163537559a5SDmitry Kasatkin struct scatterlist *out_sg; 1641bf95ccaSJoel Fernandes struct scatter_walk in_walk; 1651bf95ccaSJoel Fernandes struct scatter_walk out_walk; 166537559a5SDmitry Kasatkin int dma_in; 167ebedbf79SMark A. Greer struct dma_chan *dma_lch_in; 168537559a5SDmitry Kasatkin int dma_out; 169ebedbf79SMark A. Greer struct dma_chan *dma_lch_out; 170e77c756eSJoel Fernandes int in_sg_len; 171e77c756eSJoel Fernandes int out_sg_len; 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 350ebedbf79SMark A. Greer dma_cap_zero(mask); 351ebedbf79SMark A. Greer dma_cap_set(DMA_SLAVE, mask); 352ebedbf79SMark A. Greer 353b4b87a93SMark A. Greer dd->dma_lch_in = dma_request_slave_channel_compat(mask, 354b4b87a93SMark A. Greer omap_dma_filter_fn, 355b4b87a93SMark A. Greer &dd->dma_in, 356b4b87a93SMark A. Greer dd->dev, "rx"); 357ebedbf79SMark A. Greer if (!dd->dma_lch_in) { 358ebedbf79SMark A. Greer dev_err(dd->dev, "Unable to request in DMA channel\n"); 359ebedbf79SMark A. Greer goto err_dma_in; 360ebedbf79SMark A. Greer } 361ebedbf79SMark A. Greer 362b4b87a93SMark A. Greer dd->dma_lch_out = dma_request_slave_channel_compat(mask, 363b4b87a93SMark A. Greer omap_dma_filter_fn, 364b4b87a93SMark A. Greer &dd->dma_out, 365b4b87a93SMark A. Greer dd->dev, "tx"); 366ebedbf79SMark A. Greer if (!dd->dma_lch_out) { 367ebedbf79SMark A. Greer dev_err(dd->dev, "Unable to request out DMA channel\n"); 368ebedbf79SMark A. Greer goto err_dma_out; 369ebedbf79SMark A. Greer } 370537559a5SDmitry Kasatkin 371537559a5SDmitry Kasatkin return 0; 372537559a5SDmitry Kasatkin 373537559a5SDmitry Kasatkin err_dma_out: 374ebedbf79SMark A. Greer dma_release_channel(dd->dma_lch_in); 375537559a5SDmitry Kasatkin err_dma_in: 376537559a5SDmitry Kasatkin if (err) 377537559a5SDmitry Kasatkin pr_err("error: %d\n", err); 378537559a5SDmitry Kasatkin return err; 379537559a5SDmitry Kasatkin } 380537559a5SDmitry Kasatkin 381537559a5SDmitry Kasatkin static void omap_aes_dma_cleanup(struct omap_aes_dev *dd) 382537559a5SDmitry Kasatkin { 383ebedbf79SMark A. Greer dma_release_channel(dd->dma_lch_out); 384ebedbf79SMark A. Greer dma_release_channel(dd->dma_lch_in); 385537559a5SDmitry Kasatkin } 386537559a5SDmitry Kasatkin 387537559a5SDmitry Kasatkin static void sg_copy_buf(void *buf, struct scatterlist *sg, 388537559a5SDmitry Kasatkin unsigned int start, unsigned int nbytes, int out) 389537559a5SDmitry Kasatkin { 390537559a5SDmitry Kasatkin struct scatter_walk walk; 391537559a5SDmitry Kasatkin 392537559a5SDmitry Kasatkin if (!nbytes) 393537559a5SDmitry Kasatkin return; 394537559a5SDmitry Kasatkin 395537559a5SDmitry Kasatkin scatterwalk_start(&walk, sg); 396537559a5SDmitry Kasatkin scatterwalk_advance(&walk, start); 397537559a5SDmitry Kasatkin scatterwalk_copychunks(buf, &walk, nbytes, out); 398537559a5SDmitry Kasatkin scatterwalk_done(&walk, out, 0); 399537559a5SDmitry Kasatkin } 400537559a5SDmitry Kasatkin 401ebedbf79SMark A. Greer static int omap_aes_crypt_dma(struct crypto_tfm *tfm, 4024b645c94SJoel Fernandes struct scatterlist *in_sg, struct scatterlist *out_sg, 4034b645c94SJoel Fernandes int in_sg_len, int out_sg_len) 404537559a5SDmitry Kasatkin { 405537559a5SDmitry Kasatkin struct omap_aes_ctx *ctx = crypto_tfm_ctx(tfm); 406537559a5SDmitry Kasatkin struct omap_aes_dev *dd = ctx->dd; 407ebedbf79SMark A. Greer struct dma_async_tx_descriptor *tx_in, *tx_out; 408ebedbf79SMark A. Greer struct dma_slave_config cfg; 4094b645c94SJoel Fernandes int ret; 410537559a5SDmitry Kasatkin 4110a641712SJoel Fernandes dma_sync_sg_for_device(dd->dev, dd->in_sg, in_sg_len, DMA_TO_DEVICE); 4120a641712SJoel Fernandes 413ebedbf79SMark A. Greer memset(&cfg, 0, sizeof(cfg)); 414ebedbf79SMark A. Greer 4150d35583aSMark A. Greer cfg.src_addr = dd->phys_base + AES_REG_DATA_N(dd, 0); 4160d35583aSMark A. Greer cfg.dst_addr = dd->phys_base + AES_REG_DATA_N(dd, 0); 417ebedbf79SMark A. Greer cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 418ebedbf79SMark A. Greer cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 419ebedbf79SMark A. Greer cfg.src_maxburst = DST_MAXBURST; 420ebedbf79SMark A. Greer cfg.dst_maxburst = DST_MAXBURST; 421ebedbf79SMark A. Greer 422ebedbf79SMark A. Greer /* IN */ 423ebedbf79SMark A. Greer ret = dmaengine_slave_config(dd->dma_lch_in, &cfg); 424ebedbf79SMark A. Greer if (ret) { 425ebedbf79SMark A. Greer dev_err(dd->dev, "can't configure IN dmaengine slave: %d\n", 426ebedbf79SMark A. Greer ret); 427ebedbf79SMark A. Greer return ret; 428ebedbf79SMark A. Greer } 429ebedbf79SMark A. Greer 4304b645c94SJoel Fernandes tx_in = dmaengine_prep_slave_sg(dd->dma_lch_in, in_sg, in_sg_len, 431ebedbf79SMark A. Greer DMA_MEM_TO_DEV, 432ebedbf79SMark A. Greer DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 433ebedbf79SMark A. Greer if (!tx_in) { 434ebedbf79SMark A. Greer dev_err(dd->dev, "IN prep_slave_sg() failed\n"); 435ebedbf79SMark A. Greer return -EINVAL; 436ebedbf79SMark A. Greer } 437ebedbf79SMark A. Greer 438ebedbf79SMark A. Greer /* No callback necessary */ 439ebedbf79SMark A. Greer tx_in->callback_param = dd; 440ebedbf79SMark A. Greer 441ebedbf79SMark A. Greer /* OUT */ 442ebedbf79SMark A. Greer ret = dmaengine_slave_config(dd->dma_lch_out, &cfg); 443ebedbf79SMark A. Greer if (ret) { 444ebedbf79SMark A. Greer dev_err(dd->dev, "can't configure OUT dmaengine slave: %d\n", 445ebedbf79SMark A. Greer ret); 446ebedbf79SMark A. Greer return ret; 447ebedbf79SMark A. Greer } 448ebedbf79SMark A. Greer 4494b645c94SJoel Fernandes tx_out = dmaengine_prep_slave_sg(dd->dma_lch_out, out_sg, out_sg_len, 450ebedbf79SMark A. Greer DMA_DEV_TO_MEM, 451ebedbf79SMark A. Greer DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 452ebedbf79SMark A. Greer if (!tx_out) { 453ebedbf79SMark A. Greer dev_err(dd->dev, "OUT prep_slave_sg() failed\n"); 454ebedbf79SMark A. Greer return -EINVAL; 455ebedbf79SMark A. Greer } 456ebedbf79SMark A. Greer 457ebedbf79SMark A. Greer tx_out->callback = omap_aes_dma_out_callback; 458ebedbf79SMark A. Greer tx_out->callback_param = dd; 459ebedbf79SMark A. Greer 460ebedbf79SMark A. Greer dmaengine_submit(tx_in); 461ebedbf79SMark A. Greer dmaengine_submit(tx_out); 462ebedbf79SMark A. Greer 463ebedbf79SMark A. Greer dma_async_issue_pending(dd->dma_lch_in); 464ebedbf79SMark A. Greer dma_async_issue_pending(dd->dma_lch_out); 465537559a5SDmitry Kasatkin 4660d35583aSMark A. Greer /* start DMA */ 4674b645c94SJoel Fernandes dd->pdata->trigger(dd, dd->total); 46883ea7e0fSDmitry Kasatkin 469537559a5SDmitry Kasatkin return 0; 470537559a5SDmitry Kasatkin } 471537559a5SDmitry Kasatkin 472537559a5SDmitry Kasatkin static int omap_aes_crypt_dma_start(struct omap_aes_dev *dd) 473537559a5SDmitry Kasatkin { 474537559a5SDmitry Kasatkin struct crypto_tfm *tfm = crypto_ablkcipher_tfm( 475537559a5SDmitry Kasatkin crypto_ablkcipher_reqtfm(dd->req)); 4764b645c94SJoel Fernandes int err; 477537559a5SDmitry Kasatkin 478537559a5SDmitry Kasatkin pr_debug("total: %d\n", dd->total); 479537559a5SDmitry Kasatkin 4804b645c94SJoel Fernandes err = dma_map_sg(dd->dev, dd->in_sg, dd->in_sg_len, DMA_TO_DEVICE); 481537559a5SDmitry Kasatkin if (!err) { 482537559a5SDmitry Kasatkin dev_err(dd->dev, "dma_map_sg() error\n"); 483537559a5SDmitry Kasatkin return -EINVAL; 484537559a5SDmitry Kasatkin } 485537559a5SDmitry Kasatkin 4864b645c94SJoel Fernandes err = dma_map_sg(dd->dev, dd->out_sg, dd->out_sg_len, DMA_FROM_DEVICE); 487537559a5SDmitry Kasatkin if (!err) { 488537559a5SDmitry Kasatkin dev_err(dd->dev, "dma_map_sg() error\n"); 489537559a5SDmitry Kasatkin return -EINVAL; 490537559a5SDmitry Kasatkin } 491537559a5SDmitry Kasatkin 4924b645c94SJoel Fernandes err = omap_aes_crypt_dma(tfm, dd->in_sg, dd->out_sg, dd->in_sg_len, 4934b645c94SJoel Fernandes dd->out_sg_len); 49421fe9767SDmitry Kasatkin if (err) { 4954b645c94SJoel Fernandes dma_unmap_sg(dd->dev, dd->in_sg, dd->in_sg_len, DMA_TO_DEVICE); 4964b645c94SJoel Fernandes dma_unmap_sg(dd->dev, dd->out_sg, dd->out_sg_len, 4974b645c94SJoel Fernandes DMA_FROM_DEVICE); 49821fe9767SDmitry Kasatkin } 499537559a5SDmitry Kasatkin 500537559a5SDmitry Kasatkin return err; 501537559a5SDmitry Kasatkin } 502537559a5SDmitry Kasatkin 503537559a5SDmitry Kasatkin static void omap_aes_finish_req(struct omap_aes_dev *dd, int err) 504537559a5SDmitry Kasatkin { 50521fe9767SDmitry Kasatkin struct ablkcipher_request *req = dd->req; 506537559a5SDmitry Kasatkin 507537559a5SDmitry Kasatkin pr_debug("err: %d\n", err); 508537559a5SDmitry Kasatkin 509eeb2b202SDmitry Kasatkin dd->flags &= ~FLAGS_BUSY; 510eeb2b202SDmitry Kasatkin 51121fe9767SDmitry Kasatkin req->base.complete(&req->base, err); 512537559a5SDmitry Kasatkin } 513537559a5SDmitry Kasatkin 514537559a5SDmitry Kasatkin static int omap_aes_crypt_dma_stop(struct omap_aes_dev *dd) 515537559a5SDmitry Kasatkin { 516537559a5SDmitry Kasatkin int err = 0; 517537559a5SDmitry Kasatkin 518537559a5SDmitry Kasatkin pr_debug("total: %d\n", dd->total); 519537559a5SDmitry Kasatkin 5200d35583aSMark A. Greer omap_aes_dma_stop(dd); 521537559a5SDmitry Kasatkin 522ebedbf79SMark A. Greer dmaengine_terminate_all(dd->dma_lch_in); 523ebedbf79SMark A. Greer dmaengine_terminate_all(dd->dma_lch_out); 524537559a5SDmitry Kasatkin 5254b645c94SJoel Fernandes dma_unmap_sg(dd->dev, dd->in_sg, dd->in_sg_len, DMA_TO_DEVICE); 5264b645c94SJoel Fernandes dma_unmap_sg(dd->dev, dd->out_sg, dd->out_sg_len, DMA_FROM_DEVICE); 527537559a5SDmitry Kasatkin 528537559a5SDmitry Kasatkin return err; 529537559a5SDmitry Kasatkin } 530537559a5SDmitry Kasatkin 53121fe9767SDmitry Kasatkin static int omap_aes_handle_queue(struct omap_aes_dev *dd, 532eeb2b202SDmitry Kasatkin struct ablkcipher_request *req) 533537559a5SDmitry Kasatkin { 534537559a5SDmitry Kasatkin struct crypto_async_request *async_req, *backlog; 535537559a5SDmitry Kasatkin struct omap_aes_ctx *ctx; 536537559a5SDmitry Kasatkin struct omap_aes_reqctx *rctx; 537537559a5SDmitry Kasatkin unsigned long flags; 53821fe9767SDmitry Kasatkin int err, ret = 0; 539537559a5SDmitry Kasatkin 540537559a5SDmitry Kasatkin spin_lock_irqsave(&dd->lock, flags); 541eeb2b202SDmitry Kasatkin if (req) 54221fe9767SDmitry Kasatkin ret = ablkcipher_enqueue_request(&dd->queue, req); 543eeb2b202SDmitry Kasatkin if (dd->flags & FLAGS_BUSY) { 544eeb2b202SDmitry Kasatkin spin_unlock_irqrestore(&dd->lock, flags); 54521fe9767SDmitry Kasatkin return ret; 546eeb2b202SDmitry Kasatkin } 547537559a5SDmitry Kasatkin backlog = crypto_get_backlog(&dd->queue); 548537559a5SDmitry Kasatkin async_req = crypto_dequeue_request(&dd->queue); 549eeb2b202SDmitry Kasatkin if (async_req) 550eeb2b202SDmitry Kasatkin dd->flags |= FLAGS_BUSY; 551537559a5SDmitry Kasatkin spin_unlock_irqrestore(&dd->lock, flags); 552537559a5SDmitry Kasatkin 553537559a5SDmitry Kasatkin if (!async_req) 55421fe9767SDmitry Kasatkin return ret; 555537559a5SDmitry Kasatkin 556537559a5SDmitry Kasatkin if (backlog) 557537559a5SDmitry Kasatkin backlog->complete(backlog, -EINPROGRESS); 558537559a5SDmitry Kasatkin 559537559a5SDmitry Kasatkin req = ablkcipher_request_cast(async_req); 560537559a5SDmitry Kasatkin 561537559a5SDmitry Kasatkin /* assign new request to device */ 562537559a5SDmitry Kasatkin dd->req = req; 563537559a5SDmitry Kasatkin dd->total = req->nbytes; 564537559a5SDmitry Kasatkin dd->in_sg = req->src; 565537559a5SDmitry Kasatkin dd->out_sg = req->dst; 566537559a5SDmitry Kasatkin 567e77c756eSJoel Fernandes dd->in_sg_len = scatterwalk_bytes_sglen(dd->in_sg, dd->total); 568e77c756eSJoel Fernandes dd->out_sg_len = scatterwalk_bytes_sglen(dd->out_sg, dd->total); 569e77c756eSJoel Fernandes BUG_ON(dd->in_sg_len < 0 || dd->out_sg_len < 0); 570e77c756eSJoel Fernandes 571537559a5SDmitry Kasatkin rctx = ablkcipher_request_ctx(req); 572537559a5SDmitry Kasatkin ctx = crypto_ablkcipher_ctx(crypto_ablkcipher_reqtfm(req)); 573537559a5SDmitry Kasatkin rctx->mode &= FLAGS_MODE_MASK; 574537559a5SDmitry Kasatkin dd->flags = (dd->flags & ~FLAGS_MODE_MASK) | rctx->mode; 575537559a5SDmitry Kasatkin 576537559a5SDmitry Kasatkin dd->ctx = ctx; 57767a730ceSDmitry Kasatkin ctx->dd = dd; 578537559a5SDmitry Kasatkin 57983ea7e0fSDmitry Kasatkin err = omap_aes_write_ctrl(dd); 58083ea7e0fSDmitry Kasatkin if (!err) 58121fe9767SDmitry Kasatkin err = omap_aes_crypt_dma_start(dd); 58221fe9767SDmitry Kasatkin if (err) { 58321fe9767SDmitry Kasatkin /* aes_task will not finish it, so do it here */ 58421fe9767SDmitry Kasatkin omap_aes_finish_req(dd, err); 58521fe9767SDmitry Kasatkin tasklet_schedule(&dd->queue_task); 586537559a5SDmitry Kasatkin } 587537559a5SDmitry Kasatkin 58821fe9767SDmitry Kasatkin return ret; /* return ret, which is enqueue return value */ 58921fe9767SDmitry Kasatkin } 59021fe9767SDmitry Kasatkin 59121fe9767SDmitry Kasatkin static void omap_aes_done_task(unsigned long data) 592537559a5SDmitry Kasatkin { 593537559a5SDmitry Kasatkin struct omap_aes_dev *dd = (struct omap_aes_dev *)data; 594537559a5SDmitry Kasatkin 5954b645c94SJoel Fernandes pr_debug("enter done_task\n"); 596537559a5SDmitry Kasatkin 5970a641712SJoel Fernandes dma_sync_sg_for_cpu(dd->dev, dd->in_sg, dd->in_sg_len, DMA_FROM_DEVICE); 5980a641712SJoel Fernandes 5994b645c94SJoel Fernandes omap_aes_crypt_dma_stop(dd); 6004b645c94SJoel Fernandes omap_aes_finish_req(dd, 0); 60121fe9767SDmitry Kasatkin omap_aes_handle_queue(dd, NULL); 602537559a5SDmitry Kasatkin 603537559a5SDmitry Kasatkin pr_debug("exit\n"); 604537559a5SDmitry Kasatkin } 605537559a5SDmitry Kasatkin 60621fe9767SDmitry Kasatkin static void omap_aes_queue_task(unsigned long data) 60721fe9767SDmitry Kasatkin { 60821fe9767SDmitry Kasatkin struct omap_aes_dev *dd = (struct omap_aes_dev *)data; 60921fe9767SDmitry Kasatkin 61021fe9767SDmitry Kasatkin omap_aes_handle_queue(dd, NULL); 61121fe9767SDmitry Kasatkin } 61221fe9767SDmitry Kasatkin 613537559a5SDmitry Kasatkin static int omap_aes_crypt(struct ablkcipher_request *req, unsigned long mode) 614537559a5SDmitry Kasatkin { 615537559a5SDmitry Kasatkin struct omap_aes_ctx *ctx = crypto_ablkcipher_ctx( 616537559a5SDmitry Kasatkin crypto_ablkcipher_reqtfm(req)); 617537559a5SDmitry Kasatkin struct omap_aes_reqctx *rctx = ablkcipher_request_ctx(req); 618537559a5SDmitry Kasatkin struct omap_aes_dev *dd; 619537559a5SDmitry Kasatkin 620537559a5SDmitry Kasatkin pr_debug("nbytes: %d, enc: %d, cbc: %d\n", req->nbytes, 621537559a5SDmitry Kasatkin !!(mode & FLAGS_ENCRYPT), 622537559a5SDmitry Kasatkin !!(mode & FLAGS_CBC)); 623537559a5SDmitry Kasatkin 62421fe9767SDmitry Kasatkin if (!IS_ALIGNED(req->nbytes, AES_BLOCK_SIZE)) { 62521fe9767SDmitry Kasatkin pr_err("request size is not exact amount of AES blocks\n"); 62621fe9767SDmitry Kasatkin return -EINVAL; 62721fe9767SDmitry Kasatkin } 62821fe9767SDmitry Kasatkin 629537559a5SDmitry Kasatkin dd = omap_aes_find_dev(ctx); 630537559a5SDmitry Kasatkin if (!dd) 631537559a5SDmitry Kasatkin return -ENODEV; 632537559a5SDmitry Kasatkin 633537559a5SDmitry Kasatkin rctx->mode = mode; 634537559a5SDmitry Kasatkin 63521fe9767SDmitry Kasatkin return omap_aes_handle_queue(dd, req); 636537559a5SDmitry Kasatkin } 637537559a5SDmitry Kasatkin 638537559a5SDmitry Kasatkin /* ********************** ALG API ************************************ */ 639537559a5SDmitry Kasatkin 640537559a5SDmitry Kasatkin static int omap_aes_setkey(struct crypto_ablkcipher *tfm, const u8 *key, 641537559a5SDmitry Kasatkin unsigned int keylen) 642537559a5SDmitry Kasatkin { 643537559a5SDmitry Kasatkin struct omap_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm); 644537559a5SDmitry Kasatkin 645537559a5SDmitry Kasatkin if (keylen != AES_KEYSIZE_128 && keylen != AES_KEYSIZE_192 && 646537559a5SDmitry Kasatkin keylen != AES_KEYSIZE_256) 647537559a5SDmitry Kasatkin return -EINVAL; 648537559a5SDmitry Kasatkin 649537559a5SDmitry Kasatkin pr_debug("enter, keylen: %d\n", keylen); 650537559a5SDmitry Kasatkin 651537559a5SDmitry Kasatkin memcpy(ctx->key, key, keylen); 652537559a5SDmitry Kasatkin ctx->keylen = keylen; 653537559a5SDmitry Kasatkin 654537559a5SDmitry Kasatkin return 0; 655537559a5SDmitry Kasatkin } 656537559a5SDmitry Kasatkin 657537559a5SDmitry Kasatkin static int omap_aes_ecb_encrypt(struct ablkcipher_request *req) 658537559a5SDmitry Kasatkin { 659537559a5SDmitry Kasatkin return omap_aes_crypt(req, FLAGS_ENCRYPT); 660537559a5SDmitry Kasatkin } 661537559a5SDmitry Kasatkin 662537559a5SDmitry Kasatkin static int omap_aes_ecb_decrypt(struct ablkcipher_request *req) 663537559a5SDmitry Kasatkin { 664537559a5SDmitry Kasatkin return omap_aes_crypt(req, 0); 665537559a5SDmitry Kasatkin } 666537559a5SDmitry Kasatkin 667537559a5SDmitry Kasatkin static int omap_aes_cbc_encrypt(struct ablkcipher_request *req) 668537559a5SDmitry Kasatkin { 669537559a5SDmitry Kasatkin return omap_aes_crypt(req, FLAGS_ENCRYPT | FLAGS_CBC); 670537559a5SDmitry Kasatkin } 671537559a5SDmitry Kasatkin 672537559a5SDmitry Kasatkin static int omap_aes_cbc_decrypt(struct ablkcipher_request *req) 673537559a5SDmitry Kasatkin { 674537559a5SDmitry Kasatkin return omap_aes_crypt(req, FLAGS_CBC); 675537559a5SDmitry Kasatkin } 676537559a5SDmitry Kasatkin 677f9fb69e7SMark A. Greer static int omap_aes_ctr_encrypt(struct ablkcipher_request *req) 678f9fb69e7SMark A. Greer { 679f9fb69e7SMark A. Greer return omap_aes_crypt(req, FLAGS_ENCRYPT | FLAGS_CTR); 680f9fb69e7SMark A. Greer } 681f9fb69e7SMark A. Greer 682f9fb69e7SMark A. Greer static int omap_aes_ctr_decrypt(struct ablkcipher_request *req) 683f9fb69e7SMark A. Greer { 684f9fb69e7SMark A. Greer return omap_aes_crypt(req, FLAGS_CTR); 685f9fb69e7SMark A. Greer } 686f9fb69e7SMark A. Greer 687537559a5SDmitry Kasatkin static int omap_aes_cra_init(struct crypto_tfm *tfm) 688537559a5SDmitry Kasatkin { 689a3485e68SJoel A Fernandes struct omap_aes_dev *dd = NULL; 690537559a5SDmitry Kasatkin 691a3485e68SJoel A Fernandes /* Find AES device, currently picks the first device */ 692a3485e68SJoel A Fernandes spin_lock_bh(&list_lock); 693a3485e68SJoel A Fernandes list_for_each_entry(dd, &dev_list, list) { 694a3485e68SJoel A Fernandes break; 695a3485e68SJoel A Fernandes } 696a3485e68SJoel A Fernandes spin_unlock_bh(&list_lock); 697a3485e68SJoel A Fernandes 698a3485e68SJoel A Fernandes pm_runtime_get_sync(dd->dev); 699537559a5SDmitry Kasatkin tfm->crt_ablkcipher.reqsize = sizeof(struct omap_aes_reqctx); 700537559a5SDmitry Kasatkin 701537559a5SDmitry Kasatkin return 0; 702537559a5SDmitry Kasatkin } 703537559a5SDmitry Kasatkin 704537559a5SDmitry Kasatkin static void omap_aes_cra_exit(struct crypto_tfm *tfm) 705537559a5SDmitry Kasatkin { 706a3485e68SJoel A Fernandes struct omap_aes_dev *dd = NULL; 707a3485e68SJoel A Fernandes 708a3485e68SJoel A Fernandes /* Find AES device, currently picks the first device */ 709a3485e68SJoel A Fernandes spin_lock_bh(&list_lock); 710a3485e68SJoel A Fernandes list_for_each_entry(dd, &dev_list, list) { 711a3485e68SJoel A Fernandes break; 712a3485e68SJoel A Fernandes } 713a3485e68SJoel A Fernandes spin_unlock_bh(&list_lock); 714a3485e68SJoel A Fernandes 715a3485e68SJoel A Fernandes pm_runtime_put_sync(dd->dev); 716537559a5SDmitry Kasatkin } 717537559a5SDmitry Kasatkin 718537559a5SDmitry Kasatkin /* ********************** ALGS ************************************ */ 719537559a5SDmitry Kasatkin 720f9fb69e7SMark A. Greer static struct crypto_alg algs_ecb_cbc[] = { 721537559a5SDmitry Kasatkin { 722537559a5SDmitry Kasatkin .cra_name = "ecb(aes)", 723537559a5SDmitry Kasatkin .cra_driver_name = "ecb-aes-omap", 724537559a5SDmitry Kasatkin .cra_priority = 100, 725d912bb76SNikos Mavrogiannopoulos .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | 726d912bb76SNikos Mavrogiannopoulos CRYPTO_ALG_KERN_DRIVER_ONLY | 727d912bb76SNikos Mavrogiannopoulos CRYPTO_ALG_ASYNC, 728537559a5SDmitry Kasatkin .cra_blocksize = AES_BLOCK_SIZE, 729537559a5SDmitry Kasatkin .cra_ctxsize = sizeof(struct omap_aes_ctx), 730537559a5SDmitry Kasatkin .cra_alignmask = 0, 731537559a5SDmitry Kasatkin .cra_type = &crypto_ablkcipher_type, 732537559a5SDmitry Kasatkin .cra_module = THIS_MODULE, 733537559a5SDmitry Kasatkin .cra_init = omap_aes_cra_init, 734537559a5SDmitry Kasatkin .cra_exit = omap_aes_cra_exit, 735537559a5SDmitry Kasatkin .cra_u.ablkcipher = { 736537559a5SDmitry Kasatkin .min_keysize = AES_MIN_KEY_SIZE, 737537559a5SDmitry Kasatkin .max_keysize = AES_MAX_KEY_SIZE, 738537559a5SDmitry Kasatkin .setkey = omap_aes_setkey, 739537559a5SDmitry Kasatkin .encrypt = omap_aes_ecb_encrypt, 740537559a5SDmitry Kasatkin .decrypt = omap_aes_ecb_decrypt, 741537559a5SDmitry Kasatkin } 742537559a5SDmitry Kasatkin }, 743537559a5SDmitry Kasatkin { 744537559a5SDmitry Kasatkin .cra_name = "cbc(aes)", 745537559a5SDmitry Kasatkin .cra_driver_name = "cbc-aes-omap", 746537559a5SDmitry Kasatkin .cra_priority = 100, 747d912bb76SNikos Mavrogiannopoulos .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | 748d912bb76SNikos Mavrogiannopoulos CRYPTO_ALG_KERN_DRIVER_ONLY | 749d912bb76SNikos Mavrogiannopoulos CRYPTO_ALG_ASYNC, 750537559a5SDmitry Kasatkin .cra_blocksize = AES_BLOCK_SIZE, 751537559a5SDmitry Kasatkin .cra_ctxsize = sizeof(struct omap_aes_ctx), 752537559a5SDmitry Kasatkin .cra_alignmask = 0, 753537559a5SDmitry Kasatkin .cra_type = &crypto_ablkcipher_type, 754537559a5SDmitry Kasatkin .cra_module = THIS_MODULE, 755537559a5SDmitry Kasatkin .cra_init = omap_aes_cra_init, 756537559a5SDmitry Kasatkin .cra_exit = omap_aes_cra_exit, 757537559a5SDmitry Kasatkin .cra_u.ablkcipher = { 758537559a5SDmitry Kasatkin .min_keysize = AES_MIN_KEY_SIZE, 759537559a5SDmitry Kasatkin .max_keysize = AES_MAX_KEY_SIZE, 760537559a5SDmitry Kasatkin .ivsize = AES_BLOCK_SIZE, 761537559a5SDmitry Kasatkin .setkey = omap_aes_setkey, 762537559a5SDmitry Kasatkin .encrypt = omap_aes_cbc_encrypt, 763537559a5SDmitry Kasatkin .decrypt = omap_aes_cbc_decrypt, 764537559a5SDmitry Kasatkin } 765537559a5SDmitry Kasatkin } 766537559a5SDmitry Kasatkin }; 767537559a5SDmitry Kasatkin 768f9fb69e7SMark A. Greer static struct crypto_alg algs_ctr[] = { 769f9fb69e7SMark A. Greer { 770f9fb69e7SMark A. Greer .cra_name = "ctr(aes)", 771f9fb69e7SMark A. Greer .cra_driver_name = "ctr-aes-omap", 772f9fb69e7SMark A. Greer .cra_priority = 100, 773f9fb69e7SMark A. Greer .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | 774f9fb69e7SMark A. Greer CRYPTO_ALG_KERN_DRIVER_ONLY | 775f9fb69e7SMark A. Greer CRYPTO_ALG_ASYNC, 776f9fb69e7SMark A. Greer .cra_blocksize = AES_BLOCK_SIZE, 777f9fb69e7SMark A. Greer .cra_ctxsize = sizeof(struct omap_aes_ctx), 778f9fb69e7SMark A. Greer .cra_alignmask = 0, 779f9fb69e7SMark A. Greer .cra_type = &crypto_ablkcipher_type, 780f9fb69e7SMark A. Greer .cra_module = THIS_MODULE, 781f9fb69e7SMark A. Greer .cra_init = omap_aes_cra_init, 782f9fb69e7SMark A. Greer .cra_exit = omap_aes_cra_exit, 783f9fb69e7SMark A. Greer .cra_u.ablkcipher = { 784f9fb69e7SMark A. Greer .min_keysize = AES_MIN_KEY_SIZE, 785f9fb69e7SMark A. Greer .max_keysize = AES_MAX_KEY_SIZE, 786f9fb69e7SMark A. Greer .geniv = "eseqiv", 787f9fb69e7SMark A. Greer .ivsize = AES_BLOCK_SIZE, 788f9fb69e7SMark A. Greer .setkey = omap_aes_setkey, 789f9fb69e7SMark A. Greer .encrypt = omap_aes_ctr_encrypt, 790f9fb69e7SMark A. Greer .decrypt = omap_aes_ctr_decrypt, 791f9fb69e7SMark A. Greer } 792f9fb69e7SMark A. Greer } , 793f9fb69e7SMark A. Greer }; 794f9fb69e7SMark A. Greer 795f9fb69e7SMark A. Greer static struct omap_aes_algs_info omap_aes_algs_info_ecb_cbc[] = { 796f9fb69e7SMark A. Greer { 797f9fb69e7SMark A. Greer .algs_list = algs_ecb_cbc, 798f9fb69e7SMark A. Greer .size = ARRAY_SIZE(algs_ecb_cbc), 799f9fb69e7SMark A. Greer }, 800f9fb69e7SMark A. Greer }; 801f9fb69e7SMark A. Greer 8020d35583aSMark A. Greer static const struct omap_aes_pdata omap_aes_pdata_omap2 = { 803f9fb69e7SMark A. Greer .algs_info = omap_aes_algs_info_ecb_cbc, 804f9fb69e7SMark A. Greer .algs_info_size = ARRAY_SIZE(omap_aes_algs_info_ecb_cbc), 8050d35583aSMark A. Greer .trigger = omap_aes_dma_trigger_omap2, 8060d35583aSMark A. Greer .key_ofs = 0x1c, 8070d35583aSMark A. Greer .iv_ofs = 0x20, 8080d35583aSMark A. Greer .ctrl_ofs = 0x30, 8090d35583aSMark A. Greer .data_ofs = 0x34, 8100d35583aSMark A. Greer .rev_ofs = 0x44, 8110d35583aSMark A. Greer .mask_ofs = 0x48, 8120d35583aSMark A. Greer .dma_enable_in = BIT(2), 8130d35583aSMark A. Greer .dma_enable_out = BIT(3), 8140d35583aSMark A. Greer .dma_start = BIT(5), 8150d35583aSMark A. Greer .major_mask = 0xf0, 8160d35583aSMark A. Greer .major_shift = 4, 8170d35583aSMark A. Greer .minor_mask = 0x0f, 8180d35583aSMark A. Greer .minor_shift = 0, 8190d35583aSMark A. Greer }; 8200d35583aSMark A. Greer 821bc69d124SMark A. Greer #ifdef CONFIG_OF 822f9fb69e7SMark A. Greer static struct omap_aes_algs_info omap_aes_algs_info_ecb_cbc_ctr[] = { 823f9fb69e7SMark A. Greer { 824f9fb69e7SMark A. Greer .algs_list = algs_ecb_cbc, 825f9fb69e7SMark A. Greer .size = ARRAY_SIZE(algs_ecb_cbc), 826f9fb69e7SMark A. Greer }, 827f9fb69e7SMark A. Greer { 828f9fb69e7SMark A. Greer .algs_list = algs_ctr, 829f9fb69e7SMark A. Greer .size = ARRAY_SIZE(algs_ctr), 830f9fb69e7SMark A. Greer }, 831f9fb69e7SMark A. Greer }; 832f9fb69e7SMark A. Greer 833f9fb69e7SMark A. Greer static const struct omap_aes_pdata omap_aes_pdata_omap3 = { 834f9fb69e7SMark A. Greer .algs_info = omap_aes_algs_info_ecb_cbc_ctr, 835f9fb69e7SMark A. Greer .algs_info_size = ARRAY_SIZE(omap_aes_algs_info_ecb_cbc_ctr), 836f9fb69e7SMark A. Greer .trigger = omap_aes_dma_trigger_omap2, 837f9fb69e7SMark A. Greer .key_ofs = 0x1c, 838f9fb69e7SMark A. Greer .iv_ofs = 0x20, 839f9fb69e7SMark A. Greer .ctrl_ofs = 0x30, 840f9fb69e7SMark A. Greer .data_ofs = 0x34, 841f9fb69e7SMark A. Greer .rev_ofs = 0x44, 842f9fb69e7SMark A. Greer .mask_ofs = 0x48, 843f9fb69e7SMark A. Greer .dma_enable_in = BIT(2), 844f9fb69e7SMark A. Greer .dma_enable_out = BIT(3), 845f9fb69e7SMark A. Greer .dma_start = BIT(5), 846f9fb69e7SMark A. Greer .major_mask = 0xf0, 847f9fb69e7SMark A. Greer .major_shift = 4, 848f9fb69e7SMark A. Greer .minor_mask = 0x0f, 849f9fb69e7SMark A. Greer .minor_shift = 0, 850f9fb69e7SMark A. Greer }; 851f9fb69e7SMark A. Greer 8520d35583aSMark A. Greer static const struct omap_aes_pdata omap_aes_pdata_omap4 = { 853f9fb69e7SMark A. Greer .algs_info = omap_aes_algs_info_ecb_cbc_ctr, 854f9fb69e7SMark A. Greer .algs_info_size = ARRAY_SIZE(omap_aes_algs_info_ecb_cbc_ctr), 8550d35583aSMark A. Greer .trigger = omap_aes_dma_trigger_omap4, 8560d35583aSMark A. Greer .key_ofs = 0x3c, 8570d35583aSMark A. Greer .iv_ofs = 0x40, 8580d35583aSMark A. Greer .ctrl_ofs = 0x50, 8590d35583aSMark A. Greer .data_ofs = 0x60, 8600d35583aSMark A. Greer .rev_ofs = 0x80, 8610d35583aSMark A. Greer .mask_ofs = 0x84, 86267216756SJoel Fernandes .irq_status_ofs = 0x8c, 86367216756SJoel Fernandes .irq_enable_ofs = 0x90, 8640d35583aSMark A. Greer .dma_enable_in = BIT(5), 8650d35583aSMark A. Greer .dma_enable_out = BIT(6), 8660d35583aSMark A. Greer .major_mask = 0x0700, 8670d35583aSMark A. Greer .major_shift = 8, 8680d35583aSMark A. Greer .minor_mask = 0x003f, 8690d35583aSMark A. Greer .minor_shift = 0, 8700d35583aSMark A. Greer }; 8710d35583aSMark A. Greer 8721bf95ccaSJoel Fernandes static irqreturn_t omap_aes_irq(int irq, void *dev_id) 8731bf95ccaSJoel Fernandes { 8741bf95ccaSJoel Fernandes struct omap_aes_dev *dd = dev_id; 8751bf95ccaSJoel Fernandes u32 status, i; 8761bf95ccaSJoel Fernandes u32 *src, *dst; 8771bf95ccaSJoel Fernandes 8781bf95ccaSJoel Fernandes status = omap_aes_read(dd, AES_REG_IRQ_STATUS(dd)); 8791bf95ccaSJoel Fernandes if (status & AES_REG_IRQ_DATA_IN) { 8801bf95ccaSJoel Fernandes omap_aes_write(dd, AES_REG_IRQ_ENABLE(dd), 0x0); 8811bf95ccaSJoel Fernandes 8821bf95ccaSJoel Fernandes BUG_ON(!dd->in_sg); 8831bf95ccaSJoel Fernandes 8841bf95ccaSJoel Fernandes BUG_ON(_calc_walked(in) > dd->in_sg->length); 8851bf95ccaSJoel Fernandes 8861bf95ccaSJoel Fernandes src = sg_virt(dd->in_sg) + _calc_walked(in); 8871bf95ccaSJoel Fernandes 8881bf95ccaSJoel Fernandes for (i = 0; i < AES_BLOCK_WORDS; i++) { 8891bf95ccaSJoel Fernandes omap_aes_write(dd, AES_REG_DATA_N(dd, i), *src); 8901bf95ccaSJoel Fernandes 8911bf95ccaSJoel Fernandes scatterwalk_advance(&dd->in_walk, 4); 8921bf95ccaSJoel Fernandes if (dd->in_sg->length == _calc_walked(in)) { 8931bf95ccaSJoel Fernandes dd->in_sg = scatterwalk_sg_next(dd->in_sg); 8941bf95ccaSJoel Fernandes if (dd->in_sg) { 8951bf95ccaSJoel Fernandes scatterwalk_start(&dd->in_walk, 8961bf95ccaSJoel Fernandes dd->in_sg); 8971bf95ccaSJoel Fernandes src = sg_virt(dd->in_sg) + 8981bf95ccaSJoel Fernandes _calc_walked(in); 8991bf95ccaSJoel Fernandes } 9001bf95ccaSJoel Fernandes } else { 9011bf95ccaSJoel Fernandes src++; 9021bf95ccaSJoel Fernandes } 9031bf95ccaSJoel Fernandes } 9041bf95ccaSJoel Fernandes 9051bf95ccaSJoel Fernandes /* Clear IRQ status */ 9061bf95ccaSJoel Fernandes status &= ~AES_REG_IRQ_DATA_IN; 9071bf95ccaSJoel Fernandes omap_aes_write(dd, AES_REG_IRQ_STATUS(dd), status); 9081bf95ccaSJoel Fernandes 9091bf95ccaSJoel Fernandes /* Enable DATA_OUT interrupt */ 9101bf95ccaSJoel Fernandes omap_aes_write(dd, AES_REG_IRQ_ENABLE(dd), 0x4); 9111bf95ccaSJoel Fernandes 9121bf95ccaSJoel Fernandes } else if (status & AES_REG_IRQ_DATA_OUT) { 9131bf95ccaSJoel Fernandes omap_aes_write(dd, AES_REG_IRQ_ENABLE(dd), 0x0); 9141bf95ccaSJoel Fernandes 9151bf95ccaSJoel Fernandes BUG_ON(!dd->out_sg); 9161bf95ccaSJoel Fernandes 9171bf95ccaSJoel Fernandes BUG_ON(_calc_walked(out) > dd->out_sg->length); 9181bf95ccaSJoel Fernandes 9191bf95ccaSJoel Fernandes dst = sg_virt(dd->out_sg) + _calc_walked(out); 9201bf95ccaSJoel Fernandes 9211bf95ccaSJoel Fernandes for (i = 0; i < AES_BLOCK_WORDS; i++) { 9221bf95ccaSJoel Fernandes *dst = omap_aes_read(dd, AES_REG_DATA_N(dd, i)); 9231bf95ccaSJoel Fernandes scatterwalk_advance(&dd->out_walk, 4); 9241bf95ccaSJoel Fernandes if (dd->out_sg->length == _calc_walked(out)) { 9251bf95ccaSJoel Fernandes dd->out_sg = scatterwalk_sg_next(dd->out_sg); 9261bf95ccaSJoel Fernandes if (dd->out_sg) { 9271bf95ccaSJoel Fernandes scatterwalk_start(&dd->out_walk, 9281bf95ccaSJoel Fernandes dd->out_sg); 9291bf95ccaSJoel Fernandes dst = sg_virt(dd->out_sg) + 9301bf95ccaSJoel Fernandes _calc_walked(out); 9311bf95ccaSJoel Fernandes } 9321bf95ccaSJoel Fernandes } else { 9331bf95ccaSJoel Fernandes dst++; 9341bf95ccaSJoel Fernandes } 9351bf95ccaSJoel Fernandes } 9361bf95ccaSJoel Fernandes 9371bf95ccaSJoel Fernandes dd->total -= AES_BLOCK_SIZE; 9381bf95ccaSJoel Fernandes 9391bf95ccaSJoel Fernandes BUG_ON(dd->total < 0); 9401bf95ccaSJoel Fernandes 9411bf95ccaSJoel Fernandes /* Clear IRQ status */ 9421bf95ccaSJoel Fernandes status &= ~AES_REG_IRQ_DATA_OUT; 9431bf95ccaSJoel Fernandes omap_aes_write(dd, AES_REG_IRQ_STATUS(dd), status); 9441bf95ccaSJoel Fernandes 9451bf95ccaSJoel Fernandes if (!dd->total) 9461bf95ccaSJoel Fernandes /* All bytes read! */ 9471bf95ccaSJoel Fernandes tasklet_schedule(&dd->done_task); 9481bf95ccaSJoel Fernandes else 9491bf95ccaSJoel Fernandes /* Enable DATA_IN interrupt for next block */ 9501bf95ccaSJoel Fernandes omap_aes_write(dd, AES_REG_IRQ_ENABLE(dd), 0x2); 9511bf95ccaSJoel Fernandes } 9521bf95ccaSJoel Fernandes 9531bf95ccaSJoel Fernandes return IRQ_HANDLED; 9541bf95ccaSJoel Fernandes } 9551bf95ccaSJoel Fernandes 956bc69d124SMark A. Greer static const struct of_device_id omap_aes_of_match[] = { 957bc69d124SMark A. Greer { 958bc69d124SMark A. Greer .compatible = "ti,omap2-aes", 9590d35583aSMark A. Greer .data = &omap_aes_pdata_omap2, 9600d35583aSMark A. Greer }, 9610d35583aSMark A. Greer { 962f9fb69e7SMark A. Greer .compatible = "ti,omap3-aes", 963f9fb69e7SMark A. Greer .data = &omap_aes_pdata_omap3, 964f9fb69e7SMark A. Greer }, 965f9fb69e7SMark A. Greer { 9660d35583aSMark A. Greer .compatible = "ti,omap4-aes", 9670d35583aSMark A. Greer .data = &omap_aes_pdata_omap4, 968bc69d124SMark A. Greer }, 969bc69d124SMark A. Greer {}, 970bc69d124SMark A. Greer }; 971bc69d124SMark A. Greer MODULE_DEVICE_TABLE(of, omap_aes_of_match); 972bc69d124SMark A. Greer 973bc69d124SMark A. Greer static int omap_aes_get_res_of(struct omap_aes_dev *dd, 974bc69d124SMark A. Greer struct device *dev, struct resource *res) 975bc69d124SMark A. Greer { 976bc69d124SMark A. Greer struct device_node *node = dev->of_node; 977bc69d124SMark A. Greer const struct of_device_id *match; 978bc69d124SMark A. Greer int err = 0; 979bc69d124SMark A. Greer 980bc69d124SMark A. Greer match = of_match_device(of_match_ptr(omap_aes_of_match), dev); 981bc69d124SMark A. Greer if (!match) { 982bc69d124SMark A. Greer dev_err(dev, "no compatible OF match\n"); 983bc69d124SMark A. Greer err = -EINVAL; 984bc69d124SMark A. Greer goto err; 985bc69d124SMark A. Greer } 986bc69d124SMark A. Greer 987bc69d124SMark A. Greer err = of_address_to_resource(node, 0, res); 988bc69d124SMark A. Greer if (err < 0) { 989bc69d124SMark A. Greer dev_err(dev, "can't translate OF node address\n"); 990bc69d124SMark A. Greer err = -EINVAL; 991bc69d124SMark A. Greer goto err; 992bc69d124SMark A. Greer } 993bc69d124SMark A. Greer 994bc69d124SMark A. Greer dd->dma_out = -1; /* Dummy value that's unused */ 995bc69d124SMark A. Greer dd->dma_in = -1; /* Dummy value that's unused */ 996bc69d124SMark A. Greer 9970d35583aSMark A. Greer dd->pdata = match->data; 9980d35583aSMark A. Greer 999bc69d124SMark A. Greer err: 1000bc69d124SMark A. Greer return err; 1001bc69d124SMark A. Greer } 1002bc69d124SMark A. Greer #else 1003bc69d124SMark A. Greer static const struct of_device_id omap_aes_of_match[] = { 1004bc69d124SMark A. Greer {}, 1005bc69d124SMark A. Greer }; 1006bc69d124SMark A. Greer 1007bc69d124SMark A. Greer static int omap_aes_get_res_of(struct omap_aes_dev *dd, 1008bc69d124SMark A. Greer struct device *dev, struct resource *res) 1009bc69d124SMark A. Greer { 1010bc69d124SMark A. Greer return -EINVAL; 1011bc69d124SMark A. Greer } 1012bc69d124SMark A. Greer #endif 1013bc69d124SMark A. Greer 1014bc69d124SMark A. Greer static int omap_aes_get_res_pdev(struct omap_aes_dev *dd, 1015bc69d124SMark A. Greer struct platform_device *pdev, struct resource *res) 1016bc69d124SMark A. Greer { 1017bc69d124SMark A. Greer struct device *dev = &pdev->dev; 1018bc69d124SMark A. Greer struct resource *r; 1019bc69d124SMark A. Greer int err = 0; 1020bc69d124SMark A. Greer 1021bc69d124SMark A. Greer /* Get the base address */ 1022bc69d124SMark A. Greer r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1023bc69d124SMark A. Greer if (!r) { 1024bc69d124SMark A. Greer dev_err(dev, "no MEM resource info\n"); 1025bc69d124SMark A. Greer err = -ENODEV; 1026bc69d124SMark A. Greer goto err; 1027bc69d124SMark A. Greer } 1028bc69d124SMark A. Greer memcpy(res, r, sizeof(*res)); 1029bc69d124SMark A. Greer 1030bc69d124SMark A. Greer /* Get the DMA out channel */ 1031bc69d124SMark A. Greer r = platform_get_resource(pdev, IORESOURCE_DMA, 0); 1032bc69d124SMark A. Greer if (!r) { 1033bc69d124SMark A. Greer dev_err(dev, "no DMA out resource info\n"); 1034bc69d124SMark A. Greer err = -ENODEV; 1035bc69d124SMark A. Greer goto err; 1036bc69d124SMark A. Greer } 1037bc69d124SMark A. Greer dd->dma_out = r->start; 1038bc69d124SMark A. Greer 1039bc69d124SMark A. Greer /* Get the DMA in channel */ 1040bc69d124SMark A. Greer r = platform_get_resource(pdev, IORESOURCE_DMA, 1); 1041bc69d124SMark A. Greer if (!r) { 1042bc69d124SMark A. Greer dev_err(dev, "no DMA in resource info\n"); 1043bc69d124SMark A. Greer err = -ENODEV; 1044bc69d124SMark A. Greer goto err; 1045bc69d124SMark A. Greer } 1046bc69d124SMark A. Greer dd->dma_in = r->start; 1047bc69d124SMark A. Greer 10480d35583aSMark A. Greer /* Only OMAP2/3 can be non-DT */ 10490d35583aSMark A. Greer dd->pdata = &omap_aes_pdata_omap2; 10500d35583aSMark A. Greer 1051bc69d124SMark A. Greer err: 1052bc69d124SMark A. Greer return err; 1053bc69d124SMark A. Greer } 1054bc69d124SMark A. Greer 1055537559a5SDmitry Kasatkin static int omap_aes_probe(struct platform_device *pdev) 1056537559a5SDmitry Kasatkin { 1057537559a5SDmitry Kasatkin struct device *dev = &pdev->dev; 1058537559a5SDmitry Kasatkin struct omap_aes_dev *dd; 1059f9fb69e7SMark A. Greer struct crypto_alg *algp; 1060bc69d124SMark A. Greer struct resource res; 1061537559a5SDmitry Kasatkin int err = -ENOMEM, i, j; 1062537559a5SDmitry Kasatkin u32 reg; 1063537559a5SDmitry Kasatkin 1064537559a5SDmitry Kasatkin dd = kzalloc(sizeof(struct omap_aes_dev), GFP_KERNEL); 1065537559a5SDmitry Kasatkin if (dd == NULL) { 1066537559a5SDmitry Kasatkin dev_err(dev, "unable to alloc data struct.\n"); 1067537559a5SDmitry Kasatkin goto err_data; 1068537559a5SDmitry Kasatkin } 1069537559a5SDmitry Kasatkin dd->dev = dev; 1070537559a5SDmitry Kasatkin platform_set_drvdata(pdev, dd); 1071537559a5SDmitry Kasatkin 1072537559a5SDmitry Kasatkin spin_lock_init(&dd->lock); 1073537559a5SDmitry Kasatkin crypto_init_queue(&dd->queue, OMAP_AES_QUEUE_LENGTH); 1074537559a5SDmitry Kasatkin 1075bc69d124SMark A. Greer err = (dev->of_node) ? omap_aes_get_res_of(dd, dev, &res) : 1076bc69d124SMark A. Greer omap_aes_get_res_pdev(dd, pdev, &res); 1077bc69d124SMark A. Greer if (err) 1078537559a5SDmitry Kasatkin goto err_res; 1079537559a5SDmitry Kasatkin 108030862281SLaurent Navet dd->io_base = devm_ioremap_resource(dev, &res); 108130862281SLaurent Navet if (IS_ERR(dd->io_base)) { 108230862281SLaurent Navet err = PTR_ERR(dd->io_base); 10835946c4a5SMark A. Greer goto err_res; 1084537559a5SDmitry Kasatkin } 1085bc69d124SMark A. Greer dd->phys_base = res.start; 1086537559a5SDmitry Kasatkin 10875946c4a5SMark A. Greer pm_runtime_enable(dev); 10885946c4a5SMark A. Greer pm_runtime_get_sync(dev); 10895946c4a5SMark A. Greer 10900d35583aSMark A. Greer omap_aes_dma_stop(dd); 10910d35583aSMark A. Greer 10920d35583aSMark A. Greer reg = omap_aes_read(dd, AES_REG_REV(dd)); 10935946c4a5SMark A. Greer 10945946c4a5SMark A. Greer pm_runtime_put_sync(dev); 1095537559a5SDmitry Kasatkin 10960d35583aSMark A. Greer dev_info(dev, "OMAP AES hw accel rev: %u.%u\n", 10970d35583aSMark A. Greer (reg & dd->pdata->major_mask) >> dd->pdata->major_shift, 10980d35583aSMark A. Greer (reg & dd->pdata->minor_mask) >> dd->pdata->minor_shift); 10990d35583aSMark A. Greer 110021fe9767SDmitry Kasatkin tasklet_init(&dd->done_task, omap_aes_done_task, (unsigned long)dd); 110121fe9767SDmitry Kasatkin tasklet_init(&dd->queue_task, omap_aes_queue_task, (unsigned long)dd); 1102537559a5SDmitry Kasatkin 1103537559a5SDmitry Kasatkin err = omap_aes_dma_init(dd); 1104537559a5SDmitry Kasatkin if (err) 1105537559a5SDmitry Kasatkin goto err_dma; 1106537559a5SDmitry Kasatkin 1107537559a5SDmitry Kasatkin INIT_LIST_HEAD(&dd->list); 1108537559a5SDmitry Kasatkin spin_lock(&list_lock); 1109537559a5SDmitry Kasatkin list_add_tail(&dd->list, &dev_list); 1110537559a5SDmitry Kasatkin spin_unlock(&list_lock); 1111537559a5SDmitry Kasatkin 1112f9fb69e7SMark A. Greer for (i = 0; i < dd->pdata->algs_info_size; i++) { 1113f9fb69e7SMark A. Greer for (j = 0; j < dd->pdata->algs_info[i].size; j++) { 1114f9fb69e7SMark A. Greer algp = &dd->pdata->algs_info[i].algs_list[j]; 1115f9fb69e7SMark A. Greer 1116f9fb69e7SMark A. Greer pr_debug("reg alg: %s\n", algp->cra_name); 1117f9fb69e7SMark A. Greer INIT_LIST_HEAD(&algp->cra_list); 1118f9fb69e7SMark A. Greer 1119f9fb69e7SMark A. Greer err = crypto_register_alg(algp); 1120537559a5SDmitry Kasatkin if (err) 1121537559a5SDmitry Kasatkin goto err_algs; 1122f9fb69e7SMark A. Greer 1123f9fb69e7SMark A. Greer dd->pdata->algs_info[i].registered++; 1124f9fb69e7SMark A. Greer } 1125537559a5SDmitry Kasatkin } 1126537559a5SDmitry Kasatkin 1127537559a5SDmitry Kasatkin return 0; 1128537559a5SDmitry Kasatkin err_algs: 1129f9fb69e7SMark A. Greer for (i = dd->pdata->algs_info_size - 1; i >= 0; i--) 1130f9fb69e7SMark A. Greer for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--) 1131f9fb69e7SMark A. Greer crypto_unregister_alg( 1132f9fb69e7SMark A. Greer &dd->pdata->algs_info[i].algs_list[j]); 1133537559a5SDmitry Kasatkin omap_aes_dma_cleanup(dd); 1134537559a5SDmitry Kasatkin err_dma: 113521fe9767SDmitry Kasatkin tasklet_kill(&dd->done_task); 113621fe9767SDmitry Kasatkin tasklet_kill(&dd->queue_task); 11375946c4a5SMark A. Greer pm_runtime_disable(dev); 1138537559a5SDmitry Kasatkin err_res: 1139537559a5SDmitry Kasatkin kfree(dd); 1140537559a5SDmitry Kasatkin dd = NULL; 1141537559a5SDmitry Kasatkin err_data: 1142537559a5SDmitry Kasatkin dev_err(dev, "initialization failed.\n"); 1143537559a5SDmitry Kasatkin return err; 1144537559a5SDmitry Kasatkin } 1145537559a5SDmitry Kasatkin 1146537559a5SDmitry Kasatkin static int omap_aes_remove(struct platform_device *pdev) 1147537559a5SDmitry Kasatkin { 1148537559a5SDmitry Kasatkin struct omap_aes_dev *dd = platform_get_drvdata(pdev); 1149f9fb69e7SMark A. Greer int i, j; 1150537559a5SDmitry Kasatkin 1151537559a5SDmitry Kasatkin if (!dd) 1152537559a5SDmitry Kasatkin return -ENODEV; 1153537559a5SDmitry Kasatkin 1154537559a5SDmitry Kasatkin spin_lock(&list_lock); 1155537559a5SDmitry Kasatkin list_del(&dd->list); 1156537559a5SDmitry Kasatkin spin_unlock(&list_lock); 1157537559a5SDmitry Kasatkin 1158f9fb69e7SMark A. Greer for (i = dd->pdata->algs_info_size - 1; i >= 0; i--) 1159f9fb69e7SMark A. Greer for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--) 1160f9fb69e7SMark A. Greer crypto_unregister_alg( 1161f9fb69e7SMark A. Greer &dd->pdata->algs_info[i].algs_list[j]); 1162537559a5SDmitry Kasatkin 116321fe9767SDmitry Kasatkin tasklet_kill(&dd->done_task); 116421fe9767SDmitry Kasatkin tasklet_kill(&dd->queue_task); 1165537559a5SDmitry Kasatkin omap_aes_dma_cleanup(dd); 11665946c4a5SMark A. Greer pm_runtime_disable(dd->dev); 1167537559a5SDmitry Kasatkin kfree(dd); 1168537559a5SDmitry Kasatkin dd = NULL; 1169537559a5SDmitry Kasatkin 1170537559a5SDmitry Kasatkin return 0; 1171537559a5SDmitry Kasatkin } 1172537559a5SDmitry Kasatkin 11730635fb3aSMark A. Greer #ifdef CONFIG_PM_SLEEP 11740635fb3aSMark A. Greer static int omap_aes_suspend(struct device *dev) 11750635fb3aSMark A. Greer { 11760635fb3aSMark A. Greer pm_runtime_put_sync(dev); 11770635fb3aSMark A. Greer return 0; 11780635fb3aSMark A. Greer } 11790635fb3aSMark A. Greer 11800635fb3aSMark A. Greer static int omap_aes_resume(struct device *dev) 11810635fb3aSMark A. Greer { 11820635fb3aSMark A. Greer pm_runtime_get_sync(dev); 11830635fb3aSMark A. Greer return 0; 11840635fb3aSMark A. Greer } 11850635fb3aSMark A. Greer #endif 11860635fb3aSMark A. Greer 11870635fb3aSMark A. Greer static const struct dev_pm_ops omap_aes_pm_ops = { 11880635fb3aSMark A. Greer SET_SYSTEM_SLEEP_PM_OPS(omap_aes_suspend, omap_aes_resume) 11890635fb3aSMark A. Greer }; 11900635fb3aSMark A. Greer 1191537559a5SDmitry Kasatkin static struct platform_driver omap_aes_driver = { 1192537559a5SDmitry Kasatkin .probe = omap_aes_probe, 1193537559a5SDmitry Kasatkin .remove = omap_aes_remove, 1194537559a5SDmitry Kasatkin .driver = { 1195537559a5SDmitry Kasatkin .name = "omap-aes", 1196537559a5SDmitry Kasatkin .owner = THIS_MODULE, 11970635fb3aSMark A. Greer .pm = &omap_aes_pm_ops, 1198bc69d124SMark A. Greer .of_match_table = omap_aes_of_match, 1199537559a5SDmitry Kasatkin }, 1200537559a5SDmitry Kasatkin }; 1201537559a5SDmitry Kasatkin 120294e51df9SSachin Kamat module_platform_driver(omap_aes_driver); 1203537559a5SDmitry Kasatkin 1204537559a5SDmitry Kasatkin MODULE_DESCRIPTION("OMAP AES hw acceleration support."); 1205537559a5SDmitry Kasatkin MODULE_LICENSE("GPL v2"); 1206537559a5SDmitry Kasatkin MODULE_AUTHOR("Dmitry Kasatkin"); 1207537559a5SDmitry Kasatkin 1208