diff options
Diffstat (limited to 'drivers/char/hw_random')
-rw-r--r-- | drivers/char/hw_random/Kconfig | 29 | ||||
-rw-r--r-- | drivers/char/hw_random/Makefile | 2 | ||||
-rw-r--r-- | drivers/char/hw_random/exynos-rng.c | 23 | ||||
-rw-r--r-- | drivers/char/hw_random/hisi-rng.c | 126 | ||||
-rw-r--r-- | drivers/char/hw_random/ppc4xx-rng.c | 147 |
5 files changed, 162 insertions, 165 deletions
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index 67ee8b08a..ac51149e9 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -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 @@ -309,7 +296,8 @@ config HW_RANDOM_POWERNV config HW_RANDOM_EXYNOS tristate "EXYNOS HW random number generator support" - depends on ARCH_EXYNOS + depends on ARCH_EXYNOS || COMPILE_TEST + depends on HAS_IOMEM default HW_RANDOM ---help--- This driver provides kernel-side support for the Random Number @@ -333,6 +321,19 @@ config HW_RANDOM_TPM If unsure, say Y. +config HW_RANDOM_HISI + tristate "Hisilicon Random Number Generator support" + depends on HW_RANDOM && ARCH_HISI + default HW_RANDOM + ---help--- + This driver provides kernel-side support for the Random Number + Generator hardware found on Hisilicon Hip04 and Hip05 SoC. + + To compile this driver as a module, choose M here: the + module will be called hisi-rng. + + If unsure, say Y. + config HW_RANDOM_MSM tristate "Qualcomm SoCs Random Number Generator support" depends on HW_RANDOM && ARCH_QCOM diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile index f5a6fa769..63022b49f 100644 --- a/drivers/char/hw_random/Makefile +++ b/drivers/char/hw_random/Makefile @@ -22,10 +22,10 @@ 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 +obj-$(CONFIG_HW_RANDOM_HISI) += hisi-rng.o obj-$(CONFIG_HW_RANDOM_TPM) += tpm-rng.o obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o obj-$(CONFIG_HW_RANDOM_IPROC_RNG200) += iproc-rng200.o diff --git a/drivers/char/hw_random/exynos-rng.c b/drivers/char/hw_random/exynos-rng.c index b98a141ea..ed44561ea 100644 --- a/drivers/char/hw_random/exynos-rng.c +++ b/drivers/char/hw_random/exynos-rng.c @@ -2,7 +2,7 @@ * exynos-rng.c - Random Number Generator driver for the exynos * * Copyright (C) 2012 Samsung Electronics - * Jonghwa Lee <jonghwa3.lee@smasung.com> + * Jonghwa Lee <jonghwa3.lee@samsung.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 @@ -77,7 +77,8 @@ static int exynos_init(struct hwrng *rng) pm_runtime_get_sync(exynos_rng->dev); ret = exynos_rng_configure(exynos_rng); - pm_runtime_put_noidle(exynos_rng->dev); + pm_runtime_mark_last_busy(exynos_rng->dev); + pm_runtime_put_autosuspend(exynos_rng->dev); return ret; } @@ -118,6 +119,7 @@ static int exynos_rng_probe(struct platform_device *pdev) { struct exynos_rng *exynos_rng; struct resource *res; + int ret; exynos_rng = devm_kzalloc(&pdev->dev, sizeof(struct exynos_rng), GFP_KERNEL); @@ -145,7 +147,21 @@ static int exynos_rng_probe(struct platform_device *pdev) pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_enable(&pdev->dev); - return devm_hwrng_register(&pdev->dev, &exynos_rng->rng); + ret = devm_hwrng_register(&pdev->dev, &exynos_rng->rng); + if (ret) { + pm_runtime_dont_use_autosuspend(&pdev->dev); + pm_runtime_disable(&pdev->dev); + } + + return ret; +} + +static int exynos_rng_remove(struct platform_device *pdev) +{ + pm_runtime_dont_use_autosuspend(&pdev->dev); + pm_runtime_disable(&pdev->dev); + + return 0; } static int __maybe_unused exynos_rng_runtime_suspend(struct device *dev) @@ -205,6 +221,7 @@ static struct platform_driver exynos_rng_driver = { .of_match_table = exynos_rng_dt_match, }, .probe = exynos_rng_probe, + .remove = exynos_rng_remove, }; module_platform_driver(exynos_rng_driver); diff --git a/drivers/char/hw_random/hisi-rng.c b/drivers/char/hw_random/hisi-rng.c new file mode 100644 index 000000000..40d96572c --- /dev/null +++ b/drivers/char/hw_random/hisi-rng.c @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2016 HiSilicon Co., Ltd. + * + * 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. + */ + +#include <linux/err.h> +#include <linux/kernel.h> +#include <linux/hw_random.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/random.h> + +#define RNG_SEED 0x0 +#define RNG_CTRL 0x4 + #define RNG_SEED_SEL BIT(2) + #define RNG_RING_EN BIT(1) + #define RNG_EN BIT(0) +#define RNG_RAN_NUM 0x10 +#define RNG_PHY_SEED 0x14 + +#define to_hisi_rng(p) container_of(p, struct hisi_rng, rng) + +static int seed_sel; +module_param(seed_sel, int, S_IRUGO); +MODULE_PARM_DESC(seed_sel, "Auto reload seed. 0, use LFSR(default); 1, use ring oscillator."); + +struct hisi_rng { + void __iomem *base; + struct hwrng rng; +}; + +static int hisi_rng_init(struct hwrng *rng) +{ + struct hisi_rng *hrng = to_hisi_rng(rng); + int val = RNG_EN; + u32 seed; + + /* get a random number as initial seed */ + get_random_bytes(&seed, sizeof(seed)); + + writel_relaxed(seed, hrng->base + RNG_SEED); + + /** + * The seed is reload periodically, there are two choice + * of seeds, default seed using the value from LFSR, or + * will use seed generated by ring oscillator. + */ + if (seed_sel == 1) + val |= RNG_RING_EN | RNG_SEED_SEL; + + writel_relaxed(val, hrng->base + RNG_CTRL); + return 0; +} + +static void hisi_rng_cleanup(struct hwrng *rng) +{ + struct hisi_rng *hrng = to_hisi_rng(rng); + + writel_relaxed(0, hrng->base + RNG_CTRL); +} + +static int hisi_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait) +{ + struct hisi_rng *hrng = to_hisi_rng(rng); + u32 *data = buf; + + *data = readl_relaxed(hrng->base + RNG_RAN_NUM); + return 4; +} + +static int hisi_rng_probe(struct platform_device *pdev) +{ + struct hisi_rng *rng; + struct resource *res; + int ret; + + rng = devm_kzalloc(&pdev->dev, sizeof(*rng), GFP_KERNEL); + if (!rng) + return -ENOMEM; + + platform_set_drvdata(pdev, rng); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + rng->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(rng->base)) + return PTR_ERR(rng->base); + + rng->rng.name = pdev->name; + rng->rng.init = hisi_rng_init; + rng->rng.cleanup = hisi_rng_cleanup; + rng->rng.read = hisi_rng_read; + + ret = devm_hwrng_register(&pdev->dev, &rng->rng); + if (ret) { + dev_err(&pdev->dev, "failed to register hwrng\n"); + return ret; + } + + return 0; +} + +static const struct of_device_id hisi_rng_dt_ids[] = { + { .compatible = "hisilicon,hip04-rng" }, + { .compatible = "hisilicon,hip05-rng" }, + { } +}; +MODULE_DEVICE_TABLE(of, hisi_rng_dt_ids); + +static struct platform_driver hisi_rng_driver = { + .probe = hisi_rng_probe, + .driver = { + .name = "hisi-rng", + .of_match_table = of_match_ptr(hisi_rng_dt_ids), + }, +}; + +module_platform_driver(hisi_rng_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Kefeng Wang <wangkefeng.wang@huawei>"); +MODULE_DESCRIPTION("Hisilicon random number generator driver"); diff --git a/drivers/char/hw_random/ppc4xx-rng.c b/drivers/char/hw_random/ppc4xx-rng.c deleted file mode 100644 index c0db4387d..000000000 --- a/drivers/char/hw_random/ppc4xx-rng.c +++ /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"); |