Subject: [PATCH 1/5] MIPS: BCM63XX: fix BCM6368 IPSec clock bit

From: Florian Fainelli <[email-masked]>
Date: Fri, 9 Dec 2011 20:01:06 +0100

The IPsec clock bit is 18 and not 17.

Signed-off-by: Florian Fainelli <[email-masked]>
---
 arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
index 94d4faa..fdcd78c 100644
--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
+++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
@@ -99,7 +99,7 @@
 #define CKCTL_6368_USBH_CLK_EN		(1 << 15)
 #define CKCTL_6368_DISABLE_GLESS_EN	(1 << 16)
 #define CKCTL_6368_NAND_CLK_EN		(1 << 17)
-#define CKCTL_6368_IPSEC_CLK_EN		(1 << 17)
+#define CKCTL_6368_IPSEC_CLK_EN		(1 << 18)
 
 #define CKCTL_6368_ALL_SAFE_EN		(CKCTL_6368_SWPKT_USB_EN |	\
 					CKCTL_6368_SWPKT_SAR_EN |	\
-- 
1.7.5.4

---

From: Florian Fainelli <[email-masked]>
Date: Fri, 9 Dec 2011 20:01:08 +0100

Signed-off-by: Florian Fainelli <[email-masked]>
---
 arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h  |    9 +++++++++
 arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h |   13 +++++++++++++
 2 files changed, 22 insertions(+), 0 deletions(-)

diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h
index 5b8d15b..f0ab172 100644
--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h
+++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h
@@ -130,6 +130,7 @@ enum bcm63xx_regs_set {
 	RSET_PCMDMA,
 	RSET_PCMDMAC,
 	RSET_PCMDMAS,
+	RSET_TRNG
 };
 
 #define RSET_DSL_LMEM_SIZE		(64 * 1024 * 4)
