crypto4xx: integrate ppc4xx-rng into crypto4xx
authorChristian Lamparter <chunkeey@googlemail.com>
Mon, 18 Apr 2016 10:57:41 +0000 (12:57 +0200)
committerHerbert Xu <herbert@gondor.apana.org.au>
Wed, 20 Apr 2016 09:50:02 +0000 (17:50 +0800)
This patch integrates the ppc4xx-rng driver into the existing
crypto4xx. This is because the true random number generator
is controlled and part of the security core.

Signed-off-by: Christian Lamparter <chunkeey@googlemail.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
drivers/char/hw_random/Kconfig
drivers/char/hw_random/Makefile
drivers/char/hw_random/ppc4xx-rng.c [deleted file]
drivers/crypto/Kconfig
drivers/crypto/amcc/Makefile
drivers/crypto/amcc/crypto4xx_core.c
drivers/crypto/amcc/crypto4xx_core.h
drivers/crypto/amcc/crypto4xx_reg_def.h
drivers/crypto/amcc/crypto4xx_trng.c [new file with mode: 0644]
drivers/crypto/amcc/crypto4xx_trng.h [new file with mode: 0644]

index c76a88da8d0412df7b847eb766f450836b2ca206..ac51149e977758beb8db91e159175be9525fc13c 100644 (file)
@@ -268,19 +268,6 @@ config HW_RANDOM_NOMADIK
 
          If unsure, say Y.
 
-config HW_RANDOM_PPC4XX
-       tristate "PowerPC 4xx generic true random number generator support"
-       depends on PPC && 4xx
-       default HW_RANDOM
-       ---help---
-        This driver provides the kernel-side support for the TRNG hardware
-        found in the security function of some PowerPC 4xx SoCs.
-
-        To compile this driver as a module, choose M here: the
-        module will be called ppc4xx-rng.
-
-        If unsure, say N.
-
 config HW_RANDOM_PSERIES
        tristate "pSeries HW Random Number Generator support"
        depends on PPC64 && IBMVIO
index e09305bb89e1cf4d4b2c9322e2e878e2100e85d6..63022b49f160a191c4e7d1b34f10c1fce0d0ed39 100644 (file)
@@ -22,7 +22,6 @@ obj-$(CONFIG_HW_RANDOM_TX4939) += tx4939-rng.o
 obj-$(CONFIG_HW_RANDOM_MXC_RNGA) += mxc-rnga.o
 obj-$(CONFIG_HW_RANDOM_OCTEON) += octeon-rng.o
 obj-$(CONFIG_HW_RANDOM_NOMADIK) += nomadik-rng.o
-obj-$(CONFIG_HW_RANDOM_PPC4XX) += ppc4xx-rng.o
 obj-$(CONFIG_HW_RANDOM_PSERIES) += pseries-rng.o
 obj-$(CONFIG_HW_RANDOM_POWERNV) += powernv-rng.o
 obj-$(CONFIG_HW_RANDOM_EXYNOS) += exynos-rng.o
