aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/mxs/patches/105-imx23-dcp.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/mxs/patches/105-imx23-dcp.patch')
-rw-r--r--target/linux/mxs/patches/105-imx23-dcp.patch957
1 files changed, 0 insertions, 957 deletions
diff --git a/target/linux/mxs/patches/105-imx23-dcp.patch b/target/linux/mxs/patches/105-imx23-dcp.patch
deleted file mode 100644
index ae74209775..0000000000
--- a/target/linux/mxs/patches/105-imx23-dcp.patch
+++ /dev/null
@@ -1,957 +0,0 @@
---- a/drivers/crypto/Kconfig
-+++ b/drivers/crypto/Kconfig
-@@ -287,6 +287,16 @@ config CRYPTO_DEV_SAHARA
- This option enables support for the SAHARA HW crypto accelerator
- found in some Freescale i.MX chips.
-
-+config CRYPTO_DEV_DCP
-+ tristate "Support for the DCP engine"
-+ depends on ARCH_MXS && OF
-+ select CRYPTO_BLKCIPHER
-+ select CRYPTO_AES
-+ select CRYPTO_CBC
-+ help
-+ This options enables support for the hardware crypto-acceleration
-+ capabilities of the DCP co-processor
-+
- config CRYPTO_DEV_S5P
- tristate "Support for Samsung S5PV210 crypto accelerator"
- depends on ARCH_S5PV210
---- a/drivers/crypto/Makefile
-+++ b/drivers/crypto/Makefile
-@@ -13,6 +13,7 @@ obj-$(CONFIG_CRYPTO_DEV_OMAP_SHAM) += om
- obj-$(CONFIG_CRYPTO_DEV_OMAP_AES) += omap-aes.o
- obj-$(CONFIG_CRYPTO_DEV_PICOXCELL) += picoxcell_crypto.o
- obj-$(CONFIG_CRYPTO_DEV_SAHARA) += sahara.o
-+obj-$(CONFIG_CRYPTO_DEV_DCP) += dcp.o
- obj-$(CONFIG_CRYPTO_DEV_S5P) += s5p-sss.o
- obj-$(CONFIG_CRYPTO_DEV_TEGRA_AES) += tegra-aes.o
- obj-$(CONFIG_CRYPTO_DEV_UX500) += ux500/
---- /dev/null
-+++ b/drivers/crypto/dcp.c
-@@ -0,0 +1,925 @@
-+/*
-+ * Cryptographic API.
-+ *
-+ * Support for DCP cryptographic accelerator.
-+ *
-+ * Copyright (c) 2013
-+ * Author: Tobias Rauter <tobias.rau...@gmail.com>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as published
-+ * by the Free Software Foundation.
-+ *
-+ * Based on tegra-aes.c, dcp.c (from freescale SDK) and sahara.c
-+ */
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/errno.h>
-+#include <linux/kernel.h>
-+#include <linux/platform_device.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/io.h>
-+#include <linux/mutex.h>
-+#include <linux/interrupt.h>
-+#include <linux/completion.h>
-+#include <linux/workqueue.h>
-+#include <linux/delay.h>
-+#include <linux/crypto.h>
-+#include <linux/miscdevice.h>
-+
-+#include <crypto/scatterwalk.h>
-+#include <crypto/aes.h>
-+
-+
-+/* IOCTL for DCP OTP Key AES - taken from Freescale's SDK*/
-+#define DBS_IOCTL_BASE 'd'
-+#define DBS_ENC _IOW(DBS_IOCTL_BASE, 0x00, uint8_t[16])
-+#define DBS_DEC _IOW(DBS_IOCTL_BASE, 0x01, uint8_t[16])
-+
-+/* DCP channel used for AES */
-+#define USED_CHANNEL 1
-+/* Ring Buffers' maximum size */
-+#define DCP_MAX_PKG 20
-+
-+/* Control Register */
-+#define DCP_REG_CTRL 0x000
-+#define DCP_CTRL_SFRST (1<<31)
-+#define DCP_CTRL_CLKGATE (1<<30)
-+#define DCP_CTRL_CRYPTO_PRESENT (1<<29)
-+#define DCP_CTRL_SHA_PRESENT (1<<28)
-+#define DCP_CTRL_GATHER_RES_WRITE (1<<23)
-+#define DCP_CTRL_ENABLE_CONTEXT_CACHE (1<<22)
-+#define DCP_CTRL_ENABLE_CONTEXT_SWITCH (1<<21)
-+#define DCP_CTRL_CH_IRQ_E_0 0x01
-+#define DCP_CTRL_CH_IRQ_E_1 0x02
-+#define DCP_CTRL_CH_IRQ_E_2 0x04
-+#define DCP_CTRL_CH_IRQ_E_3 0x08
-+
-+/* Status register */
-+#define DCP_REG_STAT 0x010
-+#define DCP_STAT_OTP_KEY_READY (1<<28)
-+#define DCP_STAT_CUR_CHANNEL(stat) ((stat>>24)&0x0F)
-+#define DCP_STAT_READY_CHANNEL(stat) ((stat>>16)&0x0F)
-+#define DCP_STAT_IRQ(stat) (stat&0x0F)
-+#define DCP_STAT_CHAN_0 (0x01)
-+#define DCP_STAT_CHAN_1 (0x02)
-+#define DCP_STAT_CHAN_2 (0x04)
-+#define DCP_STAT_CHAN_3 (0x08)
-+
-+/* Channel Control Register */
-+#define DCP_REG_CHAN_CTRL 0x020
-+#define DCP_CHAN_CTRL_CH0_IRQ_MERGED (1<<16)
-+#define DCP_CHAN_CTRL_HIGH_PRIO_0 (0x0100)
-+#define DCP_CHAN_CTRL_HIGH_PRIO_1 (0x0200)
-+#define DCP_CHAN_CTRL_HIGH_PRIO_2 (0x0400)
-+#define DCP_CHAN_CTRL_HIGH_PRIO_3 (0x0800)
-+#define DCP_CHAN_CTRL_ENABLE_0 (0x01)
-+#define DCP_CHAN_CTRL_ENABLE_1 (0x02)
-+#define DCP_CHAN_CTRL_ENABLE_2 (0x04)
-+#define DCP_CHAN_CTRL_ENABLE_3 (0x08)
-+
-+/*
-+ * Channel Registers:
-+ * The DCP has 4 channels. Each of this channels
-+ * has 4 registers (command pointer, semaphore, status and options).
-+ * The address of register REG of channel CHAN is obtained by
-+ * dcp_chan_reg(REG, CHAN)
-+ */
-+#define DCP_REG_CHAN_PTR 0x00000100
-+#define DCP_REG_CHAN_SEMA 0x00000110
-+#define DCP_REG_CHAN_STAT 0x00000120
-+#define DCP_REG_CHAN_OPT 0x00000130
-+
-+#define DCP_CHAN_STAT_NEXT_CHAIN_IS_0 0x010000
-+#define DCP_CHAN_STAT_NO_CHAIN 0x020000
-+#define DCP_CHAN_STAT_CONTEXT_ERROR 0x030000
-+#define DCP_CHAN_STAT_PAYLOAD_ERROR 0x040000
-+#define DCP_CHAN_STAT_INVALID_MODE 0x050000
-+#define DCP_CHAN_STAT_PAGEFAULT 0x40
-+#define DCP_CHAN_STAT_DST 0x20
-+#define DCP_CHAN_STAT_SRC 0x10
-+#define DCP_CHAN_STAT_PACKET 0x08
-+#define DCP_CHAN_STAT_SETUP 0x04
-+#define DCP_CHAN_STAT_MISMATCH 0x02
-+
-+/* hw packet control*/
-+
-+#define DCP_PKT_PAYLOAD_KEY (1<<11)
-+#define DCP_PKT_OTP_KEY (1<<10)
-+#define DCP_PKT_CIPHER_INIT (1<<9)
-+#define DCP_PKG_CIPHER_ENCRYPT (1<<8)
-+#define DCP_PKT_CIPHER_ENABLE (1<<5)
-+#define DCP_PKT_DECR_SEM (1<<1)
-+#define DCP_PKT_CHAIN (1<<2)
-+#define DCP_PKT_IRQ 1
-+
-+#define DCP_PKT_MODE_CBC (1<<4)
-+#define DCP_PKT_KEYSELECT_OTP (0xFF<<8)
-+
-+/* cipher flags */
-+#define DCP_ENC 0x0001
-+#define DCP_DEC 0x0002
-+#define DCP_ECB 0x0004
-+#define DCP_CBC 0x0008
-+#define DCP_CBC_INIT 0x0010
-+#define DCP_NEW_KEY 0x0040
-+#define DCP_OTP_KEY 0x0080
-+#define DCP_AES 0x1000
-+
-+/* DCP Flags */
-+#define DCP_FLAG_BUSY 0x01
-+#define DCP_FLAG_PRODUCING 0x02
-+
-+/* clock defines */
-+#define CLOCK_ON 1
-+#define CLOCK_OFF 0
-+
-+struct dcp_dev_req_ctx {
-+ int mode;
-+};
-+
-+struct dcp_op {
-+ unsigned int flags;
-+ u8 key[AES_KEYSIZE_128];
-+ int keylen;
-+
-+ struct ablkcipher_request *req;
-+ struct crypto_ablkcipher *fallback;
-+
-+ uint32_t stat;
-+ uint32_t pkt1;
-+ uint32_t pkt2;
-+ struct ablkcipher_walk walk;
-+};
-+
-+struct dcp_dev {
-+ struct device *dev;
-+ void __iomem *dcp_regs_base;
-+
-+ int dcp_vmi_irq;
-+ int dcp_irq;
-+
-+ spinlock_t queue_lock;
-+ struct crypto_queue queue;
-+
-+ uint32_t pkt_produced;
-+ uint32_t pkt_consumed;
-+
-+ struct dcp_hw_packet *hw_pkg[DCP_MAX_PKG];
-+ dma_addr_t hw_phys_pkg;
-+
-+ /* [KEY][IV] Both with 16 Bytes */
-+ u8 *payload_base;
-+ dma_addr_t payload_base_dma;
-+
-+
-+ struct tasklet_struct done_task;
-+ struct tasklet_struct queue_task;
-+ struct timer_list watchdog;
-+
-+ unsigned long flags;
-+
-+ struct dcp_op *ctx;
-+
-+ struct miscdevice dcp_bootstream_misc;
-+};
-+
-+struct dcp_hw_packet {
-+ uint32_t next;
-+ uint32_t pkt1;
-+ uint32_t pkt2;
-+ uint32_t src;
-+ uint32_t dst;
-+ uint32_t size;
-+ uint32_t payload;
-+ uint32_t stat;
-+};
-+
-+struct dcp_dev *global_dev;
-+
-+static inline u32 dcp_chan_reg(u32 reg, int chan)
-+{
-+ return reg + (chan) * 0x40;
-+}
-+
-+static inline void dcp_write(struct dcp_dev *dev, u32 data, u32 reg)
-+{
-+ writel(data, dev->dcp_regs_base + reg);
-+}
-+
-+static inline void dcp_set(struct dcp_dev *dev, u32 data, u32 reg)
-+{
-+ writel(data, dev->dcp_regs_base + (reg | 0x04));
-+}
-+
-+static inline void dcp_clear(struct dcp_dev *dev, u32 data, u32 reg)
-+{
-+ writel(data, dev->dcp_regs_base + (reg | 0x08));
-+}
-+
-+static inline void dcp_toggle(struct dcp_dev *dev, u32 data, u32 reg)
-+{
-+ writel(data, dev->dcp_regs_base + (reg | 0x0C));
-+}
-+
-+static inline unsigned int dcp_read(struct dcp_dev *dev, u32 reg)
-+{
-+ return readl(dev->dcp_regs_base + reg);
-+}
-+
-+void dcp_dma_unmap(struct dcp_dev *dev, struct dcp_hw_packet *pkt)
-+{
-+ dma_unmap_page(dev->dev, pkt->src, pkt->size, DMA_TO_DEVICE);
-+ dma_unmap_page(dev->dev, pkt->dst, pkt->size, DMA_FROM_DEVICE);
-+ dev_dbg(dev->dev, "unmap packet %x", (unsigned int) pkt);
-+}
-+
-+int dcp_dma_map(struct dcp_dev *dev,
-+ struct ablkcipher_walk *walk, struct dcp_hw_packet *pkt)
-+{
-+ dev_dbg(dev->dev, "map packet %x", (unsigned int) pkt);
-+ /* align to length = 16 */
-+ pkt->size = walk->nbytes - (walk->nbytes % 16);
-+
-+ pkt->src = dma_map_page(dev->dev, walk->src.page, walk->src.offset,
-+ pkt->size, DMA_TO_DEVICE);
-+
-+ if (pkt->src == 0) {
-+ dev_err(dev->dev, "Unable to map src");
-+ return -ENOMEM;
-+ }
-+
-+ pkt->dst = dma_map_page(dev->dev, walk->dst.page, walk->dst.offset,
-+ pkt->size, DMA_FROM_DEVICE);
-+
-+ if (pkt->dst == 0) {
-+ dev_err(dev->dev, "Unable to map dst");
-+ dma_unmap_page(dev->dev, pkt->src, pkt->size, DMA_TO_DEVICE);
-+ return -ENOMEM;
-+ }
-+
-+ return 0;
-+}
-+
-+static void dcp_op_one(struct dcp_dev *dev, struct dcp_hw_packet *pkt,
-+ uint8_t last)
-+{
-+ struct dcp_op *ctx = dev->ctx;
-+ pkt->pkt1 = ctx->pkt1;
-+ pkt->pkt2 = ctx->pkt2;
-+
-+ pkt->payload = (u32) dev->payload_base_dma;
-+ pkt->stat = 0;
-+
-+ if (ctx->flags & DCP_CBC_INIT) {
-+ pkt->pkt1 |= DCP_PKT_CIPHER_INIT;
-+ ctx->flags &= ~DCP_CBC_INIT;
-+ }
-+
-+ mod_timer(&dev->watchdog, jiffies + msecs_to_jiffies(500));
-+ pkt->pkt1 |= DCP_PKT_IRQ;
-+ if (!last)
-+ pkt->pkt1 |= DCP_PKT_CHAIN;
-+
-+ dev->pkt_produced++;
-+
-+ dcp_write(dev, 1,
-+ dcp_chan_reg(DCP_REG_CHAN_SEMA, USED_CHANNEL));
-+}
-+
-+static void dcp_op_proceed(struct dcp_dev *dev)
-+{
-+ struct dcp_op *ctx = dev->ctx;
-+ struct dcp_hw_packet *pkt;
-+
-+ while (ctx->walk.nbytes) {
-+ int err = 0;
-+
-+ pkt = dev->hw_pkg[dev->pkt_produced % DCP_MAX_PKG];
-+ err = dcp_dma_map(dev, &ctx->walk, pkt);
-+ if (err) {
-+ dev->ctx->stat |= err;
-+ /* start timer to wait for already set up calls */
-+ mod_timer(&dev->watchdog,
-+ jiffies + msecs_to_jiffies(500));
-+ break;
-+ }
-+
-+
-+ err = ctx->walk.nbytes - pkt->size;
-+ ablkcipher_walk_done(dev->ctx->req, &dev->ctx->walk, err);
-+
-+ dcp_op_one(dev, pkt, ctx->walk.nbytes == 0);
-+ /* we have to wait if no space is left in buffer */
-+ if (dev->pkt_produced - dev->pkt_consumed == DCP_MAX_PKG)
-+ break;
-+ }
-+ clear_bit(DCP_FLAG_PRODUCING, &dev->flags);
-+}
-+
-+static void dcp_op_start(struct dcp_dev *dev, uint8_t use_walk)
-+{
-+ struct dcp_op *ctx = dev->ctx;
-+
-+ if (ctx->flags & DCP_NEW_KEY) {
-+ memcpy(dev->payload_base, ctx->key, ctx->keylen);
-+ ctx->flags &= ~DCP_NEW_KEY;
-+ }
-+
-+ ctx->pkt1 = 0;
-+ ctx->pkt1 |= DCP_PKT_CIPHER_ENABLE;
-+ ctx->pkt1 |= DCP_PKT_DECR_SEM;
-+
-+ if (ctx->flags & DCP_OTP_KEY)
-+ ctx->pkt1 |= DCP_PKT_OTP_KEY;
-+ else
-+ ctx->pkt1 |= DCP_PKT_PAYLOAD_KEY;
-+
-+ if (ctx->flags & DCP_ENC)
-+ ctx->pkt1 |= DCP_PKG_CIPHER_ENCRYPT;
-+
-+ ctx->pkt2 = 0;
-+ if (ctx->flags & DCP_CBC)
-+ ctx->pkt2 |= DCP_PKT_MODE_CBC;
-+
-+ dev->pkt_produced = 0;
-+ dev->pkt_consumed = 0;
-+
-+ ctx->stat = 0;
-+ dcp_clear(dev, -1, dcp_chan_reg(DCP_REG_CHAN_STAT, USED_CHANNEL));
-+ dcp_write(dev, (u32) dev->hw_phys_pkg,
-+ dcp_chan_reg(DCP_REG_CHAN_PTR, USED_CHANNEL));
-+
-+ set_bit(DCP_FLAG_PRODUCING, &dev->flags);
-+
-+ if (use_walk) {
-+ ablkcipher_walk_init(&ctx->walk, ctx->req->dst,
-+ ctx->req->src, ctx->req->nbytes);
-+ ablkcipher_walk_phys(ctx->req, &ctx->walk);
-+ dcp_op_proceed(dev);
-+ } else {
-+ dcp_op_one(dev, dev->hw_pkg[0], 1);
-+ clear_bit(DCP_FLAG_PRODUCING, &dev->flags);
-+ }
-+}
-+
-+static void dcp_done_task(unsigned long data)
-+{
-+ struct dcp_dev *dev = (struct dcp_dev *)data;
-+ struct dcp_hw_packet *last_packet;
-+ int fin;
-+ fin = 0;
-+
-+ for (last_packet = dev->hw_pkg[(dev->pkt_consumed) % DCP_MAX_PKG];
-+ last_packet->stat == 1;
-+ last_packet =
-+ dev->hw_pkg[++(dev->pkt_consumed) % DCP_MAX_PKG]) {
-+
-+ dcp_dma_unmap(dev, last_packet);
-+ last_packet->stat = 0;
-+ fin++;
-+ }
-+ /* the last call of this function already consumed this IRQ's packet */
-+ if (fin == 0)
-+ return;
-+
-+ dev_dbg(dev->dev,
-+ "Packet(s) done with status %x; finished: %d, produced:%d, complete consumed: %d",
-+ dev->ctx->stat, fin, dev->pkt_produced, dev->pkt_consumed);
-+
-+ last_packet = dev->hw_pkg[(dev->pkt_consumed - 1) % DCP_MAX_PKG];
-+ if (!dev->ctx->stat && last_packet->pkt1 & DCP_PKT_CHAIN) {
-+ if (!test_and_set_bit(DCP_FLAG_PRODUCING, &dev->flags))
-+ dcp_op_proceed(dev);
-+ return;
-+ }
-+
-+ while (unlikely(dev->pkt_consumed < dev->pkt_produced)) {
-+ dcp_dma_unmap(dev,
-+ dev->hw_pkg[dev->pkt_consumed++ % DCP_MAX_PKG]);
-+ }
-+
-+ if (dev->ctx->flags & DCP_OTP_KEY) {
-+ /* we used the miscdevice, no walk to finish */
-+ clear_bit(DCP_FLAG_BUSY, &dev->flags);
-+ return;
-+ }
-+
-+ ablkcipher_walk_complete(&dev->ctx->walk);
-+ dev->ctx->req->base.complete(&dev->ctx->req->base,
-+ dev->ctx->stat);
-+ dev->ctx->req = 0;
-+ /* in case there are other requests in the queue */
-+ tasklet_schedule(&dev->queue_task);
-+}
-+
-+void dcp_watchdog(unsigned long data)
-+{
-+ struct dcp_dev *dev = (struct dcp_dev *)data;
-+ dev->ctx->stat |= dcp_read(dev,
-+ dcp_chan_reg(DCP_REG_CHAN_STAT, USED_CHANNEL));
-+
-+ dev_err(dev->dev, "Timeout, Channel status: %x", dev->ctx->stat);
-+
-+ if (!dev->ctx->stat)
-+ dev->ctx->stat = -ETIMEDOUT;
-+
-+ dcp_done_task(data);
-+}
-+
-+
-+static irqreturn_t dcp_common_irq(int irq, void *context)
-+{
-+ u32 msk;
-+ struct dcp_dev *dev = (struct dcp_dev *) context;
-+
-+ del_timer(&dev->watchdog);
-+
-+ msk = DCP_STAT_IRQ(dcp_read(dev, DCP_REG_STAT));
-+ dcp_clear(dev, msk, DCP_REG_STAT);
-+ if (msk == 0)
-+ return IRQ_NONE;
-+
-+ dev->ctx->stat |= dcp_read(dev,
-+ dcp_chan_reg(DCP_REG_CHAN_STAT, USED_CHANNEL));
-+
-+ if (msk & DCP_STAT_CHAN_1)
-+ tasklet_schedule(&dev->done_task);
-+
-+ return IRQ_HANDLED;
-+}
-+
-+static irqreturn_t dcp_vmi_irq(int irq, void *context)
-+{
-+ return dcp_common_irq(irq, context);
-+}
-+
-+static irqreturn_t dcp_irq(int irq, void *context)
-+{
-+ return dcp_common_irq(irq, context);
-+}
-+
-+static void dcp_crypt(struct dcp_dev *dev, struct dcp_op *ctx)
-+{
-+ dev->ctx = ctx;
-+
-+ if ((ctx->flags & DCP_CBC) && ctx->req->info) {
-+ ctx->flags |= DCP_CBC_INIT;
-+ memcpy(dev->payload_base + AES_KEYSIZE_128,
-+ ctx->req->info, AES_KEYSIZE_128);
-+ }
-+
-+ dcp_op_start(dev, 1);
-+}
-+
-+static void dcp_queue_task(unsigned long data)
-+{
-+ struct dcp_dev *dev = (struct dcp_dev *) data;
-+ struct crypto_async_request *async_req, *backlog;
-+ struct crypto_ablkcipher *tfm;
-+ struct dcp_op *ctx;
-+ struct dcp_dev_req_ctx *rctx;
-+ struct ablkcipher_request *req;
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&dev->queue_lock, flags);
-+
-+ backlog = crypto_get_backlog(&dev->queue);
-+ async_req = crypto_dequeue_request(&dev->queue);
-+
-+ spin_unlock_irqrestore(&dev->queue_lock, flags);
-+
-+ if (!async_req)
-+ goto ret_nothing_done;
-+
-+ if (backlog)
-+ backlog->complete(backlog, -EINPROGRESS);
-+
-+ req = ablkcipher_request_cast(async_req);
-+ tfm = crypto_ablkcipher_reqtfm(req);
-+ rctx = ablkcipher_request_ctx(req);
-+ ctx = crypto_ablkcipher_ctx(tfm);
-+
-+ if (!req->src || !req->dst)
-+ goto ret_nothing_done;
-+
-+ ctx->flags |= rctx->mode;
-+ ctx->req = req;
-+
-+ dcp_crypt(dev, ctx);
-+
-+ return;
-+
-+ret_nothing_done:
-+ clear_bit(DCP_FLAG_BUSY, &dev->flags);
-+}
-+
-+
-+static int dcp_cra_init(struct crypto_tfm *tfm)
-+{
-+ const char *name = tfm->__crt_alg->cra_name;
-+ struct dcp_op *ctx = crypto_tfm_ctx(tfm);
-+
-+ tfm->crt_ablkcipher.reqsize = sizeof(struct dcp_dev_req_ctx);
-+
-+ ctx->fallback = crypto_alloc_ablkcipher(name, 0,
-+ CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK);
-+
-+ if (IS_ERR(ctx->fallback)) {
-+ dev_err(global_dev->dev, "Error allocating fallback algo %s\n",
-+ name);
-+ return PTR_ERR(ctx->fallback);
-+ }
-+
-+ return 0;
-+}
-+
-+static void dcp_cra_exit(struct crypto_tfm *tfm)
-+{
-+ struct dcp_op *ctx = crypto_tfm_ctx(tfm);
-+
-+ if (ctx->fallback)
-+ crypto_free_ablkcipher(ctx->fallback);
-+
-+ ctx->fallback = NULL;
-+}
-+
-+/* async interface */
-+static int dcp_aes_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
-+ unsigned int len)
-+{
-+ struct dcp_op *ctx = crypto_ablkcipher_ctx(tfm);
-+ unsigned int ret = 0;
-+ ctx->keylen = len;
-+ ctx->flags = 0;
-+ if (len == AES_KEYSIZE_128) {
-+ if (memcmp(ctx->key, key, AES_KEYSIZE_128)) {
-+ memcpy(ctx->key, key, len);
-+ ctx->flags |= DCP_NEW_KEY;
-+ }
-+ return 0;
-+ }
-+
-+ ctx->fallback->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK;
-+ ctx->fallback->base.crt_flags |=
-+ (tfm->base.crt_flags & CRYPTO_TFM_REQ_MASK);
-+
-+ ret = crypto_ablkcipher_setkey(ctx->fallback, key, len);
-+ if (ret) {
-+ struct crypto_tfm *tfm_aux = crypto_ablkcipher_tfm(tfm);
-+
-+ tfm_aux->crt_flags &= ~CRYPTO_TFM_RES_MASK;
-+ tfm_aux->crt_flags |=
-+ (ctx->fallback->base.crt_flags & CRYPTO_TFM_RES_MASK);
-+ }
-+ return ret;
-+}
-+
-+static int dcp_aes_cbc_crypt(struct ablkcipher_request *req, int mode)
-+{
-+ struct dcp_dev_req_ctx *rctx = ablkcipher_request_ctx(req);
-+ struct dcp_dev *dev = global_dev;
-+ unsigned long flags;
-+ int err = 0;
-+
-+ if (!IS_ALIGNED(req->nbytes, AES_BLOCK_SIZE))
-+ return -EINVAL;
-+
-+ rctx->mode = mode;
-+
-+ spin_lock_irqsave(&dev->queue_lock, flags);
-+ err = ablkcipher_enqueue_request(&dev->queue, req);
-+ spin_unlock_irqrestore(&dev->queue_lock, flags);
-+
-+ flags = test_and_set_bit(DCP_FLAG_BUSY, &dev->flags);
-+
-+ if (!(flags & DCP_FLAG_BUSY))
-+ tasklet_schedule(&dev->queue_task);
-+
-+ return err;
-+}
-+
-+static int dcp_aes_cbc_encrypt(struct ablkcipher_request *req)
-+{
-+ struct crypto_tfm *tfm =
-+ crypto_ablkcipher_tfm(crypto_ablkcipher_reqtfm(req));
-+ struct dcp_op *ctx = crypto_ablkcipher_ctx(
-+ crypto_ablkcipher_reqtfm(req));
-+
-+ if (unlikely(ctx->keylen != AES_KEYSIZE_128)) {
-+ int err = 0;
-+ ablkcipher_request_set_tfm(req, ctx->fallback);
-+ err = crypto_ablkcipher_encrypt(req);
-+ ablkcipher_request_set_tfm(req, __crypto_ablkcipher_cast(tfm));
-+ return err;
-+ }
-+
-+ return dcp_aes_cbc_crypt(req, DCP_AES | DCP_ENC | DCP_CBC);
-+}
-+
-+static int dcp_aes_cbc_decrypt(struct ablkcipher_request *req)
-+{
-+ struct crypto_tfm *tfm =
-+ crypto_ablkcipher_tfm(crypto_ablkcipher_reqtfm(req));
-+ struct dcp_op *ctx = crypto_ablkcipher_ctx(
-+ crypto_ablkcipher_reqtfm(req));
-+
-+ if (unlikely(ctx->keylen != AES_KEYSIZE_128)) {
-+ int err = 0;
-+ ablkcipher_request_set_tfm(req, ctx->fallback);
-+ err = crypto_ablkcipher_decrypt(req);
-+ ablkcipher_request_set_tfm(req, __crypto_ablkcipher_cast(tfm));
-+ return err;
-+ }
-+ return dcp_aes_cbc_crypt(req, DCP_AES | DCP_DEC | DCP_CBC);
-+}
-+
-+static struct crypto_alg algs[] = {
-+ {
-+ .cra_name = "cbc(aes)",
-+ .cra_driver_name = "dcp-cbc-aes",
-+ .cra_alignmask = 3,
-+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC |
-+ CRYPTO_ALG_NEED_FALLBACK,
-+ .cra_blocksize = AES_KEYSIZE_128,
-+ .cra_type = &crypto_ablkcipher_type,
-+ .cra_priority = 300,
-+ .cra_u.ablkcipher = {
-+ .min_keysize = AES_KEYSIZE_128,
-+ .max_keysize = AES_KEYSIZE_128,
-+ .setkey = dcp_aes_setkey,
-+ .encrypt = dcp_aes_cbc_encrypt,
-+ .decrypt = dcp_aes_cbc_decrypt,
-+ .ivsize = AES_KEYSIZE_128,
-+ }
-+
-+ },
-+};
-+
-+/* DCP bootstream verification interface: uses OTP key for crypto */
-+static int dcp_bootstream_open(struct inode *inode, struct file *file)
-+{
-+ file->private_data = container_of((file->private_data),
-+ struct dcp_dev, dcp_bootstream_misc);
-+ return 0;
-+}
-+
-+static long dcp_bootstream_ioctl(struct file *file,
-+ unsigned int cmd, unsigned long arg)
-+{
-+ struct dcp_dev *dev = (struct dcp_dev *) file->private_data;
-+ void __user *argp = (void __user *)arg;
-+ int ret;
-+
-+ if (dev == NULL)
-+ return -EBADF;
-+
-+ if (cmd != DBS_ENC && cmd != DBS_DEC)
-+ return -EINVAL;
-+
-+ if (copy_from_user(dev->payload_base, argp, 16))
-+ return -EFAULT;
-+
-+ if (test_and_set_bit(DCP_FLAG_BUSY, &dev->flags))
-+ return -EAGAIN;
-+
-+ dev->ctx = kzalloc(sizeof(struct dcp_op), GFP_KERNEL);
-+ if (!dev->ctx) {
-+ dev_err(dev->dev,
-+ "cannot allocate context for OTP crypto");
-+ clear_bit(DCP_FLAG_BUSY, &dev->flags);
-+ return -ENOMEM;
-+ }
-+
-+ dev->ctx->flags = DCP_AES | DCP_ECB | DCP_OTP_KEY | DCP_CBC_INIT;
-+ dev->ctx->flags |= (cmd == DBS_ENC) ? DCP_ENC : DCP_DEC;
-+ dev->hw_pkg[0]->src = dev->payload_base_dma;
-+ dev->hw_pkg[0]->dst = dev->payload_base_dma;
-+ dev->hw_pkg[0]->size = 16;
-+
-+ dcp_op_start(dev, 0);
-+
-+ while (test_bit(DCP_FLAG_BUSY, &dev->flags))
-+ cpu_relax();
-+
-+ ret = dev->ctx->stat;
-+ if (!ret && copy_to_user(argp, dev->payload_base, 16))
-+ ret = -EFAULT;
-+
-+ kfree(dev->ctx);
-+
-+ return ret;
-+}
-+
-+static const struct file_operations dcp_bootstream_fops = {
-+ .owner = THIS_MODULE,
-+ .unlocked_ioctl = dcp_bootstream_ioctl,
-+ .open = dcp_bootstream_open,
-+};
-+
-+static int dcp_probe(struct platform_device *pdev)
-+{
-+ struct dcp_dev *dev = NULL;
-+ struct resource *r;
-+ int i, ret, j;
-+
-+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
-+ if (dev == NULL) {
-+ dev_err(&pdev->dev, "Failed to allocate structure\n");
-+ ret = -ENOMEM;
-+ goto err;
-+ }
-+ global_dev = dev;
-+ dev->dev = &pdev->dev;
-+
-+ platform_set_drvdata(pdev, dev);
-+
-+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ if (!r) {
-+ dev_err(&pdev->dev, "failed to get IORESOURCE_MEM\n");
-+ ret = -ENXIO;
-+ goto err_dev;
-+ }
-+ dev->dcp_regs_base = ioremap(r->start, resource_size(r));
-+
-+
-+ dcp_set(dev, DCP_CTRL_SFRST, DCP_REG_CTRL);
-+ udelay(10);
-+ dcp_clear(dev, DCP_CTRL_SFRST | DCP_CTRL_CLKGATE, DCP_REG_CTRL);
-+
-+ dcp_write(dev, DCP_CTRL_GATHER_RES_WRITE |
-+ DCP_CTRL_ENABLE_CONTEXT_CACHE | DCP_CTRL_CH_IRQ_E_1,
-+ DCP_REG_CTRL);
-+
-+ dcp_write(dev, DCP_CHAN_CTRL_ENABLE_1, DCP_REG_CHAN_CTRL);
-+
-+ for (i = 0; i < 4; i++)
-+ dcp_clear(dev, -1, dcp_chan_reg(DCP_REG_CHAN_STAT, i));
-+
-+ dcp_clear(dev, -1, DCP_REG_STAT);
-+
-+
-+ r = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-+ if (!r) {
-+ dev_err(&pdev->dev, "can't get IRQ resource (0)\n");
-+ ret = -EIO;
-+ goto err_unmap_mem;
-+ }
-+ dev->dcp_vmi_irq = r->start;
-+ ret = request_irq(dev->dcp_vmi_irq, dcp_vmi_irq, 0, "dcp", dev);
-+ if (ret != 0) {
-+ dev_err(&pdev->dev, "can't request_irq (0)\n");
-+ ret = -EIO;
-+ goto err_unmap_mem;
-+ }
-+
-+ r = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
-+ if (!r) {
-+ dev_err(&pdev->dev, "can't get IRQ resource (1)\n");
-+ ret = -EIO;
-+ goto err_free_irq0;
-+ }
-+ dev->dcp_irq = r->start;
-+ ret = request_irq(dev->dcp_irq, dcp_irq, 0, "dcp", dev);
-+ if (ret != 0) {
-+ dev_err(&pdev->dev, "can't request_irq (1)\n");
-+ ret = -EIO;
-+ goto err_free_irq0;
-+ }
-+
-+ dev->hw_pkg[0] = dma_alloc_coherent(&pdev->dev,
-+ DCP_MAX_PKG * sizeof(struct dcp_hw_packet),
-+ &dev->hw_phys_pkg,
-+ GFP_KERNEL);
-+ if (!dev->hw_pkg[0]) {
-+ dev_err(&pdev->dev, "Could not allocate hw descriptors\n");
-+ ret = -ENOMEM;
-+ goto err_free_irq1;
-+ }
-+
-+ for (i = 1; i < DCP_MAX_PKG; i++) {
-+ dev->hw_pkg[i - 1]->next = dev->hw_phys_pkg
-+ + i * sizeof(struct dcp_hw_packet);
-+ dev->hw_pkg[i] = dev->hw_pkg[i - 1] + 1;
-+ }
-+ dev->hw_pkg[i - 1]->next = dev->hw_phys_pkg;
-+
-+
-+ dev->payload_base = dma_alloc_coherent(&pdev->dev, 2 * AES_KEYSIZE_128,
-+ &dev->payload_base_dma, GFP_KERNEL);
-+ if (!dev->payload_base) {
-+ dev_err(&pdev->dev, "Could not allocate memory for key\n");
-+ ret = -ENOMEM;
-+ goto err_free_hw_packet;
-+ }
-+ tasklet_init(&dev->queue_task, dcp_queue_task,
-+ (unsigned long) dev);
-+ tasklet_init(&dev->done_task, dcp_done_task,
-+ (unsigned long) dev);
-+ spin_lock_init(&dev->queue_lock);
-+
-+ crypto_init_queue(&dev->queue, 10);
-+
-+ init_timer(&dev->watchdog);
-+ dev->watchdog.function = &dcp_watchdog;
-+ dev->watchdog.data = (unsigned long)dev;
-+
-+ dev->dcp_bootstream_misc.minor = MISC_DYNAMIC_MINOR,
-+ dev->dcp_bootstream_misc.name = "dcpboot",
-+ dev->dcp_bootstream_misc.fops = &dcp_bootstream_fops,
-+ ret = misc_register(&dev->dcp_bootstream_misc);
-+ if (ret != 0) {
-+ dev_err(dev->dev, "Unable to register misc device\n");
-+ goto err_free_key_iv;
-+ }
-+
-+ for (i = 0; i < ARRAY_SIZE(algs); i++) {
-+ algs[i].cra_priority = 300;
-+ algs[i].cra_ctxsize = sizeof(struct dcp_op);
-+ algs[i].cra_module = THIS_MODULE;
-+ algs[i].cra_init = dcp_cra_init;
-+ algs[i].cra_exit = dcp_cra_exit;
-+ if (crypto_register_alg(&algs[i])) {
-+ dev_err(&pdev->dev, "register algorithm failed\n");
-+ ret = -ENOMEM;
-+ goto err_unregister;
-+ }
-+ }
-+ dev_notice(&pdev->dev, "DCP crypto enabled.!\n");
-+
-+ return 0;
-+
-+err_unregister:
-+ for (j = 0; j < i; j++)
-+ crypto_unregister_alg(&algs[j]);
-+err_free_key_iv:
-+ dma_free_coherent(&pdev->dev, 2 * AES_KEYSIZE_128, dev->payload_base,
-+ dev->payload_base_dma);
-+err_free_hw_packet:
-+ dma_free_coherent(&pdev->dev, DCP_MAX_PKG *
-+ sizeof(struct dcp_hw_packet), dev->hw_pkg[0],
-+ dev->hw_phys_pkg);
-+err_free_irq1:
-+ free_irq(dev->dcp_irq, dev);
-+err_free_irq0:
-+ free_irq(dev->dcp_vmi_irq, dev);
-+err_unmap_mem:
-+ iounmap((void *) dev->dcp_regs_base);
-+err_dev:
-+ kfree(dev);
-+err:
-+ return ret;
-+}
-+
-+static int dcp_remove(struct platform_device *pdev)
-+{
-+ struct dcp_dev *dev;
-+ int j;
-+ dev = platform_get_drvdata(pdev);
-+ platform_set_drvdata(pdev, NULL);
-+
-+ dma_free_coherent(&pdev->dev,
-+ DCP_MAX_PKG * sizeof(struct dcp_hw_packet),
-+ dev->hw_pkg[0], dev->hw_phys_pkg);
-+
-+ dma_free_coherent(&pdev->dev, 2 * AES_KEYSIZE_128, dev->payload_base,
-+ dev->payload_base_dma);
-+
-+ free_irq(dev->dcp_irq, dev);
-+ free_irq(dev->dcp_vmi_irq, dev);
-+
-+ tasklet_kill(&dev->done_task);
-+ tasklet_kill(&dev->queue_task);
-+
-+ iounmap((void *) dev->dcp_regs_base);
-+
-+ for (j = 0; j < ARRAY_SIZE(algs); j++)
-+ crypto_unregister_alg(&algs[j]);
-+
-+ misc_deregister(&dev->dcp_bootstream_misc);
-+
-+ kfree(dev);
-+ return 0;
-+}
-+
-+static struct of_device_id fs_dcp_of_match[] = {
-+ { .compatible = "fsl-dcp"},
-+ {},
-+};
-+
-+static struct platform_driver fs_dcp_driver = {
-+ .probe = dcp_probe,
-+ .remove = dcp_remove,
-+ .driver = {
-+ .name = "fsl-dcp",
-+ .owner = THIS_MODULE,
-+ .of_match_table = fs_dcp_of_match
-+ }
-+};
-+
-+module_platform_driver(fs_dcp_driver);
-+
-+
-+MODULE_AUTHOR("Tobias Rauter <tobias.rau...@gmail.com>");
-+MODULE_DESCRIPTION("Freescale DCP Crypto Driver");
-+MODULE_LICENSE("GPL");