1
0
mirror of https://git.yoctoproject.org/meta-ti synced 2026-06-05 18:30:50 +00:00

linux-am335x-3.2.0-psp04.06.00.08: Add PSP v04.06.00.08 of the Linux kernel

* Add the PSP release version of the Linux kernel for the am335x-evm
* Include a variable called KERNEL_PATCHES which can be used to add
  patches on top of the PSP release of the Linux kernel. Currently used
  to apply various patches that add functionality or fixes bugs.

Signed-off-by: Franklin S. Cooper Jr <fcooper@ti.com>
Signed-off-by: Denys Dmytriyenko <denys@ti.com>
This commit is contained in:
Franklin S. Cooper Jr
2012-10-12 00:14:45 -05:00
committed by Denys Dmytriyenko
parent 2a3c7305fb
commit c911405cbc
23 changed files with 16322 additions and 0 deletions
@@ -0,0 +1,62 @@
From 69c82f68876d24e798388fc053c8d6766236ac65 Mon Sep 17 00:00:00 2001
From: Vita Preskovsky <vitap@ti.com>
Date: Thu, 28 Jun 2012 14:53:12 +0300
Subject: [PATCH] am3358-sk: modified WLAN enable and irq to match board revision 1.2
* 1. WLAN enable and irq are modified to match board revision 1.2
2. support suspend/resume for SK board
Upstream-Status: Pending
Signed-off-by: Vita Preskovsky <vitap@ti.com>
---
arch/arm/mach-omap2/board-am335xevm.c | 11 +++++++----
1 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/arch/arm/mach-omap2/board-am335xevm.c b/arch/arm/mach-omap2/board-am335xevm.c
index 64f7547..6ae4e68 100755
--- a/arch/arm/mach-omap2/board-am335xevm.c
+++ b/arch/arm/mach-omap2/board-am335xevm.c
@@ -905,7 +905,7 @@ static struct pinmux_config ecap2_pin_mux[] = {
#define AM335XEVM_WLAN_PMENA_GPIO GPIO_TO_PIN(1, 30)
#define AM335XEVM_WLAN_IRQ_GPIO GPIO_TO_PIN(3, 17)
-#define AM335XEVM_SK_WLAN_IRQ_GPIO GPIO_TO_PIN(1, 29)
+#define AM335XEVM_SK_WLAN_IRQ_GPIO GPIO_TO_PIN(0, 31)
struct wl12xx_platform_data am335xevm_wlan_data = {
.irq = OMAP_GPIO_IRQ(AM335XEVM_WLAN_IRQ_GPIO),
@@ -941,8 +941,8 @@ static struct pinmux_config wl12xx_pin_mux[] = {
};
static struct pinmux_config wl12xx_pin_mux_sk[] = {
- {"gpmc_wpn.gpio0_31", OMAP_MUX_MODE7 | AM33XX_PIN_OUTPUT},
- {"gpmc_csn0.gpio1_29", OMAP_MUX_MODE7 | AM33XX_PIN_INPUT},
+ {"gpmc_wpn.gpio0_31", OMAP_MUX_MODE7 | AM33XX_PIN_INPUT},
+ {"gpmc_csn0.gpio1_29", OMAP_MUX_MODE7 | AM33XX_PIN_OUTPUT_PULLUP},
{"mcasp0_ahclkx.gpio3_21", OMAP_MUX_MODE7 | AM33XX_PIN_OUTPUT},
{NULL, 0},
};
@@ -1618,6 +1618,7 @@ static void mmc1_wl12xx_init(int evm_id, int profile)
am335x_mmc[1].name = "wl1271";
am335x_mmc[1].caps = MMC_CAP_4_BIT_DATA | MMC_CAP_POWER_OFF_CARD;
am335x_mmc[1].nonremovable = true;
+ am335x_mmc[1].pm_caps = MMC_PM_KEEP_POWER;
am335x_mmc[1].gpio_cd = -EINVAL;
am335x_mmc[1].gpio_wp = -EINVAL;
am335x_mmc[1].ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34; /* 3V3 */
@@ -1674,10 +1675,12 @@ static void wl12xx_init(int evm_id, int profile)
int ret;
if (evm_id == EVM_SK) {
- am335xevm_wlan_data.wlan_enable_gpio = GPIO_TO_PIN(0, 31);
+ am335xevm_wlan_data.wlan_enable_gpio = GPIO_TO_PIN(1, 29);
am335xevm_wlan_data.bt_enable_gpio = GPIO_TO_PIN(3, 21);
am335xevm_wlan_data.irq =
OMAP_GPIO_IRQ(AM335XEVM_SK_WLAN_IRQ_GPIO);
+ am335xevm_wlan_data.platform_quirks =
+ WL12XX_PLATFORM_QUIRK_EDGE_IRQ;
setup_pin_mux(wl12xx_pin_mux_sk);
} else {
setup_pin_mux(wl12xx_pin_mux);
--
1.7.0.4
@@ -0,0 +1,130 @@
From 1edc97015f69fac420c32df514e1d1d546041d42 Mon Sep 17 00:00:00 2001
From: Greg Turner <gregturner@ti.com>
Date: Fri, 8 Jun 2012 13:54:13 -0500
Subject: [PATCH] [am335x]: Add crypto driver settings to defconfig
* Add Crypto Driver and configuration to defconfig
---
arch/arm/configs/am335x_evm_defconfig | 39 +++++++++++++++++++++++---------
1 files changed, 28 insertions(+), 11 deletions(-)
mode change 100644 => 100755 arch/arm/configs/am335x_evm_defconfig
diff --git a/arch/arm/configs/am335x_evm_defconfig b/arch/arm/configs/am335x_evm_defconfig
old mode 100644
new mode 100755
index de1eaad..0bf7efd
--- a/arch/arm/configs/am335x_evm_defconfig
+++ b/arch/arm/configs/am335x_evm_defconfig
@@ -1277,6 +1277,9 @@ CONFIG_SERIAL_OMAP_CONSOLE=y
# CONFIG_SERIAL_XILINX_PS_UART is not set
# CONFIG_HVC_DCC is not set
# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
+CONFIG_HW_RANDOM_OMAP4=y
# CONFIG_HW_RANDOM is not set
# CONFIG_R3964 is not set
# CONFIG_RAW_DRIVER is not set
@@ -2472,36 +2475,38 @@ CONFIG_CRYPTO=y
#
CONFIG_CRYPTO_ALGAPI=y
CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD=y
CONFIG_CRYPTO_AEAD2=y
CONFIG_CRYPTO_BLKCIPHER=y
CONFIG_CRYPTO_BLKCIPHER2=y
CONFIG_CRYPTO_HASH=y
CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG=y
CONFIG_CRYPTO_RNG2=y
CONFIG_CRYPTO_PCOMP2=y
CONFIG_CRYPTO_MANAGER=y
CONFIG_CRYPTO_MANAGER2=y
# CONFIG_CRYPTO_USER is not set
-CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
+# CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set
# CONFIG_CRYPTO_GF128MUL is not set
# CONFIG_CRYPTO_NULL is not set
CONFIG_CRYPTO_WORKQUEUE=y
# CONFIG_CRYPTO_CRYPTD is not set
# CONFIG_CRYPTO_AUTHENC is not set
-# CONFIG_CRYPTO_TEST is not set
+CONFIG_CRYPTO_TEST=m
#
# Authenticated Encryption with Associated Data
#
# CONFIG_CRYPTO_CCM is not set
# CONFIG_CRYPTO_GCM is not set
-# CONFIG_CRYPTO_SEQIV is not set
+CONFIG_CRYPTO_SEQIV=y
#
# Block modes
#
-# CONFIG_CRYPTO_CBC is not set
-# CONFIG_CRYPTO_CTR is not set
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_CTR=y
# CONFIG_CRYPTO_CTS is not set
CONFIG_CRYPTO_ECB=y
# CONFIG_CRYPTO_LRW is not set
@@ -2511,7 +2516,7 @@ CONFIG_CRYPTO_ECB=y
#
# Hash modes
#
-# CONFIG_CRYPTO_HMAC is not set
+CONFIG_CRYPTO_HMAC=y
# CONFIG_CRYPTO_XCBC is not set
# CONFIG_CRYPTO_VMAC is not set
@@ -2521,14 +2526,14 @@ CONFIG_CRYPTO_ECB=y
CONFIG_CRYPTO_CRC32C=y
# CONFIG_CRYPTO_GHASH is not set
# CONFIG_CRYPTO_MD4 is not set
-# CONFIG_CRYPTO_MD5 is not set
+CONFIG_CRYPTO_MD5=y
CONFIG_CRYPTO_MICHAEL_MIC=y
# CONFIG_CRYPTO_RMD128 is not set
# CONFIG_CRYPTO_RMD160 is not set
# CONFIG_CRYPTO_RMD256 is not set
# CONFIG_CRYPTO_RMD320 is not set
-# CONFIG_CRYPTO_SHA1 is not set
-# CONFIG_CRYPTO_SHA256 is not set
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA256=y
# CONFIG_CRYPTO_SHA512 is not set
# CONFIG_CRYPTO_TGR192 is not set
# CONFIG_CRYPTO_WP512 is not set
@@ -2543,7 +2548,7 @@ CONFIG_CRYPTO_ARC4=y
# CONFIG_CRYPTO_CAMELLIA is not set
# CONFIG_CRYPTO_CAST5 is not set
# CONFIG_CRYPTO_CAST6 is not set
-# CONFIG_CRYPTO_DES is not set
+CONFIG_CRYPTO_DES=y
# CONFIG_CRYPTO_FCRYPT is not set
# CONFIG_CRYPTO_KHAZAD is not set
# CONFIG_CRYPTO_SALSA20 is not set
@@ -2565,7 +2570,19 @@ CONFIG_CRYPTO_LZO=y
# CONFIG_CRYPTO_ANSI_CPRNG is not set
# CONFIG_CRYPTO_USER_API_HASH is not set
# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
-# CONFIG_CRYPTO_HW is not set
+CONFIG_CRYPTO_HW=y
+CONFIG_CRYPTO_DEV_OMAP4_AES=y
+CONFIG_CRYPTO_DEV_OMAP4_SHAM=y
+
+#
+# OCF Configuration
+#
+CONFIG_OCF_OCF=y
+# CONFIG_OCF_RANDOMHARVEST is not set
+CONFIG_OCF_CRYPTODEV=y
+CONFIG_OCF_CRYPTOSOFT=y
+# CONFIG_OCF_OCFNULL is not set
+# CONFIG_OCF_BENCH is not set
# CONFIG_BINARY_PRINTF is not set
#
--
1.7.0.4
@@ -0,0 +1,405 @@
From 7cb6dbae57e2bb5d237bb88f6eb40971cf8fc3b5 Mon Sep 17 00:00:00 2001
From: Greg Turner <gregturner@ti.com>
Date: Wed, 18 Jul 2012 09:15:18 -0500
Subject: [PATCH] [am335x]: Add pm_runtime API to crypto driver
* Add pm_runtime API to crypto driver AES and SHA
* Mod devices.c file to add pm_runtime for crypto
* Mod omap_hwmod_33xx_data.c to add resources structures
* Crypto module clocks are enabled in probe function
and disabled only on remove or other error.
---
arch/arm/mach-omap2/devices.c | 66 ++++++++++++++++++++++++++++
arch/arm/mach-omap2/omap_hwmod_33xx_data.c | 15 ++++++-
drivers/crypto/omap4-aes.c | 52 +++++++++++----------
drivers/crypto/omap4-sham.c | 45 ++++++++++---------
4 files changed, 131 insertions(+), 47 deletions(-)
mode change 100644 => 100755 arch/arm/mach-omap2/devices.c
mode change 100644 => 100755 arch/arm/mach-omap2/omap_hwmod_33xx_data.c
mode change 100644 => 100755 drivers/crypto/omap4-aes.c
mode change 100644 => 100755 drivers/crypto/omap4-sham.c
diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
old mode 100644
new mode 100755
index ebf0d9e..156e363
--- a/arch/arm/mach-omap2/devices.c
+++ b/arch/arm/mach-omap2/devices.c
@@ -751,6 +751,7 @@ static struct platform_device sham_device = {
.id = -1,
};
+#if 0
static void omap_init_sham(void)
{
sham_device.resource = omap4_sham_resources;
@@ -758,6 +759,38 @@ static void omap_init_sham(void)
platform_device_register(&sham_device);
}
+#endif
+
+int __init omap_init_sham(void)
+{
+ int id = -1;
+ struct platform_device *pdev;
+ struct omap_hwmod *oh;
+ char *oh_name = "sha0";
+ char *name = "omap4-sham";
+
+ oh = omap_hwmod_lookup(oh_name);
+ if (!oh) {
+ pr_err("Could not look up %s\n", oh_name);
+ return -ENODEV;
+ }
+
+ pdev = omap_device_build(name, id, oh, NULL, 0, NULL, 0, 0);
+ //pdev.resource = omap4_sham_resources;
+ //pdev.num_resources = omap4_sham_resources_sz;
+
+ if (IS_ERR(pdev)) {
+ WARN(1, "Can't build omap_device for %s:%s.\n",
+ name, oh->name);
+ return PTR_ERR(pdev);
+ }
+
+ return 0;
+}
+
+
+
+
#else
static inline void omap_init_sham(void) { }
@@ -853,12 +886,45 @@ static struct platform_device aes_device = {
.id = -1,
};
+#if 0
static void omap_init_aes(void)
{
aes_device.resource = omap4_aes_resources;
aes_device.num_resources = omap4_aes_resources_sz;
platform_device_register(&aes_device);
}
+#endif
+
+int __init omap_init_aes(void)
+{
+ int id = -1;
+ struct platform_device *pdev;
+ struct omap_hwmod *oh;
+ char *oh_name = "aes0";
+ char *name = "omap4-aes";
+
+ oh = omap_hwmod_lookup(oh_name);
+ if (!oh) {
+ pr_err("Could not look up %s\n", oh_name);
+ return -ENODEV;
+ }
+
+ pdev = omap_device_build(name, id, oh, NULL, 0, NULL, 0, 0);
+ //pdev.resource = omap4_sham_resources;
+ //pdev.num_resources = omap4_sham_resources_sz;
+
+ if (IS_ERR(pdev)) {
+ WARN(1, "Can't build omap_device for %s:%s.\n",
+ name, oh->name);
+ return PTR_ERR(pdev);
+ }
+
+ return 0;
+}
+
+
+
+
#else
static inline void omap_init_aes(void) { }
diff --git a/arch/arm/mach-omap2/omap_hwmod_33xx_data.c b/arch/arm/mach-omap2/omap_hwmod_33xx_data.c
old mode 100644
new mode 100755
index 995b73f..2f9982c
--- a/arch/arm/mach-omap2/omap_hwmod_33xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_33xx_data.c
@@ -434,11 +434,18 @@ static struct omap_hwmod_irq_info am33xx_aes0_irqs[] = {
{ .irq = -1 }
};
+static struct omap_hwmod_dma_info am33xx_aes0_dma[] = {
+ { .dma_req = AM33XX_DMA_AESEIP36T0_DOUT },
+ { .dma_req = AM33XX_DMA_AESEIP36T0_DIN },
+ { .dma_req = -1 }
+};
+
static struct omap_hwmod am33xx_aes0_hwmod = {
.name = "aes0",
.class = &am33xx_aes_hwmod_class,
.clkdm_name = "l3_clkdm",
.mpu_irqs = am33xx_aes0_irqs,
+ .sdma_reqs = am33xx_aes0_dma,
.main_clk = "aes0_fck",
.prcm = {
.omap4 = {
@@ -2165,15 +2172,21 @@ static struct omap_hwmod_class am33xx_sha0_hwmod_class = {
};
static struct omap_hwmod_irq_info am33xx_sha0_irqs[] = {
- { .irq = 108 },
+ { .irq = AM33XX_IRQ_SHAEIP57t0_P },
{ .irq = -1 }
};
+static struct omap_hwmod_dma_info am33xx_sha0_dma[] = {
+ { .dma_req = AM33XX_DMA_SHAEIP57T0_DIN },
+ { .dma_req = -1 }
+};
+
static struct omap_hwmod am33xx_sha0_hwmod = {
.name = "sha0",
.class = &am33xx_sha0_hwmod_class,
.clkdm_name = "l3_clkdm",
.mpu_irqs = am33xx_sha0_irqs,
+ .sdma_reqs = am33xx_sha0_dma,
.main_clk = "sha0_fck",
.prcm = {
.omap4 = {
diff --git a/drivers/crypto/omap4-aes.c b/drivers/crypto/omap4-aes.c
old mode 100644
new mode 100755
index f0b3fe2..76f988a
--- a/drivers/crypto/omap4-aes.c
+++ b/drivers/crypto/omap4-aes.c
@@ -32,13 +32,14 @@
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/kernel.h>
-#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/scatterlist.h>
#include <linux/dma-mapping.h>
#include <linux/io.h>
#include <linux/crypto.h>
+#include <linux/pm_runtime.h>
#include <linux/interrupt.h>
+#include <linux/delay.h>
#include <crypto/scatterwalk.h>
#include <crypto/aes.h>
@@ -145,12 +146,6 @@ static void omap4_aes_write_n(struct omap4_aes_dev *dd, u32 offset,
static int omap4_aes_hw_init(struct omap4_aes_dev *dd)
{
- /*
- * clocks are enabled when request starts and disabled when finished.
- * It may be long delays between requests.
- * Device might go to off mode to save power.
- */
- clk_enable(dd->iclk);
omap4_aes_write(dd, AES_REG_SYSCFG, 0);
if (!(dd->flags & FLAGS_INIT)) {
@@ -494,7 +489,6 @@ static void omap4_aes_finish_req(struct omap4_aes_dev *dd, int err)
pr_debug("err: %d\n", err);
- clk_disable(dd->iclk);
dd->flags &= ~FLAGS_BUSY;
req->base.complete(&req->base, err);
@@ -801,13 +795,15 @@ static int omap4_aes_probe(struct platform_device *pdev)
crypto_init_queue(&dd->queue, AM33X_AES_QUEUE_LENGTH);
/* Get the base address */
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(dev, "invalid resource type\n");
- err = -ENODEV;
- goto err_res;
- }
- dd->phys_base = res->start;
+ //res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ //if (!res) {
+ // dev_err(dev, "invalid resource type\n");
+ // err = -ENODEV;
+ // goto err_res;
+ //}
+
+ //dd->phys_base = res->start;
+ dd->phys_base = AM33XX_AES0_P_BASE;
/* Get the DMA */
res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
@@ -823,13 +819,10 @@ static int omap4_aes_probe(struct platform_device *pdev)
else
dd->dma_in = res->start;
- /* Initializing the clock */
- dd->iclk = clk_get(dev, "aes0_fck");
- if (IS_ERR(dd->iclk)) {
- dev_err(dev, "clock initialization failed.\n");
- err = PTR_ERR(dd->iclk);
- goto err_res;
- }
+ pm_runtime_enable(dev);
+ udelay(1);
+ pm_runtime_get_sync(dev);
+ udelay(1);
dd->io_base = ioremap(dd->phys_base, SZ_4K);
if (!dd->io_base) {
@@ -840,7 +833,7 @@ static int omap4_aes_probe(struct platform_device *pdev)
omap4_aes_hw_init(dd);
reg = omap4_aes_read(dd, AES_REG_REV);
- clk_disable(dd->iclk);
+
dev_info(dev, "AM33X AES hw accel rev: %u.%02u\n",
((reg & AES_REG_REV_X_MAJOR_MASK) >> 8),
(reg & AES_REG_REV_Y_MINOR_MASK));
@@ -879,7 +872,12 @@ err_dma:
iounmap(dd->io_base);
err_io:
- clk_put(dd->iclk);
+ pm_runtime_put_sync(dev);
+ udelay(1);
+ pm_runtime_disable(dev);
+ udelay(1);
+
+
err_res:
kfree(dd);
dd = NULL;
@@ -907,7 +905,11 @@ static int omap4_aes_remove(struct platform_device *pdev)
tasklet_kill(&dd->queue_task);
omap4_aes_dma_cleanup(dd);
iounmap(dd->io_base);
- clk_put(dd->iclk);
+ pm_runtime_put_sync(&pdev->dev);
+ udelay(1);
+ pm_runtime_disable(&pdev->dev);
+ udelay(1);
+
kfree(dd);
dd = NULL;
diff --git a/drivers/crypto/omap4-sham.c b/drivers/crypto/omap4-sham.c
old mode 100644
new mode 100755
index 79f6be9..21f1b48
--- a/drivers/crypto/omap4-sham.c
+++ b/drivers/crypto/omap4-sham.c
@@ -31,7 +31,6 @@
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
-#include <linux/clk.h>
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/platform_device.h>
@@ -40,6 +39,7 @@
#include <linux/delay.h>
#include <linux/crypto.h>
#include <linux/cryptohash.h>
+#include <linux/pm_runtime.h>
#include <crypto/scatterwalk.h>
#include <crypto/algapi.h>
#include <crypto/sha.h>
@@ -700,7 +700,6 @@ static void omap4_sham_finish_req(struct ahash_request *req, int err)
/* atomic operation is not needed here */
dd->dflags &= ~(BIT(FLAGS_BUSY) | BIT(FLAGS_FINAL) | BIT(FLAGS_CPU) |
BIT(FLAGS_DMA_READY) | BIT(FLAGS_OUTPUT_READY));
- clk_disable(dd->iclk);
if (req->base.complete)
req->base.complete(&req->base, err);
@@ -743,7 +742,6 @@ static int omap4_sham_handle_queue(struct omap4_sham_dev *dd,
dev_dbg(dd->dev, "handling new req, op: %lu, nbytes: %d\n",
ctx->op, req->nbytes);
- clk_enable(dd->iclk);
if (!test_bit(FLAGS_INIT, &dd->dflags)) {
set_bit(FLAGS_INIT, &dd->dflags);
dd->err = 0;
@@ -1272,13 +1270,15 @@ static int __devinit omap4_sham_probe(struct platform_device *pdev)
dd->irq = -1;
/* Get the base address */
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(dev, "no MEM resource info\n");
- err = -ENODEV;
- goto res_err;
- }
- dd->phys_base = res->start;
+ //res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ //if (!res) {
+ // dev_err(dev, "no MEM resource info\n");
+ // err = -ENODEV;
+ // goto res_err;
+ //}
+
+ //dd->phys_base = res->start;
+ dd->phys_base = AM33XX_SHA1MD5_P_BASE;
/* Get the DMA */
res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
@@ -1308,13 +1308,10 @@ static int __devinit omap4_sham_probe(struct platform_device *pdev)
if (err)
goto dma_err;
- /* Initializing the clock */
- dd->iclk = clk_get(dev, "sha0_fck");
- if (IS_ERR(dd->iclk)) {
- dev_err(dev, "clock initialization failed.\n");
- err = PTR_ERR(dd->iclk);
- goto clk_err;
- }
+ pm_runtime_enable(dev);
+ udelay(1);
+ pm_runtime_get_sync(dev);
+ udelay(1);
dd->io_base = ioremap(dd->phys_base, SZ_4K);
if (!dd->io_base) {
@@ -1323,9 +1320,7 @@ static int __devinit omap4_sham_probe(struct platform_device *pdev)
goto io_err;
}
- clk_enable(dd->iclk);
reg = omap4_sham_read(dd, SHA_REG_REV);
- clk_disable(dd->iclk);
dev_info(dev, "AM33X SHA/MD5 hw accel rev: %u.%02u\n",
(reg & SHA_REG_REV_X_MAJOR_MASK) >> 8, reg & SHA_REG_REV_Y_MINOR_MASK);
@@ -1349,7 +1344,11 @@ err_algs:
crypto_unregister_ahash(&algs[j]);
iounmap(dd->io_base);
io_err:
- clk_put(dd->iclk);
+ pm_runtime_put_sync(dev);
+ udelay(1);
+ pm_runtime_disable(dev);
+ udelay(1);
+
clk_err:
omap4_sham_dma_cleanup(dd);
dma_err:
@@ -1379,7 +1378,11 @@ static int __devexit omap4_sham_remove(struct platform_device *pdev)
crypto_unregister_ahash(&algs[i]);
tasklet_kill(&dd->done_task);
iounmap(dd->io_base);
- clk_put(dd->iclk);
+ pm_runtime_put_sync(&pdev->dev);
+ udelay(1);
+ pm_runtime_disable(&pdev->dev);
+ udelay(1);
+
omap4_sham_dma_cleanup(dd);
if (dd->irq >= 0)
free_irq(dd->irq, dd);
--
1.7.0.4
@@ -0,0 +1,57 @@
From f69ffbef6793b7238a8518481735fd53326e0cdf Mon Sep 17 00:00:00 2001
From: Vita Preskovsky <vitap@ti.com>
Date: Tue, 24 Jul 2012 20:02:28 +0300
Subject: [PATCH] am335x: enable pullup on the WLAN enable pin for keeping wlan
* Enable pullup on the WLAN enable pin for keeping wlan active
during suspend in wowlan mode. The fix is relevant only in the case
of am335x-SK board.
Signed-off-by: Vita Preskovsky <vitap@ti.com>
---
arch/arm/mach-omap2/board-am335xevm.c | 22 ++++++++++++++++++++++
1 files changed, 22 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-omap2/board-am335xevm.c b/arch/arm/mach-omap2/board-am335xevm.c
index f68710c..f263f84 100644
--- a/arch/arm/mach-omap2/board-am335xevm.c
+++ b/arch/arm/mach-omap2/board-am335xevm.c
@@ -1673,13 +1673,35 @@ static void wl12xx_bluetooth_enable(void)
gpio_direction_output(am335xevm_wlan_data.bt_enable_gpio, 0);
}
+#define AM33XX_CTRL_REGADDR(reg) \
+ AM33XX_L4_WK_IO_ADDRESS(AM33XX_SCM_BASE + (reg))
+
+/* wlan enable pin */
+#define AM33XX_CONTROL_PADCONF_GPMC_CSN0_OFFSET 0x087C
static int wl12xx_set_power(struct device *dev, int slot, int on, int vdd)
{
+ int pad_mux_value;
+
if (on) {
gpio_direction_output(am335xevm_wlan_data.wlan_enable_gpio, 1);
+
+ /* Enable pullup on the WLAN enable pin for keeping wlan active during suspend
+ in wowlan mode */
+ if ( am335x_evm_get_id() == EVM_SK ) {
+ pad_mux_value = readl(AM33XX_CTRL_REGADDR(AM33XX_CONTROL_PADCONF_GPMC_CSN0_OFFSET));
+ pad_mux_value &= (~AM33XX_PULL_DISA);
+ writel(pad_mux_value, AM33XX_CTRL_REGADDR(AM33XX_CONTROL_PADCONF_GPMC_CSN0_OFFSET));
+ }
+
mdelay(70);
} else {
gpio_direction_output(am335xevm_wlan_data.wlan_enable_gpio, 0);
+ /* Disable pullup on the WLAN enable when WLAN is off */
+ if ( am335x_evm_get_id() == EVM_SK ) {
+ pad_mux_value = readl(AM33XX_CTRL_REGADDR(AM33XX_CONTROL_PADCONF_GPMC_CSN0_OFFSET));
+ pad_mux_value |= AM33XX_PULL_DISA;
+ writel(pad_mux_value, AM33XX_CTRL_REGADDR(AM33XX_CONTROL_PADCONF_GPMC_CSN0_OFFSET));
+ }
}
return 0;
--
1.7.0.4
@@ -0,0 +1,35 @@
From 95eca5a896c96d0af7188c97825a3b3ef5313ed3 Mon Sep 17 00:00:00 2001
From: Chase Maupin <Chase.Maupin@ti.com>
Date: Thu, 2 Feb 2012 16:38:51 -0600
Subject: [PATCH] am335x_evm_defconfig: turn off MUSB DMA
* Turn off the MUSB DMA in the am335x_evm_defconfig. This way
we can pull the default defconfig without enabling the
faulty USB DMA.
Signed-off-by: Chase Maupin <Chase.Maupin@ti.com>
---
arch/arm/configs/am335x_evm_defconfig | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/arch/arm/configs/am335x_evm_defconfig b/arch/arm/configs/am335x_evm_defconfig
index d105c61..121dc7f 100644
--- a/arch/arm/configs/am335x_evm_defconfig
+++ b/arch/arm/configs/am335x_evm_defconfig
@@ -1982,11 +1982,11 @@ CONFIG_USB_MUSB_TI81XX_GLUE=y
CONFIG_USB_MUSB_TI81XX=y
# CONFIG_USB_MUSB_BLACKFIN is not set
# CONFIG_USB_MUSB_UX500 is not set
-CONFIG_USB_TI_CPPI41_DMA_HW=y
-# CONFIG_MUSB_PIO_ONLY is not set
+# CONFIG_USB_TI_CPPI41_DMA_HW is not set
+CONFIG_MUSB_PIO_ONLY=y
# CONFIG_USB_INVENTRA_DMA is not set
# CONFIG_USB_TI_CPPI_DMA is not set
-CONFIG_USB_TI_CPPI41_DMA=y
+# CONFIG_USB_TI_CPPI41_DMA is not set
# CONFIG_USB_TUSB_OMAP_DMA is not set
# CONFIG_USB_UX500_DMA is not set
# CONFIG_USB_RENESAS_USBHS is not set
--
1.7.0.4
@@ -0,0 +1,35 @@
From be52bac69dfe6a56276b16ccd234970c4f7b1255 Mon Sep 17 00:00:00 2001
From: Vita Preskovsky <vitap@ti.com>
Date: Wed, 18 Jul 2012 16:20:36 +0300
Subject: [PATCH] am335xevm: using edge triggered interrupts for WLAN
*using edge triggered interrupts instead of default level triggered in
all platforms supporting WLAN. This reduces CPU cycles and possibility
for missed interrupts.
Signed-off-by: Vita Preskovsky <vitap@ti.com>
---
arch/arm/mach-omap2/board-am335xevm.c | 3 +--
1 files changed, 1 insertions(+), 2 deletions(-)
diff --git a/arch/arm/mach-omap2/board-am335xevm.c b/arch/arm/mach-omap2/board-am335xevm.c
index 6ae4e68..ac005c8 100644
--- a/arch/arm/mach-omap2/board-am335xevm.c
+++ b/arch/arm/mach-omap2/board-am335xevm.c
@@ -1679,12 +1679,11 @@ static void wl12xx_init(int evm_id, int profile)
am335xevm_wlan_data.bt_enable_gpio = GPIO_TO_PIN(3, 21);
am335xevm_wlan_data.irq =
OMAP_GPIO_IRQ(AM335XEVM_SK_WLAN_IRQ_GPIO);
- am335xevm_wlan_data.platform_quirks =
- WL12XX_PLATFORM_QUIRK_EDGE_IRQ;
setup_pin_mux(wl12xx_pin_mux_sk);
} else {
setup_pin_mux(wl12xx_pin_mux);
}
+ am335xevm_wlan_data.platform_quirks = WL12XX_PLATFORM_QUIRK_EDGE_IRQ;
wl12xx_bluetooth_enable();
if (wl12xx_set_platform_data(&am335xevm_wlan_data))
--
1.7.0.4
@@ -0,0 +1,41 @@
From 5f2f17a488aba4319b537aed040ea13607af128b Mon Sep 17 00:00:00 2001
From: Greg Turner <gregturner@ti.com>
Date: Thu, 17 May 2012 14:25:40 -0500
Subject: [PATCH 1/8] am33x: Add memory addresses for crypto modules
* Add base memory addresses to the am33xx.h header file
These addresses are for the HW crypto modules including TRNG, AES, and SHA/MD5
Signed-off-by: Greg Turner <gregturner@ti.com>
---
arch/arm/plat-omap/include/plat/am33xx.h | 11 +++++++++++
1 files changed, 11 insertions(+), 0 deletions(-)
mode change 100644 => 100755 arch/arm/plat-omap/include/plat/am33xx.h
diff --git a/arch/arm/plat-omap/include/plat/am33xx.h b/arch/arm/plat-omap/include/plat/am33xx.h
old mode 100644
new mode 100755
index a16e72c..96ab1c3
--- a/arch/arm/plat-omap/include/plat/am33xx.h
+++ b/arch/arm/plat-omap/include/plat/am33xx.h
@@ -65,6 +65,17 @@
#define AM33XX_ELM_BASE 0x48080000
+/* Base address for crypto modules */
+#define AM33XX_SHA1MD5_S_BASE 0x53000000
+#define AM33XX_SHA1MD5_P_BASE 0x53100000
+
+#define AM33XX_AES0_S_BASE 0x53400000
+#define AM33XX_AES0_P_BASE 0x53500000
+#define AM33XX_AES1_S_BASE 0x53600000
+#define AM33XX_AES1_P_BASE 0x53700000
+
+#define AM33XX_RNG_BASE 0x48310000
+
#define AM33XX_ASP0_BASE 0x48038000
#define AM33XX_ASP1_BASE 0x4803C000
--
1.7.0.4
@@ -0,0 +1,71 @@
From 31ec2850e89414efb30accb9d8b5228257e507b1 Mon Sep 17 00:00:00 2001
From: Chase Maupin <Chase.Maupin@ti.com>
Date: Wed, 21 Mar 2012 10:18:03 -0500
Subject: [PATCH 1/1] mach-omap2: pm33xx: Disable VT switch
* Added a new config option TI_PM_DISABLE_VT_SWITCH which
disables the VT console switch which normally occurs during
suspend. This console switch can cause a hange when performed
with applications like Matrix running. The VT switch is
considered unnecessary.
* Modified the am335x_evm_defconfig file to default the
TI_PM_DISABLE_VT_SWITCH to "y".
* Based on a patch for the linux-omap3 kernel by Greg Guyotte
Signed-off-by: Chase Maupin <Chase.Maupin@ti.com>
---
arch/arm/configs/am335x_evm_defconfig | 1 +
arch/arm/mach-omap2/Kconfig | 9 +++++++++
arch/arm/mach-omap2/pm33xx.c | 5 +++++
3 files changed, 15 insertions(+), 0 deletions(-)
diff --git a/arch/arm/configs/am335x_evm_defconfig b/arch/arm/configs/am335x_evm_defconfig
index 53d1b6a..7a5e7ad 100644
--- a/arch/arm/configs/am335x_evm_defconfig
+++ b/arch/arm/configs/am335x_evm_defconfig
@@ -325,6 +325,7 @@ CONFIG_MACH_TI8148EVM=y
CONFIG_MACH_AM335XEVM=y
CONFIG_MACH_AM335XIAEVM=y
# CONFIG_OMAP3_EMU is not set
+CONFIG_TI_PM_DISABLE_VT_SWITCH=y
# CONFIG_OMAP3_SDRC_AC_TIMING is not set
CONFIG_OMAP3_EDMA=y
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index e44e942..f13e9dc 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -372,6 +372,15 @@ config OMAP3_EMU
help
Say Y here to enable debugging hardware of omap3
+config TI_PM_DISABLE_VT_SWITCH
+ bool "TI Disable PM Console Switch"
+ depends on ARCH_OMAP3
+ default y
+ help
+ This option disables the default PM VT switch behavior for TI devices.
+ Some platforms hang during suspend due to a failed attempt to
+ perform the VT switch. The VT switch is unnecessary on many platforms.
+
config OMAP3_SDRC_AC_TIMING
bool "Enable SDRC AC timing register changes"
depends on ARCH_OMAP3
diff --git a/arch/arm/mach-omap2/pm33xx.c b/arch/arm/mach-omap2/pm33xx.c
index 70bcb42..019ae46 100644
--- a/arch/arm/mach-omap2/pm33xx.c
+++ b/arch/arm/mach-omap2/pm33xx.c
@@ -502,6 +502,11 @@ static int __init am33xx_pm_init(void)
pr_info("Power Management for AM33XX family\n");
#ifdef CONFIG_SUSPEND
+
+#ifdef CONFIG_TI_PM_DISABLE_VT_SWITCH
+ pm_set_vt_switch(0);
+#endif
+
/* Read SDRAM_CONFIG register to determine Memory Type */
base = am33xx_get_ram_base();
reg = readl(base + EMIF4_0_SDRAM_CONFIG);
--
1.7.0.4
@@ -0,0 +1,45 @@
From 214f6b2fee005dba5e01b3b434f184adf4386a25 Mon Sep 17 00:00:00 2001
From: Chase Maupin <Chase.Maupin@ti.com>
Date: Thu, 2 Feb 2012 15:52:10 -0600
Subject: [PATCH] musb: update PIO mode help information in Kconfig
* Updated the Kconfig help information for the PIO mode for MUSB
to make it more clear to the customer when to select this option
and which devices currently have issues with this option.
* This is in accordance with the findings for CPPI4.1 DMA usage
for MUSB
Upstream-Status: Submitted
* Submitted to the PSP team using the lpr list
Signed-off-by: Matt Porter <mporter@ti.com>
Signed-off-by: Chase Maupin <Chase.Maupin@ti.com>
---
drivers/usb/musb/Kconfig | 12 ++++++++----
1 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index a06335f..3576afe 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -159,10 +159,14 @@ config MUSB_PIO_ONLY
All data is copied between memory and FIFO by the CPU.
DMA controllers are ignored.
- Do not choose this unless DMA support for your SOC or board
- is unavailable (or unstable). When DMA is enabled at compile time,
- you can still disable it at run time using the "use_dma=n" module
- parameter.
+ Select 'y' here if DMA support for your SOC or board
+ is unavailable (or unstable). On CPPI 4.1 DMA based
+ systems (AM335x, AM35x, and AM180x) DMA support is
+ considered unstable and this option should be enabled
+ in production systems so that DMA is disabled, unless DMA
+ has been validated for all use cases. When DMA is enabled at
+ compile time, you can still disable it at run time using the
+ "use_dma=n" module parameter.
endchoice
--
1.7.0.4
@@ -0,0 +1,42 @@
From 0f62d1f4d4543a315815b8eb15ea9cdad25d16c8 Mon Sep 17 00:00:00 2001
From: Eyal Reizer <eyalr@ti.com>
Date: Wed, 27 Jun 2012 16:08:53 +0300
Subject: [PATCH] omap-serial: add delay before suspending
In case suspending during Bluetooth traffic, after resume the bluetooth is
stuck.
It was identified that suspend is happening before the UART buffer was
fully drained which caused this hang after resume.
The folliwng delay is a temporary workaround until the issue is resolved
properly.
Upstream Status: Pending
Signed-off-by: Eyal Reizer <eyalr@ti.com>
---
drivers/tty/serial/omap-serial.c | 10 ++++++++++
1 files changed, 10 insertions(+), 0 deletions(-)
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index ca24ab3..108ea2b 100755
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -1166,6 +1166,16 @@ static int serial_omap_suspend(struct device *dev)
struct uart_omap_port *up = dev_get_drvdata(dev);
if (up) {
+ /*
+ In case suspending during Bluetooth traffic, after resume
+ the bluetooth is stuck.
+ It was identified that suspend is happening before the
+ UART buffer was fully drained which caused this hang after
+ resume. The following delay is a temporary workaround until
+ the issue is resolved properly.
+ */
+ msleep(10);
+
uart_suspend_port(&serial_omap_reg, &up->port);
flush_work_sync(&up->qos_work);
}
--
1.7.0.4
@@ -0,0 +1,147 @@
From 0fb328ec0a5ba8a1440336c8dc7a029cfffa4529 Mon Sep 17 00:00:00 2001
From: Greg Turner <gregturner@ti.com>
Date: Thu, 19 Jul 2012 15:27:59 -0500
Subject: [PATCH 2/2] [am335x]: Add suspend resume routines to crypto driver
* Add suspend resume routines to AES crypto driver
* Add suspend resume routines to SHA crypto driver
* Cleaned up some build warnings
---
drivers/crypto/omap4-aes.c | 31 ++++++++++++++++++++++++++++---
drivers/crypto/omap4-sham.c | 32 +++++++++++++++++++++++++++-----
2 files changed, 55 insertions(+), 8 deletions(-)
diff --git a/drivers/crypto/omap4-aes.c b/drivers/crypto/omap4-aes.c
index 76f988a..c7d08df 100755
--- a/drivers/crypto/omap4-aes.c
+++ b/drivers/crypto/omap4-aes.c
@@ -878,9 +878,9 @@ err_io:
udelay(1);
-err_res:
- kfree(dd);
- dd = NULL;
+//err_res:
+ //kfree(dd);
+ //dd = NULL;
err_data:
dev_err(dev, "initialization failed.\n");
return err;
@@ -916,12 +916,35 @@ static int omap4_aes_remove(struct platform_device *pdev)
return 0;
}
+static int omap4_aes_suspend(struct device *dev)
+{
+ pr_debug("#### Crypto: Suspend call ####\n");
+
+ return 0;
+}
+
+
+static int omap4_aes_resume(struct device *dev)
+{
+ pr_debug("#### Crypto: resume call ####\n");
+
+ return 0;
+}
+
+static struct dev_pm_ops omap4_aes_dev_pm_ops = {
+ .suspend = omap4_aes_suspend,
+ .resume = omap4_aes_resume,
+ .runtime_suspend = omap4_aes_suspend,
+ .runtime_resume = omap4_aes_resume,
+};
+
static struct platform_driver omap4_aes_driver = {
.probe = omap4_aes_probe,
.remove = omap4_aes_remove,
.driver = {
.name = "omap4-aes",
.owner = THIS_MODULE,
+ .pm = &omap4_aes_dev_pm_ops
},
};
@@ -944,6 +967,8 @@ static void __exit omap4_aes_mod_exit(void)
platform_driver_unregister(&omap4_aes_driver);
}
+
+
module_init(omap4_aes_mod_init);
module_exit(omap4_aes_mod_exit);
diff --git a/drivers/crypto/omap4-sham.c b/drivers/crypto/omap4-sham.c
index 21f1b48..2fb71b9 100755
--- a/drivers/crypto/omap4-sham.c
+++ b/drivers/crypto/omap4-sham.c
@@ -239,7 +239,7 @@ static void omap4_sham_copy_ready_hash(struct ahash_request *req)
struct omap4_sham_reqctx *ctx = ahash_request_ctx(req);
u32 *in = (u32 *)ctx->digest;
u32 *hash = (u32 *)req->result;
- int i, d;
+ int i, d = 0;
if (!hash)
return;
@@ -1224,8 +1224,6 @@ static void omap4_sham_dma_callback(unsigned int lch, u16 ch_status, void *data)
static int omap4_sham_dma_init(struct omap4_sham_dev *dd)
{
- int err;
-
dd->dma_lch = -1;
dd->dma_lch = edma_alloc_channel(dd->dma, omap4_sham_dma_callback, dd, EVENTQ_2);
@@ -1349,8 +1347,9 @@ io_err:
pm_runtime_disable(dev);
udelay(1);
-clk_err:
- omap4_sham_dma_cleanup(dd);
+//clk_err:
+// omap4_sham_dma_cleanup(dd);
+
dma_err:
if (dd->irq >= 0)
free_irq(dd->irq, dd);
@@ -1392,12 +1391,35 @@ static int __devexit omap4_sham_remove(struct platform_device *pdev)
return 0;
}
+static int omap4_sham_suspend(struct device *dev)
+{
+ pr_debug("#### Crypto: Suspend call ####\n");
+
+ return 0;
+}
+
+
+static int omap4_sham_resume(struct device *dev)
+{
+ pr_debug("#### Crypto: resume call ####\n");
+
+ return 0;
+}
+
+static struct dev_pm_ops omap4_sham_dev_pm_ops = {
+ .suspend = omap4_sham_suspend,
+ .resume = omap4_sham_resume,
+ .runtime_suspend = omap4_sham_suspend,
+ .runtime_resume = omap4_sham_resume,
+};
+
static struct platform_driver omap4_sham_driver = {
.probe = omap4_sham_probe,
.remove = omap4_sham_remove,
.driver = {
.name = "omap4-sham",
.owner = THIS_MODULE,
+ .pm = &omap4_sham_dev_pm_ops
},
};
--
1.7.0.4
@@ -0,0 +1,111 @@
From 8c0f7553e75774849463f90b0135874754650386 Mon Sep 17 00:00:00 2001
From: Greg Turner <gregturner@ti.com>
Date: Thu, 17 May 2012 14:45:05 -0500
Subject: [PATCH 2/8] am33x: Add crypto device and resource structures
* Add platform device and resource structures to devices.c
* Structures are for the AES and SHA/MD5 crypto modules
* Used in the OMAP4 crypto driver
Signed-off-by: Greg Turner <gregturner@ti.com>
---
arch/arm/mach-omap2/devices.c | 67 +++++++++++++++++++++++++++++++++++++++++
1 files changed, 67 insertions(+), 0 deletions(-)
mode change 100644 => 100755 arch/arm/mach-omap2/devices.c
diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
old mode 100644
new mode 100755
index 9e029da..5c6e3e2
--- a/arch/arm/mach-omap2/devices.c
+++ b/arch/arm/mach-omap2/devices.c
@@ -47,6 +47,7 @@
#include <plat/omap_hwmod.h>
#include <plat/omap_device.h>
#include <plat/omap4-keypad.h>
+#include <plat/am33xx.h>
#include <plat/config_pwm.h>
#include <plat/cpu.h>
#include <plat/gpmc.h>
@@ -702,6 +703,41 @@ static void omap_init_sham(void)
}
platform_device_register(&sham_device);
}
+
+#elif defined(CONFIG_CRYPTO_DEV_OMAP4_SHAM) || defined(CONFIG_CRYPTO_DEV_OMAP4_SHAM_MODULE)
+
+static struct resource omap4_sham_resources[] = {
+ {
+ .start = AM33XX_SHA1MD5_P_BASE,
+ .end = AM33XX_SHA1MD5_P_BASE + 0x120,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = AM33XX_IRQ_SHAEIP57t0_P,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = AM33XX_DMA_SHAEIP57T0_DIN,
+ .flags = IORESOURCE_DMA,
+ }
+};
+
+static int omap4_sham_resources_sz = ARRAY_SIZE(omap4_sham_resources);
+
+
+static struct platform_device sham_device = {
+ .name = "omap4-sham",
+ .id = -1,
+};
+
+static void omap_init_sham(void)
+{
+ sham_device.resource = omap4_sham_resources;
+ sham_device.num_resources = omap4_sham_resources_sz;
+
+ platform_device_register(&sham_device);
+}
+
#else
static inline void omap_init_sham(void) { }
#endif
@@ -772,6 +808,37 @@ static void omap_init_aes(void)
platform_device_register(&aes_device);
}
+#elif defined(CONFIG_CRYPTO_DEV_OMAP4_AES) || defined(CONFIG_CRYPTO_DEV_OMAP4_AES_MODULE)
+
+static struct resource omap4_aes_resources[] = {
+ {
+ .start = AM33XX_AES0_P_BASE,
+ .end = AM33XX_AES0_P_BASE + 0x4C,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = AM33XX_DMA_AESEIP36T0_DOUT,
+ .flags = IORESOURCE_DMA,
+ },
+ {
+ .start = AM33XX_DMA_AESEIP36T0_DIN,
+ .flags = IORESOURCE_DMA,
+ }
+};
+static int omap4_aes_resources_sz = ARRAY_SIZE(omap4_aes_resources);
+
+static struct platform_device aes_device = {
+ .name = "omap4-aes",
+ .id = -1,
+};
+
+static void omap_init_aes(void)
+{
+ aes_device.resource = omap4_aes_resources;
+ aes_device.num_resources = omap4_aes_resources_sz;
+ platform_device_register(&aes_device);
+}
+
#else
static inline void omap_init_aes(void) { }
#endif
--
1.7.0.4
@@ -0,0 +1,26 @@
From e1b7a67fc82991a633f0ed615d69157c98c1c35d Mon Sep 17 00:00:00 2001
From: Greg Guyotte <gguyotte@ti.com>
Date: Thu, 7 Jun 2012 18:15:21 -0500
Subject: [PATCH 2/2] am33xx: Enable CONFIG_AM33XX_SMARTREFLEX
Simply enables the SmartReflex driver in the defconfig file.
Signed-off-by: Greg Guyotte <gguyotte@ti.com>
---
arch/arm/configs/am335x_evm_defconfig | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/arch/arm/configs/am335x_evm_defconfig b/arch/arm/configs/am335x_evm_defconfig
index de1eaad..ce5d1d6 100644
--- a/arch/arm/configs/am335x_evm_defconfig
+++ b/arch/arm/configs/am335x_evm_defconfig
@@ -269,6 +269,7 @@ CONFIG_ARCH_OMAP2PLUS=y
# OMAP Feature Selections
#
# CONFIG_OMAP_SMARTREFLEX is not set
+CONFIG_AM33XX_SMARTREFLEX=y
CONFIG_OMAP_RESET_CLOCKS=y
CONFIG_OMAP_MUX=y
CONFIG_OMAP_MUX_DEBUG=y
--
1.7.0.4
@@ -0,0 +1,60 @@
From b7477dd40221a91af286bffa110879075a498943 Mon Sep 17 00:00:00 2001
From: Greg Turner <gregturner@ti.com>
Date: Thu, 17 May 2012 14:49:39 -0500
Subject: [PATCH 3/8] am33x: Add crypto device and resource structure for TRNG
* Add platform device and resource structure to devices.c
* Structures are for the TRNG crypto module
* Used in the OMAP4 crypto driver
Signed-off-by: Greg Turner <gregturner@ti.com>
---
arch/arm/plat-omap/devices.c | 23 +++++++++++++++++++++++
1 files changed, 23 insertions(+), 0 deletions(-)
mode change 100644 => 100755 arch/arm/plat-omap/devices.c
diff --git a/arch/arm/plat-omap/devices.c b/arch/arm/plat-omap/devices.c
old mode 100644
new mode 100755
index 1971932..52720b4
--- a/arch/arm/plat-omap/devices.c
+++ b/arch/arm/plat-omap/devices.c
@@ -26,6 +26,7 @@
#include <plat/mmc.h>
#include <plat/menelaus.h>
#include <plat/omap44xx.h>
+#include <plat/am33xx.h>
#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) || \
defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE)
@@ -104,6 +105,28 @@ static void omap_init_rng(void)
{
(void) platform_device_register(&omap_rng_device);
}
+#elif defined(CONFIG_HW_RANDOM_OMAP4) || defined(CONFIG_HW_RANDOM_OMAP4_MODULE)
+
+static struct resource rng_resources[] = {
+ {
+ .start = AM33XX_RNG_BASE,
+ .end = AM33XX_RNG_BASE + 0x1FFC,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device omap4_rng_device = {
+ .name = "omap4_rng",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(rng_resources),
+ .resource = rng_resources,
+};
+
+static void omap_init_rng(void)
+{
+ (void) platform_device_register(&omap4_rng_device);
+}
+
#else
static inline void omap_init_rng(void) {}
#endif
--
1.7.0.4
@@ -0,0 +1,124 @@
From e49e6dcff5665cb2f132d9654a060fa43a382810 Mon Sep 17 00:00:00 2001
From: Greg Turner <gregturner@ti.com>
Date: Thu, 17 May 2012 14:53:25 -0500
Subject: [PATCH 4/8] am33x: Add crypto drivers to Kconfig and Makefiles
* Add OMAP4 TRNG driver to hw_random Kconfig and Makefile
* Add OMAP4 AES and SHA/MD5 driver to crypto Kconfig and Makefile
* Needed so that drivers can be selected during kernel config
Signed-off-by: Greg Turner <gregturner@ti.com>
---
drivers/char/hw_random/Kconfig | 13 +++++++++++++
drivers/char/hw_random/Makefile | 1 +
drivers/crypto/Kconfig | 22 ++++++++++++++++++++--
drivers/crypto/Makefile | 2 ++
4 files changed, 36 insertions(+), 2 deletions(-)
mode change 100644 => 100755 drivers/char/hw_random/Kconfig
mode change 100644 => 100755 drivers/char/hw_random/Makefile
mode change 100644 => 100755 drivers/crypto/Kconfig
mode change 100644 => 100755 drivers/crypto/Makefile
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
old mode 100644
new mode 100755
index 0689bf6..207e3e7
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -139,6 +139,19 @@ config HW_RANDOM_OMAP
If unsure, say Y.
+config HW_RANDOM_OMAP4
+ tristate "OMAP4 Random Number Generator support"
+ depends on HW_RANDOM && SOC_OMAPAM33XX
+ default HW_RANDOM
+ ---help---
+ This driver provides kernel-side support for the Random Number
+ Generator hardware found on OMAP4 derived processors.
+
+ To compile this driver as a module, choose M here: the
+ module will be called omap4-rng.
+
+ If unsure, say Y.
+
config HW_RANDOM_OCTEON
tristate "Octeon Random Number Generator support"
depends on HW_RANDOM && CPU_CAVIUM_OCTEON
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
old mode 100644
new mode 100755
index b2ff526..fecced0
--- a/drivers/char/hw_random/Makefile
+++ b/drivers/char/hw_random/Makefile
@@ -14,6 +14,7 @@ n2-rng-y := n2-drv.o n2-asm.o
obj-$(CONFIG_HW_RANDOM_VIA) += via-rng.o
obj-$(CONFIG_HW_RANDOM_IXP4XX) += ixp4xx-rng.o
obj-$(CONFIG_HW_RANDOM_OMAP) += omap-rng.o
+obj-$(CONFIG_HW_RANDOM_OMAP4) += omap4-rng.o
obj-$(CONFIG_HW_RANDOM_PASEMI) += pasemi-rng.o
obj-$(CONFIG_HW_RANDOM_VIRTIO) += virtio-rng.o
obj-$(CONFIG_HW_RANDOM_TX4939) += tx4939-rng.o
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
old mode 100644
new mode 100755
index 6d16b4b..6c1331a
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -250,7 +250,7 @@ config CRYPTO_DEV_PPC4XX
config CRYPTO_DEV_OMAP_SHAM
tristate "Support for OMAP SHA1/MD5 hw accelerator"
- depends on ARCH_OMAP2 || ARCH_OMAP3
+ depends on (ARCH_OMAP2) || (ARCH_OMAP3) && (!SOC_OMAPAM33XX)
select CRYPTO_SHA1
select CRYPTO_MD5
help
@@ -259,12 +259,30 @@ config CRYPTO_DEV_OMAP_SHAM
config CRYPTO_DEV_OMAP_AES
tristate "Support for OMAP AES hw engine"
- depends on ARCH_OMAP2 || ARCH_OMAP3
+ depends on (ARCH_OMAP2) || (ARCH_OMAP3) && (!SOC_OMAPAM33XX)
select CRYPTO_AES
help
OMAP processors have AES module accelerator. Select this if you
want to use the OMAP module for AES algorithms.
+config CRYPTO_DEV_OMAP4_AES
+ tristate "Support for OMAP4 AES hw engine"
+ depends on SOC_OMAPAM33XX
+ select CRYPTO_AES
+ help
+ OMAP4 -based processors have AES module accelerators. Select this if you
+ want to use the OMAP4 module for AES algorithms.
+
+config CRYPTO_DEV_OMAP4_SHAM
+ tristate "Support for OMAP4 SHA/MD5 hw engine"
+ depends on SOC_OMAPAM33XX
+ select CRYPTO_SHA1
+ select CRYPTO_SHA256
+ select CRYPTO_MD5
+ help
+ OMAP4 -based processors have SHA/MD5 module accelerators. Select this if you
+ want to use the OMAP4 module for SHA/MD5 algorithms.
+
config CRYPTO_DEV_PICOXCELL
tristate "Support for picoXcell IPSEC and Layer2 crypto engines"
depends on ARCH_PICOXCELL && HAVE_CLK
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
old mode 100644
new mode 100755
index 53ea501..5b420a5
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -11,5 +11,7 @@ obj-$(CONFIG_CRYPTO_DEV_IXP4XX) += ixp4xx_crypto.o
obj-$(CONFIG_CRYPTO_DEV_PPC4XX) += amcc/
obj-$(CONFIG_CRYPTO_DEV_OMAP_SHAM) += omap-sham.o
obj-$(CONFIG_CRYPTO_DEV_OMAP_AES) += omap-aes.o
+obj-$(CONFIG_CRYPTO_DEV_OMAP4_AES) += omap4-aes.o
+obj-$(CONFIG_CRYPTO_DEV_OMAP4_SHAM) += omap4-sham.o
obj-$(CONFIG_CRYPTO_DEV_PICOXCELL) += picoxcell_crypto.o
obj-$(CONFIG_CRYPTO_DEV_S5P) += s5p-sss.o
--
1.7.0.4
@@ -0,0 +1,213 @@
From 2dc9dec7510746b3c3f5420f4f3ab8395cc7b012 Mon Sep 17 00:00:00 2001
From: Greg Turner <gregturner@ti.com>
Date: Thu, 17 May 2012 14:59:38 -0500
Subject: [PATCH 5/8] am33x: Create header file for OMAP4 crypto modules
* This header file defines addresses and macros used to access crypto modules on OMAP4 derivative SOC's like AM335x.
Signed-off-by: Greg Turner <gregturner@ti.com>
---
drivers/crypto/omap4.h | 192 ++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 192 insertions(+), 0 deletions(-)
create mode 100644 drivers/crypto/omap4.h
diff --git a/drivers/crypto/omap4.h b/drivers/crypto/omap4.h
new file mode 100644
index 0000000..d9d6315
--- /dev/null
+++ b/drivers/crypto/omap4.h
@@ -0,0 +1,192 @@
+/*
+ * drivers/crypto/omap4.h
+ *
+ * Copyright © 2011 Texas Instruments Incorporated
+ * Author: Greg Turner
+ *
+ * Adapted from Netra/Centaurus crypto driver
+ * Copyright © 2011 Texas Instruments Incorporated
+ * Author: Herman Schuurman
+ *
+ * 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
+ */
+#ifndef __DRIVERS_CRYPTO_AM33X_H
+#define __DRIVERS_CRYPTO_AM33X_H
+
+/* ==================================================================== */
+/** Crypto subsystem module layout
+ */
+/* ==================================================================== */
+
+#define AM33X_AES_CLKCTRL (AM33XX_PRCM_BASE + 0x00000094)
+#define AM33X_SHA_CLKCTRL (AM33XX_PRCM_BASE + 0x000000A0)
+
+#define FLD_MASK(start, end) (((1 << ((start) - (end) + 1)) - 1) << (end))
+#define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end))
+
+/* ==================================================================== */
+/** AES module layout
+ */
+/* ==================================================================== */
+
+#define AES_REG_KEY2(x) (0x1C - ((x ^ 0x01) * 0x04))
+#define AES_REG_KEY1(x) (0x3C - ((x ^ 0x01) * 0x04))
+#define AES_REG_IV(x) (0x40 + ((x) * 0x04))
+
+#define AES_REG_CTRL 0x50
+#define AES_REG_CTRL_CTX_RDY (1 << 31)
+#define AES_REG_CTRL_SAVE_CTX_RDY (1 << 30)
+#define AES_REG_CTRL_SAVE_CTX (1 << 29)
+#define AES_REG_CTRL_CCM_M_MASK (7 << 22)
+#define AES_REG_CTRL_CCM_M_SHFT 22
+#define AES_REG_CTRL_CCM_L_MASK (7 << 19)
+#define AES_REG_CTRL_CCM_L_SHFT 19
+#define AES_REG_CTRL_CCM (1 << 18)
+#define AES_REG_CTRL_GCM (3 << 16)
+#define AES_REG_CTRL_CBCMAC (1 << 15)
+#define AES_REG_CTRL_F9 (1 << 14)
+#define AES_REG_CTRL_F8 (1 << 13)
+#define AES_REG_CTRL_XTS_MASK (3 << 11)
+#define AES_REG_CTRL_XTS_01 (1 << 11)
+#define AES_REG_CTRL_XTS_10 (2 << 11)
+#define AES_REG_CTRL_XTS_11 (3 << 11)
+#define AES_REG_CTRL_CFB (1 << 10)
+#define AES_REG_CTRL_ICM (1 << 9)
+#define AES_REG_CTRL_CTR_WIDTH_MASK (3 << 7)
+#define AES_REG_CTRL_CTR_WIDTH_32 (0 << 7)
+#define AES_REG_CTRL_CTR_WIDTH_64 (1 << 7)
+#define AES_REG_CTRL_CTR_WIDTH_96 (2 << 7)
+#define AES_REG_CTRL_CTR_WIDTH_128 (3 << 7)
+#define AES_REG_CTRL_CTR (1 << 6)
+#define AES_REG_CTRL_CBC (1 << 5)
+#define AES_REG_CTRL_KEY_SIZE_MASK (3 << 3)
+#define AES_REG_CTRL_KEY_SIZE_128 (1 << 3)
+#define AES_REG_CTRL_KEY_SIZE_192 (2 << 3)
+#define AES_REG_CTRL_KEY_SIZE_256 (3 << 3)
+#define AES_REG_CTRL_DIRECTION (1 << 2)
+#define AES_REG_CTRL_INPUT_RDY (1 << 1)
+#define AES_REG_CTRL_OUTPUT_RDY (1 << 0)
+
+#define AES_REG_LENGTH_N(x) (0x54 + ((x) * 0x04))
+#define AES_REG_AUTH_LENGTH 0x5C
+#define AES_REG_DATA 0x60
+#define AES_REG_DATA_N(x) (0x60 + ((x) * 0x04))
+#define AES_REG_TAG 0x70
+#define AES_REG_TAG_N(x) (0x70 + ((x) * 0x04))
+
+#define AES_REG_REV 0x80
+#define AES_REG_REV_SCHEME_MASK (3 << 30)
+#define AES_REG_REV_FUNC_MASK (0xFFF << 16)
+#define AES_REG_REV_R_RTL_MASK (0x1F << 11)
+#define AES_REG_REV_X_MAJOR_MASK (7 << 8)
+#define AES_REG_REV_CUSTOM_MASK (3 << 6)
+#define AES_REG_REV_Y_MINOR_MASK (0x3F << 0)
+
+#define AES_REG_SYSCFG 0x84
+#define AES_REG_SYSCFG_K3 (1 << 12)
+#define AES_REG_SYSCFG_KEY_ENC (1 << 11)
+#define AES_REG_SYSCFG_KEK_MODE (1 << 10)
+#define AES_REG_SYSCFG_MAP_CTX_OUT (1 << 9)
+#define AES_REG_SYSCFG_DREQ_MASK (15 << 5)
+#define AES_REG_SYSCFG_DREQ_CTX_OUT_EN (1 << 8)
+#define AES_REG_SYSCFG_DREQ_CTX_IN_EN (1 << 7)
+#define AES_REG_SYSCFG_DREQ_DATA_OUT_EN (1 << 6)
+#define AES_REG_SYSCFG_DREQ_DATA_IN_EN (1 << 5)
+#define AES_REG_SYSCFG_DIRECTBUSEN (1 << 4)
+#define AES_REG_SYSCFG_SIDLE_MASK (3 << 2)
+#define AES_REG_SYSCFG_SIDLE_FORCEIDLE (0 << 2)
+#define AES_REG_SYSCFG_SIDLE_NOIDLE (1 << 2)
+#define AES_REG_SYSCFG_SIDLE_SMARTIDLE (2 << 2)
+#define AES_REG_SYSCFG_SOFTRESET (1 << 1)
+#define AES_REG_SYSCFG_AUTOIDLE (1 << 0)
+
+#define AES_REG_SYSSTATUS 0x88
+#define AES_REG_SYSSTATUS_RESETDONE (1 << 0)
+
+#define AES_REG_IRQSTATUS 0x8C
+#define AES_REG_IRQSTATUS_CTX_OUT (1 << 3)
+#define AES_REG_IRQSTATUS_DATA_OUT (1 << 2)
+#define AES_REG_IRQSTATUS_DATA_IN (1 << 1)
+#define AES_REG_IRQSTATUS_CTX_IN (1 << 0)
+
+#define AES_REG_IRQENA 0x90
+#define AES_REG_IRQENA_CTX_OUT (1 << 3)
+#define AES_REG_IRQENA_DATA_OUT (1 << 2)
+#define AES_REG_IRQENA_DATA_IN (1 << 1)
+#define AES_REG_IRQENA_CTX_IN (1 << 0)
+
+/* ==================================================================== */
+/** SHA / MD5 module layout.
+ */
+/* ==================================================================== */
+
+#define SHA_REG_ODIGEST 0x00
+#define SHA_REG_ODIGEST_N(x) (0x00 + ((x) * 0x04))
+#define SHA_REG_IDIGEST 0x20
+#define SHA_REG_IDIGEST_N(x) (0x20 + ((x) * 0x04))
+
+#define SHA_REG_DIGEST_COUNT 0x40
+#define SHA_REG_MODE 0x44
+#define SHA_REG_MODE_HMAC_OUTER_HASH (1 << 7)
+#define SHA_REG_MODE_HMAC_KEY_PROC (1 << 5)
+#define SHA_REG_MODE_CLOSE_HASH (1 << 4)
+#define SHA_REG_MODE_ALGO_CONSTANT (1 << 3)
+#define SHA_REG_MODE_ALGO_MASK (3 << 1)
+#define SHA_REG_MODE_ALGO_MD5_128 (0 << 1)
+#define SHA_REG_MODE_ALGO_SHA1_160 (1 << 1)
+#define SHA_REG_MODE_ALGO_SHA2_224 (2 << 1)
+#define SHA_REG_MODE_ALGO_SHA2_256 (3 << 1)
+
+#define SHA_REG_LENGTH 0x48
+
+#define SHA_REG_DATA 0x80
+#define SHA_REG_DATA_N(x) (0x80 + ((x) * 0x04))
+
+#define SHA_REG_REV 0x100
+#define SHA_REG_REV_SCHEME_MASK (3 << 30)
+#define SHA_REG_REV_FUNC_MASK (0xFFF << 16)
+#define SHA_REG_REV_R_RTL_MASK (0x1F << 11)
+#define SHA_REG_REV_X_MAJOR_MASK (7 << 8)
+#define SHA_REG_REV_CUSTOM_MASK (3 << 6)
+#define SHA_REG_REV_Y_MINOR_MASK (0x3F << 0)
+
+#define SHA_REG_SYSCFG 0x110
+#define SHA_REG_SYSCFG_SADVANCED (1 << 7)
+#define SHA_REG_SYSCFG_SCONT_SWT (1 << 6)
+#define SHA_REG_SYSCFG_SIDLE_MASK (3 << 4)
+#define SHA_REG_SYSCFG_SIDLE_FORCEIDLE (0 << 4)
+#define SHA_REG_SYSCFG_SIDLE_NOIDLE (1 << 4)
+#define SHA_REG_SYSCFG_SIDLE_SMARTIDLE (2 << 4)
+#define SHA_REG_SYSCFG_SDMA_EN (1 << 3)
+#define SHA_REG_SYSCFG_SIT_EN (1 << 2)
+#define SHA_REG_SYSCFG_SOFTRESET (1 << 1)
+#define SHA_REG_SYSCFG_AUTOIDLE (1 << 0)
+
+#define SHA_REG_SYSSTATUS 0x114
+#define SHA_REG_SYSSTATUS_RESETDONE (1 << 0)
+
+#define SHA_REG_IRQSTATUS 0x118
+#define SHA_REG_IRQSTATUS_CTX_RDY (1 << 3)
+#define SHA_REG_IRQSTATUS_PARTHASH_RDY (1 << 2)
+#define SHA_REG_IRQSTATUS_INPUT_RDY (1 << 1)
+#define SHA_REG_IRQSTATUS_OUTPUT_RDY (1 << 0)
+
+#define SHA_REG_IRQENA 0x11C
+#define SHA_REG_IRQENA_CTX_RDY (1 << 3)
+#define SHA_REG_IRQENA_PARTHASH_RDY (1 << 2)
+#define SHA_REG_IRQENA_INPUT_RDY (1 << 1)
+#define SHA_REG_IRQENA_OUTPUT_RDY (1 << 0)
+
+#endif /* __DRIVERS_CRYPTO_AM33X_H */
--
1.7.0.4
@@ -0,0 +1,324 @@
From d56c0ab935577ef32ffdf23a62d2e1cecc391730 Mon Sep 17 00:00:00 2001
From: Greg Turner <gregturner@ti.com>
Date: Thu, 17 May 2012 15:11:26 -0500
Subject: [PATCH 6/8] am33x: Create driver for TRNG crypto module
This is the initial version of the driver for the TRNG crypto module for a GP version of OMAP4 derivative SOC's such as AM335x.
Signed-off-by: Greg Turner <gregturner@ti.com>
---
drivers/char/hw_random/omap4-rng.c | 303 ++++++++++++++++++++++++++++++++++++
1 files changed, 303 insertions(+), 0 deletions(-)
create mode 100755 drivers/char/hw_random/omap4-rng.c
diff --git a/drivers/char/hw_random/omap4-rng.c b/drivers/char/hw_random/omap4-rng.c
new file mode 100755
index 0000000..523ec63
--- /dev/null
+++ b/drivers/char/hw_random/omap4-rng.c
@@ -0,0 +1,303 @@
+/*
+ * drivers/char/hw_random/omap4-rng.c
+ *
+ * Copyright (c) 2012 Texas Instruments
+ * TRNG driver for OMAP4 derivatives (AM33x, etc) - Herman Schuurman <herman@ti.com>
+ *
+ * derived from omap-rng.c.
+ *
+ * Author: Deepak Saxena <dsaxena@plexity.net>
+ *
+ * Copyright 2005 (c) MontaVista Software, Inc.
+ *
+ * Mostly based on original driver:
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ * Author: Juha Yrjölä <juha.yrjola@nokia.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/random.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/hw_random.h>
+#include <linux/delay.h>
+
+#include <mach/hardware.h>
+#include <asm/io.h>
+
+/* ==================================================================== */
+/** RNG module layout.
+ */
+/* ==================================================================== */
+#define RNG_REG_OUTPUT_L 0x00
+#define RNG_REG_OUTPUT_H 0x04
+
+#define RNG_REG_STATUS 0x08
+#define RNG_REG_STATUS_NEED_CLK (1 << 31)
+#define RNG_REG_STATUS_SHUTDOWN_OFLO (1 << 1)
+#define RNG_REG_STATUS_RDY (1 << 0)
+
+#define RNG_REG_IMASK 0x0C
+#define RNG_REG_IMASK_SHUTDOWN_OFLO (1 << 1)
+#define RNG_REG_IMASK_RDY (1 << 0)
+
+#define RNG_REG_INTACK 0x10
+#define RNG_REG_INTACK_SHUTDOWN_OFLO (1 << 1)
+#define RNG_REG_INTACK_RDY (1 << 0)
+
+#define RNG_REG_CONTROL 0x14
+#define RNG_REG_CONTROL_STARTUP_MASK 0xFFFF0000
+#define RNG_REG_CONTROL_ENABLE_TRNG (1 << 10)
+#define RNG_REG_CONTROL_NO_LFSR_FB (1 << 2)
+
+#define RNG_REG_CONFIG 0x18
+#define RNG_REG_CONFIG_MAX_REFILL_MASK 0xFFFF0000
+#define RNG_REG_CONFIG_SAMPLE_DIV 0x00000F00
+#define RNG_REG_CONFIG_MIN_REFILL_MASK 0x000000FF
+
+#define RNG_REG_ALARMCNT 0x1C
+#define RNG_REG_ALARMCNT_SHTDWN_MASK 0x3F000000
+#define RNG_REG_ALARMCNT_SD_THLD_MASK 0x001F0000
+#define RNG_REG_ALARMCNT_ALM_THLD_MASK 0x000000FF
+
+#define RNG_REG_FROENABLE 0x20
+#define RNG_REG_FRODETUNE 0x24
+#define RNG_REG_ALARMMASK 0x28
+#define RNG_REG_ALARMSTOP 0x2C
+#define RNG_REG_LFSR_L 0x30
+#define RNG_REG_LFSR_M 0x34
+#define RNG_REG_LFSR_H 0x38
+#define RNG_REG_COUNT 0x3C
+#define RNG_REG_TEST 0x40
+
+#define RNG_REG_OPTIONS 0x78
+#define RNG_REG_OPTIONS_NUM_FROS_MASK 0x00000FC0
+
+#define RNG_REG_EIP_REV 0x7C
+#define RNG_REG_STATUS_EN 0x1FD8
+#define RNG_REG_STATUS_EN_SHUTDOWN_OFLO (1 << 1)
+#define RNG_REG_STATUS_EN_RDY (1 << 0)
+
+#define RNG_REG_REV 0x1FE0
+#define RNG_REG_REV_X_MAJOR_MASK (0x0F << 4)
+#define RNG_REG_REV_Y_MINOR_MASK (0x0F << 0)
+
+#define RNG_REG_SYSCFG 0x1FE4
+#define RNG_REG_SYSCFG_SIDLEMODE_MASK (3 << 3)
+#define RNG_REG_SYSCFG_SIDLEMODE_FORCE (0 << 3)
+#define RNG_REG_SYSCFG_SIDLEMODE_NO (1 << 3)
+#define RNG_REG_SYSCFG_SIDLEMODE_SMART (2 << 3)
+#define RNG_REG_SYSCFG_AUTOIDLE (1 << 0)
+
+#define RNG_REG_STATUS_SET 0x1FEC
+#define RNG_REG_STATUS_SET_SHUTDOWN_OFLO (1 << 1)
+#define RNG_REG_STATUS_SET_RDY (1 << 0)
+
+#define RNG_REG_SOFT_RESET 0x1FF0
+#define RNG_REG_SOFTRESET (1 << 0)
+
+#define RNG_REG_IRQ_EOI 0x1FF4
+#define RNG_REG_IRQ_EOI_PULSE_INT_CLEAR (1 << 0)
+
+#define RNG_REG_IRQSTATUS 0x1FF8
+#define RNG_REG_IRQSTATUS_IRQ_EN (1 << 0)
+
+
+static void __iomem *rng_base;
+static struct clk *rng_fck;
+static struct platform_device *rng_dev;
+
+#define trng_read(reg) \
+({ \
+ u32 __val; \
+ __val = __raw_readl(rng_base + RNG_REG_##reg); \
+})
+
+#define trng_write(val, reg) \
+({ \
+ __raw_writel((val), rng_base + RNG_REG_##reg); \
+})
+
+static int omap4_rng_data_read(struct hwrng *rng, void *buf, size_t max, bool wait)
+{
+ int res, i;
+
+ for (i = 0; i < 20; i++) {
+ res = trng_read(STATUS) & RNG_REG_STATUS_RDY;
+ if (res || !wait)
+ break;
+ /* RNG produces data fast enough (2+ MBit/sec, even
+ * during "rngtest" loads, that these delays don't
+ * seem to trigger. We *could* use the RNG IRQ, but
+ * that'd be higher overhead ... so why bother?
+ */
+ udelay(10);
+ }
+
+ /* If we have data waiting, collect it... */
+ if (res) {
+ *(u32 *)buf = trng_read(OUTPUT_L);
+ buf += sizeof(u32);
+ *(u32 *)buf = trng_read(OUTPUT_H);
+
+ trng_write(RNG_REG_INTACK_RDY, INTACK);
+
+ res = 2 * sizeof(u32);
+ }
+ return res;
+}
+
+static struct hwrng omap4_rng_ops = {
+ .name = "omap4",
+ .read = omap4_rng_data_read,
+};
+
+static int __devinit omap4_rng_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ int ret;
+ u32 reg;
+
+ /*
+ * A bit ugly, and it will never actually happen but there can
+ * be only one RNG and this catches any bork
+ */
+ if (rng_dev)
+ return -EBUSY;
+
+ rng_fck = clk_get(&pdev->dev, "rng_fck");
+ if (IS_ERR(rng_fck)) {
+ dev_err(&pdev->dev, "Could not get rng_fck\n");
+ ret = PTR_ERR(rng_fck);
+ return ret;
+ } else
+ clk_enable(rng_fck);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ ret = -ENOENT;
+ goto err_region;
+ }
+
+ if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
+ ret = -EBUSY;
+ goto err_region;
+ }
+
+ dev_set_drvdata(&pdev->dev, res);
+ rng_base = ioremap(res->start, resource_size(res));
+ if (!rng_base) {
+ ret = -ENOMEM;
+ goto err_ioremap;
+ }
+
+ ret = hwrng_register(&omap4_rng_ops);
+ if (ret)
+ goto err_register;
+
+ reg = trng_read(REV);
+ dev_info(&pdev->dev, "OMAP4 Random Number Generator ver. %u.%02u\n",
+ ((reg & RNG_REG_REV_X_MAJOR_MASK) >> 4),
+ (reg & RNG_REG_REV_Y_MINOR_MASK));
+
+ rng_dev = pdev;
+
+ /* start TRNG if not running yet */
+ if (!(trng_read(CONTROL) & RNG_REG_CONTROL_ENABLE_TRNG)) {
+ trng_write(0x00220021, CONFIG);
+ trng_write(0x00210400, CONTROL);
+ }
+
+ return 0;
+
+err_register:
+ iounmap(rng_base);
+ rng_base = NULL;
+err_ioremap:
+ release_mem_region(res->start, resource_size(res));
+err_region:
+ clk_disable(rng_fck);
+ clk_put(rng_fck);
+ return ret;
+}
+
+static int __exit omap4_rng_remove(struct platform_device *pdev)
+{
+ struct resource *res = dev_get_drvdata(&pdev->dev);
+
+ hwrng_unregister(&omap4_rng_ops);
+
+ trng_write(trng_read(CONTROL) & ~RNG_REG_CONTROL_ENABLE_TRNG, CONTROL);
+
+ iounmap(rng_base);
+
+ clk_disable(rng_fck);
+ clk_put(rng_fck);
+ release_mem_region(res->start, resource_size(res));
+ rng_base = NULL;
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int omap4_rng_suspend(struct platform_device *pdev, pm_message_t message)
+{
+ trng_write(trng_read(CONTROL) & ~RNG_REG_CONTROL_ENABLE_TRNG, CONTROL);
+
+ return 0;
+}
+
+static int omap4_rng_resume(struct platform_device *pdev)
+{
+ trng_write(trng_read(CONTROL) | RNG_REG_CONTROL_ENABLE_TRNG, CONTROL);
+
+ return 0;
+}
+
+#else
+
+#define omap4_rng_suspend NULL
+#define omap4_rng_resume NULL
+
+#endif
+
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:omap4_rng");
+
+static struct platform_driver omap4_rng_driver = {
+ .driver = {
+ .name = "omap4_rng",
+ .owner = THIS_MODULE,
+ },
+ .probe = omap4_rng_probe,
+ .remove = __exit_p(omap4_rng_remove),
+ .suspend = omap4_rng_suspend,
+ .resume = omap4_rng_resume
+};
+
+static int __init omap4_rng_init(void)
+{
+ if (!cpu_is_am33xx() || omap_type() != OMAP2_DEVICE_TYPE_GP)
+ return -ENODEV;
+
+ return platform_driver_register(&omap4_rng_driver);
+}
+
+static void __exit omap4_rng_exit(void)
+{
+ platform_driver_unregister(&omap4_rng_driver);
+}
+
+module_init(omap4_rng_init);
+module_exit(omap4_rng_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("AM33X TRNG driver");
--
1.7.0.4
@@ -0,0 +1,971 @@
From 501def5dd499457a38e6284f9780ba169284e530 Mon Sep 17 00:00:00 2001
From: Greg Turner <gregturner@ti.com>
Date: Thu, 17 May 2012 15:17:13 -0500
Subject: [PATCH 7/8] am33x: Create driver for AES crypto module
This is the initial version of the driver for the AES crypto module for a GP version of OMAP4 derivative SOC's such as AM335x.
Signed-off-by: Greg Turner <gregturner@ti.com>
---
drivers/crypto/omap4-aes.c | 950 ++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 950 insertions(+), 0 deletions(-)
create mode 100755 drivers/crypto/omap4-aes.c
diff --git a/drivers/crypto/omap4-aes.c b/drivers/crypto/omap4-aes.c
new file mode 100755
index 0000000..f0b3fe2
--- /dev/null
+++ b/drivers/crypto/omap4-aes.c
@@ -0,0 +1,950 @@
+/*
+ * Cryptographic API.
+ *
+ * Support for OMAP AES HW acceleration.
+ *
+ * Copyright (c) 2010 Nokia Corporation
+ * Author: Dmitry Kasatkin <dmitry.kasatkin@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ */
+/*
+ * Copyright © 2011 Texas Instruments Incorporated
+ * Author: Herman Schuurman
+ * Change: July 2011 - Adapted the omap-aes.c driver to support Netra
+ * implementation of AES hardware accelerator.
+ */
+/*
+ * Copyright © 2011 Texas Instruments Incorporated
+ * Author: Greg Turner
+ * Change: November 2011 - Adapted for AM33x support HW accelerator.
+ */
+
+//#define DEBUG
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/crypto.h>
+#include <linux/interrupt.h>
+#include <crypto/scatterwalk.h>
+#include <crypto/aes.h>
+
+#include <plat/cpu.h>
+#include <plat/dma.h>
+#include <mach/edma.h>
+#include <mach/hardware.h>
+#include "omap4.h"
+
+#define DEFAULT_TIMEOUT (5*HZ)
+
+#define FLAGS_MODE_MASK 0x000f
+#define FLAGS_ENCRYPT BIT(0)
+#define FLAGS_CBC BIT(1)
+#define FLAGS_CTR BIT(2)
+#define FLAGS_GIV BIT(3)
+
+#define FLAGS_INIT BIT(4)
+#define FLAGS_FAST BIT(5)
+#define FLAGS_BUSY BIT(6)
+
+struct omap4_aes_ctx {
+ struct omap4_aes_dev *dd;
+
+ int keylen;
+ u32 key[AES_KEYSIZE_256 / sizeof(u32)];
+ unsigned long flags;
+};
+
+struct omap4_aes_reqctx {
+ unsigned long mode;
+};
+
+#define AM33X_AES_QUEUE_LENGTH 1
+#define AM33X_AES_CACHE_SIZE 0
+
+struct omap4_aes_dev {
+ struct list_head list;
+ unsigned long phys_base;
+ void __iomem *io_base;
+ struct clk *iclk;
+ struct omap4_aes_ctx *ctx;
+ struct device *dev;
+ unsigned long flags;
+ int err;
+
+ spinlock_t lock;
+ struct crypto_queue queue;
+
+ struct tasklet_struct done_task;
+ struct tasklet_struct queue_task;
+
+ struct ablkcipher_request *req;
+ size_t total;
+ struct scatterlist *in_sg;
+ size_t in_offset;
+ struct scatterlist *out_sg;
+ size_t out_offset;
+
+ size_t buflen;
+ void *buf_in;
+ size_t dma_size;
+ int dma_in;
+ int dma_lch_in;
+ dma_addr_t dma_addr_in;
+ void *buf_out;
+ int dma_out;
+ int dma_lch_out;
+ dma_addr_t dma_addr_out;
+};
+
+/* keep registered devices data here */
+static LIST_HEAD(dev_list);
+static DEFINE_SPINLOCK(list_lock);
+
+static inline u32 omap4_aes_read(struct omap4_aes_dev *dd, u32 offset)
+{
+ return __raw_readl(dd->io_base + offset);
+}
+
+static inline void omap4_aes_write(struct omap4_aes_dev *dd, u32 offset,
+ u32 value)
+{
+ __raw_writel(value, dd->io_base + offset);
+}
+
+static inline void omap4_aes_write_mask(struct omap4_aes_dev *dd, u32 offset,
+ u32 value, u32 mask)
+{
+ u32 val;
+
+ val = omap4_aes_read(dd, offset);
+ val &= ~mask;
+ val |= value;
+ omap4_aes_write(dd, offset, val);
+}
+
+static void omap4_aes_write_n(struct omap4_aes_dev *dd, u32 offset,
+ u32 *value, int count)
+{
+ for (; count--; value++, offset += 4)
+ omap4_aes_write(dd, offset, *value);
+}
+
+static int omap4_aes_hw_init(struct omap4_aes_dev *dd)
+{
+ /*
+ * clocks are enabled when request starts and disabled when finished.
+ * It may be long delays between requests.
+ * Device might go to off mode to save power.
+ */
+ clk_enable(dd->iclk);
+ omap4_aes_write(dd, AES_REG_SYSCFG, 0);
+
+ if (!(dd->flags & FLAGS_INIT)) {
+ dd->flags |= FLAGS_INIT;
+ dd->err = 0;
+ }
+
+ return 0;
+}
+
+static int omap4_aes_write_ctrl(struct omap4_aes_dev *dd)
+{
+ unsigned int key32;
+ int i, err;
+ u32 val, mask;
+
+ err = omap4_aes_hw_init(dd);
+ if (err)
+ return err;
+
+ pr_debug("Set key\n");
+ key32 = dd->ctx->keylen / sizeof(u32);
+
+ /* set a key */
+ for (i = 0; i < key32; i++) {
+ omap4_aes_write(dd, AES_REG_KEY1(i),
+ __le32_to_cpu(dd->ctx->key[i]));
+ }
+
+ if ((dd->flags & (FLAGS_CBC | FLAGS_CTR)) && dd->req->info)
+ omap4_aes_write_n(dd, AES_REG_IV(0), dd->req->info, 4);
+
+ val = FLD_VAL(((dd->ctx->keylen >> 3) - 1), 4, 3);
+ if (dd->flags & FLAGS_CBC)
+ val |= AES_REG_CTRL_CBC;
+ else if (dd->flags & FLAGS_CTR)
+ val |= AES_REG_CTRL_CTR | AES_REG_CTRL_CTR_WIDTH_32;
+ if (dd->flags & FLAGS_ENCRYPT)
+ val |= AES_REG_CTRL_DIRECTION;
+
+ mask = AES_REG_CTRL_CBC | AES_REG_CTRL_CTR | AES_REG_CTRL_DIRECTION |
+ AES_REG_CTRL_KEY_SIZE_MASK | AES_REG_CTRL_CTR_WIDTH_MASK;
+
+ omap4_aes_write_mask(dd, AES_REG_CTRL, val, mask);
+
+ return 0;
+}
+
+static struct omap4_aes_dev *omap4_aes_find_dev(struct omap4_aes_ctx *ctx)
+{
+ struct omap4_aes_dev *dd = NULL, *tmp;
+
+ spin_lock_bh(&list_lock);
+ if (!ctx->dd) {
+ list_for_each_entry(tmp, &dev_list, list) {
+ /* FIXME: take fist available aes core */
+ dd = tmp;
+ break;
+ }
+ ctx->dd = dd;
+ } else {
+ /* already found before */
+ dd = ctx->dd;
+ }
+ spin_unlock_bh(&list_lock);
+
+ return dd;
+}
+
+static void omap4_aes_dma_callback(unsigned int lch, u16 ch_status, void *data)
+{
+ struct omap4_aes_dev *dd = data;
+
+ edma_stop(lch);
+
+ if (ch_status != DMA_COMPLETE) {
+ pr_err("omap4-aes DMA error status: 0x%hx\n", ch_status);
+ dd->err = -EIO;
+ dd->flags &= ~FLAGS_INIT; /* request to re-initialize */
+ } else if (lch == dd->dma_lch_in) {
+ return;
+ }
+
+ /* dma_lch_out - completed */
+ tasklet_schedule(&dd->done_task);
+}
+
+static int omap4_aes_dma_init(struct omap4_aes_dev *dd)
+{
+ int err = -ENOMEM;
+
+ dd->dma_lch_out = -1;
+ dd->dma_lch_in = -1;
+
+ dd->buf_in = (void *)__get_free_pages(GFP_KERNEL, AM33X_AES_CACHE_SIZE);
+ dd->buf_out = (void *)__get_free_pages(GFP_KERNEL, AM33X_AES_CACHE_SIZE);
+ dd->buflen = PAGE_SIZE << AM33X_AES_CACHE_SIZE;
+ dd->buflen &= ~(AES_BLOCK_SIZE - 1);
+
+ if (!dd->buf_in || !dd->buf_out) {
+ dev_err(dd->dev, "unable to alloc pages.\n");
+ goto err_alloc;
+ }
+
+ /* MAP here */
+ dd->dma_addr_in = dma_map_single(dd->dev, dd->buf_in, dd->buflen,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(dd->dev, dd->dma_addr_in)) {
+ dev_err(dd->dev, "dma %d bytes error\n", dd->buflen);
+ err = -EINVAL;
+ goto err_map_in;
+ }
+
+ dd->dma_addr_out = dma_map_single(dd->dev, dd->buf_out, dd->buflen,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(dd->dev, dd->dma_addr_out)) {
+ dev_err(dd->dev, "dma %d bytes error\n", dd->buflen);
+ err = -EINVAL;
+ goto err_map_out;
+ }
+
+ dd->dma_lch_in = edma_alloc_channel(dd->dma_in, omap4_aes_dma_callback,
+ dd, EVENTQ_DEFAULT);
+
+ if (dd->dma_lch_in < 0) {
+ dev_err(dd->dev, "Unable to request DMA channel\n");
+ goto err_dma_in;
+ }
+
+ dd->dma_lch_out = edma_alloc_channel(dd->dma_out, omap4_aes_dma_callback, dd, EVENTQ_2);
+
+ if (dd->dma_lch_out < 0) {
+ dev_err(dd->dev, "Unable to request DMA channel\n");
+ goto err_dma_out;
+ }
+
+ return 0;
+
+err_dma_out:
+ edma_free_channel(dd->dma_lch_in);
+err_dma_in:
+ dma_unmap_single(dd->dev, dd->dma_addr_out, dd->buflen,
+ DMA_FROM_DEVICE);
+err_map_out:
+ dma_unmap_single(dd->dev, dd->dma_addr_in, dd->buflen, DMA_TO_DEVICE);
+err_map_in:
+ free_pages((unsigned long)dd->buf_out, AM33X_AES_CACHE_SIZE);
+ free_pages((unsigned long)dd->buf_in, AM33X_AES_CACHE_SIZE);
+err_alloc:
+ if (err)
+ pr_err("error: %d\n", err);
+ return err;
+}
+
+static void omap4_aes_dma_cleanup(struct omap4_aes_dev *dd)
+{
+ edma_free_channel(dd->dma_lch_out);
+ edma_free_channel(dd->dma_lch_in);
+ dma_unmap_single(dd->dev, dd->dma_addr_out, dd->buflen,
+ DMA_FROM_DEVICE);
+ dma_unmap_single(dd->dev, dd->dma_addr_in, dd->buflen, DMA_TO_DEVICE);
+ free_pages((unsigned long)dd->buf_out, AM33X_AES_CACHE_SIZE);
+ free_pages((unsigned long)dd->buf_in, AM33X_AES_CACHE_SIZE);
+}
+
+static void sg_copy_buf(void *buf, struct scatterlist *sg,
+ unsigned int start, unsigned int nbytes, int out)
+{
+ struct scatter_walk walk;
+
+ if (!nbytes)
+ return;
+
+ scatterwalk_start(&walk, sg);
+ scatterwalk_advance(&walk, start);
+ scatterwalk_copychunks(buf, &walk, nbytes, out);
+ scatterwalk_done(&walk, out, 0);
+}
+
+static int sg_copy(struct scatterlist **sg, size_t *offset, void *buf,
+ size_t buflen, size_t total, int out)
+{
+ unsigned int count, off = 0;
+
+ while (buflen && total) {
+ count = min((*sg)->length - *offset, total);
+ count = min(count, buflen);
+
+ if (!count)
+ return off;
+
+ /*
+ * buflen and total are AES_BLOCK_SIZE size aligned,
+ * so count should be also aligned
+ */
+
+ sg_copy_buf(buf + off, *sg, *offset, count, out);
+
+ off += count;
+ buflen -= count;
+ *offset += count;
+ total -= count;
+
+ if (*offset == (*sg)->length) {
+ *sg = sg_next(*sg);
+ if (*sg)
+ *offset = 0;
+ else
+ total = 0;
+ }
+ }
+
+ return off;
+}
+
+static int omap4_aes_crypt_dma(struct crypto_tfm *tfm, dma_addr_t dma_addr_in,
+ dma_addr_t dma_addr_out, int length)
+{
+ struct omap4_aes_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct omap4_aes_dev *dd = ctx->dd;
+ int nblocks;
+ struct edmacc_param p_ram;
+
+ pr_debug("len: %d\n", length);
+
+ dd->dma_size = length;
+
+ if (!(dd->flags & FLAGS_FAST))
+ dma_sync_single_for_device(dd->dev, dma_addr_in, length,
+ DMA_TO_DEVICE);
+
+ nblocks = DIV_ROUND_UP(length, AES_BLOCK_SIZE);
+
+ /* EDMA IN */
+ p_ram.opt = TCINTEN |
+ EDMA_TCC(EDMA_CHAN_SLOT(dd->dma_lch_in));
+ p_ram.src = dma_addr_in;
+ p_ram.a_b_cnt = AES_BLOCK_SIZE | nblocks << 16;
+ p_ram.dst = dd->phys_base + AES_REG_DATA;
+ p_ram.src_dst_bidx = AES_BLOCK_SIZE;
+ p_ram.link_bcntrld = 1 << 16 | 0xFFFF;
+ p_ram.src_dst_cidx = 0;
+ p_ram.ccnt = 1;
+ edma_write_slot(dd->dma_lch_in, &p_ram);
+
+ /* EDMA OUT */
+ p_ram.opt = TCINTEN |
+ EDMA_TCC(EDMA_CHAN_SLOT(dd->dma_lch_out));
+ p_ram.src = dd->phys_base + AES_REG_DATA;
+ p_ram.dst = dma_addr_out;
+ p_ram.src_dst_bidx = AES_BLOCK_SIZE << 16;
+ edma_write_slot(dd->dma_lch_out, &p_ram);
+
+ edma_start(dd->dma_lch_in);
+ edma_start(dd->dma_lch_out);
+
+ /* write data length info out */
+ omap4_aes_write(dd, AES_REG_LENGTH_N(0), length);
+ omap4_aes_write(dd, AES_REG_LENGTH_N(1), 0);
+ /* start DMA or disable idle mode */
+ omap4_aes_write_mask(dd, AES_REG_SYSCFG,
+ AES_REG_SYSCFG_DREQ_DATA_OUT_EN | AES_REG_SYSCFG_DREQ_DATA_IN_EN,
+ AES_REG_SYSCFG_DREQ_MASK);
+
+ return 0;
+}
+
+static int omap4_aes_crypt_dma_start(struct omap4_aes_dev *dd)
+{
+ struct crypto_tfm *tfm = crypto_ablkcipher_tfm(
+ crypto_ablkcipher_reqtfm(dd->req));
+ int err, fast = 0, in, out;
+ size_t count;
+ dma_addr_t addr_in, addr_out;
+
+ pr_debug("total: %d\n", dd->total);
+
+ if (sg_is_last(dd->in_sg) && sg_is_last(dd->out_sg)) {
+ /* check for alignment */
+ in = IS_ALIGNED((u32)dd->in_sg->offset, sizeof(u32));
+ out = IS_ALIGNED((u32)dd->out_sg->offset, sizeof(u32));
+
+ fast = in && out;
+ }
+
+ if (fast) {
+ count = min(dd->total, sg_dma_len(dd->in_sg));
+ count = min(count, sg_dma_len(dd->out_sg));
+
+ if (count != dd->total) {
+ pr_err("request length != buffer length\n");
+ return -EINVAL;
+ }
+
+ pr_debug("fast\n");
+
+ err = dma_map_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
+ if (!err) {
+ dev_err(dd->dev, "dma_map_sg() error\n");
+ return -EINVAL;
+ }
+
+ err = dma_map_sg(dd->dev, dd->out_sg, 1, DMA_FROM_DEVICE);
+ if (!err) {
+ dev_err(dd->dev, "dma_map_sg() error\n");
+ dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
+ return -EINVAL;
+ }
+
+ addr_in = sg_dma_address(dd->in_sg);
+ addr_out = sg_dma_address(dd->out_sg);
+
+ dd->flags |= FLAGS_FAST;
+
+ } else {
+ /* use cache buffers */
+ count = sg_copy(&dd->in_sg, &dd->in_offset, dd->buf_in,
+ dd->buflen, dd->total, 0);
+
+ addr_in = dd->dma_addr_in;
+ addr_out = dd->dma_addr_out;
+
+ dd->flags &= ~FLAGS_FAST;
+
+ }
+
+ dd->total -= count;
+
+ err = omap4_aes_crypt_dma(tfm, addr_in, addr_out, count);
+ if (err) {
+ dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
+ dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_TO_DEVICE);
+ }
+
+ return err;
+}
+
+static void omap4_aes_finish_req(struct omap4_aes_dev *dd, int err)
+{
+ struct ablkcipher_request *req = dd->req;
+
+ pr_debug("err: %d\n", err);
+
+ clk_disable(dd->iclk);
+ dd->flags &= ~FLAGS_BUSY;
+
+ req->base.complete(&req->base, err);
+}
+
+static int omap4_aes_crypt_dma_stop(struct omap4_aes_dev *dd)
+{
+ int err = 0;
+ size_t count;
+
+ pr_debug("total: %d\n", dd->total);
+
+ omap4_aes_write_mask(dd, AES_REG_SYSCFG, 0, AES_REG_SYSCFG_DREQ_MASK);
+
+ edma_stop(dd->dma_lch_in);
+ edma_clean_channel(dd->dma_lch_in);
+ edma_stop(dd->dma_lch_out);
+ edma_clean_channel(dd->dma_lch_out);
+
+ if (dd->flags & FLAGS_FAST) {
+ dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_FROM_DEVICE);
+ dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
+ } else {
+ dma_sync_single_for_device(dd->dev, dd->dma_addr_out,
+ dd->dma_size, DMA_FROM_DEVICE);
+
+ /* copy data */
+ count = sg_copy(&dd->out_sg, &dd->out_offset, dd->buf_out,
+ dd->buflen, dd->dma_size, 1);
+ if (count != dd->dma_size) {
+ err = -EINVAL;
+ pr_err("not all data converted: %u\n", count);
+ }
+ }
+
+ return err;
+}
+
+static int omap4_aes_handle_queue(struct omap4_aes_dev *dd,
+ struct ablkcipher_request *req)
+{
+ struct crypto_async_request *async_req, *backlog;
+ struct omap4_aes_ctx *ctx;
+ struct omap4_aes_reqctx *rctx;
+ unsigned long flags;
+ int err, ret = 0;
+
+ spin_lock_irqsave(&dd->lock, flags);
+ if (req)
+ ret = ablkcipher_enqueue_request(&dd->queue, req);
+
+ if (dd->flags & FLAGS_BUSY) {
+ spin_unlock_irqrestore(&dd->lock, flags);
+ return ret;
+ }
+ backlog = crypto_get_backlog(&dd->queue);
+ async_req = crypto_dequeue_request(&dd->queue);
+ if (async_req)
+ dd->flags |= FLAGS_BUSY;
+ spin_unlock_irqrestore(&dd->lock, flags);
+
+ if (!async_req)
+ return ret;
+
+ if (backlog)
+ backlog->complete(backlog, -EINPROGRESS);
+
+ req = ablkcipher_request_cast(async_req);
+
+ /* assign new request to device */
+ dd->req = req;
+ dd->total = req->nbytes;
+ dd->in_offset = 0;
+ dd->in_sg = req->src;
+ dd->out_offset = 0;
+ dd->out_sg = req->dst;
+
+ rctx = ablkcipher_request_ctx(req);
+ ctx = crypto_ablkcipher_ctx(crypto_ablkcipher_reqtfm(req));
+ rctx->mode &= FLAGS_MODE_MASK;
+ dd->flags = (dd->flags & ~FLAGS_MODE_MASK) | rctx->mode;
+
+ dd->ctx = ctx;
+ ctx->dd = dd;
+
+ err = omap4_aes_write_ctrl(dd);
+ if (!err)
+ err = omap4_aes_crypt_dma_start(dd);
+ if (err) {
+ /* aes_task will not finish it, so do it here */
+ omap4_aes_finish_req(dd, err);
+ tasklet_schedule(&dd->queue_task);
+ }
+
+ return ret; /* return ret, which is enqueue return value */
+}
+
+static void omap4_aes_done_task(unsigned long data)
+{
+ struct omap4_aes_dev *dd = (struct omap4_aes_dev *)data;
+ int err;
+
+ pr_debug("enter\n");
+
+ err = omap4_aes_crypt_dma_stop(dd);
+
+ err = dd->err ? : err;
+
+ if (dd->total && !err) {
+ err = omap4_aes_crypt_dma_start(dd);
+ if (!err)
+ return; /* DMA started. Not finishing. */
+ }
+
+ omap4_aes_finish_req(dd, err);
+ omap4_aes_handle_queue(dd, NULL);
+
+ pr_debug("exit\n");
+}
+
+static void omap4_aes_queue_task(unsigned long data)
+{
+ struct omap4_aes_dev *dd = (struct omap4_aes_dev *)data;
+
+ omap4_aes_handle_queue(dd, NULL);
+}
+
+static int omap4_aes_crypt(struct ablkcipher_request *req, unsigned long mode)
+{
+ struct omap4_aes_ctx *ctx = crypto_ablkcipher_ctx(
+ crypto_ablkcipher_reqtfm(req));
+ struct omap4_aes_reqctx *rctx = ablkcipher_request_ctx(req);
+ struct omap4_aes_dev *dd;
+
+ pr_debug("nbytes: %d, enc: %d, cbc: %d, ctr: %d\n", req->nbytes,
+ !!(mode & FLAGS_ENCRYPT),
+ !!(mode & FLAGS_CBC),
+ !!(mode & FLAGS_CTR));
+
+ if (!IS_ALIGNED(req->nbytes, AES_BLOCK_SIZE)) {
+ pr_err("request size is not exact amount of AES blocks\n");
+ return -EINVAL;
+ }
+
+ dd = omap4_aes_find_dev(ctx);
+ if (!dd)
+ return -ENODEV;
+
+ rctx->mode = mode;
+
+ return omap4_aes_handle_queue(dd, req);
+}
+
+/* ********************** ALG API ************************************ */
+
+static int omap4_aes_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ struct omap4_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm);
+
+ if (keylen != AES_KEYSIZE_128 && keylen != AES_KEYSIZE_192 &&
+ keylen != AES_KEYSIZE_256)
+ return -EINVAL;
+
+ pr_debug("enter, keylen: %d\n", keylen);
+
+ memcpy(ctx->key, key, keylen);
+ ctx->keylen = keylen;
+
+ return 0;
+}
+
+static int omap4_aes_ecb_encrypt(struct ablkcipher_request *req)
+{
+ return omap4_aes_crypt(req, FLAGS_ENCRYPT);
+}
+
+static int omap4_aes_ecb_decrypt(struct ablkcipher_request *req)
+{
+ return omap4_aes_crypt(req, 0);
+}
+
+static int omap4_aes_cbc_encrypt(struct ablkcipher_request *req)
+{
+ return omap4_aes_crypt(req, FLAGS_ENCRYPT | FLAGS_CBC);
+}
+
+static int omap4_aes_cbc_decrypt(struct ablkcipher_request *req)
+{
+ return omap4_aes_crypt(req, FLAGS_CBC);
+}
+
+static int omap4_aes_ctr_encrypt(struct ablkcipher_request *req)
+{
+ return omap4_aes_crypt(req, FLAGS_ENCRYPT | FLAGS_CTR);
+}
+
+static int omap4_aes_ctr_decrypt(struct ablkcipher_request *req)
+{
+ return omap4_aes_crypt(req, FLAGS_CTR);
+}
+
+static int omap4_aes_cra_init(struct crypto_tfm *tfm)
+{
+ pr_debug("enter\n");
+
+ tfm->crt_ablkcipher.reqsize = sizeof(struct omap4_aes_reqctx);
+
+ return 0;
+}
+
+static void omap4_aes_cra_exit(struct crypto_tfm *tfm)
+{
+ pr_debug("enter\n");
+}
+
+/* ********************** ALGS ************************************ */
+
+static struct crypto_alg algs[] = {
+ {
+ .cra_name = "ecb(aes)",
+ .cra_driver_name = "ecb-aes-omap4",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct omap4_aes_ctx),
+ .cra_alignmask = 0,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = omap4_aes_cra_init,
+ .cra_exit = omap4_aes_cra_exit,
+ .cra_u.ablkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .setkey = omap4_aes_setkey,
+ .encrypt = omap4_aes_ecb_encrypt,
+ .decrypt = omap4_aes_ecb_decrypt,
+ }
+ },
+ {
+ .cra_name = "cbc(aes)",
+ .cra_driver_name = "cbc-aes-omap4",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct omap4_aes_ctx),
+ .cra_alignmask = 0,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = omap4_aes_cra_init,
+ .cra_exit = omap4_aes_cra_exit,
+ .cra_u.ablkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .geniv = "eseqiv",
+ .ivsize = AES_BLOCK_SIZE,
+ .setkey = omap4_aes_setkey,
+ .encrypt = omap4_aes_cbc_encrypt,
+ .decrypt = omap4_aes_cbc_decrypt,
+
+ }
+ },
+ {
+ .cra_name = "ctr(aes)",
+ .cra_driver_name = "ctr-aes-omap4",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct omap4_aes_ctx),
+ .cra_alignmask = 0,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = omap4_aes_cra_init,
+ .cra_exit = omap4_aes_cra_exit,
+ .cra_u.ablkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .geniv = "eseqiv",
+ .ivsize = AES_BLOCK_SIZE,
+ .setkey = omap4_aes_setkey,
+ .encrypt = omap4_aes_ctr_encrypt,
+ .decrypt = omap4_aes_ctr_decrypt,
+ }
+ }
+};
+
+static int omap4_aes_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct omap4_aes_dev *dd;
+ struct resource *res;
+ int err = -ENOMEM, i, j;
+ u32 reg;
+
+ dd = kzalloc(sizeof(struct omap4_aes_dev), GFP_KERNEL);
+ if (dd == NULL) {
+ dev_err(dev, "unable to alloc data struct.\n");
+ goto err_data;
+ }
+ dd->dev = dev;
+ platform_set_drvdata(pdev, dd);
+
+ spin_lock_init(&dd->lock);
+ crypto_init_queue(&dd->queue, AM33X_AES_QUEUE_LENGTH);
+
+ /* Get the base address */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(dev, "invalid resource type\n");
+ err = -ENODEV;
+ goto err_res;
+ }
+ dd->phys_base = res->start;
+
+ /* Get the DMA */
+ res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (!res)
+ dev_info(dev, "no DMA info\n");
+ else
+ dd->dma_out = res->start;
+
+ /* Get the DMA */
+ res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+ if (!res)
+ dev_info(dev, "no DMA info\n");
+ else
+ dd->dma_in = res->start;
+
+ /* Initializing the clock */
+ dd->iclk = clk_get(dev, "aes0_fck");
+ if (IS_ERR(dd->iclk)) {
+ dev_err(dev, "clock initialization failed.\n");
+ err = PTR_ERR(dd->iclk);
+ goto err_res;
+ }
+
+ dd->io_base = ioremap(dd->phys_base, SZ_4K);
+ if (!dd->io_base) {
+ dev_err(dev, "can't ioremap\n");
+ err = -ENOMEM;
+ goto err_io;
+ }
+
+ omap4_aes_hw_init(dd);
+ reg = omap4_aes_read(dd, AES_REG_REV);
+ clk_disable(dd->iclk);
+ dev_info(dev, "AM33X AES hw accel rev: %u.%02u\n",
+ ((reg & AES_REG_REV_X_MAJOR_MASK) >> 8),
+ (reg & AES_REG_REV_Y_MINOR_MASK));
+
+ tasklet_init(&dd->done_task, omap4_aes_done_task, (unsigned long)dd);
+ tasklet_init(&dd->queue_task, omap4_aes_queue_task, (unsigned long)dd);
+
+ err = omap4_aes_dma_init(dd);
+ if (err)
+ goto err_dma;
+
+ INIT_LIST_HEAD(&dd->list);
+ spin_lock(&list_lock);
+ list_add_tail(&dd->list, &dev_list);
+ spin_unlock(&list_lock);
+
+ for (i = 0; i < ARRAY_SIZE(algs); i++) {
+ pr_debug("reg alg: %s\n", algs[i].cra_name);
+ INIT_LIST_HEAD(&algs[i].cra_list);
+ err = crypto_register_alg(&algs[i]);
+ if (err)
+ goto err_algs;
+ }
+
+ pr_info("probe() done\n");
+
+ return 0;
+
+err_algs:
+ for (j = 0; j < i; j++)
+ crypto_unregister_alg(&algs[j]);
+ omap4_aes_dma_cleanup(dd);
+err_dma:
+ tasklet_kill(&dd->done_task);
+ tasklet_kill(&dd->queue_task);
+ iounmap(dd->io_base);
+
+err_io:
+ clk_put(dd->iclk);
+err_res:
+ kfree(dd);
+ dd = NULL;
+err_data:
+ dev_err(dev, "initialization failed.\n");
+ return err;
+}
+
+static int omap4_aes_remove(struct platform_device *pdev)
+{
+ struct omap4_aes_dev *dd = platform_get_drvdata(pdev);
+ int i;
+
+ if (!dd)
+ return -ENODEV;
+
+ spin_lock(&list_lock);
+ list_del(&dd->list);
+ spin_unlock(&list_lock);
+
+ for (i = 0; i < ARRAY_SIZE(algs); i++)
+ crypto_unregister_alg(&algs[i]);
+
+ tasklet_kill(&dd->done_task);
+ tasklet_kill(&dd->queue_task);
+ omap4_aes_dma_cleanup(dd);
+ iounmap(dd->io_base);
+ clk_put(dd->iclk);
+ kfree(dd);
+ dd = NULL;
+
+ return 0;
+}
+
+static struct platform_driver omap4_aes_driver = {
+ .probe = omap4_aes_probe,
+ .remove = omap4_aes_remove,
+ .driver = {
+ .name = "omap4-aes",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init omap4_aes_mod_init(void)
+{
+ pr_info("loading AM33X AES driver\n");
+
+ /* This only works on a GP device */
+ if (!cpu_is_am33xx() || omap_type() != OMAP2_DEVICE_TYPE_GP) {
+ pr_err("Unsupported cpu\n");
+ return -ENODEV;
+ }
+ return platform_driver_register(&omap4_aes_driver);
+}
+
+static void __exit omap4_aes_mod_exit(void)
+{
+ pr_info("unloading AM33X AES driver\n");
+
+ platform_driver_unregister(&omap4_aes_driver);
+}
+
+module_init(omap4_aes_mod_init);
+module_exit(omap4_aes_mod_exit);
+
+MODULE_DESCRIPTION("AM33X AES acceleration support.");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Herman Schuurman");
--
1.7.0.4
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,81 @@
SECTION = "kernel"
DESCRIPTION = "Linux kernel for TI33x devices from PSP"
LICENSE = "GPLv2"
LIC_FILES_CHKSUM = "file://COPYING;md5=d7810fab7487fb0aad327b76f1be7cd7"
COMPATIBLE_MACHINE = "ti33x"
DEFAULT_PREFERENCE = "-1"
inherit kernel
# Stage the power management firmware before building the kernel
DEPENDS += "am33x-cm3"
KERNEL_IMAGETYPE = "uImage"
# The main PR is now using MACHINE_KERNEL_PR, for ti33x see conf/machine/include/ti33x.inc
MACHINE_KERNEL_PR_append = "a+gitr${SRCREV}"
BRANCH = "v3.2-staging"
# This SRCREV corresponds to tag v3.2_AM335xPSP_04.06.00.08
SRCREV = "d7e124e8074cccf9958290e773c88a4b2b36412b"
SRC_URI = "git://arago-project.org/git/projects/linux-am33x.git;protocol=git;branch=${BRANCH} \
file://defconfig \
${KERNEL_PATCHES} \
"
S = "${WORKDIR}/git"
# Allow a layer to easily add to the list of patches or completely override them.
KERNEL_PATCHES ?= "${PATCHES}"
# Add a set of patches that enabled features, fixed bugs or disabled buggy features
# that weren't part of the official PSP release
PATCHES = "file://0001-musb-update-PIO-mode-help-information-in-Kconfig.patch \
file://0001-am335x_evm_defconfig-turn-off-MUSB-DMA.patch \
file://0001-mach-omap2-pm33xx-Disable-VT-switch.patch"
# Add Cryptography support early driver patches while working to get the driver
# upstream.
PATCHES += "file://0001-am33x-Add-memory-addresses-for-crypto-modules.patch \
file://0002-am33x-Add-crypto-device-and-resource-structures.patch \
file://0003-am33x-Add-crypto-device-and-resource-structure-for-T.patch \
file://0004-am33x-Add-crypto-drivers-to-Kconfig-and-Makefiles.patch \
file://0005-am33x-Create-header-file-for-OMAP4-crypto-modules.patch \
file://0006-am33x-Create-driver-for-TRNG-crypto-module.patch \
file://0007-am33x-Create-driver-for-AES-crypto-module.patch \
file://0008-am33x-Create-driver-for-SHA-MD5-crypto-module.patch \
file://0002-AM335x-OCF-Driver-for-Linux-3.patch \
file://0001-am335x-Add-crypto-driver-settings-to-defconfig.patch \
file://0001-am335x-Add-pm_runtime-API-to-crypto-driver.patch \
file://0002-am335x-Add-suspend-resume-routines-to-crypto-driver.patch \
"
# Add SmartReflex support early driver patches while working to get the driver
# upstream.
PATCHES += "file://0001-am33xx-Add-SmartReflex-support.patch \
file://0002-am33xx-Enable-CONFIG_AM33XX_SMARTREFLEX.patch \
"
# Add a patch to the omap-serial driver to allow suspend/resume during
# Bluetooth traffic
PATCHES += "file://0001-omap-serial-add-delay-before-suspending.patch"
# Add patch to allow wireless to work properly on EVM-SK 1.2.
PATCHES += "file://0001-am3358-sk-modified-WLAN-enable-and-irq-to-match-boar.patch"
# Add CPU utilization patch for WLAN
PATCHES += "file://0001-am335xevm-using-edge-triggered-interrupts-for-WLAN.patch"
# Add patch to enable pullup on WLAN enable
PATCHES += "file://0001-am335x-enable-pullup-on-the-WLAN-enable-pin-fo.patch"
# Copy the am33x-cm3 firmware if it is available
do_compile_prepend() {
if [ -e "${STAGING_DIR_HOST}/${base_libdir}/firmware/am335x-pm-firmware.bin" ]
then
cp "${STAGING_DIR_HOST}/${base_libdir}/firmware/am335x-pm-firmware.bin" "${S}/firmware"
fi
}