From 0419eb27af72bd37c3ef926169fe4db90e8690d3 Mon Sep 17 00:00:00 2001
From: Alison Wang <b18965@freescale.com>
Date: Thu, 4 Aug 2011 09:59:41 +0800
Subject: [PATCH 11/52] Add CAU driver for MCF5445x and MCF5441x

Add CAU driver support for MCF5445x and MCF5441x.

Signed-off-by: Alison Wang <b18965@freescale.com>
---
 crypto/testmgr.c             |   13 +-
 drivers/crypto/Kconfig       |   65 +++
 drivers/crypto/Makefile      |    5 +
 drivers/crypto/mcfcau-aes.c  |  367 ++++++++++++++++
 drivers/crypto/mcfcau-des.c  |  525 +++++++++++++++++++++++
 drivers/crypto/mcfcau-md5.c  |  972 ++++++++++++++++++++++++++++++++++++++++++
 drivers/crypto/mcfcau-sha1.c |  331 ++++++++++++++
 drivers/crypto/mcfcau.c      |   33 ++
 drivers/crypto/mcfcau.h      |  101 +++++
 9 files changed, 2410 insertions(+), 2 deletions(-)
 create mode 100644 drivers/crypto/mcfcau-aes.c
 create mode 100644 drivers/crypto/mcfcau-des.c
 create mode 100644 drivers/crypto/mcfcau-md5.c
 create mode 100644 drivers/crypto/mcfcau-sha1.c
 create mode 100644 drivers/crypto/mcfcau.c
 create mode 100644 drivers/crypto/mcfcau.h

--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -705,6 +705,7 @@ static int test_cipher(struct crypto_cip
 	else
 		e = "decryption";
 
+	printk(KERN_INFO "%s testing %s %s\n", __func__, algo, e);
 	j = 0;
 	for (i = 0; i < tcount; i++) {
 		if (template[i].np)
@@ -750,7 +751,9 @@ static int test_cipher(struct crypto_cip
 			hexdump(q, template[i].rlen);
 			ret = -EINVAL;
 			goto out;
-		}
+		} else
+			printk(KERN_INFO "alg: cipher: Test %d pass "
+				"on %s for %s\n", j, e, algo);
 	}
 
 	ret = 0;
@@ -785,6 +788,7 @@ 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);
@@ -863,10 +867,13 @@ static int test_skcipher(struct crypto_a
 				hexdump(q, template[i].rlen);
 				ret = -EINVAL;
 				goto out;
-			}
+			} else
+				printk(KERN_INFO "alg: skcipher: Test %d "
+					"pass on %s for %s\n", j, e, algo);
 		}
 	}
 
