[PATCH 1/2] crypto: added support for fsl-dcp on iMX23,28,50
Christoph G. Baumann
cb at sgoc.de
Fri Apr 26 07:20:14 EDT 2013
From: "Christoph G. Baumann" <cb at sgoc.de>
This patch contains added files
Signed-off-by: "Christoph G. Baumann" <cb at sgoc.de>
---
drivers/staging/crypto/Kconfig | 15 +
drivers/staging/crypto/Makefile | 1 +
drivers/staging/crypto/fsl-dcp.c | 1790 ++++++++++++++++++++++++++
drivers/staging/crypto/fsl-dcp.h | 739 +++++++++++
include/linux/fsl/fsl-dcp_bootstream_ioctl.h | 32 +
5 files changed, 2577 insertions(+)
create mode 100644 drivers/staging/crypto/Kconfig
create mode 100644 drivers/staging/crypto/Makefile
create mode 100644 drivers/staging/crypto/fsl-dcp.c
create mode 100644 drivers/staging/crypto/fsl-dcp.h
create mode 100644 include/linux/fsl/fsl-dcp_bootstream_ioctl.h
diff --git a/drivers/staging/crypto/Kconfig b/drivers/staging/crypto/Kconfig
new file mode 100644
index 0000000..acf2cf9
--- /dev/null
+++ b/drivers/staging/crypto/Kconfig
@@ -0,0 +1,15 @@
+config CRYPTO_DEV_FSL_DCP
+ tristate "Support for the DCP engine"
+ depends on SOC_IMX23 || SOC_IMX28 || SOC_IMX50
+ select CRYPTO_HW
+ select CRYPTO_ALGAPI
+ select CRYPTO_SHA256
+ select CRYPTO_AES
+ select CRYPTO_BLKCIPHER
+ help
+ Say 'Y' here to use the DCP AES and SHA
+ engine for the CryptoAPI algorithms.
+
+ To compile this driver as a module, choose M here: the module
+ will be called fsl-dcp.
+
diff --git a/drivers/staging/crypto/Makefile b/drivers/staging/crypto/Makefile
new file mode 100644
index 0000000..06eabdf
--- /dev/null
+++ b/drivers/staging/crypto/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_CRYPTO_DEV_FSL_DCP) += fsl-dcp.o
diff --git a/drivers/staging/crypto/fsl-dcp.c b/drivers/staging/crypto/fsl-dcp.c
new file mode 100644
index 0000000..9d27ebe
--- /dev/null
+++ b/drivers/staging/crypto/fsl-dcp.c
@@ -0,0 +1,1790 @@
+/*
+ * Copyright (C) 2008-2010 Freescale Semiconductor, Inc.
+ */
+/*
+ * adapted to Kernel version 3.7 by Christoph G. Baumann <cgb at debian.org>
+ */
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+/*
+ * Based on geode-aes.c
+ * Copyright (C) 2004-2006, Advanced Micro Devices, Inc.
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/bitops.h>
+#include <linux/crypto.h>
+#include <linux/spinlock.h>
+#include <linux/miscdevice.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/sysfs.h>
+#include <linux/fs.h>
+#include <crypto/algapi.h>
+#include <crypto/aes.h>
+#include <crypto/sha.h>
+#include <crypto/hash.h>
+#include <crypto/internal/hash.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+
+#include <asm/cacheflush.h>
+#include <mach/hardware.h>
+#include <linux/fsl/fsl-dcp_bootstream_ioctl.h>
+#include "fsl-dcp.h"
+
+/* Following data only used by DCP bootstream interface */
+struct dcpboot_dma_area {
+ struct dcp_hw_packet hw_packet;
+ uint16_t block[16];
+};
+
+struct dcp {
+ struct device *dev;
+ spinlock_t lock;
+ struct mutex op_mutex[DCP_NUM_CHANNELS];
+ struct completion op_wait[DCP_NUM_CHANNELS];
+ int wait[DCP_NUM_CHANNELS];
+ int dcp_vmi_irq;
+ int dcp_irq;
+ u32 dcp_regs_base;
+ ulong clock_state;
+ bool chan_in_use[DCP_NUM_CHANNELS];
+
+ /* Following buffers used in hashing to meet 64-byte len alignment */
+ char *buf1;
+ char *buf2;
+ dma_addr_t buf1_phys;
+ dma_addr_t buf2_phys;
+ struct dcp_hash_coherent_block *buf1_desc;
+ struct dcp_hash_coherent_block *buf2_desc;
+ struct dcp_hash_coherent_block *user_buf_desc;
+
+ /* Following data only used by DCP bootstream interface */
+ struct dcpboot_dma_area *dcpboot_dma_area;
+ dma_addr_t dcpboot_dma_area_phys;
+};
+
+/* 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_OTPKEY 0x0020
+
+/* hash flags */
+#define DCP_INIT 0x0001
+#define DCP_UPDATE 0x0002
+#define DCP_FINAL 0x0004
+
+#define DCP_AES 0x1000
+#define DCP_SHA1 0x2000
+#define DCP_CRC32 0x3000
+#define DCP_COPY 0x4000
+#define DCP_FILL 0x5000
+#define DCP_MODE_MASK 0xf000
+
+/* clock defines */
+#define CLOCK_ON 1
+#define CLOCK_OFF 0
+
+struct dcp_op {
+
+ unsigned int flags;
+
+ void *src;
+ dma_addr_t src_phys;
+
+ void *dst;
+ dma_addr_t dst_phys;
+
+ int len;
+
+ /* the key contains the IV for block modes */
+ union {
+ struct {
+ u8 key[2 * AES_KEYSIZE_128] __aligned(32);
+ dma_addr_t key_phys;
+ int keylen;
+ } cipher;
+ struct {
+ u8 digest[SHA256_DIGEST_SIZE] __aligned(32);
+ dma_addr_t digest_phys;
+ int digestlen;
+ int init;
+ } hash;
+ };
+
+ union {
+ struct crypto_blkcipher *blk;
+ struct crypto_cipher *cip;
+ struct crypto_hash *hash;
+ } fallback;
+
+ struct dcp_hw_packet pkt __aligned(32);
+};
+
+struct dcp_hash_coherent_block {
+ struct dcp_hw_packet pkt[1] __aligned(32);
+ u8 digest[SHA256_DIGEST_SIZE] __aligned(32);
+ unsigned int len;
+ dma_addr_t src_phys;
+ void *src;
+ void *dst;
+ dma_addr_t my_phys;
+ u32 hash_sel;
+ struct dcp_hash_coherent_block *next;
+};
+
+struct dcp_hash_op {
+
+ unsigned int flags;
+
+ /* the key contains the IV for block modes */
+ union {
+ struct {
+ u8 key[2 * AES_KEYSIZE_128] __aligned(32);
+ dma_addr_t key_phys;
+ int keylen;
+ } cipher;
+ struct {
+ u8 digest[SHA256_DIGEST_SIZE] __aligned(32);
+ dma_addr_t digest_phys;
+ int digestlen;
+ int init;
+ } hash;
+ };
+
+ u32 length;
+ struct dcp_hash_coherent_block *head_desc;
+ struct dcp_hash_coherent_block *tail_desc;
+};
+
+/* only one */
+static struct dcp *global_sdcp;
+
+static void dcp_clock(struct dcp *sdcp, ulong state, bool force)
+{
+ u32 chan;
+ struct clk *clk = clk_get(sdcp->dev, "dcp_clk");
+
+ /* unless force is true (used during suspend/resume), if any
+ * channel is running, then clk is already on, and must stay on */
+ if (!force) {
+ for (chan = 0; chan < DCP_NUM_CHANNELS; chan++) {
+ if (sdcp->chan_in_use[chan])
+ goto exit;
+ }
+ }
+
+ if (state == CLOCK_OFF) {
+ /* gate at clock source */
+ if (!IS_ERR(clk)) {
+ clk_disable(clk);
+ /* gate at DCP */
+ } else {
+ __raw_writel(BM_DCP_CTRL_CLKGATE,
+ (void *)(sdcp->dcp_regs_base + HW_DCP_CTRL_SET));
+ }
+
+ sdcp->clock_state = CLOCK_OFF;
+
+ } else {
+ /* ungate at clock source */
+ if (!IS_ERR(clk)) {
+ clk_enable(clk);
+ /* ungate at DCP */
+ } else {
+ __raw_writel(BM_DCP_CTRL_CLKGATE,
+ (void *)(sdcp->dcp_regs_base + HW_DCP_CTRL_CLR));
+ }
+
+ sdcp->clock_state = CLOCK_ON;
+ }
+
+ exit:
+ return;
+}
+
+static void dcp_perform_op(struct dcp_op *op)
+{
+ struct dcp *sdcp = global_sdcp;
+ struct mutex *mutex;
+ struct dcp_hw_packet *pkt;
+ int chan;
+ u32 pkt1, pkt2;
+ unsigned long timeout;
+ dma_addr_t pkt_phys;
+ u32 stat;
+
+ pkt1 = BM_DCP_PACKET1_DECR_SEMAPHORE | BM_DCP_PACKET1_INTERRUPT;
+
+ switch (op->flags & DCP_MODE_MASK) {
+
+ case DCP_AES:
+
+ chan = CIPHER_CHAN;
+
+ /* key is at the payload */
+ pkt1 |= BM_DCP_PACKET1_ENABLE_CIPHER;
+ if ((op->flags & DCP_OTPKEY) == 0)
+ pkt1 |= BM_DCP_PACKET1_PAYLOAD_KEY;
+ if (op->flags & DCP_ENC)
+ pkt1 |= BM_DCP_PACKET1_CIPHER_ENCRYPT;
+ if (op->flags & DCP_CBC_INIT)
+ pkt1 |= BM_DCP_PACKET1_CIPHER_INIT;
+
+ pkt2 = BF(0, DCP_PACKET2_CIPHER_CFG) |
+ BF(0, DCP_PACKET2_KEY_SELECT) |
+ BF(BV_DCP_PACKET2_CIPHER_SELECT__AES128,
+ DCP_PACKET2_CIPHER_SELECT);
+
+ if (op->flags & DCP_ECB)
+ pkt2 |= BF(BV_DCP_PACKET2_CIPHER_MODE__ECB,
+ DCP_PACKET2_CIPHER_MODE);
+ else if (op->flags & DCP_CBC)
+ pkt2 |= BF(BV_DCP_PACKET2_CIPHER_MODE__CBC,
+ DCP_PACKET2_CIPHER_MODE);
+
+ break;
+
+ case DCP_SHA1:
+
+ chan = HASH_CHAN;
+
+ pkt1 |= BM_DCP_PACKET1_ENABLE_HASH;
+ if (op->flags & DCP_INIT)
+ pkt1 |= BM_DCP_PACKET1_HASH_INIT;
+ if (op->flags & DCP_FINAL) {
+ pkt1 |= BM_DCP_PACKET1_HASH_TERM;
+ BUG_ON(op->hash.digest == NULL);
+ }
+
+ pkt2 = BF(BV_DCP_PACKET2_HASH_SELECT__SHA1,
+ DCP_PACKET2_HASH_SELECT);
+ break;
+
+ default:
+ dev_err(sdcp->dev, "Unsupported mode\n");
+ return;
+ }
+
+ mutex = &sdcp->op_mutex[chan];
+ pkt = &op->pkt;
+
+ pkt->next = 0;
+ pkt->pkt1 = pkt1;
+ pkt->pkt2 = pkt2;
+ pkt->src = (u32) op->src_phys;
+ pkt->dst = (u32) op->dst_phys;
+ pkt->size = op->len;
+ pkt->payload = chan == CIPHER_CHAN ?
+ (u32) op->cipher.key_phys : (u32) op->hash.digest_phys;
+ pkt->stat = 0;
+
+ pkt_phys = dma_map_single(sdcp->dev, pkt, sizeof(*pkt),
+ DMA_BIDIRECTIONAL);
+ if (dma_mapping_error(sdcp->dev, pkt_phys)) {
+ dev_err(sdcp->dev, "Unable to map packet descriptor\n");
+ return;
+ }
+
+ /* submit the work */
+ mutex_lock(mutex);
+ dcp_clock(sdcp, CLOCK_ON, false);
+ sdcp->chan_in_use[chan] = true;
+
+ __raw_writel(-1, (void *)(sdcp->dcp_regs_base
+ + HW_DCP_CH_N_STAT_CLR(chan)));
+
+ /* Load the work packet pointer and bump the channel semaphore */
+ __raw_writel((u32) pkt_phys, (void *)(sdcp->dcp_regs_base
+ + HW_DCP_CH_N_CMDPTR(chan)));
+
+ /* XXX wake from interrupt instead of looping */
+ timeout = jiffies + msecs_to_jiffies(1000);
+
+ sdcp->wait[chan] = 0;
+ __raw_writel(BF(1, DCP_CH_N_SEMA_INCREMENT),
+ (void *)(sdcp->dcp_regs_base + HW_DCP_CH_N_SEMA(chan)));
+ while (time_before(jiffies, timeout) && sdcp->wait[chan] == 0)
+ cpu_relax();
+
+ if (!time_before(jiffies, timeout)) {
+ dev_err(sdcp->dev, "Timeout while waiting STAT 0x%08x\n",
+ __raw_readl((void *)(sdcp->dcp_regs_base
+ + HW_DCP_STAT)));
+ goto out;
+ }
+
+ stat =
+ __raw_readl((void *)(sdcp->dcp_regs_base + HW_DCP_CH_N_STAT(chan)));
+ if ((stat & 0xff) != 0) {
+ dev_err(sdcp->dev, "Channel stat error 0x%02x\n",
+ __raw_readl((void *)(sdcp->dcp_regs_base
+ + (HW_DCP_CH_N_STAT(chan) & 0xff))));
+ }
+
+ out:
+ sdcp->chan_in_use[chan] = false;
+ dcp_clock(sdcp, CLOCK_OFF, false);
+ mutex_unlock(mutex);
+ dma_unmap_single(sdcp->dev, pkt_phys, sizeof(*pkt), DMA_TO_DEVICE);
+}
+
+static int dcp_aes_setkey_cip(struct crypto_tfm *tfm, const u8 *key,
+ unsigned int len)
+{
+ struct dcp_op *op = crypto_tfm_ctx(tfm);
+ unsigned int ret;
+
+ op->cipher.keylen = len;
+
+ if (len == AES_KEYSIZE_128) {
+ memcpy(op->cipher.key, key, len);
+ return 0;
+ }
+
+ if (len != AES_KEYSIZE_192 && len != AES_KEYSIZE_256) {
+ /* not supported at all */
+ tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+ return -EINVAL;
+ }
+
+ /*
+ * The requested key size is not supported by HW, do a fallback
+ */
+ op->fallback.blk->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK;
+ op->fallback.blk->base.crt_flags |= (tfm->crt_flags &
+ CRYPTO_TFM_REQ_MASK);
+
+ ret = crypto_cipher_setkey(op->fallback.cip, key, len);
+ if (ret) {
+ tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK;
+ tfm->crt_flags |= (op->fallback.blk->base.crt_flags &
+ CRYPTO_TFM_RES_MASK);
+ }
+ return ret;
+}
+
+static void dcp_aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+{
+ struct dcp *sdcp = global_sdcp;
+ struct dcp_op *op = crypto_tfm_ctx(tfm);
+
+ if (unlikely(op->cipher.keylen != AES_KEYSIZE_128)) {
+ crypto_cipher_encrypt_one(op->fallback.cip, out, in);
+ return;
+ }
+
+ op->src = (void *)in;
+ op->dst = (void *)out;
+ op->flags = DCP_AES | DCP_ENC | DCP_ECB;
+ op->len = AES_KEYSIZE_128;
+
+ /* map the data */
+ op->src_phys = dma_map_single(sdcp->dev, (void *)in,
+ AES_KEYSIZE_128, DMA_TO_DEVICE);
+ if (dma_mapping_error(sdcp->dev, op->src_phys)) {
+ dev_err(sdcp->dev, "Unable to map source\n");
+ return;
+ }
+
+ op->dst_phys = dma_map_single(sdcp->dev, out, AES_KEYSIZE_128,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(sdcp->dev, op->dst_phys)) {
+ dev_err(sdcp->dev, "Unable to map dest\n");
+ goto err_unmap_src;
+ }
+
+ op->cipher.key_phys = dma_map_single(sdcp->dev, op->cipher.key,
+ AES_KEYSIZE_128, DMA_TO_DEVICE);
+ if (dma_mapping_error(sdcp->dev, op->cipher.key_phys)) {
+ dev_err(sdcp->dev, "Unable to map key\n");
+ goto err_unmap_dst;
+ }
+
+ /* perform the operation */
+ dcp_perform_op(op);
+
+ dma_unmap_single(sdcp->dev, op->cipher.key_phys, AES_KEYSIZE_128,
+ DMA_TO_DEVICE);
+ err_unmap_dst:
+ dma_unmap_single(sdcp->dev, op->dst_phys, op->len, DMA_FROM_DEVICE);
+ err_unmap_src:
+ dma_unmap_single(sdcp->dev, op->src_phys, op->len, DMA_TO_DEVICE);
+}
+
+static void dcp_aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+{
+ struct dcp *sdcp = global_sdcp;
+ struct dcp_op *op = crypto_tfm_ctx(tfm);
+
+ if (unlikely(op->cipher.keylen != AES_KEYSIZE_128)) {
+ crypto_cipher_decrypt_one(op->fallback.cip, out, in);
+ return;
+ }
+
+ op->src = (void *)in;
+ op->dst = (void *)out;
+ op->flags = DCP_AES | DCP_DEC | DCP_ECB;
+ op->len = AES_KEYSIZE_128;
+
+ /* map the data */
+ op->src_phys = dma_map_single(sdcp->dev, (void *)in, AES_KEYSIZE_128,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(sdcp->dev, op->src_phys)) {
+ dev_err(sdcp->dev, "Unable to map source\n");
+ return;
+ }
+
+ op->dst_phys = dma_map_single(sdcp->dev, out, AES_KEYSIZE_128,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(sdcp->dev, op->dst_phys)) {
+ dev_err(sdcp->dev, "Unable to map dest\n");
+ goto err_unmap_src;
+ }
+
+ op->cipher.key_phys = dma_map_single(sdcp->dev, op->cipher.key,
+ AES_KEYSIZE_128, DMA_TO_DEVICE);
+ if (dma_mapping_error(sdcp->dev, op->cipher.key_phys)) {
+ dev_err(sdcp->dev, "Unable to map key\n");
+ goto err_unmap_dst;
+ }
+
+ /* perform the operation */
+ dcp_perform_op(op);
+
+ dma_unmap_single(sdcp->dev, op->cipher.key_phys, AES_KEYSIZE_128,
+ DMA_TO_DEVICE);
+ err_unmap_dst:
+ dma_unmap_single(sdcp->dev, op->dst_phys, op->len, DMA_FROM_DEVICE);
+ err_unmap_src:
+ dma_unmap_single(sdcp->dev, op->src_phys, op->len, DMA_TO_DEVICE);
+}
+
+static int fallback_init_cip(struct crypto_tfm *tfm)
+{
+ const char *name = tfm->__crt_alg->cra_name;
+ struct dcp_op *op = crypto_tfm_ctx(tfm);
+
+ op->fallback.cip = crypto_alloc_cipher(name, 0,
+ CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_NEED_FALLBACK);
+
+ if (IS_ERR(op->fallback.cip))
+ return PTR_ERR(op->fallback.cip);
+
+ return 0;
+}
+
+static void fallback_exit_cip(struct crypto_tfm *tfm)
+{
+ struct dcp_op *op = crypto_tfm_ctx(tfm);
+
+ crypto_free_cipher(op->fallback.cip);
+ op->fallback.cip = NULL;
+}
+
+static struct crypto_alg dcp_aes_alg = {
+ .cra_name = "aes",
+ .cra_driver_name = "dcp-aes",
+ .cra_priority = 300,
+ .cra_alignmask = 15,
+ .cra_flags = CRYPTO_ALG_TYPE_CIPHER | CRYPTO_ALG_NEED_FALLBACK,
+ .cra_init = fallback_init_cip,
+ .cra_exit = fallback_exit_cip,
+ .cra_blocksize = AES_KEYSIZE_128,
+ .cra_ctxsize = sizeof(struct dcp_op),
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(dcp_aes_alg.cra_list),
+ .cra_u = {
+ .cipher = {
+ .cia_min_keysize = AES_MIN_KEY_SIZE,
+ .cia_max_keysize = AES_MAX_KEY_SIZE,
+ .cia_setkey = dcp_aes_setkey_cip,
+ .cia_encrypt = dcp_aes_encrypt,
+ .cia_decrypt = dcp_aes_decrypt}
+ }
+};
+
+static int dcp_aes_setkey_blk(struct crypto_tfm *tfm, const u8 *key,
+ unsigned int len)
+{
+ struct dcp_op *op = crypto_tfm_ctx(tfm);
+ unsigned int ret;
+
+ op->cipher.keylen = len;
+
+ if (len == AES_KEYSIZE_128) {
+ memcpy(op->cipher.key, key, len);
+ return 0;
+ }
+
+ if (len != AES_KEYSIZE_192 && len != AES_KEYSIZE_256) {
+ /* not supported at all */
+ tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+ return -EINVAL;
+ }
+
+ /*
+ * The requested key size is not supported by HW, do a fallback
+ */
+ op->fallback.blk->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK;
+ op->fallback.blk->base.crt_flags |= (tfm->crt_flags &
+ CRYPTO_TFM_REQ_MASK);
+
+ ret = crypto_blkcipher_setkey(op->fallback.blk, key, len);
+ if (ret) {
+ tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK;
+ tfm->crt_flags |= (op->fallback.blk->base.crt_flags &
+ CRYPTO_TFM_RES_MASK);
+ }
+ return ret;
+}
+
+static int fallback_blk_dec(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
+{
+ unsigned int ret;
+ struct crypto_blkcipher *tfm;
+ struct dcp_op *op = crypto_blkcipher_ctx(desc->tfm);
+
+ tfm = desc->tfm;
+ desc->tfm = op->fallback.blk;
+
+ ret = crypto_blkcipher_decrypt_iv(desc, dst, src, nbytes);
+
+ desc->tfm = tfm;
+ return ret;
+}
+
+static int fallback_blk_enc(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
+{
+ unsigned int ret;
+ struct crypto_blkcipher *tfm;
+ struct dcp_op *op = crypto_blkcipher_ctx(desc->tfm);
+
+ tfm = desc->tfm;
+ desc->tfm = op->fallback.blk;
+
+ ret = crypto_blkcipher_encrypt_iv(desc, dst, src, nbytes);
+
+ desc->tfm = tfm;
+ return ret;
+}
+
+static int fallback_init_blk(struct crypto_tfm *tfm)
+{
+ const char *name = tfm->__crt_alg->cra_name;
+ struct dcp_op *op = crypto_tfm_ctx(tfm);
+
+ op->fallback.blk = crypto_alloc_blkcipher(name, 0,
+ CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_NEED_FALLBACK);
+
+ if (IS_ERR(op->fallback.blk))
+ return PTR_ERR(op->fallback.blk);
+
+ return 0;
+}
+
+static void fallback_exit_blk(struct crypto_tfm *tfm)
+{
+ struct dcp_op *op = crypto_tfm_ctx(tfm);
+
+ crypto_free_blkcipher(op->fallback.blk);
+ op->fallback.blk = NULL;
+}
+
+static int
+dcp_aes_ecb_decrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
+{
+ struct dcp *sdcp = global_sdcp;
+ struct dcp_op *op = crypto_blkcipher_ctx(desc->tfm);
+ struct blkcipher_walk walk;
+ int err;
+
+ if (unlikely(op->cipher.keylen != AES_KEYSIZE_128))
+ return fallback_blk_dec(desc, dst, src, nbytes);
+
+ blkcipher_walk_init(&walk, dst, src, nbytes);
+
+ /* key needs to be mapped only once */
+ op->cipher.key_phys = dma_map_single(sdcp->dev, op->cipher.key,
+ AES_KEYSIZE_128, DMA_TO_DEVICE);
+ if (dma_mapping_error(sdcp->dev, op->cipher.key_phys)) {
+ dev_err(sdcp->dev, "Unable to map key\n");
+ return -ENOMEM;
+ }
+
+ err = blkcipher_walk_virt(desc, &walk);
+ while (err == 0 && (nbytes = walk.nbytes) > 0) {
+ op->src = walk.src.virt.addr, op->dst = walk.dst.virt.addr;
+ op->flags = DCP_AES | DCP_DEC | DCP_ECB;
+ op->len = nbytes - (nbytes % AES_KEYSIZE_128);
+
+ /* map the data */
+ op->src_phys = dma_map_single(sdcp->dev, op->src, op->len,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(sdcp->dev, op->src_phys)) {
+ dev_err(sdcp->dev, "Unable to map source\n");
+ err = -ENOMEM;
+ break;
+ }
+
+ op->dst_phys = dma_map_single(sdcp->dev, op->dst, op->len,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(sdcp->dev, op->dst_phys)) {
+ dma_unmap_single(sdcp->dev, op->src_phys, op->len,
+ DMA_TO_DEVICE);
+ dev_err(sdcp->dev, "Unable to map dest\n");
+ err = -ENOMEM;
+ break;
+ }
+
+ /* perform! */
+ dcp_perform_op(op);
+
+ dma_unmap_single(sdcp->dev, op->dst_phys, op->len,
+ DMA_FROM_DEVICE);
+ dma_unmap_single(sdcp->dev, op->src_phys, op->len,
+ DMA_TO_DEVICE);
+
+ nbytes -= op->len;
+ err = blkcipher_walk_done(desc, &walk, nbytes);
+ }
+
+ dma_unmap_single(sdcp->dev, op->cipher.key_phys, AES_KEYSIZE_128,
+ DMA_TO_DEVICE);
+
+ return err;
+}
+
+static int
+dcp_aes_ecb_encrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
+{
+ struct dcp *sdcp = global_sdcp;
+ struct dcp_op *op = crypto_blkcipher_ctx(desc->tfm);
+ struct blkcipher_walk walk;
+ int err, ret;
+
+ if (unlikely(op->cipher.keylen != AES_KEYSIZE_128))
+ return fallback_blk_enc(desc, dst, src, nbytes);
+
+ blkcipher_walk_init(&walk, dst, src, nbytes);
+
+ /* key needs to be mapped only once */
+ op->cipher.key_phys = dma_map_single(sdcp->dev, op->cipher.key,
+ AES_KEYSIZE_128, DMA_TO_DEVICE);
+ if (dma_mapping_error(sdcp->dev, op->cipher.key_phys)) {
+ dev_err(sdcp->dev, "Unable to map key\n");
+ return -ENOMEM;
+ }
+
+ err = blkcipher_walk_virt(desc, &walk);
+
+ err = 0;
+ while (err == 0 && (nbytes = walk.nbytes) > 0) {
+ op->src = walk.src.virt.addr, op->dst = walk.dst.virt.addr;
+ op->flags = DCP_AES | DCP_ENC | DCP_ECB;
+ op->len = nbytes - (nbytes % AES_KEYSIZE_128);
+
+ /* map the data */
+ op->src_phys = dma_map_single(sdcp->dev, op->src, op->len,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(sdcp->dev, op->src_phys)) {
+ dev_err(sdcp->dev, "Unable to map source\n");
+ err = -ENOMEM;
+ break;
+ }
+
+ op->dst_phys = dma_map_single(sdcp->dev, op->dst, op->len,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(sdcp->dev, op->dst_phys)) {
+ dma_unmap_single(sdcp->dev, op->src_phys, op->len,
+ DMA_TO_DEVICE);
+ dev_err(sdcp->dev, "Unable to map dest\n");
+ err = -ENOMEM;
+ break;
+ }
+
+ /* perform! */
+ dcp_perform_op(op);
+
+ dma_unmap_single(sdcp->dev, op->dst_phys, op->len,
+ DMA_FROM_DEVICE);
+ dma_unmap_single(sdcp->dev, op->src_phys, op->len,
+ DMA_TO_DEVICE);
+
+ nbytes -= op->len;
+ ret = blkcipher_walk_done(desc, &walk, nbytes);
+ }
+
+ dma_unmap_single(sdcp->dev, op->cipher.key_phys, AES_KEYSIZE_128,
+ DMA_TO_DEVICE);
+
+ return err;
+}
+
+static struct crypto_alg dcp_aes_ecb_alg = {
+ .cra_name = "ecb(aes)",
+ .cra_driver_name = "dcp-ecb-aes",
+ .cra_priority = 400,
+ .cra_alignmask = 15,
+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | CRYPTO_ALG_NEED_FALLBACK,
+ .cra_init = fallback_init_blk,
+ .cra_exit = fallback_exit_blk,
+ .cra_blocksize = AES_KEYSIZE_128,
+ .cra_ctxsize = sizeof(struct dcp_op),
+ .cra_type = &crypto_blkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(dcp_aes_ecb_alg.cra_list),
+ .cra_u = {
+ .blkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .setkey = dcp_aes_setkey_blk,
+ .encrypt = dcp_aes_ecb_encrypt,
+ .decrypt = dcp_aes_ecb_decrypt}
+ }
+};
+
+static int
+dcp_aes_cbc_decrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
+{
+ struct dcp *sdcp = global_sdcp;
+ struct dcp_op *op = crypto_blkcipher_ctx(desc->tfm);
+ struct blkcipher_walk walk;
+ int err, blockno;
+
+ if (unlikely(op->cipher.keylen != AES_KEYSIZE_128))
+ return fallback_blk_dec(desc, dst, src, nbytes);
+
+ blkcipher_walk_init(&walk, dst, src, nbytes);
+
+ blockno = 0;
+ err = blkcipher_walk_virt(desc, &walk);
+ while (err == 0 && (nbytes = walk.nbytes) > 0) {
+ op->src = walk.src.virt.addr, op->dst = walk.dst.virt.addr;
+ op->flags = DCP_AES | DCP_DEC | DCP_CBC;
+ if (blockno == 0) {
+ op->flags |= DCP_CBC_INIT;
+ memcpy(op->cipher.key + AES_KEYSIZE_128, walk.iv,
+ AES_KEYSIZE_128);
+ }
+ op->len = nbytes - (nbytes % AES_KEYSIZE_128);
+
+ /* key (+iv) needs to be mapped only once */
+ op->cipher.key_phys = dma_map_single(sdcp->dev, op->cipher.key,
+ AES_KEYSIZE_128 * 2,
+ DMA_BIDIRECTIONAL);
+ if (dma_mapping_error(sdcp->dev, op->cipher.key_phys)) {
+ dev_err(sdcp->dev, "Unable to map key\n");
+ err = -ENOMEM;
+ break;
+ }
+
+ /* map the data */
+ op->src_phys = dma_map_single(sdcp->dev, op->src, op->len,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(sdcp->dev, op->src_phys)) {
+ dma_unmap_single(sdcp->dev, op->cipher.key_phys,
+ AES_KEYSIZE_128 * 2,
+ DMA_BIDIRECTIONAL);
+ dev_err(sdcp->dev, "Unable to map source\n");
+ err = -ENOMEM;
+ break;
+ }
+
+ op->dst_phys = dma_map_single(sdcp->dev, op->dst, op->len,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(sdcp->dev, op->dst_phys)) {
+ dma_unmap_single(sdcp->dev, op->cipher.key_phys,
+ AES_KEYSIZE_128 * 2,
+ DMA_BIDIRECTIONAL);
+ dma_unmap_single(sdcp->dev, op->src_phys, op->len,
+ DMA_TO_DEVICE);
+ dev_err(sdcp->dev, "Unable to map dest\n");
+ err = -ENOMEM;
+ break;
+ }
+
+ /* perform! */
+ dcp_perform_op(op);
+
+ dma_unmap_single(sdcp->dev, op->cipher.key_phys,
+ AES_KEYSIZE_128 * 2, DMA_BIDIRECTIONAL);
+ dma_unmap_single(sdcp->dev, op->dst_phys, op->len,
+ DMA_FROM_DEVICE);
+ dma_unmap_single(sdcp->dev, op->src_phys, op->len,
+ DMA_TO_DEVICE);
+
+ nbytes -= op->len;
+ err = blkcipher_walk_done(desc, &walk, nbytes);
+
+ blockno++;
+ }
+
+ return err;
+}
+
+static int
+dcp_aes_cbc_encrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
+{
+ struct dcp *sdcp = global_sdcp;
+ struct dcp_op *op = crypto_blkcipher_ctx(desc->tfm);
+ struct blkcipher_walk walk;
+ int err, ret, blockno;
+
+ if (unlikely(op->cipher.keylen != AES_KEYSIZE_128))
+ return fallback_blk_enc(desc, dst, src, nbytes);
+
+ blkcipher_walk_init(&walk, dst, src, nbytes);
+
+ blockno = 0;
+
+ err = blkcipher_walk_virt(desc, &walk);
+ while (err == 0 && (nbytes = walk.nbytes) > 0) {
+ op->src = walk.src.virt.addr, op->dst = walk.dst.virt.addr;
+ op->flags = DCP_AES | DCP_ENC | DCP_CBC;
+ if (blockno == 0) {
+ op->flags |= DCP_CBC_INIT;
+ memcpy(op->cipher.key + AES_KEYSIZE_128, walk.iv,
+ AES_KEYSIZE_128);
+ }
+ op->len = nbytes - (nbytes % AES_KEYSIZE_128);
+
+ /* key needs to be mapped only once */
+ op->cipher.key_phys = dma_map_single(sdcp->dev, op->cipher.key,
+ AES_KEYSIZE_128 * 2,
+ DMA_BIDIRECTIONAL);
+ if (dma_mapping_error(sdcp->dev, op->cipher.key_phys)) {
+ dev_err(sdcp->dev, "Unable to map key\n");
+ return -ENOMEM;
+ }
+
+ /* map the data */
+ op->src_phys = dma_map_single(sdcp->dev, op->src, op->len,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(sdcp->dev, op->src_phys)) {
+ dma_unmap_single(sdcp->dev, op->cipher.key_phys,
+ AES_KEYSIZE_128 * 2,
+ DMA_BIDIRECTIONAL);
+ dev_err(sdcp->dev, "Unable to map source\n");
+ err = -ENOMEM;
+ break;
+ }
+
+ op->dst_phys = dma_map_single(sdcp->dev, op->dst, op->len,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(sdcp->dev, op->dst_phys)) {
+ dma_unmap_single(sdcp->dev, op->cipher.key_phys,
+ AES_KEYSIZE_128 * 2,
+ DMA_BIDIRECTIONAL);
+ dma_unmap_single(sdcp->dev, op->src_phys, op->len,
+ DMA_TO_DEVICE);
+ dev_err(sdcp->dev, "Unable to map dest\n");
+ err = -ENOMEM;
+ break;
+ }
+
+ /* perform! */
+ dcp_perform_op(op);
+
+ dma_unmap_single(sdcp->dev, op->cipher.key_phys,
+ AES_KEYSIZE_128 * 2, DMA_BIDIRECTIONAL);
+ dma_unmap_single(sdcp->dev, op->dst_phys, op->len,
+ DMA_FROM_DEVICE);
+ dma_unmap_single(sdcp->dev, op->src_phys, op->len,
+ DMA_TO_DEVICE);
+
+ nbytes -= op->len;
+ ret = blkcipher_walk_done(desc, &walk, nbytes);
+
+ blockno++;
+ }
+
+ return err;
+}
+
+static struct crypto_alg dcp_aes_cbc_alg = {
+ .cra_name = "cbc(aes)",
+ .cra_driver_name = "dcp-cbc-aes",
+ .cra_priority = 400,
+ .cra_alignmask = 15,
+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | CRYPTO_ALG_NEED_FALLBACK,
+ .cra_init = fallback_init_blk,
+ .cra_exit = fallback_exit_blk,
+ .cra_blocksize = AES_KEYSIZE_128,
+ .cra_ctxsize = sizeof(struct dcp_op),
+ .cra_type = &crypto_blkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(dcp_aes_cbc_alg.cra_list),
+ .cra_u = {
+ .blkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .setkey = dcp_aes_setkey_blk,
+ .encrypt = dcp_aes_cbc_encrypt,
+ .decrypt = dcp_aes_cbc_decrypt,
+ .ivsize = AES_KEYSIZE_128,
+ }
+ }
+};
+
+static int dcp_perform_hash_op(struct dcp_hash_coherent_block *input,
+ u32 num_desc, bool init, bool terminate)
+{
+ struct dcp *sdcp = global_sdcp;
+ int chan;
+ struct dcp_hw_packet *pkt;
+ struct dcp_hash_coherent_block *hw;
+ unsigned long timeout;
+ u32 stat;
+ int descno, mapped;
+
+ chan = HASH_CHAN;
+
+ hw = input;
+ pkt = hw->pkt;
+
+ for (descno = 0; descno < num_desc; descno++) {
+
+ if (descno != 0) {
+
+ /* set next ptr and CHAIN bit in last packet */
+ pkt->next = hw->next->my_phys
+ + offsetof(struct dcp_hash_coherent_block, pkt[0]);
+ pkt->pkt1 |= BM_DCP_PACKET1_CHAIN;
+
+ /* iterate to next descriptor */
+ hw = hw->next;
+ pkt = hw->pkt;
+ }
+
+ pkt->pkt1 = BM_DCP_PACKET1_DECR_SEMAPHORE |
+ BM_DCP_PACKET1_ENABLE_HASH;
+
+ if (init && descno == 0)
+ pkt->pkt1 |= BM_DCP_PACKET1_HASH_INIT;
+
+ pkt->pkt2 = BF(hw->hash_sel, DCP_PACKET2_HASH_SELECT);
+
+ /* no need to flush buf1 or buf2, which are uncached */
+ if (hw->src != sdcp->buf1 && hw->src != sdcp->buf2) {
+
+ /* we have to flush the cache for the buffer */
+ hw->src_phys = dma_map_single(sdcp->dev,
+ hw->src, hw->len,
+ DMA_TO_DEVICE);
+
+ if (dma_mapping_error(sdcp->dev, hw->src_phys)) {
+ dev_err(sdcp->dev, "Unable to map source\n");
+
+ /* unmap any previous mapped buffers */
+ for (mapped = 0, hw = input; mapped < descno;
+ mapped++) {
+
+ if (mapped != 0)
+ hw = hw->next;
+ if (hw->src != sdcp->buf1 &&
+ hw->src != sdcp->buf2)
+ dma_unmap_single(sdcp->dev,
+ hw->src_phys,
+ hw->len,
+ DMA_TO_DEVICE);
+ }
+
+ return -EFAULT;
+ }
+ }
+
+ pkt->src = (u32) hw->src_phys;
+ pkt->dst = 0;
+ pkt->size = hw->len;
+ pkt->payload = 0;
+ pkt->stat = 0;
+
+ /* set HASH_TERM bit on last buf if terminate was set */
+ if (terminate && (descno == (num_desc - 1))) {
+ pkt->pkt1 |= BM_DCP_PACKET1_HASH_TERM;
+
+ memset(input->digest, 0, sizeof(input->digest));
+
+ /* set payload ptr to the 1st buffer's digest */
+ pkt->payload = (u32) input->my_phys +
+ offsetof(struct dcp_hash_coherent_block, digest);
+ }
+ }
+
+ /* submit the work */
+ __raw_writel(-1, (void *)(sdcp->dcp_regs_base
+ + HW_DCP_CH_N_STAT_CLR(chan)));
+
+ mb();
+ /* Load the 1st descriptor's physical address */
+ __raw_writel((u32) input->my_phys
+ + offsetof(struct dcp_hash_coherent_block, pkt[0]),
+ (void *)(sdcp->dcp_regs_base
+ + HW_DCP_CH_N_CMDPTR(chan)));
+
+ /* XXX wake from interrupt instead of looping */
+ timeout = jiffies + msecs_to_jiffies(1000);
+
+ /* write num_desc into sema register */
+ __raw_writel(BF(num_desc, DCP_CH_N_SEMA_INCREMENT),
+ (void *)(sdcp->dcp_regs_base + HW_DCP_CH_N_SEMA(chan)));
+
+ while (time_before(jiffies, timeout)
+ && (__raw_readl((void *)(sdcp->dcp_regs_base
+ + ((HW_DCP_CH_N_SEMA(chan) >> 16) & 0xff))) != 0)) {
+ cpu_relax();
+ }
+
+ if (!time_before(jiffies, timeout)) {
+ dev_err(sdcp->dev, "Timeout while waiting STAT 0x%08x\n",
+ __raw_readl((void *)(sdcp->dcp_regs_base
+ + HW_DCP_STAT)));
+ }
+
+ stat =
+ __raw_readl((void *)(sdcp->dcp_regs_base + HW_DCP_CH_N_STAT(chan)));
+ if ((stat & 0xff) != 0) {
+ dev_err(sdcp->dev, "Channel stat error 0x%02x\n",
+ __raw_readl((void *)(sdcp->dcp_regs_base
+ + (HW_DCP_CH_N_STAT(chan) & 0xff))));
+ }
+
+ /* unmap all src buffers */
+ for (descno = 0, hw = input; descno < num_desc; descno++) {
+ if (descno != 0)
+ hw = hw->next;
+
+ if (hw->src != sdcp->buf1 && hw->src != sdcp->buf2) {
+ dma_unmap_single(sdcp->dev, hw->src_phys,
+ hw->len, DMA_TO_DEVICE);
+ }
+ }
+
+ return 0;
+
+}
+
+static int dcp_sha_init(struct shash_desc *desc)
+{
+ struct dcp *sdcp = global_sdcp;
+ struct dcp_hash_op *op = shash_desc_ctx(desc);
+ struct mutex *mutex = &sdcp->op_mutex[HASH_CHAN];
+
+ mutex_lock(mutex);
+ dcp_clock(sdcp, CLOCK_ON, false);
+ sdcp->chan_in_use[HASH_CHAN] = true;
+
+ op->length = 0;
+
+ /* reset the lengths and the pointers of buffer descriptors */
+ sdcp->buf1_desc->len = 0;
+ sdcp->buf1_desc->src = sdcp->buf1;
+ sdcp->buf2_desc->len = 0;
+ sdcp->buf2_desc->src = sdcp->buf2;
+ op->head_desc = sdcp->buf1_desc;
+ op->tail_desc = sdcp->buf2_desc;
+
+ return 0;
+}
+
+static int dcp_sha_update(struct shash_desc *desc, const u8 *data,
+ unsigned int length)
+{
+ struct dcp *sdcp = global_sdcp;
+ struct dcp_hash_op *op = shash_desc_ctx(desc);
+ struct dcp_hash_coherent_block *temp;
+ u32 rem_bytes, bytes_borrowed, hash_sel;
+ int ret = 0;
+
+ if (strcmp(desc->tfm->base.__crt_alg->cra_name, "sha1") == 0)
+ hash_sel = BV_DCP_PACKET2_HASH_SELECT__SHA1;
+ else
+ hash_sel = BV_DCP_PACKET2_HASH_SELECT__SHA256;
+
+ sdcp->user_buf_desc->src = (void *)data;
+ sdcp->user_buf_desc->len = length;
+
+ op->tail_desc->len = 0;
+
+ /* check if any pending data from previous updates */
+ if (op->head_desc->len) {
+
+ /* borrow from this buffer to make it 64 bytes */
+ bytes_borrowed = min(64 - op->head_desc->len,
+ sdcp->user_buf_desc->len);
+
+ /* copy n bytes to head */
+ memcpy(op->head_desc->src + op->head_desc->len,
+ sdcp->user_buf_desc->src, bytes_borrowed);
+ op->head_desc->len += bytes_borrowed;
+
+ /* update current buffer's src and len */
+ sdcp->user_buf_desc->src += bytes_borrowed;
+ sdcp->user_buf_desc->len -= bytes_borrowed;
+ }
+
+ /* Is current buffer unaligned to 64 byte length?
+ * Each buffer's length must be a multiple of 64 bytes for DCP
+ */
+ rem_bytes = sdcp->user_buf_desc->len % 64;
+
+ /* if length is unaligned, copy remainder to tail */
+ if (rem_bytes) {
+
+ memcpy(op->tail_desc->src, (sdcp->user_buf_desc->src +
+ sdcp->user_buf_desc->len -
+ rem_bytes), rem_bytes);
+
+ /* update length of current buffer */
+ sdcp->user_buf_desc->len -= rem_bytes;
+
+ op->tail_desc->len = rem_bytes;
+ }
+
+ /* do not send to DCP if length is < 64 */
+ if ((op->head_desc->len + sdcp->user_buf_desc->len) >= 64) {
+
+ /* set hash alg to be used (SHA1 or SHA256) */
+ op->head_desc->hash_sel = hash_sel;
+ sdcp->user_buf_desc->hash_sel = hash_sel;
+
+ if (op->head_desc->len) {
+ op->head_desc->next = sdcp->user_buf_desc;
+
+ ret = dcp_perform_hash_op(op->head_desc,
+ sdcp->user_buf_desc->
+ len ? 2 : 1, op->length == 0,
+ false);
+ } else {
+ ret = dcp_perform_hash_op(sdcp->user_buf_desc, 1,
+ op->length == 0, false);
+ }
+
+ op->length += op->head_desc->len + sdcp->user_buf_desc->len;
+ op->head_desc->len = 0;
+ }
+
+ /* if tail has bytes, make it the head for next time */
+ if (op->tail_desc->len) {
+ temp = op->head_desc;
+ op->head_desc = op->tail_desc;
+ op->tail_desc = temp;
+ }
+
+ /* hash_sel to be used by final function */
+ op->head_desc->hash_sel = hash_sel;
+
+ return ret;
+}
+
+static int dcp_sha_final(struct shash_desc *desc, u8 *out)
+{
+ struct dcp_hash_op *op = shash_desc_ctx(desc);
+ const uint8_t *digest;
+ struct dcp *sdcp = global_sdcp;
+ u32 i, digest_len;
+ struct mutex *mutex = &sdcp->op_mutex[HASH_CHAN];
+ int ret = 0;
+
+ /* Send the leftover bytes in head, which can be length 0,
+ * but DCP still produces hash result in payload ptr.
+ * Last data bytes need not be 64-byte multiple.
+ */
+ ret = dcp_perform_hash_op(op->head_desc, 1, op->length == 0, true);
+
+ op->length += op->head_desc->len;
+
+ digest_len = (op->head_desc->hash_sel ==
+ BV_DCP_PACKET2_HASH_SELECT__SHA1) ? SHA1_DIGEST_SIZE :
+ SHA256_DIGEST_SIZE;
+
+ /* hardware reverses the digest (for some unexplicable reason) */
+ digest = op->head_desc->digest + digest_len;
+ for (i = 0; i < digest_len; i++)
+ *out++ = *--digest;
+
+ sdcp->chan_in_use[HASH_CHAN] = false;
+ dcp_clock(sdcp, CLOCK_OFF, false);
+ mutex_unlock(mutex);
+
+ return ret;
+}
+
+static struct shash_alg dcp_sha1_alg = {
+ .init = dcp_sha_init,
+ .update = dcp_sha_update,
+ .final = dcp_sha_final,
+ .descsize = sizeof(struct dcp_hash_op),
+ .digestsize = SHA1_DIGEST_SIZE,
+ .base = {
+ .cra_name = "sha1",
+ .cra_driver_name = "sha1-dcp",
+ .cra_priority = 300,
+ .cra_blocksize = SHA1_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct dcp_hash_op),
+ .cra_module = THIS_MODULE,
+ }
+};
+
+static struct shash_alg dcp_sha256_alg = {
+ .init = dcp_sha_init,
+ .update = dcp_sha_update,
+ .final = dcp_sha_final,
+ .descsize = sizeof(struct dcp_hash_op),
+ .digestsize = SHA256_DIGEST_SIZE,
+ .base = {
+ .cra_name = "sha256",
+ .cra_driver_name = "sha256-dcp",
+ .cra_priority = 300,
+ .cra_blocksize = SHA256_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct dcp_hash_op),
+ .cra_module = THIS_MODULE,
+ }
+};
+
+static irqreturn_t dcp_common_irq(int irq, void *context)
+{
+ struct dcp *sdcp = context;
+ u32 msk;
+
+ /* check */
+ msk = __raw_readl((void *)(sdcp->dcp_regs_base + HW_DCP_STAT))
+ & BF(0x0f, DCP_STAT_IRQ);
+ if (msk == 0)
+ return IRQ_NONE;
+
+ /* clear this channel */
+ __raw_writel(msk, (void *)(sdcp->dcp_regs_base + HW_DCP_STAT_CLR));
+ if (msk & BF(0x01, DCP_STAT_IRQ))
+ sdcp->wait[0]++;
+ if (msk & BF(0x02, DCP_STAT_IRQ))
+ sdcp->wait[1]++;
+ if (msk & BF(0x04, DCP_STAT_IRQ))
+ sdcp->wait[2]++;
+ if (msk & BF(0x08, DCP_STAT_IRQ))
+ sdcp->wait[3]++;
+
+ 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);
+}
+
+/* DCP bootstream verification interface: uses OTP key for crypto */
+static long dcp_bootstream_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct dcp *sdcp = global_sdcp;
+ struct dcpboot_dma_area *da = sdcp->dcpboot_dma_area;
+ void __user *argp = (void __user *)arg;
+ int chan = ROM_DCP_CHAN;
+ unsigned long timeout;
+ struct mutex *mutex;
+ int retval;
+
+ /* be paranoid */
+ if (sdcp == NULL)
+ return -EBADF;
+
+ if (cmd != DBS_ENC && cmd != DBS_DEC)
+ return -EINVAL;
+
+ /* copy to (aligned) block */
+ if (copy_from_user(da->block, argp, 16))
+ return -EFAULT;
+
+ mutex = &sdcp->op_mutex[chan];
+ mutex_lock(mutex);
+ dcp_clock(sdcp, CLOCK_ON, false);
+ sdcp->chan_in_use[chan] = true;
+
+ __raw_writel(-1, (void *)(sdcp->dcp_regs_base
+ + HW_DCP_CH_N_STAT_CLR(ROM_DCP_CHAN)));
+ __raw_writel(BF(ROM_DCP_CHAN_MASK, DCP_STAT_IRQ),
+ (void *)(sdcp->dcp_regs_base + HW_DCP_STAT_CLR));
+
+ da->hw_packet.next = 0;
+ da->hw_packet.pkt1 = BM_DCP_PACKET1_DECR_SEMAPHORE |
+ BM_DCP_PACKET1_ENABLE_CIPHER | BM_DCP_PACKET1_OTP_KEY |
+ BM_DCP_PACKET1_INTERRUPT |
+ (cmd == DBS_ENC ? BM_DCP_PACKET1_CIPHER_ENCRYPT : 0);
+ da->hw_packet.pkt2 = BF(0, DCP_PACKET2_CIPHER_CFG) |
+ BF(0, DCP_PACKET2_KEY_SELECT) |
+ BF(BV_DCP_PACKET2_CIPHER_MODE__ECB, DCP_PACKET2_CIPHER_MODE) |
+ BF(BV_DCP_PACKET2_CIPHER_SELECT__AES128, DCP_PACKET2_CIPHER_SELECT);
+ da->hw_packet.src = sdcp->dcpboot_dma_area_phys +
+ offsetof(struct dcpboot_dma_area, block);
+ da->hw_packet.dst = da->hw_packet.src; /* in-place */
+ da->hw_packet.size = 16;
+ da->hw_packet.payload = 0;
+ da->hw_packet.stat = 0;
+
+ /* Load the work packet pointer and bump the channel semaphore */
+ __raw_writel(sdcp->dcpboot_dma_area_phys
+ + offsetof(struct dcpboot_dma_area, hw_packet),
+ (void *)(sdcp->dcp_regs_base
+ + HW_DCP_CH_N_CMDPTR(ROM_DCP_CHAN)));
+
+ sdcp->wait[chan] = 0;
+ __raw_writel(BF(1, DCP_CH_N_SEMA_INCREMENT),
+ (void *)(sdcp->dcp_regs_base
+ + HW_DCP_CH_N_SEMA(ROM_DCP_CHAN)));
+
+ timeout = jiffies + msecs_to_jiffies(100);
+
+ while (time_before(jiffies, timeout) && sdcp->wait[chan] == 0)
+ cpu_relax();
+
+ if (!time_before(jiffies, timeout)) {
+ dev_err(sdcp->dev,
+ "Timeout while waiting for operation to complete\n");
+ retval = -ETIMEDOUT;
+ goto exit;
+ }
+
+ if (__raw_readl((void *)(sdcp->dcp_regs_base
+ + (HW_DCP_CH_N_STAT(ROM_DCP_CHAN) & 0xff))) != 0) {
+ dev_err(sdcp->dev, "Channel stat error 0x%02x\n",
+ __raw_readl((void *)(sdcp->dcp_regs_base
+ + (HW_DCP_CH_N_STAT(ROM_DCP_CHAN) & 0xff))));
+ retval = -EFAULT;
+ goto exit;
+ }
+
+ if (copy_to_user(argp, da->block, 16)) {
+ retval = -EFAULT;
+ goto exit;
+ }
+
+ retval = 0;
+
+ exit:
+ sdcp->chan_in_use[chan] = false;
+ dcp_clock(sdcp, CLOCK_OFF, false);
+ mutex_unlock(mutex);
+ return retval;
+}
+
+static const struct file_operations dcp_bootstream_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = dcp_bootstream_ioctl,
+};
+
+static struct miscdevice dcp_bootstream_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "dcpboot",
+ .fops = &dcp_bootstream_fops,
+};
+
+static int dcp_probe(struct platform_device *pdev)
+{
+ struct dcp *sdcp = NULL;
+ struct resource *r;
+ int i, ret;
+ dma_addr_t hw_phys;
+
+ if (global_sdcp != NULL) {
+ dev_err(&pdev->dev, "Only one instance allowed\n");
+ ret = -ENODEV;
+ goto err;
+ }
+
+ /* allocate memory */
+ sdcp = kzalloc(sizeof(*sdcp), GFP_KERNEL);
+ if (sdcp == NULL) {
+ dev_err(&pdev->dev, "Failed to allocate structure\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ sdcp->dev = &pdev->dev;
+ spin_lock_init(&sdcp->lock);
+
+ for (i = 0; i < DCP_NUM_CHANNELS; i++) {
+ mutex_init(&sdcp->op_mutex[i]);
+ init_completion(&sdcp->op_wait[i]);
+ sdcp->chan_in_use[i] = false;
+ }
+
+ platform_set_drvdata(pdev, sdcp);
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!r) {
+ dev_err(&pdev->dev, "failed to get IORESOURCE_MEM\n");
+ ret = -ENXIO;
+ goto err_kfree;
+ }
+ sdcp->dcp_regs_base = (u32) ioremap(r->start, r->end - r->start + 1);
+ dcp_clock(sdcp, CLOCK_ON, true);
+
+ /* Soft reset and remove the clock gate */
+ __raw_writel(BM_DCP_CTRL_SFTRST, (void *)(sdcp->dcp_regs_base
+ + HW_DCP_CTRL_SET));
+
+ /* At 24Mhz, it takes no more than 4 clocks (160 ns) Maximum for
+ * the part to reset, reading the register twice should
+ * be sufficient to get 4 clks delay.
+ */
+ __raw_readl((void *)(sdcp->dcp_regs_base + HW_DCP_CTRL));
+ __raw_readl((void *)(sdcp->dcp_regs_base + HW_DCP_CTRL));
+
+ __raw_writel(BM_DCP_CTRL_SFTRST | BM_DCP_CTRL_CLKGATE,
+ (void *)(sdcp->dcp_regs_base + HW_DCP_CTRL_CLR));
+
+ /* Initialize control registers */
+ __raw_writel(DCP_CTRL_INIT, (void *)(sdcp->dcp_regs_base
+ + HW_DCP_CTRL));
+ __raw_writel(DCP_CHANNELCTRL_INIT,
+ (void *)(sdcp->dcp_regs_base + HW_DCP_CHANNELCTRL));
+
+ /* We do not enable context switching. Give the context
+ * buffer pointer an illegal address so if context switching is
+ * inadvertantly enabled, the dcp will return an error instead of
+ * trashing good memory. The dcp dma cannot access rom, so any rom
+ * address will do.
+ */
+ __raw_writel(0xFFFF0000, (void *)(sdcp->dcp_regs_base
+ + HW_DCP_CONTEXT));
+
+ for (i = 0; i < DCP_NUM_CHANNELS; i++) {
+ __raw_writel(-1, (void *)(sdcp->dcp_regs_base
+ + HW_DCP_CH_N_STAT_CLR(i)));
+ }
+ __raw_writel(-1, (void *)(sdcp->dcp_regs_base + HW_DCP_STAT_CLR));
+
+ 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_gate_clk;
+ }
+ sdcp->dcp_vmi_irq = r->start;
+ ret = request_irq(sdcp->dcp_vmi_irq, dcp_vmi_irq, 0, "dcp", sdcp);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "can't request_irq (0)\n");
+ goto err_gate_clk;
+ }
+
+ 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;
+ }
+ sdcp->dcp_irq = r->start;
+ ret = request_irq(sdcp->dcp_irq, dcp_irq, 0, "dcp", sdcp);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "can't request_irq (1)\n");
+ goto err_free_irq0;
+ }
+
+ global_sdcp = sdcp;
+
+ ret = crypto_register_alg(&dcp_aes_alg);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "Failed to register aes crypto\n");
+ goto err_free_irq1;
+ }
+
+ ret = crypto_register_alg(&dcp_aes_ecb_alg);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "Failed to register aes ecb crypto\n");
+ goto err_unregister_aes;
+ }
+
+ ret = crypto_register_alg(&dcp_aes_cbc_alg);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "Failed to register aes cbc crypto\n");
+ goto err_unregister_aes_ecb;
+ }
+
+ /* Allocate the descriptor to be used for user buffer
+ * passed in by the "update" function from Crypto API
+ */
+ sdcp->user_buf_desc = dma_alloc_coherent(sdcp->dev,
+ sizeof(
+ struct dcp_hash_coherent_block),
+ &hw_phys, GFP_KERNEL);
+ if (sdcp->user_buf_desc == NULL) {
+ dev_err(&pdev->dev, "Error allocating coherent block\n");
+ ret = -ENOMEM;
+ goto err_unregister_aes_cbc;
+ }
+
+ sdcp->user_buf_desc->my_phys = hw_phys;
+
+ /* Allocate 2 buffers (head & tail) & its descriptors to deal with
+ * buffer lengths that are not 64 byte aligned, except for the
+ * last one.
+ */
+ sdcp->buf1 = dma_alloc_coherent(sdcp->dev,
+ 64, &sdcp->buf1_phys, GFP_KERNEL);
+ if (sdcp->buf1 == NULL) {
+ dev_err(&pdev->dev, "Error allocating coherent block\n");
+ ret = -ENOMEM;
+ goto err_unregister_aes_cbc;
+ }
+
+ sdcp->buf2 = dma_alloc_coherent(sdcp->dev,
+ 64, &sdcp->buf2_phys, GFP_KERNEL);
+ if (sdcp->buf2 == NULL) {
+ dev_err(&pdev->dev, "Error allocating coherent block\n");
+ ret = -ENOMEM;
+ goto err_unregister_aes_cbc;
+ }
+
+ sdcp->buf1_desc = dma_alloc_coherent(sdcp->dev,
+ sizeof(struct
+ dcp_hash_coherent_block),
+ &hw_phys, GFP_KERNEL);
+ if (sdcp->buf1_desc == NULL) {
+ dev_err(&pdev->dev, "Error allocating coherent block\n");
+ ret = -ENOMEM;
+ goto err_unregister_aes_cbc;
+ }
+
+ sdcp->buf1_desc->my_phys = hw_phys;
+ sdcp->buf1_desc->src = (void *)sdcp->buf1;
+ sdcp->buf1_desc->src_phys = sdcp->buf1_phys;
+
+ sdcp->buf2_desc = dma_alloc_coherent(sdcp->dev,
+ sizeof(struct
+ dcp_hash_coherent_block),
+ &hw_phys, GFP_KERNEL);
+ if (sdcp->buf2_desc == NULL) {
+ dev_err(&pdev->dev, "Error allocating coherent block\n");
+ ret = -ENOMEM;
+ goto err_unregister_aes_cbc;
+ }
+
+ sdcp->buf2_desc->my_phys = hw_phys;
+ sdcp->buf2_desc->src = (void *)sdcp->buf2;
+ sdcp->buf2_desc->src_phys = sdcp->buf2_phys;
+
+ ret = crypto_register_shash(&dcp_sha1_alg);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "Failed to register sha1 hash\n");
+ goto err_unregister_aes_cbc;
+ }
+
+ if (__raw_readl((void *)(sdcp->dcp_regs_base +
+ HW_DCP_CAPABILITY1)) &
+ BF_DCP_CAPABILITY1_HASH_ALGORITHMS
+ (BV_DCP_CAPABILITY1_HASH_ALGORITHMS__SHA256)) {
+
+ ret = crypto_register_shash(&dcp_sha256_alg);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "Failed to register sha256 hash\n");
+ goto err_unregister_sha1;
+ }
+ }
+
+ /* register dcpboot interface to allow apps (such as kobs-ng) to
+ * verify files (such as the bootstream) using the OTP key for crypto */
+ ret = misc_register(&dcp_bootstream_misc);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "Unable to register misc device\n");
+ goto err_unregister_sha1;
+ }
+
+ sdcp->dcpboot_dma_area = dma_alloc_coherent(&pdev->dev,
+ sizeof(*sdcp->
+ dcpboot_dma_area),
+ &sdcp->
+ dcpboot_dma_area_phys,
+ GFP_KERNEL);
+ if (sdcp->dcpboot_dma_area == NULL) {
+ dev_err(&pdev->dev,
+ "Unable to allocate DMAable memory for dcpboot interface\n");
+ goto err_dereg;
+ }
+
+ dcp_clock(sdcp, CLOCK_OFF, false);
+ dev_notice(&pdev->dev, "DCP crypto enabled.!\n");
+ return 0;
+
+ err_dereg:
+ misc_deregister(&dcp_bootstream_misc);
+ err_unregister_sha1:
+ crypto_unregister_shash(&dcp_sha1_alg);
+ err_unregister_aes_cbc:
+ crypto_unregister_alg(&dcp_aes_cbc_alg);
+ err_unregister_aes_ecb:
+ crypto_unregister_alg(&dcp_aes_ecb_alg);
+ err_unregister_aes:
+ crypto_unregister_alg(&dcp_aes_alg);
+ err_free_irq1:
+ free_irq(sdcp->dcp_irq, sdcp);
+ err_free_irq0:
+ free_irq(sdcp->dcp_vmi_irq, sdcp);
+ err_gate_clk:
+ dcp_clock(sdcp, CLOCK_OFF, false);
+ err_kfree:
+ kfree(sdcp);
+ err:
+
+ return ret;
+}
+
+static int dcp_remove(struct platform_device *pdev)
+{
+ struct dcp *sdcp;
+
+ sdcp = platform_get_drvdata(pdev);
+ platform_set_drvdata(pdev, NULL);
+
+ dcp_clock(sdcp, CLOCK_ON, false);
+
+ free_irq(sdcp->dcp_irq, sdcp);
+ free_irq(sdcp->dcp_vmi_irq, sdcp);
+
+ /* if head and tail buffers were allocated, free them */
+ if (sdcp->buf1) {
+ dma_free_coherent(sdcp->dev, 64, sdcp->buf1, sdcp->buf1_phys);
+ dma_free_coherent(sdcp->dev, 64, sdcp->buf2, sdcp->buf2_phys);
+
+ dma_free_coherent(sdcp->dev,
+ sizeof(struct dcp_hash_coherent_block),
+ sdcp->buf1_desc, sdcp->buf1_desc->my_phys);
+
+ dma_free_coherent(sdcp->dev,
+ sizeof(struct dcp_hash_coherent_block),
+ sdcp->buf2_desc, sdcp->buf2_desc->my_phys);
+
+ dma_free_coherent(sdcp->dev,
+ sizeof(struct dcp_hash_coherent_block),
+ sdcp->user_buf_desc,
+ sdcp->user_buf_desc->my_phys);
+ }
+
+ if (sdcp->dcpboot_dma_area) {
+ dma_free_coherent(&pdev->dev, sizeof(*sdcp->dcpboot_dma_area),
+ sdcp->dcpboot_dma_area,
+ sdcp->dcpboot_dma_area_phys);
+ misc_deregister(&dcp_bootstream_misc);
+ }
+
+ crypto_unregister_shash(&dcp_sha1_alg);
+
+ if (__raw_readl((void *)(sdcp->dcp_regs_base + HW_DCP_CAPABILITY1))
+ & BF_DCP_CAPABILITY1_HASH_ALGORITHMS(
+ BV_DCP_CAPABILITY1_HASH_ALGORITHMS__SHA256)) {
+ crypto_unregister_shash(&dcp_sha256_alg);
+ }
+
+ crypto_unregister_alg(&dcp_aes_cbc_alg);
+ crypto_unregister_alg(&dcp_aes_ecb_alg);
+ crypto_unregister_alg(&dcp_aes_alg);
+
+ dcp_clock(sdcp, CLOCK_OFF, true);
+ iounmap((void *)sdcp->dcp_regs_base);
+ kfree(sdcp);
+ global_sdcp = NULL;
+
+ return 0;
+}
+
+static int dcp_suspend(struct platform_device *pdev, pm_message_t state)
+{
+#ifdef CONFIG_PM
+ struct dcp *sdcp = platform_get_drvdata(pdev);
+
+ if (sdcp->clock_state == CLOCK_ON) {
+ dcp_clock(sdcp, CLOCK_OFF, true);
+ /* indicate that clock needs to be turned on upon resume */
+ sdcp->clock_state = CLOCK_ON;
+ }
+#endif
+ return 0;
+}
+
+static int dcp_resume(struct platform_device *pdev)
+{
+#ifdef CONFIG_PM
+ struct dcp *sdcp = platform_get_drvdata(pdev);
+
+ /* if clock was on prior to suspend, turn it back on */
+ if (sdcp->clock_state == CLOCK_ON)
+ dcp_clock(sdcp, CLOCK_ON, true);
+#endif
+ return 0;
+}
+
+static const struct of_device_id mxs_dcp_dt_ids[] = {
+ {.compatible = "fsl,fsl-dcp", .data = NULL,},
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, mxs_dcp_dt_ids);
+
+static struct platform_driver dcp_driver = {
+ .probe = dcp_probe,
+ .remove = dcp_remove,
+ .suspend = dcp_suspend,
+ .resume = dcp_resume,
+ .driver = {
+ .name = "fsl-dcp",
+ .owner = THIS_MODULE,
+ .of_match_table = mxs_dcp_dt_ids,
+ },
+};
+
+static int __init dcp_init(void)
+{
+ return platform_driver_register(&dcp_driver);
+}
+
+static void __exit dcp_exit(void)
+{
+ platform_driver_unregister(&dcp_driver);
+}
+
+MODULE_AUTHOR("Pantelis Antoniou <pantelis at embeddedalley.com>");
+MODULE_DESCRIPTION("DCP Crypto Driver");
+MODULE_LICENSE("GPL");
+
+module_init(dcp_init);
+module_exit(dcp_exit);
diff --git a/drivers/staging/crypto/fsl-dcp.h b/drivers/staging/crypto/fsl-dcp.h
new file mode 100644
index 0000000..3b21c09
--- /dev/null
+++ b/drivers/staging/crypto/fsl-dcp.h
@@ -0,0 +1,739 @@
+/*
+ * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef DCP_H_
+#define DCP_H_
+
+/* 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_OTPKEY 0x0020
+
+/* hash flags */
+#define DCP_INIT 0x0001
+#define DCP_UPDATE 0x0002
+#define DCP_FINAL 0x0004
+
+#define DCP_AES 0x1000
+#define DCP_SHA1 0x2000
+#define DCP_CRC32 0x3000
+#define DCP_COPY 0x4000
+#define DCP_FILL 0x5000
+#define DCP_MODE_MASK 0xf000
+
+/* clock defines */
+#define CLOCK_ON 1
+#define CLOCK_OFF 0
+
+#define CIPHER_CHAN 1
+#define CIPHER_MASK (1 << CIPHER_CHAN)
+
+#define HASH_CHAN 0
+#define HASH_MASK (1 << HASH_CHAN)
+
+/* DCP boostream interface uses this channel (same as the ROM) */
+#define ROM_DCP_CHAN 3
+#define ROM_DCP_CHAN_MASK (1 << ROM_DCP_CHAN)
+
+#define ALL_MASK (CIPHER_MASK | HASH_MASK | ROM_DCP_CHAN_MASK)
+
+/* Defines the initialization value for the dcp control register */
+#define DCP_CTRL_INIT \
+ (BM_DCP_CTRL_GATHER_RESIDUAL_WRITES | \
+ BM_DCP_CTRL_ENABLE_CONTEXT_CACHING | \
+ BV_DCP_CTRL_CHANNEL_INTERRUPT_ENABLE__CH0 | \
+ BV_DCP_CTRL_CHANNEL_INTERRUPT_ENABLE__CH1 | \
+ BV_DCP_CTRL_CHANNEL_INTERRUPT_ENABLE__CH2 | \
+ BV_DCP_CTRL_CHANNEL_INTERRUPT_ENABLE__CH3)
+
+/* Defines the initialization value for the dcp channel control register */
+#define DCP_CHANNELCTRL_INIT \
+ BF(ALL_MASK, DCP_CHANNELCTRL_ENABLE_CHANNEL)
+
+/* DCP work packet 1 value for encryption */
+#define DCP_PKT1_ENCRYPT \
+ (BM_DCP_PACKET1_DECR_SEMAPHORE | \
+ BM_DCP_PACKET1_ENABLE_CIPHER | \
+ BM_DCP_PACKET1_CIPHER_ENCRYPT | \
+ BM_DCP_PACKET1_CIPHER_INIT)
+
+/* DCP work packet 1 value for decryption */
+#define DCP_PKT1_DECRYPT \
+ (BM_DCP_PACKET1_DECR_SEMAPHORE | \
+ BM_DCP_PACKET1_ENABLE_CIPHER | \
+ BM_DCP_PACKET1_CIPHER_INIT)
+
+/* DCP (decryption) work packet definition */
+struct dcp_hw_packet {
+ uint32_t next; /* next dcp work packet address */
+ uint32_t pkt1; /* dcp work packet 1 (control 0) */
+ uint32_t pkt2; /* dcp work packet 2 (control 1) */
+ uint32_t src; /* source buffer address */
+ uint32_t dst; /* destination buffer address */
+ uint32_t size; /* buffer size in bytes */
+ uint32_t payload; /* payload buffer address */
+ uint32_t stat; /* dcp status (written by dcp) */
+};
+
+#define DCP_NUM_CHANNELS 4
+
+/* DCP Register definitions */
+
+#ifndef BF
+#define BF(value, field) (((value) << BP_##field) & BM_##field)
+#endif
+
+#define REGS_DCP_SIZE 0x00002000
+
+#define HW_DCP_CTRL (0x00000000)
+#define HW_DCP_CTRL_SET (0x00000004)
+#define HW_DCP_CTRL_CLR (0x00000008)
+#define HW_DCP_CTRL_TOG (0x0000000c)
+
+#define BM_DCP_CTRL_SFTRST 0x80000000
+#define BM_DCP_CTRL_CLKGATE 0x40000000
+#define BM_DCP_CTRL_PRESENT_CRYPTO 0x20000000
+#define BV_DCP_CTRL_PRESENT_CRYPTO__PRESENT 0x1
+#define BV_DCP_CTRL_PRESENT_CRYPTO__ABSENT 0x0
+#define BM_DCP_CTRL_PRESENT_CSC 0x10000000
+#define BV_DCP_CTRL_PRESENT_CSC__PRESENT 0x1
+#define BV_DCP_CTRL_PRESENT_CSC__ABSENT 0x0
+#define BP_DCP_CTRL_RSVD1 24
+#define BM_DCP_CTRL_RSVD1 0x0F000000
+#define BF_DCP_CTRL_RSVD1(v) \
+ (((v) << 24) & BM_DCP_CTRL_RSVD1)
+#define BM_DCP_CTRL_GATHER_RESIDUAL_WRITES 0x00800000
+#define BM_DCP_CTRL_ENABLE_CONTEXT_CACHING 0x00400000
+#define BM_DCP_CTRL_ENABLE_CONTEXT_SWITCHING 0x00200000
+#define BP_DCP_CTRL_RSVD0 9
+#define BM_DCP_CTRL_RSVD0 0x001FFE00
+#define BF_DCP_CTRL_RSVD0(v) \
+ (((v) << 9) & BM_DCP_CTRL_RSVD0)
+#define BM_DCP_CTRL_CSC_INTERRUPT_ENABLE 0x00000100
+#define BP_DCP_CTRL_CHANNEL_INTERRUPT_ENABLE 0
+#define BM_DCP_CTRL_CHANNEL_INTERRUPT_ENABLE 0x000000FF
+#define BF_DCP_CTRL_CHANNEL_INTERRUPT_ENABLE(v) \
+ (((v) << 0) & BM_DCP_CTRL_CHANNEL_INTERRUPT_ENABLE)
+#define BV_DCP_CTRL_CHANNEL_INTERRUPT_ENABLE__CH0 0x01
+#define BV_DCP_CTRL_CHANNEL_INTERRUPT_ENABLE__CH1 0x02
+#define BV_DCP_CTRL_CHANNEL_INTERRUPT_ENABLE__CH2 0x04
+#define BV_DCP_CTRL_CHANNEL_INTERRUPT_ENABLE__CH3 0x08
+
+#define HW_DCP_STAT (0x00000010)
+#define HW_DCP_STAT_SET (0x00000014)
+#define HW_DCP_STAT_CLR (0x00000018)
+#define HW_DCP_STAT_TOG (0x0000001c)
+
+#define BP_DCP_STAT_RSVD2 29
+#define BM_DCP_STAT_RSVD2 0xE0000000
+#define BF_DCP_STAT_RSVD2(v) \
+ (((v) << 29) & BM_DCP_STAT_RSVD2)
+#define BM_DCP_STAT_OTP_KEY_READY 0x10000000
+#define BP_DCP_STAT_CUR_CHANNEL 24
+#define BM_DCP_STAT_CUR_CHANNEL 0x0F000000
+#define BF_DCP_STAT_CUR_CHANNEL(v) \
+ (((v) << 24) & BM_DCP_STAT_CUR_CHANNEL)
+#define BV_DCP_STAT_CUR_CHANNEL__NONE 0x0
+#define BV_DCP_STAT_CUR_CHANNEL__CH0 0x1
+#define BV_DCP_STAT_CUR_CHANNEL__CH1 0x2
+#define BV_DCP_STAT_CUR_CHANNEL__CH2 0x3
+#define BV_DCP_STAT_CUR_CHANNEL__CH3 0x4
+#define BV_DCP_STAT_CUR_CHANNEL__CSC 0x8
+#define BP_DCP_STAT_READY_CHANNELS 16
+#define BM_DCP_STAT_READY_CHANNELS 0x00FF0000
+#define BF_DCP_STAT_READY_CHANNELS(v) \
+ (((v) << 16) & BM_DCP_STAT_READY_CHANNELS)
+#define BV_DCP_STAT_READY_CHANNELS__CH0 0x01
+#define BV_DCP_STAT_READY_CHANNELS__CH1 0x02
+#define BV_DCP_STAT_READY_CHANNELS__CH2 0x04
+#define BV_DCP_STAT_READY_CHANNELS__CH3 0x08
+#define BP_DCP_STAT_RSVD1 9
+#define BM_DCP_STAT_RSVD1 0x0000FE00
+#define BF_DCP_STAT_RSVD1(v) \
+ (((v) << 9) & BM_DCP_STAT_RSVD1)
+#define BM_DCP_STAT_CSCIRQ 0x00000100
+#define BP_DCP_STAT_RSVD0 4
+#define BM_DCP_STAT_RSVD0 0x000000F0
+#define BF_DCP_STAT_RSVD0(v) \
+ (((v) << 4) & BM_DCP_STAT_RSVD0)
+#define BP_DCP_STAT_IRQ 0
+#define BM_DCP_STAT_IRQ 0x0000000F
+#define BF_DCP_STAT_IRQ(v) \
+ (((v) << 0) & BM_DCP_STAT_IRQ)
+
+#define HW_DCP_CHANNELCTRL (0x00000020)
+#define HW_DCP_CHANNELCTRL_SET (0x00000024)
+#define HW_DCP_CHANNELCTRL_CLR (0x00000028)
+#define HW_DCP_CHANNELCTRL_TOG (0x0000002c)
+
+#define BP_DCP_CHANNELCTRL_RSVD 19
+#define BM_DCP_CHANNELCTRL_RSVD 0xFFF80000
+#define BF_DCP_CHANNELCTRL_RSVD(v) \
+ (((v) << 19) & BM_DCP_CHANNELCTRL_RSVD)
+#define BP_DCP_CHANNELCTRL_CSC_PRIORITY 17
+#define BM_DCP_CHANNELCTRL_CSC_PRIORITY 0x00060000
+#define BF_DCP_CHANNELCTRL_CSC_PRIORITY(v) \
+ (((v) << 17) & BM_DCP_CHANNELCTRL_CSC_PRIORITY)
+#define BV_DCP_CHANNELCTRL_CSC_PRIORITY__HIGH 0x3
+#define BV_DCP_CHANNELCTRL_CSC_PRIORITY__MED 0x2
+#define BV_DCP_CHANNELCTRL_CSC_PRIORITY__LOW 0x1
+#define BV_DCP_CHANNELCTRL_CSC_PRIORITY__BACKGROUND 0x0
+#define BM_DCP_CHANNELCTRL_CH0_IRQ_MERGED 0x00010000
+#define BP_DCP_CHANNELCTRL_HIGH_PRIORITY_CHANNEL 8
+#define BM_DCP_CHANNELCTRL_HIGH_PRIORITY_CHANNEL 0x0000FF00
+#define BF_DCP_CHANNELCTRL_HIGH_PRIORITY_CHANNEL(v) \
+ (((v) << 8) & BM_DCP_CHANNELCTRL_HIGH_PRIORITY_CHANNEL)
+#define BV_DCP_CHANNELCTRL_HIGH_PRIORITY_CHANNEL__CH0 0x01
+#define BV_DCP_CHANNELCTRL_HIGH_PRIORITY_CHANNEL__CH1 0x02
+#define BV_DCP_CHANNELCTRL_HIGH_PRIORITY_CHANNEL__CH2 0x04
+#define BV_DCP_CHANNELCTRL_HIGH_PRIORITY_CHANNEL__CH3 0x08
+#define BP_DCP_CHANNELCTRL_ENABLE_CHANNEL 0
+#define BM_DCP_CHANNELCTRL_ENABLE_CHANNEL 0x000000FF
+#define BF_DCP_CHANNELCTRL_ENABLE_CHANNEL(v) \
+ (((v) << 0) & BM_DCP_CHANNELCTRL_ENABLE_CHANNEL)
+#define BV_DCP_CHANNELCTRL_ENABLE_CHANNEL__CH0 0x01
+#define BV_DCP_CHANNELCTRL_ENABLE_CHANNEL__CH1 0x02
+#define BV_DCP_CHANNELCTRL_ENABLE_CHANNEL__CH2 0x04
+#define BV_DCP_CHANNELCTRL_ENABLE_CHANNEL__CH3 0x08
+
+#define HW_DCP_CAPABILITY0 (0x00000030)
+
+#define BM_DCP_CAPABILITY0_DISABLE_DECRYPT 0x80000000
+#define BM_DCP_CAPABILITY0_ENABLE_TZONE 0x40000000
+#define BP_DCP_CAPABILITY0_RSVD 12
+#define BM_DCP_CAPABILITY0_RSVD 0x3FFFF000
+#define BF_DCP_CAPABILITY0_RSVD(v) \
+ (((v) << 12) & BM_DCP_CAPABILITY0_RSVD)
+#define BP_DCP_CAPABILITY0_NUM_CHANNELS 8
+#define BM_DCP_CAPABILITY0_NUM_CHANNELS 0x00000F00
+#define BF_DCP_CAPABILITY0_NUM_CHANNELS(v) \
+ (((v) << 8) & BM_DCP_CAPABILITY0_NUM_CHANNELS)
+#define BP_DCP_CAPABILITY0_NUM_KEYS 0
+#define BM_DCP_CAPABILITY0_NUM_KEYS 0x000000FF
+#define BF_DCP_CAPABILITY0_NUM_KEYS(v) \
+ (((v) << 0) & BM_DCP_CAPABILITY0_NUM_KEYS)
+
+#define HW_DCP_CAPABILITY1 (0x00000040)
+
+#define BP_DCP_CAPABILITY1_HASH_ALGORITHMS 16
+#define BM_DCP_CAPABILITY1_HASH_ALGORITHMS 0xFFFF0000
+#define BF_DCP_CAPABILITY1_HASH_ALGORITHMS(v) \
+ (((v) << 16) & BM_DCP_CAPABILITY1_HASH_ALGORITHMS)
+#define BV_DCP_CAPABILITY1_HASH_ALGORITHMS__SHA1 0x0001
+#define BV_DCP_CAPABILITY1_HASH_ALGORITHMS__CRC32 0x0002
+#define BV_DCP_CAPABILITY1_HASH_ALGORITHMS__SHA256 0x0004
+#define BP_DCP_CAPABILITY1_CIPHER_ALGORITHMS 0
+#define BM_DCP_CAPABILITY1_CIPHER_ALGORITHMS 0x0000FFFF
+#define BF_DCP_CAPABILITY1_CIPHER_ALGORITHMS(v) \
+ (((v) << 0) & BM_DCP_CAPABILITY1_CIPHER_ALGORITHMS)
+#define BV_DCP_CAPABILITY1_CIPHER_ALGORITHMS__AES128 0x0001
+
+#define HW_DCP_CONTEXT (0x00000050)
+
+#define BP_DCP_CONTEXT_ADDR 0
+#define BM_DCP_CONTEXT_ADDR 0xFFFFFFFF
+#define BF_DCP_CONTEXT_ADDR(v) (v)
+
+#define HW_DCP_KEY (0x00000060)
+
+#define BP_DCP_KEY_RSVD 8
+#define BM_DCP_KEY_RSVD 0xFFFFFF00
+#define BF_DCP_KEY_RSVD(v) \
+ (((v) << 8) & BM_DCP_KEY_RSVD)
+#define BP_DCP_KEY_RSVD_INDEX 6
+#define BM_DCP_KEY_RSVD_INDEX 0x000000C0
+#define BF_DCP_KEY_RSVD_INDEX(v) \
+ (((v) << 6) & BM_DCP_KEY_RSVD_INDEX)
+#define BP_DCP_KEY_INDEX 4
+#define BM_DCP_KEY_INDEX 0x00000030
+#define BF_DCP_KEY_INDEX(v) \
+ (((v) << 4) & BM_DCP_KEY_INDEX)
+#define BP_DCP_KEY_RSVD_SUBWORD 2
+#define BM_DCP_KEY_RSVD_SUBWORD 0x0000000C
+#define BF_DCP_KEY_RSVD_SUBWORD(v) \
+ (((v) << 2) & BM_DCP_KEY_RSVD_SUBWORD)
+#define BP_DCP_KEY_SUBWORD 0
+#define BM_DCP_KEY_SUBWORD 0x00000003
+#define BF_DCP_KEY_SUBWORD(v) \
+ (((v) << 0) & BM_DCP_KEY_SUBWORD)
+
+#define HW_DCP_KEYDATA (0x00000070)
+
+#define BP_DCP_KEYDATA_DATA 0
+#define BM_DCP_KEYDATA_DATA 0xFFFFFFFF
+#define BF_DCP_KEYDATA_DATA(v) (v)
+
+#define HW_DCP_PACKET0 (0x00000080)
+
+#define BP_DCP_PACKET0_ADDR 0
+#define BM_DCP_PACKET0_ADDR 0xFFFFFFFF
+#define BF_DCP_PACKET0_ADDR(v) (v)
+
+#define HW_DCP_PACKET1 (0x00000090)
+
+#define BP_DCP_PACKET1_TAG 24
+#define BM_DCP_PACKET1_TAG 0xFF000000
+#define BF_DCP_PACKET1_TAG(v) \
+ (((v) << 24) & BM_DCP_PACKET1_TAG)
+#define BM_DCP_PACKET1_OUTPUT_WORDSWAP 0x00800000
+#define BM_DCP_PACKET1_OUTPUT_BYTESWAP 0x00400000
+#define BM_DCP_PACKET1_INPUT_WORDSWAP 0x00200000
+#define BM_DCP_PACKET1_INPUT_BYTESWAP 0x00100000
+#define BM_DCP_PACKET1_KEY_WORDSWAP 0x00080000
+#define BM_DCP_PACKET1_KEY_BYTESWAP 0x00040000
+#define BM_DCP_PACKET1_TEST_SEMA_IRQ 0x00020000
+#define BM_DCP_PACKET1_CONSTANT_FILL 0x00010000
+#define BM_DCP_PACKET1_HASH_OUTPUT 0x00008000
+#define BV_DCP_PACKET1_HASH_OUTPUT__INPUT 0x00
+#define BV_DCP_PACKET1_HASH_OUTPUT__OUTPUT 0x01
+#define BM_DCP_PACKET1_CHECK_HASH 0x00004000
+#define BM_DCP_PACKET1_HASH_TERM 0x00002000
+#define BM_DCP_PACKET1_HASH_INIT 0x00001000
+#define BM_DCP_PACKET1_PAYLOAD_KEY 0x00000800
+#define BM_DCP_PACKET1_OTP_KEY 0x00000400
+#define BM_DCP_PACKET1_CIPHER_INIT 0x00000200
+#define BM_DCP_PACKET1_CIPHER_ENCRYPT 0x00000100
+#define BV_DCP_PACKET1_CIPHER_ENCRYPT__ENCRYPT 0x01
+#define BV_DCP_PACKET1_CIPHER_ENCRYPT__DECRYPT 0x00
+#define BM_DCP_PACKET1_ENABLE_BLIT 0x00000080
+#define BM_DCP_PACKET1_ENABLE_HASH 0x00000040
+#define BM_DCP_PACKET1_ENABLE_CIPHER 0x00000020
+#define BM_DCP_PACKET1_ENABLE_MEMCOPY 0x00000010
+#define BM_DCP_PACKET1_CHAIN_CONTIGUOUS 0x00000008
+#define BM_DCP_PACKET1_CHAIN 0x00000004
+#define BM_DCP_PACKET1_DECR_SEMAPHORE 0x00000002
+#define BM_DCP_PACKET1_INTERRUPT 0x00000001
+
+#define HW_DCP_PACKET2 (0x000000a0)
+
+#define BP_DCP_PACKET2_CIPHER_CFG 24
+#define BM_DCP_PACKET2_CIPHER_CFG 0xFF000000
+#define BF_DCP_PACKET2_CIPHER_CFG(v) \
+ (((v) << 24) & BM_DCP_PACKET2_CIPHER_CFG)
+#define BP_DCP_PACKET2_RSVD 20
+#define BM_DCP_PACKET2_RSVD 0x00F00000
+#define BF_DCP_PACKET2_RSVD(v) \
+ (((v) << 20) & BM_DCP_PACKET2_RSVD)
+#define BP_DCP_PACKET2_HASH_SELECT 16
+#define BM_DCP_PACKET2_HASH_SELECT 0x000F0000
+#define BF_DCP_PACKET2_HASH_SELECT(v) \
+ (((v) << 16) & BM_DCP_PACKET2_HASH_SELECT)
+#define BV_DCP_PACKET2_HASH_SELECT__SHA1 0x00
+#define BV_DCP_PACKET2_HASH_SELECT__CRC32 0x01
+#define BV_DCP_PACKET2_HASH_SELECT__SHA256 0x02
+#define BP_DCP_PACKET2_KEY_SELECT 8
+#define BM_DCP_PACKET2_KEY_SELECT 0x0000FF00
+#define BF_DCP_PACKET2_KEY_SELECT(v) \
+ (((v) << 8) & BM_DCP_PACKET2_KEY_SELECT)
+#define BP_DCP_PACKET2_CIPHER_MODE 4
+#define BM_DCP_PACKET2_CIPHER_MODE 0x000000F0
+#define BF_DCP_PACKET2_CIPHER_MODE(v) \
+ (((v) << 4) & BM_DCP_PACKET2_CIPHER_MODE)
+#define BV_DCP_PACKET2_CIPHER_MODE__ECB 0x00
+#define BV_DCP_PACKET2_CIPHER_MODE__CBC 0x01
+#define BP_DCP_PACKET2_CIPHER_SELECT 0
+#define BM_DCP_PACKET2_CIPHER_SELECT 0x0000000F
+#define BF_DCP_PACKET2_CIPHER_SELECT(v) \
+ (((v) << 0) & BM_DCP_PACKET2_CIPHER_SELECT)
+#define BV_DCP_PACKET2_CIPHER_SELECT__AES128 0x00
+
+#define HW_DCP_PACKET3 (0x000000b0)
+
+#define BP_DCP_PACKET3_ADDR 0
+#define BM_DCP_PACKET3_ADDR 0xFFFFFFFF
+#define BF_DCP_PACKET3_ADDR(v) (v)
+
+#define HW_DCP_PACKET4 (0x000000c0)
+
+#define BP_DCP_PACKET4_ADDR 0
+#define BM_DCP_PACKET4_ADDR 0xFFFFFFFF
+#define BF_DCP_PACKET4_ADDR(v) (v)
+
+#define HW_DCP_PACKET5 (0x000000d0)
+
+#define BP_DCP_PACKET5_COUNT 0
+#define BM_DCP_PACKET5_COUNT 0xFFFFFFFF
+#define BF_DCP_PACKET5_COUNT(v) (v)
+
+#define HW_DCP_PACKET6 (0x000000e0)
+
+#define BP_DCP_PACKET6_ADDR 0
+#define BM_DCP_PACKET6_ADDR 0xFFFFFFFF
+#define BF_DCP_PACKET6_ADDR(v) (v)
+
+/*
+ * multi-register-define name HW_DCP_CH_N_CMDPTR
+ * base 0x00000100
+ * count 4
+ * offset 0x40
+ */
+#define HW_DCP_CH_N_CMDPTR(n) (0x00000100 + (n) * 0x40)
+
+#define BP_DCP_CH_N_CMDPTR_ADDR 0
+#define BM_DCP_CH_N_CMDPTR_ADDR 0xFFFFFFFF
+#define BF_DCP_CH_N_CMDPTR_ADDR(v) (v)
+
+/*
+ * multi-register-define name HW_DCP_CH_N_SEMA
+ * base 0x00000110
+ * count 4
+ * offset 0x40
+ */
+#define HW_DCP_CH_N_SEMA(n) (0x00000110 + (n) * 0x40)
+
+#define BP_DCP_CH_N_SEMA_RSVD2 24
+#define BM_DCP_CH_N_SEMA_RSVD2 0xFF000000
+#define BF_DCP_CH_N_SEMA_RSVD2(v) \
+ (((v) << 24) & BM_DCP_CH_N_SEMA_RSVD2)
+#define BP_DCP_CH_N_SEMA_VALUE 16
+#define BM_DCP_CH_N_SEMA_VALUE 0x00FF0000
+#define BF_DCP_CH_N_SEMA_VALUE(v) \
+ (((v) << 16) & BM_DCP_CH_N_SEMA_VALUE)
+#define BP_DCP_CH_N_SEMA_RSVD1 8
+#define BM_DCP_CH_N_SEMA_RSVD1 0x0000FF00
+#define BF_DCP_CH_N_SEMA_RSVD1(v) \
+ (((v) << 8) & BM_DCP_CH_N_SEMA_RSVD1)
+#define BP_DCP_CH_N_SEMA_INCREMENT 0
+#define BM_DCP_CH_N_SEMA_INCREMENT 0x000000FF
+#define BF_DCP_CH_N_SEMA_INCREMENT(v) \
+ (((v) << 0) & BM_DCP_CH_N_SEMA_INCREMENT)
+
+/*
+ * multi-register-define name HW_DCP_CH_N_STAT
+ * base 0x00000120
+ * count 4
+ * offset 0x40
+ */
+#define HW_DCP_CH_N_STAT(n) (0x00000120 + (n) * 0x40)
+#define HW_DCP_CH_N_STAT_SET(n) (0x00000124 + (n) * 0x40)
+#define HW_DCP_CH_N_STAT_CLR(n) (0x00000128 + (n) * 0x40)
+#define HW_DCP_CH_N_STAT_TOG(n) (0x0000012c + (n) * 0x40)
+
+#define BP_DCP_CH_N_STAT_TAG 24
+#define BM_DCP_CH_N_STAT_TAG 0xFF000000
+#define BF_DCP_CH_N_STAT_TAG(v) \
+ (((v) << 24) & BM_DCP_CH_N_STAT_TAG)
+#define BP_DCP_CH_N_STAT_ERROR_CODE 16
+#define BM_DCP_CH_N_STAT_ERROR_CODE 0x00FF0000
+#define BF_DCP_CH_N_STAT_ERROR_CODE(v) \
+ (((v) << 16) & BM_DCP_CH_N_STAT_ERROR_CODE)
+#define BV_DCP_CH_N_STAT_ERROR_CODE__NEXT_CHAIN_IS_0 0x01
+#define BV_DCP_CH_N_STAT_ERROR_CODE__NO_CHAIN 0x02
+#define BV_DCP_CH_N_STAT_ERROR_CODE__CONTEXT_ERROR 0x03
+#define BV_DCP_CH_N_STAT_ERROR_CODE__PAYLOAD_ERROR 0x04
+#define BV_DCP_CH_N_STAT_ERROR_CODE__INVALID_MODE 0x05
+#define BP_DCP_CH_N_STAT_RSVD0 7
+#define BM_DCP_CH_N_STAT_RSVD0 0x0000FF80
+#define BF_DCP_CH_N_STAT_RSVD0(v) \
+ (((v) << 7) & BM_DCP_CH_N_STAT_RSVD0)
+#define BM_DCP_CH_N_STAT_ERROR_PAGEFAULT 0x00000040
+#define BM_DCP_CH_N_STAT_ERROR_DST 0x00000020
+#define BM_DCP_CH_N_STAT_ERROR_SRC 0x00000010
+#define BM_DCP_CH_N_STAT_ERROR_PACKET 0x00000008
+#define BM_DCP_CH_N_STAT_ERROR_SETUP 0x00000004
+#define BM_DCP_CH_N_STAT_HASH_MISMATCH 0x00000002
+#define BM_DCP_CH_N_STAT_RSVD_COMPLETE 0x00000001
+
+/*
+ * multi-register-define name HW_DCP_CH_N_OPTS
+ * base 0x00000130
+ * count 4
+ * offset 0x40
+ */
+#define HW_DCP_CH_N_OPTS(n) (0x00000130 + (n) * 0x40)
+#define HW_DCP_CH_N_OPTS_SET(n) (0x00000134 + (n) * 0x40)
+#define HW_DCP_CH_N_OPTS_CLR(n) (0x00000138 + (n) * 0x40)
+#define HW_DCP_CH_N_OPTS_TOG(n) (0x0000013c + (n) * 0x40)
+
+#define BP_DCP_CH_N_OPTS_RSVD 16
+#define BM_DCP_CH_N_OPTS_RSVD 0xFFFF0000
+#define BF_DCP_CH_N_OPTS_RSVD(v) \
+ (((v) << 16) & BM_DCP_CH_N_OPTS_RSVD)
+#define BP_DCP_CH_N_OPTS_RECOVERY_TIMER 0
+#define BM_DCP_CH_N_OPTS_RECOVERY_TIMER 0x0000FFFF
+#define BF_DCP_CH_N_OPTS_RECOVERY_TIMER(v) \
+ (((v) << 0) & BM_DCP_CH_N_OPTS_RECOVERY_TIMER)
+
+#define HW_DCP_CSCCTRL0 (0x00000300)
+#define HW_DCP_CSCCTRL0_SET (0x00000304)
+#define HW_DCP_CSCCTRL0_CLR (0x00000308)
+#define HW_DCP_CSCCTRL0_TOG (0x0000030c)
+
+#define BP_DCP_CSCCTRL0_RSVD1 16
+#define BM_DCP_CSCCTRL0_RSVD1 0xFFFF0000
+#define BF_DCP_CSCCTRL0_RSVD1(v) \
+ (((v) << 16) & BM_DCP_CSCCTRL0_RSVD1)
+#define BM_DCP_CSCCTRL0_CLIP 0x00008000
+#define BM_DCP_CSCCTRL0_UPSAMPLE 0x00004000
+#define BM_DCP_CSCCTRL0_SCALE 0x00002000
+#define BM_DCP_CSCCTRL0_ROTATE 0x00001000
+#define BM_DCP_CSCCTRL0_SUBSAMPLE 0x00000800
+#define BM_DCP_CSCCTRL0_DELTA 0x00000400
+#define BP_DCP_CSCCTRL0_RGB_FORMAT 8
+#define BM_DCP_CSCCTRL0_RGB_FORMAT 0x00000300
+#define BF_DCP_CSCCTRL0_RGB_FORMAT(v) \
+ (((v) << 8) & BM_DCP_CSCCTRL0_RGB_FORMAT)
+#define BV_DCP_CSCCTRL0_RGB_FORMAT__RGB16_565 0x0
+#define BV_DCP_CSCCTRL0_RGB_FORMAT__YCbCrI 0x1
+#define BV_DCP_CSCCTRL0_RGB_FORMAT__RGB24 0x2
+#define BV_DCP_CSCCTRL0_RGB_FORMAT__YUV422I 0x3
+#define BP_DCP_CSCCTRL0_YUV_FORMAT 4
+#define BM_DCP_CSCCTRL0_YUV_FORMAT 0x000000F0
+#define BF_DCP_CSCCTRL0_YUV_FORMAT(v) \
+ (((v) << 4) & BM_DCP_CSCCTRL0_YUV_FORMAT)
+#define BV_DCP_CSCCTRL0_YUV_FORMAT__YUV420 0x0
+#define BV_DCP_CSCCTRL0_YUV_FORMAT__YUV422 0x2
+#define BP_DCP_CSCCTRL0_RSVD0 1
+#define BM_DCP_CSCCTRL0_RSVD0 0x0000000E
+#define BF_DCP_CSCCTRL0_RSVD0(v) \
+ (((v) << 1) & BM_DCP_CSCCTRL0_RSVD0)
+#define BM_DCP_CSCCTRL0_ENABLE 0x00000001
+
+#define HW_DCP_CSCSTAT (0x00000310)
+#define HW_DCP_CSCSTAT_SET (0x00000314)
+#define HW_DCP_CSCSTAT_CLR (0x00000318)
+#define HW_DCP_CSCSTAT_TOG (0x0000031c)
+
+#define BP_DCP_CSCSTAT_RSVD3 24
+#define BM_DCP_CSCSTAT_RSVD3 0xFF000000
+#define BF_DCP_CSCSTAT_RSVD3(v) \
+ (((v) << 24) & BM_DCP_CSCSTAT_RSVD3)
+#define BP_DCP_CSCSTAT_ERROR_CODE 16
+#define BM_DCP_CSCSTAT_ERROR_CODE 0x00FF0000
+#define BF_DCP_CSCSTAT_ERROR_CODE(v) \
+ (((v) << 16) & BM_DCP_CSCSTAT_ERROR_CODE)
+#define BV_DCP_CSCSTAT_ERROR_CODE__LUMA0_FETCH_ERROR_Y0 0x01
+#define BV_DCP_CSCSTAT_ERROR_CODE__LUMA1_FETCH_ERROR_Y1 0x02
+#define BV_DCP_CSCSTAT_ERROR_CODE__CHROMA_FETCH_ERROR_U 0x03
+#define BV_DCP_CSCSTAT_ERROR_CODE__CHROMA_FETCH_ERROR_V 0x04
+#define BP_DCP_CSCSTAT_RSVD2 7
+#define BM_DCP_CSCSTAT_RSVD2 0x0000FF80
+#define BF_DCP_CSCSTAT_RSVD2(v) \
+ (((v) << 7) & BM_DCP_CSCSTAT_RSVD2)
+#define BM_DCP_CSCSTAT_ERROR_PAGEFAULT 0x00000040
+#define BM_DCP_CSCSTAT_ERROR_DST 0x00000020
+#define BM_DCP_CSCSTAT_ERROR_SRC 0x00000010
+#define BM_DCP_CSCSTAT_RSVD1 0x00000008
+#define BM_DCP_CSCSTAT_ERROR_SETUP 0x00000004
+#define BM_DCP_CSCSTAT_RSVD0 0x00000002
+#define BM_DCP_CSCSTAT_COMPLETE 0x00000001
+
+#define HW_DCP_CSCOUTBUFPARAM (0x00000320)
+
+#define BP_DCP_CSCOUTBUFPARAM_RSVD1 24
+#define BM_DCP_CSCOUTBUFPARAM_RSVD1 0xFF000000
+#define BF_DCP_CSCOUTBUFPARAM_RSVD1(v) \
+ (((v) << 24) & BM_DCP_CSCOUTBUFPARAM_RSVD1)
+#define BP_DCP_CSCOUTBUFPARAM_FIELD_SIZE 12
+#define BM_DCP_CSCOUTBUFPARAM_FIELD_SIZE 0x00FFF000
+#define BF_DCP_CSCOUTBUFPARAM_FIELD_SIZE(v) \
+ (((v) << 12) & BM_DCP_CSCOUTBUFPARAM_FIELD_SIZE)
+#define BP_DCP_CSCOUTBUFPARAM_LINE_SIZE 0
+#define BM_DCP_CSCOUTBUFPARAM_LINE_SIZE 0x00000FFF
+#define BF_DCP_CSCOUTBUFPARAM_LINE_SIZE(v) \
+ (((v) << 0) & BM_DCP_CSCOUTBUFPARAM_LINE_SIZE)
+
+#define HW_DCP_CSCINBUFPARAM (0x00000330)
+
+#define BP_DCP_CSCINBUFPARAM_RSVD1 12
+#define BM_DCP_CSCINBUFPARAM_RSVD1 0xFFFFF000
+#define BF_DCP_CSCINBUFPARAM_RSVD1(v) \
+ (((v) << 12) & BM_DCP_CSCINBUFPARAM_RSVD1)
+#define BP_DCP_CSCINBUFPARAM_LINE_SIZE 0
+#define BM_DCP_CSCINBUFPARAM_LINE_SIZE 0x00000FFF
+#define BF_DCP_CSCINBUFPARAM_LINE_SIZE(v) \
+ (((v) << 0) & BM_DCP_CSCINBUFPARAM_LINE_SIZE)
+
+#define HW_DCP_CSCRGB (0x00000340)
+
+#define BP_DCP_CSCRGB_ADDR 0
+#define BM_DCP_CSCRGB_ADDR 0xFFFFFFFF
+#define BF_DCP_CSCRGB_ADDR(v) (v)
+
+#define HW_DCP_CSCLUMA (0x00000350)
+
+#define BP_DCP_CSCLUMA_ADDR 0
+#define BM_DCP_CSCLUMA_ADDR 0xFFFFFFFF
+#define BF_DCP_CSCLUMA_ADDR(v) (v)
+
+#define HW_DCP_CSCCHROMAU (0x00000360)
+
+#define BP_DCP_CSCCHROMAU_ADDR 0
+#define BM_DCP_CSCCHROMAU_ADDR 0xFFFFFFFF
+#define BF_DCP_CSCCHROMAU_ADDR(v) (v)
+
+#define HW_DCP_CSCCHROMAV (0x00000370)
+
+#define BP_DCP_CSCCHROMAV_ADDR 0
+#define BM_DCP_CSCCHROMAV_ADDR 0xFFFFFFFF
+#define BF_DCP_CSCCHROMAV_ADDR(v) (v)
+
+#define HW_DCP_CSCCOEFF0 (0x00000380)
+
+#define BP_DCP_CSCCOEFF0_RSVD1 26
+#define BM_DCP_CSCCOEFF0_RSVD1 0xFC000000
+#define BF_DCP_CSCCOEFF0_RSVD1(v) \
+ (((v) << 26) & BM_DCP_CSCCOEFF0_RSVD1)
+#define BP_DCP_CSCCOEFF0_C0 16
+#define BM_DCP_CSCCOEFF0_C0 0x03FF0000
+#define BF_DCP_CSCCOEFF0_C0(v) \
+ (((v) << 16) & BM_DCP_CSCCOEFF0_C0)
+#define BP_DCP_CSCCOEFF0_UV_OFFSET 8
+#define BM_DCP_CSCCOEFF0_UV_OFFSET 0x0000FF00
+#define BF_DCP_CSCCOEFF0_UV_OFFSET(v) \
+ (((v) << 8) & BM_DCP_CSCCOEFF0_UV_OFFSET)
+#define BP_DCP_CSCCOEFF0_Y_OFFSET 0
+#define BM_DCP_CSCCOEFF0_Y_OFFSET 0x000000FF
+#define BF_DCP_CSCCOEFF0_Y_OFFSET(v) \
+ (((v) << 0) & BM_DCP_CSCCOEFF0_Y_OFFSET)
+
+#define HW_DCP_CSCCOEFF1 (0x00000390)
+
+#define BP_DCP_CSCCOEFF1_RSVD1 26
+#define BM_DCP_CSCCOEFF1_RSVD1 0xFC000000
+#define BF_DCP_CSCCOEFF1_RSVD1(v) \
+ (((v) << 26) & BM_DCP_CSCCOEFF1_RSVD1)
+#define BP_DCP_CSCCOEFF1_C1 16
+#define BM_DCP_CSCCOEFF1_C1 0x03FF0000
+#define BF_DCP_CSCCOEFF1_C1(v) \
+ (((v) << 16) & BM_DCP_CSCCOEFF1_C1)
+#define BP_DCP_CSCCOEFF1_RSVD0 10
+#define BM_DCP_CSCCOEFF1_RSVD0 0x0000FC00
+#define BF_DCP_CSCCOEFF1_RSVD0(v) \
+ (((v) << 10) & BM_DCP_CSCCOEFF1_RSVD0)
+#define BP_DCP_CSCCOEFF1_C4 0
+#define BM_DCP_CSCCOEFF1_C4 0x000003FF
+#define BF_DCP_CSCCOEFF1_C4(v) \
+ (((v) << 0) & BM_DCP_CSCCOEFF1_C4)
+
+#define HW_DCP_CSCCOEFF2 (0x000003a0)
+
+#define BP_DCP_CSCCOEFF2_RSVD1 26
+#define BM_DCP_CSCCOEFF2_RSVD1 0xFC000000
+#define BF_DCP_CSCCOEFF2_RSVD1(v) \
+ (((v) << 26) & BM_DCP_CSCCOEFF2_RSVD1)
+#define BP_DCP_CSCCOEFF2_C2 16
+#define BM_DCP_CSCCOEFF2_C2 0x03FF0000
+#define BF_DCP_CSCCOEFF2_C2(v) \
+ (((v) << 16) & BM_DCP_CSCCOEFF2_C2)
+#define BP_DCP_CSCCOEFF2_RSVD0 10
+#define BM_DCP_CSCCOEFF2_RSVD0 0x0000FC00
+#define BF_DCP_CSCCOEFF2_RSVD0(v) \
+ (((v) << 10) & BM_DCP_CSCCOEFF2_RSVD0)
+#define BP_DCP_CSCCOEFF2_C3 0
+#define BM_DCP_CSCCOEFF2_C3 0x000003FF
+#define BF_DCP_CSCCOEFF2_C3(v) \
+ (((v) << 0) & BM_DCP_CSCCOEFF2_C3)
+
+#define HW_DCP_CSCCLIP (0x000003d0)
+
+#define BP_DCP_CSCCLIP_RSVD1 24
+#define BM_DCP_CSCCLIP_RSVD1 0xFF000000
+#define BF_DCP_CSCCLIP_RSVD1(v) \
+ (((v) << 24) & BM_DCP_CSCCLIP_RSVD1)
+#define BP_DCP_CSCCLIP_HEIGHT 12
+#define BM_DCP_CSCCLIP_HEIGHT 0x00FFF000
+#define BF_DCP_CSCCLIP_HEIGHT(v) \
+ (((v) << 12) & BM_DCP_CSCCLIP_HEIGHT)
+#define BP_DCP_CSCCLIP_WIDTH 0
+#define BM_DCP_CSCCLIP_WIDTH 0x00000FFF
+#define BF_DCP_CSCCLIP_WIDTH(v) \
+ (((v) << 0) & BM_DCP_CSCCLIP_WIDTH)
+
+#define HW_DCP_CSCXSCALE (0x000003e0)
+
+#define BP_DCP_CSCXSCALE_RSVD1 26
+#define BM_DCP_CSCXSCALE_RSVD1 0xFC000000
+#define BF_DCP_CSCXSCALE_RSVD1(v) \
+ (((v) << 26) & BM_DCP_CSCXSCALE_RSVD1)
+#define BP_DCP_CSCXSCALE_INT 24
+#define BM_DCP_CSCXSCALE_INT 0x03000000
+#define BF_DCP_CSCXSCALE_INT(v) \
+ (((v) << 24) & BM_DCP_CSCXSCALE_INT)
+#define BP_DCP_CSCXSCALE_FRAC 12
+#define BM_DCP_CSCXSCALE_FRAC 0x00FFF000
+#define BF_DCP_CSCXSCALE_FRAC(v) \
+ (((v) << 12) & BM_DCP_CSCXSCALE_FRAC)
+#define BP_DCP_CSCXSCALE_WIDTH 0
+#define BM_DCP_CSCXSCALE_WIDTH 0x00000FFF
+#define BF_DCP_CSCXSCALE_WIDTH(v) \
+ (((v) << 0) & BM_DCP_CSCXSCALE_WIDTH)
+
+#define HW_DCP_CSCYSCALE (0x000003f0)
+
+#define BP_DCP_CSCYSCALE_RSVD1 26
+#define BM_DCP_CSCYSCALE_RSVD1 0xFC000000
+#define BF_DCP_CSCYSCALE_RSVD1(v) \
+ (((v) << 26) & BM_DCP_CSCYSCALE_RSVD1)
+#define BP_DCP_CSCYSCALE_INT 24
+#define BM_DCP_CSCYSCALE_INT 0x03000000
+#define BF_DCP_CSCYSCALE_INT(v) \
+ (((v) << 24) & BM_DCP_CSCYSCALE_INT)
+#define BP_DCP_CSCYSCALE_FRAC 12
+#define BM_DCP_CSCYSCALE_FRAC 0x00FFF000
+#define BF_DCP_CSCYSCALE_FRAC(v) \
+ (((v) << 12) & BM_DCP_CSCYSCALE_FRAC)
+#define BP_DCP_CSCYSCALE_HEIGHT 0
+#define BM_DCP_CSCYSCALE_HEIGHT 0x00000FFF
+#define BF_DCP_CSCYSCALE_HEIGHT(v) \
+ (((v) << 0) & BM_DCP_CSCYSCALE_HEIGHT)
+
+#define HW_DCP_DBGSELECT (0x00000400)
+
+#define BP_DCP_DBGSELECT_RSVD 8
+#define BM_DCP_DBGSELECT_RSVD 0xFFFFFF00
+#define BF_DCP_DBGSELECT_RSVD(v) \
+ (((v) << 8) & BM_DCP_DBGSELECT_RSVD)
+#define BP_DCP_DBGSELECT_INDEX 0
+#define BM_DCP_DBGSELECT_INDEX 0x000000FF
+#define BF_DCP_DBGSELECT_INDEX(v) \
+ (((v) << 0) & BM_DCP_DBGSELECT_INDEX)
+#define BV_DCP_DBGSELECT_INDEX__CONTROL 0x01
+#define BV_DCP_DBGSELECT_INDEX__OTPKEY0 0x10
+#define BV_DCP_DBGSELECT_INDEX__OTPKEY1 0x11
+#define BV_DCP_DBGSELECT_INDEX__OTPKEY2 0x12
+#define BV_DCP_DBGSELECT_INDEX__OTPKEY3 0x13
+
+#define HW_DCP_DBGDATA (0x00000410)
+
+#define BP_DCP_DBGDATA_DATA 0
+#define BM_DCP_DBGDATA_DATA 0xFFFFFFFF
+#define BF_DCP_DBGDATA_DATA(v) (v)
+
+#define HW_DCP_PAGETABLE (0x00000420)
+
+#define BP_DCP_PAGETABLE_BASE 2
+#define BM_DCP_PAGETABLE_BASE 0xFFFFFFFC
+#define BF_DCP_PAGETABLE_BASE(v) \
+ (((v) << 2) & BM_DCP_PAGETABLE_BASE)
+#define BM_DCP_PAGETABLE_FLUSH 0x00000002
+#define BM_DCP_PAGETABLE_ENABLE 0x00000001
+
+#define HW_DCP_VERSION (0x00000430)
+
+#define BP_DCP_VERSION_MAJOR 24
+#define BM_DCP_VERSION_MAJOR 0xFF000000
+#define BF_DCP_VERSION_MAJOR(v) \
+ (((v) << 24) & BM_DCP_VERSION_MAJOR)
+#define BP_DCP_VERSION_MINOR 16
+#define BM_DCP_VERSION_MINOR 0x00FF0000
+#define BF_DCP_VERSION_MINOR(v) \
+ (((v) << 16) & BM_DCP_VERSION_MINOR)
+#define BP_DCP_VERSION_STEP 0
+#define BM_DCP_VERSION_STEP 0x0000FFFF
+#define BF_DCP_VERSION_STEP(v) \
+ (((v) << 0) & BM_DCP_VERSION_STEP)
+
+#endif
diff --git a/include/linux/fsl/fsl-dcp_bootstream_ioctl.h b/include/linux/fsl/fsl-dcp_bootstream_ioctl.h
new file mode 100644
index 0000000..2859a8d
--- /dev/null
+++ b/include/linux/fsl/fsl-dcp_bootstream_ioctl.h
@@ -0,0 +1,32 @@
+/*
+ * Freescale DCP driver for bootstream update. Only handles the OTP KEY
+ * case and can only encrypt/decrypt.
+ *
+ * Author: Pantelis Antoniou <pantelis at embeddedalley.com>
+ *
+ * Copyright (C) 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef DCP_BOOTSTREAM_IOCTL_H
+#define DCP_BOOTSTREAM_IOCTL_H
+
+/* remember to have included the proper _IO definition
+ * file before hand.
+ * For user space it's <sys/ioctl.h>
+ */
+
+#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])
+
+#endif
--
1.7.9.5
More information about the linux-arm-kernel
mailing list