From c925421b8c35357427499f3d298777535c2c6cfd Mon Sep 17 00:00:00 2001
From: Alison Wang <b18965@freescale.com>
Date: Thu, 4 Aug 2011 09:59:45 +0800
Subject: [PATCH 24/52] Add SEC 1.1 support for MCF547x and MCF548x

Add SEC 1.1 support for MCF547x and MCF548x. The SEC driver is
in drivers/crypto.

Signed-off-by: Alison Wang <b18965@freescale.com>
---
 arch/m68k/coldfire/m547x/mcf548x-devices.c |    2 +-
 arch/m68k/include/asm/cf_io.h              |    4 +
 crypto/testmgr.c                           |   18 +-
 drivers/crypto/Kconfig                     |   13 +
 drivers/crypto/Makefile                    |    1 +
 drivers/crypto/cf_talitos.c                | 1727 ++++++++++++++++++++++++++++
 drivers/crypto/cf_talitos.h                |  229 ++++
 7 files changed, 1989 insertions(+), 5 deletions(-)
 create mode 100644 drivers/crypto/cf_talitos.c
 create mode 100644 drivers/crypto/cf_talitos.h

--- a/arch/m68k/coldfire/m547x/mcf548x-devices.c
+++ b/arch/m68k/coldfire/m547x/mcf548x-devices.c
@@ -54,7 +54,7 @@ static struct resource coldfire_sec_reso
 };
 
 static struct platform_device coldfire_sec_device = {
-	.name                   = "fsl-sec1",
+	.name                   = "talitos",
 	.id                     = -1,
 	.num_resources          = ARRAY_SIZE(coldfire_sec_resources),
 	.resource               = coldfire_sec_resources,
--- a/arch/m68k/include/asm/cf_io.h
+++ b/arch/m68k/include/asm/cf_io.h
@@ -192,4 +192,8 @@ static inline void memcpy_toio(volatile
 #define writel(b, addr) (void)((*(volatile unsigned int *) (addr)) = (b))
 #endif /* readb */
 
+/* access ports */
+#define setbits32(_addr, _v) out_be32((_addr), in_be32(_addr) |  (_v))
+#define clrbits32(_addr, _v) out_be32((_addr), in_be32(_addr) & ~(_v))
+
 #endif /* _IO_H */
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -212,7 +212,11 @@ static int test_hash(struct crypto_ahash
 				   tcrypt_complete, &tresult);
 
 	j = 0;
+#if defined(CONFIG_CRYPTO_DEV_CF_TALITOS)
+	for (i = 1; i < tcount; i++) {
+#else
 	for (i = 0; i < tcount; i++) {
+#endif
 		if (template[i].np)
 			continue;
 
@@ -276,7 +280,9 @@ static int test_hash(struct crypto_ahash
 			hexdump(result, crypto_ahash_digestsize(tfm));
 			ret = -EINVAL;
 			goto out;
-		}
+		} else
+			printk(KERN_INFO "alg: hash: Test %d succeed for %s\n",
+				j, algo);
 	}
 
 	j = 0;
@@ -344,7 +350,9 @@ static int test_hash(struct crypto_ahash
 				hexdump(result, crypto_ahash_digestsize(tfm));
 				ret = -EINVAL;
 				goto out;
-			}
+			} else
+				printk(KERN_INFO "alg: hash: Chunking test %d "
+				       "succeed for %s\n", j, algo);
 		}
 	}
 
@@ -788,7 +796,6 @@ static int test_skcipher(struct crypto_a
 	else
 		e = "decryption";
 
-	printk(KERN_INFO "%s testing %s %s\n", __func__, algo, e);
 	init_completion(&result.completion);
 
 	req = ablkcipher_request_alloc(tfm, GFP_KERNEL);
@@ -963,7 +970,10 @@ static int test_skcipher(struct crypto_a
 					       "%u for %s\n", j, e, k, algo);
 					hexdump(q, template[i].tap[k]);
 					goto out;
-				}
+				} else
+					printk(KERN_INFO "alg: skcipher: Chunk "
+						"test %d pass on %s for %s\n",
+						j, e, algo);
 
 				q += template[i].tap[k];
 				for (n = 0; offset_in_page(q + n) && q[n]; n++)
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -282,6 +282,19 @@ config CRYPTO_DEV_TALITOS
 	  To compile this driver as a module, choose M here: the module
 	  will be called talitos.
 
+config CRYPTO_DEV_CF_TALITOS
+	tristate "Talitos Freescale Coldfire Security Engine (SEC)"
+	select CRYPTO_ALGAPI
+	select CRYPTO_AUTHENC
+	select HW_RANDOM
+	depends on (M547X || M548X)
+	help
+	  Say 'Y' here to use the Freescale Coldfire Security Engine (SEC)
+	  to offload cryptographic algorithm computation.
+
+	  The Freescale SEC is present on Coldfire MCF547x and MCF548x
+	  processors.
+
 config CRYPTO_DEV_IXP4XX
 	tristate "Driver for IXP4xx crypto hardware acceleration"
 	depends on ARCH_IXP4XX
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -6,6 +6,7 @@ n2_crypto-y := n2_core.o n2_asm.o
 obj-$(CONFIG_CRYPTO_DEV_HIFN_795X) += hifn_795x.o
 obj-$(CONFIG_CRYPTO_DEV_MV_CESA) += mv_cesa.o
 obj-$(CONFIG_CRYPTO_DEV_TALITOS) += talitos.o
+obj-$(CONFIG_CRYPTO_DEV_CF_TALITOS) += cf_talitos.o
 obj-$(CONFIG_CRYPTO_DEV_IXP4XX) += ixp4xx_crypto.o
 obj-$(CONFIG_CRYPTO_DEV_MCFCAU) += mcfcau.o
 obj-$(CONFIG_CRYPTO_DEV_MCFCAU_DES) += mcfcau-des.o