+	printk(KERN_INFO "\ntesting %s %s across pages (chunking)\n", algo, e);
 	j = 0;
 	for (i = 0; i < tcount; i++) {
 
@@ -2514,6 +2521,8 @@ int alg_test(const char *driver, const c
 	int j;
 	int rc;
 
+	printk(KERN_INFO  "\ntesting %s\n", alg);
+
 	if ((type & CRYPTO_ALG_TYPE_MASK) == CRYPTO_ALG_TYPE_CIPHER) {
 		char nalg[CRYPTO_MAX_ALG_NAME];
 
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -61,6 +61,71 @@ config CRYPTO_DEV_GEODE
 	  To compile this driver as a module, choose M here: the module
 	  will be called geode-aes.
 
+config CRYPTO_DEV_MCFCAU
+	bool "Support for Freescale Coldfire Cryptographic Acceleration Unit (CAU)"
+	depends on M5445X || M5441X
+	select CRYPTO_ALGAPI
+	help
+	  The cryptographic acceleration unit (CAU) is a ColdFire coprocessor
+	  implementing a set of specialized operations in hardware. For example,
+	  you can find it on MCF5445X, or M5441X.
+
+	  Say Y here if you want to use CAU.
+
+config CRYPTO_DEV_MCFCAU_DES
+	tristate "DES and Triple DES cipher algorithms (coldfire)"
+	depends on CRYPTO_DEV_MCFCAU
+	select CRYPTO_ALGAPI
+	select CRYPTO_BLKCIPHER
+	help
+	  DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3).
+
+	  Say 'Y' here to use the CAU coprocessor for
+	  the CryptoAPI DES and 3DES alogrithms.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called mcfcau-des.
+
+config CRYPTO_DEV_MCFCAU_AES
+	tristate "AES cipher algorithm (coldfire)"
+	depends on CRYPTO_DEV_MCFCAU
+	select CRYPTO_ALGAPI
+	select CRYPTO_BLKCIPHER
+	help
+	  AES cipher algorithm (FIPS 197).
+
+	  Say 'Y' here to use the CAU coprocessor for
+	  the CryptoAPI AES alogrithm.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called mcfcau-aes.
+
+config CRYPTO_DEV_MCFCAU_MD5
+	tristate "MD5 digest algorithm (coldfire)"
+	depends on CRYPTO_DEV_MCFCAU
+	select CRYPTO_ALGAPI
+	help
+	  MD5 message digest algorithm (RFC1321).
+
+	  Say 'Y' here to use the CAU coprocessor for
+	  the CryptoAPI MD5 alogrithm.
+
+	  To compile this driver as a module, choose M here:
+	  the module will be called mcfcau-md5.
+
+config CRYPTO_DEV_MCFCAU_SHA1
+	tristate "SHA1 digest algorithm (coldfire)"
+	depends on CRYPTO_DEV_MCFCAU
+	select CRYPTO_ALGAPI
+	help
+	  SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
+
+	  Say 'Y' here to use the CAU coprocessor for
+	  the CryptoAPI SHA1 alogrithm.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called mcfcau-sha1.
+
 config ZCRYPT
 	tristate "Support for PCI-attached cryptographic adapters"
 	depends on S390
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -7,6 +7,11 @@ obj-$(CONFIG_CRYPTO_DEV_HIFN_795X) += hi
 obj-$(CONFIG_CRYPTO_DEV_MV_CESA) += mv_cesa.o
 obj-$(CONFIG_CRYPTO_DEV_TALITOS) += 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
+obj-$(CONFIG_CRYPTO_DEV_MCFCAU_AES) += mcfcau-aes.o
+obj-$(CONFIG_CRYPTO_DEV_MCFCAU_MD5) += mcfcau-md5.o
+obj-$(CONFIG_CRYPTO_DEV_MCFCAU_SHA1) += mcfcau-sha1.o
 obj-$(CONFIG_CRYPTO_DEV_PPC4XX) += amcc/
 obj-$(CONFIG_CRYPTO_DEV_OMAP_SHAM) += omap-sham.o
 obj-$(CONFIG_CRYPTO_DEV_OMAP_AES) += omap-aes.o
--- /dev/null
+++ b/drivers/crypto/mcfcau-aes.c
@@ -0,0 +1,367 @@
+/***************************************************************************
+ * mcfcau-aes.c - Implementation of AES Cipher Algorithm
+ *                for Freescale ColdFire Cryptographic Acceleration Unit (CAU).
+ *
+ * Copyright (C) 2007-2011 Freescale Semiconductor Inc. All Rights Reserved.
+ * Author: Andrey Butok
+ *         Shrek Wu B16972@freescale.com
+ *
+ * NOTE: You can find the ColdFire CAU module on MCF5445X and MCF52235.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ ***************************************************************************
+ * Changes:
+ * v0.01	17 September 2007	Andrey Butok
+ *		Initial Release - developed on 2.6.20 Linux kernel.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/crypto.h>
+
+/*
+#undef DEBUG
+#define DEBUG 1
+*/
+
+#include "mcfcau.h"
+
+#define MCFCAU_AES_MIN_KEY_SIZE	(16)
+#define MCFCAU_AES_MAX_KEY_SIZE	(32)
+#define MCFCAU_AES_BLOCK_SIZE	(16)
+
+#define	MCFCAU_AES_DRIVER_DESC		"AES ColdFire CAU driver"
+#define	MCFCAU_AES_DRIVER_VERSION	"v0.01"
+
+struct mcfcau_aes_ctx {
+	int Nr_1;
+	u32 buf[120];
+	u32 buf_tmp[16];
+};
+
+static u32 mcfcau_rco_tab[10]
+	= { 0x01000000, 0x02000000, 0x04000000, 0x08000000,
+	0x10000000, 0x20000000, 0x40000000, 0x80000000,
+	0x1b000000, 0x36000000};
+
+int mcfcau_aes_setkey(struct crypto_tfm *tfm, const u8 *in_key,
+		       unsigned int key_len)
+{
+	struct mcfcau_aes_ctx *ctx = crypto_tfm_ctx(tfm);
+	const u32 *key = (const u32 *)in_key;
+	u32 *flags = &tfm->crt_flags;
+	u32 i;
+	u32 *key_sch = (&ctx->buf[0]);
+	u32 *temp_p, *rcon_p;
+	u32 Nx;
+	u32 Nk;
+	unsigned long iflags;
+
+	DBG("mcfcau_aes_setkey\n");
+
+	if (key_len % 8) {
+		*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+		return -EINVAL;
+	}
+
+	Nk = key_len>>2;
+
+	for (i = 0; i < Nk; i++)
+		key_sch[i] = key[i];
+
+	ctx->Nr_1 = Nk+5;
+
+	/* Key Expansion */
+	temp_p = &key_sch[Nk-1];
+	rcon_p = &mcfcau_rco_tab[0];
+
+	spin_lock_irqsave(&mcfcau_lock, iflags);
+
+	asm volatile ("move.l	%0, %%a1"
+		: : "m"(temp_p) : "a1");
+	asm volatile ("move.l	%0, %%a3"
+		: : "m"(rcon_p) : "a3");
+	asm volatile ("move.l	%0, %%a4"
+		: : "m"(key_sch) : "a4");
+
+	Nx = (Nk+7)<<2; /* (Nr+1)*Nb */
+
+	for (i = Nk; i < Nx; i++) {
+		/* temp = key_sch[Nk-1] */
+		asm volatile ("cp0ld.l	(%%a1)+,%%d0,#1,%0"
+			: : "n"(MCFCAU_LDR+MCFCAU_CAA) : "a1");
+
+		if (i % Nk == 0) {
+			asm volatile ("moveq	#8, %%d0" : : : "d0");
+			/* CAA=RotWord(temp) */
+			asm volatile ("cp0ld.l	%%d0,%%d0,#1,%0"
+				: : "n"(MCFCAU_ROTL+MCFCAU_CAA) : "d0");
+			/* SubWord(CAA) */
+			asm volatile ("cp0ld.l	%%d0,%%d0,#1,%0"
+				: : "n"(MCFCAU_AESS+MCFCAU_CAA));
+			/* ACC xor rcon[i/Nk] */
+			asm volatile ("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+				: : "n"(MCFCAU_XOR+MCFCAU_CAA) : "a3");
+
+		} else if ((Nk > 6) && (i % Nk == 4)) {
+			/* SubWord(ACC) */
+			asm volatile ("cp0ld.l	%%d0,%%d0,#1,%0"
+				: : "n"(MCFCAU_AESS+MCFCAU_CAA));
+		}
+
+		/* key_sch[i]^=key_sch[i-Nk]; store ACC to key_sch[i] */
+		asm volatile ("cp0ld.l	(%%a4)+,%%d0,#1,%0"
+			: : "n"(MCFCAU_XOR+MCFCAU_CAA) : "a4");
+		asm volatile ("cp0st.l	%%d0,(%%a1),#1,%0"
+			: : "n"(MCFCAU_STR+MCFCAU_CAA));
+	}
+	spin_unlock_irqrestore(&mcfcau_lock, iflags);
+
+	return 0;
+}
+
+
+/* encrypt a block of text */
+static void mcfcau_aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+{
+	struct mcfcau_aes_ctx *ctx = crypto_tfm_ctx(tfm);
+	const int Nr_1 = ctx->Nr_1;
+
+	u32 *key_sch = &(ctx->buf[0]);
+	u32 i;
+	unsigned long iflags;
+
+	DBG("mcfcau_aes_encrypt\n");
+
+	spin_lock_irqsave(&mcfcau_lock, iflags);
+	asm("move.l	%0, %%a1" : : "m"(in) : "a1");
+	asm("move.l	%0, %%a0" : : "m"(key_sch) : "a0");
+	/* state=in */
+	asm("cp0ld.l	(%%a1)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_LDR+MCFCAU_CA0) : "a1");
+	asm("cp0ld.l	(%%a1)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_LDR+MCFCAU_CA1) : "a1");
+	asm("cp0ld.l	(%%a1)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_LDR+MCFCAU_CA2) : "a1");
+	asm("cp0ld.l	(%%a1)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_LDR+MCFCAU_CA3) : "a1");
+	/* AddRoundKey() */
+	asm("cp0ld.l	(%%a0)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_XOR+MCFCAU_CA0) : "a0");
+	asm("cp0ld.l	(%%a0)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_XOR+MCFCAU_CA1) : "a0");
+	asm("cp0ld.l	(%%a0)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_XOR+MCFCAU_CA2) : "a0");
+	asm("cp0ld.l	(%%a0)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_XOR+MCFCAU_CA3) : "a0");
+
+	for (i = Nr_1; i > 0; i--) {
+		/* SubBytes(state) */
+		asm("cp0ld.l	%%d0,%%d0,#1,%0"
+			: : "n"(MCFCAU_AESS+MCFCAU_CA0));
+		asm("cp0ld.l	%%d0,%%d0,#1,%0"
+			: : "n"(MCFCAU_AESS+MCFCAU_CA1));
+		asm("cp0ld.l	%%d0,%%d0,#1,%0"
+			: : "n"(MCFCAU_AESS+MCFCAU_CA2));
+		asm("cp0ld.l	%%d0,%%d0,#1,%0"
+			: : "n"(MCFCAU_AESS+MCFCAU_CA3));
+		/* ShiftRows(state) */
+		asm("cp0ld.l	%%d0,%%d0,#1,%0" : : "n"(MCFCAU_AESR));
+		/* MixColumns(state); AddRoundKey() */
+		asm("cp0ld.l	(%%a0)+,%%d0,#1,%0"
+			: : "n"(MCFCAU_AESC+MCFCAU_CA0) : "a0");
+		asm("cp0ld.l	(%%a0)+,%%d0,#1,%0"
+			: : "n"(MCFCAU_AESC+MCFCAU_CA1) : "a0");
+		asm("cp0ld.l	(%%a0)+,%%d0,#1,%0"
+			: : "n"(MCFCAU_AESC+MCFCAU_CA2) : "a0");
+		asm("cp0ld.l	(%%a0)+,%%d0,#1,%0"
+			: : "n"(MCFCAU_AESC+MCFCAU_CA3) : "a0");
+	}
+	/* SubBytes(state)*/
+	asm("cp0ld.l	%%d0,%%d0,#1,%0" : : "n"(MCFCAU_AESS+MCFCAU_CA0));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0" : : "n"(MCFCAU_AESS+MCFCAU_CA1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0" : : "n"(MCFCAU_AESS+MCFCAU_CA2));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0" : : "n"(MCFCAU_AESS+MCFCAU_CA3));
+	/* ShiftRows(state) */
+	asm("cp0ld.l	%%d0,%%d0,#1,%0" : : "n"(MCFCAU_AESR));
+	/* AddRoundKey() */
+	asm("cp0ld.l	(%%a0)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_XOR+MCFCAU_CA0) : "a0");
+	asm("cp0ld.l	(%%a0)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_XOR+MCFCAU_CA1) : "a0");
+	asm("cp0ld.l	(%%a0)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_XOR+MCFCAU_CA2) : "a0");
+	asm("cp0ld.l	(%%a0)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_XOR+MCFCAU_CA3) : "a0");
+	/* out = state */
+	asm("move.l	%0, %%a1" : : "m"(out) : "a1");
+	asm("cp0st.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_STR+MCFCAU_CA0) : "d0");
+	asm("cp0st.l	%%d0,%%d1,#1,%0"
+		: : "n"(MCFCAU_STR+MCFCAU_CA1) : "d1");
+
+	asm("move.l	%%d0,(%%a1)+" : : : "a1");
+	asm("move.l	%%d1,(%%a1)+" : : : "a1");
+
+	asm("cp0st.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_STR+MCFCAU_CA2) : "d0");
+	asm("cp0st.l	%%d0,%%d1,#1,%0"
+		: : "n"(MCFCAU_STR+MCFCAU_CA3) : "d1");
+
+	asm("move.l	%%d0,(%%a1)+" : : : "a1");
+	asm("move.l	%%d1,(%%a1)+" : : : "a1");
+	spin_unlock_irqrestore(&mcfcau_lock, iflags);
+}
+
+
+/* decrypt a block of text */
+static void mcfcau_aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+{
+	struct mcfcau_aes_ctx *ctx = crypto_tfm_ctx(tfm);
+	u32 *key_sch = &(ctx->buf[0]);
+	u32 i;
+	unsigned long iflags;
+	const int Nr_1 = ctx->Nr_1;
+	key_sch = &key_sch[(Nr_1+2)*4];
+
+	DBG("mcfcau_aes_decrypt\n");
+
+	spin_lock_irqsave(&mcfcau_lock, iflags);
+
+	asm("move.l	%0, %%a1" : : "m"(in) : "a1");
+	asm("move.l	%0, %%a0" : : "m"(key_sch) : "a0");
+	/* state=in */
+	asm("cp0ld.l	(%%a1)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_LDR+MCFCAU_CA0) : "a1");
+	asm("cp0ld.l	(%%a1)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_LDR+MCFCAU_CA1) : "a1");
+	asm("cp0ld.l	(%%a1)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_LDR+MCFCAU_CA2) : "a1");
+	asm("cp0ld.l	(%%a1)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_LDR+MCFCAU_CA3) : "a1");
+	/* AddRoundKey() */
+	asm("cp0ld.l	-(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_XOR+MCFCAU_CA3) : "a0");
+	asm("cp0ld.l	-(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_XOR+MCFCAU_CA2) : "a0");
+	asm("cp0ld.l	-(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_XOR+MCFCAU_CA1) : "a0");
+	asm("cp0ld.l	-(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_XOR+MCFCAU_CA0) : "a0");
+
+	for (i = Nr_1; i > 0; i--) {
+		/* InvShiftRows(state) */
+		asm("cp0ld.l	%%d0,%%d0,#1,%0"
+			: : "n"(MCFCAU_AESIR));
+		/* InvSubBytes(state) */
+		asm("cp0ld.l	%%d0,%%d0,#1,%0"
+			: : "n"(MCFCAU_AESIS+MCFCAU_CA3));
+		asm("cp0ld.l	%%d0,%%d0,#1,%0"
+			: : "n"(MCFCAU_AESIS+MCFCAU_CA2));
+		asm("cp0ld.l	%%d0,%%d0,#1,%0"
+			: : "n"(MCFCAU_AESIS+MCFCAU_CA1));
+		asm("cp0ld.l	%%d0,%%d0,#1,%0"
+			: : "n"(MCFCAU_AESIS+MCFCAU_CA0));
+		/* InvMixColumns(state); AddRoundKey() */
+		asm("cp0ld.l	-(%%a0),%%d0,#1,%0"
+			: : "n"(MCFCAU_AESIC+MCFCAU_CA3) : "a0");
+		asm("cp0ld.l	-(%%a0),%%d0,#1,%0"
+			: : "n"(MCFCAU_AESIC+MCFCAU_CA2) : "a0");
+		asm("cp0ld.l	-(%%a0),%%d0,#1,%0"
+			: : "n"(MCFCAU_AESIC+MCFCAU_CA1) : "a0");
+		asm("cp0ld.l	-(%%a0),%%d0,#1,%0"
+			: : "n"(MCFCAU_AESIC+MCFCAU_CA0) : "a0");
+	}
+	/* InvShiftRows(state) */
+	asm("cp0ld.l	%%d0,%%d0,#1,%0" : : "n"(MCFCAU_AESIR));
+	/* InvSubBytes(state)*/
+	asm("cp0ld.l	%%d0,%%d0,#1,%0" : : "n"(MCFCAU_AESIS+MCFCAU_CA3));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0" : : "n"(MCFCAU_AESIS+MCFCAU_CA2));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0" : : "n"(MCFCAU_AESIS+MCFCAU_CA1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0" : : "n"(MCFCAU_AESIS+MCFCAU_CA0));
+	/* AddRoundKey() */
+	asm("cp0ld.l	-(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_XOR+MCFCAU_CA3) : "a0");
+	asm("cp0ld.l	-(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_XOR+MCFCAU_CA2) : "a0");
+	asm("cp0ld.l	-(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_XOR+MCFCAU_CA1) : "a0");
+	asm("cp0ld.l	-(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_XOR+MCFCAU_CA0) : "a0");
+	/* out = state */
+	asm("move.l	%0, %%a1"	 : : "m"(out) : "a1");
+	asm("cp0st.l	%%d0,%%d0,#1,%0" : : "n"(MCFCAU_STR+MCFCAU_CA0) : "d0");
+	asm("cp0st.l	%%d0,%%d1,#1,%0" : : "n"(MCFCAU_STR+MCFCAU_CA1) : "d1");
+
+	asm("move.l	%%d0,(%%a1)+" : : : "a1");
+	asm("move.l	%%d1,(%%a1)+" : : : "a1");
+
+	asm("cp0st.l	%%d0,%%d0,#1,%0" : : "n"(MCFCAU_STR+MCFCAU_CA2) : "d0");
+	asm("cp0st.l	%%d0,%%d1,#1,%0" : : "n"(MCFCAU_STR+MCFCAU_CA3) : "d1");
+
+	asm("move.l	%%d0,(%%a1)+" : : : "a1");
+	asm("move.l	%%d1,(%%a1)+" : : : "a1");
+	spin_unlock_irqrestore(&mcfcau_lock, iflags);
+
+}
+
+
+static struct crypto_alg mcfcau_aes_alg = {
+	.cra_name		=	"aes",
+	.cra_driver_name	=	"aes-mcfcau",
+	.cra_priority		=	MCFCAU_CRA_PRIORITY,
+	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
+	.cra_blocksize		=	MCFCAU_AES_BLOCK_SIZE,
+	.cra_ctxsize		=	sizeof(struct mcfcau_aes_ctx),
+	.cra_alignmask		=	3,
+	.cra_module		=	THIS_MODULE,
+	.cra_list		=	LIST_HEAD_INIT(mcfcau_aes_alg.cra_list),
+	.cra_u			=	{
+		.cipher = {
+			.cia_min_keysize	=	MCFCAU_AES_MIN_KEY_SIZE,
+			.cia_max_keysize	=	MCFCAU_AES_MAX_KEY_SIZE,
+			.cia_setkey		=	mcfcau_aes_setkey,
+			.cia_encrypt		=	mcfcau_aes_encrypt,
+			.cia_decrypt		=	mcfcau_aes_decrypt
+		}
+	}
+};
+
+static int __init mcfcau_aes_init(void)
+{
+	int ret = crypto_register_alg(&mcfcau_aes_alg);
+
+	printk(KERN_INFO MCFCAU_AES_DRIVER_DESC " "
+		MCFCAU_AES_DRIVER_VERSION " %s.\n",
+		ret ? "failed" : "registered");
+	return ret;
+}
+
+static void __exit mcfcau_aes_fini(void)
+{
+	crypto_unregister_alg(&mcfcau_aes_alg);
+	printk(KERN_INFO MCFCAU_AES_DRIVER_DESC " "
+		MCFCAU_AES_DRIVER_VERSION " unregistered.\n");
+}
+
+module_init(mcfcau_aes_init);
+module_exit(mcfcau_aes_fini);
+
+MODULE_DESCRIPTION(MCFCAU_AES_DRIVER_DESC);
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Andrey Butok");
--- /dev/null
+++ b/drivers/crypto/mcfcau-des.c
@@ -0,0 +1,525 @@
+/***************************************************************************
+ * mcfcau-des.c - Implementation of DES & Triple DES EDE Cipher Algorithms
+ *                for Freescale ColdFire Cryptographic Acceleration Unit (CAU).
+ *
+ * Copyright (C) 2007-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Author: Andrey Butok
+ *         Shrek Wu B16972@freescale.com
+ *
+ * NOTE: You can find the ColdFire CAU module on MCF5445X and MCF52235.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ ***************************************************************************
+ * Changes:
+ * v0.01	14 August 2007	Andrey Butok
+ *		Initial Release - developed on 2.6.20 Linux kernel.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/crypto.h>
+#include <linux/types.h>
+
+/*
+#undef DEBUG
+#define DEBUG 1
+*/
+
+#include "mcfcau.h"
+
+#define MCFCAU_DES_KEY_SIZE		(8)
+#define MCFCAU_DES_EXPKEY_WORDS		(32)
+#define MCFCAU_DES_BLOCK_SIZE		(8)
+
+#define MCFCAU_DES3_EDE_KEY_SIZE	(3 * MCFCAU_DES_KEY_SIZE)
+#define MCFCAU_DES3_EDE_EXPKEY_WORDS	(3 * MCFCAU_DES_EXPKEY_WORDS)
+#define MCFCAU_DES3_EDE_BLOCK_SIZE	(MCFCAU_DES_BLOCK_SIZE)
+
+#define	MCFCAU_DES_DRIVER_DESC		"DES & 3DES ColdFire CAU driver"
+#define	MCFCAU_DES_DRIVER_VERSION	"v0.01"
+
+struct mcfcau_des_ctx {
+	u32 expkey[MCFCAU_DES_EXPKEY_WORDS];
+};
+
+struct mcfcau_des3_ede_ctx {
+	u32 expkey[MCFCAU_DES3_EDE_EXPKEY_WORDS];
+};
+
+/* DES round operations */
+static inline void mcfcau_des_encipher(void)
+{
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_DESK));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_DESR+MCFCAU_IP+MCFCAU_KSL1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_DESR+MCFCAU_KSL2));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_DESR+MCFCAU_KSL2));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_DESR+MCFCAU_KSL2));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_DESR+MCFCAU_KSL2));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_DESR+MCFCAU_KSL2));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_DESR+MCFCAU_KSL2));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_DESR+MCFCAU_KSL1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_DESR+MCFCAU_KSL2));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_DESR+MCFCAU_KSL2));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_DESR+MCFCAU_KSL2));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_DESR+MCFCAU_KSL2));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_DESR+MCFCAU_KSL2));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_DESR+MCFCAU_KSL2));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_DESR+MCFCAU_KSL1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_DESR+MCFCAU_FP+MCFCAU_KSL1));
+}
+
+static inline void mcfcau_des_decipher(void)
+{
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_DESK+MCFCAU_DC));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_DESR+MCFCAU_IP+MCFCAU_KSR1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_DESR+MCFCAU_KSR2));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_DESR+MCFCAU_KSR2));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_DESR+MCFCAU_KSR2));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_DESR+MCFCAU_KSR2));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_DESR+MCFCAU_KSR2));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_DESR+MCFCAU_KSR2));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_DESR+MCFCAU_KSR1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_DESR+MCFCAU_KSR2));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_DESR+MCFCAU_KSR2));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_DESR+MCFCAU_KSR2));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_DESR+MCFCAU_KSR2));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_DESR+MCFCAU_KSR2));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_DESR+MCFCAU_KSR2));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_DESR+MCFCAU_KSR1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_DESR+MCFCAU_FP+MCFCAU_KSL1));
+}
+
+
+static int mcfcau_des_setkey(struct crypto_tfm *tfm, const u8 *key_p,
+		      unsigned int keylen)
+{
+	struct mcfcau_des_ctx *dctx = crypto_tfm_ctx(tfm);
+	u32 *flags = &tfm->crt_flags;
+	u32 * key = (u32 *) key_p;
+
+	DBG("mcfcau_des_setkey\n");
+
+	/*
+	* RFC2451: Weak key checks SHOULD be performed.
+	*
+	* FIPS 74:
+	*   Keys having duals are keys which produce all zeros, all ones, or
+	*   alternating zero-one patterns in the C and D registers
+	*   after Permuted
+	*   Choice 1 has operated on the key.
+	*
+	*/
+	if (*flags & CRYPTO_TFM_REQ_WEAK_KEY) { /* FIPS 74 */
+		if (key[0] < 0xE001E00l) {
+			if (key[0] < 0x1FE01FE0) {
+				if (key[0] < 0x01E001E0) {
+					if (((key[0] == 0x01010101) &&
+						(key[1] == 0x01010101)) ||
+						((key[0] == 0x011F011F) &&
+						(key[1] == 0x010E010E)))
+						goto WEAK_KEY;
+				} else {
+					if (((key[0] == 0x01E001E0) &&
+						(key[1] == 0x01F101F1)) ||
+						((key[0] == 0x01FE01FE) &&
+						(key[1] == 0x01FE01FE)))
+						goto WEAK_KEY;
+				}
+			} else {
+				if (key[0] < 0x1F1F1F1F) {
+					if (((key[0] == 0x1FE01FE0) &&
+						(key[1] == 0x0EF10EF1)) ||
+						((key[0] == 0x1F011F0l) &&
+						(key[1] == 0x0E010E01)))
+						goto WEAK_KEY;
+				} else{
+					if (((key[0] == 0x1F1F1F1F) &&
+						(key[1] == 0x0E0E0E0E)) ||
+						((key[0] == 0x1FFE1FFE) &&
+						(key[1] == 0x0EFE0EFE)))
+						goto WEAK_KEY;
+				}
+			}
+		} else {
+			if (key[0] < 0xFE01FE01) {
+				if (key[0] < 0xE0E0E0E0) {
+					if (((key[0] == 0xE001E00l) &&
+						(key[1] == 0xF101F101)) ||
+						((key[0] == 0xE01FE01F) &&
+						(key[1] == 0xF10EF10E)))
+						goto WEAK_KEY;
+				} else {
+					if (((key[0] == 0xE0E0E0E0) &&
+						(key[1] == 0xF1F1F1F1)) ||
+						((key[0] == 0xE0FEE0FE) &&
+						(key[1] == 0xF1FEF1FE)))
+						goto WEAK_KEY;
+				}
+			} else {
+				if (key[0] < 0xFEE0FEE0) {
+					if (((key[0] == 0xFE01FE01) &&
+						(key[1] == 0xFE01FE01)) ||
+						((key[0] == 0xFE1FFE1F) &&
+						(key[1] == 0xFE0EFE0E)))
+						goto WEAK_KEY;
+				} else {
+					if (((key[0] == 0xFEE0FEE0) &&
+						(key[1] == 0xFEF1FEF1)) ||
+						((key[0] == 0xFEFEFEFE)
+						&& (key[1] == 0xFEFEFEFE)))
+						goto WEAK_KEY;
+				}
+			}
+		}
+	}
+	memcpy(dctx->expkey, key_p, keylen);
+	return 0;
+WEAK_KEY:
+	*flags |= CRYPTO_TFM_RES_WEAK_KEY;
+	return -EINVAL;
+}
+
+
+void mcfcau_des_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+{
+	struct mcfcau_des_ctx *ctx = crypto_tfm_ctx(tfm);
+	u32 *des_key_tmp = ctx->expkey;
+	unsigned long iflags;
+
+	DBG("mcfcau_des_encrypt\n");
+
+	spin_lock_irqsave(&mcfcau_lock, iflags);
+
+	asm("move.l	%0, %%a0" : : "m"(src) : "a0");
+	asm("move.l	%0, %%a1" : : "m"(des_key_tmp) : "a1");
+
+	asm("cp0ld.l	(%%a0)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_LDR+MCFCAU_CA2) : "a0");
+	asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_LDR+MCFCAU_CA3));
+	asm("cp0ld.l	(%%a1)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_LDR+MCFCAU_CA0) : "a1");
+	asm("cp0ld.l	(%%a1),%%d0,#1,%0"
+		: : "n"(MCFCAU_LDR+MCFCAU_CA1));
+
+	mcfcau_des_encipher();
+
+	asm("cp0st.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_STR+MCFCAU_CA2) : "d0");
+	asm("cp0st.l	%%d0,%%d1,#1,%0"
+		: : "n"(MCFCAU_STR+MCFCAU_CA3) : "d1");
+	asm("move.l	%0, %%a1" : : "m"(dst) : "a1");
+	asm("move.l	%d0,(%a1)+");
+	asm("move.l	%d1,(%a1)");
+
+	spin_unlock_irqrestore(&mcfcau_lock, iflags);
+}
+
+
+void mcfcau_des_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+{
+	struct mcfcau_des_ctx *ctx = crypto_tfm_ctx(tfm);
+	u32 *des_key_tmp = ctx->expkey;
+	unsigned long iflags;
+
+	DBG("mcfcau_des_decrypt\n");
+
+	spin_lock_irqsave(&mcfcau_lock, iflags);
+
+	asm("move.l	%0, %%a0" : : "m"(src) : "a0");
+	asm("move.l	%0, %%a1" : : "m"(des_key_tmp) : "a1");
+
+	asm("cp0ld.l	(%%a0)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_LDR+MCFCAU_CA2) : "a0");
+	asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_LDR+MCFCAU_CA3));
+	asm("cp0ld.l	(%%a1)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_LDR+MCFCAU_CA0) : "a1");
+	asm("cp0ld.l	(%%a1),%%d0,#1,%0"
+		: : "n"(MCFCAU_LDR+MCFCAU_CA1));
+
+	mcfcau_des_decipher();
+
+	asm("move.l	%0, %%a1" : : "m"(dst) : "a1");
+	asm("cp0st.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_STR+MCFCAU_CA2) : "d0");
+	asm("cp0st.l	%%d0,%%d1,#1,%0"
+		: : "n"(MCFCAU_STR+MCFCAU_CA3) : "d1");
+	asm("move.l	%d0,(%a1)+");
+	asm("move.l	%d1,(%a1)");
+
+	spin_unlock_irqrestore(&mcfcau_lock, iflags);
+}
+
+
+/*
+ * RFC2451:
+ *
+ *   For DES-EDE3, there is no known need to reject weak or
+ *   complementation keys.  Any weakness is obviated by the use of
+ *   multiple keys.
+ *
+ *   However, if the first two or last two independent 64-bit keys are
+ *   equal (k1 == k2 or k2 == k3), then the DES3 operation is simply the
+ *   same as DES.  Implementers MUST reject keys that exhibit this
+ *   property.
+ *
+ */
+
+static int mcfcau_des3_ede_setkey(
+	struct crypto_tfm *tfm, const u8 *key_p, unsigned int keylen)
+{
+	const u32 *key = (const u32 *)key_p;
+	struct mcfcau_des3_ede_ctx *dctx = crypto_tfm_ctx(tfm);
+	u32 *flags = &tfm->crt_flags;
+
+	DBG("mcfcau_des3_ede_setkey\n");
+
+	if (unlikely(!((key[0] ^ key[2]) | (key[1] ^ key[3])) ||
+		     !((key[2] ^ key[4]) | (key[3] ^ key[5])))) {
+		*flags |= CRYPTO_TFM_RES_BAD_KEY_SCHED;
+		return -EINVAL;
+	}
+
+	memcpy(dctx->expkey, key_p, keylen);
+
+	return 0;
+}
+
+static void mcfcau_des3_ede_encrypt(
+	struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+{
+	struct mcfcau_des3_ede_ctx *dctx = crypto_tfm_ctx(tfm);
+	const u32 *des_key_tmp = dctx->expkey;
+	unsigned long iflags;
+
+	DBG("mcfcau_des3_ede_encrypt\n");
+
+	spin_lock_irqsave(&mcfcau_lock, iflags);
+
+	/*EK1*/
+	asm("move.l	%0, %%a0"
+		: : "m"(src) : "a0");
+	asm("move.l	%0, %%a1"
+		: : "m"(des_key_tmp) : "a1");
+
+	asm("cp0ld.l	(%%a0)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_LDR+MCFCAU_CA2) : "a0");
+	asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_LDR+MCFCAU_CA3));
+	asm("cp0ld.l	(%%a1)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_LDR+MCFCAU_CA0) : "a1");
+	asm("cp0ld.l	(%%a1)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_LDR+MCFCAU_CA1) : "a1");
+
+	mcfcau_des_encipher();
+
+	/*DK2*/
+	asm("cp0ld.l	(%%a1)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_LDR+MCFCAU_CA0) : "a1");
+	asm("cp0ld.l	(%%a1)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_LDR+MCFCAU_CA1) : "a1");
+
+	mcfcau_des_decipher();
+
+	/*EK3*/
+	asm("cp0ld.l	(%%a1)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_LDR+MCFCAU_CA0) : "a1");
+	asm("cp0ld.l	(%%a1),%%d0,#1,%0"
+		: : "n"(MCFCAU_LDR+MCFCAU_CA1));
+
+	mcfcau_des_encipher();
+
+	asm("move.l	%0, %%a1"
+		: : "m"(dst) : "a1");
+	asm("cp0st.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_STR+MCFCAU_CA2) : "d0");
+	asm("cp0st.l	%%d0,%%d1,#1,%0"
+		: : "n"(MCFCAU_STR+MCFCAU_CA3) : "d1");
+	asm("move.l	%d0,(%a1)+");
+	asm("move.l	%d1,(%a1)");
+
+	spin_unlock_irqrestore(&mcfcau_lock, iflags);
+}
+
+static void mcfcau_des3_ede_decrypt(
+	struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+{
+	struct mcfcau_des3_ede_ctx *dctx = crypto_tfm_ctx(tfm);
+	const u32 *des_key_tmp = dctx->expkey + 6 - 2;
+	unsigned long iflags;
+
+	DBG("mcfcau_des3_ede_decrypt\n");
+
+	spin_lock_irqsave(&mcfcau_lock, iflags);
+
+	/*DK3*/
+	asm("move.l	%0, %%a0"
+		: : "m"(src) : "a0");
+	asm("move.l	%0, %%a1"
+		: : "m"(des_key_tmp) : "a1");
+
+	asm("cp0ld.l	(%%a0)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_LDR+MCFCAU_CA2) : "a0");
+	asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_LDR+MCFCAU_CA3));
+	asm("cp0ld.l	(%%a1)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_LDR+MCFCAU_CA0) : "a1");
+	asm("cp0ld.l	(%%a1),%%d0,#1,%0"
+		: : "n"(MCFCAU_LDR+MCFCAU_CA1));
+
+	mcfcau_des_decipher();
+
+	/*EK2*/
+	asm("suba.l	#12,%a1");	/*dec key pointer*/
+
+	asm("cp0ld.l	(%%a1)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_LDR+MCFCAU_CA0) : "a1");
+	asm("cp0ld.l	(%%a1),%%d0,#1,%0"
+		: : "n"(MCFCAU_LDR+MCFCAU_CA1));
+
+	mcfcau_des_encipher();
+
+	/*DK1*/
+	asm("suba.l	#12,%a1");	/*dec key pointer*/
+
+	asm("cp0ld.l	(%%a1)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_LDR+MCFCAU_CA0) : "a1");
+	asm("cp0ld.l	(%%a1),%%d0,#1,%0"
+		: : "n"(MCFCAU_LDR+MCFCAU_CA1));
+
+	mcfcau_des_decipher();
+
+	asm("move.l	%0, %%a1"
+		: : "m"(dst) : "a1");
+	asm("cp0st.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_STR+MCFCAU_CA2) : "d0");
+	asm("cp0st.l	%%d0,%%d1,#1,%0"
+		: : "n"(MCFCAU_STR+MCFCAU_CA3) : "d1");
+	asm("move.l	%d0,(%a1)+");
+	asm("move.l	%d1,(%a1)");
+
+	spin_unlock_irqrestore(&mcfcau_lock, iflags);
+}
+
+
+static struct crypto_alg mcfcau_des_alg = {
+	.cra_name		=	"des",
+	.cra_driver_name	=	"des-mcfcau",
+	.cra_priority		=	MCFCAU_CRA_PRIORITY,
+	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
+	.cra_blocksize		=	MCFCAU_DES_BLOCK_SIZE,
+	.cra_ctxsize		=	sizeof(struct mcfcau_des_ctx),
+	.cra_module		=	THIS_MODULE,
+	.cra_alignmask		=	3,
+	.cra_list		=	LIST_HEAD_INIT(mcfcau_des_alg.cra_list),
+	.cra_u			=	{ .cipher = {
+	.cia_min_keysize	=	MCFCAU_DES_KEY_SIZE,
+	.cia_max_keysize	=	MCFCAU_DES_KEY_SIZE,
+	.cia_setkey		=	mcfcau_des_setkey,
+	.cia_encrypt		=	mcfcau_des_encrypt,
+	.cia_decrypt		=	mcfcau_des_decrypt } }
+};
+
+static struct crypto_alg mcfcau_des3_ede_alg = {
+	.cra_name		=	"des3_ede",
+	.cra_driver_name	=	"des3_ede-mcfcau",
+	.cra_priority		=	MCFCAU_CRA_PRIORITY,
+	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
+	.cra_blocksize		=	MCFCAU_DES3_EDE_BLOCK_SIZE,
+	.cra_ctxsize		=	sizeof(struct mcfcau_des3_ede_ctx),
+	.cra_module		=	THIS_MODULE,
+	.cra_alignmask		=	3,
+	.cra_list		=
+			LIST_HEAD_INIT(mcfcau_des3_ede_alg.cra_list),
+	.cra_u			=	{ .cipher = {
+	.cia_min_keysize	=	MCFCAU_DES3_EDE_KEY_SIZE,
+	.cia_max_keysize	=	MCFCAU_DES3_EDE_KEY_SIZE,
+	.cia_setkey		=	mcfcau_des3_ede_setkey,
+	.cia_encrypt		=	mcfcau_des3_ede_encrypt,
+	.cia_decrypt		=	mcfcau_des3_ede_decrypt } }
+};
+
+MODULE_ALIAS("mcfcau_des3_ede");
+
+static int __init mcfcau_des_init(void)
+{
+	int ret;
+
+	ret = crypto_register_alg(&mcfcau_des_alg);
+	if (ret < 0)
+		goto out;
+
+	ret = crypto_register_alg(&mcfcau_des3_ede_alg);
+	if (ret < 0)
+		crypto_unregister_alg(&mcfcau_des_alg);
+out:
+	printk(KERN_INFO MCFCAU_DES_DRIVER_DESC " "
+		MCFCAU_DES_DRIVER_VERSION " %s.\n",
+		ret ? "failed" : "registered");
+	return ret;
+}
+
+static void __exit mcfcau_des_exit(void)
+{
+	crypto_unregister_alg(&mcfcau_des3_ede_alg);
+	crypto_unregister_alg(&mcfcau_des_alg);
+
+	printk(KERN_INFO MCFCAU_DES_DRIVER_DESC " "
+		MCFCAU_DES_DRIVER_VERSION " unregistered.\n");
+}
+
+module_init(mcfcau_des_init);
+module_exit(mcfcau_des_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("DES & Triple DES EDE Cipher Algorithms for ColdFire CAU");
+MODULE_AUTHOR("Andrey Butok");
--- /dev/null
+++ b/drivers/crypto/mcfcau-md5.c
@@ -0,0 +1,972 @@
+/***************************************************************************
+ * mcfcau-md5.c - Implementation of MD5 Message Digest Algorithm (RFC1321)
+ *                for Freescale ColdFire Cryptographic Acceleration Unit (CAU).
+ *
+ * Copyright (C) 2007-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Author: Andrey Butok
+ *         Shrek Wu B16972@freescale.com
+ *         Alison Wang b18965@freescale.com
+ *
+ * NOTE: You can find the ColdFire CAU module on MCF5445X and MCF52235.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ ***************************************************************************
+ * Changes:
+ * v0.01	30 September 2007	Andrey Butok
+ *		Initial Release - developed on 2.6.20 Linux kernel.
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/crypto.h>
+#include <linux/types.h>
+#include <crypto/algapi.h>
+#include <crypto/hash.h>
+#include <crypto/internal/hash.h>
+#include <asm/byteorder.h>
+
+#include "mcfcau.h"
+
+#define MCFCAU_MD5_DIGEST_SIZE		(16)
+#define MCFCAU_MD5_HMAC_BLOCK_SIZE	(64)
+#define MCFCAU_MD5_BLOCK_WORDS		(16)
+#define MCFCAU_MD5_HASH_WORDS		(4)
+
+#define	MCFCAU_MD5_DRIVER_DESC		"MD5 ColdFire CAU driver"
+#define	MCFCAU_MD5_DRIVER_VERSION	"v0.01"
+
+
+struct mcfcau_md5_ctx {
+	u32 hash[MCFCAU_MD5_HASH_WORDS];
+	u32 block[MCFCAU_MD5_BLOCK_WORDS];
+	u64 byte_count;
+};
+
+u32 mcfcau_md5_t[64] = {0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
+			0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
+			0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
+			0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
+			0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
+			0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
+			0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
+			0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
+			0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
+			0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
+			0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
+			0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
+			0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
+			0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
+			0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
+			0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391};
+
+
+
+static void mcfcau_md5_transform(u32 *hash, u32 const *in)
+{
+	int i;
+	u32 *md5_t_p = &mcfcau_md5_t[0];
+	unsigned long iflags;
+
+	spin_lock_irqsave(&mcfcau_lock, iflags);
+	asm("move.l	%0, %%a1" : : "m"(hash) : "a1");
+	asm("cp0ld.l	(%%a1)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_LDR+MCFCAU_CAA) : "a1");/*a*/
+	asm("cp0ld.l	(%%a1)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_LDR+MCFCAU_CA1) : "a1");/*b*/
+	asm("cp0ld.l	(%%a1)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_LDR+MCFCAU_CA2) : "a1");/*c*/
+	asm("cp0ld.l	(%%a1)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_LDR+MCFCAU_CA3) : "a1");/*d*/
+	asm("move.l	%0, %%a0" : : "m"(in) : "a0");	/* X[] */
+	asm("move.l	%0, %%a3" : : "m"(md5_t_p) : "a3");	/* T[] */
+
+	/*  Round 1 */
+	asm("moveq.l	#7, %%d4" : : : "d4");	/* for rotating by 7 */
+	asm("moveq.l	#12, %%d5" : : : "d5");	/* for rotating by 12 */
+	asm("moveq.l	#17, %%d6" : : : "d6");	/* for rotating by 17 */
+	asm("moveq.l	#22, %%d7" : : : "d7");	/* for rotating by 22 */
+
+	for (i = 0; i < 4; i++) {
+		asm("cp0ld.l	%%d0,%%d0,#1,%0"
+			: : "n"(MCFCAU_HASH+MCFCAU_HFF));
+		/* a+F(b,c,d) */
+		asm("cp0ld.l	(%%a0)+,%%d0,#1,%0"
+			: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+		/* add byterev x[i] */
+		asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+			: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+		/* add t[i] */
+		asm("cp0ld.l	%%d4,%%d0,#1,%0"
+			: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+		/* rotate by 7 */
+		asm("cp0ld.l	%%d0,%%d0,#1,%0"
+			: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+		/* add b */
+		asm("cp0ld.l	%%d0,%%d0,#1,%0"
+			: : "n"(MCFCAU_MDS));
+		/* register to register shift */
+
+		asm("cp0ld.l	%%d0,%%d0,#1,%0"
+			: : "n"(MCFCAU_HASH+MCFCAU_HFF));
+		asm("cp0ld.l	(%%a0)+,%%d0,#1,%0"
+			: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+		asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+			: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+		asm("cp0ld.l	%%d5,%%d0,#1,%0"
+			: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+		asm("cp0ld.l	%%d0,%%d0,#1,%0"
+			: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+		asm("cp0ld.l	%%d0,%%d0,#1,%0"
+			: : "n"(MCFCAU_MDS));
+
+		asm("cp0ld.l	%%d0,%%d0,#1,%0"
+			: : "n"(MCFCAU_HASH+MCFCAU_HFF));
+		asm("cp0ld.l	(%%a0)+,%%d0,#1,%0"
+			: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+		asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+			: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+		asm("cp0ld.l	%%d6,%%d0,#1,%0"
+			: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+		asm("cp0ld.l	%%d0,%%d0,#1,%0"
+			: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+		asm("cp0ld.l	%%d0,%%d0,#1,%0"
+			: : "n"(MCFCAU_MDS));
+
+		asm("cp0ld.l	%%d0,%%d0,#1,%0"
+			: : "n"(MCFCAU_HASH+MCFCAU_HFF));
+		asm("cp0ld.l	(%%a0)+,%%d0,#1,%0"
+			: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+		asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+			: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+		asm("cp0ld.l	%%d7,%%d0,#1,%0"
+			: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+		asm("cp0ld.l	%%d0,%%d0,#1,%0"
+			: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+		asm("cp0ld.l	%%d0,%%d0,#1,%0"
+			: : "n"(MCFCAU_MDS));
+	};
+
+
+	/* Round 2 */
+	asm("moveq.l	#5, %%d4" : : : "d4");	/* for rotating by 5 */
+	asm("moveq.l	#9, %%d5" : : : "d5");	/* for rotating by 9 */
+	asm("moveq.l	#14, %%d6" : : : "d6");	/* for rotating by 14 */
+	asm("moveq.l	#20, %%d7" : : : "d7");	/* for rotating by 20 */
+
+	asm("lea -60(%%a0),%%a0" : : : "a0");
+
+	for (i = 0; i < 2; i++) {
+		asm("cp0ld.l	%%d0,%%d0,#1,%0"
+			: : "n"(MCFCAU_HASH+MCFCAU_HFG));
+		asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+			: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+		asm("lea	20(%%a0),%%a0"		: : : "a0");
+		asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+			: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+		asm("cp0ld.l	%%d4,%%d0,#1,%0"
+			: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+		asm("cp0ld.l	%%d0,%%d0,#1,%0"
+			: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+		asm("cp0ld.l	%%d0,%%d0,#1,%0"
+			: : "n"(MCFCAU_MDS));
+
+		asm("cp0ld.l	%%d0,%%d0,#1,%0"
+			: : "n"(MCFCAU_HASH+MCFCAU_HFG));
+		asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+			: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+		asm("lea	20(%%a0),%%a0"	: : : "a0");
+		asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+			: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+		asm("cp0ld.l	%%d5,%%d0,#1,%0"
+			: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+		asm("cp0ld.l	%%d0,%%d0,#1,%0"
+			: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+		asm("cp0ld.l	%%d0,%%d0,#1,%0"	: : "n"(MCFCAU_MDS));
+
+		asm("cp0ld.l	%%d0,%%d0,#1,%0"
+			: : "n"(MCFCAU_HASH+MCFCAU_HFG));
+		asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+			: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+		asm("lea	-44(%%a0),%%a0"		: : : "a0");
+		asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+			: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+		asm("cp0ld.l	%%d6,%%d0,#1,%0"
+			: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+		asm("cp0ld.l	%%d0,%%d0,#1,%0"
+			: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+		asm("cp0ld.l	%%d0,%%d0,#1,%0"
+			: : "n"(MCFCAU_MDS));
+
+		asm("cp0ld.l	%%d0,%%d0,#1,%0"
+			: : "n"(MCFCAU_HASH+MCFCAU_HFG));
+		asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+			: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+		asm("lea	20(%%a0),%%a0"	: : : "a0");
+		asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+			: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+		asm("cp0ld.l	%%d7,%%d0,#1,%0"
+			: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+		asm("cp0ld.l	%%d0,%%d0,#1,%0"
+			: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+		asm("cp0ld.l	%%d0,%%d0,#1,%0"
+			: : "n"(MCFCAU_MDS));
+	};
+
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_HASH+MCFCAU_HFG));
+	asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+	asm("lea	20(%%a0),%%a0"
+		: : : "a0");
+	asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+	asm("cp0ld.l	%%d4,%%d0,#1,%0"
+		: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_MDS));
+
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_HASH+MCFCAU_HFG));
+	asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+	asm("lea	-44(%%a0),%%a0"
+		: : : "a0");
+	asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+	asm("cp0ld.l	%%d5,%%d0,#1,%0"
+		: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_MDS));
+
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_HASH+MCFCAU_HFG));
+	asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+	asm("lea	20(%%a0),%%a0"
+		: : : "a0");
+	asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+	asm("cp0ld.l	%%d6,%%d0,#1,%0"
+		: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_MDS));
+
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_HASH+MCFCAU_HFG));
+	asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+	asm("lea	20(%%a0),%%a0"	: : : "a0");
+	asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+	asm("cp0ld.l	%%d7,%%d0,#1,%0"
+		: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_MDS));
+
+
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_HASH+MCFCAU_HFG));
+	asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+	asm("lea	-44(%%a0),%%a0"	: : : "a0");
+	asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+	asm("cp0ld.l	%%d4,%%d0,#1,%0"
+		: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_MDS));
+
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_HASH+MCFCAU_HFG));
+	asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+	asm("lea	20(%%a0),%%a0"	: : : "a0");
+	asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+	asm("cp0ld.l	%%d5,%%d0,#1,%0"
+		: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_MDS));
+
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_HASH+MCFCAU_HFG));
+	asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+	asm("lea	20(%%a0),%%a0"	: : : "a0");
+	asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+	asm("cp0ld.l	%%d6,%%d0,#1,%0"
+		: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_MDS));
+
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_HASH+MCFCAU_HFG));
+	asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+	asm("lea	-28(%%a0),%%a0"	: : : "a0");
+	asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+	asm("cp0ld.l	%%d7,%%d0,#1,%0"
+		: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_MDS));
+
+
+	/* Round 3 */
+	asm("moveq.l	#4, %%d4" : : : "d4");	/* for rotating by 5 */
+	asm("moveq.l	#11, %%d5" : : : "d5");	/* for rotating by 9 */
+	asm("moveq.l	#16, %%d6" : : : "d6");	/* for rotating by 14 */
+	asm("moveq.l	#23, %%d7" : : : "d7");	/* for rotating by 20 */
+
+
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_HASH+MCFCAU_HFH));
+	asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+	asm("lea	12(%%a0),%%a0"	: : : "a0");
+	asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+	asm("cp0ld.l	%%d4,%%d0,#1,%0"
+		: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_MDS));
+
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_HASH+MCFCAU_HFH));
+	asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+	asm("lea	12(%%a0),%%a0"	: : : "a0");
+	asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+	asm("cp0ld.l	%%d5,%%d0,#1,%0"
+		: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_MDS));
+
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_HASH+MCFCAU_HFH));
+	asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+	asm("lea	12(%%a0),%%a0"	: : : "a0");
+	asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+	asm("cp0ld.l	%%d6,%%d0,#1,%0"
+		: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0" : : "n"(MCFCAU_MDS));
+
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_HASH+MCFCAU_HFH));
+	asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+	asm("lea	-52(%%a0),%%a0"	: : : "a0");
+	asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+	asm("cp0ld.l	%%d7,%%d0,#1,%0"
+		: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_MDS));
+
+
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_HASH+MCFCAU_HFH));
+	asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+	asm("lea	12(%%a0),%%a0"	: : : "a0");
+	asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+	asm("cp0ld.l	%%d4,%%d0,#1,%0"
+		: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_MDS));
+
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_HASH+MCFCAU_HFH));
+	asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+	asm("lea	12(%%a0),%%a0"	: : : "a0");
+	asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+	asm("cp0ld.l	%%d5,%%d0,#1,%0"
+		: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_MDS));
+
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_HASH+MCFCAU_HFH));
+	asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+	asm("lea	12(%%a0),%%a0"	: : : "a0");
+	asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+	asm("cp0ld.l	%%d6,%%d0,#1,%0"
+		: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_MDS));
+
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_HASH+MCFCAU_HFH));
+	asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+	asm("lea	12(%%a0),%%a0"	: : : "a0");
+	asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+	asm("cp0ld.l	%%d7,%%d0,#1,%0"
+		: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_MDS));
+
+
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_HASH+MCFCAU_HFH));
+	asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+	asm("lea	-52(%%a0),%%a0"	: : : "a0");
+	asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+	asm("cp0ld.l	%%d4,%%d0,#1,%0"
+		: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_MDS));
+
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_HASH+MCFCAU_HFH));
+	asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+	asm("lea	12(%%a0),%%a0"	: : : "a0");
+	asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+	asm("cp0ld.l	%%d5,%%d0,#1,%0"
+		: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_MDS));
+
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_HASH+MCFCAU_HFH));
+	asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+	asm("lea	12(%%a0),%%a0"	: : : "a0");
+	asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+	asm("cp0ld.l	%%d6,%%d0,#1,%0"
+		: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_MDS));
+
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_HASH+MCFCAU_HFH));
+	asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+	asm("lea	12(%%a0),%%a0"	: : : "a0");
+	asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+	asm("cp0ld.l	%%d7,%%d0,#1,%0"
+		: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_MDS));
+
+
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_HASH+MCFCAU_HFH));
+	asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+	asm("lea	12(%%a0),%%a0"	: : : "a0");
+	asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+	asm("cp0ld.l	%%d4,%%d0,#1,%0"
+		: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_MDS));
+
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_HASH+MCFCAU_HFH));
+	asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+	asm("lea	12(%%a0),%%a0"	: : : "a0");
+	asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+	asm("cp0ld.l	%%d5,%%d0,#1,%0"
+		: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_MDS));
+
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_HASH+MCFCAU_HFH));
+	asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+	asm("lea	-52(%%a0),%%a0"	: : : "a0");
+	asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+	asm("cp0ld.l	%%d6,%%d0,#1,%0"
+		: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_MDS));
+
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_HASH+MCFCAU_HFH));
+	asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+	asm("lea	-8(%%a0),%%a0"	: : : "a0");
+	asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+	asm("cp0ld.l	%%d7,%%d0,#1,%0"
+		: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_MDS));
+
+	/* Round 4 */
+	asm("moveq.l	#6, %%d4" : : : "d4");	/* for rotating by 6 */
+	asm("moveq.l	#10, %%d5" : : : "d5");	/* for rotating by 10 */
+	asm("moveq.l	#15, %%d6" : : : "d6");	/* for rotating by 15 */
+	asm("moveq.l	#21, %%d7" : : : "d7");	/* for rotating by 21 */
+
+
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_HASH+MCFCAU_HFI));
+	asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+	asm("lea	28(%%a0),%%a0"	: : : "a0");
+	asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+	asm("cp0ld.l	%%d4,%%d0,#1,%0"
+		: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_MDS));
+
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_HASH+MCFCAU_HFI));
+	asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+	asm("lea	28(%%a0),%%a0"	: : : "a0");
+	asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+	asm("cp0ld.l	%%d5,%%d0,#1,%0"
+		: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_MDS));
+
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_HASH+MCFCAU_HFI));
+	asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+	asm("lea	-36(%%a0),%%a0"	: : : "a0");
+	asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+	asm("cp0ld.l	%%d6,%%d0,#1,%0"
+		: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_MDS));
+
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_HASH+MCFCAU_HFI));
+	asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+	asm("lea	28(%%a0),%%a0"	: : : "a0");
+	asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+	asm("cp0ld.l	%%d7,%%d0,#1,%0"
+		: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_MDS));
+
+
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_HASH+MCFCAU_HFI));
+	asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+	asm("lea	-36(%%a0),%%a0"	: : : "a0");
+	asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+	asm("cp0ld.l	%%d4,%%d0,#1,%0"
+		: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_MDS));
+
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_HASH+MCFCAU_HFI));
+	asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+	asm("lea	28(%%a0),%%a0"	: : : "a0");
+	asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+	asm("cp0ld.l	%%d5,%%d0,#1,%0"
+		: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_MDS));
+
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_HASH+MCFCAU_HFI));
+	asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+	asm("lea	-36(%%a0),%%a0"	: : : "a0");
+	asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+	asm("cp0ld.l	%%d6,%%d0,#1,%0"
+		: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_MDS));
+
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_HASH+MCFCAU_HFI));
+	asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+	asm("lea	28(%%a0),%%a0"	: : : "a0");
+	asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+	asm("cp0ld.l	%%d7,%%d0,#1,%0"
+		: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_MDS));
+
+
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_HASH+MCFCAU_HFI));
+	asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+	asm("lea	28(%%a0),%%a0"	: : : "a0");
+	asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+	asm("cp0ld.l	%%d4,%%d0,#1,%0"
+		: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_MDS));
+
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_HASH+MCFCAU_HFI));
+	asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+	asm("lea	-36(%%a0),%%a0"	: : : "a0");
+	asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+	asm("cp0ld.l	%%d5,%%d0,#1,%0"
+		: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_MDS));
+
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_HASH+MCFCAU_HFI));
+	asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+	asm("lea	28(%%a0),%%a0"	: : : "a0");
+	asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+	asm("cp0ld.l	%%d6,%%d0,#1,%0"
+		: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_MDS));
+
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_HASH+MCFCAU_HFI));
+	asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+	asm("lea	-36(%%a0),%%a0" : : : "a0");
+	asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+	asm("cp0ld.l	%%d7,%%d0,#1,%0"
+		: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_MDS));
+
+
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_HASH+MCFCAU_HFI));
+	asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+	asm("lea	28(%%a0),%%a0"
+		: : : "a0");
+	asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+	asm("cp0ld.l	%%d4,%%d0,#1,%0"
+		: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_MDS));
+
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_HASH+MCFCAU_HFI));
+	asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+	asm("lea	-36(%%a0),%%a0"
+		: : : "a0");
+	asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+	asm("cp0ld.l	%%d5,%%d0,#1,%0"
+		: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_MDS));
+
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_HASH+MCFCAU_HFI));
+	asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+	asm("lea	28(%%a0),%%a0"
+		: : : "a0");
+	asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+	asm("cp0ld.l	%%d6,%%d0,#1,%0"
+		: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_MDS));
+
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_HASH+MCFCAU_HFI));
+	asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+		: : "n"(MCFCAU_RADR+MCFCAU_CAA) : "a0");
+	asm("lea	28(%%a0),%%a0"		: : : "a0");
+	asm("cp0ld.l	(%%a3)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a3");
+	asm("cp0ld.l	%%d7,%%d0,#1,%0"
+		: : "n"(MCFCAU_ROTL+MCFCAU_CAA));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADRA+MCFCAU_CA1));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_MDS));
+
+
+	asm("move.l	%0, %%a1" : : "m"(hash) : "a1");
+
+	asm("cp0ld.l	(%%a1)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a1");/*a*/
+	asm("cp0ld.l	(%%a1)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CA1) : "a1");/*b*/
+	asm("cp0ld.l	(%%a1)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CA2) : "a1");/*c*/
+	asm("cp0ld.l	(%%a1)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CA3) : "a1");/*d*/
+
+	asm("cp0st.l	%%d0,-(%%a1),#1,%0"
+		: : "n"(MCFCAU_STR+MCFCAU_CA3) : "a1");/*d*/
+	asm("cp0st.l	%%d0,-(%%a1),#1,%0"
+		: : "n"(MCFCAU_STR+MCFCAU_CA2) : "a1");/*c*/
+	asm("cp0st.l	%%d0,-(%%a1),#1,%0"
+		: : "n"(MCFCAU_STR+MCFCAU_CA1) : "a1");/*b*/
+	asm("cp0st.l	%%d0,-(%%a1),#1,%0"
+		: : "n"(MCFCAU_STR+MCFCAU_CAA) : "a1");/*a*/
+	spin_unlock_irqrestore(&mcfcau_lock, iflags);
+}
+
+static inline void le32_to_cpu_array(u32 *buf, unsigned int words)
+{
+	while (words--) {
+		__le32_to_cpus(buf);
+		buf++;
+	}
+}
+
+static inline void cpu_to_le32_array(u32 *buf, unsigned int words)
+{
+	while (words--) {
+		__cpu_to_le32s(buf);
+		buf++;
+	}
+}
+
+static int mcfcau_md5_initialization(struct shash_desc *desc)
+{
+	struct mcfcau_md5_ctx *mctx = shash_desc_ctx(desc);
+
+	DBG("mcfcau_md5_initialization\n");
+	mctx->hash[0] = 0x67452301;
+	mctx->hash[1] = 0xefcdab89;
+	mctx->hash[2] = 0x98badcfe;
+	mctx->hash[3] = 0x10325476;
+	mctx->byte_count = 0;
+
+	return 0;
+}
+
+static int mcfcau_md5_update(struct shash_desc *desc,
+		const u8 *data, unsigned int len)
+{
+	struct mcfcau_md5_ctx *mctx = shash_desc_ctx(desc);
+	const u32 avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f);
+
+	DBG("mcfcau_md5_update\n");
+	mctx->byte_count += len;
+
+	if (avail > len) {
+		memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
+		       data, len);
+	} else {
+		memcpy((char *)mctx->block +
+			(sizeof(mctx->block) - avail), data, avail);
+
+		mcfcau_md5_transform(mctx->hash, mctx->block);
+		data += avail;
+		len -= avail;
+
+		while (len >= sizeof(mctx->block)) {
+			memcpy(mctx->block, data, sizeof(mctx->block));
+			mcfcau_md5_transform(mctx->hash, mctx->block);
+			data += sizeof(mctx->block);
+			len -= sizeof(mctx->block);
+		}
+
+		memcpy(mctx->block, data, len);
+	}
+
+	return 0;
+}
+
+static int mcfcau_md5_final(struct shash_desc *desc, u8 *out)
+{
+	struct mcfcau_md5_ctx *mctx = shash_desc_ctx(desc);
+	const unsigned int offset = mctx->byte_count & 0x3f;
+	char *p = (char *)mctx->block + offset;
+	int padding = 56 - (offset + 1);
+
+	DBG("mcfcau_md5_final\n");
+
+	*p++ = 0x80;
+	if (padding < 0) {
+		memset(p, 0x00, padding + sizeof(u64));
+		mcfcau_md5_transform(mctx->hash, mctx->block);
+		p = (char *)mctx->block;
+		padding = 56;
+	}
+
+	memset(p, 0, padding);
+	mctx->block[14] = mctx->byte_count << 3;
+	mctx->block[15] = mctx->byte_count >> 29;
+	le32_to_cpu_array(&mctx->block[14], 2);
+
+	mcfcau_md5_transform(mctx->hash, mctx->block);
+
+	cpu_to_le32_array(mctx->hash, sizeof(mctx->hash) / sizeof(u32));
+	memcpy(out, mctx->hash, sizeof(mctx->hash));
+	memset(mctx, 0, sizeof(*mctx));
+
+	return 0;
+}
+
+static struct shash_alg mcfcau_md5_alg = {
+	.init = mcfcau_md5_initialization,
+	.update = mcfcau_md5_update,
+	.final = mcfcau_md5_final,
+	.digestsize = MCFCAU_MD5_DIGEST_SIZE,
+	.descsize = sizeof(struct mcfcau_md5_ctx),
+	.statesize = sizeof(struct mcfcau_md5_ctx),
+	.base = {
+		.cra_name = "md5",
+		.cra_driver_name = "md5-mcfcau",
+		.cra_blocksize = MCFCAU_MD5_HMAC_BLOCK_SIZE,
+		.cra_flags = CRYPTO_ALG_TYPE_SHASH,
+		.cra_priority =	MCFCAU_CRA_PRIORITY,
+		.cra_module = THIS_MODULE
+	}
+};
+
+static int __init mcfcau_md5_init(void)
+{
+	int ret = 0;
+
+	ret = crypto_register_shash(&mcfcau_md5_alg);
+	printk(KERN_INFO MCFCAU_MD5_DRIVER_DESC " "
+		MCFCAU_MD5_DRIVER_VERSION " %s.\n",
+		ret ? "failed" : "registered");
+	return ret;
+}
+
+static void __exit mcfcau_md5_exit(void)
+{
+	crypto_unregister_shash(&mcfcau_md5_alg);
+	printk(KERN_INFO MCFCAU_MD5_DRIVER_DESC " "
+		MCFCAU_MD5_DRIVER_VERSION " unregistered.\n");
+}
+
+module_init(mcfcau_md5_init);
+module_exit(mcfcau_md5_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(MCFCAU_MD5_DRIVER_DESC);
+MODULE_AUTHOR("Andrey Butok");
--- /dev/null
+++ b/drivers/crypto/mcfcau-sha1.c
@@ -0,0 +1,331 @@
+/***************************************************************************
+ * mcfcau-sha1.c - Implementation of SHA1 Secure Hash Algorithm
+ *                for Freescale ColdFire Cryptographic Acceleration Unit (CAU).
+ *
+ * Copyright (C) 2007-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Author: Andrey Butok
+ *         Shrek Wu B16972@freescale.com
+ *         Alison Wang b18965@freescale.com
+ *
+ * NOTE: You can find the ColdFire CAU module on MCF5445X and MCF52235.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ ***************************************************************************
+ * Changes:
+ * v0.01	15 October 2007	Andrey Butok
+ *		Initial Release - developed on 2.6.20 Linux kernel.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/crypto.h>
+#include <linux/types.h>
+#include <crypto/algapi.h>
+#include <crypto/hash.h>
+#include <crypto/internal/hash.h>
+
+#include "mcfcau.h"
+
+#define MCFCAU_SHA1_DIGEST_WORDS	(5)
+#define MCFCAU_SHA1_WORKSPACE_WORDS	(80)
+
+#define MCFCAU_SHA1_DIGEST_SIZE		(20)
+#define MCFCAU_SHA1_HMAC_BLOCK_SIZE	(64)
+
+#define	MCFCAU_SHA1_DRIVER_DESC		"SHA1 ColdFire CAU driver"
+#define	MCFCAU_SHA1_DRIVER_VERSION	"v0.01"
+
+static const u32 K[4] = {0x5A827999L,	/* Rounds  0-19: sqrt(2) * 2^30 */
+			0x6ED9EBA1L,	/* Rounds 20-39: sqrt(3) * 2^30 */
+			0x8F1BBCDCL,	/* Rounds 40-59: sqrt(5) * 2^30 */
+			0xCA62C1D6L};	/* Rounds 60-79: sqrt(10) * 2^30 */
+
+struct mcfcau_sha1_ctx {
+	u64 count;
+	u32 state[5];
+	u8 buffer[64];
+};
+
+static void mcfcau_sha1_transform(__u32 *digest, const char *in, __u32 *W)
+{
+	int i;
+	u32 *tmp_p;
+	unsigned long iflags;
+
+	/* (a) Devide M(i) into 16 words W */
+	for (i = 0; i < 16; i++)
+		W[i] = ((const u32 *)in)[i];
+
+	/* (b) W[i+16] = S^1(W[i+13] ^ W[i+8] ^ W[i+2] ^ W[i]) */
+	tmp_p = &W[16];
+
+	spin_lock_irqsave(&mcfcau_lock, iflags);
+	asm("move.l	%0, %%a0" : : "m"(tmp_p) : "a0");
+	asm("moveq.l	#1, %%d3" : : : "d3");
+
+	for (i = 0; i < 64; i++) {
+		asm("cp0ld.l	-64(%%a0),%%d0,#1,%0"
+			: : "n"(MCFCAU_LDR+MCFCAU_CA0));
+		asm("cp0ld.l	-56(%%a0),%%d0,#1,%0"
+			: : "n"(MCFCAU_XOR+MCFCAU_CA0));
+		asm("cp0ld.l	-32(%%a0),%%d0,#1,%0"
+			: : "n"(MCFCAU_XOR+MCFCAU_CA0));
+		asm("cp0ld.l	-12(%%a0),%%d0,#1,%0"
+			: : "n"(MCFCAU_XOR+MCFCAU_CA0));
+		asm("cp0ld.l	%%d3,%%d0,#1,%0"
+			: : "n"(MCFCAU_ROTL+MCFCAU_CA0) : "d3");
+		asm("cp0st.l	%%d0,(%%a0)+,#1,%0"
+			: : "n"(MCFCAU_STR+MCFCAU_CA0));
+	}
+
+	/* (c) */
+	asm("move.l	%0, %%a0" : : "m"(digest) : "a0");
+	asm("cp0ld.l	(%%a0)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_LDR+MCFCAU_CA0) : "a0"); /* a */
+	asm("cp0ld.l	(%%a0)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_LDR+MCFCAU_CA1) : "a0"); /* b */
+	asm("cp0ld.l	(%%a0)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_LDR+MCFCAU_CA2) : "a0"); /* c */
+	asm("cp0ld.l	(%%a0)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_LDR+MCFCAU_CA3) : "a0"); /* d */
+	asm("cp0ld.l	(%%a0)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_LDR+MCFCAU_CA4) : "a0"); /* e */
+
+	/* (d) */
+	asm("moveq.l	#5, %%d0" : : : "d0");
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_MVRA+MCFCAU_CA0));
+	asm("cp0ld.l	%%d0,%%d0,#1,%0"
+		: : "n"(MCFCAU_ROTL+MCFCAU_CAA)); /*S^5(A)*/
+
+	tmp_p = (u32 *)K;
+	asm("move.l	%0, %%a0" : : "m"(tmp_p) : "a0");
+	asm("move.l	%0, %%a1" : : "m"(W) : "a1");
+
+	for (i = 0; i < 20; i++) {
+		/* t = f1(b, c, d) + K1 + rol32(a, 5) + e + W[i]; */
+		/* e = d; d = c; c = rol32(b, 30); b = a; a = t; */
+		asm("cp0ld.l	%%d0,%%d0,#1,%0"
+			: : "n"(MCFCAU_HASH+MCFCAU_HFC)); /*f(b,c,d)*/
+		asm("cp0ld.l	%%d0,%%d0,#1,%0"
+			: : "n"(MCFCAU_ADRA+MCFCAU_CA4)); /*+e*/
+		asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+			: : "n"(MCFCAU_ADR+MCFCAU_CAA)); /*+K*/
+		asm("cp0ld.l	(%%a1)+,%%d0,#1,%0"
+			: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a1"); /*+W*/
+		asm("cp0ld.l	%%d0,%%d0,#1,%0"
+			: : "n"(MCFCAU_SHS));
+	}
+
+	asm("add.l #4,%%a0"	: : : "a0"); /* update K */
+
+	for (; i < 40; i++) {
+		/* t = f2(b, c, d) + K2 + rol32(a, 5) + e + W[i]; */
+		/* e = d; d = c; c = rol32(b, 30); b = a; a = t; */
+		asm("cp0ld.l	%%d0,%%d0,#1,%0"
+			: : "n"(MCFCAU_HASH+MCFCAU_HFH)); /*f(b,c,d)*/
+		asm("cp0ld.l	%%d0,%%d0,#1,%0"
+			: : "n"(MCFCAU_ADRA+MCFCAU_CA4)); /*+e*/
+		asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+			: : "n"(MCFCAU_ADR+MCFCAU_CAA)); /*+K*/
+		asm("cp0ld.l	(%%a1)+,%%d0,#1,%0"
+			: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a1"); /*+W*/
+		asm("cp0ld.l	%%d0,%%d0,#1,%0"
+			: : "n"(MCFCAU_SHS));
+	}
+
+	asm("add.l #4,%%a0"	 : : : "a0"); /* update K */
+
+	for (; i < 60; i++) {
+		/* t = f3(b, c, d) + K3 + rol32(a, 5) + e + W[i]; */
+		/* e = d; d = c; c = rol32(b, 30); b = a; a = t; */
+		asm("cp0ld.l	%%d0,%%d0,#1,%0"
+			: : "n"(MCFCAU_HASH+MCFCAU_HFM)); /*f(b,c,d)*/
+		asm("cp0ld.l	%%d0,%%d0,#1,%0"
+			: : "n"(MCFCAU_ADRA+MCFCAU_CA4)); /*+e*/
+		asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+			: : "n"(MCFCAU_ADR+MCFCAU_CAA)); /*+K*/
+		asm("cp0ld.l	(%%a1)+,%%d0,#1,%0"
+			: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a1"); /*+W*/
+		asm("cp0ld.l	%%d0,%%d0,#1,%0"
+			: : "n"(MCFCAU_SHS));
+	}
+
+	asm("add.l #4,%%a0"	: : : "a0"); /* update K */
+
+	for (; i < 80; i++) {
+		/* t = f2(b, c, d) + K4 + rol32(a, 5) + e + W[i]; */
+		/* e = d; d = c; c = rol32(b, 30); b = a; a = t; */
+		asm("cp0ld.l	%%d0,%%d0,#1,%0"
+			: : "n"(MCFCAU_HASH+MCFCAU_HFH)); /*f(b,c,d)*/
+		asm("cp0ld.l	%%d0,%%d0,#1,%0"
+			: : "n"(MCFCAU_ADRA+MCFCAU_CA4)); /*+e*/
+		asm("cp0ld.l	(%%a0),%%d0,#1,%0"
+			: : "n"(MCFCAU_ADR+MCFCAU_CAA)); /*+K*/
+		asm("cp0ld.l	(%%a1)+,%%d0,#1,%0"
+			: : "n"(MCFCAU_ADR+MCFCAU_CAA) : "a1"); /*+W*/
+		asm("cp0ld.l	%%d0,%%d0,#1,%0"
+			: : "n"(MCFCAU_SHS));
+	}
+
+	/* (e) */
+	asm("move.l	%0, %%a0" : : "m"(digest) : "a0");
+	asm("cp0ld.l	(%%a0)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CA0) : "a0"); /* +a */
+	asm("cp0ld.l	(%%a0)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CA1) : "a0"); /* +b */
+	asm("cp0ld.l	(%%a0)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CA2) : "a0"); /* +c */
+	asm("cp0ld.l	(%%a0)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CA3) : "a0"); /* +d */
+	asm("cp0ld.l	(%%a0)+,%%d0,#1,%0"
+		: : "n"(MCFCAU_ADR+MCFCAU_CA4) : "a0"); /* +e */
+
+	asm("cp0st.l	%%d0,-(%%a0),#1,%0"
+		: : "n"(MCFCAU_STR+MCFCAU_CA4) : "a0");
+	asm("cp0st.l	%%d0,-(%%a0),#1,%0"
+		: : "n"(MCFCAU_STR+MCFCAU_CA3) : "a0");
+	asm("cp0st.l	%%d0,-(%%a0),#1,%0"
+		: : "n"(MCFCAU_STR+MCFCAU_CA2) : "a0");
+	asm("cp0st.l	%%d0,-(%%a0),#1,%0"
+		: : "n"(MCFCAU_STR+MCFCAU_CA1) : "a0");
+	asm("cp0st.l	%%d0,-(%%a0),#1,%0"
+		: : "n"(MCFCAU_STR+MCFCAU_CA0) : "a0");
+	spin_unlock_irqrestore(&mcfcau_lock, iflags);
+}
+
+static int mcfcau_sha1_init(struct shash_desc *desc)
+{
+	struct mcfcau_sha1_ctx *sctx = shash_desc_ctx(desc);
+	static const struct mcfcau_sha1_ctx initstate = {
+	  0,
+	  { 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 },
+	  { 0, }
+	};
+
+	DBG("mcfcau_sha1_init\n");
+	*sctx = initstate;
+
+	return 0;
+}
+
+static int mcfcau_sha1_update(struct shash_desc *desc, const u8 *data,
+				unsigned int len)
+{
+	struct mcfcau_sha1_ctx *sctx = shash_desc_ctx(desc);
+	unsigned int partial, done;
+	const u8 *src;
+
+	DBG("mcfcau_sha1_update\n");
+	partial = sctx->count & 0x3f;
+	sctx->count += len;
+	done = 0;
+	src = data;
+
+	if ((partial + len) > 63) {
+		u32 temp[MCFCAU_SHA1_WORKSPACE_WORDS];
+
+		if (partial) {
+			done = -partial;
+			memcpy(sctx->buffer + partial, data, done + 64);
+			src = sctx->buffer;
+		}
+
+		do {
+			mcfcau_sha1_transform(sctx->state, src, temp);
+			done += 64;
+			src = data + done;
+		} while (done + 63 < len);
+
+		memset(temp, 0, sizeof(temp));
+		partial = 0;
+	}
+	memcpy(sctx->buffer + partial, src, len - done);
+	return 0;
+}
+
+
+/* Add padding and return the message digest. */
+static int mcfcau_sha1_final(struct shash_desc *desc, u8 *out)
+{
+	struct mcfcau_sha1_ctx *sctx = shash_desc_ctx(desc);
+	u32 *dst = (u32 *)out;
+	u32 i, index, padlen;
+	u64 bits;
+	static const u8 padding[64] = { 0x80, };
+
+	DBG("mcfcau_sha1_final\n");
+	bits = sctx->count << 3;
+
+	/* Pad out to 56 mod 64 */
+	index = sctx->count & 0x3f;
+	padlen = (index < 56) ? (56 - index) : ((64+56) - index);
+	mcfcau_sha1_update(desc, padding, padlen);
+
+	/* Append length */
+	mcfcau_sha1_update(desc, (const u8 *)&bits, sizeof(bits));
+
+	/* Store state in digest */
+	for (i = 0; i < 5; i++)
+		dst[i] = sctx->state[i];
+
+	/* Wipe context */
+	memset(sctx, 0, sizeof *sctx);
+
+	return 0;
+}
+
+static struct shash_alg mcfcau_sha1_alg = {
+	.init		=	mcfcau_sha1_init,
+	.update		=	mcfcau_sha1_update,
+	.final		=	mcfcau_sha1_final,
+	.digestsize	=	MCFCAU_SHA1_DIGEST_SIZE,
+	.descsize	=	sizeof(struct mcfcau_sha1_ctx),
+	.statesize	=	sizeof(struct mcfcau_sha1_ctx),
+	.base	=	{
+		.cra_name	 =	"sha1",
+		.cra_driver_name =	"sha1-mcfcau",
+		.cra_priority	 =	MCFCAU_CRA_PRIORITY,
+		.cra_flags	 =	CRYPTO_ALG_TYPE_SHASH,
+		.cra_blocksize	 =	MCFCAU_SHA1_HMAC_BLOCK_SIZE,
+		.cra_module	 =	THIS_MODULE,
+		.cra_alignmask	 =	3,
+	}
+};
+
+static int __init init(void)
+{
+	int ret = crypto_register_shash(&mcfcau_sha1_alg);
+	printk(KERN_INFO MCFCAU_SHA1_DRIVER_DESC " "
+		MCFCAU_SHA1_DRIVER_VERSION " %s.\n",
+		ret ? "failed" : "registered");
+	return ret;
+}
+
+static void __exit fini(void)
+{
+	crypto_unregister_shash(&mcfcau_sha1_alg);
+	printk(KERN_INFO MCFCAU_SHA1_DRIVER_DESC " "
+		MCFCAU_SHA1_DRIVER_VERSION " unregistered.\n");
+}
+
+module_init(init);
+module_exit(fini);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(MCFCAU_SHA1_DRIVER_DESC);
+MODULE_AUTHOR("Andrey Butok");
--- /dev/null
+++ b/drivers/crypto/mcfcau.c
@@ -0,0 +1,33 @@
+/***************************************************************************
+ * mcfcau.c - Implementation of DES & Triple DES EDE Cipher Algorithms
+ *                for Freescale ColdFire Cryptographic Acceleration Unit (CAU).
+ *
+ * Copyright (C) 2007-2011 Freescale Semiconductor Inc. All Rights Reserved.
+ * Author: Andrey Butok
+ *         Shrek Wu B16972@freescale.com
+ *
+ * NOTE: You can find the ColdFire CAU module on MCF5445X and MCF52235.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ ***************************************************************************
+ * Changes:
+ * v0.01	28 September 2006	Andrey Butok
+ *		Initial Release - developed on 2.6.20 Linux kernel.
+ */
+#include <linux/module.h>
+
+DEFINE_SPINLOCK(mcfcau_lock);
+EXPORT_SYMBOL(mcfcau_lock);
--- /dev/null
+++ b/drivers/crypto/mcfcau.h
@@ -0,0 +1,101 @@
+/***************************************************************************
+ * mcfcau.h - Common header file for Freescale ColdFire
+ *            Cryptographic Acceleration Unit (CAU) drivers.
+ *
+ * Copyright (C) 2007-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Author: Andrey Butok
+ *         Shrek Wu B16972@freescale.com
+ *
+ * NOTE: You can find the ColdFire CAU module on MCF5445X and MCF52235.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ ***************************************************************************
+ * Changes:
+ * v0.01	14 August 2007	Andrey Butok
+ */
+
+#ifndef MCFCAU_H
+#define MCFCAU_H
+
+#include <linux/spinlock.h>
+
+/* CAU Registers (CAx) */
+#define MCFCAU_CASR		(0x0)
+#define MCFCAU_CAA		(0x1)
+#define MCFCAU_CA0		(0x2)
+#define MCFCAU_CA1		(0x3)
+#define MCFCAU_CA2		(0x4)
+#define MCFCAU_CA3		(0x5)
+#define MCFCAU_CA4		(0x6)
+#define MCFCAU_CA5		(0x7)
+
+ /* CAU Commands */
+#define MCFCAU_CNOP		(0x000)
+#define MCFCAU_LDR		(0x010)
+#define MCFCAU_STR		(0x020)
+#define MCFCAU_ADR		(0x030)
+#define MCFCAU_RADR		(0x040)
+#define MCFCAU_ADRA		(0x050)
+#define MCFCAU_XOR		(0x060)
+#define MCFCAU_ROTL		(0x070)
+#define MCFCAU_MVRA		(0x080)
+#define MCFCAU_MVAR		(0x090)
+#define MCFCAU_AESS		(0x0A0)
+#define MCFCAU_AESIS		(0x0B0)
+#define MCFCAU_AESC		(0x0C0)
+#define MCFCAU_AESIC		(0x0D0)
+#define MCFCAU_AESR		(0x0E0)
+#define MCFCAU_AESIR		(0x0F0)
+#define MCFCAU_DESR		(0x100)
+#define MCFCAU_DESK		(0x110)
+#define MCFCAU_HASH		(0x120)
+#define MCFCAU_SHS		(0x130)
+#define MCFCAU_MDS		(0x140)
+#define MCFCAU_ILL		(0x1F0)
+
+/* DESR Fields */
+#define MCFCAU_IP		(0x08)	/* initial permutation */
+#define MCFCAU_FP		(0x04)	/* final permutation */
+#define MCFCAU_KSL1		(0x00)	/* key schedule left 1 bit */
+#define MCFCAU_KSL2		(0x01)	/* key schedule left 2 bits */
+#define MCFCAU_KSR1		(0x02)	/* key schedule right 1 bit */
+#define MCFCAU_KSR2		(0x03)	/* key schedule right 2 bits */
+
+/* DESK Field */
+#define MCFCAU_DC		(0x01)	/* decrypt key schedule */
+#define MCFCAU_CP		(0x02)	/* check parity */
+
+/* HASH Functions Codes */
+#define MCFCAU_HFF		(0x0)	/* MD5 F() CA1&CA2 | ~CA1&CA3 */
+#define MCFCAU_HFG		(0x1)	/* MD5 G() CA1&CA3 | CA2&~CA3 */
+#define MCFCAU_HFH		(0x2)	/* MD5 H(), SHA Parity() CA1^CA2^CA3 */
+#define MCFCAU_HFI		(0x3)	/* MD5 I() CA2^(CA1|~CA3) */
+#define MCFCAU_HFC		(0x4)	/* SHA Ch() CA1&CA2 ^ ~CA1&CA3 */
+#define MCFCAU_HFM		(0x5)
+/* SHA Maj() CA1&CA2 ^ CA1&CA3 ^ CA2&CA3 */
+
+#define MCFCAU_CRA_PRIORITY	(300)
+
+extern spinlock_t mcfcau_lock;
+
+#ifdef DEBUG
+#define DBG(fmt, args...) printk(KERN_INFO "[%s]  " fmt ,\
+			__func__, ## args)
+#else
+#define DBG(fmt, args...) do {} while (0)
+#endif
+
+#endif