diff --git a/drivers/char/hw_random/ppc4xx-rng.c b/drivers/char/hw_random/ppc4xx-rng.c
deleted file mode 100644 (file)
index c0db438..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Generic PowerPC 44x RNG driver
- *
- * Copyright 2011 IBM Corporation
- *
- * 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; version 2 of the License.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/platform_device.h>
-#include <linux/hw_random.h>
-#include <linux/delay.h>
-#include <linux/of_address.h>
-#include <linux/of_platform.h>
-#include <asm/io.h>
-
-#define PPC4XX_TRNG_DEV_CTRL 0x60080
-
-#define PPC4XX_TRNGE 0x00020000
-#define PPC4XX_TRNG_CTRL 0x0008
-#define PPC4XX_TRNG_CTRL_DALM 0x20
-#define PPC4XX_TRNG_STAT 0x0004
-#define PPC4XX_TRNG_STAT_B 0x1
-#define PPC4XX_TRNG_DATA 0x0000
-
-#define MODULE_NAME "ppc4xx_rng"
-
-static int ppc4xx_rng_data_present(struct hwrng *rng, int wait)
-{
-       void __iomem *rng_regs = (void __iomem *) rng->priv;
-       int busy, i, present = 0;
-
-       for (i = 0; i < 20; i++) {
-               busy = (in_le32(rng_regs + PPC4XX_TRNG_STAT) & PPC4XX_TRNG_STAT_B);
-               if (!busy || !wait) {
-                       present = 1;
-                       break;
-               }
-               udelay(10);
-       }
-       return present;
-}
-
-static int ppc4xx_rng_data_read(struct hwrng *rng, u32 *data)
-{
-       void __iomem *rng_regs = (void __iomem *) rng->priv;
-       *data = in_le32(rng_regs + PPC4XX_TRNG_DATA);
-       return 4;
-}
-
-static int ppc4xx_rng_enable(int enable)
-{
-       struct device_node *ctrl;
-       void __iomem *ctrl_reg;
-       int err = 0;
-       u32 val;
-
-       /* Find the main crypto device node and map it to turn the TRNG on */
-       ctrl = of_find_compatible_node(NULL, NULL, "amcc,ppc4xx-crypto");
-       if (!ctrl)
-               return -ENODEV;
-
-       ctrl_reg = of_iomap(ctrl, 0);
-       if (!ctrl_reg) {
-               err = -ENODEV;
-               goto out;
-       }
-
-       val = in_le32(ctrl_reg + PPC4XX_TRNG_DEV_CTRL);
-
-       if (enable)
-               val |= PPC4XX_TRNGE;
-       else
-               val = val & ~PPC4XX_TRNGE;
-
-       out_le32(ctrl_reg + PPC4XX_TRNG_DEV_CTRL, val);
-       iounmap(ctrl_reg);
-
-out:
-       of_node_put(ctrl);
-
-       return err;
-}
-
-static struct hwrng ppc4xx_rng = {
-       .name = MODULE_NAME,
-       .data_present = ppc4xx_rng_data_present,
-       .data_read = ppc4xx_rng_data_read,
-};
-
-static int ppc4xx_rng_probe(struct platform_device *dev)
-{
-       void __iomem *rng_regs;
-       int err = 0;
-
-       rng_regs = of_iomap(dev->dev.of_node, 0);
-       if (!rng_regs)
-               return -ENODEV;
-
-       err = ppc4xx_rng_enable(1);
-       if (err)
-               return err;
-
-       out_le32(rng_regs + PPC4XX_TRNG_CTRL, PPC4XX_TRNG_CTRL_DALM);
-       ppc4xx_rng.priv = (unsigned long) rng_regs;
-
-       err = hwrng_register(&ppc4xx_rng);
-
-       return err;
-}
-
-static int ppc4xx_rng_remove(struct platform_device *dev)
-{
-       void __iomem *rng_regs = (void __iomem *) ppc4xx_rng.priv;
-
-       hwrng_unregister(&ppc4xx_rng);
-       ppc4xx_rng_enable(0);
-       iounmap(rng_regs);
-
-       return 0;
-}
-
-static const struct of_device_id ppc4xx_rng_match[] = {
-       { .compatible = "ppc4xx-rng", },
-       { .compatible = "amcc,ppc460ex-rng", },
-       { .compatible = "amcc,ppc440epx-rng", },
-       {},
-};
-MODULE_DEVICE_TABLE(of, ppc4xx_rng_match);
-
-static struct platform_driver ppc4xx_rng_driver = {
-       .driver = {
-               .name = MODULE_NAME,
-               .of_match_table = ppc4xx_rng_match,
-       },
-       .probe = ppc4xx_rng_probe,
-       .remove = ppc4xx_rng_remove,
-};
-
-module_platform_driver(ppc4xx_rng_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Josh Boyer <jwboyer@linux.vnet.ibm.com>");
-MODULE_DESCRIPTION("HW RNG driver for PPC 4xx processors");
index 0a22ac7db360b00d466acb6dd76c04746833bdd6..12fd49950f47153bb6e1312492cee5c1b2ba839d 100644 (file)
@@ -279,6 +279,14 @@ config CRYPTO_DEV_PPC4XX
        help
          This option allows you to have support for AMCC crypto acceleration.
 
+config HW_RANDOM_PPC4XX
+       bool "PowerPC 4xx generic true random number generator support"
+       depends on CRYPTO_DEV_PPC4XX && HW_RANDOM
+       default y
+       ---help---
+        This option provides the kernel-side support for the TRNG hardware
+        found in the security function of some PowerPC 4xx SoCs.
+
 config CRYPTO_DEV_OMAP_SHAM
        tristate "Support for OMAP MD5/SHA1/SHA2 hw accelerator"
        depends on ARCH_OMAP2PLUS
index 5c0c62b65d6933c64bea281ecd5f21bc60b3a89c..b95539928fdfd6499da0536dfb1b16846d59ffce 100644 (file)
@@ -1,2 +1,3 @@
 obj-$(CONFIG_CRYPTO_DEV_PPC4XX) += crypto4xx.o
 crypto4xx-y :=  crypto4xx_core.o crypto4xx_alg.o crypto4xx_sa.o
+crypto4xx-$(CONFIG_HW_RANDOM_PPC4XX) += crypto4xx_trng.o
index 62134c8a226091c1a57d3d1687acd26e84ee3dcd..dae1e39139e9a19bb0155f42d5ccf233d6c15dd4 100644 (file)
@@ -40,6 +40,7 @@
 #include "crypto4xx_reg_def.h"
 #include "crypto4xx_core.h"
 #include "crypto4xx_sa.h"
+#include "crypto4xx_trng.h"
 
 #define PPC4XX_SEC_VERSION_STR                 "0.5"
 
@@ -1225,6 +1226,7 @@ static int crypto4xx_probe(struct platform_device *ofdev)
        if (rc)
                goto err_start_dev;
 
+       ppc4xx_trng_probe(core_dev);
        return 0;
 
 err_start_dev:
@@ -1252,6 +1254,8 @@ static int crypto4xx_remove(struct platform_device *ofdev)
        struct device *dev = &ofdev->dev;
        struct crypto4xx_core_device *core_dev = dev_get_drvdata(dev);
 
+       ppc4xx_trng_remove(core_dev);
+
        free_irq(core_dev->irq, dev);
        irq_dispose_mapping(core_dev->irq);
 
@@ -1272,7 +1276,7 @@ MODULE_DEVICE_TABLE(of, crypto4xx_match);
 
 static struct platform_driver crypto4xx_driver = {
        .driver = {
-               .name = "crypto4xx",
+               .name = MODULE_NAME,
                .of_match_table = crypto4xx_match,
        },
        .probe          = crypto4xx_probe,
@@ -1284,4 +1288,3 @@ module_platform_driver(crypto4xx_driver);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("James Hsiao <jhsiao@amcc.com>");
 MODULE_DESCRIPTION("Driver for AMCC PPC4xx crypto accelerator");
-
index bac0bdeb4b5f9955c193e6896a7f5bb182c19e63..ecfdcfe3698d62204ffa3f4f9096d0769c4094b5 100644 (file)
@@ -24,6 +24,8 @@
 
 #include <crypto/internal/hash.h>
 
+#define MODULE_NAME "crypto4xx"
+
 #define PPC460SX_SDR0_SRST                      0x201
 #define PPC405EX_SDR0_SRST                      0x200
 #define PPC460EX_SDR0_SRST                      0x201
@@ -72,6 +74,7 @@ struct crypto4xx_device {
        char *name;
        u64  ce_phy_address;
        void __iomem *ce_base;
+       void __iomem *trng_base;
 
        void *pdr;                      /* base address of packet
                                        descriptor ring */
@@ -106,6 +109,7 @@ struct crypto4xx_core_device {
        struct device *device;
        struct platform_device *ofdev;
        struct crypto4xx_device *dev;
+       struct hwrng *trng;
        u32 int_status;
        u32 irq;
        struct tasklet_struct tasklet;
index 5f5fbc0716ff1b28e43986faa6f18e918cb43ddc..46fe57c8f6eb9a89a81131a8fa3273b89ac034ab 100644 (file)
 #define PPC4XX_INTERRUPT_CLR                   0x3ffff
 #define PPC4XX_PRNG_CTRL_AUTO_EN               0x3
 #define PPC4XX_DC_3DES_EN                      1
+#define PPC4XX_TRNG_EN                         0x00020000
 #define PPC4XX_INT_DESCR_CNT                   4
 #define PPC4XX_INT_TIMEOUT_CNT                 0
 #define PPC4XX_INT_CFG                         1
diff --git a/drivers/crypto/amcc/crypto4xx_trng.c b/drivers/crypto/amcc/crypto4xx_trng.c
new file mode 100644 (file)
index 0000000..677ca17
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Generic PowerPC 44x RNG driver
+ *
+ * Copyright 2011 IBM Corporation
+ *
+ * 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; version 2 of the License.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/hw_random.h>
+#include <linux/delay.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/io.h>
+
+#include "crypto4xx_core.h"
+#include "crypto4xx_trng.h"
+#include "crypto4xx_reg_def.h"
+
+#define PPC4XX_TRNG_CTRL       0x0008
+#define PPC4XX_TRNG_CTRL_DALM  0x20
+#define PPC4XX_TRNG_STAT       0x0004
+#define PPC4XX_TRNG_STAT_B     0x1
+#define PPC4XX_TRNG_DATA       0x0000
+
+static int ppc4xx_trng_data_present(struct hwrng *rng, int wait)
+{
+       struct crypto4xx_device *dev = (void *)rng->priv;
+       int busy, i, present = 0;
+
+       for (i = 0; i < 20; i++) {
+               busy = (in_le32(dev->trng_base + PPC4XX_TRNG_STAT) &
+                       PPC4XX_TRNG_STAT_B);
+               if (!busy || !wait) {
+                       present = 1;
+                       break;
+               }
+               udelay(10);
+       }
+       return present;
+}
+
+static int ppc4xx_trng_data_read(struct hwrng *rng, u32 *data)
+{
+       struct crypto4xx_device *dev = (void *)rng->priv;
+       *data = in_le32(dev->trng_base + PPC4XX_TRNG_DATA);
+       return 4;
+}
+
+static void ppc4xx_trng_enable(struct crypto4xx_device *dev, bool enable)
+{
+       u32 device_ctrl;
+
+       device_ctrl = readl(dev->ce_base + CRYPTO4XX_DEVICE_CTRL);
+       if (enable)
+               device_ctrl |= PPC4XX_TRNG_EN;
+       else
+               device_ctrl &= ~PPC4XX_TRNG_EN;
+       writel(device_ctrl, dev->ce_base + CRYPTO4XX_DEVICE_CTRL);
+}
+
+static const struct of_device_id ppc4xx_trng_match[] = {
+       { .compatible = "ppc4xx-rng", },
+       { .compatible = "amcc,ppc460ex-rng", },
+       { .compatible = "amcc,ppc440epx-rng", },
+       {},
+};
+
+void ppc4xx_trng_probe(struct crypto4xx_core_device *core_dev)
+{
+       struct crypto4xx_device *dev = core_dev->dev;
+       struct device_node *trng = NULL;
+       struct hwrng *rng = NULL;
+       int err;
+
+       /* Find the TRNG device node and map it */
+       trng = of_find_matching_node(NULL, ppc4xx_trng_match);
+       if (!trng || !of_device_is_available(trng))
+               return;
+
+       dev->trng_base = of_iomap(trng, 0);
+       of_node_put(trng);
+       if (!dev->trng_base)
+               goto err_out;
+
+       rng = kzalloc(sizeof(*rng), GFP_KERNEL);
+       if (!rng)
+               goto err_out;
+
+       rng->name = MODULE_NAME;
+       rng->data_present = ppc4xx_trng_data_present;
+       rng->data_read = ppc4xx_trng_data_read;
+       rng->priv = (unsigned long) dev;
+       core_dev->trng = rng;
+       ppc4xx_trng_enable(dev, true);
+       out_le32(dev->trng_base + PPC4XX_TRNG_CTRL, PPC4XX_TRNG_CTRL_DALM);
+       err = devm_hwrng_register(core_dev->device, core_dev->trng);
+       if (err) {
+               ppc4xx_trng_enable(dev, false);
+               dev_err(core_dev->device, "failed to register hwrng (%d).\n",
+                       err);
+               goto err_out;
+       }
+       return;
+
+err_out:
+       of_node_put(trng);
+       iounmap(dev->trng_base);
+       kfree(rng);
+       dev->trng_base = NULL;
+       core_dev->trng = NULL;
+}
+
+void ppc4xx_trng_remove(struct crypto4xx_core_device *core_dev)
+{
+       if (core_dev && core_dev->trng) {
+               struct crypto4xx_device *dev = core_dev->dev;
+
+               devm_hwrng_unregister(core_dev->device, core_dev->trng);
+               ppc4xx_trng_enable(dev, false);
+               iounmap(dev->trng_base);
+               kfree(core_dev->trng);
+       }
+}
+
+MODULE_ALIAS("ppc4xx_rng");
diff --git a/drivers/crypto/amcc/crypto4xx_trng.h b/drivers/crypto/amcc/crypto4xx_trng.h
new file mode 100644 (file)
index 0000000..931d225
--- /dev/null
@@ -0,0 +1,34 @@
+/**
+ * AMCC SoC PPC4xx Crypto Driver
+ *
+ * Copyright (c) 2008 Applied Micro Circuits Corporation.
+ * All rights reserved. James Hsiao <jhsiao@amcc.com>
+ *
+ * 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.
+ *
+ * This file defines the security context
+ * associate format.
+ */
+
+#ifndef __CRYPTO4XX_TRNG_H__
+#define __CRYPTO4XX_TRNG_H__
+
+#ifdef CONFIG_HW_RANDOM_PPC4XX
+void ppc4xx_trng_probe(struct crypto4xx_core_device *core_dev);
+void ppc4xx_trng_remove(struct crypto4xx_core_device *core_dev);
+#else
+static inline void ppc4xx_trng_probe(
+       struct crypto4xx_device *dev __maybe_unused) { }
+static inline void ppc4xx_trng_remove(
+       struct crypto4xx_device *dev __maybe_unused) { }
+#endif
+
+#endif