diff options
author | Kefeng Wang <wangkefeng.wang@huawei.com> | 2016-04-13 06:11:28 -0400 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2016-04-15 10:36:36 -0400 |
commit | afc39d6e89b4f410f511f03dc6de8dc1d4952d42 (patch) | |
tree | 6ab5bee42fdebde12258e80dfd2626b5b962942e | |
parent | c7995ee7ff60c1973a3a63e35b41c2393f47f760 (diff) |
hwrng: hisi - Add support for Hisilicon SoC RNG
This adds the Hisilicon Random Number Generator(RNG) support,
which is found in Hip04 and Hip05 soc.
Reviewed-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
-rw-r--r-- | drivers/char/hw_random/Kconfig | 13 | ||||
-rw-r--r-- | drivers/char/hw_random/Makefile | 1 | ||||
-rw-r--r-- | drivers/char/hw_random/hisi-rng.c | 126 |
3 files changed, 140 insertions, 0 deletions
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index 3c5be60befce..c76a88da8d04 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig | |||
@@ -334,6 +334,19 @@ config HW_RANDOM_TPM | |||
334 | 334 | ||
335 | If unsure, say Y. | 335 | If unsure, say Y. |
336 | 336 | ||
337 | config HW_RANDOM_HISI | ||
338 | tristate "Hisilicon Random Number Generator support" | ||
339 | depends on HW_RANDOM && ARCH_HISI | ||
340 | default HW_RANDOM | ||
341 | ---help--- | ||
342 | This driver provides kernel-side support for the Random Number | ||
343 | Generator hardware found on Hisilicon Hip04 and Hip05 SoC. | ||
344 | |||
345 | To compile this driver as a module, choose M here: the | ||
346 | module will be called hisi-rng. | ||
347 | |||
348 | If unsure, say Y. | ||
349 | |||
337 | config HW_RANDOM_MSM | 350 | config HW_RANDOM_MSM |
338 | tristate "Qualcomm SoCs Random Number Generator support" | 351 | tristate "Qualcomm SoCs Random Number Generator support" |
339 | depends on HW_RANDOM && ARCH_QCOM | 352 | depends on HW_RANDOM && ARCH_QCOM |
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile index f5a6fa7690e7..e09305bb89e1 100644 --- a/drivers/char/hw_random/Makefile +++ b/drivers/char/hw_random/Makefile | |||
@@ -26,6 +26,7 @@ obj-$(CONFIG_HW_RANDOM_PPC4XX) += ppc4xx-rng.o | |||
26 | obj-$(CONFIG_HW_RANDOM_PSERIES) += pseries-rng.o | 26 | obj-$(CONFIG_HW_RANDOM_PSERIES) += pseries-rng.o |
27 | obj-$(CONFIG_HW_RANDOM_POWERNV) += powernv-rng.o | 27 | obj-$(CONFIG_HW_RANDOM_POWERNV) += powernv-rng.o |
28 | obj-$(CONFIG_HW_RANDOM_EXYNOS) += exynos-rng.o | 28 | obj-$(CONFIG_HW_RANDOM_EXYNOS) += exynos-rng.o |
29 | obj-$(CONFIG_HW_RANDOM_HISI) += hisi-rng.o | ||
29 | obj-$(CONFIG_HW_RANDOM_TPM) += tpm-rng.o | 30 | obj-$(CONFIG_HW_RANDOM_TPM) += tpm-rng.o |
30 | obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o | 31 | obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o |
31 | obj-$(CONFIG_HW_RANDOM_IPROC_RNG200) += iproc-rng200.o | 32 | obj-$(CONFIG_HW_RANDOM_IPROC_RNG200) += iproc-rng200.o |
diff --git a/drivers/char/hw_random/hisi-rng.c b/drivers/char/hw_random/hisi-rng.c new file mode 100644 index 000000000000..40d96572c591 --- /dev/null +++ b/drivers/char/hw_random/hisi-rng.c | |||
@@ -0,0 +1,126 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2016 HiSilicon Co., Ltd. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #include <linux/err.h> | ||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/hw_random.h> | ||
12 | #include <linux/io.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/of.h> | ||
15 | #include <linux/platform_device.h> | ||
16 | #include <linux/random.h> | ||
17 | |||
18 | #define RNG_SEED 0x0 | ||
19 | #define RNG_CTRL 0x4 | ||
20 | #define RNG_SEED_SEL BIT(2) | ||
21 | #define RNG_RING_EN BIT(1) | ||
22 | #define RNG_EN BIT(0) | ||
23 | #define RNG_RAN_NUM 0x10 | ||
24 | #define RNG_PHY_SEED 0x14 | ||
25 | |||
26 | #define to_hisi_rng(p) container_of(p, struct hisi_rng, rng) | ||
27 | |||
28 | static int seed_sel; | ||
29 | module_param(seed_sel, int, S_IRUGO); | ||
30 | MODULE_PARM_DESC(seed_sel, "Auto reload seed. 0, use LFSR(default); 1, use ring oscillator."); | ||
31 | |||
32 | struct hisi_rng { | ||
33 | void __iomem *base; | ||
34 | struct hwrng rng; | ||
35 | }; | ||
36 | |||
37 | static int hisi_rng_init(struct hwrng *rng) | ||
38 | { | ||
39 | struct hisi_rng *hrng = to_hisi_rng(rng); | ||
40 | int val = RNG_EN; | ||
41 | u32 seed; | ||
42 | |||
43 | /* get a random number as initial seed */ | ||
44 | get_random_bytes(&seed, sizeof(seed)); | ||
45 | |||
46 | writel_relaxed(seed, hrng->base + RNG_SEED); | ||
47 | |||
48 | /** | ||
49 | * The seed is reload periodically, there are two choice | ||
50 | * of seeds, default seed using the value from LFSR, or | ||
51 | * will use seed generated by ring oscillator. | ||
52 | */ | ||
53 | if (seed_sel == 1) | ||
54 | val |= RNG_RING_EN | RNG_SEED_SEL; | ||
55 | |||
56 | writel_relaxed(val, hrng->base + RNG_CTRL); | ||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | static void hisi_rng_cleanup(struct hwrng *rng) | ||
61 | { | ||
62 | struct hisi_rng *hrng = to_hisi_rng(rng); | ||
63 | |||
64 | writel_relaxed(0, hrng->base + RNG_CTRL); | ||
65 | } | ||
66 | |||
67 | static int hisi_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait) | ||
68 | { | ||
69 | struct hisi_rng *hrng = to_hisi_rng(rng); | ||
70 | u32 *data = buf; | ||
71 | |||
72 | *data = readl_relaxed(hrng->base + RNG_RAN_NUM); | ||
73 | return 4; | ||
74 | } | ||
75 | |||
76 | static int hisi_rng_probe(struct platform_device *pdev) | ||
77 | { | ||
78 | struct hisi_rng *rng; | ||
79 | struct resource *res; | ||
80 | int ret; | ||
81 | |||
82 | rng = devm_kzalloc(&pdev->dev, sizeof(*rng), GFP_KERNEL); | ||
83 | if (!rng) | ||
84 | return -ENOMEM; | ||
85 | |||
86 | platform_set_drvdata(pdev, rng); | ||
87 | |||
88 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
89 | rng->base = devm_ioremap_resource(&pdev->dev, res); | ||
90 | if (IS_ERR(rng->base)) | ||
91 | return PTR_ERR(rng->base); | ||
92 | |||
93 | rng->rng.name = pdev->name; | ||
94 | rng->rng.init = hisi_rng_init; | ||
95 | rng->rng.cleanup = hisi_rng_cleanup; | ||
96 | rng->rng.read = hisi_rng_read; | ||
97 | |||
98 | ret = devm_hwrng_register(&pdev->dev, &rng->rng); | ||
99 | if (ret) { | ||
100 | dev_err(&pdev->dev, "failed to register hwrng\n"); | ||
101 | return ret; | ||
102 | } | ||
103 | |||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | static const struct of_device_id hisi_rng_dt_ids[] = { | ||
108 | { .compatible = "hisilicon,hip04-rng" }, | ||
109 | { .compatible = "hisilicon,hip05-rng" }, | ||
110 | { } | ||
111 | }; | ||
112 | MODULE_DEVICE_TABLE(of, hisi_rng_dt_ids); | ||
113 | |||
114 | static struct platform_driver hisi_rng_driver = { | ||
115 | .probe = hisi_rng_probe, | ||
116 | .driver = { | ||
117 | .name = "hisi-rng", | ||
118 | .of_match_table = of_match_ptr(hisi_rng_dt_ids), | ||
119 | }, | ||
120 | }; | ||
121 | |||
122 | module_platform_driver(hisi_rng_driver); | ||
123 | |||
124 | MODULE_LICENSE("GPL"); | ||
125 | MODULE_AUTHOR("Kefeng Wang <wangkefeng.wang@huawei>"); | ||
126 | MODULE_DESCRIPTION("Hisilicon random number generator driver"); | ||