--- /dev/null
+++ b/drivers/crypto/cf_talitos.c
@@ -0,0 +1,1727 @@
+/*
+ * cf_talitos - Freescale Coldfire Integrated Security Engine
+ *		(SEC) device driver
+ *
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *	Author: Alison Wang <b18965@freescale.com>
+ *		based on talitos.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/crypto.h>
+#include <linux/hw_random.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/rtnetlink.h>
+#include <linux/slab.h>
+
+#include <crypto/algapi.h>
+#include <crypto/aes.h>
+#include <crypto/des.h>
+#include <crypto/sha.h>
+#include <crypto/md5.h>
+#include <crypto/aead.h>
+#include <crypto/authenc.h>
+#include <crypto/skcipher.h>
+#include <crypto/hash.h>
+#include <crypto/internal/hash.h>
+#include <crypto/scatterwalk.h>
+
+#include <asm/m5485sim.h>
+#include "cf_talitos.h"
+
+#define TALITOS_TIMEOUT 100000
+#define TALITOS_MAX_DATA_LEN 65535
+
+#define DESC_TYPE(desc_hdr) (((desc_hdr) >> 4) & 0xf)
+#define PRIMARY_EU(desc_hdr) (((desc_hdr) >> 28) & 0xf)
+#define SECONDARY_EU(desc_hdr) (((desc_hdr) >> 16) & 0xf)
+
+#define CF_TALITOS_DEBUG 0
+#if CF_TALITOS_DEBUG
+#define dprintk(args...) printk(args)
+#else
+#define dprintk(...)
+#endif
+
+/* descriptor pointer entry */
+struct talitos_ptr {
+	u32 len;	/* length */
+	u32 ptr;	/* address */
+};
+
+static const struct talitos_ptr zero_entry = {
+	.len = 0,
+	.ptr = 0
+};
+
+/* descriptor */
+struct talitos_desc {
+	u32 hdr;			/* header */
+	struct talitos_ptr ptr[7];	/* ptr/len pair array */
+	u32 next_hdr;
+};
+
+/**
+ * talitos_request - descriptor submission request
+ * @desc: descriptor pointer (kernel virtual)
+ * @dma_desc: descriptor's physical bus address
+ * @callback: whom to call when descriptor processing is done
+ * @context: caller context (optional)
+ */
+struct talitos_request {
+	struct talitos_desc *desc;
+	dma_addr_t dma_desc;
+	void (*callback) (struct device *dev, struct talitos_desc *desc,
+		void *context, int error);
+	void *context;
+};
+
+/* per-channel fifo management */
+struct talitos_channel {
+	/* request fifo */
+	struct talitos_request *fifo;
+
+	/* number of requests pending in channel h/w fifo */
+	atomic_t submit_count ____cacheline_aligned;
+
+	/* request submission (head) lock */
+	spinlock_t head_lock ____cacheline_aligned;
+	/* index to next free descriptor request */
+	int head;
+
+	/* request release (tail) lock */
+	spinlock_t tail_lock ____cacheline_aligned;
+	/* index to next in-progress/done descriptor request */
+	int tail;
+};
+
+struct talitos_private {
+	struct device *dev;
+	struct platform_device *pdev;
+	void __iomem *reg;
+	int irq;
+
+	/* SEC version geometry (from device tree node) */
+	unsigned int num_channels;
+	unsigned int chfifo_len;
+	unsigned int exec_units;
+	unsigned int desc_types;
+
+	/* SEC Compatibility info */
+	unsigned long features;
+
+	/*
+	 * length of the request fifo
+	 * fifo_len is chfifo_len rounded up to next power of 2
+	 * so we can use bitwise ops to wrap
+	 */
+	unsigned int fifo_len;
+
+	struct talitos_channel *chan;
+
+	/* next channel to be assigned next incoming descriptor */
+	atomic_t last_chan ____cacheline_aligned;
+
+	/* request callback tasklet */
+	struct tasklet_struct done_task;
+
+	/* list of registered algorithms */
+	struct list_head alg_list;
+
+	/* hwrng device */
+	struct hwrng rng;
+};
+
+/* .features flag */
+#define TALITOS_FTR_SRC_LINK_TBL_LEN_INCLUDES_EXTENT 0x00000001
+#define TALITOS_FTR_HW_AUTH_CHECK 0x00000002
+#define TALITOS_FTR_SHA224_HWINIT 0x00000004
+
+/*
+ * map virtual single (contiguous) pointer to h/w descriptor pointer
+ */
+static void map_single_talitos_ptr(struct device *dev,
+				   struct talitos_ptr *talitos_ptr,
+				   unsigned short len, void *data,
+				   unsigned char extent,
+				   enum dma_data_direction dir)
+{
+	dma_addr_t dma_addr = dma_map_single(dev, data, len, dir);
+
+	talitos_ptr->len = len;
+	talitos_ptr->ptr = dma_addr;
+}
+
+/*
+ * unmap bus single (contiguous) h/w descriptor pointer
+ */
+static void unmap_single_talitos_ptr(struct device *dev,
+				     struct talitos_ptr *talitos_ptr,
+				     enum dma_data_direction dir)
+{
+	dma_unmap_single(dev, talitos_ptr->ptr, talitos_ptr->len, dir);
+}
+
+static int reset_channel(struct device *dev, int ch)
+{
+	struct talitos_private *priv = dev_get_drvdata(dev);
+	unsigned int timeout = TALITOS_TIMEOUT;
+
+	setbits32(priv->reg + TALITOS_CCCR(ch), TALITOS_CCCR_RESET);
+
+	while ((in_be32(priv->reg + TALITOS_CCCR(ch)) &
+		TALITOS_CCCR_RESET) && --timeout)
+		cpu_relax();
+
+	if (timeout == 0) {
+		dev_err(dev, "failed to reset channel %d\n", ch);
+		return -EIO;
+	}
+
+	/* set 36-bit addressing, done writeback enable and done IRQ enable */
+	setbits32(priv->reg + TALITOS_CCCR(ch), TALITOS_CCCR_NE |
+			TALITOS_CCCR_NT | TALITOS_CCCR_CDWE |
+			TALITOS_CCCR_CDIE);
+
+	return 0;
+}
+
+static int reset_device(struct device *dev)
+{
+	struct talitos_private *priv = dev_get_drvdata(dev);
+	unsigned int timeout = TALITOS_TIMEOUT;
+
+	setbits32(priv->reg + TALITOS_MCR, TALITOS_MCR_SWR);
+
+	while ((in_be32(priv->reg + TALITOS_MCR) & TALITOS_MCR_SWR)
+	       && --timeout)
+		cpu_relax();
+
+	if (timeout == 0) {
+		dev_err(dev, "failed to reset device\n");
+		return -EIO;
+	}
+
+	setbits32(priv->reg + TALITOS_DEURCR, TALITOS_DEURCR_RESET);
+	setbits32(priv->reg + TALITOS_AFEURCR, TALITOS_AFEURCR_RESET);
+	setbits32(priv->reg + TALITOS_AESURCR, TALITOS_AESURCR_RESET);
+	setbits32(priv->reg + TALITOS_MDEURCR, TALITOS_MDEURCR_RESET);
+	setbits32(priv->reg + TALITOS_RNGRCR, TALITOS_RNGRCR_SR);
+	return 0;
+}
+
+/*
+ * Reset and initialize the device
+ */
+static int init_device(struct device *dev)
+{
+	struct talitos_private *priv = dev_get_drvdata(dev);
+	int ch, err;
+
+	/*
+	 * Master reset
+	 * errata documentation: warning: certain SEC interrupts
+	 * are not fully cleared by writing the MCR:SWR bit,
+	 * set bit twice to completely reset
+	 */
+	err = reset_device(dev);
+	if (err)
+		return err;
+
+	err = reset_device(dev);
+	if (err)
+		return err;
+
+	/* reset channels */
+	for (ch = 0; ch < priv->num_channels; ch++) {
+		err = reset_channel(dev, ch);
+		if (err)
+			return err;
+	}
+
+	/* enable channel done and error interrupts */
+	out_be32(priv->reg + TALITOS_IMR, 0);
+	out_be32(priv->reg + TALITOS_IMR_LO, 0);
+
+	out_be32(priv->reg + TALITOS_ICR,
+			TALITOS_ICR_CHERR | TALITOS_ICR_CHDONE);
+	out_be32(priv->reg + TALITOS_ICR_LO,
+			TALITOS_ICR_LO_CHERR | TALITOS_ICR_LO_CHDONE);
+
+	return 0;
+}
+
+/**
+ * talitos_submit - submits a descriptor to the device for processing
+ * @dev:	the SEC device to be used
+ * @desc:	the descriptor to be processed by the device
+ * @callback:	whom to call when processing is complete
+ * @context:	a handle for use by caller (optional)
+ *
+ * desc must contain valid dma-mapped (bus physical) address pointers.
+ * callback must check err and feedback in descriptor header
+ * for device processing status.
+ */
+static int talitos_submit(struct device *dev, struct talitos_desc *desc,
+			  void (*callback)(struct device *dev,
+					   struct talitos_desc *desc,
+					   void *context, int error),
+			  void *context)
+{
+	struct talitos_private *priv = dev_get_drvdata(dev);
+	struct talitos_request *request;
+	unsigned long flags, ch;
+	int head;
+
+	/* ignore key parity check in triple DES */
+	if (((desc->hdr & DESC_HDR_SEL0_MASK) == DESC_HDR_SEL0_DEU) &&
+		(desc->hdr & DESC_HDR_MODE0_DEU_3DES))
+		setbits32(priv->reg + TALITOS_DEUIMR, TALITOS_DEUIMR_KPE_MASK);
+
+	/* select done notification */
+	desc->hdr |= DESC_HDR_DONE;
+
+	/* emulate SEC's round-robin channel fifo polling scheme */
+	ch = atomic_inc_return(&priv->last_chan) & (priv->num_channels - 1);
+
+	spin_lock_irqsave(&priv->chan[ch].head_lock, flags);
+
+	head = priv->chan[ch].head;
+	request = &priv->chan[ch].fifo[head];
+
+	/* map descriptor and save caller data */
+	request->dma_desc = dma_map_single(dev, desc, sizeof(*desc),
+				DMA_BIDIRECTIONAL);
+	request->callback = callback;
+	request->context = context;
+
+	/* increment fifo head */
+	priv->chan[ch].head = (priv->chan[ch].head + 1) & (priv->fifo_len - 1);
+
+	smp_wmb();
+	request->desc = desc;
+
+	/* GO! */
+	wmb();
+	out_be32(priv->reg + TALITOS_FF(ch), request->dma_desc);
+
+	spin_unlock_irqrestore(&priv->chan[ch].head_lock, flags);
+
+	return -EINPROGRESS;
+}
+
+/*
+ * process what was done, notify callback of error if not
+ */
+static void flush_channel(struct device *dev, int ch, int error, int reset_ch)
+{
+	struct talitos_private *priv = dev_get_drvdata(dev);
+	struct talitos_request *request, saved_req;
+	unsigned long flags;
+	int tail, status;
+
+	spin_lock_irqsave(&priv->chan[ch].tail_lock, flags);
+
+	tail = priv->chan[ch].tail;
+	while (priv->chan[ch].fifo[tail].desc) {
+		request = &priv->chan[ch].fifo[tail];
+
+		/* descriptors with their done bits set don't get the error */
+		rmb();
+		if ((request->desc->hdr & DESC_HDR_DONE) == DESC_HDR_DONE)
+			status = 0;
+		else
+			if (!error)
+				break;
+			else
+				status = error;
+
+		dma_unmap_single(dev, request->dma_desc,
+				 sizeof(struct talitos_desc),
+				 DMA_BIDIRECTIONAL);
+
+		/* copy entries so we can call callback outside lock */
+		saved_req.desc = request->desc;
+		saved_req.callback = request->callback;
+		saved_req.context = request->context;
+
+		/* release request entry in fifo */
+		smp_wmb();
+		request->desc = NULL;
+
+		/* increment fifo tail */
+		priv->chan[ch].tail = (tail + 1) & (priv->fifo_len - 1);
+
+		spin_unlock_irqrestore(&priv->chan[ch].tail_lock, flags);
+
+		atomic_dec(&priv->chan[ch].submit_count);
+
+		saved_req.callback(dev, saved_req.desc, saved_req.context,
+				   status);
+		/* channel may resume processing in single desc error case */
+		if (error && !reset_ch && status == error)
+			return;
+		spin_lock_irqsave(&priv->chan[ch].tail_lock, flags);
+		tail = priv->chan[ch].tail;
+	}
+
+	spin_unlock_irqrestore(&priv->chan[ch].tail_lock, flags);
+}
+
+/*
+ * process completed requests for channels that have done status
+ */
+static void talitos_done(unsigned long data)
+{
+	struct device *dev = (struct device *)data;
+	struct talitos_private *priv = dev_get_drvdata(dev);
+	int ch;
+
+	for (ch = 0; ch < priv->num_channels; ch++)
+		flush_channel(dev, ch, 0, 0);
+
+	/* At this point, all completed channels have been processed.
+	 * Unmask done interrupts for channels completed later on.
+	 */
+	out_be32(priv->reg + TALITOS_IMR, 0);
+	out_be32(priv->reg + TALITOS_IMR_LO, 0);
+
+	out_be32(priv->reg + TALITOS_ICR,
+			TALITOS_ICR_CHERR | TALITOS_ICR_CHDONE);
+	out_be32(priv->reg + TALITOS_ICR_LO,
+			TALITOS_ICR_LO_CHERR | TALITOS_ICR_LO_CHDONE);
+}
+
+/*
+ * locate current (offending) descriptor
+ */
+static struct talitos_desc *current_desc(struct device *dev, int ch)
+{
+	struct talitos_private *priv = dev_get_drvdata(dev);
+	int tail = priv->chan[ch].tail;
+	dma_addr_t cur_desc;
+
+	cur_desc = in_be32(priv->reg + TALITOS_CDPR(ch));
+
+	while (priv->chan[ch].fifo[tail].dma_desc != cur_desc) {
+		tail = (tail + 1) & (priv->fifo_len - 1);
+		if (tail == priv->chan[ch].tail) {
+			dev_err(dev, "couldn't locate current descriptor\n");
+			return NULL;
+		}
+	}
+
+	return priv->chan[ch].fifo[tail].desc;
+}
+
+/*
+ * user diagnostics; report root cause of error based on execution unit status
+ */
+static void report_eu_error(struct device *dev, int ch,
+			    struct talitos_desc *desc)
+{
+	struct talitos_private *priv = dev_get_drvdata(dev);
+	int i;
+
+	switch (desc->hdr & DESC_HDR_SEL0_MASK) {
+	case DESC_HDR_SEL0_AFEU:
+		dev_err(dev, "AFEUISR 0x%08x\n",
+			in_be32(priv->reg + TALITOS_AFEUISR));
+		break;
+	case DESC_HDR_SEL0_DEU:
+		dev_err(dev, "DEUISR 0x%08x\n",
+			in_be32(priv->reg + TALITOS_DEUISR));
+		break;
+	case DESC_HDR_SEL0_MDEU:
+		dev_err(dev, "MDEUISR 0x%08x\n",
+			in_be32(priv->reg + TALITOS_MDEUISR));
+		break;
+	case DESC_HDR_SEL0_RNG:
+		dev_err(dev, "RNGISR 0x%08x\n",
+			in_be32(priv->reg + TALITOS_RNGISR));
+		break;
+	case DESC_HDR_SEL0_AESU:
+		dev_err(dev, "AESUISR 0x%08x\n",
+			in_be32(priv->reg + TALITOS_AESUISR));
+		break;
+	}
+
+	switch (desc->hdr & DESC_HDR_SEL1_MASK) {
+	case DESC_HDR_SEL1_MDEU:
+		dev_err(dev, "MDEUISR 0x%08x\n",
+			in_be32(priv->reg + TALITOS_MDEUISR));
+		break;
+	}
+
+	for (i = 0; i < 8; i++)
+		dev_err(dev, "DESCBUF 0x%08x\n",
+			in_be32(priv->reg + TALITOS_DESCBUF(ch) + 8 * i));
+}
+
+/*
+ * recover from error interrupts
+ */
+static void talitos_error(unsigned long data, u32 isr, u32 isr_lo)
+{
+	struct device *dev = (struct device *)data;
+	struct talitos_private *priv = dev_get_drvdata(dev);
+	int ch, error, reset_ch = 0;
+	u32 v, v_lo;
+
+	for (ch = 0; ch < priv->num_channels; ch++) {
+		/* skip channels without errors */
+		if (!((isr >> 29) & (1 << (ch * 2))))
+			continue;
+
+		error = -EINVAL;
+
+		v = in_be32(priv->reg + TALITOS_CCPSR(ch));
+		v_lo = in_be32(priv->reg + TALITOS_CCPSR_LO(ch));
+
+		if (v_lo & TALITOS_CCPSR_LO_TEA)
+			dev_err(dev, "master data transfer error\n");
+		if (v_lo & TALITOS_CCPSR_LO_PERR)
+			dev_err(dev, "fetch pointer not complete error\n");
+		if (v_lo & TALITOS_CCPSR_LO_DERR)
+			dev_err(dev, "illegal descriptor header error\n");
+		if (v_lo & TALITOS_CCPSR_LO_SERR)
+			dev_err(dev, "static assignment error\n");
+		if (v_lo & TALITOS_CCPSR_LO_EUERR)
+			report_eu_error(dev, ch, current_desc(dev, ch));
+
+		flush_channel(dev, ch, error, reset_ch);
+
+		if (reset_ch)
+			reset_channel(dev, ch);
+	}
+
+	/* purge request queues */
+	for (ch = 0; ch < priv->num_channels; ch++)
+		flush_channel(dev, ch, -EIO, 1);
+
+	/* reset and reinitialize the device */
+	init_device(dev);
+}
+
+static irqreturn_t talitos_interrupt(int irq, void *data)
+{
+	struct device *dev = data;
+	struct talitos_private *priv = dev_get_drvdata(dev);
+	u32 isr, isr_lo;
+
+	isr = in_be32(priv->reg + TALITOS_ISR);
+	isr_lo = in_be32(priv->reg + TALITOS_ISR_LO);
+	/* Acknowledge interrupt */
+	out_be32(priv->reg + TALITOS_ICR, isr);
+	out_be32(priv->reg + TALITOS_ICR_LO, isr_lo);
+
+	if (unlikely(isr & ~TALITOS_ISR_CHDONE)) {
+		talitos_error((unsigned long)data, isr, isr_lo);
+	} else if (likely(isr & TALITOS_ISR_CHDONE)) {
+		/* mask further done interrupts. */
+		setbits32(priv->reg + TALITOS_IMR, TALITOS_IMR_DONE);
+		/* done_task will unmask done interrupts at exit */
+		tasklet_schedule(&priv->done_task);
+	}
+
+	return (isr || isr_lo) ? IRQ_HANDLED : IRQ_NONE;
+}
+
+
+/*
+ * crypto alg
+ */
+#define TALITOS_CRA_PRIORITY		3000
+#define TALITOS_MAX_KEY_SIZE		64
+#define TALITOS_MAX_IV_LENGTH		16
+#define TALITOS_MAX_OUTPUTDATA_SIZE	64
+#define TALITOS_MAX_INPUTDATA_SIZE	64
+
+#define ARC4_MIN_KEY_SIZE		4
+#define ARC4_MAX_KEY_SIZE		16
+#define ARC4_BLOCK_SIZE			64
+#define MD5_BLOCK_SIZE			64
+
+struct talitos_ctx {
+	struct device *dev;
+	__be32 desc_hdr_template;
+	u8 key[TALITOS_MAX_KEY_SIZE];
+	u8 iv[TALITOS_MAX_IV_LENGTH];
+	unsigned int keylen;
+	unsigned int enckeylen;
+	unsigned int authkeylen;
+	unsigned int authsize;
+};
+
+#define HASH_MAX_BLOCK_SIZE		SHA512_BLOCK_SIZE
+#define TALITOS_MDEU_MAX_CONTEXT_SIZE		\
+	TALITOS_MDEU_CONTEXT_SIZE_MD5_SHA1_SHA256
+
+struct talitos_ahash_req_ctx {
+	u32 hw_context[TALITOS_MDEU_MAX_CONTEXT_SIZE / sizeof(u32)];
+	unsigned int hw_context_size;
+	u8 buf[HASH_MAX_BLOCK_SIZE];
+	u8 bufnext[HASH_MAX_BLOCK_SIZE];
+	unsigned int swinit;
+	unsigned int first;
+	unsigned int last;
+	unsigned int to_hash_later;
+	u64 nbuf;
+	struct scatterlist bufsl[2];
+	struct scatterlist *psrc;
+};
+
+/*
+ * talitos_edesc - s/w-extended descriptor
+ * @src_nents: number of segments in input scatterlist
+ * @dst_nents: number of segments in output scatterlist
+ * @desc: h/w descriptor
+ *
+ * if decrypting (with authcheck), or either one of src_nents or dst_nents
+ * is greater than 1, an integrity check value is concatenated to the end
+ * of link_tbl data
+ */
+struct talitos_edesc {
+	int src_nents;
+	int dst_nents;
+	int src_is_chained;
+	int dst_is_chained;
+	struct talitos_desc desc;
+	u8 src_buf[TALITOS_MAX_INPUTDATA_SIZE];
+	u8 dst_buf[TALITOS_MAX_OUTPUTDATA_SIZE];
+};
+
+static int talitos_map_sg(struct device *dev, struct scatterlist *sg,
+			  unsigned int nents, enum dma_data_direction dir,
+			  int chained)
+{
+	if (unlikely(chained))
+		while (sg) {
+			dma_map_sg(dev, sg, 1, dir);
+			sg = scatterwalk_sg_next(sg);
+		}
+	else
+		dma_map_sg(dev, sg, nents, dir);
+	return nents;
+}
+
+static void talitos_unmap_sg_chain(struct device *dev, struct scatterlist *sg,
+				   enum dma_data_direction dir)
+{
+	while (sg) {
+		dma_unmap_sg(dev, sg, 1, dir);
+		sg = scatterwalk_sg_next(sg);
+	}
+}
+
+static void talitos_sg_unmap(struct device *dev,
+			     struct talitos_edesc *edesc,
+			     struct scatterlist *src,
+			     struct scatterlist *dst)
+{
+	unsigned int src_nents = edesc->src_nents ? : 1;
+	unsigned int dst_nents = edesc->dst_nents ? : 1;
+
+	if (src != dst) {
+		if (edesc->src_is_chained)
+			talitos_unmap_sg_chain(dev, src, DMA_TO_DEVICE);
+		else
+			dma_unmap_sg(dev, src, src_nents, DMA_TO_DEVICE);
+
+		if (dst) {
+			if (edesc->dst_is_chained)
+				talitos_unmap_sg_chain(dev, dst,
+						       DMA_FROM_DEVICE);
+			else
+				dma_unmap_sg(dev, dst, dst_nents,
+					     DMA_FROM_DEVICE);
+		}
+	} else
+		if (edesc->src_is_chained)
+			talitos_unmap_sg_chain(dev, src, DMA_BIDIRECTIONAL);
+		else
+			dma_unmap_sg(dev, src, src_nents, DMA_BIDIRECTIONAL);
+}
+
+/*
+ * derive number of elements in scatterlist
+ */
+static int sg_count(struct scatterlist *sg_list, int nbytes, int *chained)
+{
+	struct scatterlist *sg = sg_list;
+	int sg_nents = 0;
+
+	*chained = 0;
+	while (nbytes > 0) {
+		sg_nents++;
+		nbytes -= sg->length;
+		if (!sg_is_last(sg) && (sg + 1)->length == 0)
+			*chained = 1;
+		sg = scatterwalk_sg_next(sg);
+	}
+
+	return sg_nents;
+}
+
+/**
+ * sg_copy_end_to_buffer - Copy end data from SG list to a linear buffer
+ * @sgl:		 The SG list
+ * @nents:		 Number of SG entries
+ * @buf:		 Where to copy to
+ * @buflen:		 The number of bytes to copy
+ * @skip:		 The number of bytes to skip before copying.
+ *                       Note: skip + buflen should equal SG total size.
+ *
+ * Returns the number of copied bytes.
+ *
+ **/
+static size_t sg_copy_end_to_buffer(struct scatterlist *sgl, unsigned int nents,
+				    void *buf, size_t buflen, unsigned int skip)
+{
+	unsigned int offset = 0;
+	unsigned int boffset = 0;
+	struct sg_mapping_iter miter;
+	unsigned long flags;
+	unsigned int sg_flags = SG_MITER_ATOMIC;
+	size_t total_buffer = buflen + skip;
+
+	sg_flags |= SG_MITER_FROM_SG;
+
+	sg_miter_start(&miter, sgl, nents, sg_flags);
+
+	local_irq_save(flags);
+
+	while (sg_miter_next(&miter) && offset < total_buffer) {
+		unsigned int len;
+		unsigned int ignore;
+
+		if ((offset + miter.length) > skip) {
+			if (offset < skip) {
+				/* Copy part of this segment */
+				ignore = skip - offset;
+				len = miter.length - ignore;
+				if (boffset + len > buflen)
+					len = buflen - boffset;
+				memcpy(buf + boffset, miter.addr + ignore, len);
+			} else {
+				/* Copy all of this segment (up to buflen) */
+				len = miter.length;
+				if (boffset + len > buflen)
+					len = buflen - boffset;
+				memcpy(buf + boffset, miter.addr, len);
+			}
+			boffset += len;
+		}
+		offset += miter.length;
+	}
+
+	sg_miter_stop(&miter);
+
+	local_irq_restore(flags);
+	return boffset;
+}
+
+/*
+ * allocate and map the extended descriptor
+ */
+static struct talitos_edesc *talitos_edesc_alloc(struct device *dev,
+						 struct scatterlist *src,
+						 struct scatterlist *dst,
+						 int hash_result,
+						 unsigned int cryptlen,
+						 unsigned int authsize,
+						 int icv_stashing,
+						 u32 cryptoflags)
+{
+	struct talitos_edesc *edesc;
+	int src_nents, dst_nents, alloc_len;
+	int src_chained, dst_chained = 0;
+	gfp_t flags = cryptoflags & CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL :
+		      GFP_ATOMIC;
+
+	if (cryptlen + authsize > TALITOS_MAX_DATA_LEN) {
+		dev_err(dev, "length exceeds h/w max limit\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	src_nents = sg_count(src, cryptlen + authsize, &src_chained);
+	src_nents = (src_nents == 1) ? 0 : src_nents;
+
+	if (hash_result) {
+		dst_nents = 0;
+	} else {
+		if (dst == src) {
+			dst_nents = src_nents;
+		} else {
+			dst_nents = sg_count(dst, cryptlen + authsize,
+					     &dst_chained);
+			dst_nents = (dst_nents == 1) ? 0 : dst_nents;
+		}
+	}
+
+	/*
+	 * allocate space for base edesc plus the link tables,
+	 * allowing for two separate entries for ICV and generated ICV (+ 2),
+	 * and the ICV data itself
+	 */
+	alloc_len = sizeof(struct talitos_edesc);
+
+	edesc = kmalloc(alloc_len, GFP_KERNEL | flags);
+	if (!edesc) {
+		dev_err(dev, "could not allocate edescriptor\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	edesc->src_nents = src_nents;
+	edesc->dst_nents = dst_nents;
+	edesc->src_is_chained = src_chained;
+	edesc->dst_is_chained = dst_chained;
+	return edesc;
+}
+
+static int ablkcipher_setkey(struct crypto_ablkcipher *cipher,
+			     const u8 *key, unsigned int keylen)
+{
+	struct talitos_ctx *ctx = crypto_ablkcipher_ctx(cipher);
+	struct ablkcipher_alg *alg = crypto_ablkcipher_alg(cipher);
+
+	if (keylen > TALITOS_MAX_KEY_SIZE)
+		goto badkey;
+
+	if (keylen < alg->min_keysize || keylen > alg->max_keysize)
+		goto badkey;
+
+	memcpy(&ctx->key, key, keylen);
+	ctx->keylen = keylen;
+
+	return 0;
+
+badkey:
+	crypto_ablkcipher_set_flags(cipher, CRYPTO_TFM_RES_BAD_KEY_LEN);
+	return -EINVAL;
+}
+
+static void common_nonsnoop_unmap(struct device *dev,
+				  struct talitos_edesc *edesc,
+				  struct ablkcipher_request *areq)
+{
+	unmap_single_talitos_ptr(dev, &edesc->desc.ptr[5], DMA_FROM_DEVICE);
+	unmap_single_talitos_ptr(dev, &edesc->desc.ptr[2], DMA_TO_DEVICE);
+	unmap_single_talitos_ptr(dev, &edesc->desc.ptr[1], DMA_TO_DEVICE);
+
+	talitos_sg_unmap(dev, edesc, areq->src, areq->dst);
+}
+
+static void ablkcipher_done(struct device *dev,
+			    struct talitos_desc *desc, void *context,
+			    int err)
+{
+	struct ablkcipher_request *areq = context;
+	struct talitos_edesc *edesc;
+
+	edesc = container_of(desc, struct talitos_edesc, desc);
+
+	if (edesc->dst_nents != 0)
+		sg_copy_from_buffer(areq->dst, edesc->dst_nents,
+			edesc->dst_buf, areq->nbytes);
+
+	common_nonsnoop_unmap(dev, edesc, areq);
+
+	kfree(edesc);
+
+	areq->base.complete(&areq->base, err);
+}
+
+static int common_nonsnoop(struct talitos_edesc *edesc,
+			   struct ablkcipher_request *areq,
+			   u8 *giv,
+			   void (*callback) (struct device *dev,
+					     struct talitos_desc *desc,
+					     void *context, int error))
+{
+	struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq);
+	struct talitos_ctx *ctx = crypto_ablkcipher_ctx(cipher);
+	struct device *dev = ctx->dev;
+	struct talitos_desc *desc = &edesc->desc;
+	unsigned int cryptlen = areq->nbytes;
+	unsigned int ivsize;
+	int sg_count, ret;
+
+	desc->next_hdr = 0;
+
+	/* first DWORD empty */
+	desc->ptr[0] = zero_entry;
+
+	/* cipher iv */
+	ivsize = crypto_ablkcipher_ivsize(cipher);
+	map_single_talitos_ptr(dev, &desc->ptr[1], ivsize, giv ?: areq->info, 0,
+			       DMA_TO_DEVICE);
+
+	/* AFEU using a key */
+	if (((desc->hdr & DESC_HDR_SEL0_MASK) == DESC_HDR_SEL0_AFEU) &&
+		((desc->hdr & DESC_HDR_MODE0_MASK) ==
+		 DESC_HDR_MODE0_AFEU_USE_KEY))
+		desc->ptr[1] = zero_entry;
+
+	/* cipher key */
+	map_single_talitos_ptr(dev, &desc->ptr[2], ctx->keylen,
+			       (char *)&ctx->key, 0, DMA_TO_DEVICE);
+
+	/* AFEU using context */
+	if (((desc->hdr & DESC_HDR_SEL0_MASK) == DESC_HDR_SEL0_AFEU) &&
+		((desc->hdr & DESC_HDR_MODE0_MASK) ==
+		 DESC_HDR_MODE0_AFEU_USE_CONTEXT))
+		desc->ptr[2] = zero_entry;
+
+	/*
+	 * cipher in
+	 */
+	desc->ptr[3].len = cpu_to_be16(cryptlen);
+
+	sg_count = talitos_map_sg(dev, areq->src, edesc->src_nents ? : 1,
+				  (areq->src == areq->dst) ? DMA_BIDIRECTIONAL
+							   : DMA_TO_DEVICE,
+				  edesc->src_is_chained);
+
+	if (sg_count == 1)
+		desc->ptr[3].ptr = sg_dma_address(areq->src);
+	else {
+		sg_copy_to_buffer(areq->src, sg_count, edesc->src_buf,
+				desc->ptr[3].len);
+		desc->ptr[3].ptr = (u32)edesc->src_buf;
+	}
+
+	/* cipher out */
+	desc->ptr[4].len = cpu_to_be16(cryptlen);
+
+	if (areq->src != areq->dst)
+		sg_count = talitos_map_sg(dev, areq->dst,
+					  edesc->dst_nents ? : 1,
+					  DMA_FROM_DEVICE,
+					  edesc->dst_is_chained);
+
+	if (sg_count == 1)
+		desc->ptr[4].ptr = sg_dma_address(areq->dst);
+	else
+		desc->ptr[4].ptr = (u32)edesc->dst_buf;
+
+	/* iv out */
+	map_single_talitos_ptr(dev, &desc->ptr[5], ivsize, ctx->iv, 0,
+			       DMA_FROM_DEVICE);
+
+	/* last DWORD empty */
+	desc->ptr[6] = zero_entry;
+
+	ret = talitos_submit(dev, desc, callback, areq);
+	if (ret != -EINPROGRESS) {
+		common_nonsnoop_unmap(dev, edesc, areq);
+		kfree(edesc);
+	}
+	return ret;
+}
+
+static struct talitos_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request *
+						    areq)
+{
+	struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq);
+	struct talitos_ctx *ctx = crypto_ablkcipher_ctx(cipher);
+
+	return talitos_edesc_alloc(ctx->dev, areq->src, areq->dst, 0,
+				   areq->nbytes, 0, 0, areq->base.flags);
+}
+
+static int ablkcipher_encrypt(struct ablkcipher_request *areq)
+{
+	struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq);
+	struct talitos_ctx *ctx = crypto_ablkcipher_ctx(cipher);
+	struct talitos_edesc *edesc;
+
+	/* allocate extended descriptor */
+	edesc = ablkcipher_edesc_alloc(areq);
+	if (IS_ERR(edesc))
+		return PTR_ERR(edesc);
+
+	/* set encrypt except AFEU */
+	if ((ctx->desc_hdr_template & DESC_HDR_SEL0_MASK) == DESC_HDR_SEL0_AFEU)
+		edesc->desc.hdr = ctx->desc_hdr_template;
+	else
+		edesc->desc.hdr = ctx->desc_hdr_template |
+			DESC_HDR_MODE0_ENCRYP;
+
+	return common_nonsnoop(edesc, areq, NULL, ablkcipher_done);
+}
+
+static int ablkcipher_decrypt(struct ablkcipher_request *areq)
+{
+	struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq);
+	struct talitos_ctx *ctx = crypto_ablkcipher_ctx(cipher);
+	struct talitos_edesc *edesc;
+
+	/* allocate extended descriptor */
+	edesc = ablkcipher_edesc_alloc(areq);
+	if (IS_ERR(edesc))
+		return PTR_ERR(edesc);
+
+	edesc->desc.hdr = ctx->desc_hdr_template | DESC_HDR_DIR_INBOUND;
+
+	return common_nonsnoop(edesc, areq, NULL, ablkcipher_done);
+}
+
+static void common_nonsnoop_hash_unmap(struct device *dev,
+				       struct talitos_edesc *edesc,
+				       struct ahash_request *areq)
+{
+	struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+
+	unmap_single_talitos_ptr(dev, &edesc->desc.ptr[5], DMA_FROM_DEVICE);
+
+	/* When using hashctx-in, must unmap it. */
+	if (edesc->desc.ptr[1].len)
+		unmap_single_talitos_ptr(dev, &edesc->desc.ptr[1],
+					 DMA_TO_DEVICE);
+
+	if (edesc->desc.ptr[2].len)
+		unmap_single_talitos_ptr(dev, &edesc->desc.ptr[2],
+					 DMA_TO_DEVICE);
+
+	talitos_sg_unmap(dev, edesc, req_ctx->psrc, NULL);
+}
+
+static void ahash_done(struct device *dev,
+		       struct talitos_desc *desc, void *context,
+		       int err)
+{
+	struct ahash_request *areq = context;
+	struct talitos_edesc *edesc =
+		 container_of(desc, struct talitos_edesc, desc);
+	struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+
+	if (!req_ctx->last && req_ctx->to_hash_later) {
+		/* Position any partial block for next update/final/finup */
+		memcpy(req_ctx->buf, req_ctx->bufnext, req_ctx->to_hash_later);
+		req_ctx->nbuf = req_ctx->to_hash_later;
+	}
+	common_nonsnoop_hash_unmap(dev, edesc, areq);
+
+	kfree(edesc);
+
+	areq->base.complete(&areq->base, err);
+}
+
+static int common_nonsnoop_hash(struct talitos_edesc *edesc,
+				struct ahash_request *areq, unsigned int length,
+				void (*callback) (struct device *dev,
+						  struct talitos_desc *desc,
+						  void *context, int error))
+{
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+	struct talitos_ctx *ctx = crypto_ahash_ctx(tfm);
+	struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+	struct device *dev = ctx->dev;
+	struct talitos_desc *desc = &edesc->desc;
+	int sg_count, ret;
+
+	desc->next_hdr = 0;
+
+	/* first DWORD empty */
+	desc->ptr[0] = zero_entry;
+
+	/* hash context in */
+	if (!req_ctx->first || req_ctx->swinit) {
+		map_single_talitos_ptr(dev, &desc->ptr[1],
+				       req_ctx->hw_context_size,
+				       (char *)req_ctx->hw_context, 0,
+				       DMA_TO_DEVICE);
+		req_ctx->swinit = 0;
+	} else {
+		desc->ptr[1] = zero_entry;
+		/* Indicate next op is not the first. */
+		req_ctx->first = 0;
+	}
+
+	/* HMAC key */
+	if (ctx->keylen)
+		map_single_talitos_ptr(dev, &desc->ptr[2], ctx->keylen,
+				       (char *)&ctx->key, 0, DMA_TO_DEVICE);
+	else
+		desc->ptr[2] = zero_entry;
+
+	/*
+	 * data in
+	 */
+	desc->ptr[3].len = length;
+	sg_count = talitos_map_sg(dev, req_ctx->psrc,
+				  edesc->src_nents ? : 1,
+				  DMA_TO_DEVICE,
+				  edesc->src_is_chained);
+
+	if (sg_count == 1)
+		desc->ptr[3].ptr = sg_dma_address(req_ctx->psrc);
+	else {
+		sg_copy_to_buffer(req_ctx->psrc, sg_count, edesc->src_buf,
+				desc->ptr[3].len);
+		desc->ptr[3].ptr = (u32)edesc->src_buf;
+	}
+
+	/* fifth DWORD empty */
+	desc->ptr[4] = zero_entry;
+
+	/* hash/HMAC out -or- hash context out */
+	if (req_ctx->last)
+		map_single_talitos_ptr(dev, &desc->ptr[5],
+				crypto_ahash_digestsize(tfm),
+				areq->result, 0, DMA_FROM_DEVICE);
+	else
+		map_single_talitos_ptr(dev, &desc->ptr[5],
+				req_ctx->hw_context_size,
+				req_ctx->hw_context, 0, DMA_FROM_DEVICE);
+
+	/* last DWORD empty */
+	desc->ptr[6] = zero_entry;
+
+	ret = talitos_submit(dev, desc, callback, areq);
+	if (ret != -EINPROGRESS) {
+		common_nonsnoop_hash_unmap(dev, edesc, areq);
+		kfree(edesc);
+	}
+	return ret;
+}
+
+static struct talitos_edesc *ahash_edesc_alloc(struct ahash_request *areq,
+					       unsigned int nbytes)
+{
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+	struct talitos_ctx *ctx = crypto_ahash_ctx(tfm);
+	struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+
+	return talitos_edesc_alloc(ctx->dev, req_ctx->psrc, NULL, 1,
+				   nbytes, 0, 0, areq->base.flags);
+}
+
+static int ahash_init(struct ahash_request *areq)
+{
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+	struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+
+	/* Initialize the context */
+	req_ctx->nbuf = 0;
+	req_ctx->first = 1; /* first indicates h/w must init its context */
+	req_ctx->swinit = 0; /* assume h/w init of context */
+	req_ctx->hw_context_size =
+		(crypto_ahash_digestsize(tfm) <= SHA256_DIGEST_SIZE)
+			? TALITOS_MDEU_CONTEXT_SIZE_MD5_SHA1_SHA256
+			: TALITOS_MDEU_CONTEXT_SIZE_SHA384_SHA512;
+
+	return 0;
+}
+
+/*
+ * on h/w without explicit sha224 support, we initialize h/w context
+ * manually with sha224 constants, and tell it to run sha256.
+ */
+static int ahash_init_sha224_swinit(struct ahash_request *areq)
+{
+	struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+
+	ahash_init(areq);
+	req_ctx->swinit = 1;/* prevent h/w initting context with sha256 values*/
+
+	req_ctx->hw_context[0] = SHA224_H0;
+	req_ctx->hw_context[1] = SHA224_H1;
+	req_ctx->hw_context[2] = SHA224_H2;
+	req_ctx->hw_context[3] = SHA224_H3;
+	req_ctx->hw_context[4] = SHA224_H4;
+	req_ctx->hw_context[5] = SHA224_H5;
+	req_ctx->hw_context[6] = SHA224_H6;
+	req_ctx->hw_context[7] = SHA224_H7;
+
+	/* init 64-bit count */
+	req_ctx->hw_context[8] = 0;
+	req_ctx->hw_context[9] = 0;
+
+	return 0;
+}
+
+static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
+{
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+	struct talitos_ctx *ctx = crypto_ahash_ctx(tfm);
+	struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+	struct talitos_edesc *edesc;
+	unsigned int blocksize =
+			crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm));
+	unsigned int nbytes_to_hash;
+	unsigned int to_hash_later;
+	unsigned int nsg;
+	int chained;
+
+	if (!req_ctx->last && (nbytes + req_ctx->nbuf <= blocksize)) {
+		/* Buffer up to one whole block */
+		sg_copy_to_buffer(areq->src,
+				  sg_count(areq->src, nbytes, &chained),
+				  req_ctx->buf + req_ctx->nbuf, nbytes);
+		req_ctx->nbuf += nbytes;
+		return 0;
+	}
+
+	/* At least (blocksize + 1) bytes are available to hash */
+	nbytes_to_hash = nbytes + req_ctx->nbuf;
+	to_hash_later = nbytes_to_hash & (blocksize - 1);
+
+	if (req_ctx->last)
+		to_hash_later = 0;
+	else if (to_hash_later)
+		/* There is a partial block. Hash the full block(s) now */
+		nbytes_to_hash -= to_hash_later;
+	else {
+		/* Keep one block buffered */
+		nbytes_to_hash -= blocksize;
+		to_hash_later = blocksize;
+	}
+
+	/* Chain in any previously buffered data */
+	if (req_ctx->nbuf) {
+		nsg = (req_ctx->nbuf < nbytes_to_hash) ? 2 : 1;
+		sg_init_table(req_ctx->bufsl, nsg);
+		sg_set_buf(req_ctx->bufsl, req_ctx->buf, req_ctx->nbuf);
+		if (nsg > 1)
+			scatterwalk_sg_chain(req_ctx->bufsl, 2, areq->src);
+		req_ctx->psrc = req_ctx->bufsl;
+	} else
+		req_ctx->psrc = areq->src;
+
+	if (to_hash_later) {
+		int nents = sg_count(areq->src, nbytes, &chained);
+		sg_copy_end_to_buffer(areq->src, nents,
+				      req_ctx->bufnext,
+				      to_hash_later,
+				      nbytes - to_hash_later);
+	}
+	req_ctx->to_hash_later = to_hash_later;
+
+	/* Allocate extended descriptor */
+	edesc = ahash_edesc_alloc(areq, nbytes_to_hash);
+	if (IS_ERR(edesc))
+		return PTR_ERR(edesc);
+
+	edesc->desc.hdr = ctx->desc_hdr_template;
+
+	/* On last one, request SEC to pad; otherwise continue */
+	if (req_ctx->last)
+		edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_PAD;
+	else
+		edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_CONT;
+
+	/* request SEC to INIT hash. */
+	if (req_ctx->first && !req_ctx->swinit)
+		edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_INIT;
+
+	/* When the tfm context has a keylen, it's an HMAC.
+	 * A first or last (ie. not middle) descriptor must request HMAC.
+	 */
+	if (ctx->keylen && (req_ctx->first || req_ctx->last))
+		edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_HMAC;
+
+	return common_nonsnoop_hash(edesc, areq, nbytes_to_hash,
+				    ahash_done);
+}
+
+static int ahash_update(struct ahash_request *areq)
+{
+	struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+
+	req_ctx->last = 0;
+
+	return ahash_process_req(areq, areq->nbytes);
+}
+
+static int ahash_final(struct ahash_request *areq)
+{
+	struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+
+	req_ctx->last = 1;
+
+	return ahash_process_req(areq, 0);
+}
+
+static int ahash_finup(struct ahash_request *areq)
+{
+	struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+
+	req_ctx->last = 1;
+
+	return ahash_process_req(areq, areq->nbytes);
+}
+
+static int ahash_digest(struct ahash_request *areq)
+{
+	struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+	struct crypto_ahash *ahash = crypto_ahash_reqtfm(areq);
+
+	ahash->init(areq);
+	req_ctx->last = 1;
+
+	return ahash_process_req(areq, areq->nbytes);
+}
+
+struct talitos_alg_template {
+	u32 type;
+	union {
+		struct crypto_alg crypto;
+		struct ahash_alg hash;
+	} alg;
+	__be32 desc_hdr_template;
+};
+
+static struct talitos_alg_template driver_algs[] = {
+	/* ABLKCIPHER algorithms. */
+	{	.type = CRYPTO_ALG_TYPE_ABLKCIPHER,
+		.alg.crypto = {
+			.cra_name = "ecb(arc4)",
+			.cra_driver_name = "ecb-arc4-talitos",
+			.cra_blocksize = ARC4_BLOCK_SIZE,
+			.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+					CRYPTO_ALG_ASYNC,
+			.cra_type = &crypto_ablkcipher_type,
+			.cra_ablkcipher = {
+				.setkey = ablkcipher_setkey,
+				.encrypt = ablkcipher_encrypt,
+				.decrypt = ablkcipher_decrypt,
+				.geniv = "eseqiv",
+				.min_keysize = ARC4_MIN_KEY_SIZE,
+				.max_keysize = ARC4_MAX_KEY_SIZE,
+				.ivsize = ARC4_BLOCK_SIZE,
+			}
+		},
+		.desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_AFEU |
+				     DESC_HDR_SEL0_AFEU |
+				     DESC_HDR_MODE0_AFEU_USE_KEY,
+	},
+	{	.type = CRYPTO_ALG_TYPE_ABLKCIPHER,
+		.alg.crypto = {
+			.cra_name = "cbc(aes)",
+			.cra_driver_name = "cbc-aes-talitos",
+			.cra_blocksize = AES_BLOCK_SIZE,
+			.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+					CRYPTO_ALG_ASYNC,
+			.cra_type = &crypto_ablkcipher_type,
+			.cra_ablkcipher = {
+				.setkey = ablkcipher_setkey,
+				.encrypt = ablkcipher_encrypt,
+				.decrypt = ablkcipher_decrypt,
+				.geniv = "eseqiv",
+				.min_keysize = AES_MIN_KEY_SIZE,
+				.max_keysize = AES_MAX_KEY_SIZE,
+				.ivsize = AES_BLOCK_SIZE,
+			}
+		},
+		.desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
+				     DESC_HDR_SEL0_AESU |
+				     DESC_HDR_MODE0_AESU_CBC,
+	},
+	{	.type = CRYPTO_ALG_TYPE_ABLKCIPHER,
+		.alg.crypto = {
+			.cra_name = "cbc(des)",
+			.cra_driver_name = "cbc-des-talitos",
+			.cra_blocksize = DES_BLOCK_SIZE,
+			.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+					CRYPTO_ALG_ASYNC,
+			.cra_type = &crypto_ablkcipher_type,
+			.cra_ablkcipher = {
+				.setkey = ablkcipher_setkey,
+				.encrypt = ablkcipher_encrypt,
+				.decrypt = ablkcipher_decrypt,
+				.geniv = "eseqiv",
+				.min_keysize = DES_KEY_SIZE,
+				.max_keysize = DES_KEY_SIZE,
+				.ivsize = DES_BLOCK_SIZE,
+			}
+		},
+		.desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
+					DESC_HDR_SEL0_DEU |
+					DESC_HDR_MODE0_DEU_CBC,
+	},
+	{	.type = CRYPTO_ALG_TYPE_ABLKCIPHER,
+		.alg.crypto = {
+			.cra_name = "cbc(des3_ede)",
+			.cra_driver_name = "cbc-3des-talitos",
+			.cra_blocksize = DES3_EDE_BLOCK_SIZE,
+			.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+					CRYPTO_ALG_ASYNC,
+			.cra_type = &crypto_ablkcipher_type,
+			.cra_ablkcipher = {
+				.setkey = ablkcipher_setkey,
+				.encrypt = ablkcipher_encrypt,
+				.decrypt = ablkcipher_decrypt,
+				.geniv = "eseqiv",
+				.min_keysize = DES3_EDE_KEY_SIZE,
+				.max_keysize = DES3_EDE_KEY_SIZE,
+				.ivsize = DES3_EDE_BLOCK_SIZE,
+			}
+		},
+		.desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
+					DESC_HDR_SEL0_DEU |
+					DESC_HDR_MODE0_DEU_CBC |
+					DESC_HDR_MODE0_DEU_3DES,
+	},
+	/* AHASH algorithms. */
+	{	.type = CRYPTO_ALG_TYPE_AHASH,
+		.alg.hash = {
+			.init = ahash_init,
+			.update = ahash_update,
+			.final = ahash_final,
+			.finup = ahash_finup,
+			.digest = ahash_digest,
+			.halg.digestsize = MD5_DIGEST_SIZE,
+			.halg.base = {
+				.cra_name = "md5",
+				.cra_driver_name = "md5-talitos",
+				.cra_blocksize = MD5_BLOCK_SIZE,
+				.cra_flags = CRYPTO_ALG_TYPE_AHASH |
+					     CRYPTO_ALG_ASYNC,
+				.cra_type = &crypto_ahash_type
+			}
+		},
+		.desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
+				     DESC_HDR_SEL0_MDEU |
+				     DESC_HDR_MODE0_MDEU_MD5,
+	},
+	{	.type = CRYPTO_ALG_TYPE_AHASH,
+		.alg.hash = {
+			.init = ahash_init,
+			.update = ahash_update,
+			.final = ahash_final,
+			.finup = ahash_finup,
+			.digest = ahash_digest,
+			.halg.digestsize = SHA1_DIGEST_SIZE,
+			.halg.base = {
+				.cra_name = "sha1",
+				.cra_driver_name = "sha1-talitos",
+				.cra_blocksize = SHA1_BLOCK_SIZE,
+				.cra_flags = CRYPTO_ALG_TYPE_AHASH |
+					     CRYPTO_ALG_ASYNC,
+				.cra_type = &crypto_ahash_type
+			}
+		},
+		.desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
+				     DESC_HDR_SEL0_MDEU |
+				     DESC_HDR_MODE0_MDEU_SHA1,
+	},
+};
+
+struct talitos_crypto_alg {
+	struct list_head entry;
+	struct device *dev;
+	struct talitos_alg_template algt;
+};
+
+static int talitos_cra_init(struct crypto_tfm *tfm)
+{
+	struct crypto_alg *alg = tfm->__crt_alg;
+	struct talitos_crypto_alg *talitos_alg;
+	struct talitos_ctx *ctx = crypto_tfm_ctx(tfm);
+
+	if ((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) == CRYPTO_ALG_TYPE_AHASH)
+		talitos_alg = container_of(__crypto_ahash_alg(alg),
+					   struct talitos_crypto_alg,
+					   algt.alg.hash);
+	else
+		talitos_alg = container_of(alg, struct talitos_crypto_alg,
+					   algt.alg.crypto);
+
+	/* update context with ptr to dev */
+	ctx->dev = talitos_alg->dev;
+
+	/* copy descriptor header template value */
+	ctx->desc_hdr_template = talitos_alg->algt.desc_hdr_template;
+
+	return 0;
+}
+
+static int talitos_cra_init_ahash(struct crypto_tfm *tfm)
+{
+	struct talitos_ctx *ctx = crypto_tfm_ctx(tfm);
+
+	talitos_cra_init(tfm);
+
+	ctx->keylen = 0;
+	crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
+				 sizeof(struct talitos_ahash_req_ctx));
+
+	return 0;
+}
+
+/*
+ * given the alg's descriptor header template, determine whether descriptor
+ * type and primary/secondary execution units required match the hw
+ * capabilities description provided in the device tree node.
+ */
+static int hw_supports(struct device *dev, __be32 desc_hdr_template)
+{
+	struct talitos_private *priv = dev_get_drvdata(dev);
+	int ret;
+
+	ret = (DESC_TYPE(desc_hdr_template) & priv->desc_types) &&
+	      (PRIMARY_EU(desc_hdr_template) & priv->exec_units);
+
+	if (SECONDARY_EU(desc_hdr_template))
+		ret = ret && (SECONDARY_EU(desc_hdr_template)
+				& priv->exec_units);
+
+	return ret;
+}
+
+static int talitos_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct talitos_private *priv = dev_get_drvdata(dev);
+	struct talitos_crypto_alg *t_alg, *n;
+	int i;
+
+	list_for_each_entry_safe(t_alg, n, &priv->alg_list, entry) {
+		switch (t_alg->algt.type) {
+		case CRYPTO_ALG_TYPE_ABLKCIPHER:
+		case CRYPTO_ALG_TYPE_AEAD:
+			crypto_unregister_alg(&t_alg->algt.alg.crypto);
+			break;
+		case CRYPTO_ALG_TYPE_AHASH:
+			crypto_unregister_ahash(&t_alg->algt.alg.hash);
+			break;
+		}
+		list_del(&t_alg->entry);
+		kfree(t_alg);
+	}
+
+	for (i = 0; i < priv->num_channels; i++)
+		kfree(priv->chan[i].fifo);
+
+	kfree(priv->chan);
+
+	if (priv->irq != 0)
+		free_irq(priv->irq, dev);
+
+	tasklet_kill(&priv->done_task);
+
+	iounmap(priv->reg);
+
+	dev_set_drvdata(dev, NULL);
+
+	kfree(priv);
+
+	return 0;
+}
+
+static struct talitos_crypto_alg *talitos_alg_alloc(struct device *dev,
+						    struct talitos_alg_template
+							*template)
+{
+	struct talitos_private *priv = dev_get_drvdata(dev);
+	struct talitos_crypto_alg *t_alg;
+	struct crypto_alg *alg;
+
+	t_alg = kzalloc(sizeof(struct talitos_crypto_alg), GFP_KERNEL);
+	if (!t_alg)
+		return ERR_PTR(-ENOMEM);
+
+	t_alg->algt = *template;
+
+	switch (t_alg->algt.type) {
+	case CRYPTO_ALG_TYPE_ABLKCIPHER:
+		alg = &t_alg->algt.alg.crypto;
+		alg->cra_init = talitos_cra_init;
+		break;
+	case CRYPTO_ALG_TYPE_AHASH:
+		alg = &t_alg->algt.alg.hash.halg.base;
+		alg->cra_init = talitos_cra_init_ahash;
+		if (!(priv->features & TALITOS_FTR_SHA224_HWINIT) &&
+		    !strcmp(alg->cra_name, "sha224")) {
+			t_alg->algt.alg.hash.init = ahash_init_sha224_swinit;
+			t_alg->algt.desc_hdr_template =
+					DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
+					DESC_HDR_SEL0_MDEU |
+					DESC_HDR_MODE0_MDEU_SHA256;
+		}
+		break;
+	default:
+		dev_err(dev, "unknown algorithm type %d\n", t_alg->algt.type);
+		return ERR_PTR(-EINVAL);
+	}
+
+	alg->cra_module = THIS_MODULE;
+	alg->cra_priority = TALITOS_CRA_PRIORITY;
+	alg->cra_alignmask = 0;
+	alg->cra_ctxsize = sizeof(struct talitos_ctx);
+
+	t_alg->dev = dev;
+
+	return t_alg;
+}
+
+static int __devinit talitos_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct talitos_private *priv;
+	int prop;
+	struct resource *r;
+	int i, err;
+
+	priv = kzalloc(sizeof(struct talitos_private), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, priv);
+
+	priv->pdev = pdev;
+
+	tasklet_init(&priv->done_task, talitos_done, (unsigned long)dev);
+
+	INIT_LIST_HEAD(&priv->alg_list);
+
+	priv->irq = 64 + ISC_SEC;
+	/* get the irq line */
+	err = request_irq(priv->irq, talitos_interrupt, IRQF_DISABLED,
+			dev_driver_string(dev), dev);
+	if (err) {
+		dev_err(dev, "failed to request irq %d\n", priv->irq);
+		goto err_out;
+	} else
+		MCF_ICR(ISC_SEC) = ILP_SEC;
+
+
+	/* get a pointer to the register memory */
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	priv->reg = ioremap(r->start, (r->end - r->start));
+	if (!priv->reg)
+		dev_err(dev, "failed to ioremap\n");
+
+	/* get SEC version capabilities from device tree */
+	prop = in_be32(priv->reg + TALITOS_ID);
+	if (prop & TALITOS_ID_SEC_1_1) {
+		priv->num_channels = TALITOS_NCHANNELS_SEC_1_1;
+		priv->chfifo_len = TALITOS_CHFIFOLEN_SEC_1_1;
+		priv->exec_units = TALITOS_HAS_EUS_SEC_1_1;
+		priv->desc_types = TALITOS_HAS_DESCTYPES_SEC_1_1;
+	} else {
+		dev_err(dev, "failed to id device\n");
+		goto err_out;
+	}
+
+	priv->chan = kzalloc(sizeof(struct talitos_channel) *
+			     priv->num_channels, GFP_KERNEL);
+	if (!priv->chan) {
+		dev_err(dev, "failed to allocate channel management space\n");
+		err = -ENOMEM;
+		goto err_out;
+	}
+
+	for (i = 0; i < priv->num_channels; i++) {
+		spin_lock_init(&priv->chan[i].head_lock);
+		spin_lock_init(&priv->chan[i].tail_lock);
+	}
+
+	priv->fifo_len = roundup_pow_of_two(priv->chfifo_len);
+
+	for (i = 0; i < priv->num_channels; i++) {
+		priv->chan[i].fifo = kzalloc(sizeof(struct talitos_request) *
+					     priv->fifo_len, GFP_KERNEL);
+		if (!priv->chan[i].fifo) {
+			dev_err(dev, "failed to allocate request fifo %d\n", i);
+			err = -ENOMEM;
+			goto err_out;
+		}
+	}
+
+	for (i = 0; i < priv->num_channels; i++)
+		atomic_set(&priv->chan[i].submit_count,
+			-(priv->chfifo_len - 1));
+
+	dma_set_mask(dev, DMA_BIT_MASK(36));
+
+	/* reset and initialize the h/w */
+	err = init_device(dev);
+	if (err) {
+		dev_err(dev, "failed to initialize device\n");
+		goto err_out;
+	}
+
+	/* register crypto algorithms the device supports */
+	for (i = 0; i < ARRAY_SIZE(driver_algs); i++) {
+		if (hw_supports(dev, driver_algs[i].desc_hdr_template)) {
+			struct talitos_crypto_alg *t_alg;
+			char *name = NULL;
+
+			t_alg = talitos_alg_alloc(dev, &driver_algs[i]);
+			if (IS_ERR(t_alg)) {
+				err = PTR_ERR(t_alg);
+				goto err_out;
+			}
+
+			switch (t_alg->algt.type) {
+			case CRYPTO_ALG_TYPE_ABLKCIPHER:
+			case CRYPTO_ALG_TYPE_AEAD:
+				err = crypto_register_alg(
+						&t_alg->algt.alg.crypto);
+				name = t_alg->algt.alg.crypto.cra_driver_name;
+				break;
+			case CRYPTO_ALG_TYPE_AHASH:
+				err = crypto_register_ahash(
+						&t_alg->algt.alg.hash);
+				name =
+				t_alg->algt.alg.hash.halg.base.cra_driver_name;
+				break;
+			}
+			if (err) {
+				dev_err(dev, "%s alg registration failed\n",
+					name);
+				kfree(t_alg);
+			} else {
+				list_add_tail(&t_alg->entry, &priv->alg_list);
+				dev_info(dev, "%s\n", name);
+			}
+		}
+	}
+
+	return 0;
+
+err_out:
+	talitos_remove(pdev);
+
+	return err;
+}
+
+static struct platform_driver talitos_driver = {
+	.driver = {
+		.name = "talitos",
+		.owner = THIS_MODULE,
+	},
+	.probe = talitos_probe,
+	.remove = talitos_remove,
+};
+
+static int __init talitos_init(void)
+{
+	return platform_driver_register(&talitos_driver);
+}
+module_init(talitos_init);
+
+static void __exit talitos_exit(void)
+{
+	platform_driver_unregister(&talitos_driver);
+}
+module_exit(talitos_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Kim Phillips <kim.phillips@freescale.com>");
+MODULE_DESCRIPTION("Freescale integrated security engine (SEC) driver");
--- /dev/null
+++ b/drivers/crypto/cf_talitos.h
@@ -0,0 +1,229 @@
+/*
+ * Freescale Coldfire SEC (talitos) device dependent data structures
+ *
+ * Copyright 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+/* device ID register values */
+#define TALITOS_ID_SEC_1_1	(0x09000000)  /* MCF547x and MCF548x */
+
+/*
+ * following num_channels, channel-fifo-depth, exec-unit-mask, and
+ * descriptor-types-mask are for forward-compatibility with openfirmware
+ * flat device trees
+ */
+
+/*
+ *  num_channels : the number of channels available in each SEC version.
+ */
+
+/* n.b. this driver requires these values be a power of 2 */
+#define TALITOS_NCHANNELS_SEC_1_1       2
+
+/*
+ *  channel-fifo-depth : The number of descriptor
+ *  pointers a channel fetch fifo can hold.
+ */
+#define TALITOS_CHFIFOLEN_SEC_1_1       1
+
+/* the corresponding masks for each SEC version */
+#define TALITOS_HAS_EUS_SEC_1_1		0x7
+
+/* the corresponding masks for each SEC version */
+#define TALITOS_HAS_DESCTYPES_SEC_1_1   0xf
+
+/*
+ * a TALITOS_xxx_HI address points to the low data bits (32-63) of the register
+ */
+/* global register offset addresses */
+/* EU Assaginment controller register is useless*/
+#define TALITOS_EUACR           0x1000
+#define TALITOS_EUACR_LO        0x1004
+
+#define TALITOS_IMR		0x1008		/* interrupt mask register */
+#define TALITOS_IMR_ALL		0xf8000000	/* enable all interrupts mask */
+#define TALITOS_IMR_ERR		0xa8000000	/* mask error interrupts */
+#define TALITOS_IMR_DONE	0x50000000      /* mask done interrupts */
+#define TALITOS_IMR_LO		0x100C		/* interrupt mask register */
+/* mask all channel interrupts mask */
+#define TALITOS_IMR_LO_ALL	0x03333340
+#define TALITOS_IMR_LO_ERR	0x02222240	/* mask error interrupts */
+#define TALITOS_IMR_LO_DONE	0x01111100      /* mask done interrupts */
+
+#define TALITOS_ISR		0x1010		/* interrupt status register */
+#define TALITOS_ISR_CHERR	0xa8000000	/* errors mask */
+#define TALITOS_ISR_CHDONE	0x50000000	/* channel(s) done mask */
+#define TALITOS_ISR_LO		0x1014		/* interrupt status register */
+
+#define TALITOS_ICR		0x1018		/* interrupt clear register */
+#define TALITOS_ICR_CHERR	0xa8000000	/* errors enable */
+#define TALITOS_ICR_CHDONE	0x50000000	/* channel(s) done enable */
+#define TALITOS_ICR_LO		0x101C		/* interrupt clear register */
+#define TALITOS_ICR_LO_CHERR	0x02222240	/* errors enable */
+#define TALITOS_ICR_LO_CHDONE	0x01111100	/* channel(s) done enable */
+
+#define TALITOS_ID              0x1020
+
+/* EU Assaginment status register is useless*/
+#define TALITOS_EUASR           0x1028
+#define TALITOS_EUASR_LO        0x102C
+
+#define TALITOS_MCR             0x1030          /* master control register */
+#define TALITOS_MCR_SWR         0x01000000
+
+#define TALITOS_MEAR		0x1038
+
+/* channel register address stride */
+#define TALITOS_CH_STRIDE	0x1000
+
+/* channel register offset addresses and bits */
+#define TALITOS_CCCR(ch)	(ch * TALITOS_CH_STRIDE + 0x200c)
+#define TALITOS_CCCR_RESET   0x1     /* Channel Reset bit */
+#define TALITOS_CCCR_CDWE    0x10    /* Channel done writeback enable bit */
+#define TALITOS_CCCR_NE      0x8     /* Fetch Next Descriptor Enable bit */
+#define TALITOS_CCCR_NT      0x4     /* Notification type bit */
+#define TALITOS_CCCR_CDIE    0x2     /* Channel Done Interrupt Enable bit */
+
+/* Crypto-Channel Pointer Status Reg */
+#define TALITOS_CCPSR(ch)	(ch * TALITOS_CH_STRIDE + 0x2010)
+#define TALITOS_CCPSR_LO(ch)	(ch * TALITOS_CH_STRIDE + 0x2014)
+#define TALITOS_CCPSR_LO_TEA	0x2000	/* Transfer error acknowledge */
+#define TALITOS_CCPSR_LO_PERR	0x1000	/* Pointer not complete error */
+#define TALITOS_CCPSR_LO_DERR	0x400	/* Descriptor error */
+#define TALITOS_CCPSR_LO_SERR	0x200	/* Static assignment error */
+#define TALITOS_CCPSR_LO_EUERR	0x100	/* EU error */
+
+/* channel fetch fifo register */
+#define TALITOS_FF(ch)		(ch * TALITOS_CH_STRIDE + 0x204c)
+
+/* Crypto-Channel Pointer Status Reg */
+#define TALITOS_CDPR(ch)	(ch * TALITOS_CH_STRIDE + 0x2044)
+
+/* Descriptor Buffer (debug) 0x2080-0x20BF*/
+#define TALITOS_DESCBUF(ch)	(ch * TALITOS_CH_STRIDE + 0x2080)
+
+/* execution unit register offset addresses and bits */
+#define TALITOS_DEURCR          0xa018  /* DEU reset control register */
+#define TALITOS_DEURCR_RESET    0x01000000  /* DEU reset bit */
+#define TALITOS_DEUSR		0xa028	/* DEU status register */
+#define TALITOS_DEUSR_RESET     0x01000000  /* DEU Reset status bit */
+#define TALITOS_DEUISR		0xa030	/* DEU interrupt status register */
+#define TALITOS_DEUIMR		0xa038	/* DEU interrupt mask register */
+#define TALITOS_DEUIMR_MASK     0xf63f0000  /* DEU interrupt control mask*/
+#define TALITOS_DEUIMR_KPE_MASK	0x00200000  /* DEU interrupt KPE mask*/
+
+#define TALITOS_AESURCR         0x12018  /* AESU reset control register */
+#define TALITOS_AESURCR_RESET   0x01000000  /* AESU reset bit */
+#define TALITOS_AESUSR          0x12028  /* AESU status register */
+#define TALITOS_AESUSR_RESET    0x01000000  /* AESU Reset status bit */
+#define TALITOS_AESUISR         0x12030  /* AESU interrupt status register */
+#define TALITOS_AESUIMR         0x12038  /* AESU interrupt mask register */
+#define TALITOS_AESUIMR_MASK    0xf61f0000  /* AESU interrupt control mask*/
+
+#define TALITOS_MDEURCR         0xc018  /* MDEU reset control register */
+#define TALITOS_MDEURCR_RESET   0x01000000  /* MDEU reset bit */
+#define TALITOS_MDEUSR          0xc028  /* MDEU status register */
+#define TALITOS_MDEUSR_RESET    0x01000000  /* MDEU Reset status bit */
+#define TALITOS_MDEUISR         0xc030  /* MDEU interrupt status register */
+#define TALITOS_MDEUIMR         0xc038  /* MDEU interrupt mask register */
+#define TALITOS_MDEUIMR_MASK    0xc41f0000  /* MDEU interrupt control mask*/
+
+#define TALITOS_AFEURCR         0x8018  /* AFEU reset control register */
+#define TALITOS_AFEURCR_RESET   0x01000000  /* AFEU reset bit */
+#define TALITOS_AFEUSR          0x8028  /* AFEU status register */
+#define TALITOS_AFEUSR_RESET    0x01000000  /* AFEU Reset status bit */
+#define TALITOS_AFEUISR         0x8030  /* AFEU interrupt status register */
+#define TALITOS_AFEUIMR         0x8038  /* AFEU interrupt mask register */
+#define TALITOS_AFEUIMR_MASK    0xf61f0000  /* AFEU interrupt control mask*/
+
+#define TALITOS_RNGRCR          0xe018  /* RNG Reset control register */
+#define TALITOS_RNGRCR_SR       0x01000000      /* RNG RNGRCR:Software Reset */
+#define TALITOS_RNGSR		0xe028	/* RNG status register */
+#define TALITOS_RNGSR_RD	0x01000000	/* RNG Reset done */
+#define TALITOS_RNGISR		0xe030	/* RNG Interrupt status register */
+#define TALITOS_RNGIMR          0xe038  /* RNG interrupt mask register */
+#define TALITOS_RNGIMR_MASK     0xc2100000  /* RNG interrupt control mask*/
+
+#define TALITOS_MDEU_CONTEXT_SIZE_MD5_SHA1_SHA256       0x28
+#define TALITOS_MDEU_CONTEXT_SIZE_SHA384_SHA512         0x48
+
+/***************************RC4*******************/
+#define ARC4_SEC_MIN_KEY_SIZE   5
+#define ARC4_SEC_MAX_KEY_SIZE   16
+#define ARC4_SEC_CONTEXT_LEN    259
+#define SEC_ALG_AFEU_KEY              0x10200050
+#define SEC_ALG_AFEU_CONTEXT          0x10700050
+
+/* talitos descriptor header (hdr) bits */
+
+/* primary execution unit select */
+#define	DESC_HDR_SEL0_MASK	0xf0000000
+#define	DESC_HDR_SEL0_AFEU	0x10000000
+#define	DESC_HDR_SEL0_DEU	0x20000000
+#define	DESC_HDR_SEL0_MDEU	0x30000000
+#define	DESC_HDR_SEL0_RNG	0x40000000
+#define	DESC_HDR_SEL0_AESU	0x60000000
+
+/* primary execution unit mode (MODE0) and derivatives */
+#define	DESC_HDR_MODE0_MASK		0x0ff00000
+#define	DESC_HDR_MODE0_ENCRYP		0x00100000
+#define	DESC_HDR_MODE0_AFEU_USE_KEY	0x00200000
+#define	DESC_HDR_MODE0_AFEU_USE_CONTEXT	0x00700000
+#define	DESC_HDR_MODE0_AESU_CBC		0x00200000
+#define	DESC_HDR_MODE0_AESU_ENC		0x00100000
+#define	DESC_HDR_MODE0_DEU_CBC		0x00400000
+#define	DESC_HDR_MODE0_DEU_3DES		0x00200000
+#define	DESC_HDR_MODE0_DEU_ENC		0x00100000
+#define	DESC_HDR_MODE0_MDEU_CONT	0x08000000
+#define	DESC_HDR_MODE0_MDEU_INIT	0x01000000	/* init starting regs */
+#define	DESC_HDR_MODE0_MDEU_HMAC	0x00800000
+#define	DESC_HDR_MODE0_MDEU_PAD		0x00400000	/* PD */
+#define	DESC_HDR_MODE0_MDEU_MD5		0x00200000
+#define	DESC_HDR_MODE0_MDEU_SHA256	0x00100000
+#define	DESC_HDR_MODE0_MDEU_SHA1	0x00000000	/* SHA-160 */
+#define	DESC_HDR_MODE0_MDEU_MD5_HMAC	\
+		(DESC_HDR_MODE0_MDEU_MD5 | DESC_HDR_MODE0_MDEU_HMAC)
+#define	DESC_HDR_MODE0_MDEU_SHA256_HMAC	\
+		(DESC_HDR_MODE0_MDEU_SHA256 | DESC_HDR_MODE0_MDEU_HMAC)
+#define	DESC_HDR_MODE0_MDEU_SHA1_HMAC	\
+		(DESC_HDR_MODE0_MDEU_SHA1 | DESC_HDR_MODE0_MDEU_HMAC)
+
+/* secondary execution unit select (SEL1) */
+/* it's MDEU or nothing */
+#define	DESC_HDR_SEL1_MASK	0x000f0000
+#define	DESC_HDR_SEL1_MDEU	0x00030000
+
+/* secondary execution unit mode (MODE1) and derivatives */
+#define	DESC_HDR_MODE1_MDEU_INIT	0x00001000	/* init starting regs */
+#define	DESC_HDR_MODE1_MDEU_HMAC	0x00000800
+#define	DESC_HDR_MODE1_MDEU_PAD		0x00000400	/* PD */
+#define	DESC_HDR_MODE1_MDEU_MD5		0x00000200
+#define	DESC_HDR_MODE1_MDEU_SHA256	0x00000100
+#define	DESC_HDR_MODE1_MDEU_SHA1	0x00000000	/* SHA-160 */
+#define	DESC_HDR_MODE1_MDEU_MD5_HMAC	\
+	(DESC_HDR_MODE1_MDEU_MD5 | DESC_HDR_MODE1_MDEU_HMAC)
+#define	DESC_HDR_MODE1_MDEU_SHA256_HMAC	\
+	(DESC_HDR_MODE1_MDEU_SHA256 | DESC_HDR_MODE1_MDEU_HMAC)
+#define	DESC_HDR_MODE1_MDEU_SHA1_HMAC	\
+	(DESC_HDR_MODE1_MDEU_SHA1 | DESC_HDR_MODE1_MDEU_HMAC)
+
+/* direction of overall data flow (DIR) */
+#define	DESC_HDR_DIR_OUTBOUND	0x00000000
+#define	DESC_HDR_DIR_INBOUND	0x00000002
+
+/* done notification (DN) */
+#define	DESC_HDR_DONE		0x00000001
+
+/* descriptor types */
+#define DESC_HDR_TYPE_AESU_CTR_NONSNOOP         (0 << 4)
+#define DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU	(1 << 4)
+#define DESC_HDR_TYPE_HMAC_SNOOP_NO_AFEU	(2 << 4)
+#define DESC_HDR_TYPE_NONHMAC_SNOOP_NO_AFEU	(3 << 4)
+#define DESC_HDR_TYPE_COMMON_NONSNOOP_AFEU	(5 << 4)
+
+#define TALITOS_HDR_DONE_BITS	0xff000000
