* [PATCH 01/12] hw_random: support ctrlc()
2024-03-13 10:56 [PATCH 00/12] hw_random: add 6 more RNG drivers Ahmad Fatoum
@ 2024-03-13 10:56 ` Ahmad Fatoum
2024-03-13 10:56 ` [PATCH 02/12] ARM: io: read 32 bits at once for aligned I/O memcpy/memset Ahmad Fatoum
` (11 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Ahmad Fatoum @ 2024-03-13 10:56 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
It's valid for HWRNG drivers to return 0 bytes read, thereby instructing
the caller to try again. We do that for the cdev_read operation, but in
case the driver never returns a non-zero value, barebox will keep
waiting indefinitely. Check ctrlc() in that case and return a short read
if the user interrupts the operation.
We don't need ctrlc() in the general case, as the caller is free to
check for ctrlc() between reads to the device.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/hw_random/core.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/hw_random/core.c b/drivers/hw_random/core.c
index 89b979ade8b1..7bc3c33319f9 100644
--- a/drivers/hw_random/core.c
+++ b/drivers/hw_random/core.c
@@ -44,10 +44,10 @@ static ssize_t rng_dev_read(struct cdev *cdev, void *buf, size_t size,
while (count) {
int max = min(count, (size_t)RNG_BUFFER_SIZE);
len = hwrng_get_data(rng, rng->buf, max, true);
- if (len < 0) {
- cur = len;
- break;
- }
+ if (len < 0)
+ return len;
+ if (!len && ctrlc())
+ return cur;
memcpy(buf + cur, rng->buf, len);
--
2.39.2
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 02/12] ARM: io: read 32 bits at once for aligned I/O memcpy/memset
2024-03-13 10:56 [PATCH 00/12] hw_random: add 6 more RNG drivers Ahmad Fatoum
2024-03-13 10:56 ` [PATCH 01/12] hw_random: support ctrlc() Ahmad Fatoum
@ 2024-03-13 10:56 ` Ahmad Fatoum
2024-03-13 10:56 ` [PATCH 03/12] driver: implement dev_platform_get_and_ioremap_resource Ahmad Fatoum
` (10 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Ahmad Fatoum @ 2024-03-13 10:56 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
The barebox arm32 implementation for I/O memcpy/memset uses single
byte accesses exclusively. This is different from the barebox arm64
implementation, which accesses 64 bits at once if the buffer is aligned
and the Linux arm32 implementation, which is the optimized assembly
version that doesn't use single byte accesses for aligned buffers
either.
The current implementation is slower than need be and breaks code ported
from Linux. e.g. the OMAP RNG driver uses memcpy_fromio and expects it
to perform 32-bit accesses as any smaller access leads to a data abort
on the hardware. In Linux this works, but in barebox it crashes.
Avoid these issues by using 32-bit accesses if possible.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
arch/arm/lib32/io.c | 73 +++++++++++++++++++++++++++++++++++----------
1 file changed, 57 insertions(+), 16 deletions(-)
diff --git a/arch/arm/lib32/io.c b/arch/arm/lib32/io.c
index a12da49c0ab2..780b1083a641 100644
--- a/arch/arm/lib32/io.c
+++ b/arch/arm/lib32/io.c
@@ -2,48 +2,89 @@
#include <module.h>
#include <linux/types.h>
+#include <asm/unaligned.h>
#include <io.h>
/*
* Copy data from IO memory space to "real" memory space.
- * This needs to be optimized.
*/
void memcpy_fromio(void *to, const volatile void __iomem *from, size_t count)
{
- unsigned char *t = to;
- while (count) {
- count--;
- *t = readb(from);
- t++;
+ while (count && !PTR_IS_ALIGNED(from, 4)) {
+ *(u8 *)to = __raw_readb(from);
from++;
+ to++;
+ count--;
+ }
+
+ while (count >= 4) {
+ put_unaligned(__raw_readl(from), (u32 *)to);
+ from += 4;
+ to += 4;
+ count -= 4;
+ }
+
+ while (count) {
+ *(u8 *)to = __raw_readb(from);
+ from++;
+ to++;
+ count--;
}
}
/*
* Copy data from "real" memory space to IO memory space.
- * This needs to be optimized.
*/
void memcpy_toio(volatile void __iomem *to, const void *from, size_t count)
{
- const unsigned char *f = from;
- while (count) {
- count--;
- writeb(*f, to);
- f++;
+ while (count && !IS_ALIGNED((unsigned long)to, 4)) {
+ __raw_writeb(*(u8 *)from, to);
+ from++;
to++;
+ count--;
+ }
+
+ while (count >= 4) {
+ __raw_writel(get_unaligned((u32 *)from), to);
+ from += 4;
+ to += 4;
+ count -= 4;
+ }
+
+ while (count) {
+ __raw_writeb(*(u8 *)from, to);
+ from++;
+ to++;
+ count--;
}
}
/*
* "memset" on IO memory space.
- * This needs to be optimized.
*/
void memset_io(volatile void __iomem *dst, int c, size_t count)
{
- while (count) {
- count--;
- writeb(c, dst);
+ u32 qc = (u8)c;
+
+ qc |= qc << 8;
+ qc |= qc << 16;
+
+ while (count && !PTR_IS_ALIGNED(dst, 4)) {
+ __raw_writeb(c, dst);
dst++;
+ count--;
+ }
+
+ while (count >= 4) {
+ __raw_writel(qc, dst);
+ dst += 4;
+ count -= 4;
+ }
+
+ while (count) {
+ __raw_writeb(c, dst);
+ dst++;
+ count--;
}
}
--
2.39.2
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 03/12] driver: implement dev_platform_get_and_ioremap_resource
2024-03-13 10:56 [PATCH 00/12] hw_random: add 6 more RNG drivers Ahmad Fatoum
2024-03-13 10:56 ` [PATCH 01/12] hw_random: support ctrlc() Ahmad Fatoum
2024-03-13 10:56 ` [PATCH 02/12] ARM: io: read 32 bits at once for aligned I/O memcpy/memset Ahmad Fatoum
@ 2024-03-13 10:56 ` Ahmad Fatoum
2024-03-13 10:56 ` [PATCH 04/12] hw_random: add struct hwrng::priv member Ahmad Fatoum
` (9 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Ahmad Fatoum @ 2024-03-13 10:56 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
To simplify porting of Linux drivers that make use of this function, add
an implementation to barebox. This was so far not done, because AT91 has
I/O memory regions that conflict with the error pointers.
Therefore, we emit a warning if we run into such a conflict.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/base/driver.c | 19 +++++++++++++++++++
include/driver.h | 4 ++++
2 files changed, 23 insertions(+)
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index b2d428b70550..fbc5cbebe0ab 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -538,6 +538,25 @@ void __iomem *dev_request_mem_region_by_name(struct device *dev,
}
EXPORT_SYMBOL(dev_request_mem_region_by_name);
+void __iomem *dev_platform_get_and_ioremap_resource(struct device *dev,
+ int num,
+ struct resource **out_res)
+{
+ struct resource *res;
+
+ res = dev_request_mem_resource(dev, num);
+ if (IS_ERR(res))
+ return IOMEM_ERR_PTR(PTR_ERR(res));
+ else if (WARN_ON(IS_ERR_VALUE(res->start)))
+ return IOMEM_ERR_PTR(-EINVAL);
+
+ if (out_res)
+ *out_res = res;
+
+ return IOMEM(res->start);
+}
+EXPORT_SYMBOL(dev_platform_get_and_ioremap_resource);
+
struct resource *dev_request_mem_resource(struct device *dev, int num)
{
struct resource *res;
diff --git a/include/driver.h b/include/driver.h
index 7ff65d63946d..a61b9dca2285 100644
--- a/include/driver.h
+++ b/include/driver.h
@@ -289,6 +289,10 @@ struct resource *dev_request_mem_resource(struct device *dev, int num);
struct resource *dev_request_mem_resource_by_name(struct device *dev,
const char *name);
+void __iomem *dev_platform_get_and_ioremap_resource(struct device *dev,
+ int num,
+ struct resource **out_res);
+
/*
* exlusively request register base 'num' for a device
* will return NULL on error
--
2.39.2
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 04/12] hw_random: add struct hwrng::priv member
2024-03-13 10:56 [PATCH 00/12] hw_random: add 6 more RNG drivers Ahmad Fatoum
` (2 preceding siblings ...)
2024-03-13 10:56 ` [PATCH 03/12] driver: implement dev_platform_get_and_ioremap_resource Ahmad Fatoum
@ 2024-03-13 10:56 ` Ahmad Fatoum
2024-03-13 10:56 ` [PATCH 05/12] hw_random: remove confusing left-overs from kernel help texts Ahmad Fatoum
` (8 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Ahmad Fatoum @ 2024-03-13 10:56 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
A number of Linux hw_random drivers use container_of to arrive at the
driver private data, but some others use the priv member of struct
hwrng. A unsigned long worth of extra malloc space doesn't hurt, so add
the same member to barebox too.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
include/linux/hw_random.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/include/linux/hw_random.h b/include/linux/hw_random.h
index 9143ba1f8d4c..4479428bc743 100644
--- a/include/linux/hw_random.h
+++ b/include/linux/hw_random.h
@@ -33,6 +33,7 @@ struct hwrng {
struct cdev cdev;
struct device *dev;
void *buf;
+ unsigned long priv;
};
/* Register a new Hardware Random Number Generator driver. */
--
2.39.2
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 05/12] hw_random: remove confusing left-overs from kernel help texts
2024-03-13 10:56 [PATCH 00/12] hw_random: add 6 more RNG drivers Ahmad Fatoum
` (3 preceding siblings ...)
2024-03-13 10:56 ` [PATCH 04/12] hw_random: add struct hwrng::priv member Ahmad Fatoum
@ 2024-03-13 10:56 ` Ahmad Fatoum
2024-03-13 10:56 ` [PATCH 06/12] hw_random: remove reference to undefined CONFIG_HW_RANDOM Ahmad Fatoum
` (7 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Ahmad Fatoum @ 2024-03-13 10:56 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
Mentioning Linux in the help text for barebox drivers can be confusing
as there's indeed barebox drivers that prepare stuff for Linux to use.
hw_random drivers don't though and they for use inside barebox, so
adjust the help text accordingly.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/hw_random/Kconfig | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/hw_random/Kconfig b/drivers/hw_random/Kconfig
index 6daff6490693..7662566d7fba 100644
--- a/drivers/hw_random/Kconfig
+++ b/drivers/hw_random/Kconfig
@@ -12,7 +12,7 @@ config HWRNG_MXC_RNGC
tristate "Freescale i.MX RNGC Random Number Generator"
depends on ARCH_IMX25 || ARCH_IMX35 || ARCH_IMX53 || COMPILE_TEST
help
- This driver provides kernel-side support for the Random Number
+ This driver provides barebox support for the Random Number
Generator hardware found on some Freescale i.MX processors.
config HWRNG_STM32
@@ -56,8 +56,8 @@ config HW_RANDOM_OPTEE
depends on OPTEE
default HW_RANDOM
help
- This driver provides support for OP-TEE based Random Number
+ This driver provides support for OP-TEE based Random Number
Generator on ARM SoCs where hardware entropy sources are not
- accessible to normal world (Linux).
+ accessible to normal world (barebox and e.g. Linux after it).
endif
--
2.39.2
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 06/12] hw_random: remove reference to undefined CONFIG_HW_RANDOM
2024-03-13 10:56 [PATCH 00/12] hw_random: add 6 more RNG drivers Ahmad Fatoum
` (4 preceding siblings ...)
2024-03-13 10:56 ` [PATCH 05/12] hw_random: remove confusing left-overs from kernel help texts Ahmad Fatoum
@ 2024-03-13 10:56 ` Ahmad Fatoum
2024-03-13 10:56 ` [PATCH 07/12] hw_random: add Atmel RNG driver Ahmad Fatoum
` (6 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Ahmad Fatoum @ 2024-03-13 10:56 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
CONFIG_HW_RANDOM is called CONFIG_HWRNG in barebox, so remove references
to the former.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/hw_random/Kconfig | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/hw_random/Kconfig b/drivers/hw_random/Kconfig
index 7662566d7fba..bd9ba9e19ec2 100644
--- a/drivers/hw_random/Kconfig
+++ b/drivers/hw_random/Kconfig
@@ -54,7 +54,6 @@ config HW_RANDOM_EFI
config HW_RANDOM_OPTEE
tristate "OP-TEE based Random Number Generator support"
depends on OPTEE
- default HW_RANDOM
help
This driver provides support for OP-TEE based Random Number
Generator on ARM SoCs where hardware entropy sources are not
--
2.39.2
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 07/12] hw_random: add Atmel RNG driver
2024-03-13 10:56 [PATCH 00/12] hw_random: add 6 more RNG drivers Ahmad Fatoum
` (5 preceding siblings ...)
2024-03-13 10:56 ` [PATCH 06/12] hw_random: remove reference to undefined CONFIG_HW_RANDOM Ahmad Fatoum
@ 2024-03-13 10:56 ` Ahmad Fatoum
2024-03-13 10:56 ` [PATCH 08/12] hw_random: add BCM2835 " Ahmad Fatoum
` (5 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Ahmad Fatoum @ 2024-03-13 10:56 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
To enable proper hardening with stack protector, add support for the
Atmel RNG. This has been tested on a SAMA5D2.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/hw_random/Kconfig | 7 ++
drivers/hw_random/Makefile | 1 +
drivers/hw_random/atmel-rng.c | 165 ++++++++++++++++++++++++++++++++++
3 files changed, 173 insertions(+)
create mode 100644 drivers/hw_random/atmel-rng.c
diff --git a/drivers/hw_random/Kconfig b/drivers/hw_random/Kconfig
index bd9ba9e19ec2..873e2bf1e4f4 100644
--- a/drivers/hw_random/Kconfig
+++ b/drivers/hw_random/Kconfig
@@ -59,4 +59,11 @@ config HW_RANDOM_OPTEE
Generator on ARM SoCs where hardware entropy sources are not
accessible to normal world (barebox and e.g. Linux after it).
+config HW_RANDOM_ATMEL
+ tristate "Atmel Random Number Generator support"
+ depends on ARCH_AT91 || COMPILE_TEST
+ help
+ This driver provides barebox support for the Random Number
+ Generator hardware found on Atmel AT91 devices.
+
endif
diff --git a/drivers/hw_random/Makefile b/drivers/hw_random/Makefile
index 2c7d196f2f72..b0710e4ce977 100644
--- a/drivers/hw_random/Makefile
+++ b/drivers/hw_random/Makefile
@@ -7,3 +7,4 @@ obj-$(CONFIG_HW_RANDOM_VIRTIO) += virtio-rng.o
obj-$(CONFIG_HW_RANDOM_STARFIVE) += starfive-vic-rng.o
obj-$(CONFIG_HW_RANDOM_EFI) += efi-rng.o
obj-$(CONFIG_HW_RANDOM_OPTEE) += optee-rng.o
+obj-$(CONFIG_HW_RANDOM_ATMEL) += atmel-rng.o
diff --git a/drivers/hw_random/atmel-rng.c b/drivers/hw_random/atmel-rng.c
new file mode 100644
index 000000000000..bdd2139b08a5
--- /dev/null
+++ b/drivers/hw_random/atmel-rng.c
@@ -0,0 +1,165 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-FileCopyrightText: 2011 Peter Korsgaard <jacmet@sunsite.dk>
+
+#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/hw_random.h>
+#include <of.h>
+#include <linux/device.h>
+
+#define TRNG_CR 0x00
+#define TRNG_MR 0x04
+#define TRNG_ISR 0x1c
+#define TRNG_ISR_DATRDY BIT(0)
+#define TRNG_ODATA 0x50
+
+#define TRNG_KEY 0x524e4700 /* RNG */
+
+#define TRNG_HALFR BIT(0) /* generate RN every 168 cycles */
+
+struct atmel_trng_data {
+ bool has_half_rate;
+};
+
+struct atmel_trng {
+ struct clk *clk;
+ void __iomem *base;
+ struct hwrng rng;
+ bool has_half_rate;
+};
+
+static bool atmel_trng_wait_ready(struct atmel_trng *trng, bool wait)
+{
+ int ready;
+
+ ready = readl(trng->base + TRNG_ISR) & TRNG_ISR_DATRDY;
+ if (!ready && wait)
+ readl_poll_timeout(trng->base + TRNG_ISR, ready,
+ ready & TRNG_ISR_DATRDY, 20000);
+
+ return !!ready;
+}
+
+static int atmel_trng_read(struct hwrng *rng, void *buf, size_t max,
+ bool wait)
+{
+ struct atmel_trng *trng = container_of(rng, struct atmel_trng, rng);
+ u32 *data = buf;
+ int ret;
+
+ ret = atmel_trng_wait_ready(trng, wait);
+ if (!ret)
+ return 0;
+
+ *data = readl(trng->base + TRNG_ODATA);
+ /*
+ * ensure data ready is only set again AFTER the next data word is ready
+ * in case it got set between checking ISR and reading ODATA, so we
+ * don't risk re-reading the same word
+ */
+ readl(trng->base + TRNG_ISR);
+ ret = 4;
+
+ return ret;
+}
+
+static int atmel_trng_init(struct hwrng *rng)
+{
+ struct atmel_trng *trng = container_of(rng, struct atmel_trng, rng);
+ unsigned long rate;
+ int ret;
+
+ ret = clk_prepare_enable(trng->clk);
+ if (ret)
+ return ret;
+
+ if (trng->has_half_rate) {
+ rate = clk_get_rate(trng->clk);
+
+ /* if peripheral clk is above 100MHz, set HALFR */
+ if (rate > 100000000)
+ writel(TRNG_HALFR, trng->base + TRNG_MR);
+ }
+
+ writel(TRNG_KEY | 1, trng->base + TRNG_CR);
+
+ return 0;
+}
+
+static void atmel_trng_cleanup(struct atmel_trng *trng)
+{
+ writel(TRNG_KEY, trng->base + TRNG_CR);
+ clk_disable_unprepare(trng->clk);
+}
+
+static int atmel_trng_probe(struct device *dev)
+{
+ struct atmel_trng *trng;
+ const struct atmel_trng_data *data;
+
+ trng = devm_kzalloc(dev, sizeof(*trng), GFP_KERNEL);
+ if (!trng)
+ return -ENOMEM;
+
+ trng->base = dev_platform_ioremap_resource(dev, 0);
+ if (IS_ERR(trng->base))
+ return PTR_ERR(trng->base);
+
+ trng->clk = clk_get(dev, NULL);
+ if (IS_ERR(trng->clk))
+ return PTR_ERR(trng->clk);
+ data = device_get_match_data(dev);
+ if (!data)
+ return -ENODEV;
+
+ trng->has_half_rate = data->has_half_rate;
+ trng->rng.name = dev_name(dev);
+ trng->rng.read = atmel_trng_read;
+ trng->rng.init = atmel_trng_init;
+ dev->priv = trng;
+
+ return hwrng_register(dev, &trng->rng);
+}
+
+static void atmel_trng_remove(struct device *dev)
+{
+ atmel_trng_cleanup(dev->priv);
+}
+
+static const struct atmel_trng_data at91sam9g45_config = {
+ .has_half_rate = false,
+};
+
+static const struct atmel_trng_data sam9x60_config = {
+ .has_half_rate = true,
+};
+
+static const struct of_device_id atmel_trng_dt_ids[] = {
+ {
+ .compatible = "atmel,at91sam9g45-trng",
+ .data = &at91sam9g45_config,
+ }, {
+ .compatible = "microchip,sam9x60-trng",
+ .data = &sam9x60_config,
+ }, {
+ /* sentinel */
+ }
+};
+MODULE_DEVICE_TABLE(of, atmel_trng_dt_ids);
+
+static struct driver atmel_trng_driver = {
+ .name = "atmel-trng",
+ .probe = atmel_trng_probe,
+ .remove = atmel_trng_remove,
+ .of_match_table = atmel_trng_dt_ids,
+};
+device_platform_driver(atmel_trng_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>");
+MODULE_DESCRIPTION("Atmel true random number generator driver");
--
2.39.2
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 08/12] hw_random: add BCM2835 RNG driver
2024-03-13 10:56 [PATCH 00/12] hw_random: add 6 more RNG drivers Ahmad Fatoum
` (6 preceding siblings ...)
2024-03-13 10:56 ` [PATCH 07/12] hw_random: add Atmel RNG driver Ahmad Fatoum
@ 2024-03-13 10:56 ` Ahmad Fatoum
2024-03-13 10:56 ` [PATCH 09/12] hw_random: add IPROC RNG200 driver for BCM2711 Ahmad Fatoum
` (4 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Ahmad Fatoum @ 2024-03-13 10:56 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
To enable proper hardening with stack protector, add support for the
BCM2835 RNG. This has been tested on a Raspberry Pi 3B.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/hw_random/Kconfig | 7 ++
drivers/hw_random/Makefile | 1 +
drivers/hw_random/bcm2835-rng.c | 199 ++++++++++++++++++++++++++++++++
include/linux/hw_random.h | 5 +
4 files changed, 212 insertions(+)
create mode 100644 drivers/hw_random/bcm2835-rng.c
diff --git a/drivers/hw_random/Kconfig b/drivers/hw_random/Kconfig
index 873e2bf1e4f4..e38bf42a67cd 100644
--- a/drivers/hw_random/Kconfig
+++ b/drivers/hw_random/Kconfig
@@ -66,4 +66,11 @@ config HW_RANDOM_ATMEL
This driver provides barebox support for the Random Number
Generator hardware found on Atmel AT91 devices.
+config HW_RANDOM_BCM2835
+ tristate "Broadcom BCM2835/BCM63xx Random Number Generator support"
+ depends on ARCH_BCM283X || COMPILE_TEST
+ help
+ This driver provides barebox support for the Random Number
+ Generator hardware found on the Broadcom BCM2835 SoCs.
+
endif
diff --git a/drivers/hw_random/Makefile b/drivers/hw_random/Makefile
index b0710e4ce977..ed0a4efeedf4 100644
--- a/drivers/hw_random/Makefile
+++ b/drivers/hw_random/Makefile
@@ -8,3 +8,4 @@ obj-$(CONFIG_HW_RANDOM_STARFIVE) += starfive-vic-rng.o
obj-$(CONFIG_HW_RANDOM_EFI) += efi-rng.o
obj-$(CONFIG_HW_RANDOM_OPTEE) += optee-rng.o
obj-$(CONFIG_HW_RANDOM_ATMEL) += atmel-rng.o
+obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o
diff --git a/drivers/hw_random/bcm2835-rng.c b/drivers/hw_random/bcm2835-rng.c
new file mode 100644
index 000000000000..d82331c950d2
--- /dev/null
+++ b/drivers/hw_random/bcm2835-rng.c
@@ -0,0 +1,199 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
+ * Copyright (c) 2013 Lubomir Rintel
+ */
+
+#include <linux/hw_random.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/reset.h>
+#include <of.h>
+#include <linux/device.h>
+#include <linux/printk.h>
+#include <linux/clk.h>
+#include <linux/reset.h>
+
+#define RNG_CTRL 0x0
+#define RNG_STATUS 0x4
+#define RNG_DATA 0x8
+#define RNG_INT_MASK 0x10
+
+/* enable rng */
+#define RNG_RBGEN 0x1
+
+/* the initial numbers generated are "less random" so will be discarded */
+#define RNG_WARMUP_COUNT 0x40000
+
+#define RNG_INT_OFF 0x1
+
+struct bcm2835_rng_priv {
+ struct hwrng rng;
+ void __iomem *base;
+ bool mask_interrupts;
+ struct clk *clk;
+ struct reset_control *reset;
+};
+
+static inline struct bcm2835_rng_priv *to_rng_priv(struct hwrng *rng)
+{
+ return container_of(rng, struct bcm2835_rng_priv, rng);
+}
+
+static inline u32 rng_readl(struct bcm2835_rng_priv *priv, u32 offset)
+{
+ /* MIPS chips strapped for BE will automagically configure the
+ * peripheral registers for CPU-native byte order.
+ */
+ if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
+ return __raw_readl(priv->base + offset);
+ else
+ return readl(priv->base + offset);
+}
+
+static inline void rng_writel(struct bcm2835_rng_priv *priv, u32 val,
+ u32 offset)
+{
+ if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
+ __raw_writel(val, priv->base + offset);
+ else
+ writel(val, priv->base + offset);
+}
+
+static int bcm2835_rng_read(struct hwrng *rng, void *buf, size_t max,
+ bool wait)
+{
+ struct bcm2835_rng_priv *priv = to_rng_priv(rng);
+ u32 max_words = max / sizeof(u32);
+ u32 num_words, count;
+
+ while ((rng_readl(priv, RNG_STATUS) >> 24) == 0) {
+ if (!wait)
+ return 0;
+ hwrng_yield(rng);
+ }
+
+ num_words = rng_readl(priv, RNG_STATUS) >> 24;
+ if (num_words > max_words)
+ num_words = max_words;
+
+ for (count = 0; count < num_words; count++)
+ ((u32 *)buf)[count] = rng_readl(priv, RNG_DATA);
+
+ return num_words * sizeof(u32);
+}
+
+static int bcm2835_rng_init(struct hwrng *rng)
+{
+ struct bcm2835_rng_priv *priv = to_rng_priv(rng);
+ int ret = 0;
+ u32 val;
+
+ ret = clk_prepare_enable(priv->clk);
+ if (ret)
+ return ret;
+
+ ret = reset_control_reset(priv->reset);
+ if (ret)
+ return ret;
+
+ if (priv->mask_interrupts) {
+ /* mask the interrupt */
+ val = rng_readl(priv, RNG_INT_MASK);
+ val |= RNG_INT_OFF;
+ rng_writel(priv, val, RNG_INT_MASK);
+ }
+
+ /* set warm-up count & enable */
+ rng_writel(priv, RNG_WARMUP_COUNT, RNG_STATUS);
+ rng_writel(priv, RNG_RBGEN, RNG_CTRL);
+
+ return ret;
+}
+
+static void bcm2835_rng_cleanup(struct bcm2835_rng_priv *priv)
+{
+ /* disable rng hardware */
+ rng_writel(priv, 0, RNG_CTRL);
+
+ clk_disable_unprepare(priv->clk);
+}
+
+struct bcm2835_rng_of_data {
+ bool mask_interrupts;
+};
+
+static const struct bcm2835_rng_of_data nsp_rng_of_data = {
+ .mask_interrupts = true,
+};
+
+static const struct of_device_id bcm2835_rng_of_match[] = {
+ { .compatible = "brcm,bcm2835-rng"},
+ { .compatible = "brcm,bcm-nsp-rng", .data = &nsp_rng_of_data },
+ { .compatible = "brcm,bcm5301x-rng", .data = &nsp_rng_of_data },
+ { .compatible = "brcm,bcm6368-rng"},
+ {},
+};
+
+static int bcm2835_rng_probe(struct device *dev)
+{
+ const struct bcm2835_rng_of_data *of_data;
+ struct bcm2835_rng_priv *priv;
+ int err;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ /* map peripheral */
+ priv->base = dev_platform_ioremap_resource(dev, 0);
+ if (IS_ERR(priv->base))
+ return PTR_ERR(priv->base);
+
+ /* Clock is optional on most platforms */
+ priv->clk = clk_get_optional(dev, NULL);
+ if (IS_ERR(priv->clk))
+ return PTR_ERR(priv->clk);
+
+ priv->reset = reset_control_get_optional(dev, NULL);
+ if (IS_ERR(priv->reset))
+ return PTR_ERR(priv->reset);
+
+ priv->rng.name = dev_name(dev);
+ priv->rng.init = bcm2835_rng_init;
+ priv->rng.read = bcm2835_rng_read;
+
+ of_data = device_get_match_data(dev);
+ if (of_data)
+ priv->mask_interrupts = of_data->mask_interrupts;
+
+ /* register driver */
+ err = hwrng_register(dev, &priv->rng);
+ if (err)
+ dev_err(dev, "hwrng registration failed\n");
+ else
+ dev_info(dev, "hwrng registered\n");
+
+ dev->priv = priv;
+
+ return err;
+}
+
+static void bcm2835_rng_remove(struct device *dev)
+{
+ bcm2835_rng_cleanup(dev->priv);
+}
+
+MODULE_DEVICE_TABLE(of, bcm2835_rng_of_match);
+
+static struct driver bcm2835_rng_driver = {
+ .name = "bcm2835-rng",
+ .of_match_table = bcm2835_rng_of_match,
+ .probe = bcm2835_rng_probe,
+ .remove = bcm2835_rng_remove,
+};
+device_platform_driver(bcm2835_rng_driver);
+
+MODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>");
+MODULE_DESCRIPTION("BCM2835 Random Number Generator (RNG) driver");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/hw_random.h b/include/linux/hw_random.h
index 4479428bc743..ff6d3bb58285 100644
--- a/include/linux/hw_random.h
+++ b/include/linux/hw_random.h
@@ -52,4 +52,9 @@ static inline int hwrng_get_data(struct hwrng *rng, void *buffer, size_t size, i
void hwrng_unregister(struct hwrng *rng);
+static inline long hwrng_yield(struct hwrng *rng)
+{
+ return 0;
+}
+
#endif /* LINUX_HWRANDOM_H_ */
--
2.39.2
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 09/12] hw_random: add IPROC RNG200 driver for BCM2711
2024-03-13 10:56 [PATCH 00/12] hw_random: add 6 more RNG drivers Ahmad Fatoum
` (7 preceding siblings ...)
2024-03-13 10:56 ` [PATCH 08/12] hw_random: add BCM2835 " Ahmad Fatoum
@ 2024-03-13 10:56 ` Ahmad Fatoum
2024-03-13 10:56 ` [PATCH 10/12] hw_random: add Rockchip RNG support Ahmad Fatoum
` (3 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Ahmad Fatoum @ 2024-03-13 10:56 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
To enable proper hardening with stack protector, add support for the
IPROC RNG200. This has been tested on a Raspberry Pi 4.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/hw_random/Kconfig | 7 +
drivers/hw_random/Makefile | 1 +
drivers/hw_random/iproc-rng200.c | 220 +++++++++++++++++++++++++++++++
3 files changed, 228 insertions(+)
create mode 100644 drivers/hw_random/iproc-rng200.c
diff --git a/drivers/hw_random/Kconfig b/drivers/hw_random/Kconfig
index e38bf42a67cd..8aef00d61d81 100644
--- a/drivers/hw_random/Kconfig
+++ b/drivers/hw_random/Kconfig
@@ -73,4 +73,11 @@ config HW_RANDOM_BCM2835
This driver provides barebox support for the Random Number
Generator hardware found on the Broadcom BCM2835 SoCs.
+config HW_RANDOM_IPROC_RNG200
+ tristate "Broadcom iProc/STB RNG200 support"
+ depends on ARCH_BCM283X || COMPILE_TEST
+ help
+ This driver provides barebox support for the RNG200
+ hardware found on the BCM2711.
+
endif
diff --git a/drivers/hw_random/Makefile b/drivers/hw_random/Makefile
index ed0a4efeedf4..120f4c465635 100644
--- a/drivers/hw_random/Makefile
+++ b/drivers/hw_random/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_HW_RANDOM_EFI) += efi-rng.o
obj-$(CONFIG_HW_RANDOM_OPTEE) += optee-rng.o
obj-$(CONFIG_HW_RANDOM_ATMEL) += atmel-rng.o
obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o
+obj-$(CONFIG_HW_RANDOM_IPROC_RNG200) += iproc-rng200.o
diff --git a/drivers/hw_random/iproc-rng200.c b/drivers/hw_random/iproc-rng200.c
new file mode 100644
index 000000000000..4cb3573a7d20
--- /dev/null
+++ b/drivers/hw_random/iproc-rng200.c
@@ -0,0 +1,220 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+* Copyright (C) 2015 Broadcom Corporation
+*
+*/
+/*
+ * DESCRIPTION: The Broadcom iProc RNG200 Driver
+ */
+
+#include <linux/hw_random.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
+#include <linux/device.h>
+#include <clock.h>
+
+/* Registers */
+#define RNG_CTRL_OFFSET 0x00
+#define RNG_CTRL_RNG_RBGEN_MASK 0x00001FFF
+#define RNG_CTRL_RNG_RBGEN_ENABLE 0x00000001
+
+#define RNG_SOFT_RESET_OFFSET 0x04
+#define RNG_SOFT_RESET 0x00000001
+
+#define RBG_SOFT_RESET_OFFSET 0x08
+#define RBG_SOFT_RESET 0x00000001
+
+#define RNG_INT_STATUS_OFFSET 0x18
+#define RNG_INT_STATUS_MASTER_FAIL_LOCKOUT_IRQ_MASK 0x80000000
+#define RNG_INT_STATUS_STARTUP_TRANSITIONS_MET_IRQ_MASK 0x00020000
+#define RNG_INT_STATUS_NIST_FAIL_IRQ_MASK 0x00000020
+#define RNG_INT_STATUS_TOTAL_BITS_COUNT_IRQ_MASK 0x00000001
+
+#define RNG_FIFO_DATA_OFFSET 0x20
+
+#define RNG_FIFO_COUNT_OFFSET 0x24
+#define RNG_FIFO_COUNT_RNG_FIFO_COUNT_MASK 0x000000FF
+
+struct iproc_rng200_dev {
+ struct hwrng rng;
+ void __iomem *base;
+};
+
+#define to_rng_priv(rng) container_of(rng, struct iproc_rng200_dev, rng)
+
+static void iproc_rng200_enable_set(void __iomem *rng_base, bool enable)
+{
+ u32 val;
+
+ val = ioread32(rng_base + RNG_CTRL_OFFSET);
+ val &= ~RNG_CTRL_RNG_RBGEN_MASK;
+
+ if (enable)
+ val |= RNG_CTRL_RNG_RBGEN_ENABLE;
+
+ iowrite32(val, rng_base + RNG_CTRL_OFFSET);
+}
+
+static void iproc_rng200_restart(void __iomem *rng_base)
+{
+ uint32_t val;
+
+ iproc_rng200_enable_set(rng_base, false);
+
+ /* Clear all interrupt status */
+ iowrite32(0xFFFFFFFFUL, rng_base + RNG_INT_STATUS_OFFSET);
+
+ /* Reset RNG and RBG */
+ val = ioread32(rng_base + RBG_SOFT_RESET_OFFSET);
+ val |= RBG_SOFT_RESET;
+ iowrite32(val, rng_base + RBG_SOFT_RESET_OFFSET);
+
+ val = ioread32(rng_base + RNG_SOFT_RESET_OFFSET);
+ val |= RNG_SOFT_RESET;
+ iowrite32(val, rng_base + RNG_SOFT_RESET_OFFSET);
+
+ val = ioread32(rng_base + RNG_SOFT_RESET_OFFSET);
+ val &= ~RNG_SOFT_RESET;
+ iowrite32(val, rng_base + RNG_SOFT_RESET_OFFSET);
+
+ val = ioread32(rng_base + RBG_SOFT_RESET_OFFSET);
+ val &= ~RBG_SOFT_RESET;
+ iowrite32(val, rng_base + RBG_SOFT_RESET_OFFSET);
+
+ iproc_rng200_enable_set(rng_base, true);
+}
+
+static int iproc_rng200_read(struct hwrng *rng, void *buf, size_t max,
+ bool wait)
+{
+ struct iproc_rng200_dev *priv = to_rng_priv(rng);
+ uint32_t num_remaining = max;
+ uint32_t status;
+ u64 start;
+
+ #define MAX_RESETS_PER_READ 1
+ uint32_t num_resets = 0;
+
+ #define MAX_IDLE_TIME_NS (NSEC_PER_SEC)
+
+ start = get_time_ns();
+
+ while ((num_remaining > 0) && !is_timeout(start, MAX_IDLE_TIME_NS)) {
+
+ /* Is RNG sane? If not, reset it. */
+ status = ioread32(priv->base + RNG_INT_STATUS_OFFSET);
+ if ((status & (RNG_INT_STATUS_MASTER_FAIL_LOCKOUT_IRQ_MASK |
+ RNG_INT_STATUS_NIST_FAIL_IRQ_MASK)) != 0) {
+
+ if (num_resets >= MAX_RESETS_PER_READ)
+ return max - num_remaining;
+
+ iproc_rng200_restart(priv->base);
+ num_resets++;
+ }
+
+ /* Are there any random numbers available? */
+ if ((ioread32(priv->base + RNG_FIFO_COUNT_OFFSET) &
+ RNG_FIFO_COUNT_RNG_FIFO_COUNT_MASK) > 0) {
+
+ if (num_remaining >= sizeof(uint32_t)) {
+ /* Buffer has room to store entire word */
+ *(uint32_t *)buf = ioread32(priv->base +
+ RNG_FIFO_DATA_OFFSET);
+ buf += sizeof(uint32_t);
+ num_remaining -= sizeof(uint32_t);
+ } else {
+ /* Buffer can only store partial word */
+ uint32_t rnd_number = ioread32(priv->base +
+ RNG_FIFO_DATA_OFFSET);
+ memcpy(buf, &rnd_number, num_remaining);
+ buf += num_remaining;
+ num_remaining = 0;
+ }
+
+ /* Reset the IDLE timeout */
+ start = get_time_ns();
+ } else {
+ if (!wait)
+ /* Cannot wait, return immediately */
+ return max - num_remaining;
+ }
+ }
+
+ return max - num_remaining;
+}
+
+static int iproc_rng200_init(struct hwrng *rng)
+{
+ struct iproc_rng200_dev *priv = to_rng_priv(rng);
+
+ iproc_rng200_enable_set(priv->base, true);
+
+ return 0;
+}
+
+static void iproc_rng200_cleanup(struct iproc_rng200_dev *priv)
+{
+ iproc_rng200_enable_set(priv->base, false);
+}
+
+static int iproc_rng200_probe(struct device *dev)
+{
+ struct iproc_rng200_dev *priv;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ /* Map peripheral */
+ priv->base = dev_platform_ioremap_resource(dev, 0);
+ if (IS_ERR(priv->base)) {
+ dev_err(dev, "failed to remap rng regs\n");
+ return PTR_ERR(priv->base);
+ }
+
+ dev->priv = priv;
+
+ priv->rng.name = "iproc-rng200";
+ priv->rng.read = iproc_rng200_read;
+ priv->rng.init = iproc_rng200_init;
+
+ /* Register driver */
+ ret = hwrng_register(dev, &priv->rng);
+ if (ret) {
+ dev_err(dev, "hwrng registration failed\n");
+ return ret;
+ }
+
+ dev_info(dev, "hwrng registered\n");
+
+ return 0;
+}
+
+static void iproc_rng200_remove(struct device *dev)
+{
+ iproc_rng200_cleanup(dev->priv);
+}
+
+static const struct of_device_id iproc_rng200_of_match[] = {
+ { .compatible = "brcm,bcm2711-rng200", },
+ { .compatible = "brcm,bcm7211-rng200", },
+ { .compatible = "brcm,bcm7278-rng200", },
+ { .compatible = "brcm,iproc-rng200", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, iproc_rng200_of_match);
+
+static struct driver iproc_rng200_driver = {
+ .name = "iproc-rng200",
+ .of_match_table = iproc_rng200_of_match,
+ .probe = iproc_rng200_probe,
+ .remove = iproc_rng200_remove,
+};
+device_platform_driver(iproc_rng200_driver);
+
+MODULE_AUTHOR("Broadcom");
+MODULE_DESCRIPTION("iProc RNG200 Random Number Generator driver");
+MODULE_LICENSE("GPL v2");
--
2.39.2
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 10/12] hw_random: add Rockchip RNG support
2024-03-13 10:56 [PATCH 00/12] hw_random: add 6 more RNG drivers Ahmad Fatoum
` (8 preceding siblings ...)
2024-03-13 10:56 ` [PATCH 09/12] hw_random: add IPROC RNG200 driver for BCM2711 Ahmad Fatoum
@ 2024-03-13 10:56 ` Ahmad Fatoum
2024-03-13 10:56 ` [PATCH 11/12] hw_random: add timeriomem_rng driver Ahmad Fatoum
` (2 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Ahmad Fatoum @ 2024-03-13 10:56 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
To enable proper hardening with stack protector, add support for the
Rockchip RNG. This has been tested on the RK3568.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
arch/arm/dts/rk356x.dtsi | 8 +
drivers/hw_random/Kconfig | 7 +
drivers/hw_random/Makefile | 1 +
drivers/hw_random/rockchip-rng.c | 259 +++++++++++++++++++++++++++++++
4 files changed, 275 insertions(+)
create mode 100644 drivers/hw_random/rockchip-rng.c
diff --git a/arch/arm/dts/rk356x.dtsi b/arch/arm/dts/rk356x.dtsi
index 195b42a8b0fb..923e18e7ccda 100644
--- a/arch/arm/dts/rk356x.dtsi
+++ b/arch/arm/dts/rk356x.dtsi
@@ -22,4 +22,12 @@ cpu_id: id@a {
reg = <0x0a 0x10>;
};
};
+
+ rng: rng@fe388000 {
+ compatible = "rockchip,rk3568-rng", "rockchip,cryptov2-rng";
+ reg = <0x0 0xfe388000 0x0 0x2000>;
+ clocks = <&cru CLK_TRNG_NS>, <&cru HCLK_TRNG_NS>;
+ clock-names = "trng_clk", "trng_hclk";
+ resets = <&cru SRST_TRNG_NS>;
+ };
};
diff --git a/drivers/hw_random/Kconfig b/drivers/hw_random/Kconfig
index 8aef00d61d81..58df6a75443c 100644
--- a/drivers/hw_random/Kconfig
+++ b/drivers/hw_random/Kconfig
@@ -80,4 +80,11 @@ config HW_RANDOM_IPROC_RNG200
This driver provides barebox support for the RNG200
hardware found on the BCM2711.
+config HW_RANDOM_ROCKCHIP
+ tristate "Rockchip Random Number Generator support"
+ depends on ARCH_ROCKCHIP || COMPILE_TEST
+ help
+ This driver provides barebox support for the Random Number
+ Generator hardware found on Rockchip cpus.
+
endif
diff --git a/drivers/hw_random/Makefile b/drivers/hw_random/Makefile
index 120f4c465635..8658d4e52521 100644
--- a/drivers/hw_random/Makefile
+++ b/drivers/hw_random/Makefile
@@ -10,3 +10,4 @@ obj-$(CONFIG_HW_RANDOM_OPTEE) += optee-rng.o
obj-$(CONFIG_HW_RANDOM_ATMEL) += atmel-rng.o
obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o
obj-$(CONFIG_HW_RANDOM_IPROC_RNG200) += iproc-rng200.o
+obj-$(CONFIG_HW_RANDOM_ROCKCHIP) += rockchip-rng.o
diff --git a/drivers/hw_random/rockchip-rng.c b/drivers/hw_random/rockchip-rng.c
new file mode 100644
index 000000000000..990e5fc111fd
--- /dev/null
+++ b/drivers/hw_random/rockchip-rng.c
@@ -0,0 +1,259 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * rockchip-rng.c Random Number Generator driver for the Rockchip
+ *
+ * Copyright (c) 2018, Fuzhou Rockchip Electronics Co., Ltd.
+ * Author: Lin Jinhan <troy.lin@rock-chips.com>
+ *
+ */
+#include <linux/clk.h>
+#include <linux/hw_random.h>
+#include <linux/iopoll.h>
+#include <linux/reset.h>
+#include <linux/bitfield.h>
+#include <linux/mod_devicetable.h>
+#include <of.h>
+#include <of_address.h>
+#include <linux/device.h>
+
+#define HIWORD_UPDATE(val, mask, shift) \
+ ((val) << (shift) | (mask) << ((shift) + 16))
+
+#define ROCKCHIP_AUTOSUSPEND_DELAY 100
+#define ROCKCHIP_POLL_PERIOD_US 100
+#define ROCKCHIP_POLL_TIMEOUT_US 10000
+#define RK_MAX_RNG_BYTE (32)
+
+#define CRYPTO_V1_CTRL 0x0008
+#define CRYPTO_V1_RNG_START BIT(8)
+#define CRYPTO_V1_RNG_FLUSH BIT(9)
+#define CRYPTO_V1_TRNG_CTRL 0x0200
+#define CRYPTO_V1_OSC_ENABLE BIT(16)
+#define CRYPTO_V1_TRNG_SAMPLE_PERIOD(x) (x)
+#define CRYPTO_V1_TRNG_DOUT_0 0x0204
+
+#define CRYPTO_V2_RNG_CTL 0x0400
+#define CRYPTO_V2_RNG_BIT_LEN GENMASK(5, 4)
+#define CRYPTO_V2_RNG_64_BIT_LEN FIELD_PREP(CRYPTO_V2_RNG_BIT_LEN, 0)
+#define CRYPTO_V2_RNG_128_BIT_LEN FIELD_PREP(CRYPTO_V2_RNG_BIT_LEN, 1)
+#define CRYPTO_V2_RNG_192_BIT_LEN FIELD_PREP(CRYPTO_V2_RNG_BIT_LEN, 2)
+#define CRYPTO_V2_RNG_256_BIT_LEN FIELD_PREP(CRYPTO_V2_RNG_BIT_LEN, 3)
+#define CRYPTO_V2_RNG_SOC_RING GENMASK(3, 2)
+#define CRYPTO_V2_RNG_FASTEST_SOC_RING FIELD_PREP(CRYPTO_V2_RNG_SOC_RING, 0)
+#define CRYPTO_V2_RNG_SLOWER_SOC_RING_0 FIELD_PREP(CRYPTO_V2_RNG_SOC_RING, 1)
+#define CRYPTO_V2_RNG_SLOWER_SOC_RING_1 FIELD_PREP(CRYPTO_V2_RNG_SOC_RING, 2)
+#define CRYPTO_V2_RNG_SLOWEST_SOC_RING FIELD_PREP(CRYPTO_V2_RNG_SOC_RING, 3)
+#define CRYPTO_V2_RNG_ENABLE BIT(1)
+#define CRYPTO_V2_RNG_START BIT(0)
+#define CRYPTO_V2_RNG_SAMPLE_CNT 0x0404
+#define CRYPTO_V2_RNG_DOUT_0 0x0410
+
+struct rk_rng_soc_data {
+ const char * const *clks;
+ int clks_num;
+ int (*rk_rng_read)(struct hwrng *rng, void *buf, size_t max, bool wait);
+};
+
+struct rk_rng {
+ struct device *dev;
+ struct hwrng rng;
+ void __iomem *mem;
+ struct rk_rng_soc_data *soc_data;
+ u32 clk_num;
+ struct clk_bulk_data *clk_bulks;
+};
+
+static void rk_rng_writel(struct rk_rng *rng, u32 val, u32 offset)
+{
+ __raw_writel(val, rng->mem + offset);
+}
+
+static u32 rk_rng_readl(struct rk_rng *rng, u32 offset)
+{
+ return __raw_readl(rng->mem + offset);
+}
+
+static int rk_rng_init(struct hwrng *rng)
+{
+ int ret;
+ struct rk_rng *rk_rng = container_of(rng, struct rk_rng, rng);
+
+ ret = clk_bulk_prepare_enable(rk_rng->clk_num, rk_rng->clk_bulks);
+ if (ret < 0) {
+ dev_err(rk_rng->dev, "failed to enable clks %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void rk_rng_cleanup(struct rk_rng *rk_rng)
+{
+ clk_bulk_disable_unprepare(rk_rng->clk_num, rk_rng->clk_bulks);
+}
+
+static void rk_rng_read_regs(struct rk_rng *rng, u32 offset, void *buf,
+ size_t size)
+{
+ u32 i, sample;
+
+ for (i = 0; i < size; i += 4) {
+ sample = rk_rng_readl(rng, offset + i);
+ memcpy(buf + i, &sample, sizeof(sample));
+ }
+}
+
+static int rk_rng_v1_read(struct hwrng *rng, void *buf, size_t max, bool wait)
+{
+ int ret = 0;
+ u32 reg_ctrl = 0;
+ struct rk_rng *rk_rng = container_of(rng, struct rk_rng, rng);
+
+ /* enable osc_ring to get entropy, sample period is set as 100 */
+ reg_ctrl = CRYPTO_V1_OSC_ENABLE | CRYPTO_V1_TRNG_SAMPLE_PERIOD(100);
+ rk_rng_writel(rk_rng, reg_ctrl, CRYPTO_V1_TRNG_CTRL);
+
+ reg_ctrl = HIWORD_UPDATE(CRYPTO_V1_RNG_START, CRYPTO_V1_RNG_START, 0);
+
+ rk_rng_writel(rk_rng, reg_ctrl, CRYPTO_V1_CTRL);
+
+ ret = readl_poll_timeout(rk_rng->mem + CRYPTO_V1_CTRL, reg_ctrl,
+ !(reg_ctrl & CRYPTO_V1_RNG_START),
+ ROCKCHIP_POLL_TIMEOUT_US);
+ if (ret < 0)
+ goto out;
+
+ ret = min_t(size_t, max, RK_MAX_RNG_BYTE);
+
+ rk_rng_read_regs(rk_rng, CRYPTO_V1_TRNG_DOUT_0, buf, ret);
+
+out:
+ /* close TRNG */
+ rk_rng_writel(rk_rng, HIWORD_UPDATE(0, CRYPTO_V1_RNG_START, 0),
+ CRYPTO_V1_CTRL);
+
+ return ret;
+}
+
+static int rk_rng_v2_read(struct hwrng *rng, void *buf, size_t max, bool wait)
+{
+ int ret = 0;
+ u32 reg_ctrl = 0;
+ struct rk_rng *rk_rng = container_of(rng, struct rk_rng, rng);
+
+ /* enable osc_ring to get entropy, sample period is set as 100 */
+ rk_rng_writel(rk_rng, 100, CRYPTO_V2_RNG_SAMPLE_CNT);
+
+ reg_ctrl |= CRYPTO_V2_RNG_256_BIT_LEN;
+ reg_ctrl |= CRYPTO_V2_RNG_SLOWER_SOC_RING_0;
+ reg_ctrl |= CRYPTO_V2_RNG_ENABLE;
+ reg_ctrl |= CRYPTO_V2_RNG_START;
+
+ rk_rng_writel(rk_rng, HIWORD_UPDATE(reg_ctrl, 0xffff, 0),
+ CRYPTO_V2_RNG_CTL);
+
+ ret = readl_poll_timeout(rk_rng->mem + CRYPTO_V2_RNG_CTL, reg_ctrl,
+ !(reg_ctrl & CRYPTO_V2_RNG_START),
+ ROCKCHIP_POLL_TIMEOUT_US);
+ if (ret < 0)
+ goto out;
+
+ ret = min_t(size_t, max, RK_MAX_RNG_BYTE);
+
+ rk_rng_read_regs(rk_rng, CRYPTO_V2_RNG_DOUT_0, buf, ret);
+
+out:
+ /* close TRNG */
+ rk_rng_writel(rk_rng, HIWORD_UPDATE(0, 0xffff, 0), CRYPTO_V2_RNG_CTL);
+
+ return ret;
+}
+
+static const struct rk_rng_soc_data rk_rng_rk3399_soc_data = {
+ .clks_num = 3,
+ .rk_rng_read = rk_rng_v1_read,
+};
+
+static const struct rk_rng_soc_data rk_rng_v1_soc_data = {
+ .clks_num = 2,
+ .rk_rng_read = rk_rng_v1_read,
+};
+
+static const struct rk_rng_soc_data rk_rng_v2_soc_data = {
+ .clks_num = 2,
+ .rk_rng_read = rk_rng_v2_read,
+};
+
+static const struct of_device_id rk_rng_dt_match[] = {
+ {
+ .compatible = "rockchip,rk3399-crypto",
+ .data = (void *)&rk_rng_rk3399_soc_data,
+ },
+ {
+ .compatible = "rockchip,cryptov1-rng",
+ .data = (void *)&rk_rng_v1_soc_data,
+ },
+ {
+ .compatible = "rockchip,cryptov2-rng",
+ .data = (void *)&rk_rng_v2_soc_data,
+ },
+ { },
+};
+
+MODULE_DEVICE_TABLE(of, rk_rng_dt_match);
+
+static int rk_rng_probe(struct device *dev)
+{
+ int ret;
+ struct rk_rng *rk_rng;
+ struct device_node *np = dev->of_node;
+ const struct of_device_id *match;
+
+ rk_rng = devm_kzalloc(dev, sizeof(struct rk_rng), GFP_KERNEL);
+ if (!rk_rng)
+ return -ENOMEM;
+
+ match = of_match_node(rk_rng_dt_match, np);
+ rk_rng->soc_data = (struct rk_rng_soc_data *)match->data;
+
+ rk_rng->dev = dev;
+ rk_rng->rng.name = "rockchip";
+ rk_rng->rng.init = rk_rng_init;
+ rk_rng->rng.read = rk_rng->soc_data->rk_rng_read;
+
+ rk_rng->clk_num = clk_bulk_get_all(dev, &rk_rng->clk_bulks);
+ if (rk_rng->clk_num < rk_rng->soc_data->clks_num)
+ return dev_err_probe(dev, -EINVAL,
+ "Missing clocks, got %d instead of %d\n",
+ rk_rng->clk_num, rk_rng->soc_data->clks_num);
+
+ ret = device_reset_us(dev, 2);
+ if (ret)
+ return ret;
+
+ rk_rng->mem = of_iomap(dev->device_node, 0);
+ if (IS_ERR(rk_rng->mem))
+ return PTR_ERR(rk_rng->mem);
+
+ dev->priv = rk_rng;
+
+ return hwrng_register(dev, &rk_rng->rng);
+}
+
+static void rk_rng_remove(struct device *dev)
+{
+ rk_rng_cleanup(dev->priv);
+}
+
+static struct driver rk_rng_driver = {
+ .name = "rockchip-rng",
+ .of_match_table = rk_rng_dt_match,
+ .probe = rk_rng_probe,
+ .remove = rk_rng_remove,
+};
+
+device_platform_driver(rk_rng_driver);
+
+MODULE_DESCRIPTION("ROCKCHIP H/W Random Number Generator driver");
+MODULE_AUTHOR("Lin Jinhan <troy.lin@rock-chips.com>");
+MODULE_LICENSE("GPL v2");
--
2.39.2
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 11/12] hw_random: add timeriomem_rng driver
2024-03-13 10:56 [PATCH 00/12] hw_random: add 6 more RNG drivers Ahmad Fatoum
` (9 preceding siblings ...)
2024-03-13 10:56 ` [PATCH 10/12] hw_random: add Rockchip RNG support Ahmad Fatoum
@ 2024-03-13 10:56 ` Ahmad Fatoum
2024-03-13 10:56 ` [PATCH 12/12] hw_random: add OMAP RNG driver Ahmad Fatoum
2024-03-15 7:07 ` [PATCH 00/12] hw_random: add 6 more RNG drivers Sascha Hauer
12 siblings, 0 replies; 14+ messages in thread
From: Ahmad Fatoum @ 2024-03-13 10:56 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
To enable proper hardening with stack protector, add support for the
RNGs with the interface of a single memory mapped 32-bit register.
This can possibly come in handy for the web demo.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/hw_random/Kconfig | 7 ++
drivers/hw_random/Makefile | 1 +
drivers/hw_random/timeriomem-rng.c | 145 +++++++++++++++++++++++++++++
3 files changed, 153 insertions(+)
create mode 100644 drivers/hw_random/timeriomem-rng.c
diff --git a/drivers/hw_random/Kconfig b/drivers/hw_random/Kconfig
index 58df6a75443c..bd1ac89ad37d 100644
--- a/drivers/hw_random/Kconfig
+++ b/drivers/hw_random/Kconfig
@@ -8,6 +8,13 @@ menuconfig HWRNG
if HWRNG
+config HW_RANDOM_TIMERIOMEM
+ tristate "Timer IOMEM HW Random Number Generator support"
+ help
+ This driver provides barebox support for a generic Random
+ Number Generator used by reading a 'dumb' iomem address that
+ is to be read no faster than, for example, once a second.
+
config HWRNG_MXC_RNGC
tristate "Freescale i.MX RNGC Random Number Generator"
depends on ARCH_IMX25 || ARCH_IMX35 || ARCH_IMX53 || COMPILE_TEST
diff --git a/drivers/hw_random/Makefile b/drivers/hw_random/Makefile
index 8658d4e52521..32b02fa211ac 100644
--- a/drivers/hw_random/Makefile
+++ b/drivers/hw_random/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_HW_RANDOM_ATMEL) += atmel-rng.o
obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o
obj-$(CONFIG_HW_RANDOM_IPROC_RNG200) += iproc-rng200.o
obj-$(CONFIG_HW_RANDOM_ROCKCHIP) += rockchip-rng.o
+obj-$(CONFIG_HW_RANDOM_TIMERIOMEM) += timeriomem-rng.o
diff --git a/drivers/hw_random/timeriomem-rng.c b/drivers/hw_random/timeriomem-rng.c
new file mode 100644
index 000000000000..8d4705830653
--- /dev/null
+++ b/drivers/hw_random/timeriomem-rng.c
@@ -0,0 +1,145 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * drivers/char/hw_random/timeriomem-rng.c
+ *
+ * Copyright (C) 2009 Alexander Clouter <alex@digriz.org.uk>
+ *
+ * Derived from drivers/char/hw_random/omap-rng.c
+ * Copyright 2005 (c) MontaVista Software, Inc.
+ * Author: Deepak Saxena <dsaxena@plexity.net>
+ *
+ * Overview:
+ * This driver is useful for platforms that have an IO range that provides
+ * periodic random data from a single IO memory address. All the platform
+ * has to do is provide the address and 'wait time' that new data becomes
+ * available.
+ *
+ * TODO: add support for reading sizes other than 32bits and masking
+ */
+
+#include <linux/hw_random.h>
+#include <linux/io.h>
+#include <linux/ktime.h>
+#include <of.h>
+#include <linux/device.h>
+#include <linux/time.h>
+
+struct timeriomem_rng_private {
+ void __iomem *io_base;
+
+ ktime_t period;
+ ktime_t next_read;
+
+ struct hwrng rng_ops;
+};
+
+static int timeriomem_rng_read(struct hwrng *hwrng, void *data,
+ size_t max, bool wait)
+{
+ struct timeriomem_rng_private *priv =
+ container_of(hwrng, struct timeriomem_rng_private, rng_ops);
+ int retval = 0;
+ int period_us = ktime_to_us(priv->period);
+ ktime_t now = ktime_get();
+
+ /*
+ * There may not have been enough time for new data to be generated
+ * since the last request. If the caller doesn't want to wait, let them
+ * bail out. Otherwise, wait for the completion. If the new data has
+ * already been generated, the completion should already be available.
+ */
+ if (ktime_before(now, priv->next_read)) {
+ if (!wait)
+ return 0;
+
+ udelay(ktime_to_us(ktime_sub(priv->next_read, now)));
+ }
+
+ do {
+ /*
+ * After the first read, all additional reads will need to wait
+ * for the RNG to generate new data. Since the period can have
+ * a wide range of values (1us to 1s have been observed), allow
+ * for 1% tolerance in the sleep time rather than a fixed value.
+ */
+ if (retval > 0)
+ udelay(period_us);
+
+ *(u32 *)data = readl(priv->io_base);
+ retval += sizeof(u32);
+ data += sizeof(u32);
+ max -= sizeof(u32);
+ } while (wait && max > sizeof(u32));
+
+ /*
+ * Block any new callers until the RNG has had time to generate new
+ * data.
+ */
+ priv->next_read = ktime_add(ktime_get(), priv->period);
+
+ return retval;
+}
+
+static int timeriomem_rng_probe(struct device *dev)
+{
+ struct timeriomem_rng_private *priv;
+ struct resource *res;
+ int err = 0;
+ int period;
+
+ /* Allocate memory for the device structure (and zero it) */
+ priv = devm_kzalloc(dev,
+ sizeof(struct timeriomem_rng_private), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->io_base = dev_platform_get_and_ioremap_resource(dev, 0, &res);
+ if (IS_ERR(priv->io_base))
+ return PTR_ERR(priv->io_base);
+
+ if (res->start % 4 != 0 || resource_size(res) < 4) {
+ dev_err(dev,
+ "address must be at least four bytes wide and 32-bit aligned\n");
+ return -EINVAL;
+ }
+
+ if (of_property_read_u32(dev->of_node, "period", &period))
+ return dev_err_probe(dev, -EINVAL, "missing period\n");
+
+ priv->period = ns_to_ktime(period * NSEC_PER_USEC);
+
+ priv->rng_ops.name = dev_name(dev);
+ priv->rng_ops.read = timeriomem_rng_read;
+
+ /* Assume random data is already available. */
+ priv->next_read = ktime_get();
+
+ err = hwrng_register(dev, &priv->rng_ops);
+ if (err) {
+ dev_err(dev, "problem registering\n");
+ return err;
+ }
+
+ dev_info(dev, "32bits from 0x%p @ %dus\n",
+ priv->io_base, period);
+
+ return 0;
+}
+
+static const struct of_device_id timeriomem_rng_match[] = {
+ { .compatible = "timeriomem_rng" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, timeriomem_rng_match);
+
+static struct driver timeriomem_rng_driver = {
+ .name = "timeriomem_rng",
+ .of_match_table = timeriomem_rng_match,
+ .probe = timeriomem_rng_probe,
+};
+
+device_platform_driver(timeriomem_rng_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Alexander Clouter <alex@digriz.org.uk>");
+MODULE_DESCRIPTION("Timer IOMEM H/W RNG driver");
--
2.39.2
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 12/12] hw_random: add OMAP RNG driver
2024-03-13 10:56 [PATCH 00/12] hw_random: add 6 more RNG drivers Ahmad Fatoum
` (10 preceding siblings ...)
2024-03-13 10:56 ` [PATCH 11/12] hw_random: add timeriomem_rng driver Ahmad Fatoum
@ 2024-03-13 10:56 ` Ahmad Fatoum
2024-03-15 7:07 ` [PATCH 00/12] hw_random: add 6 more RNG drivers Sascha Hauer
12 siblings, 0 replies; 14+ messages in thread
From: Ahmad Fatoum @ 2024-03-13 10:56 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
To enable proper hardening with stack protector, add support for the
OMAP RNG driver. This has been tested on a Beagle Bone Black.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
arch/arm/mach-omap/am33xx_clock.c | 5 +
drivers/hw_random/Kconfig | 8 +
drivers/hw_random/Makefile | 1 +
drivers/hw_random/omap-rng.c | 436 ++++++++++++++++++++++++++++++
include/linux/clk.h | 33 +++
include/mach/omap/am33xx-clock.h | 1 +
6 files changed, 484 insertions(+)
create mode 100644 drivers/hw_random/omap-rng.c
diff --git a/arch/arm/mach-omap/am33xx_clock.c b/arch/arm/mach-omap/am33xx_clock.c
index eeb7e93329d2..4ba10491be6c 100644
--- a/arch/arm/mach-omap/am33xx_clock.c
+++ b/arch/arm/mach-omap/am33xx_clock.c
@@ -169,6 +169,11 @@ void am33xx_enable_per_clocks(void)
__raw_writel(PRCM_MOD_EN, CM_WKUP_ADC_TSC_CLKCTRL);
while (__raw_readl(CM_WKUP_ADC_TSC_CLKCTRL) != PRCM_MOD_EN);
+ if (IS_ENABLED(CONFIG_HW_RANDOM_OMAP)) {
+ __raw_writel(PRCM_MOD_EN, CM_PER_RNG_CLKCTRL);
+ while ((__raw_readl(CM_PER_RNG_CLKCTRL) & 0x30000) != 0x0);
+ }
+
clkdcoldo = __raw_readl(CM_CLKDCOLDO_DPLL_PER);
clkdcoldo = clkdcoldo | 0x100;
__raw_writel(clkdcoldo, CM_CLKDCOLDO_DPLL_PER);
diff --git a/drivers/hw_random/Kconfig b/drivers/hw_random/Kconfig
index bd1ac89ad37d..763929f7d65d 100644
--- a/drivers/hw_random/Kconfig
+++ b/drivers/hw_random/Kconfig
@@ -94,4 +94,12 @@ config HW_RANDOM_ROCKCHIP
This driver provides barebox support for the Random Number
Generator hardware found on Rockchip cpus.
+config HW_RANDOM_OMAP
+ tristate "OMAP Random Number Generator support"
+ depends on ARCH_OMAP || ARCH_K3 || COMPILE_TEST
+ help
+ This driver provides barebox support for the Random Number
+ Generator hardware found on OMAP2/3/4/5, AM33xx/AM43xx
+ multimedia processors, and Marvell Armada 7k/8k SoCs.
+
endif
diff --git a/drivers/hw_random/Makefile b/drivers/hw_random/Makefile
index 32b02fa211ac..7f65a6c41ec7 100644
--- a/drivers/hw_random/Makefile
+++ b/drivers/hw_random/Makefile
@@ -12,3 +12,4 @@ obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o
obj-$(CONFIG_HW_RANDOM_IPROC_RNG200) += iproc-rng200.o
obj-$(CONFIG_HW_RANDOM_ROCKCHIP) += rockchip-rng.o
obj-$(CONFIG_HW_RANDOM_TIMERIOMEM) += timeriomem-rng.o
+obj-$(CONFIG_HW_RANDOM_OMAP) += omap-rng.o
diff --git a/drivers/hw_random/omap-rng.c b/drivers/hw_random/omap-rng.c
new file mode 100644
index 000000000000..9fa50bc8e7a9
--- /dev/null
+++ b/drivers/hw_random/omap-rng.c
@@ -0,0 +1,436 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * omap-rng.c - RNG driver for TI OMAP CPU family
+ *
+ * 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>
+ */
+
+#include <init.h>
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/hw_random.h>
+#include <clock.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <of.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#define RNG_REG_STATUS_RDY (1 << 0)
+
+#define RNG_REG_INTACK_RDY_MASK (1 << 0)
+#define RNG_REG_INTACK_SHUTDOWN_OFLO_MASK (1 << 1)
+#define RNG_SHUTDOWN_OFLO_MASK (1 << 1)
+
+#define RNG_CONTROL_STARTUP_CYCLES_SHIFT 16
+#define RNG_CONTROL_STARTUP_CYCLES_MASK (0xffff << 16)
+#define RNG_CONTROL_ENABLE_TRNG_SHIFT 10
+#define RNG_CONTROL_ENABLE_TRNG_MASK (1 << 10)
+
+#define RNG_CONFIG_MAX_REFIL_CYCLES_SHIFT 16
+#define RNG_CONFIG_MAX_REFIL_CYCLES_MASK (0xffff << 16)
+#define RNG_CONFIG_MIN_REFIL_CYCLES_SHIFT 0
+#define RNG_CONFIG_MIN_REFIL_CYCLES_MASK (0xff << 0)
+
+#define RNG_CONTROL_STARTUP_CYCLES 0xff
+#define RNG_CONFIG_MIN_REFIL_CYCLES 0x21
+#define RNG_CONFIG_MAX_REFIL_CYCLES 0x22
+
+#define RNG_ALARMCNT_ALARM_TH_SHIFT 0x0
+#define RNG_ALARMCNT_ALARM_TH_MASK (0xff << 0)
+#define RNG_ALARMCNT_SHUTDOWN_TH_SHIFT 16
+#define RNG_ALARMCNT_SHUTDOWN_TH_MASK (0x1f << 16)
+#define RNG_ALARM_THRESHOLD 0xff
+#define RNG_SHUTDOWN_THRESHOLD 0x4
+
+#define RNG_REG_FROENABLE_MASK 0xffffff
+#define RNG_REG_FRODETUNE_MASK 0xffffff
+
+#define OMAP2_RNG_OUTPUT_SIZE 0x4
+#define OMAP4_RNG_OUTPUT_SIZE 0x8
+#define EIP76_RNG_OUTPUT_SIZE 0x10
+
+/*
+ * EIP76 RNG takes approx. 700us to produce 16 bytes of output data
+ * as per testing results. And to account for the lack of udelay()'s
+ * reliability, we keep the timeout as 1000us.
+ */
+#define RNG_DATA_FILL_TIMEOUT 100
+
+enum {
+ RNG_OUTPUT_0_REG = 0,
+ RNG_OUTPUT_1_REG,
+ RNG_OUTPUT_2_REG,
+ RNG_OUTPUT_3_REG,
+ RNG_STATUS_REG,
+ RNG_INTMASK_REG,
+ RNG_INTACK_REG,
+ RNG_CONTROL_REG,
+ RNG_CONFIG_REG,
+ RNG_ALARMCNT_REG,
+ RNG_FROENABLE_REG,
+ RNG_FRODETUNE_REG,
+ RNG_ALARMMASK_REG,
+ RNG_ALARMSTOP_REG,
+ RNG_REV_REG,
+ RNG_SYSCONFIG_REG,
+};
+
+static const u16 reg_map_omap2[] = {
+ [RNG_OUTPUT_0_REG] = 0x0,
+ [RNG_STATUS_REG] = 0x4,
+ [RNG_CONFIG_REG] = 0x28,
+ [RNG_REV_REG] = 0x3c,
+ [RNG_SYSCONFIG_REG] = 0x40,
+};
+
+static const u16 reg_map_omap4[] = {
+ [RNG_OUTPUT_0_REG] = 0x0,
+ [RNG_OUTPUT_1_REG] = 0x4,
+ [RNG_STATUS_REG] = 0x8,
+ [RNG_INTMASK_REG] = 0xc,
+ [RNG_INTACK_REG] = 0x10,
+ [RNG_CONTROL_REG] = 0x14,
+ [RNG_CONFIG_REG] = 0x18,
+ [RNG_ALARMCNT_REG] = 0x1c,
+ [RNG_FROENABLE_REG] = 0x20,
+ [RNG_FRODETUNE_REG] = 0x24,
+ [RNG_ALARMMASK_REG] = 0x28,
+ [RNG_ALARMSTOP_REG] = 0x2c,
+ [RNG_REV_REG] = 0x1FE0,
+ [RNG_SYSCONFIG_REG] = 0x1FE4,
+};
+
+static const u16 reg_map_eip76[] = {
+ [RNG_OUTPUT_0_REG] = 0x0,
+ [RNG_OUTPUT_1_REG] = 0x4,
+ [RNG_OUTPUT_2_REG] = 0x8,
+ [RNG_OUTPUT_3_REG] = 0xc,
+ [RNG_STATUS_REG] = 0x10,
+ [RNG_INTACK_REG] = 0x10,
+ [RNG_CONTROL_REG] = 0x14,
+ [RNG_CONFIG_REG] = 0x18,
+ [RNG_ALARMCNT_REG] = 0x1c,
+ [RNG_FROENABLE_REG] = 0x20,
+ [RNG_FRODETUNE_REG] = 0x24,
+ [RNG_ALARMMASK_REG] = 0x28,
+ [RNG_ALARMSTOP_REG] = 0x2c,
+ [RNG_REV_REG] = 0x7c,
+};
+
+struct omap_rng_dev;
+/**
+ * struct omap_rng_pdata - RNG IP block-specific data
+ * @regs: Pointer to the register offsets structure.
+ * @data_size: No. of bytes in RNG output.
+ * @data_present: Callback to determine if data is available.
+ * @init: Callback for IP specific initialization sequence.
+ * @cleanup: Callback for IP specific cleanup sequence.
+ */
+struct omap_rng_pdata {
+ u16 *regs;
+ u32 data_size;
+ u32 (*data_present)(struct omap_rng_dev *priv);
+ int (*init)(struct omap_rng_dev *priv);
+ void (*cleanup)(struct omap_rng_dev *priv);
+};
+
+struct omap_rng_dev {
+ void __iomem *base;
+ struct device *dev;
+ const struct omap_rng_pdata *pdata;
+ struct hwrng rng;
+ struct clk *clk;
+ struct clk *clk_reg;
+};
+
+static inline u32 omap_rng_read(struct omap_rng_dev *priv, u16 reg)
+{
+ return __raw_readl(priv->base + priv->pdata->regs[reg]);
+}
+
+static inline void omap_rng_write(struct omap_rng_dev *priv, u16 reg,
+ u32 val)
+{
+ __raw_writel(val, priv->base + priv->pdata->regs[reg]);
+}
+
+
+static int omap_rng_do_read(struct hwrng *rng, void *data, size_t max,
+ bool wait)
+{
+ struct omap_rng_dev *priv;
+ int i, present;
+
+ priv = (struct omap_rng_dev *)rng->priv;
+
+ /* In Linux, max is always at least 32 bytes, which is greater than
+ * the 4 bytes required by the IP not to raise a data abort.
+ * In barebox, reading 4 bytes from a HWRNG is something we want
+ * support, so we check against 4 here and restrict memcpy_fromio
+ * size below.
+ */
+ if (max < sizeof(u32))
+ return -EFAULT;
+
+ for (i = 0; i < RNG_DATA_FILL_TIMEOUT; i++) {
+ present = priv->pdata->data_present(priv);
+ if (present || !wait)
+ break;
+
+ udelay(10);
+ }
+ if (!present)
+ return 0;
+
+ max = min(max, priv->pdata->data_size);
+
+ memcpy_fromio(data, priv->base + priv->pdata->regs[RNG_OUTPUT_0_REG], max);
+
+ if (priv->pdata->regs[RNG_INTACK_REG])
+ omap_rng_write(priv, RNG_INTACK_REG, RNG_REG_INTACK_RDY_MASK);
+
+ return max;
+}
+
+static int omap_rng_init(struct hwrng *rng)
+{
+ struct omap_rng_dev *priv;
+
+ priv = (struct omap_rng_dev *)rng->priv;
+ return priv->pdata->init(priv);
+}
+
+static inline u32 omap2_rng_data_present(struct omap_rng_dev *priv)
+{
+ return omap_rng_read(priv, RNG_STATUS_REG) ? 0 : 1;
+}
+
+static int omap2_rng_init(struct omap_rng_dev *priv)
+{
+ omap_rng_write(priv, RNG_SYSCONFIG_REG, 0x1);
+ return 0;
+}
+
+static void omap2_rng_cleanup(struct omap_rng_dev *priv)
+{
+ omap_rng_write(priv, RNG_SYSCONFIG_REG, 0x0);
+}
+
+static struct omap_rng_pdata omap2_rng_pdata = {
+ .regs = (u16 *)reg_map_omap2,
+ .data_size = OMAP2_RNG_OUTPUT_SIZE,
+ .data_present = omap2_rng_data_present,
+ .init = omap2_rng_init,
+ .cleanup = omap2_rng_cleanup,
+};
+
+static inline u32 omap4_rng_data_present(struct omap_rng_dev *priv)
+{
+ return omap_rng_read(priv, RNG_STATUS_REG) & RNG_REG_STATUS_RDY;
+}
+
+static int eip76_rng_init(struct omap_rng_dev *priv)
+{
+ u32 val;
+
+ /* Return if RNG is already running. */
+ if (omap_rng_read(priv, RNG_CONTROL_REG) & RNG_CONTROL_ENABLE_TRNG_MASK)
+ return 0;
+
+ /* Number of 512 bit blocks of raw Noise Source output data that must
+ * be processed by either the Conditioning Function or the
+ * SP 800-90 DRBG ‘BC_DF’ functionality to yield a ‘full entropy’
+ * output value.
+ */
+ val = 0x5 << RNG_CONFIG_MIN_REFIL_CYCLES_SHIFT;
+
+ /* Number of FRO samples that are XOR-ed together into one bit to be
+ * shifted into the main shift register
+ */
+ val |= RNG_CONFIG_MAX_REFIL_CYCLES << RNG_CONFIG_MAX_REFIL_CYCLES_SHIFT;
+ omap_rng_write(priv, RNG_CONFIG_REG, val);
+
+ /* Enable TRNG */
+ val = RNG_CONTROL_ENABLE_TRNG_MASK;
+ omap_rng_write(priv, RNG_CONTROL_REG, val);
+
+ return 0;
+}
+
+static int omap4_rng_init(struct omap_rng_dev *priv)
+{
+ u32 val;
+
+ /* Return if RNG is already running. */
+ if (omap_rng_read(priv, RNG_CONTROL_REG) & RNG_CONTROL_ENABLE_TRNG_MASK)
+ return 0;
+
+ val = RNG_CONFIG_MIN_REFIL_CYCLES << RNG_CONFIG_MIN_REFIL_CYCLES_SHIFT;
+ val |= RNG_CONFIG_MAX_REFIL_CYCLES << RNG_CONFIG_MAX_REFIL_CYCLES_SHIFT;
+ omap_rng_write(priv, RNG_CONFIG_REG, val);
+
+ val = RNG_CONTROL_STARTUP_CYCLES << RNG_CONTROL_STARTUP_CYCLES_SHIFT;
+ val |= RNG_CONTROL_ENABLE_TRNG_MASK;
+ omap_rng_write(priv, RNG_CONTROL_REG, val);
+
+ return 0;
+}
+
+static void omap4_rng_cleanup(struct omap_rng_dev *priv)
+{
+ int val;
+
+ val = omap_rng_read(priv, RNG_CONTROL_REG);
+ val &= ~RNG_CONTROL_ENABLE_TRNG_MASK;
+ omap_rng_write(priv, RNG_CONTROL_REG, val);
+}
+
+static struct omap_rng_pdata omap4_rng_pdata = {
+ .regs = (u16 *)reg_map_omap4,
+ .data_size = OMAP4_RNG_OUTPUT_SIZE,
+ .data_present = omap4_rng_data_present,
+ .init = omap4_rng_init,
+ .cleanup = omap4_rng_cleanup,
+};
+
+static struct omap_rng_pdata eip76_rng_pdata = {
+ .regs = (u16 *)reg_map_eip76,
+ .data_size = EIP76_RNG_OUTPUT_SIZE,
+ .data_present = omap4_rng_data_present,
+ .init = eip76_rng_init,
+ .cleanup = omap4_rng_cleanup,
+};
+
+static const struct of_device_id omap_rng_of_match[] __maybe_unused = {
+ {
+ .compatible = "ti,omap2-rng",
+ .data = &omap2_rng_pdata,
+ },
+ {
+ .compatible = "ti,omap4-rng",
+ .data = &omap4_rng_pdata,
+ },
+ {
+ .compatible = "inside-secure,safexcel-eip76",
+ .data = &eip76_rng_pdata,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, omap_rng_of_match);
+
+static int of_get_omap_rng_device_details(struct omap_rng_dev *priv,
+ struct device *dev)
+{
+ priv->pdata = device_get_match_data(dev);
+ if (!priv->pdata)
+ return -ENODEV;
+
+ return 0;
+}
+
+static struct clk *ti_sysc_clk_get_enabled(struct device *dev, const char *clk_id)
+{
+ struct clk *clk;
+
+ clk = clk_get_optional_enabled(dev, clk_id);
+ if (!clk)
+ clk = clk_get_optional_enabled(dev->parent, clk_id);
+
+ if (IS_ERR(clk))
+ dev_errp_probe(dev, clk, "Unable to enable the clk\n");
+ return clk;
+}
+
+static int omap_rng_probe(struct device *dev)
+{
+ struct omap_rng_dev *priv;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(struct omap_rng_dev), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->rng.read = omap_rng_do_read;
+ priv->rng.init = omap_rng_init;
+
+ priv->rng.priv = (unsigned long)priv;
+ dev->priv = priv;
+ priv->dev = dev;
+
+ priv->base = dev_platform_ioremap_resource(dev, 0);
+ if (IS_ERR(priv->base)) {
+ ret = PTR_ERR(priv->base);
+ goto err_ioremap;
+ }
+
+ priv->rng.name = devm_kstrdup(dev, dev_name(dev), GFP_KERNEL);
+ if (!priv->rng.name) {
+ ret = -ENOMEM;
+ goto err_ioremap;
+ }
+
+ priv->clk = ti_sysc_clk_get_enabled(dev, NULL);
+ if (IS_ERR(priv->clk)) {
+ ret = PTR_ERR(priv->clk);
+ goto err_ioremap;
+ }
+
+ priv->clk_reg = ti_sysc_clk_get_enabled(dev, "reg");
+ if (IS_ERR(priv->clk_reg)) {
+ ret = PTR_ERR(priv->clk_reg);
+ goto err_ioremap;
+ }
+
+ ret = of_get_omap_rng_device_details(priv, dev);
+ if (ret)
+ goto err_register;
+
+ ret = hwrng_register(dev, &priv->rng);
+ if (ret)
+ goto err_register;
+
+ dev_info(dev, "Random Number Generator ver. %02x\n",
+ omap_rng_read(priv, RNG_REV_REG));
+
+ return 0;
+
+err_register:
+ priv->base = NULL;
+
+ clk_disable_unprepare(priv->clk_reg);
+ clk_disable_unprepare(priv->clk);
+err_ioremap:
+ dev_err(dev, "initialization failed.\n");
+ return ret;
+}
+
+static void omap_rng_remove(struct device *dev)
+{
+ struct omap_rng_dev *priv = dev->priv;
+
+
+ priv->pdata->cleanup(priv);
+
+ clk_disable_unprepare(priv->clk);
+ clk_disable_unprepare(priv->clk_reg);
+}
+
+static struct driver omap_rng_driver = {
+ .name = "omap_rng",
+ .of_match_table = of_match_ptr(omap_rng_of_match),
+ .probe = omap_rng_probe,
+ .remove = omap_rng_remove,
+};
+
+device_platform_driver(omap_rng_driver);
+MODULE_ALIAS("platform:omap_rng");
+MODULE_AUTHOR("Deepak Saxena (and others)");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/clk.h b/include/linux/clk.h
index fe0b1ce3e36c..7ba0679d03d6 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -1097,6 +1097,39 @@ static inline struct clk *clk_get_enabled(struct device *dev, const char *id)
return clk;
}
+/**
+ * clk_get_optional_enabled - clk_get_optional() +
+ * clk_prepare_enable()
+ * @dev: device for clock "consumer"
+ * @id: clock consumer ID
+ *
+ * Return: a struct clk corresponding to the clock producer, or
+ * valid IS_ERR() condition containing errno. The implementation
+ * uses @dev and @id to determine the clock consumer, and thereby
+ * the clock producer. If no such clk is found, it returns NULL
+ * which serves as a dummy clk. That's the only difference compared
+ * to clk_get_enabled().
+ *
+ * The returned clk (if valid) is enabled.
+ */
+static inline struct clk *clk_get_optional_enabled(struct device *dev, const char *id)
+{
+ struct clk *clk;
+ int ret;
+
+ clk = clk_get_optional(dev, id);
+ if (IS_ERR_OR_NULL(clk))
+ return clk;
+
+ ret = clk_enable(clk);
+ if (ret) {
+ clk_put(clk);
+ return ERR_PTR(ret);
+ }
+
+ return clk;
+}
+
/**
* clk_get_if_available - get clock, ignoring known unavailable clock controller
* @dev: device for clock "consumer"
diff --git a/include/mach/omap/am33xx-clock.h b/include/mach/omap/am33xx-clock.h
index b0293db990a3..af47a0f3e77a 100644
--- a/include/mach/omap/am33xx-clock.h
+++ b/include/mach/omap/am33xx-clock.h
@@ -139,6 +139,7 @@
#define CM_PER_UART4_CLKCTRL (CM_PER + 0x78) /* UART4 */
#define CM_PER_I2C1_CLKCTRL (CM_PER + 0x48) /* I2C1 */
#define CM_PER_I2C2_CLKCTRL (CM_PER + 0x44) /* I2C2 */
+#define CM_PER_RNG_CLKCTRL (CM_PER + 0x90) /* RNG */
#define CM_WKUP_GPIO0_CLKCTRL (CM_WKUP + 0x8) /* GPIO0 */
#define CM_WKUP_ADC_TSC_CLKCTRL (CM_WKUP + 0xbc)/* TSCADC */
--
2.39.2
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 00/12] hw_random: add 6 more RNG drivers
2024-03-13 10:56 [PATCH 00/12] hw_random: add 6 more RNG drivers Ahmad Fatoum
` (11 preceding siblings ...)
2024-03-13 10:56 ` [PATCH 12/12] hw_random: add OMAP RNG driver Ahmad Fatoum
@ 2024-03-15 7:07 ` Sascha Hauer
12 siblings, 0 replies; 14+ messages in thread
From: Sascha Hauer @ 2024-03-15 7:07 UTC (permalink / raw)
To: barebox, Ahmad Fatoum
On Wed, 13 Mar 2024 11:56:19 +0100, Ahmad Fatoum wrote:
> While stack protector support can be used without HWRNG, it will
> print a warning about the fixed canary to alert to the fact that it
> requires a random canary to be able to withstand an attacker.
>
> Linux HWRNG drivers are surprisingly easy to port to barebox though,
> so let's import 6 for commonly used platforms.
>
> [...]
Applied, thanks!
[01/12] hw_random: support ctrlc()
https://git.pengutronix.de/cgit/barebox/commit/?id=ee25397f700f (link may not be stable)
[02/12] ARM: io: read 32 bits at once for aligned I/O memcpy/memset
https://git.pengutronix.de/cgit/barebox/commit/?id=8e006fa8a9cd (link may not be stable)
[03/12] driver: implement dev_platform_get_and_ioremap_resource
https://git.pengutronix.de/cgit/barebox/commit/?id=c38ff416cbe1 (link may not be stable)
[04/12] hw_random: add struct hwrng::priv member
https://git.pengutronix.de/cgit/barebox/commit/?id=d151afa2a6d5 (link may not be stable)
[05/12] hw_random: remove confusing left-overs from kernel help texts
https://git.pengutronix.de/cgit/barebox/commit/?id=bceb7ba902ad (link may not be stable)
[06/12] hw_random: remove reference to undefined CONFIG_HW_RANDOM
https://git.pengutronix.de/cgit/barebox/commit/?id=51bcfb1b5788 (link may not be stable)
[07/12] hw_random: add Atmel RNG driver
https://git.pengutronix.de/cgit/barebox/commit/?id=3aafb07324f6 (link may not be stable)
[08/12] hw_random: add BCM2835 RNG driver
https://git.pengutronix.de/cgit/barebox/commit/?id=3140bcb3f779 (link may not be stable)
[09/12] hw_random: add IPROC RNG200 driver for BCM2711
https://git.pengutronix.de/cgit/barebox/commit/?id=233ae72300e5 (link may not be stable)
[10/12] hw_random: add Rockchip RNG support
https://git.pengutronix.de/cgit/barebox/commit/?id=f9cd14f8ae30 (link may not be stable)
[11/12] hw_random: add timeriomem_rng driver
https://git.pengutronix.de/cgit/barebox/commit/?id=45080577a633 (link may not be stable)
[12/12] hw_random: add OMAP RNG driver
https://git.pengutronix.de/cgit/barebox/commit/?id=276048a59a22 (link may not be stable)
Best regards,
--
Sascha Hauer <s.hauer@pengutronix.de>
^ permalink raw reply [flat|nested] 14+ messages in thread