aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/lantiq/patches/270-crypto.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/lantiq/patches/270-crypto.patch')
-rw-r--r--target/linux/lantiq/patches/270-crypto.patch6209
1 files changed, 6209 insertions, 0 deletions
diff --git a/target/linux/lantiq/patches/270-crypto.patch b/target/linux/lantiq/patches/270-crypto.patch
new file mode 100644
index 0000000000..e6ee88585c
--- /dev/null
+++ b/target/linux/lantiq/patches/270-crypto.patch
@@ -0,0 +1,6209 @@
+--- a/drivers/crypto/Kconfig
++++ b/drivers/crypto/Kconfig
+@@ -243,4 +243,75 @@
+ OMAP processors have SHA1/MD5 hw accelerator. Select this if you
+ want to use the OMAP module for SHA1/MD5 algorithms.
+
++config CRYPTO_DEV_LANTIQ
++ bool "Support for Lantiq crypto engine"
++ select CRYPTO_ALGAPI
++ default y
++ help
++ Will support Lantiq crypto hardware
++ If you are unsure, say M.
++
++menuconfig CRYPTO_DEV_LANTIQ_DES
++ bool "Lantiq crypto hardware for DES algorithm"
++ depends on CRYPTO_DEV_LANTIQ
++ select CRYPTO_BLKCIPHER
++ default y
++ help
++ Use crypto hardware for DES/3DES algorithm.
++ If unsure say N.
++
++menuconfig CRYPTO_DEV_LANTIQ_AES
++ bool "Lantiq crypto hardware for AES algorithm"
++ depends on CRYPTO_DEV_LANTIQ
++ select CRYPTO_BLKCIPHER
++ default y
++ help
++ Use crypto hardware for AES algorithm.
++ If unsure say N.
++
++menuconfig CRYPTO_DEV_LANTIQ_ARC4
++ bool "Lantiq crypto hardware for ARC4 algorithm"
++ depends on (CRYPTO_DEV_LANTIQ && IFXMIPS_AR9)
++ select CRYPTO_BLKCIPHER
++ default y
++ help
++ Use crypto hardware for ARC4 algorithm.
++ If unsure say N.
++
++menuconfig CRYPTO_DEV_LANTIQ_MD5
++ bool "Lantiq crypto hardware for MD5 algorithm"
++ depends on CRYPTO_DEV_LANTIQ
++ select CRYPTO_BLKCIPHER
++ default y
++ help
++ Use crypto hardware for MD5 algorithm.
++ If unsure say N.
++
++menuconfig CRYPTO_DEV_LANTIQ_SHA1
++ bool "Lantiq crypto hardware for SHA1 algorithm"
++ depends on CRYPTO_DEV_LANTIQ
++ select CRYPTO_BLKCIPHER
++ default y
++ help
++ Use crypto hardware for SHA1 algorithm.
++ If unsure say N.
++
++menuconfig CRYPTO_DEV_LANTIQ_SHA1_HMAC
++ bool "Lantiq crypto hardware for SHA1_HMAC algorithm"
++ depends on (CRYPTO_DEV_LANTIQ && IFXMIPS_AR9)
++ select CRYPTO_BLKCIPHER
++ default y
++ help
++ Use crypto hardware for SHA1_HMAC algorithm.
++ If unsure say N.
++
++menuconfig CRYPTO_DEV_LANTIQ_MD5_HMAC
++ bool "Lantiq crypto hardware for MD5_HMAC algorithms"
++ depends on (CRYPTO_DEV_LANTIQ && IFXMIPS_AR9)
++ select CRYPTO_BLKCIPHER
++ default y
++ help
++ Use crypto hardware for MD5_HMAC algorithm.
++ If unsure say N.
++
+ endif # CRYPTO_HW
+--- /dev/null
++++ b/drivers/crypto/lantiq/Makefile
+@@ -0,0 +1,11 @@
++obj-$(CONFIG_CRYPTO_DEV_LANTIQ) += deu.o
++obj-$(CONFIG_CRYPTO_DEV_LANTIQ) += deu_falcon.o
++obj-$(CONFIG_CRYPTO_DEV_LANTIQ) += deu_danube.o
++obj-$(CONFIG_CRYPTO_DEV_LANTIQ) += deu_ar9.o
++obj-$(CONFIG_CRYPTO_DEV_LANTIQ_DES) += des.o
++obj-$(CONFIG_CRYPTO_DEV_LANTIQ_AES) += aes.o
++obj-$(CONFIG_CRYPTO_DEV_LANTIQ_ARC4) += arc4.o
++obj-$(CONFIG_CRYPTO_DEV_LANTIQ_SHA1) += sha1.o
++obj-$(CONFIG_CRYPTO_DEV_LANTIQ_SHA1_HMAC) += sha1_hmac.o
++obj-$(CONFIG_CRYPTO_DEV_LANTIQ_MD5) += md5.o
++obj-$(CONFIG_CRYPTO_DEV_LANTIQ_MD5_HMAC) += md5_hmac.o
+--- /dev/null
++++ b/drivers/crypto/lantiq/aes.c
+@@ -0,0 +1,1029 @@
++/*
++ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com>
++ * Copyright (C) 2009 Mohammad Firdaus
++ */
++
++/**
++ \defgroup LQ_DEU LQ_DEU_DRIVERS
++ \ingroup API
++ \brief Lantiq DEU driver module
++*/
++
++/**
++ \file aes.c
++ \ingroup LQ_DEU
++ \brief AES Encryption Driver main file
++*/
++
++/**
++ \defgroup LQ_AES_FUNCTIONS LQ_AES_FUNCTIONS
++ \ingroup LQ_DEU
++ \brief Lantiq AES driver Functions
++*/
++
++#include <linux/version.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/crypto.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <asm/byteorder.h>
++#include <crypto/algapi.h>
++#include "deu.h"
++
++#ifdef CONFIG_CRYPTO_DEV_DMA
++# include "deu_dma.h"
++#endif
++
++static spinlock_t cipher_lock;
++
++/* Definition of constants */
++
++#define AES_MIN_KEY_SIZE 16
++#define AES_MAX_KEY_SIZE 32
++#define AES_BLOCK_SIZE 16
++#define CTR_RFC3686_NONCE_SIZE 4
++#define CTR_RFC3686_IV_SIZE 8
++#define CTR_RFC3686_MAX_KEY_SIZE (AES_MAX_KEY_SIZE \
++ + CTR_RFC3686_NONCE_SIZE)
++
++struct aes_ctx {
++ int key_length;
++ u32 buf[AES_MAX_KEY_SIZE];
++ u8 nonce[CTR_RFC3686_NONCE_SIZE];
++};
++
++/** \fn int aes_set_key(struct crypto_tfm *tfm, const uint8_t *in_key, unsigned int key_len)
++ * \ingroup LQ_AES_FUNCTIONS
++ * \brief sets the AES keys
++ * \param tfm linux crypto algo transform
++ * \param in_key input key
++ * \param key_len key lengths of 16, 24 and 32 bytes supported
++ * \return -EINVAL - bad key length, 0 - SUCCESS
++*/
++static int aes_set_key(struct crypto_tfm *tfm,
++ const u8 *in_key,
++ unsigned int key_len)
++{
++ struct aes_ctx *ctx = crypto_tfm_ctx(tfm);
++ u32 *flags = &tfm->crt_flags;
++
++ DPRINTF(0, "ctx @%p, key_len %d\n", ctx, key_len);
++
++ if (key_len != 16 && key_len != 24 && key_len != 32) {
++ *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
++ return -EINVAL;
++ }
++
++ ctx->key_length = key_len;
++ memcpy((u8 *)(ctx->buf), in_key, key_len);
++
++ return 0;
++}
++
++#ifndef CONFIG_CRYPTO_DEV_DMA
++/** \fn void deu_aes(void *ctx_arg, u8 *out_arg, const u8 *in_arg, u8 *iv_arg, size_t nbytes, int encdec, int mode)
++ * \ingroup LQ_AES_FUNCTIONS
++ * \brief main interface to AES hardware
++ * \param ctx_arg crypto algo context
++ * \param out_arg output bytestream
++ * \param in_arg input bytestream
++ * \param iv_arg initialization vector
++ * \param nbytes length of bytestream
++ * \param encdec 1 for encrypt; 0 for decrypt
++ * \param mode operation mode such as ebc, cbc, ctr
++ *
++*/
++static void deu_aes(void *ctx_arg,
++ u8 *out_arg,
++ const u8 *in_arg,
++ u8 *iv_arg,
++ size_t nbytes,
++ int encdec,
++ int mode)
++#else
++
++/** \fn void deu_aes_core(void *ctx_arg, u8 *out_arg, const u8 *in_arg, u8 *iv_arg, size_t nbytes, int encdec, int mode)
++ * \ingroup LQ_AES_FUNCTIONS
++ * \brief main interface to AES hardware
++ * \param ctx_arg crypto algo context
++ * \param out_arg output bytestream
++ * \param in_arg input bytestream
++ * \param iv_arg initialization vector
++ * \param nbytes length of bytestream
++ * \param encdec 1 for encrypt; 0 for decrypt
++ * \param mode operation mode such as ebc, cbc, ctr
++ *
++*/
++static void deu_aes_core(void *ctx_arg,
++ u8 *out_arg,
++ const u8 *in_arg,
++ u8 *iv_arg,
++ size_t nbytes,
++ int encdec,
++ int mode)
++#endif
++
++{
++ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
++ volatile struct deu_aes *aes = (volatile struct deu_aes *)AES_START;
++ struct aes_ctx *ctx = (struct aes_ctx *)ctx_arg;
++ u32 *in_key = ctx->buf;
++ ulong flag;
++ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
++ int key_len = ctx->key_length;
++
++#ifndef CONFIG_CRYPTO_DEV_DMA
++ int i = 0;
++ int byte_cnt = nbytes;
++#else
++ volatile struct deu_dma *dma = (struct deu_dma *)LQ_DEU_DMA_CON;
++ struct dma_device_info *dma_device = lq_deu[0].dma_device;
++ /* struct deu_drv_priv *deu_priv =
++ * (struct deu_drv_priv *)dma_device->priv; */
++ int wlen = 0;
++ u32 *outcopy = NULL;
++ u32 *dword_mem_aligned_in = NULL;
++
++# ifdef CONFIG_CRYPTO_DEV_POLL_DMA
++ u32 timeout = 0;
++ u32 *out_dma = NULL;
++# endif
++#endif
++
++ DPRINTF(0, "ctx @%p, mode %d, encdec %d\n", ctx, mode, encdec);
++
++ CRTCL_SECT_START;
++
++ /* 128, 192 or 256 bit key length */
++ aes->ctrl.K = key_len / 8 - 2;
++ if (key_len == 128 / 8) {
++ aes->K3R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 0));
++ aes->K2R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 1));
++ aes->K1R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 2));
++ aes->K0R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 3));
++ }
++ else if (key_len == 192 / 8) {
++ aes->K5R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 0));
++ aes->K4R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 1));
++ aes->K3R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 2));
++ aes->K2R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 3));
++ aes->K1R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 4));
++ aes->K0R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 5));
++ }
++ else if (key_len == 256 / 8) {
++ aes->K7R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 0));
++ aes->K6R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 1));
++ aes->K5R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 2));
++ aes->K4R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 3));
++ aes->K3R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 4));
++ aes->K2R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 5));
++ aes->K1R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 6));
++ aes->K0R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 7));
++ }
++ else {
++ CRTCL_SECT_END;
++ return; /* -EINVAL; */
++ }
++
++ /* let HW pre-process DEcryption key in any case (even if
++ ENcryption is used). Key Valid (KV) bit is then only
++ checked in decryption routine! */
++ aes->ctrl.PNK = 1;
++
++#ifdef CONFIG_CRYPTO_DEV_DMA
++ while (aes->ctrl.BUS) {
++ /* this will not take long */
++ }
++ AES_DMA_MISC_CONFIG();
++#endif
++
++ aes->ctrl.E_D = !encdec; /* encryption */
++ aes->ctrl.O = mode; /* 0 ECB 1 CBC 2 OFB 3 CFB 4 CTR */
++ aes->ctrl.SM = 1; /* start after writing input register */
++ aes->ctrl.DAU = 0; /* Disable Automatic Update of init
++ vector */
++ aes->ctrl.ARS = 1; /* Autostart Select - write to IHR */
++
++ /* aes->ctrl.F = 128; */ /* default; only for CFB and OFB modes;
++ change only for
++ customer-specific apps */
++ if (mode > 0) {
++ aes->IV3R = DEU_ENDIAN_SWAP(*(u32 *)iv_arg);
++ aes->IV2R = DEU_ENDIAN_SWAP(*((u32 *)iv_arg + 1));
++ aes->IV1R = DEU_ENDIAN_SWAP(*((u32 *)iv_arg + 2));
++ aes->IV0R = DEU_ENDIAN_SWAP(*((u32 *)iv_arg + 3));
++ };
++
++#ifndef CONFIG_CRYPTO_DEV_DMA
++ i = 0;
++ while (byte_cnt >= 16) {
++ aes->ID3R = INPUT_ENDIAN_SWAP(*((u32 *)in_arg + (i * 4) + 0));
++ aes->ID2R = INPUT_ENDIAN_SWAP(*((u32 *)in_arg + (i * 4) + 1));
++ aes->ID1R = INPUT_ENDIAN_SWAP(*((u32 *)in_arg + (i * 4) + 2));
++ /* start crypto */
++ aes->ID0R = INPUT_ENDIAN_SWAP(*((u32 *)in_arg + (i * 4) + 3));
++
++ while (aes->ctrl.BUS) {
++ /* this will not take long */
++ }
++
++ *((volatile u32 *)out_arg + (i * 4) + 0) = aes->OD3R;
++ *((volatile u32 *)out_arg + (i * 4) + 1) = aes->OD2R;
++ *((volatile u32 *)out_arg + (i * 4) + 2) = aes->OD1R;
++ *((volatile u32 *)out_arg + (i * 4) + 3) = aes->OD0R;
++
++ i++;
++ byte_cnt -= 16;
++ }
++#else /* dma */
++ /* Prepare Rx buf length used in dma psuedo interrupt */
++ /* deu_priv->deu_rx_buf = out_arg; */
++ /* deu_priv->deu_rx_len = nbytes; */
++
++ /* memory alignment issue */
++ dword_mem_aligned_in = (u32 *)DEU_DWORD_REORDERING(in_arg,
++ aes_buff_in,
++ BUFFER_IN, nbytes);
++
++ dma->ctrl.ALGO = 1; /* AES */
++ dma->ctrl.BS = 0;
++ aes->ctrl.DAU = 0;
++ dma->ctrl.EN = 1;
++
++ while (aes->ctrl.BUS) {
++ /* wait for AES to be ready */
++ };
++
++ wlen = dma_device_write(dma_device, (u8 *)dword_mem_aligned_in,
++ nbytes, NULL);
++ if (wlen != nbytes) {
++ dma->ctrl.EN = 0;
++ CRTCL_SECT_END;
++ printk(KERN_ERR "[%s %s %d]: dma_device_write fail!\n",
++ __FILE__, __func__, __LINE__);
++ return; /* -EINVAL; */
++ }
++
++ WAIT_AES_DMA_READY();
++
++# ifdef CONFIG_CRYPTO_DEV_POLL_DMA
++ outcopy = (u32 *)DEU_DWORD_REORDERING(out_arg, aes_buff_out,
++ BUFFER_OUT, nbytes);
++
++ /* polling DMA rx channel */
++ while ((dma_device_read(dma_device, (u8 **)&out_dma, NULL)) == 0) {
++ timeout++;
++
++ if (timeout >= 333000) {
++ dma->ctrl.EN = 0;
++ CRTCL_SECT_END;
++ printk (KERN_ERR "[%s %s %d]: timeout!!\n",
++ __FILE__, __func__, __LINE__);
++ return; /* -EINVAL; */
++ }
++ }
++
++ WAIT_AES_DMA_READY();
++
++ AES_MEMORY_COPY(outcopy, out_dma, out_arg, nbytes);
++
++# else /* not working at the moment.. */
++ CRTCL_SECT_END;
++
++ /* sleep and wait for Rx finished */
++ DEU_WAIT_EVENT(deu_priv->deu_thread_wait, DEU_EVENT,
++ deu_priv->deu_event_flags);
++
++ CRTCL_SECT_START;
++# endif
++
++#endif /* dma */
++
++ /* tc.chen : copy iv_arg back */
++ if (mode > 0) {
++ *((u32 *)iv_arg) = DEU_ENDIAN_SWAP(*((u32 *)iv_arg));
++ *((u32 *)iv_arg + 1) = DEU_ENDIAN_SWAP(*((u32 *)iv_arg + 1));
++ *((u32 *)iv_arg + 2) = DEU_ENDIAN_SWAP(*((u32 *)iv_arg + 2));
++ *((u32 *)iv_arg + 3) = DEU_ENDIAN_SWAP(*((u32 *)iv_arg + 3));
++ }
++
++ CRTCL_SECT_END;
++}
++
++/** \fn int ctr_rfc3686_aes_set_key(struct crypto_tfm *tfm, const uint8_t *in_key, unsigned int key_len)
++ * \ingroup LQ_AES_FUNCTIONS
++ * \brief sets RFC3686 key
++ * \param tfm linux crypto algo transform
++ * \param in_key input key
++ * \param key_len key lengths of 20, 28 and 36 bytes supported; last 4 bytes is nonce
++ * \return 0 - SUCCESS
++ * -EINVAL - bad key length
++*/
++static int ctr_rfc3686_aes_set_key(struct crypto_tfm *tfm,
++ const uint8_t *in_key,
++ unsigned int key_len)
++{
++ struct aes_ctx *ctx = crypto_tfm_ctx(tfm);
++ u32 *flags = &tfm->crt_flags;
++
++ memcpy(ctx->nonce, in_key + (key_len - CTR_RFC3686_NONCE_SIZE),
++ CTR_RFC3686_NONCE_SIZE);
++
++ key_len -= CTR_RFC3686_NONCE_SIZE; /* remove 4 bytes of nonce */
++
++ if (key_len != 16 && key_len != 24 && key_len != 32) {
++ *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
++ return -EINVAL;
++ }
++
++ ctx->key_length = key_len;
++
++ memcpy((u8 *)(ctx->buf), in_key, key_len);
++
++ return 0;
++}
++
++/** \fn void deu_aes(void *ctx_arg, u8 *out_arg, const u8 *in_arg, u8 *iv_arg, u32 nbytes, int encdec, int mode)
++ * \ingroup LQ_AES_FUNCTIONS
++ * \brief main interface with DEU hardware in DMA mode
++ * \param ctx_arg crypto algo context
++ * \param out_arg output bytestream
++ * \param in_arg input bytestream
++ * \param iv_arg initialization vector
++ * \param nbytes length of bytestream
++ * \param encdec 1 for encrypt; 0 for decrypt
++ * \param mode operation mode such as ebc, cbc, ctr
++*/
++
++#ifdef CONFIG_CRYPTO_DEV_DMA
++static void deu_aes(void *ctx_arg,
++ u8 *out_arg,
++ const u8 *in_arg,
++ u8 *iv_arg,
++ u32 nbytes,
++ int encdec,
++ int mode)
++{
++ u32 remain = nbytes;
++ u32 inc;
++
++ while (remain > 0) {
++ if (remain >= DEU_MAX_PACKET_SIZE)
++ inc = DEU_MAX_PACKET_SIZE;
++ else
++ inc = remain;
++
++ remain -= inc;
++
++ deu_aes_core(ctx_arg, out_arg, in_arg, iv_arg, inc, encdec,
++ mode);
++
++ out_arg += inc;
++ in_arg += inc;
++ }
++}
++#endif
++
++/* definitions from linux/include/crypto.h:
++#define CRYPTO_TFM_MODE_ECB 0x00000001
++#define CRYPTO_TFM_MODE_CBC 0x00000002
++#define CRYPTO_TFM_MODE_CFB 0x00000004
++#define CRYPTO_TFM_MODE_CTR 0x00000008
++#define CRYPTO_TFM_MODE_OFB 0x00000010
++but hardware definition: 0 ECB 1 CBC 2 OFB 3 CFB 4 CTR */
++
++/** \fn void deu_aes_ecb(void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace)
++ * \ingroup LQ_AES_FUNCTIONS
++ * \brief sets AES hardware to ECB mode
++ * \param ctx crypto algo context
++ * \param dst output bytestream
++ * \param src input bytestream
++ * \param iv initialization vector
++ * \param nbytes length of bytestream
++ * \param encdec 1 for encrypt; 0 for decrypt
++ * \param inplace not used
++*/
++static void deu_aes_ecb(void *ctx,
++ uint8_t *dst,
++ const uint8_t *src,
++ uint8_t *iv,
++ size_t nbytes,
++ int encdec,
++ int inplace)
++{
++ deu_aes(ctx, dst, src, NULL, nbytes, encdec, 0);
++}
++
++/** \fn void deu_aes_cbc(void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace)
++ * \ingroup LQ_AES_FUNCTIONS
++ * \brief sets AES hardware to CBC mode
++ * \param ctx crypto algo context
++ * \param dst output bytestream
++ * \param src input bytestream
++ * \param iv initialization vector
++ * \param nbytes length of bytestream
++ * \param encdec 1 for encrypt; 0 for decrypt
++ * \param inplace not used
++*/
++static void deu_aes_cbc(void *ctx,
++ uint8_t *dst,
++ const uint8_t *src,
++ uint8_t *iv,
++ size_t nbytes,
++ int encdec,
++ int inplace)
++{
++ deu_aes(ctx, dst, src, iv, nbytes, encdec, 1);
++}
++
++#if 0
++/** \fn void deu_aes_ofb(void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace)
++ * \ingroup LQ_AES_FUNCTIONS
++ * \brief sets AES hardware to OFB mode
++ * \param ctx crypto algo context
++ * \param dst output bytestream
++ * \param src input bytestream
++ * \param iv initialization vector
++ * \param nbytes length of bytestream
++ * \param encdec 1 for encrypt; 0 for decrypt
++ * \param inplace not used
++*/
++static void deu_aes_ofb(void *ctx,
++ uint8_t *dst,
++ const uint8_t *src,
++ uint8_t *iv,
++ size_t nbytes,
++ int encdec,
++ int inplace)
++{
++ deu_aes(ctx, dst, src, iv, nbytes, encdec, 2);
++}
++
++/** \fn void deu_aes_cfb(void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace)
++ * \ingroup LQ_AES_FUNCTIONS
++ * \brief sets AES hardware to CFB mode
++ * \param ctx crypto algo context
++ * \param dst output bytestream
++ * \param src input bytestream
++ * \param iv initialization vector
++ * \param nbytes length of bytestream
++ * \param encdec 1 for encrypt; 0 for decrypt
++ * \param inplace not used
++*/
++static void deu_aes_cfb(void *ctx,
++ uint8_t *dst,
++ const uint8_t *src,
++ uint8_t *iv,
++ size_t nbytes,
++ int encdec,
++ int inplace)
++{
++ deu_aes(ctx, dst, src, iv, nbytes, encdec, 3);
++}
++#endif
++
++/** \fn void deu_aes_ctr(void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace)
++ * \ingroup LQ_AES_FUNCTIONS
++ * \brief sets AES hardware to CTR mode
++ * \param ctx crypto algo context
++ * \param dst output bytestream
++ * \param src input bytestream
++ * \param iv initialization vector
++ * \param nbytes length of bytestream
++ * \param encdec 1 for encrypt; 0 for decrypt
++ * \param inplace not used
++*/
++static void deu_aes_ctr(void *ctx,
++ uint8_t *dst,
++ const uint8_t *src,
++ uint8_t *iv,
++ size_t nbytes,
++ int encdec,
++ int inplace)
++{
++ deu_aes(ctx, dst, src, iv, nbytes, encdec, 4);
++}
++
++/** \fn void aes_encrypt(struct crypto_tfm *tfm, uint8_t *out, const uint8_t *in)
++ * \ingroup LQ_AES_FUNCTIONS
++ * \brief encrypt AES_BLOCK_SIZE of data
++ * \param tfm linux crypto algo transform
++ * \param out output bytestream
++ * \param in input bytestream
++*/
++static void aes_encrypt(struct crypto_tfm *tfm, uint8_t *out, const uint8_t *in)
++{
++ struct aes_ctx *ctx = crypto_tfm_ctx(tfm);
++ deu_aes(ctx, out, in, NULL, AES_BLOCK_SIZE, CRYPTO_DIR_ENCRYPT, 0);
++}
++
++/** \fn void aes_decrypt(struct crypto_tfm *tfm, uint8_t *out, const uint8_t *in)
++ * \ingroup LQ_AES_FUNCTIONS
++ * \brief decrypt AES_BLOCK_SIZE of data
++ * \param tfm linux crypto algo transform
++ * \param out output bytestream
++ * \param in input bytestream
++*/
++static void aes_decrypt(struct crypto_tfm *tfm, uint8_t *out, const uint8_t *in)
++{
++ struct aes_ctx *ctx = crypto_tfm_ctx(tfm);
++ deu_aes(ctx, out, in, NULL, AES_BLOCK_SIZE, CRYPTO_DIR_DECRYPT, 0);
++}
++
++/*
++ * \brief AES function mappings
++*/
++static struct crypto_alg aes_alg = {
++ .cra_name = "aes",
++ .cra_driver_name = "lq_deu-aes",
++ .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
++ .cra_blocksize = AES_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct aes_ctx),
++ .cra_module = THIS_MODULE,
++ .cra_list = LIST_HEAD_INIT(aes_alg.cra_list),
++ .cra_u = {
++ .cipher = {
++ .cia_min_keysize = AES_MIN_KEY_SIZE,
++ .cia_max_keysize = AES_MAX_KEY_SIZE,
++ .cia_setkey = aes_set_key,
++ .cia_encrypt = aes_encrypt,
++ .cia_decrypt = aes_decrypt,
++ }
++ }
++};
++
++/** \fn int ecb_aes_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes)
++ * \ingroup LQ_AES_FUNCTIONS
++ * \brief ECB AES encrypt using linux crypto blkcipher
++ * \param desc blkcipher descriptor
++ * \param dst output scatterlist
++ * \param src input scatterlist
++ * \param nbytes data size in bytes
++ * \return err
++*/
++static int ecb_aes_encrypt(struct blkcipher_desc *desc,
++ struct scatterlist *dst,
++ struct scatterlist *src,
++ unsigned int nbytes)
++{
++ struct aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
++ struct blkcipher_walk walk;
++ int err;
++
++ blkcipher_walk_init(&walk, dst, src, nbytes);
++ err = blkcipher_walk_virt(desc, &walk);
++
++ while ((nbytes = walk.nbytes)) {
++ nbytes -= (nbytes % AES_BLOCK_SIZE);
++ deu_aes_ecb(ctx, walk.dst.virt.addr, walk.src.virt.addr,
++ NULL, nbytes, CRYPTO_DIR_ENCRYPT, 0);
++ nbytes &= AES_BLOCK_SIZE - 1;
++ err = blkcipher_walk_done(desc, &walk, nbytes);
++ }
++
++ return err;
++}
++
++/** \fn int ecb_aes_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes)
++ * \ingroup LQ_AES_FUNCTIONS
++ * \brief ECB AES decrypt using linux crypto blkcipher
++ * \param desc blkcipher descriptor
++ * \param dst output scatterlist
++ * \param src input scatterlist
++ * \param nbytes data size in bytes
++ * \return err
++*/
++static int ecb_aes_decrypt(struct blkcipher_desc *desc,
++ struct scatterlist *dst,
++ struct scatterlist *src,
++ unsigned int nbytes)
++{
++ struct aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
++ struct blkcipher_walk walk;
++ int err;
++
++ blkcipher_walk_init(&walk, dst, src, nbytes);
++ err = blkcipher_walk_virt(desc, &walk);
++
++ while ((nbytes = walk.nbytes)) {
++ nbytes -= (nbytes % AES_BLOCK_SIZE);
++ deu_aes_ecb(ctx, walk.dst.virt.addr, walk.src.virt.addr,
++ NULL, nbytes, CRYPTO_DIR_DECRYPT, 0);
++ nbytes &= AES_BLOCK_SIZE - 1;
++ err = blkcipher_walk_done(desc, &walk, nbytes);
++ }
++
++ return err;
++}
++
++/*
++ * \brief AES function mappings
++*/
++static struct crypto_alg ecb_aes_alg = {
++ .cra_name = "ecb(aes)",
++ .cra_driver_name = "lq_deu-ecb(aes)",
++ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
++ .cra_blocksize = AES_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct aes_ctx),
++ .cra_type = &crypto_blkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_list = LIST_HEAD_INIT(ecb_aes_alg.cra_list),
++ .cra_u = {
++ .blkcipher = {
++ .min_keysize = AES_MIN_KEY_SIZE,
++ .max_keysize = AES_MAX_KEY_SIZE,
++ .setkey = aes_set_key,
++ .encrypt = ecb_aes_encrypt,
++ .decrypt = ecb_aes_decrypt,
++ }
++ }
++};
++
++/** \fn int cbc_aes_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes)
++ * \ingroup LQ_AES_FUNCTIONS
++ * \brief CBC AES encrypt using linux crypto blkcipher
++ * \param desc blkcipher descriptor
++ * \param dst output scatterlist
++ * \param src input scatterlist
++ * \param nbytes data size in bytes
++ * \return err
++*/
++static int cbc_aes_encrypt(struct blkcipher_desc *desc,
++ struct scatterlist *dst,
++ struct scatterlist *src,
++ unsigned int nbytes)
++{
++ struct aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
++ struct blkcipher_walk walk;
++ int err;
++
++ blkcipher_walk_init(&walk, dst, src, nbytes);
++ err = blkcipher_walk_virt(desc, &walk);
++
++ while ((nbytes = walk.nbytes)) {
++ u8 *iv = walk.iv;
++ nbytes -= (nbytes % AES_BLOCK_SIZE);
++ deu_aes_cbc(ctx, walk.dst.virt.addr, walk.src.virt.addr,
++ iv, nbytes, CRYPTO_DIR_ENCRYPT, 0);
++ nbytes &= AES_BLOCK_SIZE - 1;
++ err = blkcipher_walk_done(desc, &walk, nbytes);
++ }
++
++ return err;
++}
++
++/** \fn int cbc_aes_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes)
++ * \ingroup LQ_AES_FUNCTIONS
++ * \brief CBC AES decrypt using linux crypto blkcipher
++ * \param desc blkcipher descriptor
++ * \param dst output scatterlist
++ * \param src input scatterlist
++ * \param nbytes data size in bytes
++ * \return err
++*/
++static int cbc_aes_decrypt(struct blkcipher_desc *desc,
++ struct scatterlist *dst,
++ struct scatterlist *src,
++ unsigned int nbytes)
++{
++ struct aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
++ struct blkcipher_walk walk;
++ int err;
++
++ blkcipher_walk_init(&walk, dst, src, nbytes);
++ err = blkcipher_walk_virt(desc, &walk);
++
++ while ((nbytes = walk.nbytes)) {
++ u8 *iv = walk.iv;
++ nbytes -= (nbytes % AES_BLOCK_SIZE);
++ deu_aes_cbc(ctx, walk.dst.virt.addr, walk.src.virt.addr,
++ iv, nbytes, CRYPTO_DIR_DECRYPT, 0);
++ nbytes &= AES_BLOCK_SIZE - 1;
++ err = blkcipher_walk_done(desc, &walk, nbytes);
++ }
++
++ return err;
++}
++
++/*
++ * \brief AES function mappings
++*/
++static struct crypto_alg cbc_aes_alg = {
++ .cra_name = "cbc(aes)",
++ .cra_driver_name = "lq_deu-cbc(aes)",
++ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
++ .cra_blocksize = AES_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct aes_ctx),
++ .cra_type = &crypto_blkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_list = LIST_HEAD_INIT(cbc_aes_alg.cra_list),
++ .cra_u = {
++ .blkcipher = {
++ .min_keysize = AES_MIN_KEY_SIZE,
++ .max_keysize = AES_MAX_KEY_SIZE,
++ .ivsize = AES_BLOCK_SIZE,
++ .setkey = aes_set_key,
++ .encrypt = cbc_aes_encrypt,
++ .decrypt = cbc_aes_decrypt,
++ }
++ }
++};
++
++/** \fn int ctr_basic_aes_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes)
++ * \ingroup LQ_AES_FUNCTIONS
++ * \brief Counter mode AES encrypt using linux crypto blkcipher
++ * \param desc blkcipher descriptor
++ * \param dst output scatterlist
++ * \param src input scatterlist
++ * \param nbytes data size in bytes
++ * \return err
++*/
++static int ctr_basic_aes_encrypt(struct blkcipher_desc *desc,
++ struct scatterlist *dst,
++ struct scatterlist *src,
++ unsigned int nbytes)
++{
++ struct aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
++ struct blkcipher_walk walk;
++ int err;
++
++ blkcipher_walk_init(&walk, dst, src, nbytes);
++ err = blkcipher_walk_virt(desc, &walk);
++
++ while ((nbytes = walk.nbytes)) {
++ u8 *iv = walk.iv;
++ nbytes -= (nbytes % AES_BLOCK_SIZE);
++ deu_aes_ctr(ctx, walk.dst.virt.addr, walk.src.virt.addr,
++ iv, nbytes, CRYPTO_DIR_ENCRYPT, 0);
++ nbytes &= AES_BLOCK_SIZE - 1;
++ err = blkcipher_walk_done(desc, &walk, nbytes);
++ }
++
++ return err;
++}
++
++/** \fn int ctr_basic_aes_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes)
++ * \ingroup LQ_AES_FUNCTIONS
++ * \brief Counter mode AES decrypt using linux crypto blkcipher
++ * \param desc blkcipher descriptor
++ * \param dst output scatterlist
++ * \param src input scatterlist
++ * \param nbytes data size in bytes
++ * \return err
++*/
++static int ctr_basic_aes_decrypt(struct blkcipher_desc *desc,
++ struct scatterlist *dst,
++ struct scatterlist *src,
++ unsigned int nbytes)
++{
++ struct aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
++ struct blkcipher_walk walk;
++ int err;
++
++ blkcipher_walk_init(&walk, dst, src, nbytes);
++ err = blkcipher_walk_virt(desc, &walk);
++
++ while ((nbytes = walk.nbytes)) {
++ u8 *iv = walk.iv;
++ nbytes -= (nbytes % AES_BLOCK_SIZE);
++ deu_aes_ctr(ctx, walk.dst.virt.addr, walk.src.virt.addr,
++ iv, nbytes, CRYPTO_DIR_DECRYPT, 0);
++ nbytes &= AES_BLOCK_SIZE - 1;
++ err = blkcipher_walk_done(desc, &walk, nbytes);
++ }
++
++ return err;
++}
++
++/*
++ * \brief AES function mappings
++*/
++static struct crypto_alg ctr_basic_aes_alg = {
++ .cra_name = "ctr(aes)",
++ .cra_driver_name = "lq_deu-ctr(aes)",
++ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
++ .cra_blocksize = AES_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct aes_ctx),
++ .cra_type = &crypto_blkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_list = LIST_HEAD_INIT(ctr_basic_aes_alg.cra_list),
++ .cra_u = {
++ .blkcipher = {
++ .min_keysize = AES_MIN_KEY_SIZE,
++ .max_keysize = AES_MAX_KEY_SIZE,
++ .ivsize = AES_BLOCK_SIZE,
++ .setkey = aes_set_key,
++ .encrypt = ctr_basic_aes_encrypt,
++ .decrypt = ctr_basic_aes_decrypt,
++ }
++ }
++};
++
++/** \fn int ctr_rfc3686_aes_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes)
++ * \ingroup LQ_AES_FUNCTIONS
++ * \brief Counter mode AES (rfc3686) encrypt using linux crypto blkcipher
++ * \param desc blkcipher descriptor
++ * \param dst output scatterlist
++ * \param src input scatterlist
++ * \param nbytes data size in bytes
++ * \return err
++*/
++static int ctr_rfc3686_aes_encrypt(struct blkcipher_desc *desc,
++ struct scatterlist *dst,
++ struct scatterlist *src,
++ unsigned int nbytes)
++{
++ struct aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
++ struct blkcipher_walk walk;
++ int err;
++ u8 rfc3686_iv[16];
++
++ blkcipher_walk_init(&walk, dst, src, nbytes);
++ err = blkcipher_walk_virt(desc, &walk);
++
++ /* set up counter block */
++ memcpy(rfc3686_iv, ctx->nonce, CTR_RFC3686_NONCE_SIZE);
++ memcpy(rfc3686_iv + CTR_RFC3686_NONCE_SIZE, walk.iv,
++ CTR_RFC3686_IV_SIZE);
++
++ /* initialize counter portion of counter block */
++ *(__be32 *)(rfc3686_iv + CTR_RFC3686_NONCE_SIZE + CTR_RFC3686_IV_SIZE) =
++ cpu_to_be32(1);
++
++ while ((nbytes = walk.nbytes)) {
++ nbytes -= (nbytes % AES_BLOCK_SIZE);
++ deu_aes_ctr(ctx, walk.dst.virt.addr, walk.src.virt.addr,
++ rfc3686_iv, nbytes, CRYPTO_DIR_ENCRYPT, 0);
++ nbytes &= AES_BLOCK_SIZE - 1;
++ err = blkcipher_walk_done(desc, &walk, nbytes);
++ }
++
++ return err;
++}
++
++/** \fn int ctr_rfc3686_aes_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes)
++ * \ingroup LQ_AES_FUNCTIONS
++ * \brief Counter mode AES (rfc3686) decrypt using linux crypto blkcipher
++ * \param desc blkcipher descriptor
++ * \param dst output scatterlist
++ * \param src input scatterlist
++ * \param nbytes data size in bytes
++ * \return err
++*/
++static int ctr_rfc3686_aes_decrypt(struct blkcipher_desc *desc,
++ struct scatterlist *dst,
++ struct scatterlist *src,
++ unsigned int nbytes)
++{
++ struct aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
++ struct blkcipher_walk walk;
++ int err;
++ u8 rfc3686_iv[16];
++
++ blkcipher_walk_init(&walk, dst, src, nbytes);
++ err = blkcipher_walk_virt(desc, &walk);
++
++ /* set up counter block */
++ memcpy(rfc3686_iv, ctx->nonce, CTR_RFC3686_NONCE_SIZE);
++ memcpy(rfc3686_iv + CTR_RFC3686_NONCE_SIZE, walk.iv,
++ CTR_RFC3686_IV_SIZE);
++
++ /* initialize counter portion of counter block */
++ *(__be32 *)(rfc3686_iv + CTR_RFC3686_NONCE_SIZE + CTR_RFC3686_IV_SIZE) =
++ cpu_to_be32(1);
++
++ while ((nbytes = walk.nbytes)) {
++ nbytes -= (nbytes % AES_BLOCK_SIZE);
++ deu_aes_ctr(ctx, walk.dst.virt.addr, walk.src.virt.addr,
++ rfc3686_iv, nbytes, CRYPTO_DIR_DECRYPT, 0);
++ nbytes &= AES_BLOCK_SIZE - 1;
++ err = blkcipher_walk_done(desc, &walk, nbytes);
++ }
++
++ return err;
++}
++
++/*
++ * \brief AES function mappings
++*/
++static struct crypto_alg ctr_rfc3686_aes_alg = {
++ .cra_name = "rfc3686(ctr(aes))",
++ .cra_driver_name = "lq_deu-ctr-rfc3686(aes)",
++ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
++ .cra_blocksize = AES_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct aes_ctx),
++ .cra_type = &crypto_blkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_list = LIST_HEAD_INIT(ctr_rfc3686_aes_alg.cra_list),
++ .cra_u = {
++ .blkcipher = {
++ .min_keysize = AES_MIN_KEY_SIZE,
++ .max_keysize = CTR_RFC3686_MAX_KEY_SIZE,
++ .ivsize = CTR_RFC3686_IV_SIZE,
++ .setkey = ctr_rfc3686_aes_set_key,
++ .encrypt = ctr_rfc3686_aes_encrypt,
++ .decrypt = ctr_rfc3686_aes_decrypt,
++ }
++ }
++};
++
++/** \fn int lq_deu_init_aes (void)
++ * \ingroup LQ_AES_FUNCTIONS
++ * \brief function to initialize AES driver
++ * \return ret
++*/
++int lq_deu_init_aes(void)
++{
++ int ret;
++
++ if ((ret = crypto_register_alg(&aes_alg)))
++ goto aes_err;
++
++ if ((ret = crypto_register_alg(&ecb_aes_alg)))
++ goto ecb_aes_err;
++
++ if ((ret = crypto_register_alg(&cbc_aes_alg)))
++ goto cbc_aes_err;
++
++ if ((ret = crypto_register_alg(&ctr_basic_aes_alg)))
++ goto ctr_basic_aes_err;
++
++ if ((ret = crypto_register_alg(&ctr_rfc3686_aes_alg)))
++ goto ctr_rfc3686_aes_err;
++
++ deu_aes_chip_init();
++
++ CRTCL_SECT_INIT;
++
++#ifdef CONFIG_CRYPTO_DEV_DMA
++ if (ALLOCATE_MEMORY(BUFFER_IN, AES_ALGO) < 0) {
++ printk(KERN_ERR "[%s %s %d]: malloc memory fail!\n",
++ __FILE__, __func__, __LINE__);
++ goto ctr_rfc3686_aes_err;
++ }
++ if (ALLOCATE_MEMORY(BUFFER_OUT, AES_ALGO) < 0) {
++ printk(KERN_ERR "[%s %s %d]: malloc memory fail!\n",
++ __FILE__, __func__, __LINE__);
++ goto ctr_rfc3686_aes_err;
++ }
++#endif
++
++ printk(KERN_NOTICE "Lantiq DEU AES initialized%s.\n",
++ disable_deudma ? "" : " (DMA)");
++ return ret;
++
++ctr_rfc3686_aes_err:
++ crypto_unregister_alg(&ctr_rfc3686_aes_alg);
++ printk(KERN_ERR "Lantiq ctr_rfc3686_aes initialization failed!\n");
++ return ret;
++ctr_basic_aes_err:
++ crypto_unregister_alg(&ctr_basic_aes_alg);
++ printk(KERN_ERR "Lantiq ctr_basic_aes initialization failed!\n");
++ return ret;
++cbc_aes_err:
++ crypto_unregister_alg(&cbc_aes_alg);
++ printk(KERN_ERR "Lantiq cbc_aes initialization failed!\n");
++ return ret;
++ecb_aes_err:
++ crypto_unregister_alg(&ecb_aes_alg);
++ printk(KERN_ERR "Lantiq aes initialization failed!\n");
++ return ret;
++aes_err:
++ printk(KERN_ERR "Lantiq DEU AES initialization failed!\n");
++ return ret;
++}
++
++/** \fn void lq_deu_fini_aes(void)
++ * \ingroup LQ_AES_FUNCTIONS
++ * \brief unregister aes driver
++*/
++void lq_deu_fini_aes(void)
++{
++ crypto_unregister_alg(&aes_alg);
++ crypto_unregister_alg(&ecb_aes_alg);
++ crypto_unregister_alg(&cbc_aes_alg);
++ crypto_unregister_alg(&ctr_basic_aes_alg);
++ crypto_unregister_alg(&ctr_rfc3686_aes_alg);
++
++#ifdef CONFIG_CRYPTO_DEV_DMA
++ FREE_MEMORY(aes_buff_in);
++ FREE_MEMORY(aes_buff_out);
++#endif
++}
+--- /dev/null
++++ b/drivers/crypto/lantiq/arc4.c
+@@ -0,0 +1,397 @@
++/*
++ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com>
++ * Copyright (C) 2009 Mohammad Firdaus
++ */
++
++/**
++ \defgroup LQ_DEU LQ_DEU_DRIVERS
++ \ingroup API
++ \brief Lantiq DEU driver module
++*/
++
++/**
++ \file arc4.c
++ \ingroup LQ_DEU
++ \brief ARC4 encryption DEU driver file
++*/
++
++/**
++ \defgroup LQ_ARC4_FUNCTIONS LQ_ARC4_FUNCTIONS
++ \ingroup LQ_DEU
++ \brief Lantiq DEU driver functions
++*/
++
++#include <linux/version.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/crypto.h>
++#include <crypto/algapi.h>
++#include <linux/interrupt.h>
++#include <asm/byteorder.h>
++#include <linux/delay.h>
++
++#ifdef CONFIG_SOL_LANTIQ_XWAY
++
++#include "deu.h"
++
++#ifdef CONFIG_CRYPTO_DEV_LANTIQ_DMA
++
++static spinlock_t cipher_lock;
++
++/* Preprocessor declerations */
++#define ARC4_MIN_KEY_SIZE 1
++/* #define ARC4_MAX_KEY_SIZE 256 */
++#define ARC4_MAX_KEY_SIZE 16
++#define ARC4_BLOCK_SIZE 1
++
++/*
++ * \brief arc4 private structure
++*/
++struct arc4_ctx {
++ int key_length;
++ u8 buf[120];
++};
++
++/** \fn static void deu_arc4(void *ctx_arg, u8 *out_arg, const u8 *in_arg, u8 *iv_arg, u32 nbytes, int encdec, int mode)
++ \ingroup LQ_ARC4_FUNCTIONS
++ \brief main interface to AES hardware
++ \param ctx_arg crypto algo context
++ \param out_arg output bytestream
++ \param in_arg input bytestream
++ \param iv_arg initialization vector
++ \param nbytes length of bytestream
++ \param encdec 1 for encrypt; 0 for decrypt
++ \param mode operation mode such as ebc, cbc, ctr
++*/
++static void deu_arc4(void *ctx_arg,
++ u8 *out_arg,
++ const u8 *in_arg,
++ u8 *iv_arg,
++ u32 nbytes,
++ int encdec,
++ int mode)
++{
++ volatile struct deu_arc4 *arc4 = (struct deu_arc4 *) ARC4_START;
++ int i = 0;
++ ulong flag;
++
++#if 1 /* need to handle nbytes not multiple of 16 */
++ volatile u32 tmp_array32[4];
++ volatile u8 *tmp_ptr8;
++ int remaining_bytes, j;
++#endif
++
++ CRTCL_SECT_START;
++
++ arc4->IDLEN = nbytes;
++
++#if 1
++ while (i < nbytes) {
++ arc4->ID3R = *((u32 *) in_arg + (i>>2) + 0);
++ arc4->ID2R = *((u32 *) in_arg + (i>>2) + 1);
++ arc4->ID1R = *((u32 *) in_arg + (i>>2) + 2);
++ arc4->ID0R = *((u32 *) in_arg + (i>>2) + 3);
++
++ arc4->ctrl.GO = 1;
++
++ while (arc4->ctrl.BUS) {
++ /* this will not take long */ }
++
++#if 1
++ /* need to handle nbytes not multiple of 16 */
++ tmp_array32[0] = arc4->OD3R;
++ tmp_array32[1] = arc4->OD2R;
++ tmp_array32[2] = arc4->OD1R;
++ tmp_array32[3] = arc4->OD0R;
++
++ remaining_bytes = nbytes - i;
++ if (remaining_bytes > 16)
++ remaining_bytes = 16;
++
++ tmp_ptr8 = (u8 *)&tmp_array32[0];
++ for (j = 0; j < remaining_bytes; j++)
++ *out_arg++ = *tmp_ptr8++;
++#else
++ *((u32 *) out_arg + (i>>2) + 0) = arc4->OD3R;
++ *((u32 *) out_arg + (i>>2) + 1) = arc4->OD2R;
++ *((u32 *) out_arg + (i>>2) + 2) = arc4->OD1R;
++ *((u32 *) out_arg + (i>>2) + 3) = arc4->OD0R;
++#endif
++
++ i += 16;
++ }
++#else /* dma */
++
++#endif /* dma */
++
++ CRTCL_SECT_END;
++}
++
++/** \fn arc4_chip_init(void)
++ \ingroup LQ_ARC4_FUNCTIONS
++ \brief initialize arc4 hardware
++*/
++static void arc4_chip_init(void)
++{
++ /* do nothing */
++}
++
++/** \fn static int arc4_set_key(struct crypto_tfm *tfm, const u8 *in_key, unsigned int key_len)
++ \ingroup LQ_ARC4_FUNCTIONS
++ \brief sets ARC4 key
++ \param tfm linux crypto algo transform
++ \param in_key input key
++ \param key_len key lengths less than or equal to 16 bytes supported
++*/
++static int arc4_set_key(struct crypto_tfm *tfm,
++ const u8 *inkey,
++ unsigned int key_len)
++{
++ /* struct arc4_ctx *ctx = crypto_tfm_ctx(tfm); */
++ volatile struct deu_arc4 *arc4 = (struct deu_arc4 *) ARC4_START;
++
++ u32 *in_key = (u32 *)inkey;
++
++ /* must program all bits at one go?!!! */
++#if 1
++ /* #ifndef CONFIG_CRYPTO_DEV_VR9_DMA */
++ *LQ_ARC4_CON = ( (1<<31) | ((key_len - 1)<<27) | (1<<26) | (3<<16) );
++ /* NDC=1,ENDI=1,GO=0,KSAE=1,SM=0 */
++
++ arc4->K3R = *((u32 *) in_key + 0);
++ arc4->K2R = *((u32 *) in_key + 1);
++ arc4->K1R = *((u32 *) in_key + 2);
++ arc4->K0R = *((u32 *) in_key + 3);
++#else /* dma */
++ *AMAZONS_ARC4_CON = ( (1<<31) | ((key_len - 1)<<27) | (1<<26) | (3<<16) | (1<<4) );
++ /* NDC=1,ENDI=1,GO=0,KSAE=1,SM=1 */
++
++ arc4->K3R = *((u32 *) in_key + 0);
++ arc4->K2R = *((u32 *) in_key + 1);
++ arc4->K1R = *((u32 *) in_key + 2);
++ arc4->K0R = *((u32 *) in_key + 3);
++
++#if 0
++ arc4->K3R = deu_endian_swap(*((u32 *) in_key + 0));
++ arc4->K2R = deu_endian_swap(*((u32 *) in_key + 1));
++ arc4->K1R = deu_endian_swap(*((u32 *) in_key + 2));
++ arc4->K0R = deu_endian_swap(*((u32 *) in_key + 3));
++#endif
++
++#endif
++
++#if 0 /* arc4 is a ugly state machine, KSAE can only be set once per session */
++ ctx->key_length = key_len;
++
++ memcpy((u8 *)(ctx->buf), in_key, key_len);
++#endif
++
++ return 0;
++}
++
++/** \fn static void deu_arc4_ecb(void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace)
++ \ingroup LQ_ARC4_FUNCTIONS
++ \brief sets ARC4 hardware to ECB mode
++ \param ctx crypto algo context
++ \param dst output bytestream
++ \param src input bytestream
++ \param iv initialization vector
++ \param nbytes length of bytestream
++ \param encdec 1 for encrypt; 0 for decrypt
++ \param inplace not used
++*/
++static void deu_arc4_ecb(void *ctx,
++ uint8_t *dst,
++ const uint8_t *src,
++ uint8_t *iv,
++ size_t nbytes,
++ int encdec,
++ int inplace)
++{
++ deu_arc4(ctx, dst, src, NULL, nbytes, encdec, 0);
++}
++
++/** \fn static void arc4_crypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
++ \ingroup LQ_ARC4_FUNCTIONS
++ \brief encrypt/decrypt ARC4_BLOCK_SIZE of data
++ \param tfm linux crypto algo transform
++ \param out output bytestream
++ \param in input bytestream
++*/
++static void arc4_crypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
++{
++ struct arc4_ctx *ctx = crypto_tfm_ctx(tfm);
++
++ deu_arc4(ctx, out, in, NULL, ARC4_BLOCK_SIZE,
++ CRYPTO_DIR_DECRYPT, CRYPTO_TFM_MODE_ECB);
++}
++
++/*
++ * \brief ARC4 function mappings
++*/
++static struct crypto_alg arc4_alg = {
++ .cra_name = "arc4",
++ .cra_driver_name = "lq_deu-arc4",
++ .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
++ .cra_blocksize = ARC4_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct arc4_ctx),
++ .cra_module = THIS_MODULE,
++ .cra_list = LIST_HEAD_INIT(arc4_alg.cra_list),
++ .cra_u = {
++ .cipher = {
++ .cia_min_keysize = ARC4_MIN_KEY_SIZE,
++ .cia_max_keysize = ARC4_MAX_KEY_SIZE,
++ .cia_setkey = arc4_set_key,
++ .cia_encrypt = arc4_crypt,
++ .cia_decrypt = arc4_crypt,
++ }
++ }
++};
++
++/** \fn static int ecb_arc4_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes)
++ \ingroup LQ_ARC4_FUNCTIONS
++ \brief ECB ARC4 encrypt using linux crypto blkcipher
++ \param desc blkcipher descriptor
++ \param dst output scatterlist
++ \param src input scatterlist
++ \param nbytes data size in bytes
++*/
++static int ecb_arc4_encrypt(struct blkcipher_desc *desc,
++ struct scatterlist *dst,
++ struct scatterlist *src,
++ unsigned int nbytes)
++{
++ struct arc4_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
++ struct blkcipher_walk walk;
++ int err;
++
++ DPRINTF(1, "\n");
++ blkcipher_walk_init(&walk, dst, src, nbytes);
++ err = blkcipher_walk_virt(desc, &walk);
++
++ while ((nbytes = walk.nbytes)) {
++ deu_arc4_ecb(ctx, walk.dst.virt.addr, walk.src.virt.addr,
++ NULL, nbytes, CRYPTO_DIR_ENCRYPT, 0);
++ nbytes &= ARC4_BLOCK_SIZE - 1;
++ err = blkcipher_walk_done(desc, &walk, nbytes);
++ }
++
++ return err;
++}
++
++/** \fn static int ecb_arc4_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes)
++ \ingroup LQ_ARC4_FUNCTIONS
++ \brief ECB ARC4 decrypt using linux crypto blkcipher
++ \param desc blkcipher descriptor
++ \param dst output scatterlist
++ \param src input scatterlist
++ \param nbytes data size in bytes
++*/
++static int ecb_arc4_decrypt(struct blkcipher_desc *desc,
++ struct scatterlist *dst,
++ struct scatterlist *src,
++ unsigned int nbytes)
++{
++ struct arc4_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
++ struct blkcipher_walk walk;
++ int err;
++
++ DPRINTF(1, "\n");
++ blkcipher_walk_init(&walk, dst, src, nbytes);
++ err = blkcipher_walk_virt(desc, &walk);
++
++ while ((nbytes = walk.nbytes)) {
++ deu_arc4_ecb(ctx, walk.dst.virt.addr, walk.src.virt.addr,
++ NULL, nbytes, CRYPTO_DIR_DECRYPT, 0);
++ nbytes &= ARC4_BLOCK_SIZE - 1;
++ err = blkcipher_walk_done(desc, &walk, nbytes);
++ }
++
++ return err;
++}
++
++/*
++ * \brief ARC4 function mappings
++*/
++static struct crypto_alg ecb_arc4_alg = {
++ .cra_name = "ecb(arc4)",
++ .cra_driver_name = "lq_deu-ecb(arc4)",
++ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
++ .cra_blocksize = ARC4_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct arc4_ctx),
++ .cra_type = &crypto_blkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_list = LIST_HEAD_INIT(ecb_arc4_alg.cra_list),
++ .cra_u = {
++ .blkcipher = {
++ .min_keysize = ARC4_MIN_KEY_SIZE,
++ .max_keysize = ARC4_MAX_KEY_SIZE,
++ .setkey = arc4_set_key,
++ .encrypt = ecb_arc4_encrypt,
++ .decrypt = ecb_arc4_decrypt,
++ }
++ }
++};
++
++/** \fn int lq_deu_init_arc4(void)
++ \ingroup LQ_ARC4_FUNCTIONS
++ \brief initialize arc4 driver
++*/
++int lq_deu_init_arc4(void)
++{
++ int ret;
++
++ if ((ret = crypto_register_alg(&arc4_alg)))
++ goto arc4_err;
++
++ if ((ret = crypto_register_alg(&ecb_arc4_alg)))
++ goto ecb_arc4_err;
++
++ arc4_chip_init();
++
++ CRTCL_SECT_INIT;
++
++ printk(KERN_NOTICE "Lantiq DEU ARC4 initialized %s.\n",
++ disable_deudma ? "" : " (DMA)");
++ return ret;
++
++arc4_err:
++ crypto_unregister_alg(&arc4_alg);
++ printk(KERN_ERR "Lantiq arc4 initialization failed!\n");
++ return ret;
++ecb_arc4_err:
++ crypto_unregister_alg(&ecb_arc4_alg);
++ printk(KERN_ERR "Lantiq ecb_arc4 initialization failed!\n");
++
++ return ret;
++}
++
++/** \fn void lq_deu_fini_arc4(void)
++ \ingroup LQ_ARC4_FUNCTIONS
++ \brief unregister arc4 driver
++*/
++void lq_deu_fini_arc4(void)
++{
++ crypto_unregister_alg(&arc4_alg);
++ crypto_unregister_alg(&ecb_arc4_alg);
++}
++
++#endif
++
++#endif
+--- /dev/null
++++ b/drivers/crypto/lantiq/des.c
+@@ -0,0 +1,929 @@
++/*
++ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com>
++ * Copyright (C) 2009 Mohammad Firdaus
++ */
++
++/**
++ \defgroup LQ_DEU LQ_DEU_DRIVERS
++ \ingroup API
++ \brief Lantiq DEU driver
++*/
++
++/**
++ \file des.c
++ \ingroup LQ_DEU
++ \brief DES encryption DEU driver file
++*/
++
++/**
++ \defgroup LQ_DES_FUNCTIONS LQ_DES_FUNCTIONS
++ \ingroup LQ_DEU
++ \brief Lantiq DES Encryption functions
++*/
++
++#include <linux/version.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/crypto.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <asm/byteorder.h>
++#include <crypto/algapi.h>
++
++#ifdef CONFIG_SOL_LANTIQ_XWAY
++
++#include "deu.h"
++
++#ifdef CONFIG_CRYPTO_DEV_DMA
++# include "deu_dma.h"
++#endif
++
++static spinlock_t cipher_lock;
++
++/* Preprocessor declarations */
++#define DES_KEY_SIZE 8
++#define DES_EXPKEY_WORDS 32
++#define DES_BLOCK_SIZE 8
++#define DES3_EDE_KEY_SIZE (3 * DES_KEY_SIZE)
++#define DES3_EDE_EXPKEY_WORDS (3 * DES_EXPKEY_WORDS)
++#define DES3_EDE_BLOCK_SIZE DES_BLOCK_SIZE
++
++struct des_ctx {
++ int controlr_M;
++ int key_length;
++ u8 iv[DES_BLOCK_SIZE];
++ u32 expkey[DES3_EDE_EXPKEY_WORDS];
++};
++
++/** \fn int des_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int key_len)
++ * \ingroup LQ_DES_FUNCTIONS
++ * \brief sets DES key
++ * \param tfm linux crypto algo transform
++ * \param key input key
++ * \param key_len key length
++*/
++static int des_setkey(struct crypto_tfm *tfm,
++ const u8 *key,
++ unsigned int key_len)
++{
++ struct des_ctx *ctx = crypto_tfm_ctx(tfm);
++
++ DPRINTF(0, "ctx @%p, key_len %d %d\n", ctx, key_len);
++
++ ctx->controlr_M = 0; /* des */
++ ctx->key_length = key_len;
++
++ memcpy((u8 *)(ctx->expkey), key, key_len);
++
++ return 0;
++}
++
++#ifndef CONFIG_CRYPTO_DEV_LANTIQ_DMA
++/** \fn void deu_des(void *ctx_arg, u8 *out_arg, const u8 *in_arg, u8 *iv_arg, u32 nbytes, int encdec, int mode)
++ * \ingroup LQ_DES_FUNCTIONS
++ * \brief main interface to DES hardware
++ * \param ctx_arg crypto algo context
++ * \param out_arg output bytestream
++ * \param in_arg input bytestream
++ * \param iv_arg initialization vector
++ * \param nbytes length of bytestream
++ * \param encdec 1 for encrypt; 0 for decrypt
++ * \param mode operation mode such as ebc, cbc
++*/
++
++static void deu_des(void *ctx_arg,
++ u8 *out_arg,
++ const u8 *in_arg,
++ u8 *iv_arg,
++ u32 nbytes,
++ int encdec,
++ int mode)
++#else
++/** \fn void deu_des_core(void *ctx_arg, u8 *out_arg, const u8 *in_arg, u8 *iv_arg, u32 nbytes, int encdec, int mode)
++ * \ingroup LQ_DES_FUNCTIONS
++ * \brief main interface to DES hardware
++ * \param ctx_arg crypto algo context
++ * \param out_arg output bytestream
++ * \param in_arg input bytestream
++ * \param iv_arg initialization vector
++ * \param nbytes length of bytestream
++ * \param encdec 1 for encrypt; 0 for decrypt
++ * \param mode operation mode such as ebc, cbc
++*/
++static void deu_des_core(void *ctx_arg,
++ u8 *out_arg,
++ const u8 *in_arg,
++ u8 *iv_arg,
++ u32 nbytes,
++ int encdec,
++ int mode)
++#endif
++{
++ volatile struct deu_des *des = (struct deu_des *) DES_3DES_START;
++ struct des_ctx *dctx = ctx_arg;
++ u32 *key = dctx->expkey;
++ ulong flag;
++
++#ifndef CONFIG_CRYPTO_DEV_LANTIQ_DMA
++ int i = 0;
++ int nblocks = 0;
++#else
++ volatile struct deu_dma *dma = (struct deu_dma *) LQ_DEU_DMA_CON;
++ struct dma_device_info *dma_device = lq_deu[0].dma_device;
++ /* struct deu_drv_priv *deu_priv =
++ * (struct deu_drv_priv *)dma_device->priv; */
++ int wlen = 0;
++ u32 *outcopy = NULL;
++ u32 *dword_mem_aligned_in = NULL;
++
++#ifdef CONFIG_CRYPTO_DEV_LANTIQ_POLL_DMA
++ u32 timeout = 0;
++ u32 *out_dma = NULL;
++#endif
++
++#endif
++
++ DPRINTF(0, "ctx @%p, mode %d, encdec %d\n", dctx, mode, encdec);
++
++ CRTCL_SECT_START;
++
++ des->ctrl.E_D = !encdec; /* encryption */
++ des->ctrl.O = mode; /* 0 ECB, 1 CBC, 2 OFB, 3 CFB, 4 CTR */
++ des->ctrl.SM = 1; /* start after writing input register */
++ des->ctrl.DAU = 0; /* Disable Automatic Update of init vect */
++ des->ctrl.ARS = 1; /* Autostart Select - write to IHR */
++
++ des->ctrl.M = dctx->controlr_M;
++ /* write keys */
++ if (dctx->controlr_M == 0) {
++ /* DES mode */
++ des->K1HR = DEU_ENDIAN_SWAP(*((u32 *) key + 0));
++ des->K1LR = DEU_ENDIAN_SWAP(*((u32 *) key + 1));
++#ifdef CRYPTO_DEBUG
++ printk("key1: %x\n", (*((u32 *) key + 0)));
++ printk("key2: %x\n", (*((u32 *) key + 1)));
++#endif
++ } else {
++ /* 3DES mode (EDE-x) */
++ switch (dctx->key_length) {
++ case 24:
++ des->K3HR = DEU_ENDIAN_SWAP(*((u32 *) key + 4));
++ des->K3LR = DEU_ENDIAN_SWAP(*((u32 *) key + 5));
++ /* no break; */
++ case 16:
++ des->K2HR = DEU_ENDIAN_SWAP(*((u32 *) key + 2));
++ des->K2LR = DEU_ENDIAN_SWAP(*((u32 *) key + 3));
++ /* no break; */
++ case 8:
++ des->K1HR = DEU_ENDIAN_SWAP(*((u32 *) key + 0));
++ des->K1LR = DEU_ENDIAN_SWAP(*((u32 *) key + 1));
++ break;
++ default:
++ CRTCL_SECT_END;
++ return;
++ }
++ }
++
++ /* write init vector (not required for ECB mode) */
++ if (mode > 0) {
++ des->IVHR = DEU_ENDIAN_SWAP(*(u32 *) iv_arg);
++ des->IVLR = DEU_ENDIAN_SWAP(*((u32 *) iv_arg + 1));
++ }
++
++#ifndef CONFIG_CRYPTO_DEV_LANTIQ_DMA
++ nblocks = nbytes / 4;
++
++ for (i = 0; i < nblocks; i += 2) {
++ /* wait for busy bit to clear */
++
++ /*--- Workaround ---------------------------------------------
++ do a dummy read to the busy flag because it is not raised
++ early enough in CFB/OFB 3DES modes */
++#ifdef CRYPTO_DEBUG
++ printk("ihr: %x\n", (*((u32 *) in_arg + i)));
++ printk("ilr: %x\n", (*((u32 *) in_arg + 1 + i)));
++#endif
++ des->IHR = INPUT_ENDIAN_SWAP(*((u32 *) in_arg + i));
++ /* start crypto */
++ des->ILR = INPUT_ENDIAN_SWAP(*((u32 *) in_arg + 1 + i));
++
++ while (des->ctrl.BUS) {
++ /* this will not take long */
++ }
++
++ *((u32 *) out_arg + 0 + i) = des->OHR;
++ *((u32 *) out_arg + 1 + i) = des->OLR;
++
++#ifdef CRYPTO_DEBUG
++ printk("ohr: %x\n", (*((u32 *) out_arg + i)));
++ printk("olr: %x\n", (*((u32 *) out_arg + 1 + i)));
++#endif
++ }
++
++#else /* dma mode */
++
++ /* Prepare Rx buf length used in dma psuedo interrupt */
++ /* deu_priv->deu_rx_buf = out_arg; */
++ /* deu_priv->deu_rx_len = nbytes; */
++
++ /* memory alignment issue */
++ dword_mem_aligned_in = (u32 *) DEU_DWORD_REORDERING(in_arg, des_buff_in,
++ BUFFER_IN, nbytes);
++
++ dma->ctrl.ALGO = 0; /* DES */
++ des->ctrl.DAU = 0;
++ dma->ctrl.BS = 0;
++ dma->ctrl.EN = 1;
++
++ while (des->ctrl.BUS) {
++ /* wait for AES to be ready */
++ };
++
++ wlen = dma_device_write(dma_device, (u8 *) dword_mem_aligned_in, nbytes,
++ NULL);
++ if (wlen != nbytes) {
++ dma->ctrl.EN = 0;
++ CRTCL_SECT_END;
++ printk(KERN_ERR "[%s %s %d]: dma_device_write fail!\n",
++ __FILE__, __func__, __LINE__);
++ return; /* -EINVAL; */
++ }
++
++ WAIT_DES_DMA_READY();
++
++#ifdef CONFIG_CRYPTO_DEV_LANTIQ_POLL_DMA
++ outcopy = (u32 *) DEU_DWORD_REORDERING(out_arg, des_buff_out,
++ BUFFER_OUT, nbytes);
++
++ /* polling DMA rx channel */
++ while ((dma_device_read(dma_device, (u8 **) &out_dma, NULL)) == 0) {
++ timeout++;
++
++ if (timeout >= 333000) {
++ dma->ctrl.EN = 0;
++ CRTCL_SECT_END;
++ printk(KERN_ERR "[%s %s %d]: timeout!!\n",
++ __FILE__, __func__, __LINE__);
++ return; /* -EINVAL; */
++ }
++ }
++
++ WAIT_DES_DMA_READY();
++
++ DES_MEMORY_COPY(outcopy, out_dma, out_arg, nbytes);
++#else
++ CRTCL_SECT_END; /* Sleep and wait for Rx finished */
++ DEU_WAIT_EVENT(deu_priv->deu_thread_wait, DEU_EVENT,
++ deu_priv->deu_event_flags);
++ CRTCL_SECT_START;
++#endif
++
++#endif /* dma mode */
++
++ if (mode > 0) {
++ *(u32 *) iv_arg = DEU_ENDIAN_SWAP(des->IVHR);
++ *((u32 *) iv_arg + 1) = DEU_ENDIAN_SWAP(des->IVLR);
++ };
++
++ CRTCL_SECT_END;
++}
++
++/* definitions from linux/include/crypto.h:
++#define CRYPTO_TFM_MODE_ECB 0x00000001
++#define CRYPTO_TFM_MODE_CBC 0x00000002
++#define CRYPTO_TFM_MODE_CFB 0x00000004
++#define CRYPTO_TFM_MODE_CTR 0x00000008
++#define CRYPTO_TFM_MODE_OFB 0x00000010
++but hardware definition: 0 ECB 1 CBC 2 OFB 3 CFB 4 CTR */
++
++/** \fn void deu_des(void *ctx_arg, u8 *out_arg, const u8 *in_arg, u8 *iv_arg, u32 nbytes, int encdec, int mode)
++ * \ingroup LQ_DES_FUNCTIONS
++ * \brief main interface to DES hardware
++ * \param ctx_arg crypto algo context
++ * \param out_arg output bytestream
++ * \param in_arg input bytestream
++ * \param iv_arg initialization vector
++ * \param nbytes length of bytestream
++ * \param encdec 1 for encrypt; 0 for decrypt
++ * \param mode operation mode such as ebc, cbc
++*/
++
++#ifdef CONFIG_CRYPTO_DEV_LANTIQ_DMA
++static void deu_des(void *ctx_arg,
++ u8 *out_arg,
++ const u8 *in_arg,
++ u8 *iv_arg,
++ u32 nbytes,
++ int encdec,
++ int mode)
++{
++ u32 remain = nbytes;
++ u32 inc;
++
++ DPRINTF(0, "\n");
++
++ while (remain > 0) {
++ if (remain >= DEU_MAX_PACKET_SIZE)
++ inc = DEU_MAX_PACKET_SIZE;
++ else
++ inc = remain;
++
++ remain -= inc;
++
++ deu_des_core(ctx_arg, out_arg, in_arg, iv_arg, inc, encdec,
++ mode);
++
++ out_arg += inc;
++ in_arg += inc;
++ }
++}
++#endif
++
++/** \fn void deu_des_ecb(void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace)
++ * \ingroup LQ_DES_FUNCTIONS
++ * \brief sets DES hardware to ECB mode
++ * \param ctx crypto algo context
++ * \param dst output bytestream
++ * \param src input bytestream
++ * \param iv initialization vector
++ * \param nbytes length of bytestream
++ * \param encdec 1 for encrypt; 0 for decrypt
++ * \param inplace not used
++*/
++
++static void deu_des_ecb(void *ctx,
++ uint8_t *dst,
++ const uint8_t *src,
++ uint8_t *iv,
++ size_t nbytes,
++ int encdec,
++ int inplace)
++{
++ DPRINTF(0, "ctx @%p\n", ctx);
++ deu_des(ctx, dst, src, NULL, nbytes, encdec, 0);
++}
++
++/** \fn void deu_des_cbc(void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace)
++ * \ingroup LQ_DES_FUNCTIONS
++ * \brief sets DES hardware to CBC mode
++ * \param ctx crypto algo context
++ * \param dst output bytestream
++ * \param src input bytestream
++ * \param iv initialization vector
++ * \param nbytes length of bytestream
++ * \param encdec 1 for encrypt; 0 for decrypt
++ * \param inplace not used
++*/
++static void deu_des_cbc(void *ctx,
++ uint8_t *dst,
++ const uint8_t *src,
++ uint8_t *iv,
++ size_t nbytes,
++ int encdec,
++ int inplace)
++{
++ DPRINTF(0, "ctx @%p\n", ctx);
++ deu_des(ctx, dst, src, iv, nbytes, encdec, 1);
++}
++
++#if 0
++/** \fn void deu_des_ofb(void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace)
++ * \ingroup LQ_DES_FUNCTIONS
++ * \brief sets DES hardware to OFB mode
++ * \param ctx crypto algo context
++ * \param dst output bytestream
++ * \param src input bytestream
++ * \param iv initialization vector
++ * \param nbytes length of bytestream
++ * \param encdec 1 for encrypt; 0 for decrypt
++ * \param inplace not used
++*/
++static void deu_des_ofb(void *ctx,
++ uint8_t *dst,
++ const uint8_t *src,
++ uint8_t *iv,
++ size_t nbytes,
++ int encdec,
++ int inplace)
++{
++ DPRINTF(0, "ctx @%p\n", ctx);
++ deu_des(ctx, dst, src, iv, nbytes, encdec, 2);
++}
++
++/** \fn void deu_des_cfb(void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace)
++ \ingroup LQ_DES_FUNCTIONS
++ \brief sets DES hardware to CFB mode
++ \param ctx crypto algo context
++ \param dst output bytestream
++ \param src input bytestream
++ \param iv initialization vector
++ \param nbytes length of bytestream
++ \param encdec 1 for encrypt; 0 for decrypt
++ \param inplace not used
++*/
++static void deu_des_cfb(void *ctx,
++ uint8_t *dst,
++ const uint8_t *src,
++ uint8_t *iv,
++ size_t nbytes,
++ int encdec,
++ int inplace)
++{
++ DPRINTF(0, "ctx @%p\n", ctx);
++ deu_des(ctx, dst, src, iv, nbytes, encdec, 3);
++}
++
++/** \fn void deu_des_ctr(void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace)
++ * \ingroup LQ_DES_FUNCTIONS
++ * \brief sets DES hardware to CTR mode
++ * \param ctx crypto algo context
++ * \param dst output bytestream
++ * \param src input bytestream
++ * \param iv initialization vector
++ * \param nbytes length of bytestream
++ * \param encdec 1 for encrypt; 0 for decrypt
++ * \param inplace not used
++*/
++static void deu_des_ctr(void *ctx,
++ uint8_t *dst,
++ const uint8_t *src,
++ uint8_t *iv,
++ size_t nbytes,
++ int encdec,
++ int inplace)
++{
++ DPRINTF(0, "ctx @%p\n", ctx);
++ deu_des(ctx, dst, src, iv, nbytes, encdec, 4);
++}
++#endif
++
++/** \fn void des_encrypt(struct crypto_tfm *tfm, uint8_t *out, const uint8_t *in)
++ * \ingroup LQ_DES_FUNCTIONS
++ * \brief encrypt DES_BLOCK_SIZE of data
++ * \param tfm linux crypto algo transform
++ * \param out output bytestream
++ * \param in input bytestream
++*/
++static void des_encrypt(struct crypto_tfm *tfm, uint8_t *out, const uint8_t *in)
++{
++ struct des_ctx *ctx = crypto_tfm_ctx(tfm);
++ DPRINTF(0, "ctx @%p\n", ctx);
++ deu_des(ctx, out, in, NULL, DES_BLOCK_SIZE, CRYPTO_DIR_ENCRYPT, 0);
++}
++
++/** \fn void des_decrypt(struct crypto_tfm *tfm, uint8_t *out, const uint8_t *in)
++ * \ingroup LQ_DES_FUNCTIONS
++ * \brief encrypt DES_BLOCK_SIZE of data
++ * \param tfm linux crypto algo transform
++ * \param out output bytestream
++ * \param in input bytestream
++*/
++static void des_decrypt(struct crypto_tfm *tfm, uint8_t *out, const uint8_t *in)
++{
++ struct des_ctx *ctx = crypto_tfm_ctx(tfm);
++ DPRINTF(0, "ctx @%p\n", ctx);
++ deu_des(ctx, out, in, NULL, DES_BLOCK_SIZE, CRYPTO_DIR_DECRYPT, 0);
++}
++
++/*
++ * \brief 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.
++ *
++ */
++
++/** \fn int des3_ede_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen)
++ * \ingroup LQ_DES_FUNCTIONS
++ * \brief sets 3DES key
++ * \param tfm linux crypto algo transform
++ * \param key input key
++ * \param keylen key length
++*/
++static int des3_ede_setkey(struct crypto_tfm *tfm,
++ const u8 *key,
++ unsigned int key_len)
++{
++ struct des_ctx *ctx = crypto_tfm_ctx(tfm);
++
++ DPRINTF(0, "ctx @%p, key_len %d\n", ctx, key_len);
++
++ ctx->controlr_M = key_len / 8 + 1; /* 3DES EDE1 / EDE2 / EDE3 Mode */
++ ctx->key_length = key_len;
++
++ memcpy((u8 *)(ctx->expkey), key, key_len);
++
++ return 0;
++}
++
++/*
++ * \brief DES function mappings
++*/
++static struct crypto_alg des_alg = {
++ .cra_name = "des",
++ .cra_driver_name = "lq_deu-des",
++ .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
++ .cra_blocksize = DES_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct des_ctx),
++ .cra_module = THIS_MODULE,
++ .cra_alignmask = 3,
++ .cra_list = LIST_HEAD_INIT(des_alg.cra_list),
++ .cra_u = {
++ .cipher = {
++ .cia_min_keysize = DES_KEY_SIZE,
++ .cia_max_keysize = DES_KEY_SIZE,
++ .cia_setkey = des_setkey,
++ .cia_encrypt = des_encrypt,
++ .cia_decrypt = des_decrypt
++ }
++ }
++};
++
++/*
++ * \brief DES function mappings
++*/
++static struct crypto_alg des3_ede_alg = {
++ .cra_name = "des3_ede",
++ .cra_driver_name = "lq_deu-des3_ede",
++ .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
++ .cra_blocksize = DES_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct des_ctx),
++ .cra_module = THIS_MODULE,
++ .cra_alignmask = 3,
++ .cra_list = LIST_HEAD_INIT(des3_ede_alg.cra_list),
++ .cra_u = {
++ .cipher = {
++ .cia_min_keysize = DES_KEY_SIZE,
++ .cia_max_keysize = DES_KEY_SIZE,
++ .cia_setkey = des3_ede_setkey,
++ .cia_encrypt = des_encrypt,
++ .cia_decrypt = des_decrypt
++ }
++ }
++};
++
++/** \fn int ecb_des_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes)
++ * \ingroup LQ_DES_FUNCTIONS
++ * \brief ECB DES encrypt using linux crypto blkcipher
++ * \param desc blkcipher descriptor
++ * \param dst output scatterlist
++ * \param src input scatterlist
++ * \param nbytes data size in bytes
++*/
++static int ecb_des_encrypt(struct blkcipher_desc *desc,
++ struct scatterlist *dst,
++ struct scatterlist *src,
++ unsigned int nbytes)
++{
++ struct des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
++ struct blkcipher_walk walk;
++ int err;
++
++ DPRINTF(0, "ctx @%p\n", ctx);
++
++ blkcipher_walk_init(&walk, dst, src, nbytes);
++ err = blkcipher_walk_virt(desc, &walk);
++
++ while ((nbytes = walk.nbytes)) {
++ nbytes -= (nbytes % DES_BLOCK_SIZE);
++ deu_des_ecb(ctx, walk.dst.virt.addr, walk.src.virt.addr,
++ NULL, nbytes, CRYPTO_DIR_ENCRYPT, 0);
++ nbytes &= DES_BLOCK_SIZE - 1;
++ err = blkcipher_walk_done(desc, &walk, nbytes);
++ }
++
++ return err;
++}
++
++/** \fn int ecb_des_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes)
++ * \ingroup LQ_DES_FUNCTIONS
++ * \brief ECB DES decrypt using linux crypto blkcipher
++ * \param desc blkcipher descriptor
++ * \param dst output scatterlist
++ * \param src input scatterlist
++ * \param nbytes data size in bytes
++ * \return err
++*/
++static int ecb_des_decrypt(struct blkcipher_desc *desc,
++ struct scatterlist *dst,
++ struct scatterlist *src,
++ unsigned int nbytes)
++{
++ struct des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
++ struct blkcipher_walk walk;
++ int err;
++
++ DPRINTF(0, "ctx @%p\n", ctx);
++
++ blkcipher_walk_init(&walk, dst, src, nbytes);
++ err = blkcipher_walk_virt(desc, &walk);
++
++ while ((nbytes = walk.nbytes)) {
++ nbytes -= (nbytes % DES_BLOCK_SIZE);
++ deu_des_ecb(ctx, walk.dst.virt.addr, walk.src.virt.addr,
++ NULL, nbytes, CRYPTO_DIR_DECRYPT, 0);
++ nbytes &= DES_BLOCK_SIZE - 1;
++ err = blkcipher_walk_done(desc, &walk, nbytes);
++ }
++
++ return err;
++}
++
++/*
++ * \brief DES function mappings
++*/
++static struct crypto_alg ecb_des_alg = {
++ .cra_name = "ecb(des)",
++ .cra_driver_name = "lq_deu-ecb(des)",
++ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
++ .cra_blocksize = DES_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct des_ctx),
++ .cra_type = &crypto_blkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_list = LIST_HEAD_INIT(ecb_des_alg.cra_list),
++ .cra_u = {
++ .blkcipher = {
++ .min_keysize = DES_KEY_SIZE,
++ .max_keysize = DES_KEY_SIZE,
++ .setkey = des_setkey,
++ .encrypt = ecb_des_encrypt,
++ .decrypt = ecb_des_decrypt,
++ }
++ }
++};
++
++/*
++ * \brief DES function mappings
++*/
++static struct crypto_alg ecb_des3_ede_alg = {
++ .cra_name = "ecb(des3_ede)",
++ .cra_driver_name = "lq_deu-ecb(des3_ede)",
++ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
++ .cra_blocksize = DES3_EDE_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct des_ctx),
++ .cra_type = &crypto_blkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_list = LIST_HEAD_INIT(ecb_des3_ede_alg.cra_list),
++ .cra_u = {
++ .blkcipher = {
++ .min_keysize = DES3_EDE_KEY_SIZE,
++ .max_keysize = DES3_EDE_KEY_SIZE,
++ .setkey = des3_ede_setkey,
++ .encrypt = ecb_des_encrypt,
++ .decrypt = ecb_des_decrypt,
++ }
++ }
++};
++
++/** \fn int cbc_des_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes)
++ * \ingroup LQ_DES_FUNCTIONS
++ * \brief CBC DES encrypt using linux crypto blkcipher
++ * \param desc blkcipher descriptor
++ * \param dst output scatterlist
++ * \param src input scatterlist
++ * \param nbytes data size in bytes
++ * \return err
++*/
++static int cbc_des_encrypt(struct blkcipher_desc *desc,
++ struct scatterlist *dst,
++ struct scatterlist *src,
++ unsigned int nbytes)
++{
++ struct des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
++ struct blkcipher_walk walk;
++ int err;
++
++ DPRINTF(0, "ctx @%p\n", ctx);
++
++ blkcipher_walk_init(&walk, dst, src, nbytes);
++ err = blkcipher_walk_virt(desc, &walk);
++
++ while ((nbytes = walk.nbytes)) {
++ u8 *iv = walk.iv;
++ /* printk("iv = %08x\n", *(u32 *)iv); */
++ nbytes -= (nbytes % DES_BLOCK_SIZE);
++ deu_des_cbc(ctx, walk.dst.virt.addr, walk.src.virt.addr,
++ iv, nbytes, CRYPTO_DIR_ENCRYPT, 0);
++ nbytes &= DES_BLOCK_SIZE - 1;
++ err = blkcipher_walk_done(desc, &walk, nbytes);
++ }
++
++ return err;
++}
++
++/** \fn int cbc_des_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes)
++ * \ingroup LQ_DES_FUNCTIONS
++ * \brief CBC DES decrypt using linux crypto blkcipher
++ * \param desc blkcipher descriptor
++ * \param dst output scatterlist
++ * \param src input scatterlist
++ * \param nbytes data size in bytes
++ * \return err
++*/
++static int cbc_des_decrypt(struct blkcipher_desc *desc,
++ struct scatterlist *dst,
++ struct scatterlist *src,
++ unsigned int nbytes)
++{
++ struct des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
++ struct blkcipher_walk walk;
++ int err;
++
++ DPRINTF(0, "ctx @%p\n", ctx);
++
++ blkcipher_walk_init(&walk, dst, src, nbytes);
++ err = blkcipher_walk_virt(desc, &walk);
++
++ while ((nbytes = walk.nbytes)) {
++ u8 *iv = walk.iv;
++ /* printk("iv = %08x\n", *(u32 *)iv); */
++ nbytes -= (nbytes % DES_BLOCK_SIZE);
++ deu_des_cbc(ctx, walk.dst.virt.addr, walk.src.virt.addr,
++ iv, nbytes, CRYPTO_DIR_DECRYPT, 0);
++ nbytes &= DES_BLOCK_SIZE - 1;
++ err = blkcipher_walk_done(desc, &walk, nbytes);
++ }
++
++ return err;
++}
++
++/*
++ * \brief DES function mappings
++*/
++static struct crypto_alg cbc_des_alg = {
++ .cra_name = "cbc(des)",
++ .cra_driver_name = "lq_deu-cbc(des)",
++ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
++ .cra_blocksize = DES_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct des_ctx),
++ .cra_type = &crypto_blkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_list = LIST_HEAD_INIT(cbc_des_alg.cra_list),
++ .cra_u = {
++ .blkcipher = {
++ .min_keysize = DES_KEY_SIZE,
++ .max_keysize = DES_KEY_SIZE,
++ .ivsize = DES_BLOCK_SIZE,
++ .setkey = des_setkey,
++ .encrypt = cbc_des_encrypt,
++ .decrypt = cbc_des_decrypt,
++ }
++ }
++};
++
++/*
++ * \brief DES function mappings
++*/
++static struct crypto_alg cbc_des3_ede_alg = {
++ .cra_name = "cbc(des3_ede)",
++ .cra_driver_name = "lq_deu-cbc(des3_ede)",
++ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
++ .cra_blocksize = DES3_EDE_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct des_ctx),
++ .cra_type = &crypto_blkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_list = LIST_HEAD_INIT(cbc_des3_ede_alg.cra_list),
++ .cra_u = {
++ .blkcipher = {
++ .min_keysize = DES3_EDE_KEY_SIZE,
++ .max_keysize = DES3_EDE_KEY_SIZE,
++ .ivsize = DES_BLOCK_SIZE,
++ .setkey = des3_ede_setkey,
++ .encrypt = cbc_des_encrypt,
++ .decrypt = cbc_des_decrypt,
++ }
++ }
++};
++
++/** \fn int lq_deu_init_des(void)
++ * \ingroup LQ_DES_FUNCTIONS
++ * \brief initialize des driver
++*/
++int lq_deu_init_des(void)
++{
++ int ret = 0;
++
++ ret = crypto_register_alg(&des_alg);
++ if (ret < 0)
++ goto des_err;
++
++ ret = crypto_register_alg(&ecb_des_alg);
++ if (ret < 0)
++ goto ecb_des_err;
++
++ ret = crypto_register_alg(&cbc_des_alg);
++ if (ret < 0)
++ goto cbc_des_err;
++
++ ret = crypto_register_alg(&des3_ede_alg);
++ if (ret < 0)
++ goto des3_ede_err;
++
++ ret = crypto_register_alg(&ecb_des3_ede_alg);
++ if (ret < 0)
++ goto ecb_des3_ede_err;
++
++ ret = crypto_register_alg(&cbc_des3_ede_alg);
++ if (ret < 0)
++ goto cbc_des3_ede_err;
++
++ deu_des_chip_init();
++
++ CRTCL_SECT_INIT;
++
++#ifdef CONFIG_CRYPTO_DEV_LANTIQ_DMA
++ if (ALLOCATE_MEMORY(BUFFER_IN, DES_ALGO) < 0) {
++ printk(KERN_ERR "[%s %s %d]: malloc memory fail!\n",
++ __FILE__, __func__, __LINE__);
++ goto cbc_des3_ede_err;
++ }
++ if (ALLOCATE_MEMORY(BUFFER_OUT, DES_ALGO) < 0) {
++ printk(KERN_ERR "[%s %s %d]: malloc memory fail!\n",
++ __FILE__, __func__, __LINE__);
++ goto cbc_des3_ede_err;
++ }
++#endif
++
++ printk(KERN_NOTICE "Lantiq DEU DES initialized%s.\n",
++ disable_deudma ? "" : " (DMA)");
++ return ret;
++
++des_err:
++ crypto_unregister_alg(&des_alg);
++ printk(KERN_ERR "Lantiq des initialization failed!\n");
++
++ return ret;
++
++ecb_des_err:
++ crypto_unregister_alg(&ecb_des_alg);
++ printk(KERN_ERR "Lantiq ecb_des initialization failed!\n");
++
++ return ret;
++
++cbc_des_err:
++ crypto_unregister_alg(&cbc_des_alg);
++ printk(KERN_ERR "Lantiq cbc_des initialization failed!\n");
++
++ return ret;
++
++des3_ede_err:
++ crypto_unregister_alg(&des3_ede_alg);
++ printk(KERN_ERR "Lantiq des3_ede initialization failed!\n");
++
++ return ret;
++
++ecb_des3_ede_err:
++ crypto_unregister_alg(&ecb_des3_ede_alg);
++ printk(KERN_ERR "Lantiq ecb_des3_ede initialization failed!\n");
++
++ return ret;
++
++cbc_des3_ede_err:
++ crypto_unregister_alg(&cbc_des3_ede_alg);
++ printk(KERN_ERR "Lantiq cbc_des3_ede initialization failed!\n");
++
++ return ret;
++}
++
++/** \fn void lq_deu_fini_des(void)
++ * \ingroup LQ_DES_FUNCTIONS
++ * \brief unregister des driver
++*/
++void lq_deu_fini_des(void)
++{
++ crypto_unregister_alg(&des_alg);
++ crypto_unregister_alg(&ecb_des_alg);
++ crypto_unregister_alg(&cbc_des_alg);
++ crypto_unregister_alg(&des3_ede_alg);
++ crypto_unregister_alg(&ecb_des3_ede_alg);
++ crypto_unregister_alg(&cbc_des3_ede_alg);
++
++#ifdef CONFIG_CRYPTO_DEV_LANTIQ_DMA
++ FREE_MEMORY(des_buff_in);
++ FREE_MEMORY(des_buff_out);
++#endif /* CONFIG_CRYPTO_DEV_LANTIQ_DMA_DANUBE */
++}
++
++#endif
+--- /dev/null
++++ b/drivers/crypto/lantiq/deu.c
+@@ -0,0 +1,195 @@
++/*
++ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com>
++ * Copyright (C) 2009 Mohammad Firdaus
++ */
++
++/**
++ \defgroup LQ_DEU LQ_DEU_DRIVERS
++ \ingroup API
++ \brief Lantiq DEU driver module
++*/
++
++/**
++ \file deu.c
++ \ingroup LQ_DEU
++ \brief main DEU driver file
++*/
++
++/**
++ \defgroup LQ_DEU_FUNCTIONS LQ_DEU_FUNCTIONS
++ \ingroup LQ_DEU
++ \brief Lantiq DEU functions
++*/
++
++#include <linux/version.h>
++#if defined(CONFIG_MODVERSIONS)
++#define MODVERSIONS
++#include <linux/modversions.h>
++#endif
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/crypto.h>
++#include <linux/proc_fs.h>
++#include <linux/fs.h> /* Stuff about file systems that we need */
++#include <asm/byteorder.h>
++
++#if 0
++#ifdef CONFIG_SOC_LANTIQ_XWAY
++# include <lq_pmu.h>
++#endif
++#endif
++
++#include "deu.h"
++
++struct lq_crypto_priv lq_crypto_ops;
++
++#ifdef CONFIG_CRYPTO_DEV_LANTIQ_DMA
++int disable_deudma = 0;
++#else
++int disable_deudma = 1;
++#endif /* CONFIG_CRYPTO_DEV_LANTIQ_DMA */
++
++#ifdef CRYPTO_DEBUG
++char deu_debug_level = 3;
++#endif
++
++#ifdef CONFIG_CRYPTO_DEV_LANTIQ_MODULE
++# define STATIC static
++#else
++# define STATIC
++#endif
++
++/** \fn static int lq_deu_init(void)
++ * \ingroup LQ_DEU_FUNCTIONS
++ * \brief link all modules that have been selected in kernel config for Lantiq HW crypto support
++ * \return ret
++*/
++int lq_deu_init(void)
++{
++ int ret = -ENOSYS;
++ u32 config;
++
++ printk(KERN_INFO "Lantiq crypto hardware driver version %s\n",
++ LQ_DEU_DRV_VERSION);
++
++ config = deu_chip_init();
++
++#ifdef CONFIG_CRYPTO_DEV_LANTIQ_DMA
++ deu_dma_init();
++#endif
++
++#if defined(CONFIG_CRYPTO_DEV_LANTIQ_AES)
++ if(config & LQ_DEU_ID_AES) {
++ if ((ret = lq_deu_init_aes())) {
++ printk(KERN_ERR "Lantiq AES initialization failed!\n");
++ }
++ } else {
++ printk(KERN_ERR "Lantiq AES not supported!\n");
++ }
++#endif
++
++#ifdef CONFIG_SOL_LANTIQ_XWAY
++#if defined(CONFIG_CRYPTO_DEV_LANTIQ_DES)
++ if(config & LQ_DEU_ID_DES) {
++ if ((ret = lq_deu_init_des())) {
++ printk(KERN_ERR "Lantiq DES initialization failed!\n");
++ }
++ } else {
++ printk(KERN_ERR "Lantiq DES not supported!\n");
++ }
++#endif
++#if defined(CONFIG_CRYPTO_DEV_LANTIQ_ARC4) && defined(CONFIG_CRYPTO_DEV_LANTIQ_DMA)
++ if ((ret = lq_deu_init_arc4())) {
++ printk(KERN_ERR "Lantiq ARC4 initialization failed!\n");
++ }
++#endif
++#endif
++
++#if defined(CONFIG_CRYPTO_DEV_LANTIQ_SHA1)
++ if(config & LQ_DEU_ID_HASH) {
++ if ((ret = lq_deu_init_sha1())) {
++ printk(KERN_ERR "Lantiq SHA1 initialization failed!\n");
++ }
++ } else {
++ printk(KERN_ERR "Lantiq SHA1 not supported!\n");
++ }
++#endif
++#if defined(CONFIG_CRYPTO_DEV_LANTIQ_MD5)
++ if(config & LQ_DEU_ID_HASH) {
++ if ((ret = lq_deu_init_md5())) {
++ printk(KERN_ERR "Lantiq MD5 initialization failed!\n");
++ }
++ } else {
++ printk(KERN_ERR "Lantiq MD5 not supported!\n");
++ }
++#endif
++#if defined(CONFIG_CRYPTO_DEV_LANTIQ_SHA1_HMAC)
++ if ((ret = lq_deu_init_sha1_hmac())) {
++ printk(KERN_ERR "Lantiq SHA1_HMAC initialization failed!\n");
++ }
++#endif
++#if defined(CONFIG_CRYPTO_DEV_LANTIQ_MD5_HMAC)
++ if ((ret = lq_deu_init_md5_hmac())) {
++ printk(KERN_ERR "Lantiq MD5_HMAC initialization failed!\n");
++ }
++#endif
++ return ret;
++}
++
++/** \fn static void lq_deu_fini(void)
++ * \ingroup LQ_DEU_FUNCTIONS
++ * \brief remove the loaded crypto algorithms
++*/
++void lq_deu_exit(void)
++{
++#if defined(CONFIG_CRYPTO_DEV_LANTIQ_AES)
++ lq_deu_fini_aes();
++#endif
++#ifdef CONFIG_SOL_LANTIQ_XWAY
++#if defined(CONFIG_CRYPTO_DEV_LANTIQ_DES)
++ lq_deu_fini_des();
++#endif
++#if defined(CONFIG_CRYPTO_DEV_LANTIQ_ARC4) \
++ && defined(CONFIG_CRYPTO_DEV_LANTIQ_DMA)
++ lq_deu_fini_arc4();
++#endif
++#endif
++#if defined(CONFIG_CRYPTO_DEV_LANTIQ_SHA1)
++ lq_deu_fini_sha1();
++#endif
++#if defined(CONFIG_CRYPTO_DEV_LANTIQ_MD5)
++ lq_deu_fini_md5();
++#endif
++#if defined(CONFIG_CRYPTO_DEV_LANTIQ_SHA1_HMAC)
++ lq_deu_fini_sha1_hmac();
++#endif
++#if defined(CONFIG_CRYPTO_DEV_LANTIQ_MD5_HMAC)
++ lq_deu_fini_md5_hmac();
++#endif
++
++ printk("DEU has exited successfully\n");
++
++#if defined(CONFIG_CRYPTO_DEV_LANTIQ_DMA)
++ deu_dma_exit();
++ printk("DMA has deregistered successfully\n");
++#endif
++}
++
++EXPORT_SYMBOL(lq_deu_init);
++EXPORT_SYMBOL(lq_deu_exit);
+--- /dev/null
++++ b/drivers/crypto/lantiq/deu.h
+@@ -0,0 +1,248 @@
++/*
++ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com>
++ * Copyright (C) 2009 Mohammad Firdaus
++ */
++
++/**
++ \defgroup LQ_DEU LQ_DEU_DRIVERS
++ \ingroup API
++ \brief Lantiq DEU driver module
++*/
++
++/**
++ \file deu.h
++ \brief Main DEU driver header file
++*/
++
++/**
++ \defgroup LQ_DEU_DEFINITIONS LQ_DEU_DEFINITIONS
++ \ingroup LQ_DEU
++ \brief Lantiq DEU definitions
++*/
++
++
++#ifndef DEU_H
++#define DEU_H
++
++#undef CRYPTO_DEBUG
++
++#define LQ_DEU_DRV_VERSION "1.0.1"
++
++#if defined(CONFIG_LANTIQ_DANUBE)
++# include "deu_danube.h"
++#elif defined(CONFIG_LANTIQ_AR9)
++# include "deu_ar9.h"
++#elif defined(CONFIG_SOC_LANTIQ_FALCON)
++# include "deu_falcon.h"
++#else
++//# error "Unknown platform"
++# include "deu_danube.h"
++#endif
++
++struct lq_crypto_priv {
++#ifdef CONFIG_CRYPTO_DEV_LANTIQ_DMA
++ u32 *des_buff_in;
++ u32 *des_buff_out;
++ u32 *aes_buff_in;
++ u32 *aes_buff_out;
++
++ int (*dma_init)(void);
++ void (*dma_exit)(void);
++ u32 (*dma_align)(const u8 *, u32 *, int, int);
++ void (*aes_dma_memcpy)(u32 *, u32 *, u8 *, int);
++ void (*des_dma_memcpy)(u32 *, u32 *, u8 *, int);
++ int (*aes_dma_malloc)(int);
++ int (*des_dma_malloc)(int);
++ void (*dma_free)(u32 *);
++#endif
++
++ u32 (*endian_swap)(u32);
++ u32 (*input_swap)(u32);
++ void (*aes_chip_init)(void);
++ void (*des_chip_init)(void);
++ u32 (*chip_init)(void);
++};
++
++extern struct lq_crypto_priv lq_crypto_ops;
++
++#define LQ_DEU_ALIGNMENT 16
++
++#define PFX "lq_deu: "
++
++#define LQ_DEU_CRA_PRIORITY 300
++#define LQ_DEU_COMPOSITE_PRIORITY 400
++
++#define CRYPTO_DIR_ENCRYPT 1
++#define CRYPTO_DIR_DECRYPT 0
++
++#define CRTCL_SECT_INIT spin_lock_init(&cipher_lock)
++#define CRTCL_SECT_START spin_lock_irqsave(&cipher_lock, flag)
++#define CRTCL_SECT_END spin_unlock_irqrestore(&cipher_lock, flag)
++
++#define LQ_DEU_ID_REV 0x00001F
++#define LQ_DEU_ID_ID 0x00FF00
++#define LQ_DEU_ID_DMA 0x010000
++#define LQ_DEU_ID_HASH 0x020000
++#define LQ_DEU_ID_AES 0x040000
++#define LQ_DEU_ID_3DES 0x080000
++#define LQ_DEU_ID_DES 0x100000
++
++extern int disable_deudma;
++
++int lq_deu_init(void);
++void lq_deu_exit(void);
++
++int lq_deu_init_des(void);
++int lq_deu_init_aes(void);
++int lq_deu_init_arc4(void);
++int lq_deu_init_sha1(void);
++int lq_deu_init_md5(void);
++int lq_deu_init_sha1_hmac(void);
++int lq_deu_init_md5_hmac(void);
++
++void lq_deu_fini_des(void);
++void lq_deu_fini_aes(void);
++void lq_deu_fini_arc4(void);
++void lq_deu_fini_sha1(void);
++void lq_deu_fini_md5(void);
++void lq_deu_fini_sha1_hmac(void);
++void lq_deu_fini_md5_hmac(void);
++
++/* board specific functions */
++/* { */
++static inline u32 deu_chip_init(void)
++{
++ return lq_crypto_ops.chip_init();
++}
++
++static inline void deu_des_chip_init(void)
++{
++ lq_crypto_ops.des_chip_init();
++}
++
++static inline void deu_aes_chip_init(void)
++{
++ lq_crypto_ops.aes_chip_init();
++}
++
++static inline u32 deu_input_swap(u32 input)
++{
++ return lq_crypto_ops.input_swap(input);
++}
++
++static inline u32 deu_endian_swap(u32 input)
++{
++ return lq_crypto_ops.endian_swap(input);
++}
++
++#ifdef CONFIG_CRYPTO_DEV_LANTIQ_DMA
++static inline int deu_aes_dma_malloc(int value)
++{
++ return lq_crypto_ops.aes_dma_malloc(value);
++}
++
++static inline int deu_des_dma_malloc(int value)
++{
++ return lq_crypto_ops.des_dma_malloc(value);
++}
++
++static inline u32 *deu_dma_align(const u8 *arg,
++ u32 *buff_alloc,
++ int in_out,
++ int nbytes)
++{
++ return lq_crypto_ops.dma_align(arg, buff_alloc, in_out, nbytes);
++}
++
++static inline void deu_aes_dma_memcpy(u32 *outcopy,
++ u32 *out_dma,
++ u8 *out_arg,
++ int nbytes)
++{
++ lq_crypto_ops.aes_dma_memcpy(outcopy, out_dma, out_arg, nbytes);
++}
++
++static inline void deu_des_dma_memcpy(u32 *outcopy,
++ u32 *out_dma,
++ u8 *out_arg,
++ int nbytes)
++{
++ lq_crypto_ops.des_dma_memcpy(outcopy, out_dma, out_arg, nbytes);
++}
++
++static inline void deu_dma_free(u32 *addr)
++{
++ lq_crypto_ops.dma_free(addr);
++}
++
++static inline int deu_dma_init(void)
++{
++ lq_crypto_ops.dma_init();
++}
++
++static inline void deu_dma_exit(void)
++{
++ lq_crypto_ops.dma_exit();
++}
++#endif
++
++/* } */
++
++#define DEU_WAKELIST_INIT(queue) \
++ init_waitqueue_head(&queue)
++
++#define DEU_WAIT_EVENT_TIMEOUT(queue, event, flags, timeout) \
++ do { \
++ wait_event_interruptible_timeout((queue), \
++ test_bit((event), \
++ &(flags)), (timeout)); \
++ clear_bit((event), &(flags)); \
++ }while (0)
++
++
++#define DEU_WAKEUP_EVENT(queue, event, flags) \
++ do { \
++ set_bit((event), &(flags)); \
++ wake_up_interruptible(&(queue)); \
++ }while (0)
++
++#define DEU_WAIT_EVENT(queue, event, flags) \
++ do { \
++ wait_event_interruptible(queue, \
++ test_bit((event), &(flags))); \
++ clear_bit((event), &(flags)); \
++ }while (0)
++
++struct deu_drv_priv {
++ wait_queue_head_t deu_thread_wait;
++#define DEU_EVENT 1
++ volatile long deu_event_flags;
++ u8 *deu_rx_buf;
++ u32 deu_rx_len;
++};
++
++#ifdef CRYPTO_DEBUG
++extern char deu_debug_level;
++# define DPRINTF(level, format, args...) \
++ if (level < deu_debug_level) \
++ printk(KERN_INFO "[%s %s %d]: " format, \
++ __FILE__, __func__, __LINE__, ##args)
++#else
++# define DPRINTF(level, format, args...) do { } while(0)
++#endif
++
++#endif /* DEU_H */
+--- /dev/null
++++ b/drivers/crypto/lantiq/deu_ar9.c
+@@ -0,0 +1,327 @@
++/*
++ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com>
++ * Copyright (C) 2009 Mohammad Firdaus
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <asm/io.h> /* dma_cache_inv */
++#include <linux/platform_device.h>
++
++#ifdef CONFIG_SOC_LANTIQ_XWAY
++
++#include "deu.h"
++
++/**
++ \defgroup LQ_DEU LQ_DEU_DRIVERS
++ \ingroup API
++ \brief Lantiq DEU driver module
++*/
++
++/**
++ \file deu_ar9.c
++ \brief Lantiq DEU board specific driver file for ar9
++*/
++
++/**
++ \defgroup BOARD_SPECIFIC_FUNCTIONS LQ_BOARD_SPECIFIC_FUNCTIONS
++ \ingroup LQ_DEU
++ \brief board specific functions
++*/
++
++#ifdef CONFIG_CRYPTO_DEV_LANTIQ_DMA
++struct lq_deu_device lq_deu[1];
++
++static u8 *g_dma_page_ptr = NULL;
++static u8 *g_dma_block = NULL;
++static u8 *g_dma_block2 = NULL;
++
++/** \fn int dma_init(void)
++ * \ingroup BOARD_SPECIFIC_FUNCTIONS
++ * \brief Initialize DMA for DEU usage. DMA specific registers are
++ * intialized here, including a pointer to the device, memory
++ * space for the device and DEU-DMA descriptors
++ * \return -1: fail, 0: SUCCESS
++*/
++static int dma_init(void)
++{
++ volatile struct deu_dma *dma = (struct deu_dma *) LQ_DEU_DMA_CON;
++ struct dma_device_info *dma_device = NULL;
++ int i = 0;
++
++ struct dma_device_info *deu_dma_device_ptr;
++
++ /* get one free page and share between g_dma_block and g_dma_block2 */
++ printk("PAGE_SIZE = %ld\n", PAGE_SIZE);
++ /* need 16-byte alignment memory block */
++ g_dma_page_ptr = (u8 *)__get_free_page(GFP_KERNEL);
++ /* need 16-byte alignment memory block */
++ g_dma_block = g_dma_page_ptr;
++ /* need 16-byte alignment memory block */
++ g_dma_block2 = (u8 *)(g_dma_page_ptr + (PAGE_SIZE >> 1));
++
++ /* deu_dma_priv_init(); */
++
++ deu_dma_device_ptr = dma_device_reserve("DEU");
++ if (!deu_dma_device_ptr) {
++ printk("DEU: reserve DMA fail!\n");
++ return -1;
++ }
++ lq_deu[0].dma_device = deu_dma_device_ptr;
++
++ dma_device = deu_dma_device_ptr;
++ /* dma_device->priv = &deu_dma_priv; */
++ dma_device->buffer_alloc = &deu_dma_buffer_alloc;
++ dma_device->buffer_free = &deu_dma_buffer_free;
++ dma_device->intr_handler = &deu_dma_intr_handler;
++
++ dma_device->tx_endianness_mode = LQ_DMA_ENDIAN_TYPE3;
++ dma_device->rx_endianness_mode = LQ_DMA_ENDIAN_TYPE3;
++ dma_device->port_num = 1;
++ dma_device->tx_burst_len = 2;
++ dma_device->rx_burst_len = 2;
++ dma_device->max_rx_chan_num = 1;
++ dma_device->max_tx_chan_num = 1;
++ dma_device->port_packet_drop_enable = 0;
++
++ for (i = 0; i < dma_device->max_rx_chan_num; i++) {
++ dma_device->rx_chan[i]->packet_size = DEU_MAX_PACKET_SIZE;
++ dma_device->rx_chan[i]->desc_len = 1;
++ dma_device->rx_chan[i]->control = LQ_DMA_CH_ON;
++ dma_device->rx_chan[i]->byte_offset = 0;
++ dma_device->rx_chan[i]->chan_poll_enable = 1;
++ }
++
++ for (i = 0; i < dma_device->max_tx_chan_num; i++) {
++ dma_device->tx_chan[i]->control = LQ_DMA_CH_ON;
++ dma_device->tx_chan[i]->desc_len = 1;
++ dma_device->tx_chan[i]->chan_poll_enable = 1;
++ }
++
++ dma_device->current_tx_chan = 0;
++ dma_device->current_rx_chan = 0;
++
++ i = dma_device_register(dma_device);
++ for (i = 0; i < dma_device->max_rx_chan_num; i++) {
++ (dma_device->rx_chan[i])->open(dma_device->rx_chan[i]);
++ }
++
++ dma->ctrl.BS = 0;
++ dma->ctrl.RXCLS = 0;
++ dma->ctrl.EN = 1;
++
++ return 0;
++}
++
++/** \fn u32 *dma_align(const u8 *arg, u32 *buffer_alloc, int in_buff, int nbytes)
++ * \ingroup BOARD_SPECIFIC_FUNCTIONS
++ * \brief Not used for AR9
++ * \param arg Pointer to the input / output memory address
++ * \param buffer_alloc A pointer to the buffer
++ * \param in_buff Input (if == 1) or Output (if == 0) buffer
++ * \param nbytes Number of bytes of data
++*/
++static u32 *dma_align(const u8 *arg, u32 *buffer_alloc, int in_buff, int nbytes)
++{
++ return (u32 *) arg;
++}
++
++/** \fn void aes_dma_memcpy(u32 *outcopy, u32 *out_dma, u8 *out_arg, int nbytes)
++ * \ingroup BOARD_SPECIFIC_FUNCTIONS
++ * \brief copy the DMA data to the memory address space for AES
++ * \param outcopy Not used
++ * \param out_dma A pointer to the memory address that stores the DMA data
++ * \param out_arg The pointer to the memory address that needs to be copied to]
++ * \param nbytes Number of bytes of data
++*/
++static void aes_dma_memcpy(u32 *outcopy, u32 *out_dma, u8 *out_arg, int nbytes)
++{
++ memcpy(out_arg, out_dma, nbytes);
++}
++
++/** \fn void des_dma_memcpy(u32 *outcopy, u32 *out_dma, u8 *out_arg, int nbytes)
++ * \ingroup BOARD_SPECIFIC_FUNCTIONS
++ * \brief copy the DMA data to the memory address space for DES
++ * \param outcopy Not used
++ * \param out_dma A pointer to the memory address that stores the DMA data
++ * \param out_arg The pointer to the memory address that needs to be copied to]
++ * \param nbytes Number of bytes of data
++*/
++static void des_dma_memcpy(u32 *outcopy, u32 *out_dma, u8 *out_arg, int nbytes)
++{
++ memcpy(out_arg, out_dma, nbytes);
++}
++
++/** \fn dma_exit(void)
++ * \ingroup BOARD_SPECIFIC_FUNCTIONS
++ * \brief unregister dma devices after exit
++*/
++static void dma_exit(void)
++{
++ if (g_dma_page_ptr)
++ free_page((u32) g_dma_page_ptr);
++ dma_device_release(lq_deu[0].dma_device);
++ dma_device_unregister(lq_deu[0].dma_device);
++}
++#endif /* CONFIG_CRYPTO_DEV_LANTIQ_DMA */
++
++/** \fn u32 endian_swap(u32 input)
++ * \ingroup BOARD_SPECIFIC_FUNCTIONS
++ * \brief Swap data given to the function
++ * \param input Data input to be swapped
++ * \return either the swapped data or the input data depending on whether it is in DMA mode or FPI mode
++*/
++static u32 endian_swap(u32 input)
++{
++#ifdef CONFIG_CRYPTO_DEV_LANTIQ_DMA
++ u8 *ptr = (u8 *)&input;
++ return ((ptr[3] << 24) | (ptr[2] << 16) | (ptr[1] << 8) | ptr[0]);
++#else
++ return input;
++#endif
++}
++
++/** \fn u32 input_swap(u32 input)
++ * \ingroup BOARD_SPECIFIC_FUNCTIONS
++ * \brief Not used
++ * \return input
++*/
++static u32 input_swap(u32 input)
++{
++ return input;
++}
++
++/** \fn void aes_chip_init(void)
++ * \ingroup BOARD_SPECIFIC_FUNCTIONS
++ * \brief initialize AES hardware
++*/
++static void aes_chip_init(void)
++{
++ volatile struct deu_aes *aes = (struct deu_aes *) AES_START;
++
++ aes->ctrl.SM = 1;
++#ifndef CONFIG_CRYPTO_DEV_LANTIQ_DMA
++ aes->ctrl.ARS = 1;
++#else
++ aes->ctrl.NDC = 1; /* to write to ENDI */
++ asm("sync");
++ aes->ctrl.ENDI = 0;
++ asm("sync");
++ aes->ctrl.ARS = 0; /* 0 for dma */
++ asm("sync");
++#endif
++}
++
++/** \fn void des_chip_init(void)
++ * \ingroup BOARD_SPECIFIC_FUNCTIONS
++ * \brief initialize DES hardware
++*/
++static void des_chip_init(void)
++{
++ volatile struct deu_des *des = (struct deu_des *) DES_3DES_START;
++
++#ifndef CONFIG_CRYPTO_DEV_LANTIQ_DMA
++ /* start crypto engine with write to ILR */
++ des->ctrl.SM = 1;
++ asm("sync");
++ des->ctrl.ARS = 1;
++#else
++ des->ctrl.SM = 1;
++ des->ctrl.NDC = 1;
++ asm("sync");
++ des->ctrl.ENDI = 0;
++ asm("sync");
++ des->ctrl.ARS = 0; /* 0 for dma */
++
++#endif
++}
++
++static u32 chip_init(void)
++{
++ volatile struct deu_clk_ctrl *clc = (struct deu_clk_ctrl *) LQ_DEU_CLK;
++
++#if 0
++ lq_pmu_enable(1<<20);
++#endif
++
++ clc->FSOE = 0;
++ clc->SBWE = 0;
++ clc->SPEN = 0;
++ clc->SBWE = 0;
++ clc->DISS = 0;
++ clc->DISR = 0;
++
++ return *LQ_DEU_ID;
++}
++
++static int lq_crypto_probe(struct platform_device *pdev)
++{
++#ifdef CONFIG_CRYPTO_DEV_LANTIQ_DMA
++ lq_crypto_ops.dma_init = dma_init;
++ lq_crypto_ops.dma_exit = dma_exit;
++ lq_crypto_ops.aes_dma_memcpy = aes_dma_memcpy;
++ lq_crypto_ops.des_dma_memcpy = des_dma_memcpy;
++ lq_crypto_ops.aes_dma_malloc = aes_dma_malloc;
++ lq_crypto_ops.des_dma_malloc = des_dma_malloc;
++ lq_crypto_ops.dma_align = dma_align;
++ lq_crypto_ops.dma_free = dma_free;
++#endif
++
++ lq_crypto_ops.endian_swap = endian_swap;
++ lq_crypto_ops.input_swap = input_swap;
++ lq_crypto_ops.aes_chip_init = aes_chip_init;
++ lq_crypto_ops.des_chip_init = des_chip_init;
++ lq_crypto_ops.chip_init = chip_init;
++
++ printk("lq_ar9_deu: driver loaded!\n");
++
++ lq_deu_init();
++
++ return 0;
++}
++
++static int lq_crypto_remove(struct platform_device *pdev)
++{
++ lq_deu_exit();
++
++ return 0;
++}
++
++static struct platform_driver lq_crypto = {
++ .probe = lq_crypto_probe,
++ .remove = lq_crypto_remove,
++ .driver = {
++ .owner = THIS_MODULE,
++ .name = "lq_ar9_deu"
++ }
++};
++
++static int __init lq_crypto_init(void)
++{
++ return platform_driver_register(&lq_crypto);
++}
++module_init(lq_crypto_init);
++
++static void __exit lq_crypto_exit(void)
++{
++ platform_driver_unregister(&lq_crypto);
++}
++module_exit(lq_crypto_exit);
++
++#endif
+--- /dev/null
++++ b/drivers/crypto/lantiq/deu_ar9.h
+@@ -0,0 +1,291 @@
++/*
++ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com>
++ * Copyright (C) 2009 Mohammad Firdaus / Infineon Technologies
++ */
++
++/**
++ \defgroup LQ_DEU LQ_DEU_DRIVERS
++ \ingroup API
++ \brief DEU driver module
++*/
++
++/**
++ \defgroup LQ_DEU_DEFINITIONS LQ_DEU_DEFINITIONS
++ \ingroup LQ_DEU
++ \brief Lantiq DEU definitions
++*/
++
++/**
++ \file deu_ar9.h
++ \brief DEU driver header file
++*/
++
++
++#ifndef DEU_AR9_H
++#define DEU_AR9_H
++
++#define LQ_DEU_BASE_ADDR (KSEG1 | 0x1E103100)
++#define LQ_DEU_CLK ((volatile u32 *)(LQ_DEU_BASE_ADDR + 0x0000))
++#define LQ_DEU_ID ((volatile u32 *)(LQ_DEU_BASE_ADDR + 0x0008))
++#define LQ_DES_CON ((volatile u32 *)(LQ_DEU_BASE_ADDR + 0x0010))
++#define LQ_AES_CON ((volatile u32 *)(LQ_DEU_BASE_ADDR + 0x0050))
++#define LQ_HASH_CON ((volatile u32 *)(LQ_DEU_BASE_ADDR + 0x00B0))
++#define LQ_ARC4_CON ((volatile u32 *)(LQ_DEU_BASE_ADDR + 0x0100))
++
++#define ARC4_START LQ_ARC4_CON
++#define DES_3DES_START LQ_DES_CON
++#define HASH_START LQ_HASH_CON
++#define AES_START LQ_AES_CON
++
++#ifdef CONFIG_CRYPTO_DEV_DMA
++# include "deu_dma.h"
++# define DEU_DWORD_REORDERING(ptr, buffer, in_out, bytes) \
++ deu_dma_align(ptr, buffer, in_out, bytes)
++# define AES_MEMORY_COPY(outcopy, out_dma, out_arg, nbytes) \
++ deu_aes_dma_memcpy(outcopy, out_dma, out_arg, nbytes)
++# define DES_MEMORY_COPY(outcopy, out_dma, out_arg, nbytes) \
++ deu_des_dma_memcpy(outcopy, out_dma, out_arg, nbytes)
++# define BUFFER_IN 1
++# define BUFFER_OUT 0
++# define AES_ALGO 1
++# define DES_ALGO 0
++# define ALLOCATE_MEMORY(val, type) 1
++# define FREE_MEMORY(buff)
++extern struct lq_deu_device lq_deu[1];
++#endif /* CONFIG_CRYPTO_DEV_DMA */
++
++/* SHA CONSTANTS */
++#define HASH_CON_VALUE 0x0700002C
++
++#define INPUT_ENDIAN_SWAP(input) deu_input_swap(input)
++#define DEU_ENDIAN_SWAP(input) deu_endian_swap(input)
++#define DELAY_PERIOD 10
++#define FIND_DEU_CHIP_VERSION chip_version()
++
++#define WAIT_AES_DMA_READY() \
++ do { \
++ int i; \
++ volatile struct deu_dma *dma = \
++ (struct deu_dma *) LQ_DEU_DMA_CON; \
++ volatile struct deu_aes *aes = \
++ (volatile struct deu_aes *) AES_START; \
++ for (i = 0; i < 10; i++) \
++ udelay(DELAY_PERIOD); \
++ while (dma->ctrl.BSY) {}; \
++ while (aes->ctrl.BUS) {}; \
++ } while (0)
++
++#define WAIT_DES_DMA_READY() \
++ do { \
++ int i; \
++ volatile struct deu_dma *dma = \
++ (struct deu_dma *) LQ_DEU_DMA_CON; \
++ volatile struct deu_des *des = \
++ (struct deu_des *) DES_3DES_START; \
++ for (i = 0; i < 10; i++) \
++ udelay(DELAY_PERIOD); \
++ while (dma->ctrl.BSY) {}; \
++ while (des->ctrl.BUS) {}; \
++ } while (0)
++
++#define AES_DMA_MISC_CONFIG() \
++ do { \
++ volatile struct deu_aes *aes = \
++ (volatile struct deu_aes *) AES_START; \
++ aes->ctrl.KRE = 1; \
++ aes->ctrl.GO = 1; \
++ } while(0)
++
++#define SHA_HASH_INIT \
++ do { \
++ volatile struct deu_hash *hash = \
++ (struct deu_hash *) HASH_START; \
++ hash->ctrl.SM = 1; \
++ hash->ctrl.ALGO = 0; \
++ hash->ctrl.INIT = 1; \
++ } while(0)
++
++/* DEU Common Structures for AR9*/
++
++struct deu_clk_ctrl {
++ u32 Res:26;
++ u32 FSOE:1;
++ u32 SBWE:1;
++ u32 EDIS:1;
++ u32 SPEN:1;
++ u32 DISS:1;
++ u32 DISR:1;
++};
++
++struct deu_des {
++ struct deu_des_ctrl { /* 10h */
++ u32 KRE:1;
++ u32 reserved1:5;
++ u32 GO:1;
++ u32 STP:1;
++ u32 Res2:6;
++ u32 NDC:1;
++ u32 ENDI:1;
++ u32 Res3:2;
++ u32 F:3;
++ u32 O:3;
++ u32 BUS:1;
++ u32 DAU:1;
++ u32 ARS:1;
++ u32 SM:1;
++ u32 E_D:1;
++ u32 M:3;
++ } ctrl;
++
++ u32 IHR; /* 14h */
++ u32 ILR; /* 18h */
++ u32 K1HR; /* 1c */
++ u32 K1LR;
++ u32 K2HR;
++ u32 K2LR;
++ u32 K3HR;
++ u32 K3LR; /* 30h */
++ u32 IVHR; /* 34h */
++ u32 IVLR; /* 38 */
++ u32 OHR; /* 3c */
++ u32 OLR; /* 40 */
++};
++
++struct deu_aes {
++ struct deu_aes_ctrl {
++ u32 KRE:1;
++ u32 reserved1:4;
++ u32 PNK:1;
++ u32 GO:1;
++ u32 STP:1;
++ u32 reserved2:6;
++ u32 NDC:1;
++ u32 ENDI:1;
++ u32 reserved3:2;
++ u32 F:3; /* fbs */
++ u32 O:3; /* om */
++ u32 BUS:1; /* bsy */
++ u32 DAU:1;
++ u32 ARS:1;
++ u32 SM:1;
++ u32 E_D:1;
++ u32 KV:1;
++ u32 K:2; /* KL */
++ } ctrl;
++
++ u32 ID3R; /* 80h */
++ u32 ID2R; /* 84h */
++ u32 ID1R; /* 88h */
++ u32 ID0R; /* 8Ch */
++ u32 K7R; /* 90h */
++ u32 K6R; /* 94h */
++ u32 K5R; /* 98h */
++ u32 K4R; /* 9Ch */
++ u32 K3R; /* A0h */
++ u32 K2R; /* A4h */
++ u32 K1R; /* A8h */
++ u32 K0R; /* ACh */
++ u32 IV3R; /* B0h */
++ u32 IV2R; /* B4h */
++ u32 IV1R; /* B8h */
++ u32 IV0R; /* BCh */
++ u32 OD3R; /* D4h */
++ u32 OD2R; /* D8h */
++ u32 OD1R; /* DCh */
++ u32 OD0R; /* E0h */
++};
++
++struct deu_arc4 {
++ struct arc4_controlr {
++ u32 KRE:1;
++ u32 KLEN:4;
++ u32 KSAE:1;
++ u32 GO:1;
++ u32 STP:1;
++ u32 reserved1:6;
++ u32 NDC:1;
++ u32 ENDI:1;
++ u32 reserved2:8;
++ u32 BUS:1; /* bsy */
++ u32 reserved3:1;
++ u32 ARS:1;
++ u32 SM:1;
++ u32 reserved4:4;
++ } ctrl;
++
++ u32 K3R; /* 104h */
++ u32 K2R; /* 108h */
++ u32 K1R; /* 10Ch */
++ u32 K0R; /* 110h */
++ u32 IDLEN; /* 114h */
++ u32 ID3R; /* 118h */
++ u32 ID2R; /* 11Ch */
++ u32 ID1R; /* 120h */
++ u32 ID0R; /* 124h */
++ u32 OD3R; /* 128h */
++ u32 OD2R; /* 12Ch */
++ u32 OD1R; /* 130h */
++ u32 OD0R; /* 134h */
++};
++
++struct deu_hash {
++ struct deu_hash_ctrl {
++ u32 reserved1:5;
++ u32 KHS:1;
++ u32 GO:1;
++ u32 INIT:1;
++ u32 reserved2:6;
++ u32 NDC:1;
++ u32 ENDI:1;
++ u32 reserved3:7;
++ u32 DGRY:1;
++ u32 BSY:1;
++ u32 reserved4:1;
++ u32 IRCL:1;
++ u32 SM:1;
++ u32 KYUE:1;
++ u32 HMEN:1;
++ u32 SSEN:1;
++ u32 ALGO:1;
++ } ctrl;
++
++ u32 MR; /* B4h */
++ u32 D1R; /* B8h */
++ u32 D2R; /* BCh */
++ u32 D3R; /* C0h */
++ u32 D4R; /* C4h */
++ u32 D5R; /* C8h */
++ u32 dummy; /* CCh */
++ u32 KIDX; /* D0h */
++ u32 KEY; /* D4h */
++ u32 DBN; /* D8h */
++};
++
++struct deu_dma {
++ struct deu_dma_ctrl {
++ u32 reserved1:22;
++ u32 BS:2;
++ u32 BSY:1;
++ u32 reserved2:1;
++ u32 ALGO:2;
++ u32 RXCLS:2;
++ u32 reserved3:1;
++ u32 EN:1;
++ } ctrl;
++};
++
++#endif /* DEU_AR9_H */
+--- /dev/null
++++ b/drivers/crypto/lantiq/deu_danube.c
+@@ -0,0 +1,484 @@
++/*
++ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com>
++ * Copyright (C) 2009 Mohammad Firdaus
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <asm/io.h> /* dma_cache_inv */
++#include <linux/platform_device.h>
++
++#ifdef CONFIG_SOC_LANTIQ_XWAY
++
++#include "deu.h"
++
++/**
++ \defgroup LQ_DEU LQ_DEU_DRIVERS
++ \ingroup API
++ \brief DEU driver module
++*/
++
++/**
++ \file deu_danube.c
++ \ingroup LQ_DEU
++ \brief board specific DEU driver file for danube
++*/
++
++/**
++ \defgroup BOARD_SPECIFIC_FUNCTIONS LQ_BOARD_SPECIFIC_FUNCTIONS
++ \ingroup LQ_DEU
++ \brief board specific DEU functions
++*/
++
++static int danube_pre_1_4;
++
++#ifdef CONFIG_CRYPTO_DEV_LANTIQ_DMA
++u32 *des_buff_in = NULL;
++u32 *des_buff_out = NULL;
++u32 *aes_buff_in = NULL;
++u32 *aes_buff_out = NULL;
++
++struct lq_deu_device lq_deu[1];
++
++static u8 *g_dma_page_ptr = NULL;
++static u8 *g_dma_block = NULL;
++static u8 *g_dma_block2 = NULL;
++
++/** \fn int dma_init(void)
++ * \ingroup BOARD_SPECIFIC_FUNCTIONS
++ * \brief Initialize DMA for DEU usage. DMA specific registers are
++ * intialized here, including a pointer to the device, memory
++ * space for the device and DEU-DMA descriptors
++ * \return -1 if fail, otherwise return 0
++*/
++static int dma_init(void)
++{
++ struct dma_device_info *dma_device = NULL;
++ int i = 0;
++ volatile struct deu_dma *dma = (struct deu_dma *) LQ_DEU_DMA_CON;
++ struct dma_device_info *deu_dma_device_ptr;
++
++ /* get one free page and share between g_dma_block and g_dma_block2 */
++ printk("PAGE_SIZE = %ld\n", PAGE_SIZE);
++ /* need 16-byte alignment memory block */
++ g_dma_page_ptr = (u8 *)__get_free_page(GFP_KERNEL);
++ /* need 16-byte alignment memory block */
++ g_dma_block = g_dma_page_ptr;
++ /* need 16-byte alignment memory block */
++ g_dma_block2 = (u8 *)(g_dma_page_ptr + (PAGE_SIZE >> 1));
++
++ deu_dma_device_ptr = dma_device_reserve("DEU");
++ if (!deu_dma_device_ptr) {
++ printk("DEU: reserve DMA fail!\n");
++ return -1;
++ }
++ lq_deu[0].dma_device = deu_dma_device_ptr;
++ dma_device = deu_dma_device_ptr;
++ /* dma_device->priv = &deu_dma_priv; */
++ dma_device->buffer_alloc = &deu_dma_buffer_alloc;
++ dma_device->buffer_free = &deu_dma_buffer_free;
++ dma_device->intr_handler = &deu_dma_intr_handler;
++ dma_device->tx_endianness_mode = LQ_DMA_ENDIAN_TYPE3;
++ dma_device->rx_endianness_mode = LQ_DMA_ENDIAN_TYPE3;
++ dma_device->port_num = 1;
++ dma_device->tx_burst_len = 4;
++ dma_device->max_rx_chan_num = 1;
++ dma_device->max_tx_chan_num = 1;
++ dma_device->port_packet_drop_enable = 0;
++
++ for (i = 0; i < dma_device->max_rx_chan_num; i++) {
++ dma_device->rx_chan[i]->packet_size = DEU_MAX_PACKET_SIZE;
++ dma_device->rx_chan[i]->desc_len = 1;
++ dma_device->rx_chan[i]->control = LQ_DMA_CH_ON;
++ dma_device->rx_chan[i]->byte_offset = 0;
++ dma_device->rx_chan[i]->chan_poll_enable = 1;
++
++ }
++
++ for (i = 0; i < dma_device->max_tx_chan_num; i++) {
++ dma_device->tx_chan[i]->control = LQ_DMA_CH_ON;
++ dma_device->tx_chan[i]->desc_len = 1;
++ dma_device->tx_chan[i]->chan_poll_enable = 1;
++ }
++
++ dma_device->current_tx_chan = 0;
++ dma_device->current_rx_chan = 0;
++
++ dma_device_register(dma_device);
++ for (i = 0; i < dma_device->max_rx_chan_num; i++) {
++ (dma_device->rx_chan[i])->open(dma_device->rx_chan[i]);
++ }
++
++ dma->ctrl.BS = 0;
++ dma->ctrl.RXCLS = 0;
++ dma->ctrl.EN = 1;
++
++
++ *LQ_DMA_PS = 1;
++
++ /* DANUBE PRE 1.4 SOFTWARE FIX */
++ if (danube_pre_1_4)
++ *LQ_DMA_PCTRL = 0x14;
++ else
++ *LQ_DMA_PCTRL = 0xF14;
++
++ return 0;
++}
++
++/** \fn u32 *dma_align(const u8 *arg, u32 *buffer_alloc, int in_buff, int nbytes)
++ * \ingroup BOARD_SPECIFIC_FUNCTIONS
++ * \brief A fix to align mis-aligned address for Danube version 1.3 chips
++ * which has memory alignment issues.
++ * \param arg Pointer to the input / output memory address
++ * \param buffer_alloc A pointer to the buffer
++ * \param in_buff Input (if == 1) or Output (if == 0) buffer
++ * \param nbytes Number of bytes of data
++ * \return returns arg: if address is aligned, buffer_alloc: if memory address is not aligned
++*/
++static u32 *dma_align(const u8 *arg, u32 *buffer_alloc, int in_buff, int nbytes)
++{
++ if (danube_pre_1_4) {
++ /* for input buffer */
++ if (in_buff) {
++ if (((u32) arg) & 0xF) {
++ memcpy(buffer_alloc, arg, nbytes);
++ return (u32 *) buffer_alloc;
++ } else {
++ return (u32 *) arg;
++ }
++ }
++ else {
++ /* for output buffer */
++ if (((u32) arg) & 0x3)
++ return buffer_alloc;
++ else
++ return (u32 *) arg;
++ }
++ }
++
++ return (u32 *) arg;
++}
++
++/** \fn void aes_dma_memcpy(u32 *outcopy, u32 *out_dma, u8 *out_arg, int nbytes)
++ * \ingroup BOARD_SPECIFIC_FUNCTIONS
++ * \brief copy the DMA data to the memory address space for AES. The swaping
++ * of the 4 bytes is done only for Danube version 1.3 (FIX). Otherwise,
++ * it is a direct memory copy to out_arg pointer
++ * \param outcopy Pointer to the address to store swapped copy
++ * \param out_dma A pointer to the memory address that stores the DMA data
++ * \param out_arg The pointer to the memory address that needs to be copied to
++ * \param nbytes Number of bytes of data
++*/
++static void aes_dma_memcpy(u32 *outcopy, u32 *out_dma, u8 *out_arg, int nbytes)
++{
++ int i = 0;
++ int x = 0;
++
++ /* DANUBE PRE 1.4 SOFTWARE FIX */
++ if (danube_pre_1_4) {
++ for (i = 0; i < (nbytes / 4); i++) {
++ x = i ^ 0x3;
++ outcopy[i] = out_dma[x];
++
++ }
++ if (((u32) out_arg) & 0x3) {
++ memcpy((u8 *)out_arg, outcopy, nbytes);
++ }
++ } else {
++ memcpy(out_arg, out_dma, nbytes);
++ }
++}
++
++/** \fn void des_dma_memcpy(u32 *outcopy, u32 *out_dma, u8 *out_arg, int nbytes)
++ * \ingroup BOARD_SPECIFIC_FUNCTIONS
++ * \brief copy the DMA data to the memory address space for DES. The swaping
++ * of the 4 bytes is done only for Danube version 1.3 (FIX). Otherwise,
++ * it is a direct memory copy to out_arg pointer
++ * \param outcopy Pointer to the address to store swapped copy
++ * \param out_dma A pointer to the memory address that stores the DMA data
++ * \param out_arg The pointer to the memory address that needs to be copied to
++ * \param nbytes Number of bytes of data
++*/
++static void des_dma_memcpy(u32 *outcopy, u32 *out_dma, u8 *out_arg, int nbytes)
++{
++ int i = 0;
++ int x = 0;
++
++ /* DANUBE PRE 1.4 SOFTWARE FIX */
++ if (danube_pre_1_4) {
++ for (i = 0; i < (nbytes / 4); i++) {
++ x = i ^ 1;
++ outcopy[i] = out_dma[x];
++
++ }
++ if (((u32) out_arg) & 0x3) {
++ memcpy((u8 *)out_arg, outcopy, nbytes);
++ }
++ } else {
++ memcpy(out_arg, out_dma, nbytes);
++ }
++}
++
++/** \fn int des_dma_malloc(int value)
++ * \ingroup BOARD_SPECIFIC_FUNCTIONS
++ * \brief allocates memory to the necessary memory input/output buffer
++ * location, used during the DES algorithm DMA transfer (memory
++ * alignment issues)
++ * \param value value determinds whether the calling of the function is for a
++ * input buffer or for an output buffer memory allocation
++*/
++static int des_dma_malloc(int value)
++{
++ if (danube_pre_1_4) {
++ if (value == BUFFER_IN) {
++ des_buff_in = kmalloc(DEU_MAX_PACKET_SIZE, GFP_ATOMIC);
++ if (!des_buff_in)
++ return -1;
++ else
++ return 0;
++ }
++ else {
++ des_buff_out = kmalloc(DEU_MAX_PACKET_SIZE, GFP_ATOMIC);
++ if (!des_buff_out)
++ return -1;
++ else
++ return 0;
++ }
++ } else {
++ return 0;
++ }
++}
++
++/** \fn int aes_dma_malloc(int value)
++ * \ingroup BOARD_SPECIFIC_FUNCTIONS
++ * \brief allocates memory to the necessary memory input/output buffer
++ * location, used during the AES algorithm DMA transfer (memory
++ * alignment issues)
++ * \param value value determinds whether the calling of the function is for a
++ * input buffer or for an output buffer memory allocation
++*/
++static int aes_dma_malloc(int value)
++{
++ if (danube_pre_1_4) {
++ if (value == BUFFER_IN) {
++ aes_buff_in = kmalloc(DEU_MAX_PACKET_SIZE, GFP_ATOMIC);
++ if (!aes_buff_in)
++ return -1;
++ else
++ return 0;
++ }
++ else {
++ aes_buff_out = kmalloc(DEU_MAX_PACKET_SIZE, GFP_ATOMIC);
++ if (!aes_buff_out)
++ return -1;
++ else
++ return 0;
++ }
++ } else {
++ return 0;
++ }
++}
++
++/** \fn void dma_free(u32 *addr)
++ * \ingroup BOARD_SPECIFIC_FUNCTIONS
++ * \brief frees previously allocated memory
++ * \param addr memory address of the buffer that needs to be freed
++*/
++static void dma_free(u32 *addr)
++{
++ if (addr)
++ kfree(addr);
++ return;
++}
++
++/** \fn dma_exit(void)
++ * \ingroup BOARD_SPECIFIC_FUNCTIONS
++ * \brief unregister dma devices after exit
++*/
++static void dma_exit(void)
++{
++ if (g_dma_page_ptr)
++ free_page((u32) g_dma_page_ptr);
++ dma_device_release(lq_deu[0].dma_device);
++ dma_device_unregister(lq_deu[0].dma_device);
++}
++#endif /* CONFIG_CRYPTO_DEV_LANTIQ_DMA */
++
++/** \fn u32 endian_swap(u32 input)
++ * \ingroup BOARD_SPECIFIC_FUNCTIONS
++ * \brief function is not used
++ * \param input Data input to be swapped
++ * \return input
++*/
++static u32 endian_swap(u32 input)
++{
++ return input;
++}
++
++/** \fn u32 input_swap(u32 input)
++ * \ingroup BOARD_SPECIFIC_FUNCTIONS
++ * \brief Swap the input data if the current chip is Danube version
++ * 1.4 and do nothing to the data if the current chip is
++ * Danube version 1.3
++ * \param input data that needs to be swapped
++ * \return input or swapped input
++*/
++static u32 input_swap(u32 input)
++{
++ if (!danube_pre_1_4) {
++ u8 *ptr = (u8 *)&input;
++ return ((ptr[3] << 24) | (ptr[2] << 16) | (ptr[1] << 8) | ptr[0]);
++ } else {
++ return input;
++ }
++}
++
++/** \fn void aes_chip_init(void)
++ * \ingroup BOARD_SPECIFIC_FUNCTIONS
++ * \brief initialize AES hardware
++*/
++static void aes_chip_init(void)
++{
++ volatile struct deu_aes *aes = (struct deu_aes *) AES_START;
++
++#ifndef CONFIG_CRYPTO_DEV_LANTIQ_DMA
++ /* start crypto engine with write to ILR */
++ aes->ctrl.SM = 1;
++ aes->ctrl.ARS = 1;
++#else
++ aes->ctrl.SM = 1;
++ aes->ctrl.ARS = 1; /* 0 for dma */
++#endif
++}
++
++/** \fn void des_chip_init(void)
++ * \ingroup BOARD_SPECIFIC_FUNCTIONS
++ * \brief initialize DES hardware
++*/
++static void des_chip_init(void)
++{
++ volatile struct deu_des *des = (struct deu_des *) DES_3DES_START;
++
++#ifndef CONFIG_CRYPTO_DEV_LANTIQ_DMA
++ /* start crypto engine with write to ILR */
++ des->ctrl.SM = 1;
++ des->ctrl.ARS = 1;
++#else
++ des->ctrl.SM = 1;
++ des->ctrl.ARS = 1; /* 0 for dma */
++#endif
++}
++
++/** \fn void deu_chip_version(void)
++ * \ingroup LQ_DES_FUNCTIONS
++ * \brief To find the version of the chip by looking at the chip ID
++ * \param danube_pre_1_4 (sets to 1 if Chip is Danube less than v1.4)
++*/
++static void deu_chip_version(void)
++{
++ /* DANUBE PRE 1.4 SOFTWARE FIX */
++ int chip_id = 0;
++ chip_id = *LQ_MPS_CHIPID;
++ chip_id >>= 28;
++
++ if (chip_id >= 4) {
++ danube_pre_1_4 = 0;
++ printk("Danube Chip ver. 1.4 detected. \n");
++ }
++ else {
++ danube_pre_1_4 = 1;
++ printk("Danube Chip ver. 1.3 or below detected. \n");
++ }
++}
++
++static u32 chip_init(void)
++{
++ volatile struct deu_clk_ctrl *clc = (struct deu_clk_ctrl *) LQ_DEU_CLK;
++
++#if 0
++ lq_pmu_enable(1<<20);
++#endif
++
++ deu_chip_version();
++
++ clc->FSOE = 0;
++ clc->SBWE = 0;
++ clc->SPEN = 0;
++ clc->SBWE = 0;
++ clc->DISS = 0;
++ clc->DISR = 0;
++
++ return *LQ_DEU_ID;
++}
++
++static int lq_crypto_probe(struct platform_device *pdev)
++{
++#ifdef CONFIG_CRYPTO_DEV_LANTIQ_DMA
++ lq_crypto_ops.dma_init = dma_init;
++ lq_crypto_ops.dma_exit = dma_exit;
++ lq_crypto_ops.aes_dma_memcpy = aes_dma_memcpy;
++ lq_crypto_ops.des_dma_memcpy = des_dma_memcpy;
++ lq_crypto_ops.aes_dma_malloc = aes_dma_malloc;
++ lq_crypto_ops.des_dma_malloc = des_dma_malloc;
++ lq_crypto_ops.dma_align = dma_align;
++ lq_crypto_ops.dma_free = dma_free;
++#endif
++
++ lq_crypto_ops.endian_swap = endian_swap;
++ lq_crypto_ops.input_swap = input_swap;
++ lq_crypto_ops.aes_chip_init = aes_chip_init;
++ lq_crypto_ops.des_chip_init = des_chip_init;
++ lq_crypto_ops.chip_init = chip_init;
++
++ printk("lq_danube_deu: driver loaded!\n");
++
++ lq_deu_init();
++
++ return 0;
++}
++
++static int lq_crypto_remove(struct platform_device *pdev)
++{
++ lq_deu_exit();
++
++ return 0;
++}
++
++static struct platform_driver lq_crypto = {
++ .probe = lq_crypto_probe,
++ .remove = lq_crypto_remove,
++ .driver = {
++ .owner = THIS_MODULE,
++ .name = "lq_danube_deu"
++ }
++};
++
++static int __init lq_crypto_init(void)
++{
++ return platform_driver_register(&lq_crypto);
++}
++module_init(lq_crypto_init);
++
++static void __exit lq_crypto_exit(void)
++{
++ platform_driver_unregister(&lq_crypto);
++}
++module_exit(lq_crypto_exit);
++
++#endif
+--- /dev/null
++++ b/drivers/crypto/lantiq/deu_danube.h
+@@ -0,0 +1,255 @@
++/*
++ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com>
++ * Copyright (C) 2009 Mohammad Firdaus / Infineon Technologies
++ */
++
++/**
++ \defgroup LQ_DEU LQ_DEU_DRIVERS
++ \ingroup API
++ \brief DEU driver module
++*/
++
++/**
++ \file deu_danube.h
++ \brief board specific driver header file for danube
++*/
++
++/**
++ \defgroup BOARD_SPECIFIC_FUNCTIONS LQ_BOARD_SPECIFIC_FUNCTIONS
++ \ingroup LQ_DEU
++ \brief board specific DEU header files
++*/
++
++#ifndef DEU_DANUBE_H
++#define DEU_DANUBE_H
++
++#define LQ_DEU_BASE_ADDR (KSEG1 | 0x1E103100)
++#define LQ_DEU_CLK ((volatile u32 *)(LQ_DEU_BASE_ADDR + 0x0000))
++#define LQ_DEU_ID ((volatile u32 *)(LQ_DEU_BASE_ADDR + 0x0008))
++#define LQ_DES_CON ((volatile u32 *)(LQ_DEU_BASE_ADDR + 0x0010))
++#define LQ_AES_CON ((volatile u32 *)(LQ_DEU_BASE_ADDR + 0x0050))
++#define LQ_HASH_CON ((volatile u32 *)(LQ_DEU_BASE_ADDR + 0x00B0))
++#define LQ_ARC4_CON ((volatile u32 *)(LQ_DEU_BASE_ADDR + 0x0100))
++
++#define ARC4_START LQ_ARC4_CON
++#define DES_3DES_START LQ_DES_CON
++#define HASH_START LQ_HASH_CON
++#define AES_START LQ_AES_CON
++
++#define LQ_MPS (KSEG1 | 0x1F107000)
++#define LQ_MPS_CHIPID ((volatile u32*)(LQ_MPS + 0x0344))
++#define LQ_MPS_CHIPID_VERSION_GET(value) (((value) >> 28) & 0xF)
++#define LQ_MPS_CHIPID_VERSION_SET(value) (((value) & 0xF) << 28)
++#define LQ_MPS_CHIPID_PARTNUM_GET(value) (((value) >> 12) & 0xFFFF)
++#define LQ_MPS_CHIPID_PARTNUM_SET(value) (((value) & 0xFFFF) << 12)
++#define LQ_MPS_CHIPID_MANID_GET(value) (((value) >> 1) & 0x7FF)
++#define LQ_MPS_CHIPID_MANID_SET(value) (((value) & 0x7FF) << 1)
++
++#ifdef CONFIG_CRYPTO_DEV_DMA
++# define DEU_DWORD_REORDERING(ptr, buffer, in_out, bytes) \
++ deu_dma_align(ptr, buffer, in_out, bytes)
++# define AES_MEMORY_COPY(outcopy, out_dma, out_arg, nbytes) \
++ deu_aes_dma_memcpy(outcopy, out_dma, out_arg, nbytes)
++# define DES_MEMORY_COPY(outcopy, out_dma, out_arg, nbytes) \
++ deu_des_dma_memcpy(outcopy, out_dma, out_arg, nbytes)
++# define BUFFER_IN 1
++# define BUFFER_OUT 0
++# define DELAY_PERIOD 9
++# define AES_ALGO 1
++# define DES_ALGO 0
++# define FREE_MEMORY(buff) deu_dma_free(buff)
++# define ALLOCATE_MEMORY(val, type) type ? \
++ deu_aes_dma_malloc(val) : \
++ deu_des_dma_malloc(val)
++#endif /* CONFIG_CRYPTO_DEV_DMA */
++
++#define INPUT_ENDIAN_SWAP(input) deu_input_swap(input)
++#define DEU_ENDIAN_SWAP(input) deu_endian_swap(input)
++#define AES_DMA_MISC_CONFIG()
++
++#define WAIT_AES_DMA_READY() \
++ do { \
++ int i; \
++ volatile struct deu_dma *dma = \
++ (struct deu_dma *) LQ_DEU_DMA_CON; \
++ volatile struct deu_aes *aes = \
++ (volatile struct deu_aes *) AES_START; \
++ for (i = 0; i < 10; i++) \
++ udelay(DELAY_PERIOD); \
++ while (dma->ctrl.BSY) {}; \
++ while (aes->ctrl.BUS) {}; \
++ } while (0)
++
++#define WAIT_DES_DMA_READY() \
++ do { \
++ int i; \
++ volatile struct deu_dma *dma = \
++ (struct deu_dma *) LQ_DEU_DMA_CON; \
++ volatile struct deu_des *des = \
++ (struct deu_des *) DES_3DES_START; \
++ for (i = 0; i < 10; i++) \
++ udelay(DELAY_PERIOD); \
++ while (dma->ctrl.BSY) {}; \
++ while (des->ctrl.BUS) {}; \
++ } while (0)
++
++#define SHA_HASH_INIT \
++ do { \
++ volatile struct deu_hash *hash = \
++ (struct deu_hash *) HASH_START; \
++ hash->ctrl.SM = 1; \
++ hash->ctrl.ALGO = 0; \
++ hash->ctrl.INIT = 1; \
++ } while(0)
++
++/* DEU STRUCTURES */
++
++struct deu_clk_ctrl {
++ u32 Res:26;
++ u32 FSOE:1;
++ u32 SBWE:1;
++ u32 EDIS:1;
++ u32 SPEN:1;
++ u32 DISS:1;
++ u32 DISR:1;
++};
++
++struct deu_des {
++ struct deu_des_ctrl {
++ u32 KRE:1;
++ u32 reserved1:5;
++ u32 GO:1;
++ u32 STP:1;
++ u32 Res2:6;
++ u32 NDC:1;
++ u32 ENDI:1;
++ u32 Res3:2;
++ u32 F:3;
++ u32 O:3;
++ u32 BUS:1;
++ u32 DAU:1;
++ u32 ARS:1;
++ u32 SM:1;
++ u32 E_D:1;
++ u32 M:3;
++ } ctrl;
++
++ u32 IHR;
++ u32 ILR;
++ u32 K1HR;
++ u32 K1LR;
++ u32 K2HR;
++ u32 K2LR;
++ u32 K3HR;
++ u32 K3LR;
++ u32 IVHR;
++ u32 IVLR;
++ u32 OHR;
++ u32 OLR;
++};
++
++struct deu_aes {
++ struct deu_aes_ctrl {
++ u32 KRE:1;
++ u32 reserved1:4;
++ u32 PNK:1;
++ u32 GO:1;
++ u32 STP:1;
++ u32 reserved2:6;
++ u32 NDC:1;
++ u32 ENDI:1;
++ u32 reserved3:2;
++ u32 F:3; /* fbs */
++ u32 O:3; /* om */
++ u32 BUS:1; /* bsy */
++ u32 DAU:1;
++ u32 ARS:1;
++ u32 SM:1;
++ u32 E_D:1;
++ u32 KV:1;
++ u32 K:2; /* KL */
++ } ctrl;
++
++ u32 ID3R; /* 80h */
++ u32 ID2R; /* 84h */
++ u32 ID1R; /* 88h */
++ u32 ID0R; /* 8Ch */
++ u32 K7R; /* 90h */
++ u32 K6R; /* 94h */
++ u32 K5R; /* 98h */
++ u32 K4R; /* 9Ch */
++ u32 K3R; /* A0h */
++ u32 K2R; /* A4h */
++ u32 K1R; /* A8h */
++ u32 K0R; /* ACh */
++ u32 IV3R; /* B0h */
++ u32 IV2R; /* B4h */
++ u32 IV1R; /* B8h */
++ u32 IV0R; /* BCh */
++ u32 OD3R; /* D4h */
++ u32 OD2R; /* D8h */
++ u32 OD1R; /* DCh */
++ u32 OD0R; /* E0h */
++};
++
++struct deu_hash {
++ struct deu_hash_ctrl {
++ u32 reserved1:5;
++ u32 KHS:1;
++ u32 GO:1;
++ u32 INIT:1;
++ u32 reserved2:6;
++ u32 NDC:1;
++ u32 ENDI:1;
++ u32 reserved3:7;
++ u32 DGRY:1;
++ u32 BSY:1;
++ u32 reserved4:1;
++ u32 IRCL:1;
++ u32 SM:1;
++ u32 KYUE:1;
++ u32 HMEN:1;
++ u32 SSEN:1;
++ u32 ALGO:1;
++ } ctrl;
++
++ u32 MR; /* B4h */
++ u32 D1R; /* B8h */
++ u32 D2R; /* BCh */
++ u32 D3R; /* C0h */
++ u32 D4R; /* C4h */
++ u32 D5R; /* C8h */
++ u32 dummy; /* CCh */
++ u32 KIDX; /* D0h */
++ u32 KEY; /* D4h */
++ u32 DBN; /* D8h */
++};
++
++struct deu_dma {
++ struct deu_dma_ctrl {
++ u32 reserved1:22;
++ u32 BS:2;
++ u32 BSY:1;
++ u32 reserved2:1;
++ u32 ALGO:2;
++ u32 RXCLS:2;
++ u32 reserved3:1;
++ u32 EN:1;
++ } ctrl;
++};
++
++#endif /* DEU_DANUBE_H */
+--- /dev/null
++++ b/drivers/crypto/lantiq/deu_dma.c
+@@ -0,0 +1,147 @@
++/*
++ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com>
++ * Copyright (C) 2009 Mohammad Firdaus
++ */
++
++/**
++ \defgroup LQ_DEU LQ_DEU_DRIVERS
++ \ingroup LQ_API
++ \brief Lantiq DEU driver module
++*/
++
++/**
++ \file deu_dma.c
++ \ingroup LQ_DEU
++ \brief DMA DEU driver file
++*/
++
++/**
++ \defgroup LQ_DMA_FUNCTIONS LQ_DMA_FUNCTIONS
++ \ingroup LQ_DEU
++ \brief DMA DEU driver functions
++*/
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/delay.h>
++#include <asm/io.h>
++#include "deu.h"
++#include "deu_dma.h"
++
++/* extern struct deu_drv_priv deu_dma_priv; */
++
++/** \fn int deu_dma_intr_handler(struct dma_device_info *dma_dev, int status)
++ * \ingroup LQ_DMA_FUNCTIONS
++ * \brief callback function for DEU DMA interrupt
++ * \param dma_dev dma device
++ * \param status not used
++*/
++int deu_dma_intr_handler(struct dma_device_info *dma_dev, int status)
++{
++#if 0
++ int len = 0;
++ while (len <= 20000) { len++; }
++ u8 *buf;
++ int len = 0;
++
++ struct deu_drv_priv *deu_priv = (struct deu_drv_priv *)dma_dev->priv;
++ /* printk("status:%d \n",status); */
++ switch(status) {
++ case RCV_INT:
++ len = dma_device_read(dma_dev, (u8 **)&buf, NULL);
++ if ( len != deu_priv->deu_rx_len) {
++ printk(KERN_ERR "%s packet length %d is not "
++ "equal to expect %d\n",
++ __func__, len, deu_priv->deu_rx_len);
++ return -1;
++ }
++ memcpy(deu_priv->deu_rx_buf, buf, deu_priv->deu_rx_len);
++ /* Reset for next usage */
++ deu_priv->deu_rx_buf = NULL;
++ deu_priv->deu_rx_len = 0;
++ DEU_WAKEUP_EVENT(deu_priv->deu_thread_wait, DEU_EVENT,
++ deu_priv->deu_event_flags);
++ break;
++ case TX_BUF_FULL_INT:
++ /* delay for buffer to be cleared */
++ while (len <= 20000) { len++; }
++ break;
++
++ case TRANSMIT_CPT_INT:
++ break;
++ default:
++ break;
++ }
++#endif
++ return 0;
++}
++
++extern u8 *g_dma_block;
++extern u8 *g_dma_block2;
++
++/** \fn u8 *deu_dma_buffer_alloc(int len, int *byte_offset, void **opt)
++ * \ingroup LQ_DMA_FUNCTIONS
++ * \brief callback function for allocating buffers for dma receive descriptors
++ * \param len not used
++ * \param byte_offset dma byte offset
++ * \param *opt not used
++ *
++*/
++u8 *deu_dma_buffer_alloc(int len, int *byte_offset, void **opt)
++{
++ u8 *swap = NULL;
++
++ /* dma-core needs at least 2 blocks of memory */
++ swap = g_dma_block;
++ g_dma_block = g_dma_block2;
++ g_dma_block2 = swap;
++
++ /* dma_cache_wback_inv((unsigned long) g_dma_block,(PAGE_SIZE >> 1)); */
++ *byte_offset = 0;
++
++ return g_dma_block;
++}
++
++/** \fn int deu_dma_buffer_free(u8 * dataptr, void *opt)
++ * \ingroup LQ_DMA_FUNCTIONS
++ * \brief callback function for freeing dma transmit descriptors
++ * \param dataptr data pointer to be freed
++ * \param opt not used
++*/
++int deu_dma_buffer_free(u8 *dataptr, void *opt)
++{
++#if 0
++ printk("Trying to free memory buffer\n");
++ if (dataptr == NULL && opt == NULL)
++ return 0;
++ else if (opt == NULL) {
++ kfree(dataptr);
++ return 1;
++ }
++ else if (dataptr == NULL) {
++ kfree(opt);
++ return 1;
++ }
++ else {
++ kfree(opt);
++ kfree(dataptr);
++ }
++#endif
++ return 0;
++}
+--- /dev/null
++++ b/drivers/crypto/lantiq/deu_dma.h
+@@ -0,0 +1,78 @@
++/*
++ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com>
++ * Copyright (C) 2009 Mohammad Firdaus
++ */
++
++/**
++ \addtogroup LQ_DEU LQ_DEU_DRIVERS
++ \ingroup API
++ \brief Lantiq DEU driver module
++*/
++
++/**
++ \file deu_dma.h
++ \ingroup LQ_DEU
++ \brief DMA DEU driver header file
++*/
++
++#ifndef DEU_DMA_H
++#define DEU_DMA_H
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/mm.h>
++#include <linux/crypto.h>
++#include <asm/scatterlist.h>
++#include <asm/byteorder.h>
++#include <linux/skbuff.h>
++#include <linux/netdevice.h>
++
++#include <asm/ifx/irq.h>
++#include <asm/ifx/ifx_dma_core.h>
++#ifndef CONFIG_CRYPTO_DEV_POLL_DMA
++# define CONFIG_CRYPTO_DEV_POLL_DMA
++#endif
++
++/* must match the size of memory block allocated for
++ * g_dma_block and g_dma_block2 */
++#define DEU_MAX_PACKET_SIZE (PAGE_SIZE >> 1)
++
++struct lq_deu_device {
++ struct dma_device_info *dma_device;
++ u8 *dst;
++ u8 *src;
++ int len;
++ int dst_count;
++ int src_count;
++ int recv_count;
++ int packet_size;
++ int packet_num;
++ wait_queue_t wait;
++};
++
++extern struct lq_deu_device lq_deu[1];
++
++extern int deu_dma_intr_handler(struct dma_device_info *, int);
++extern u8 *deu_dma_buffer_alloc(int, int *, void **);
++extern int deu_dma_buffer_free(u8 *, void *);
++extern void deu_dma_inactivate_poll(struct dma_device_info* dma_dev);
++extern void deu_dma_activate_poll(struct dma_device_info* dma_dev);
++extern struct dma_device_info* deu_dma_reserve(struct dma_device_info**
++ dma_device);
++extern int deu_dma_release(struct dma_device_info** dma_device);
++
++#endif /* IFMIPS_DEU_DMA_H */
+--- /dev/null
++++ b/drivers/crypto/lantiq/md5.c
+@@ -0,0 +1,285 @@
++/*
++ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com>
++ * Copyright (C) 2009 Mohammad Firdaus
++ */
++
++/**
++ \defgroup LQ_DEU LQ_DEU_DRIVERS
++ \ingroup API
++ \brief Lantiq DEU driver module
++*/
++
++/**
++ \file md5.c
++ \ingroup LQ_DEU
++ \brief MD5 encryption DEU driver file
++*/
++
++/**
++ \defgroup LQ_MD5_FUNCTIONS LQ_MD5_FUNCTIONS
++ \ingroup LQ_DEU
++ \brief Lantiq DEU MD5 functions
++*/
++
++#include <crypto/internal/hash.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/string.h>
++#include <linux/crypto.h>
++#include <linux/types.h>
++#include <asm/byteorder.h>
++#include "deu.h"
++
++#define MD5_DIGEST_SIZE 16
++#define MD5_HMAC_BLOCK_SIZE 64
++#define MD5_BLOCK_WORDS 16
++#define MD5_HASH_WORDS 4
++
++static spinlock_t cipher_lock;
++
++struct md5_ctx {
++ u32 hash[MD5_HASH_WORDS];
++ u32 block[MD5_BLOCK_WORDS];
++ u64 byte_count;
++};
++
++/** \fn static u32 md5_endian_swap(u32 input)
++ * \ingroup LQ_MD5_FUNCTIONS
++ * \brief perform dword level endian swap
++ * \param input value of dword that requires to be swapped
++*/
++static u32 md5_endian_swap(u32 input)
++{
++ u8 *ptr = (u8 *)&input;
++
++ return ((ptr[3] << 24) | (ptr[2] << 16) | (ptr[1] << 8) | ptr[0]);
++}
++
++/** \fn static void md5_transform(u32 *hash, u32 const *in)
++ * \ingroup LQ_MD5_FUNCTIONS
++ * \brief main interface to md5 hardware
++ * \param hash current hash value
++ * \param in 64-byte block of input
++*/
++static void md5_transform(u32 *hash, u32 const *in)
++{
++ int i;
++ volatile struct deu_hash *hashs = (struct deu_hash *) HASH_START;
++ ulong flag;
++
++ CRTCL_SECT_START;
++
++ for (i = 0; i < 16; i++) {
++ hashs->MR = md5_endian_swap(in[i]);
++ };
++
++ /* wait for processing */
++ while (hashs->ctrl.BSY) {
++ /* this will not take long */
++ }
++
++ CRTCL_SECT_END;
++}
++
++/** \fn static inline void md5_transform_helper(struct md5_ctx *ctx)
++ * \ingroup LQ_MD5_FUNCTIONS
++ * \brief interfacing function for md5_transform()
++ * \param ctx crypto context
++*/
++static inline void md5_transform_helper(struct md5_ctx *ctx)
++{
++ /* le32_to_cpu_array(ctx->block, sizeof(ctx->block) / sizeof(u32)); */
++ md5_transform(ctx->hash, ctx->block);
++}
++
++/** \fn static void md5_init(struct crypto_tfm *tfm)
++ * \ingroup LQ_MD5_FUNCTIONS
++ * \brief initialize md5 hardware
++ * \param tfm linux crypto algo transform
++*/
++static int md5_init(struct shash_desc *desc)
++{
++ struct md5_ctx *mctx = shash_desc_ctx(desc);
++ volatile struct deu_hash *hash = (struct deu_hash *) HASH_START;
++
++ hash->ctrl.SM = 1;
++ hash->ctrl.ALGO = 1; /* 1 = md5 0 = sha1 */
++ hash->ctrl.INIT = 1; /* Initialize the hash operation by writing
++ a '1' to the INIT bit. */
++
++ mctx->byte_count = 0;
++
++ return 0;
++}
++
++/** \fn static void md5_update(struct crypto_tfm *tfm, const u8 *data, unsigned int len)
++ * \ingroup LQ_MD5_FUNCTIONS
++ * \brief on-the-fly md5 computation
++ * \param tfm linux crypto algo transform
++ * \param data input data
++ * \param len size of input data
++*/
++static int md5_update(struct shash_desc *desc, const u8 *data, unsigned int len)
++{
++ struct md5_ctx *mctx = shash_desc_ctx(desc);
++ const u32 avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f);
++
++ mctx->byte_count += len;
++
++ if (avail > len) {
++ memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
++ data, len);
++ return 0;
++ }
++
++ memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
++ data, avail);
++
++ md5_transform_helper(mctx);
++ data += avail;
++ len -= avail;
++
++ while (len >= sizeof(mctx->block)) {
++ memcpy(mctx->block, data, sizeof(mctx->block));
++ md5_transform_helper(mctx);
++ data += sizeof(mctx->block);
++ len -= sizeof(mctx->block);
++ }
++
++ memcpy(mctx->block, data, len);
++
++ return 0;
++}
++
++/** \fn static void md5_final(struct crypto_tfm *tfm, u8 *out)
++ * \ingroup LQ_MD5_FUNCTIONS
++ * \brief compute final md5 value
++ * \param tfm linux crypto algo transform
++ * \param out final md5 output value
++*/
++static int md5_final(struct shash_desc *desc, u8 *out)
++{
++ struct 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);
++ volatile struct deu_hash *hashs = (struct deu_hash *) HASH_START;
++ unsigned long flag;
++
++ *p++ = 0x80;
++ if (padding < 0) {
++ memset(p, 0x00, padding + sizeof (u64));
++ md5_transform_helper(mctx);
++ p = (char *)mctx->block;
++ padding = 56;
++ }
++
++ memset(p, 0, padding);
++ mctx->block[14] = md5_endian_swap(mctx->byte_count << 3);
++ mctx->block[15] = md5_endian_swap(mctx->byte_count >> 29);
++
++#if 0
++ le32_to_cpu_array(mctx->block, (sizeof(mctx->block) -
++ sizeof(u64)) / sizeof(u32));
++#endif
++
++ md5_transform(mctx->hash, mctx->block);
++
++ CRTCL_SECT_START;
++
++ *((u32 *) out + 0) = md5_endian_swap(hashs->D1R);
++ *((u32 *) out + 1) = md5_endian_swap(hashs->D2R);
++ *((u32 *) out + 2) = md5_endian_swap(hashs->D3R);
++ *((u32 *) out + 3) = md5_endian_swap(hashs->D4R);
++
++ CRTCL_SECT_END;
++
++ /* Wipe context */
++ memset(mctx, 0, sizeof(*mctx));
++
++ return 0;
++}
++
++static int md5_export(struct shash_desc *desc, void *out)
++{
++ struct md5_ctx *sctx = shash_desc_ctx(desc);
++
++ memcpy(out, sctx, sizeof(*sctx));
++ return 0;
++}
++
++static int md5_import(struct shash_desc *desc, const void *in)
++{
++ struct md5_ctx *sctx = shash_desc_ctx(desc);
++
++ memcpy(sctx, in, sizeof(*sctx));
++ return 0;
++}
++
++/*
++ * \brief MD5 function mappings
++*/
++static struct shash_alg md5_alg = {
++ .digestsize = MD5_DIGEST_SIZE,
++ .init = md5_init,
++ .update = md5_update,
++ .final = md5_final,
++ .export = md5_export,
++ .import = md5_import,
++ .descsize = sizeof(struct md5_ctx),
++ .statesize = sizeof(struct md5_ctx),
++ .base = {
++ .cra_name = "md5",
++ .cra_driver_name = "lq_deu-md5",
++ .cra_flags = CRYPTO_ALG_TYPE_SHASH,
++ .cra_blocksize = MD5_HMAC_BLOCK_SIZE,
++ .cra_module = THIS_MODULE,
++ }
++};
++
++/** \fn int lq_deu_init_md5(void)
++ * \ingroup LQ_MD5_FUNCTIONS
++ * \brief initialize md5 driver
++*/
++int lq_deu_init_md5(void)
++{
++ int ret;
++
++ if ((ret = crypto_register_shash(&md5_alg)))
++ goto md5_err;
++
++ CRTCL_SECT_INIT;
++
++ printk(KERN_NOTICE "Lantiq DEU MD5 initialized%s.\n",
++ disable_deudma ? "" : " (DMA)");
++ return ret;
++
++md5_err:
++ printk(KERN_ERR "Lantiq DEU MD5 initialization failed!\n");
++ return ret;
++}
++
++/** \fn void lq_deu_fini_md5(void)
++ * \ingroup LQ_MD5_FUNCTIONS
++ * \brief unregister md5 driver
++*/
++
++void lq_deu_fini_md5(void)
++{
++ crypto_unregister_shash(&md5_alg);
++}
++
+--- /dev/null
++++ b/drivers/crypto/lantiq/md5_hmac.c
+@@ -0,0 +1,329 @@
++/*
++ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com>
++ * Copyright (C) 2009 Mohammad Firdaus
++ */
++
++/**
++ \defgroup LQ_DEU LQ_DEU_DRIVERS
++ \ingroup API
++ \brief Lantiq DEU driver module
++*/
++
++/**
++ \file md5_hmac.c
++ \ingroup LQ_DEU
++ \brief MD5-HMAC encryption DEU driver file
++*/
++
++/**
++ \defgroup LQ_MD5_HMAC_FUNCTIONS LQ_MD5_HMAC_FUNCTIONS
++ \ingroup LQ_DEU
++ \brief Lantiq md5-hmac driver functions
++*/
++
++#include <crypto/internal/hash.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/string.h>
++#include <linux/crypto.h>
++#include <linux/types.h>
++#include <asm/byteorder.h>
++#include "deu.h"
++
++#define MD5_DIGEST_SIZE 16
++#define MD5_HMAC_BLOCK_SIZE 64
++#define MD5_BLOCK_WORDS 16
++#define MD5_HASH_WORDS 4
++#define MD5_HMAC_DBN_TEMP_SIZE 1024 /* size in dword,
++ needed for dbn workaround */
++
++static spinlock_t cipher_lock;
++
++struct md5_hmac_ctx {
++ u32 hash[MD5_HASH_WORDS];
++ u32 block[MD5_BLOCK_WORDS];
++ u64 byte_count;
++ u32 dbn;
++ u32 temp[MD5_HMAC_DBN_TEMP_SIZE];
++};
++
++/** \fn static u32 md5_endian_swap(u32 input)
++ * \ingroup LQ_MD5_HMAC_FUNCTIONS
++ * \brief perform dword level endian swap
++ * \param input value of dword that requires to be swapped
++*/
++static u32 md5_endian_swap(u32 input)
++{
++ u8 *ptr = (u8 *)&input;
++
++ return ((ptr[3] << 24) | (ptr[2] << 16) | (ptr[1] << 8) | ptr[0]);
++}
++
++/** \fn static void md5_hmac_transform(struct crypto_tfm *tfm, u32 const *in)
++ * \ingroup LQ_MD5_HMAC_FUNCTIONS
++ * \brief save input block to context
++ * \param tfm linux crypto algo transform
++ * \param in 64-byte block of input
++*/
++static void md5_hmac_transform(struct shash_desc *desc, u32 const *in)
++{
++ struct md5_hmac_ctx *mctx = shash_desc_ctx(desc);
++
++ memcpy(&mctx->temp[mctx->dbn<<4], in, 64); /* dbn workaround */
++ mctx->dbn += 1;
++
++ if ( (mctx->dbn<<4) > MD5_HMAC_DBN_TEMP_SIZE )
++ {
++ printk("MD5_HMAC_DBN_TEMP_SIZE exceeded\n");
++ }
++}
++
++/** \fn int md5_hmac_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen)
++ * \ingroup LQ_MD5_HMAC_FUNCTIONS
++ * \brief sets md5 hmac key
++ * \param tfm linux crypto algo transform
++ * \param key input key
++ * \param keylen key length greater than 64 bytes IS NOT SUPPORTED
++*/
++static int md5_hmac_setkey(struct crypto_shash *tfm,
++ const u8 *key,
++ unsigned int keylen)
++{
++ volatile struct deu_hash *hash = (struct deu_hash *) HASH_START;
++ int i, j;
++ u32 *in_key = (u32 *)key;
++
++ hash->KIDX = 0x80000000; /* reset all 16 words of the key to '0' */
++ asm("sync");
++
++ j = 0;
++ for (i = 0; i < keylen; i+=4)
++ {
++ hash->KIDX = j;
++ asm("sync");
++ hash->KEY = *((u32 *) in_key + j);
++ j++;
++ }
++
++ return 0;
++}
++
++/** \fn void md5_hmac_init(struct crypto_tfm *tfm)
++ * \ingroup LQ_MD5_HMAC_FUNCTIONS
++ * \brief initialize md5 hmac context
++ * \param tfm linux crypto algo transform
++*/
++static int md5_hmac_init(struct shash_desc *desc)
++{
++ struct md5_hmac_ctx *mctx = shash_desc_ctx(desc);
++
++ memset(mctx, 0, sizeof(struct md5_hmac_ctx));
++ mctx->dbn = 0; /* dbn workaround */
++ return 0;
++}
++
++/** \fn void md5_hmac_update(struct crypto_tfm *tfm, const u8 *data, unsigned int len)
++ * \ingroup LQ_MD5_HMAC_FUNCTIONS
++ * \brief on-the-fly md5 hmac computation
++ * \param tfm linux crypto algo transform
++ * \param data input data
++ * \param len size of input data
++*/
++static int md5_hmac_update(struct shash_desc *desc,
++ const u8 *data,
++ unsigned int len)
++{
++ struct md5_hmac_ctx *mctx = shash_desc_ctx(desc);
++ const u32 avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f);
++
++ mctx->byte_count += len;
++
++ if (avail > len) {
++ memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
++ data, len);
++ return 0;
++ }
++
++ memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
++ data, avail);
++
++ md5_hmac_transform(desc, mctx->block);
++ data += avail;
++ len -= avail;
++
++ while (len >= sizeof(mctx->block)) {
++ memcpy(mctx->block, data, sizeof(mctx->block));
++ md5_hmac_transform(desc, mctx->block);
++ data += sizeof(mctx->block);
++ len -= sizeof(mctx->block);
++ }
++
++ memcpy(mctx->block, data, len);
++
++ return 0;
++}
++
++/** \fn void md5_hmac_final(struct crypto_tfm *tfm, u8 *out)
++ * \ingroup LQ_MD5_HMAC_FUNCTIONS
++ * \brief compute final md5 hmac value
++ * \param tfm linux crypto algo transform
++ * \param out final md5 hmac output value
++*/
++static int md5_hmac_final(struct shash_desc *desc, u8 *out)
++{
++ struct md5_hmac_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);
++ volatile struct deu_hash *hashs = (struct deu_hash *) HASH_START;
++ u32 flag;
++ int i = 0;
++ int dbn;
++ u32 *in = &mctx->temp[0];
++
++ *p++ = 0x80;
++ if (padding < 0) {
++ memset(p, 0x00, padding + sizeof (u64));
++ md5_hmac_transform(desc, mctx->block);
++ p = (char *)mctx->block;
++ padding = 56;
++ }
++
++ memset(p, 0, padding);
++ /* need to add 512 bit of the IPAD operation */
++ mctx->block[14] = md5_endian_swap((mctx->byte_count + 64) << 3);
++ mctx->block[15] = 0x00000000;
++
++ md5_hmac_transform(desc, mctx->block);
++
++ CRTCL_SECT_START;
++
++ printk("dbn = %d\n", mctx->dbn);
++ hashs->DBN = mctx->dbn;
++
++ /* khs, go, init, ndc, endi, kyue, hmen, md5 */
++ *LQ_HASH_CON = 0x0703002D;
++
++ /* wait for processing */
++ while (hashs->ctrl.BSY) {
++ /* this will not take long */
++ }
++
++ for (dbn = 0; dbn < mctx->dbn; dbn++)
++ {
++ for (i = 0; i < 16; i++) {
++ hashs->MR = in[i];
++ };
++
++ hashs->ctrl.GO = 1;
++ asm("sync");
++
++ /* wait for processing */
++ while (hashs->ctrl.BSY) {
++ /* this will not take long */
++ }
++
++ in += 16;
++ }
++
++#if 1
++ /* wait for digest ready */
++ while (! hashs->ctrl.DGRY) {
++ /* this will not take long */
++ }
++#endif
++
++ *((u32 *) out + 0) = hashs->D1R;
++ *((u32 *) out + 1) = hashs->D2R;
++ *((u32 *) out + 2) = hashs->D3R;
++ *((u32 *) out + 3) = hashs->D4R;
++ *((u32 *) out + 4) = hashs->D5R;
++
++ CRTCL_SECT_END;
++
++ return 0;
++}
++
++static int md5_hmac_export(struct shash_desc *desc, void *out)
++{
++ struct md5_hmac_ctx *sctx = shash_desc_ctx(desc);
++
++ memcpy(out, sctx, sizeof(*sctx));
++ return 0;
++}
++
++static int md5_hmac_import(struct shash_desc *desc, const void *in)
++{
++ struct md5_hmac_ctx *sctx = shash_desc_ctx(desc);
++
++ memcpy(sctx, in, sizeof(*sctx));
++ return 0;
++}
++
++/*
++ * \brief MD5_HMAC function mappings
++*/
++static struct shash_alg md5_hmac_alg = {
++ .digestsize = MD5_DIGEST_SIZE,
++ .init = md5_hmac_init,
++ .update = md5_hmac_update,
++ .final = md5_hmac_final,
++ .setkey = md5_hmac_setkey,
++ .export = md5_hmac_export,
++ .import = md5_hmac_import,
++ .descsize = sizeof(struct md5_hmac_ctx),
++ .statesize = sizeof(struct md5_hmac_ctx),
++ .base = {
++ .cra_name = "hmac(md5)",
++ .cra_driver_name = "lq_deu-md5_hmac",
++ .cra_flags = CRYPTO_ALG_TYPE_SHASH,
++ .cra_blocksize = MD5_HMAC_BLOCK_SIZE,
++ .cra_module = THIS_MODULE,
++ }
++};
++
++/** \fn int lq_deu_init_md5_hmac(void)
++ * \ingroup LQ_MD5_HMAC_FUNCTIONS
++ * \brief initialize md5 hmac driver
++*/
++int lq_deu_init_md5_hmac(void)
++{
++ int ret;
++
++ if ((ret = crypto_register_shash(&md5_hmac_alg)))
++ goto md5_hmac_err;
++
++ CRTCL_SECT_INIT;
++
++ printk(KERN_NOTICE "Lantiq DEU MD5_HMAC initialized%s.\n",
++ disable_deudma ? "" : " (DMA)");
++ return ret;
++
++md5_hmac_err:
++ printk(KERN_ERR "Lantiq DEU MD5_HMAC initialization failed!\n");
++ return ret;
++}
++
++/** \fn void lq_deu_fini_md5_hmac(void)
++ * \ingroup LQ_MD5_HMAC_FUNCTIONS
++ * \brief unregister md5 hmac driver
++*/
++void lq_deu_fini_md5_hmac(void)
++{
++ crypto_unregister_shash(&md5_hmac_alg);
++}
++
+--- /dev/null
++++ b/drivers/crypto/lantiq/sha1.c
+@@ -0,0 +1,262 @@
++/*
++ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com>
++ * Copyright (C) 2009 Mohammad Firdaus
++ */
++
++/**
++ \defgroup LQ_DEU LQ_DEU_DRIVERS
++ \ingroup API
++ \brief Lantiq DEU driver module
++*/
++
++/**
++ \file sha1.c
++ \ingroup LQ_DEU
++ \brief SHA1 encryption DEU driver file
++*/
++
++/**
++ \defgroup LQ_SHA1_FUNCTIONS LQ_SHA1_FUNCTIONS
++ \ingroup LQ_DEU
++ \brief Lantiq DEU sha1 functions
++*/
++
++
++#include <crypto/internal/hash.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/mm.h>
++#include <linux/crypto.h>
++#include <linux/cryptohash.h>
++#include <crypto/sha.h>
++#include <linux/types.h>
++#include <asm/scatterlist.h>
++#include <asm/byteorder.h>
++#include "deu.h"
++
++#define SHA1_DIGEST_SIZE 20
++#define SHA1_HMAC_BLOCK_SIZE 64
++
++static spinlock_t cipher_lock;
++
++/*
++ * \brief SHA1 private structure
++*/
++struct sha1_ctx {
++ u64 count;
++ u32 state[5];
++ u8 buffer[64];
++};
++
++/** \fn static void sha1_transform(u32 *state, const u32 *in)
++ * \ingroup LQ_SHA1_FUNCTIONS
++ * \brief main interface to sha1 hardware
++ * \param state current state
++ * \param in 64-byte block of input
++*/
++static void sha1_transform(u32 *state, const u32 *in)
++{
++ int i = 0;
++ volatile struct deu_hash *hashs = (struct deu_hash *) HASH_START;
++ unsigned long flag;
++
++ CRTCL_SECT_START;
++
++ for (i = 0; i < 16; i++) {
++ hashs->MR = in[i];
++ };
++
++ /* wait for processing */
++ while (hashs->ctrl.BSY) {
++ /* this will not take long */
++ }
++
++ CRTCL_SECT_END;
++}
++
++/** \fn static void sha1_init(struct crypto_tfm *tfm)
++ * \ingroup LQ_SHA1_FUNCTIONS
++ * \brief initialize sha1 hardware
++ * \param tfm linux crypto algo transform
++*/
++static int sha1_init(struct shash_desc *desc)
++{
++ struct sha1_ctx *sctx = shash_desc_ctx(desc);
++
++ SHA_HASH_INIT;
++
++ sctx->count = 0;
++
++ return 0;
++}
++
++/** \fn static void sha1_update(struct crypto_tfm *tfm, const u8 *data, unsigned int len)
++ * \ingroup LQ_SHA1_FUNCTIONS
++ * \brief on-the-fly sha1 computation
++ * \param tfm linux crypto algo transform
++ * \param data input data
++ * \param len size of input data
++*/
++static int sha1_update(struct shash_desc *desc, const u8 *data, unsigned int len)
++{
++ struct sha1_ctx *sctx = shash_desc_ctx(desc);
++ unsigned int i, j;
++
++ j = (sctx->count >> 3) & 0x3f;
++ sctx->count += len << 3;
++
++ if ((j + len) > 63) {
++ memcpy(&sctx->buffer[j], data, (i = 64 - j));
++ sha1_transform(sctx->state, (const u32 *)sctx->buffer);
++ for (; i + 63 < len; i += 64) {
++ sha1_transform(sctx->state, (const u32 *)&data[i]);
++ }
++
++ j = 0;
++ } else {
++ i = 0;
++ }
++
++ memcpy(&sctx->buffer[j], &data[i], len - i);
++
++ return 0;
++}
++
++/** \fn static void sha1_final(struct crypto_tfm *tfm, u8 *out)
++ * \ingroup LQ_SHA1_FUNCTIONS
++ * \brief compute final sha1 value
++ * \param tfm linux crypto algo transform
++ * \param out final md5 output value
++*/
++static int sha1_final(struct shash_desc *desc, u8 *out)
++{
++ struct sha1_ctx *sctx = shash_desc_ctx(desc);
++ u32 index, padlen;
++ u64 t;
++ u8 bits[8] = { 0, };
++ static const u8 padding[64] = { 0x80, };
++ volatile struct deu_hash *hashs = (struct deu_hash *) HASH_START;
++ ulong flag;
++
++ t = sctx->count;
++ bits[7] = 0xff & t;
++ t >>= 8;
++ bits[6] = 0xff & t;
++ t >>= 8;
++ bits[5] = 0xff & t;
++ t >>= 8;
++ bits[4] = 0xff & t;
++ t >>= 8;
++ bits[3] = 0xff & t;
++ t >>= 8;
++ bits[2] = 0xff & t;
++ t >>= 8;
++ bits[1] = 0xff & t;
++ t >>= 8;
++ bits[0] = 0xff & t;
++
++ /* Pad out to 56 mod 64 */
++ index = (sctx->count >> 3) & 0x3f;
++ padlen = (index < 56) ? (56 - index) : ((64 + 56) - index);
++ sha1_update(desc, padding, padlen);
++
++ /* Append length */
++ sha1_update(desc, bits, sizeof bits);
++
++ CRTCL_SECT_START;
++
++ *((u32 *) out + 0) = hashs->D1R;
++ *((u32 *) out + 1) = hashs->D2R;
++ *((u32 *) out + 2) = hashs->D3R;
++ *((u32 *) out + 3) = hashs->D4R;
++ *((u32 *) out + 4) = hashs->D5R;
++
++ CRTCL_SECT_END;
++
++ /* Wipe context*/
++ memset(sctx, 0, sizeof *sctx);
++
++ return 0;
++}
++
++static int sha1_export(struct shash_desc *desc, void *out)
++{
++ struct sha1_ctx *sctx = shash_desc_ctx(desc);
++
++ memcpy(out, sctx, sizeof(*sctx));
++ return 0;
++}
++
++static int sha1_import(struct shash_desc *desc, const void *in)
++{
++ struct sha1_ctx *sctx = shash_desc_ctx(desc);
++
++ memcpy(sctx, in, sizeof(*sctx));
++ return 0;
++}
++
++/*
++ * \brief SHA1 function mappings
++*/
++static struct shash_alg deu_sha1_alg = {
++ .digestsize = SHA1_DIGEST_SIZE,
++ .init = sha1_init,
++ .update = sha1_update,
++ .final = sha1_final,
++ .export = sha1_export,
++ .import = sha1_import,
++ .descsize = sizeof(struct sha1_ctx),
++ .statesize = sizeof(struct sha1_ctx),
++ .base = {
++ .cra_name = "sha1",
++ .cra_driver_name = "lq_deu-sha1",
++ .cra_flags = CRYPTO_ALG_TYPE_SHASH,
++ .cra_blocksize = SHA1_HMAC_BLOCK_SIZE,
++ .cra_module = THIS_MODULE,
++ }
++};
++
++/** \fn int lq_deu_init_sha1(void)
++ * \ingroup LQ_SHA1_FUNCTIONS
++ * \brief initialize sha1 driver
++*/
++int lq_deu_init_sha1(void)
++{
++ int ret;
++
++ if ((ret = crypto_register_shash(&deu_sha1_alg)))
++ goto sha1_err;
++
++ CRTCL_SECT_INIT;
++
++ printk(KERN_NOTICE "Lantiq DEU SHA1 initialized%s.\n",
++ disable_deudma ? "" : " (DMA)");
++ return ret;
++
++sha1_err:
++ printk(KERN_ERR "Lantiq DEU SHA1 initialization failed!\n");
++ return ret;
++}
++
++/** \fn void lq_deu_fini_sha1(void)
++ * \ingroup LQ_SHA1_FUNCTIONS
++ * \brief unregister sha1 driver
++*/
++void lq_deu_fini_sha1(void)
++{
++ crypto_unregister_shash(&deu_sha1_alg);
++}
+--- /dev/null
++++ b/drivers/crypto/lantiq/sha1_hmac.c
+@@ -0,0 +1,325 @@
++/*
++ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com>
++ * Copyright (C) 2009 Mohammad Firdaus
++ */
++
++/**
++ \defgroup LQ_DEU LQ_DEU_DRIVERS
++ \ingroup API
++ \brief Lantiq DEU driver module
++*/
++
++/**
++ \file sha1_hmac.c
++ \ingroup LQ_DEU
++ \brief SHA1-HMAC DEU driver file
++*/
++
++/**
++ \defgroup LQ_SHA1_HMAC_FUNCTIONS LQ_SHA1_HMAC_FUNCTIONS
++ \ingroup LQ_DEU
++ \brief Lantiq sha1 hmac functions
++*/
++
++
++#include <crypto/internal/hash.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/mm.h>
++#include <linux/crypto.h>
++#include <linux/cryptohash.h>
++#include <linux/types.h>
++#include <asm/scatterlist.h>
++#include <asm/byteorder.h>
++#include <linux/delay.h>
++#include "deu.h"
++
++#ifdef CONFIG_CRYPTO_DEV_LANTIQ_SHA1_HMAC
++
++#define SHA1_DIGEST_SIZE 20
++#define SHA1_HMAC_BLOCK_SIZE 64
++/* size in dword, needed for dbn workaround */
++#define SHA1_HMAC_DBN_TEMP_SIZE 1024
++
++static spinlock_t cipher_lock;
++
++struct sha1_hmac_ctx {
++ u64 count;
++ u32 state[5];
++ u8 buffer[64];
++ u32 dbn;
++ u32 temp[SHA1_HMAC_DBN_TEMP_SIZE];
++};
++
++/** \fn static void sha1_hmac_transform(struct crypto_tfm *tfm, u32 const *in)
++ * \ingroup LQ_SHA1_HMAC_FUNCTIONS
++ * \brief save input block to context
++ * \param tfm linux crypto algo transform
++ * \param in 64-byte block of input
++*/
++static void sha1_hmac_transform(struct shash_desc *desc, u32 const *in)
++{
++ struct sha1_hmac_ctx *sctx = shash_desc_ctx(desc);
++
++ memcpy(&sctx->temp[sctx->dbn<<4], in, 64); /* dbn workaround */
++ sctx->dbn += 1;
++
++ if ((sctx->dbn<<4) > SHA1_HMAC_DBN_TEMP_SIZE) {
++ printk("SHA1_HMAC_DBN_TEMP_SIZE exceeded\n");
++ }
++}
++
++/** \fn int sha1_hmac_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen)
++ * \ingroup LQ_SHA1_HMAC_FUNCTIONS
++ * \brief sets sha1 hmac key
++ * \param tfm linux crypto algo transform
++ * \param key input key
++ * \param keylen key length greater than 64 bytes IS NOT SUPPORTED
++*/
++static int sha1_hmac_setkey(struct crypto_shash *tfm,
++ const u8 *key,
++ unsigned int keylen)
++{
++ volatile struct deu_hash *hash = (struct deu_hash *) HASH_START;
++ int i, j;
++ u32 *in_key = (u32 *)key;
++
++ hash->KIDX = 0x80000000; /* reset all 16 words of the key to '0' */
++ asm("sync");
++
++ j = 0;
++ for (i = 0; i < keylen; i+=4)
++ {
++ hash->KIDX = j;
++ asm("sync");
++ hash->KEY = *((u32 *) in_key + j);
++ j++;
++ }
++
++ return 0;
++}
++
++static int sha1_hmac_export(struct shash_desc *desc, void *out)
++{
++ struct sha1_hmac_ctx *sctx = shash_desc_ctx(desc);
++
++ memcpy(out, sctx, sizeof(*sctx));
++ return 0;
++}
++
++static int sha1_hmac_import(struct shash_desc *desc, const void *in)
++{
++ struct sha1_hmac_ctx *sctx = shash_desc_ctx(desc);
++
++ memcpy(sctx, in, sizeof(*sctx));
++ return 0;
++}
++
++/** \fn void sha1_hmac_init(struct crypto_tfm *tfm)
++ * \ingroup LQ_SHA1_HMAC_FUNCTIONS
++ * \brief initialize sha1 hmac context
++ * \param tfm linux crypto algo transform
++*/
++static int sha1_hmac_init(struct shash_desc *desc)
++{
++ struct sha1_hmac_ctx *sctx = shash_desc_ctx(desc);
++
++ memset(sctx, 0, sizeof(struct sha1_hmac_ctx));
++ sctx->dbn = 0; /* dbn workaround */
++
++ return 0;
++}
++
++/** \fn static void sha1_hmac_update(struct crypto_tfm *tfm, const u8 *data, unsigned int len)
++ * \ingroup LQ_SHA1_HMAC_FUNCTIONS
++ * \brief on-the-fly sha1 hmac computation
++ * \param tfm linux crypto algo transform
++ * \param data input data
++ * \param len size of input data
++*/
++static int sha1_hmac_update(struct shash_desc *desc, const u8 *data,
++ unsigned int len)
++{
++ struct sha1_hmac_ctx *sctx = shash_desc_ctx(desc);
++ unsigned int i, j;
++
++ j = (sctx->count >> 3) & 0x3f;
++ sctx->count += len << 3;
++ /* printk("sctx->count = %d\n", (sctx->count >> 3)); */
++
++ if ((j + len) > 63) {
++ memcpy(&sctx->buffer[j], data, (i = 64 - j));
++ sha1_hmac_transform(desc, (const u32 *)sctx->buffer);
++ for (; i + 63 < len; i += 64) {
++ sha1_hmac_transform(desc, (const u32 *)&data[i]);
++ }
++
++ j = 0;
++ } else {
++ i = 0;
++ }
++
++ memcpy(&sctx->buffer[j], &data[i], len - i);
++
++ return 0;
++}
++
++/** \fn static void sha1_hmac_final(struct crypto_tfm *tfm, u8 *out)
++ * \ingroup LQ_SHA1_HMAC_FUNCTIONS
++ * \brief ompute final sha1 hmac value
++ * \param tfm linux crypto algo transform
++ * \param out final sha1 hmac output value
++*/
++static int sha1_hmac_final(struct shash_desc *desc, u8 *out)
++{
++ struct sha1_hmac_ctx *sctx = shash_desc_ctx(desc);
++ u32 index, padlen;
++ u64 t;
++ u8 bits[8] = { 0, };
++ static const u8 padding[64] = { 0x80, };
++ volatile struct deu_hash *hashs = (struct deu_hash *) HASH_START;
++ ulong flag;
++ int i = 0;
++ int dbn;
++ u32 *in = &sctx->temp[0];
++
++ t = sctx->count + 512; /* need to add 512 bit of the IPAD operation */
++ bits[7] = 0xff & t;
++ t >>= 8;
++ bits[6] = 0xff & t;
++ t >>= 8;
++ bits[5] = 0xff & t;
++ t >>= 8;
++ bits[4] = 0xff & t;
++ t >>= 8;
++ bits[3] = 0xff & t;
++ t >>= 8;
++ bits[2] = 0xff & t;
++ t >>= 8;
++ bits[1] = 0xff & t;
++ t >>= 8;
++ bits[0] = 0xff & t;
++
++ /* Pad out to 56 mod 64 */
++ index = (sctx->count >> 3) & 0x3f;
++ padlen = (index < 56) ? (56 - index) : ((64 + 56) - index);
++ sha1_hmac_update(desc, padding, padlen);
++
++ /* Append length */
++ sha1_hmac_update(desc, bits, sizeof bits);
++
++ CRTCL_SECT_START;
++
++ hashs->DBN = sctx->dbn;
++
++ /* for vr9 change, ENDI = 1 */
++ *LQ_HASH_CON = HASH_CON_VALUE;
++
++ /* wait for processing */
++ while (hashs->ctrl.BSY) {
++ /* this will not take long */
++ }
++
++ for (dbn = 0; dbn < sctx->dbn; dbn++)
++ {
++ for (i = 0; i < 16; i++) {
++ hashs->MR = in[i];
++ };
++
++ hashs->ctrl.GO = 1;
++ asm("sync");
++
++ /* wait for processing */
++ while (hashs->ctrl.BSY) {
++ /* this will not take long */
++ }
++
++ in += 16;
++
++ return 0;
++ }
++
++#if 1
++ /* wait for digest ready */
++ while (! hashs->ctrl.DGRY) {
++ /* this will not take long */
++ }
++#endif
++
++ *((u32 *) out + 0) = hashs->D1R;
++ *((u32 *) out + 1) = hashs->D2R;
++ *((u32 *) out + 2) = hashs->D3R;
++ *((u32 *) out + 3) = hashs->D4R;
++ *((u32 *) out + 4) = hashs->D5R;
++
++ CRTCL_SECT_END;
++}
++
++/*
++ * \brief SHA1-HMAC function mappings
++*/
++static struct shash_alg sha1_hmac_alg = {
++ .digestsize = SHA1_DIGEST_SIZE,
++ .init = sha1_hmac_init,
++ .update = sha1_hmac_update,
++ .final = sha1_hmac_final,
++ .export = sha1_hmac_export,
++ .import = sha1_hmac_import,
++ .setkey = sha1_hmac_setkey,
++ .descsize = sizeof(struct sha1_hmac_ctx),
++ .statesize = sizeof(struct sha1_hmac_ctx),
++ .base = {
++ .cra_name = "hmac(sha1)",
++ .cra_driver_name = "lq_deu-sha1_hmac",
++ .cra_flags = CRYPTO_ALG_TYPE_SHASH,
++ .cra_blocksize = SHA1_HMAC_BLOCK_SIZE,
++ .cra_module = THIS_MODULE,
++ }
++};
++
++/** \fn int lq_deu_init_sha1_hmac(void)
++ * \ingroup LQ_SHA1_HMAC_FUNCTIONS
++ * \brief initialize sha1 hmac driver
++*/
++int lq_deu_init_sha1_hmac(void)
++{
++ int ret;
++
++ if ((ret = crypto_register_shash(&sha1_hmac_alg)))
++ goto sha1_err;
++
++ CRTCL_SECT_INIT;
++
++ printk(KERN_NOTICE "Lantiq DEU SHA1_HMAC initialized%s.\n",
++ disable_deudma ? "" : " (DMA)");
++ return ret;
++
++sha1_err:
++ printk(KERN_ERR "Lantiq DEU SHA1_HMAC initialization failed!\n");
++ return ret;
++}
++
++/** \fn void lq_deu_fini_sha1_hmac(void)
++ * \ingroup LQ_SHA1_HMAC_FUNCTIONS
++ * \brief unregister sha1 hmac driver
++*/
++void lq_deu_fini_sha1_hmac(void)
++{
++ crypto_unregister_shash(&sha1_hmac_alg);
++}
++
++#endif
+--- /dev/null
++++ b/drivers/crypto/lantiq/deu_falcon.c
+@@ -0,0 +1,163 @@
++/*
++ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com>
++ * Copyright (C) 2009 Mohammad Firdaus
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <asm/io.h> /* dma_cache_inv */
++#include <linux/platform_device.h>
++
++#ifdef CONFIG_SOC_LANTIQ_FALCON
++
++#include "deu.h"
++
++/**
++ \defgroup LQ_DEU LQ_DEU_DRIVERS
++ \ingroup API
++ \brief Lantiq DEU driver module
++*/
++
++/**
++ \file deu_falcon.c
++ \brief Lantiq DEU board specific driver file for ar9
++*/
++
++/**
++ \defgroup BOARD_SPECIFIC_FUNCTIONS LQ_BOARD_SPECIFIC_FUNCTIONS
++ \ingroup LQ_DEU
++ \brief board specific functions
++*/
++
++#include <falcon/gpon_reg_base.h>
++#include <falcon/sys1_reg.h>
++#include <falcon/status_reg.h>
++#include <falcon/sysctrl.h>
++
++#define reg_r32(reg) __raw_readl(reg)
++#define reg_w32(val, reg) __raw_writel(val, reg)
++#define reg_w32_mask(clear, set, reg) reg_w32((reg_r32(reg) & ~(clear)) | (set), reg)
++
++static gpon_sys1_t * const sys1 = (gpon_sys1_t *)GPON_SYS1_BASE;
++static gpon_status_t * const status = (gpon_status_t *)GPON_STATUS_BASE;
++
++/** \fn u32 endian_swap(u32 input)
++ * \ingroup BOARD_SPECIFIC_FUNCTIONS
++ * \brief Swap data given to the function
++ * \param input Data input to be swapped
++ * \return either the swapped data or the input data depending on whether it is in DMA mode or FPI mode
++*/
++static u32 endian_swap(u32 input)
++{
++ return input;
++}
++
++/** \fn u32 input_swap(u32 input)
++ * \ingroup BOARD_SPECIFIC_FUNCTIONS
++ * \brief Not used
++ * \return input
++*/
++static u32 input_swap(u32 input)
++{
++ return input;
++}
++
++/** \fn void aes_chip_init(void)
++ * \ingroup BOARD_SPECIFIC_FUNCTIONS
++ * \brief initialize AES hardware
++*/
++static void aes_chip_init(void)
++{
++ volatile struct deu_aes *aes = (struct deu_aes *) AES_START;
++
++ aes->ctrl.SM = 1;
++ aes->ctrl.ARS = 1;
++}
++
++/** \fn void des_chip_init(void)
++ * \ingroup BOARD_SPECIFIC_FUNCTIONS
++ * \brief initialize DES hardware
++*/
++static void des_chip_init(void)
++{
++}
++
++static u32 chip_init(void)
++{
++ sys1_hw_clk_enable(CLKEN_SHA1_SET | CLKEN_AES_SET);
++ sys1_hw_activate(ACT_SHA1_SET | ACT_AES_SET);
++
++ return LQ_DEU_ID_AES | LQ_DEU_ID_HASH;
++}
++
++static int lq_crypto_probe(struct platform_device *pdev)
++{
++#ifdef CONFIG_CRYPTO_DEV_LANTIQ_DMA
++ lq_crypto_ops.dma_init = NULL;
++ lq_crypto_ops.dma_exit = NULL;
++ lq_crypto_ops.aes_dma_memcpy = NULL;
++ lq_crypto_ops.des_dma_memcpy = NULL;
++ lq_crypto_ops.aes_dma_malloc = NULL;
++ lq_crypto_ops.des_dma_malloc = NULL;
++ lq_crypto_ops.dma_align = NULL;
++ lq_crypto_ops.dma_free = NULL;
++#endif
++
++ lq_crypto_ops.endian_swap = endian_swap;
++ lq_crypto_ops.input_swap = input_swap;
++ lq_crypto_ops.aes_chip_init = aes_chip_init;
++ lq_crypto_ops.des_chip_init = des_chip_init;
++ lq_crypto_ops.chip_init = chip_init;
++
++ printk("lq_falcon_deu: driver loaded!\n");
++
++ lq_deu_init();
++
++ return 0;
++}
++
++static int lq_crypto_remove(struct platform_device *pdev)
++{
++ lq_deu_exit();
++
++ return 0;
++}
++
++static struct platform_driver lq_crypto = {
++ .probe = lq_crypto_probe,
++ .remove = lq_crypto_remove,
++ .driver = {
++ .owner = THIS_MODULE,
++ .name = "lq_falcon_deu"
++ }
++};
++
++static int __init lq_crypto_init(void)
++{
++ return platform_driver_register(&lq_crypto);
++}
++module_init(lq_crypto_init);
++
++static void __exit lq_crypto_exit(void)
++{
++ platform_driver_unregister(&lq_crypto);
++}
++module_exit(lq_crypto_exit);
++
++#endif
+--- /dev/null
++++ b/drivers/crypto/lantiq/deu_falcon.h
+@@ -0,0 +1,281 @@
++/*
++ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com>
++ * Copyright (C) 2009 Mohammad Firdaus / Infineon Technologies
++ */
++
++/**
++ \defgroup LQ_DEU LQ_DEU_DRIVERS
++ \ingroup API
++ \brief DEU driver module
++*/
++
++/**
++ \defgroup LQ_DEU_DEFINITIONS LQ_DEU_DEFINITIONS
++ \ingroup LQ_DEU
++ \brief Lantiq DEU definitions
++*/
++
++/**
++ \file deu_falcon.h
++ \brief DEU driver header file
++*/
++
++
++#ifndef DEU_FALCON_H
++#define DEU_FALCON_H
++
++#define HASH_START 0xbd008100
++#define AES_START 0xbd008000
++
++#ifdef CONFIG_CRYPTO_DEV_DMA
++# include "deu_dma.h"
++# define DEU_DWORD_REORDERING(ptr, buffer, in_out, bytes) \
++ deu_dma_align(ptr, buffer, in_out, bytes)
++# define AES_MEMORY_COPY(outcopy, out_dma, out_arg, nbytes) \
++ deu_aes_dma_memcpy(outcopy, out_dma, out_arg, nbytes)
++# define DES_MEMORY_COPY(outcopy, out_dma, out_arg, nbytes) \
++ deu_des_dma_memcpy(outcopy, out_dma, out_arg, nbytes)
++# define BUFFER_IN 1
++# define BUFFER_OUT 0
++# define AES_ALGO 1
++# define DES_ALGO 0
++# define ALLOCATE_MEMORY(val, type) 1
++# define FREE_MEMORY(buff)
++extern struct lq_deu_device lq_deu[1];
++#endif /* CONFIG_CRYPTO_DEV_DMA */
++
++/* SHA CONSTANTS */
++#define HASH_CON_VALUE 0x0700002C
++
++#define INPUT_ENDIAN_SWAP(input) deu_input_swap(input)
++#define DEU_ENDIAN_SWAP(input) deu_endian_swap(input)
++#define DELAY_PERIOD 10
++#define FIND_DEU_CHIP_VERSION chip_version()
++
++#define WAIT_AES_DMA_READY() \
++ do { \
++ int i; \
++ volatile struct deu_dma *dma = \
++ (struct deu_dma *) LQ_DEU_DMA_CON; \
++ volatile struct deu_aes *aes = \
++ (volatile struct deu_aes *) AES_START; \
++ for (i = 0; i < 10; i++) \
++ udelay(DELAY_PERIOD); \
++ while (dma->ctrl.BSY) {}; \
++ while (aes->ctrl.BUS) {}; \
++ } while (0)
++
++#define WAIT_DES_DMA_READY() \
++ do { \
++ int i; \
++ volatile struct deu_dma *dma = \
++ (struct deu_dma *) LQ_DEU_DMA_CON; \
++ volatile struct deu_des *des = \
++ (struct deu_des *) DES_3DES_START; \
++ for (i = 0; i < 10; i++) \
++ udelay(DELAY_PERIOD); \
++ while (dma->ctrl.BSY) {}; \
++ while (des->ctrl.BUS) {}; \
++ } while (0)
++
++#define AES_DMA_MISC_CONFIG() \
++ do { \
++ volatile struct deu_aes *aes = \
++ (volatile struct deu_aes *) AES_START; \
++ aes->ctrl.KRE = 1; \
++ aes->ctrl.GO = 1; \
++ } while(0)
++
++#define SHA_HASH_INIT \
++ do { \
++ volatile struct deu_hash *hash = \
++ (struct deu_hash *) HASH_START; \
++ hash->ctrl.SM = 1; \
++ hash->ctrl.ALGO = 0; \
++ hash->ctrl.INIT = 1; \
++ } while(0)
++
++/* DEU Common Structures for Falcon*/
++
++struct deu_clk_ctrl {
++ u32 Res:26;
++ u32 FSOE:1;
++ u32 SBWE:1;
++ u32 EDIS:1;
++ u32 SPEN:1;
++ u32 DISS:1;
++ u32 DISR:1;
++};
++
++struct deu_des {
++ struct deu_des_ctrl { /* 10h */
++ u32 KRE:1;
++ u32 reserved1:5;
++ u32 GO:1;
++ u32 STP:1;
++ u32 Res2:6;
++ u32 NDC:1;
++ u32 ENDI:1;
++ u32 Res3:2;
++ u32 F:3;
++ u32 O:3;
++ u32 BUS:1;
++ u32 DAU:1;
++ u32 ARS:1;
++ u32 SM:1;
++ u32 E_D:1;
++ u32 M:3;
++ } ctrl;
++
++ u32 IHR; /* 14h */
++ u32 ILR; /* 18h */
++ u32 K1HR; /* 1c */
++ u32 K1LR;
++ u32 K2HR;
++ u32 K2LR;
++ u32 K3HR;
++ u32 K3LR; /* 30h */
++ u32 IVHR; /* 34h */
++ u32 IVLR; /* 38 */
++ u32 OHR; /* 3c */
++ u32 OLR; /* 40 */
++};
++
++struct deu_aes {
++ struct deu_aes_ctrl {
++ u32 KRE:1;
++ u32 reserved1:4;
++ u32 PNK:1;
++ u32 GO:1;
++ u32 STP:1;
++ u32 reserved2:6;
++ u32 NDC:1;
++ u32 ENDI:1;
++ u32 reserved3:2;
++ u32 F:3; /* fbs */
++ u32 O:3; /* om */
++ u32 BUS:1; /* bsy */
++ u32 DAU:1;
++ u32 ARS:1;
++ u32 SM:1;
++ u32 E_D:1;
++ u32 KV:1;
++ u32 K:2; /* KL */
++ } ctrl;
++
++ u32 ID3R; /* 80h */
++ u32 ID2R; /* 84h */
++ u32 ID1R; /* 88h */
++ u32 ID0R; /* 8Ch */
++ u32 K7R; /* 90h */
++ u32 K6R; /* 94h */
++ u32 K5R; /* 98h */
++ u32 K4R; /* 9Ch */
++ u32 K3R; /* A0h */
++ u32 K2R; /* A4h */
++ u32 K1R; /* A8h */
++ u32 K0R; /* ACh */
++ u32 IV3R; /* B0h */
++ u32 IV2R; /* B4h */
++ u32 IV1R; /* B8h */
++ u32 IV0R; /* BCh */
++ u32 OD3R; /* D4h */
++ u32 OD2R; /* D8h */
++ u32 OD1R; /* DCh */
++ u32 OD0R; /* E0h */
++};
++
++struct deu_arc4 {
++ struct arc4_controlr {
++ u32 KRE:1;
++ u32 KLEN:4;
++ u32 KSAE:1;
++ u32 GO:1;
++ u32 STP:1;
++ u32 reserved1:6;
++ u32 NDC:1;
++ u32 ENDI:1;
++ u32 reserved2:8;
++ u32 BUS:1; /* bsy */
++ u32 reserved3:1;
++ u32 ARS:1;
++ u32 SM:1;
++ u32 reserved4:4;
++ } ctrl;
++
++ u32 K3R; /* 104h */
++ u32 K2R; /* 108h */
++ u32 K1R; /* 10Ch */
++ u32 K0R; /* 110h */
++ u32 IDLEN; /* 114h */
++ u32 ID3R; /* 118h */
++ u32 ID2R; /* 11Ch */
++ u32 ID1R; /* 120h */
++ u32 ID0R; /* 124h */
++ u32 OD3R; /* 128h */
++ u32 OD2R; /* 12Ch */
++ u32 OD1R; /* 130h */
++ u32 OD0R; /* 134h */
++};
++
++struct deu_hash {
++ struct deu_hash_ctrl {
++ u32 reserved1:5;
++ u32 KHS:1;
++ u32 GO:1;
++ u32 INIT:1;
++ u32 reserved2:6;
++ u32 NDC:1;
++ u32 ENDI:1;
++ u32 reserved3:7;
++ u32 DGRY:1;
++ u32 BSY:1;
++ u32 reserved4:1;
++ u32 IRCL:1;
++ u32 SM:1;
++ u32 KYUE:1;
++ u32 HMEN:1;
++ u32 SSEN:1;
++ u32 ALGO:1;
++ } ctrl;
++
++ u32 MR; /* B4h */
++ u32 D1R; /* B8h */
++ u32 D2R; /* BCh */
++ u32 D3R; /* C0h */
++ u32 D4R; /* C4h */
++ u32 D5R; /* C8h */
++ u32 dummy; /* CCh */
++ u32 KIDX; /* D0h */
++ u32 KEY; /* D4h */
++ u32 DBN; /* D8h */
++};
++
++struct deu_dma {
++ struct deu_dma_ctrl {
++ u32 reserved1:22;
++ u32 BS:2;
++ u32 BSY:1;
++ u32 reserved2:1;
++ u32 ALGO:2;
++ u32 RXCLS:2;
++ u32 reserved3:1;
++ u32 EN:1;
++ } ctrl;
++};
++
++#endif /* DEU_FALCON_H */
+--- a/arch/mips/lantiq/xway/devices.c
++++ b/arch/mips/lantiq/xway/devices.c
+@@ -277,3 +277,9 @@
+ break;
+ }
+ }
++
++void __init
++lq_register_crypto(const char *name)
++{
++ platform_device_register_simple(name, 0, 0, 0);
++}
+--- a/arch/mips/lantiq/xway/devices.h
++++ b/arch/mips/lantiq/xway/devices.h
+@@ -21,5 +21,6 @@
+ extern void __init lq_register_wdt(void);
+ extern void __init lq_register_ethernet(struct lq_eth_data *eth);
+ extern void __init lq_register_asc(int port);
++extern void __init lq_register_crypto(const char *name);
+
+ #endif
+--- a/arch/mips/lantiq/xway/mach-easy50712.c
++++ b/arch/mips/lantiq/xway/mach-easy50712.c
+@@ -72,6 +72,7 @@
+ lq_register_wdt();
+ lq_register_pci(&lq_pci_data);
+ lq_register_ethernet(&lq_eth_data);
++ lq_register_crypto("lq_danube_deu");
+ }
+
+ MIPS_MACHINE(LANTIQ_MACH_EASY50712,
+--- a/arch/mips/lantiq/xway/mach-easy50812.c
++++ b/arch/mips/lantiq/xway/mach-easy50812.c
+@@ -71,6 +71,7 @@
+ lq_register_wdt();
+ lq_register_pci(&lq_pci_data);
+ lq_register_ethernet(&lq_eth_data);
++ lq_register_crypto("lq_ar9_deu");
+ }
+
+ MIPS_MACHINE(LANTIQ_MACH_EASY50812,