@@ -149,6 +150,7 @@ enum bcm63xx_regs_set {
 #define RSET_XTMDMA_SIZE		256
 #define RSET_XTMDMAC_SIZE(chans)	(16 * (chans))
 #define RSET_XTMDMAS_SIZE(chans)	(16 * (chans))
+#define RSET_TRNG_SIZE			20
 
 /*
  * 6338 register sets base address
@@ -193,6 +195,7 @@ enum bcm63xx_regs_set {
 #define BCM_6338_PCMDMA_BASE		(0xdeadbeef)
 #define BCM_6338_PCMDMAC_BASE		(0xdeadbeef)
 #define BCM_6338_PCMDMAS_BASE		(0xdeadbeef)
+#define BCM_6338_TRNG_BASE		(0xdeadbeef)
 
 /*
  * 6345 register sets base address
@@ -237,6 +240,7 @@ enum bcm63xx_regs_set {
 #define BCM_6345_PCMDMA_BASE		(0xdeadbeef)
 #define BCM_6345_PCMDMAC_BASE		(0xdeadbeef)
 #define BCM_6345_PCMDMAS_BASE		(0xdeadbeef)
+#define BCM_6345_TRNG_BASE		(0xdeadbeef)
 
 /*
  * 6348 register sets base address
@@ -278,6 +282,7 @@ enum bcm63xx_regs_set {
 #define BCM_6348_PCMDMA_BASE		(0xdeadbeef)
 #define BCM_6348_PCMDMAC_BASE		(0xdeadbeef)
 #define BCM_6348_PCMDMAS_BASE		(0xdeadbeef)
+#define BCM_6348_TRNG_BASE		(0xdeadbeef)
 
 /*
  * 6358 register sets base address
@@ -319,6 +324,7 @@ enum bcm63xx_regs_set {
 #define BCM_6358_PCMDMA_BASE		(0xfffe1800)
 #define BCM_6358_PCMDMAC_BASE		(0xfffe1900)
 #define BCM_6358_PCMDMAS_BASE		(0xfffe1a00)
+#define BCM_6358_TRNG_BASE		(0xdeadbeef)

 /*
@@ -361,6 +367,7 @@ enum bcm63xx_regs_set {
 #define BCM_6368_PCMDMA_BASE		(0xb0005800)
 #define BCM_6368_PCMDMAC_BASE		(0xb0005a00)
 #define BCM_6368_PCMDMAS_BASE		(0xb0005c00)
+#define BCM_6368_TRNG_BASE		(0xb0004180)

 extern const unsigned long *bcm63xx_regs_base;
@@ -407,6 +414,7 @@ extern const unsigned long *bcm63xx_regs_base;
 	__GEN_RSET_BASE(__cpu, PCMDMA)					\
 	__GEN_RSET_BASE(__cpu, PCMDMAC)					\
 	__GEN_RSET_BASE(__cpu, PCMDMAS)					\
+	__GEN_RSET_BASE(__cpu, TRNG)					\
 	}
 
 #define __GEN_CPU_REGS_TABLE(__cpu)					\
@@ -446,6 +454,7 @@ extern const unsigned long *bcm63xx_regs_base;
 	[RSET_PCMDMA]		= BCM_## __cpu ##_PCMDMA_BASE,		\
 	[RSET_PCMDMAC]		= BCM_## __cpu ##_PCMDMAC_BASE,		\
 	[RSET_PCMDMAS]		= BCM_## __cpu ##_PCMDMAS_BASE,		\
+	[RSET_TRNG]		= BCM_## __cpu ##_TRNG_BASE,		\

 static inline unsigned long bcm63xx_regset_address(enum bcm63xx_regs_set set)
diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
index fdcd78c..0de0bd9 100644
--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
+++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
@@ -973,4 +973,17 @@
 #define M2M_SRCID_REG(x)		((x) * 0x40 + 0x14)
 #define M2M_DSTID_REG(x)		((x) * 0x40 + 0x18)
 
+/*************************************************************************
+ * _REG relative to RSET_TRNG
+ *************************************************************************/
+#define TRNG_CTRL			0x00
+#define TRNG_EN				(1 << 0)
+
+#define TRNG_STAT			0x04
+#define TRNG_AVAIL_MASK			(0xff000000)
+
+#define TRNG_DATA			0x08
+#define TRNG_THRES			0x0c
+#define TRNG_MASK			0x10
+
 #endif /* BCM63XX_REGS_H_ */
-- 
1.7.5.4

---

From: Florian Fainelli <[email-masked]>
Date: Fri, 9 Dec 2011 20:01:09 +0100

Signed-off-by: Florian Fainelli <[email-masked]>
---
 arch/mips/bcm63xx/Makefile   |    3 ++-
 arch/mips/bcm63xx/dev-trng.c |   40 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 42 insertions(+), 1 deletions(-)
 create mode 100644 arch/mips/bcm63xx/dev-trng.c

diff --git a/arch/mips/bcm63xx/Makefile b/arch/mips/bcm63xx/Makefile
index 6dfdc69..95c45b5 100644
--- a/arch/mips/bcm63xx/Makefile
+++ b/arch/mips/bcm63xx/Makefile
@@ -1,5 +1,6 @@
 obj-y		+= clk.o cpu.o cs.o gpio.o irq.o prom.o setup.o timer.o \
-		   dev-dsp.o dev-enet.o dev-pcmcia.o dev-uart.o dev-wdt.o
+		   dev-dsp.o dev-enet.o dev-pcmcia.o dev-trng.o dev-uart.o \
+		   dev-wdt.o
 obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
 
 obj-y		+= boards/
diff --git a/arch/mips/bcm63xx/dev-trng.c b/arch/mips/bcm63xx/dev-trng.c
new file mode 100644
index 0000000..19ccfbf
--- /dev/null
+++ b/arch/mips/bcm63xx/dev-trng.c
@@ -0,0 +1,40 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2011 Florian Fainelli <[email-masked]>
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <bcm63xx_cpu.h>
+
+static struct resource trng_resources[] = {
+	{
+		.start		= -1, /* filled at runtime */
+		.end		= -1, /* filled at runtime */
+		.flags		= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device bcm63xx_trng_device = {
+	.name		= "bcm63xx-trng",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(trng_resources),
+	.resource	= trng_resources,
+};
+
+int __init bcm63xx_trng_register(void)
+{
+	if (!BCMCPU_IS_6368())
+		return -ENODEV;
+
+	trng_resources[0].start = bcm63xx_regset_address(RSET_TRNG);
+	trng_resources[0].end = trng_resources[0].start;
+	trng_resources[0].end += RSET_TRNG_SIZE - 1;
+
+	return platform_device_register(&bcm63xx_trng_device);
+}
+arch_initcall(bcm63xx_trng_register);
-- 
1.7.5.4

---

From: Florian Fainelli <[email-masked]>
Date: Fri, 9 Dec 2011 20:01:07 +0100

This module is only available on BCM6368 so far and does not require
resetting the block.

Signed-off-by: Florian Fainelli <[email-masked]>
---
 arch/mips/bcm63xx/clk.c |   14 ++++++++++++++
 1 files changed, 14 insertions(+), 0 deletions(-)

diff --git a/arch/mips/bcm63xx/clk.c b/arch/mips/bcm63xx/clk.c
index 9d57c71..28137d5 100644
--- a/arch/mips/bcm63xx/clk.c
+++ b/arch/mips/bcm63xx/clk.c
@@ -222,6 +222,18 @@ static struct clk clk_xtm = {
 };
 
 /*
+ * IPsec clock
+ */
+static void ipsec_set(struct clk *clk, int enable)
+{
+	bcm_hwclock_set(CKCTL_6368_IPSEC_CLK_EN, enable);
+}
+
+static struct clk clk_ipsec = {
+	.set	= ipsec_set,
+};
+
+/*
  * Internal peripheral clock
  */
 static struct clk clk_periph = {
@@ -278,6 +290,8 @@ struct clk *clk_get(struct device *dev, const char *id)
 		return &clk_periph;
 	if (BCMCPU_IS_6358() && !strcmp(id, "pcm"))
 		return &clk_pcm;
+	if (BCMCPU_IS_6368() && !strcmp(id, "ipsec"))
+		return &clk_ipsec;
 	return ERR_PTR(-ENOENT);
 }
 
-- 
1.7.5.4

---

From: Florian Fainelli <[email-masked]>
Date: Fri, 9 Dec 2011 20:01:05 +0100

The following patch serie adds support for the Broadcom BCM63xx RNG block.

Since it depends on some MIPS bits, it might be easier to merge it via the
MIPS tree.

Thanks!

Florian Fainelli (5):
  MIPS: BCM63XX: fix BCM6368 IPSec clock bit
  MIPS: BCM63XX: add support for "ipsec" clock
  MIPS: BCM63XX: add TRNG peripheral definitions
  MIPS: BCM63XX: add RNG driver platform_device stub
  hw_random: add Broadcom BCM63xx RNG driver

 arch/mips/bcm63xx/Makefile                        |    3 +-
 arch/mips/bcm63xx/clk.c                           |   14 ++
 arch/mips/bcm63xx/dev-trng.c                      |   40 +++++
 arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h  |    9 +
 arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h |   15 ++-
 drivers/char/hw_random/Kconfig                    |   14 ++
 drivers/char/hw_random/Makefile                   |    1 +
 drivers/char/hw_random/bcm63xx-rng.c              |  175 +++++++++++++++++++++
 8 files changed, 269 insertions(+), 2 deletions(-)
 create mode 100644 arch/mips/bcm63xx/dev-trng.c
 create mode 100644 drivers/char/hw_random/bcm63xx-rng.c

-- 
1.7.5.4

---

From: Florian Fainelli <[email-masked]>
Date: Fri, 9 Dec 2011 20:01:10 +0100

Signed-off-by: Florian Fainelli <[email-masked]>
---
 drivers/char/hw_random/Kconfig       |   14 +++
 drivers/char/hw_random/Makefile      |    1 +
 drivers/char/hw_random/bcm63xx-rng.c |  175 ++++++++++++++++++++++++++++++++++
 3 files changed, 190 insertions(+), 0 deletions(-)
 create mode 100644 drivers/char/hw_random/bcm63xx-rng.c

diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index 0689bf6..f29d1bc 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -73,6 +73,20 @@ config HW_RANDOM_ATMEL
 
 	  If unsure, say Y.
 
+config HW_RANDOM_BCM63XX
+	tristate "Broadcom BCM63xx Random Number Generator support"
+	depends on HW_RANDOM && BCM63XX
+	default HW_RANDOM
+	---help---
+	  This driver provides kernel-side support for the Random Number
+	  Generator hardware found on the Broadcom BCM63xx SoCs.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called bcm63xx-rng
+
+	  If unusure, say Y.
+
+
 config HW_RANDOM_GEODE
 	tristate "AMD Geode HW Random Number Generator support"
 	depends on HW_RANDOM && X86_32 && PCI
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
index b2ff526..8cfac60 100644
--- a/drivers/char/hw_random/Makefile
+++ b/drivers/char/hw_random/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_HW_RANDOM_TIMERIOMEM) += timeriomem-rng.o
 obj-$(CONFIG_HW_RANDOM_INTEL) += intel-rng.o
 obj-$(CONFIG_HW_RANDOM_AMD) += amd-rng.o
 obj-$(CONFIG_HW_RANDOM_ATMEL) += atmel-rng.o
+obj-$(CONFIG_HW_RANDOM_BCM63XX)	+= bcm63xx-rng.o
 obj-$(CONFIG_HW_RANDOM_GEODE) += geode-rng.o
 obj-$(CONFIG_HW_RANDOM_N2RNG) += n2-rng.o
 n2-rng-y := n2-drv.o n2-asm.o
diff --git a/drivers/char/hw_random/bcm63xx-rng.c b/drivers/char/hw_random/bcm63xx-rng.c
new file mode 100644
index 0000000..80e282d
--- /dev/null
+++ b/drivers/char/hw_random/bcm63xx-rng.c
@@ -0,0 +1,175 @@
+/*
+ * Broadcom BCM63xx Random Number Generator support
+ *
+ * Copyright (C) 2011, Florian Fainelli <[email-masked]>
+ * Copyright (C) 2009, Broadcom Corporation
+ *
+ */
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/hw_random.h>
+
+#include <bcm63xx_io.h>
+#include <bcm63xx_regs.h>
+
+struct bcm63xx_trng_priv {
+	struct clk *clk;
+	void __iomem *regs;
+};
+
+#define to_trng_priv(rng)	((struct bcm63xx_trng_priv *)rng->priv)
+
+static int bcm63xx_trng_init(struct hwrng *rng)
+{
+	struct bcm63xx_trng_priv *priv = to_trng_priv(rng);
+	u32 val;
+
+	val = bcm_readl(priv->regs + TRNG_CTRL);
+	val |= TRNG_EN;
+	bcm_writel(val, priv->regs + TRNG_CTRL);
+
+	return 0;
+}
+
+static void bcm63xx_trng_cleanup(struct hwrng *rng)
+{
+	struct bcm63xx_trng_priv *priv = to_trng_priv(rng);
+	u32 val;
+
+	val = bcm_readl(priv->regs + TRNG_CTRL);
+	val &= ~TRNG_EN;
+	bcm_writel(val, priv->regs + TRNG_CTRL);
+}
+
+static int bcm63xx_trng_data_present(struct hwrng *rng, int wait)
+{
+	struct bcm63xx_trng_priv *priv = to_trng_priv(rng);
+
+	return bcm_readl(priv->regs + TRNG_STAT) & TRNG_AVAIL_MASK;
+}
+
+static int bcm63xx_trng_data_read(struct hwrng *rng, u32 *data)
+{
+	struct bcm63xx_trng_priv *priv = to_trng_priv(rng);
+
+	*data = bcm_readl(priv->regs + TRNG_DATA);
+
+	return 4;
+}
+
+static int __init bcm63xx_trng_probe(struct platform_device *pdev)
+{
+	struct resource *r;
+	struct clk *clk;
+	int ret;
+	struct bcm63xx_trng_priv *priv;
+	struct hwrng *rng;
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!r) {
+		dev_err(&pdev->dev, "no iomem resource\n");
+		ret = -ENXIO;
+		goto out;
+	}
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv) {
+		dev_err(&pdev->dev, "no memory for private structure\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	rng = kzalloc(sizeof(*rng), GFP_KERNEL);
+	if (!rng) {
+		dev_err(&pdev->dev, "no memory for rng structure\n");
+		ret = -ENOMEM;
+		goto out_free_priv;
+	}
+
+	platform_set_drvdata(pdev, rng);
+	rng->priv = (unsigned long)priv;
+	rng->name = pdev->name;
+	rng->init = bcm63xx_trng_init;
+	rng->cleanup = bcm63xx_trng_cleanup;
+	rng->data_present = bcm63xx_trng_data_present;
+	rng->data_read = bcm63xx_trng_data_read;
+
+	clk = clk_get(&pdev->dev, "ipsec");
+	if (IS_ERR(clk)) {
+		dev_err(&pdev->dev, "no clock for device\n");
+		ret = PTR_ERR(clk);
+		goto out_free_rng;
+	}
+
+	priv->clk = clk;
+
+	if (!devm_request_mem_region(&pdev->dev, r->start,
+					resource_size(r), pdev->name)) {
+		dev_err(&pdev->dev, "request mem failed");
+		ret = -ENOMEM;
+		goto out_free_rng;
+	}
+
+	priv->regs = devm_ioremap_nocache(&pdev->dev, r->start,
+					resource_size(r));
+	if (!priv->regs) {
+		dev_err(&pdev->dev, "ioremap failed");
+		ret = -ENOMEM;
+		goto out_free_rng;
+	}
+
+	clk_enable(clk);
+
+	ret = hwrng_register(rng);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to register rng device\n");
+		goto out_clk_disable;
+	}
+
+	dev_info(&pdev->dev, "registered RNG driver\n");
+
+	return 0;
+
+out_clk_disable:
+	clk_disable(clk);
+out_free_rng:
+	platform_set_drvdata(pdev, NULL);
+	kfree(rng);
+out_free_priv:
+	kfree(priv);
+out:
+	return ret;
+}
+
+static int __devexit bcm63xx_trng_remove(struct platform_device *pdev)
+{
+	struct hwrng *rng = platform_get_drvdata(pdev);
+	struct bcm63xx_trng_priv *priv = to_trng_priv(rng);
+
+	hwrng_unregister(rng);
+	clk_disable(priv->clk);
+	kfree(priv);
+	kfree(rng);
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static struct platform_driver bcm63xx_trng_driver = {
+	.probe		= bcm63xx_trng_probe,
+	.remove		= __devexit_p(bcm63xx_trng_remove),
+	.driver		= {
+		.name	= "bcm63xx-trng",
+		.owner	= THIS_MODULE,
+	},
+};
+
+module_platform_driver(bcm63xx_trng_driver);
+
+MODULE_AUTHOR("Florian Fainelli <[email-masked]>");
+MODULE_DESCRIPTION("Broadcom BCM63xx RNG driver");
+MODULE_LICENSE("GPL");
-- 
1.7.5.4

---

From: Sergei Shtylyov <[email-masked]>
Date: Sat, 10 Dec 2011 18:46:49 +0400

Hello.

On 09-12-2011 23:01, Florian Fainelli wrote:

> Signed-off-by: Florian Fainelli<[email-masked]>
[...]

> +++ b/arch/mips/bcm63xx/dev-trng.c
[...]
> +	.name		= "bcm63xx-trng",

    Why not -1? Isn't there only single device of this sort?

WBR, Sergei

---

From: Florian Fainelli <[email-masked]>
Date: Fri, 16 Dec 2011 16:03:42 +0100

Hello Sergei,

>    Why not -1? Isn't there only single device of this sort?

There is a single device, I will fix that in a second version of the 
patchset.
--
Florian