summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/clk/stm32/clk-stm32mp1.c7
-rw-r--r--drivers/core/dump.c3
-rw-r--r--drivers/firmware/ti_sci.c11
-rw-r--r--drivers/ram/stm32mp1/stm32mp1_ram.c3
-rw-r--r--drivers/rng/Kconfig8
-rw-r--r--drivers/rng/Makefile2
-rw-r--r--drivers/rng/stm32_rng.c408
-rw-r--r--drivers/rng/stm32mp1_rng.c198
8 files changed, 431 insertions, 209 deletions
diff --git a/drivers/clk/stm32/clk-stm32mp1.c b/drivers/clk/stm32/clk-stm32mp1.c
index 61502876949..f3ac8c75831 100644
--- a/drivers/clk/stm32/clk-stm32mp1.c
+++ b/drivers/clk/stm32/clk-stm32mp1.c
@@ -72,6 +72,7 @@ DECLARE_GLOBAL_DATA_PTR;
#define RCC_PLL2CSGR 0xA4
#define RCC_I2C46CKSELR 0xC0
#define RCC_SPI6CKSELR 0xC4
+#define RCC_UART1CKSELR 0xC8
#define RCC_CPERCKSELR 0xD0
#define RCC_STGENCKSELR 0xD4
#define RCC_DDRITFCR 0xD8
@@ -317,6 +318,7 @@ enum stm32mp1_parent_sel {
_SPI45_SEL,
_SPI6_SEL,
_RTC_SEL,
+ _UART1_SEL,
_PARENT_SEL_NB,
_UNKNOWN_SEL = 0xff,
};
@@ -557,6 +559,7 @@ static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = {
STM32MP1_CLK_SET_CLR(RCC_MP_APB5ENSETR, 0, SPI6_K, _SPI6_SEL),
STM32MP1_CLK_SET_CLR(RCC_MP_APB5ENSETR, 2, I2C4_K, _I2C46_SEL),
STM32MP1_CLK_SET_CLR(RCC_MP_APB5ENSETR, 3, I2C6_K, _I2C46_SEL),
+ STM32MP1_CLK_SET_CLR(RCC_MP_APB5ENSETR, 4, USART1_K, _UART1_SEL),
STM32MP1_CLK_SET_CLR(RCC_MP_APB5ENSETR, 8, RTCAPB, _PCLK5),
STM32MP1_CLK_SET_CLR(RCC_MP_APB5ENSETR, 16, BSEC, _UNKNOWN_SEL),
STM32MP1_CLK_SET_CLR(RCC_MP_APB5ENSETR, 20, STGEN_K, _STGEN_SEL),
@@ -602,6 +605,8 @@ static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = {
static const u8 i2c12_parents[] = {_PCLK1, _PLL4_R, _HSI_KER, _CSI_KER};
static const u8 i2c35_parents[] = {_PCLK1, _PLL4_R, _HSI_KER, _CSI_KER};
static const u8 i2c46_parents[] = {_PCLK5, _PLL3_Q, _HSI_KER, _CSI_KER};
+static const u8 uart1_parents[] = {_PCLK5, _PLL3_Q, _HSI_KER, _CSI_KER,
+ _PLL4_Q, _HSE_KER};
static const u8 uart6_parents[] = {_PCLK2, _PLL4_Q, _HSI_KER, _CSI_KER,
_HSE_KER};
static const u8 uart24_parents[] = {_PCLK1, _PLL4_Q, _HSI_KER, _CSI_KER,
@@ -659,6 +664,7 @@ static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = {
STM32MP1_CLK_PARENT(_RTC_SEL, RCC_BDCR, RCC_BDCR_RTCSRC_SHIFT,
(RCC_BDCR_RTCSRC_MASK >> RCC_BDCR_RTCSRC_SHIFT),
rtc_parents),
+ STM32MP1_CLK_PARENT(_UART1_SEL, RCC_UART1CKSELR, 0, 0x7, uart1_parents),
};
#ifdef STM32MP1_CLOCK_TREE_INIT
@@ -786,6 +792,7 @@ char * const stm32mp1_clk_parent_sel_name[_PARENT_SEL_NB] = {
[_SPI1_SEL] = "SPI1",
[_SPI45_SEL] = "SPI45",
[_RTC_SEL] = "RTC",
+ [_UART1_SEL] = "UART1",
};
static const struct stm32mp1_clk_data stm32mp1_data = {
diff --git a/drivers/core/dump.c b/drivers/core/dump.c
index 4023b390f54..841124830ee 100644
--- a/drivers/core/dump.c
+++ b/drivers/core/dump.c
@@ -90,9 +90,8 @@ static void dm_dump_tree_single(struct udevice *dev, bool sort)
int dev_count, uclasses;
struct udevice **devs = NULL;
- dm_get_stats(&dev_count, &uclasses);
-
if (sort) {
+ dm_get_stats(&dev_count, &uclasses);
devs = calloc(dev_count, sizeof(struct udevice *));
if (!devs) {
printf("(out of memory)\n");
diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
index 72f572d8248..166bd78ca50 100644
--- a/drivers/firmware/ti_sci.c
+++ b/drivers/firmware/ti_sci.c
@@ -2690,6 +2690,8 @@ static void ti_sci_setup_ops(struct ti_sci_info *info)
const
struct ti_sci_handle *ti_sci_get_handle_from_sysfw(struct udevice *sci_dev)
{
+ int ret;
+
if (!sci_dev)
return ERR_PTR(-EINVAL);
@@ -2703,6 +2705,11 @@ struct ti_sci_handle *ti_sci_get_handle_from_sysfw(struct udevice *sci_dev)
if (!handle)
return ERR_PTR(-EINVAL);
+ ret = ti_sci_cmd_get_revision(handle);
+
+ if (ret)
+ return ERR_PTR(-EINVAL);
+
return handle;
}
@@ -2825,11 +2832,9 @@ static int ti_sci_probe(struct udevice *dev)
list_add_tail(&info->list, &ti_sci_list);
ti_sci_setup_ops(info);
- ret = ti_sci_cmd_get_revision(&info->handle);
-
INIT_LIST_HEAD(&info->dev_list);
- return ret;
+ return 0;
}
/**
diff --git a/drivers/ram/stm32mp1/stm32mp1_ram.c b/drivers/ram/stm32mp1/stm32mp1_ram.c
index 61bc002d979..a82b1db7592 100644
--- a/drivers/ram/stm32mp1/stm32mp1_ram.c
+++ b/drivers/ram/stm32mp1/stm32mp1_ram.c
@@ -127,7 +127,8 @@ static int stm32mp1_ddr_setup(struct udevice *dev)
dev_dbg(dev, "no st,mem-name\n");
return -EINVAL;
}
- printf("RAM: %s\n", config.info.name);
+ if (CONFIG_IS_ENABLED(DISPLAY_PRINT))
+ printf("RAM: %s\n", config.info.name);
for (idx = 0; idx < ARRAY_SIZE(param); idx++) {
ret = ofnode_read_u32_array(node, param[idx].name,
diff --git a/drivers/rng/Kconfig b/drivers/rng/Kconfig
index 5deb5db5b71..24666bff987 100644
--- a/drivers/rng/Kconfig
+++ b/drivers/rng/Kconfig
@@ -48,11 +48,11 @@ config RNG_OPTEE
accessible to normal world but reserved and used by the OP-TEE
to avoid the weakness of a software PRNG.
-config RNG_STM32MP1
- bool "Enable random number generator for STM32MP1"
- depends on ARCH_STM32MP
+config RNG_STM32
+ bool "Enable random number generator for STM32"
+ depends on ARCH_STM32 || ARCH_STM32MP
help
- Enable STM32MP1 rng driver.
+ Enable STM32 rng driver.
config RNG_ROCKCHIP
bool "Enable random number generator for rockchip crypto rng"
diff --git a/drivers/rng/Makefile b/drivers/rng/Makefile
index 78f61051acf..192f911e155 100644
--- a/drivers/rng/Makefile
+++ b/drivers/rng/Makefile
@@ -9,7 +9,7 @@ obj-$(CONFIG_RNG_SANDBOX) += sandbox_rng.o
obj-$(CONFIG_RNG_MSM) += msm_rng.o
obj-$(CONFIG_RNG_NPCM) += npcm_rng.o
obj-$(CONFIG_RNG_OPTEE) += optee_rng.o
-obj-$(CONFIG_RNG_STM32MP1) += stm32mp1_rng.o
+obj-$(CONFIG_RNG_STM32) += stm32_rng.o
obj-$(CONFIG_RNG_ROCKCHIP) += rockchip_rng.o
obj-$(CONFIG_RNG_IPROC200) += iproc_rng200.o
obj-$(CONFIG_RNG_SMCCC_TRNG) += smccc_trng.o
diff --git a/drivers/rng/stm32_rng.c b/drivers/rng/stm32_rng.c
new file mode 100644
index 00000000000..c397b4d95cd
--- /dev/null
+++ b/drivers/rng/stm32_rng.c
@@ -0,0 +1,408 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019, Linaro Limited
+ */
+
+#define LOG_CATEGORY UCLASS_RNG
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <log.h>
+#include <reset.h>
+#include <rng.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+
+#include <asm/io.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+
+#define RNG_CR 0x00
+#define RNG_CR_RNGEN BIT(2)
+#define RNG_CR_CED BIT(5)
+#define RNG_CR_CONFIG1 GENMASK(11, 8)
+#define RNG_CR_NISTC BIT(12)
+#define RNG_CR_CONFIG2 GENMASK(15, 13)
+#define RNG_CR_CLKDIV_SHIFT 16
+#define RNG_CR_CLKDIV GENMASK(19, 16)
+#define RNG_CR_CONFIG3 GENMASK(25, 20)
+#define RNG_CR_CONDRST BIT(30)
+#define RNG_CR_ENTROPY_SRC_MASK (RNG_CR_CONFIG1 | RNG_CR_NISTC | RNG_CR_CONFIG2 | RNG_CR_CONFIG3)
+#define RNG_CR_CONFIG_MASK (RNG_CR_ENTROPY_SRC_MASK | RNG_CR_CED | RNG_CR_CLKDIV)
+
+#define RNG_SR 0x04
+#define RNG_SR_SEIS BIT(6)
+#define RNG_SR_CEIS BIT(5)
+#define RNG_SR_SECS BIT(2)
+#define RNG_SR_DRDY BIT(0)
+
+#define RNG_DR 0x08
+
+#define RNG_NSCR 0x0C
+#define RNG_NSCR_MASK GENMASK(17, 0)
+
+#define RNG_HTCR 0x10
+
+#define RNG_NB_RECOVER_TRIES 3
+
+/*
+ * struct stm32_rng_data - RNG compat data
+ *
+ * @max_clock_rate: Max RNG clock frequency, in Hertz
+ * @cr: Entropy source configuration
+ * @nscr: Noice sources control configuration
+ * @htcr: Health tests configuration
+ * @has_cond_reset: True if conditionnal reset is supported
+ *
+ */
+struct stm32_rng_data {
+ uint max_clock_rate;
+ u32 cr;
+ u32 nscr;
+ u32 htcr;
+ bool has_cond_reset;
+};
+
+struct stm32_rng_plat {
+ fdt_addr_t base;
+ struct clk clk;
+ struct reset_ctl rst;
+ const struct stm32_rng_data *data;
+ bool ced;
+};
+
+/*
+ * Extracts from the STM32 RNG specification when RNG supports CONDRST.
+ *
+ * When a noise source (or seed) error occurs, the RNG stops generating
+ * random numbers and sets to “1” both SEIS and SECS bits to indicate
+ * that a seed error occurred. (...)
+ *
+ * 1. Software reset by writing CONDRST at 1 and at 0 (see bitfield
+ * description for details). This step is needed only if SECS is set.
+ * Indeed, when SEIS is set and SECS is cleared it means RNG performed
+ * the reset automatically (auto-reset).
+ * 2. If SECS was set in step 1 (no auto-reset) wait for CONDRST
+ * to be cleared in the RNG_CR register, then confirm that SEIS is
+ * cleared in the RNG_SR register. Otherwise just clear SEIS bit in
+ * the RNG_SR register.
+ * 3. If SECS was set in step 1 (no auto-reset) wait for SECS to be
+ * cleared by RNG. The random number generation is now back to normal.
+ */
+static int stm32_rng_conceal_seed_error_cond_reset(struct stm32_rng_plat *pdata)
+{
+ u32 sr = readl_relaxed(pdata->base + RNG_SR);
+ u32 cr = readl_relaxed(pdata->base + RNG_CR);
+ int err;
+
+ if (sr & RNG_SR_SECS) {
+ /* Conceal by resetting the subsystem (step 1.) */
+ writel_relaxed(cr | RNG_CR_CONDRST, pdata->base + RNG_CR);
+ writel_relaxed(cr & ~RNG_CR_CONDRST, pdata->base + RNG_CR);
+ } else {
+ /* RNG auto-reset (step 2.) */
+ writel_relaxed(sr & ~RNG_SR_SEIS, pdata->base + RNG_SR);
+ return 0;
+ }
+
+ err = readl_relaxed_poll_timeout(pdata->base + RNG_SR, sr, !(sr & RNG_CR_CONDRST), 100000);
+ if (err) {
+ log_err("%s: timeout %x\n", __func__, sr);
+ return err;
+ }
+
+ /* Check SEIS is cleared (step 2.) */
+ if (readl_relaxed(pdata->base + RNG_SR) & RNG_SR_SEIS)
+ return -EINVAL;
+
+ err = readl_relaxed_poll_timeout(pdata->base + RNG_SR, sr, !(sr & RNG_SR_SECS), 100000);
+ if (err) {
+ log_err("%s: timeout %x\n", __func__, sr);
+ return err;
+ }
+
+ return 0;
+}
+
+/*
+ * Extracts from the STM32 RNG specification, when CONDRST is not supported
+ *
+ * When a noise source (or seed) error occurs, the RNG stops generating
+ * random numbers and sets to “1” both SEIS and SECS bits to indicate
+ * that a seed error occurred. (...)
+ *
+ * The following sequence shall be used to fully recover from a seed
+ * error after the RNG initialization:
+ * 1. Clear the SEIS bit by writing it to “0”.
+ * 2. Read out 12 words from the RNG_DR register, and discard each of
+ * them in order to clean the pipeline.
+ * 3. Confirm that SEIS is still cleared. Random number generation is
+ * back to normal.
+ */
+static int stm32_rng_conceal_seed_error_sw_reset(struct stm32_rng_plat *pdata)
+{
+ uint i = 0;
+ u32 sr = readl_relaxed(pdata->base + RNG_SR);
+
+ writel_relaxed(sr & ~RNG_SR_SEIS, pdata->base + RNG_SR);
+
+ for (i = 12; i != 0; i--)
+ (void)readl_relaxed(pdata->base + RNG_DR);
+
+ if (readl_relaxed(pdata->base + RNG_SR) & RNG_SR_SEIS)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int stm32_rng_conceal_seed_error(struct stm32_rng_plat *pdata)
+{
+ log_debug("Concealing RNG seed error\n");
+
+ if (pdata->data->has_cond_reset)
+ return stm32_rng_conceal_seed_error_cond_reset(pdata);
+ else
+ return stm32_rng_conceal_seed_error_sw_reset(pdata);
+};
+
+static int stm32_rng_read(struct udevice *dev, void *data, size_t len)
+{
+ int retval;
+ u32 sr, reg;
+ size_t increment;
+ struct stm32_rng_plat *pdata = dev_get_plat(dev);
+ uint tries = 0;
+
+ while (len > 0) {
+ retval = readl_poll_timeout(pdata->base + RNG_SR, sr,
+ sr, 10000);
+ if (retval) {
+ log_err("%s: Timeout RNG no data", __func__);
+ return retval;
+ }
+
+ if (sr != RNG_SR_DRDY) {
+ if (sr & RNG_SR_SEIS) {
+ retval = stm32_rng_conceal_seed_error(pdata);
+ tries++;
+ if (retval || tries > RNG_NB_RECOVER_TRIES) {
+ log_err("%s: Couldn't recover from seed error", __func__);
+ return -ENOTRECOVERABLE;
+ }
+
+ /* Start again */
+ continue;
+ }
+
+ if (sr & RNG_SR_CEIS) {
+ log_info("RNG clock too slow");
+ writel_relaxed(0, pdata->base + RNG_SR);
+ }
+ }
+
+ /*
+ * Once the DRDY bit is set, the RNG_DR register can
+ * be read up to four consecutive times.
+ */
+ reg = readl(pdata->base + RNG_DR);
+ /* Late seed error case: DR being 0 is an error status */
+ if (!reg) {
+ retval = stm32_rng_conceal_seed_error(pdata);
+ tries++;
+
+ if (retval || tries > RNG_NB_RECOVER_TRIES) {
+ log_err("%s: Couldn't recover from seed error", __func__);
+ return -ENOTRECOVERABLE;
+ }
+
+ /* Start again */
+ continue;
+ }
+
+ increment = min(len, sizeof(u32));
+ memcpy(data, &reg, increment);
+ data += increment;
+ len -= increment;
+
+ tries = 0;
+ }
+
+ return 0;
+}
+
+static uint stm32_rng_clock_freq_restrain(struct stm32_rng_plat *pdata)
+{
+ ulong clock_rate = 0;
+ uint clock_div = 0;
+
+ clock_rate = clk_get_rate(&pdata->clk);
+
+ /*
+ * Get the exponent to apply on the CLKDIV field in RNG_CR register.
+ * No need to handle the case when clock-div > 0xF as it is physically
+ * impossible.
+ */
+ while ((clock_rate >> clock_div) > pdata->data->max_clock_rate)
+ clock_div++;
+
+ log_debug("RNG clk rate : %lu\n", clk_get_rate(&pdata->clk) >> clock_div);
+
+ return clock_div;
+}
+
+static int stm32_rng_init(struct stm32_rng_plat *pdata)
+{
+ int err;
+ u32 cr, sr;
+
+ err = clk_enable(&pdata->clk);
+ if (err)
+ return err;
+
+ cr = readl(pdata->base + RNG_CR);
+
+ /*
+ * Keep default RNG configuration if none was specified, that is when conf.cr is set to 0.
+ */
+ if (pdata->data->has_cond_reset && pdata->data->cr) {
+ uint clock_div = stm32_rng_clock_freq_restrain(pdata);
+
+ cr &= ~RNG_CR_CONFIG_MASK;
+ cr |= RNG_CR_CONDRST | (pdata->data->cr & RNG_CR_ENTROPY_SRC_MASK) |
+ (clock_div << RNG_CR_CLKDIV_SHIFT);
+ if (pdata->ced)
+ cr &= ~RNG_CR_CED;
+ else
+ cr |= RNG_CR_CED;
+ writel(cr, pdata->base + RNG_CR);
+
+ /* Health tests and noise control registers */
+ writel_relaxed(pdata->data->htcr, pdata->base + RNG_HTCR);
+ writel_relaxed(pdata->data->nscr & RNG_NSCR_MASK, pdata->base + RNG_NSCR);
+
+ cr &= ~RNG_CR_CONDRST;
+ cr |= RNG_CR_RNGEN;
+ writel(cr, pdata->base + RNG_CR);
+ err = readl_poll_timeout(pdata->base + RNG_CR, cr,
+ (!(cr & RNG_CR_CONDRST)), 10000);
+ if (err) {
+ log_err("%s: Timeout!", __func__);
+ return err;
+ }
+ } else {
+ if (pdata->data->has_cond_reset)
+ cr |= RNG_CR_CONDRST;
+
+ if (pdata->ced)
+ cr &= ~RNG_CR_CED;
+ else
+ cr |= RNG_CR_CED;
+
+ writel(cr, pdata->base + RNG_CR);
+
+ if (pdata->data->has_cond_reset)
+ cr &= ~RNG_CR_CONDRST;
+
+ cr |= RNG_CR_RNGEN;
+
+ writel(cr, pdata->base + RNG_CR);
+ }
+
+ /* clear error indicators */
+ writel(0, pdata->base + RNG_SR);
+
+ err = readl_poll_timeout(pdata->base + RNG_SR, sr,
+ sr & RNG_SR_DRDY, 10000);
+ if (err)
+ log_err("%s: Timeout!", __func__);
+
+ return err;
+}
+
+static int stm32_rng_cleanup(struct stm32_rng_plat *pdata)
+{
+ writel(0, pdata->base + RNG_CR);
+
+ return clk_disable(&pdata->clk);
+}
+
+static int stm32_rng_probe(struct udevice *dev)
+{
+ struct stm32_rng_plat *pdata = dev_get_plat(dev);
+
+ pdata->data = (struct stm32_rng_data *)dev_get_driver_data(dev);
+
+ reset_assert(&pdata->rst);
+ udelay(20);
+ reset_deassert(&pdata->rst);
+
+ return stm32_rng_init(pdata);
+}
+
+static int stm32_rng_remove(struct udevice *dev)
+{
+ struct stm32_rng_plat *pdata = dev_get_plat(dev);
+
+ return stm32_rng_cleanup(pdata);
+}
+
+static int stm32_rng_of_to_plat(struct udevice *dev)
+{
+ struct stm32_rng_plat *pdata = dev_get_plat(dev);
+ int err;
+
+ pdata->base = dev_read_addr(dev);
+ if (!pdata->base)
+ return -ENOMEM;
+
+ err = clk_get_by_index(dev, 0, &pdata->clk);
+ if (err)
+ return err;
+
+ err = reset_get_by_index(dev, 0, &pdata->rst);
+ if (err)
+ return err;
+
+ pdata->ced = dev_read_bool(dev, "clock-error-detect");
+
+ return 0;
+}
+
+static const struct dm_rng_ops stm32_rng_ops = {
+ .read = stm32_rng_read,
+};
+
+static const struct stm32_rng_data stm32mp13_rng_data = {
+ .has_cond_reset = true,
+ .max_clock_rate = 48000000,
+ .htcr = 0x969D,
+ .nscr = 0x2B5BB,
+ .cr = 0xF00D00,
+};
+
+static const struct stm32_rng_data stm32_rng_data = {
+ .has_cond_reset = false,
+ .max_clock_rate = 3000000,
+ /* Not supported */
+ .htcr = 0,
+ .nscr = 0,
+ .cr = 0,
+};
+
+static const struct udevice_id stm32_rng_match[] = {
+ {.compatible = "st,stm32mp13-rng", .data = (ulong)&stm32mp13_rng_data},
+ {.compatible = "st,stm32-rng", .data = (ulong)&stm32_rng_data},
+ {},
+};
+
+U_BOOT_DRIVER(stm32_rng) = {
+ .name = "stm32-rng",
+ .id = UCLASS_RNG,
+ .of_match = stm32_rng_match,
+ .ops = &stm32_rng_ops,
+ .probe = stm32_rng_probe,
+ .remove = stm32_rng_remove,
+ .plat_auto = sizeof(struct stm32_rng_plat),
+ .of_to_plat = stm32_rng_of_to_plat,
+};
diff --git a/drivers/rng/stm32mp1_rng.c b/drivers/rng/stm32mp1_rng.c
deleted file mode 100644
index 89da78c6c8b..00000000000
--- a/drivers/rng/stm32mp1_rng.c
+++ /dev/null
@@ -1,198 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (c) 2019, Linaro Limited
- */
-
-#define LOG_CATEGORY UCLASS_RNG
-
-#include <common.h>
-#include <clk.h>
-#include <dm.h>
-#include <log.h>
-#include <reset.h>
-#include <rng.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-
-#include <asm/io.h>
-#include <linux/iopoll.h>
-#include <linux/kernel.h>
-
-#define RNG_CR 0x00
-#define RNG_CR_RNGEN BIT(2)
-#define RNG_CR_CED BIT(5)
-#define RNG_CR_CONDRST BIT(30)
-
-#define RNG_SR 0x04
-#define RNG_SR_SEIS BIT(6)
-#define RNG_SR_CEIS BIT(5)
-#define RNG_SR_SECS BIT(2)
-#define RNG_SR_DRDY BIT(0)
-
-#define RNG_DR 0x08
-
-struct stm32_rng_data {
- bool has_cond_reset;
-};
-
-struct stm32_rng_plat {
- fdt_addr_t base;
- struct clk clk;
- struct reset_ctl rst;
- const struct stm32_rng_data *data;
-};
-
-static int stm32_rng_read(struct udevice *dev, void *data, size_t len)
-{
- int retval, i;
- u32 sr, count, reg;
- size_t increment;
- struct stm32_rng_plat *pdata = dev_get_plat(dev);
-
- while (len > 0) {
- retval = readl_poll_timeout(pdata->base + RNG_SR, sr,
- sr & RNG_SR_DRDY, 10000);
- if (retval)
- return retval;
-
- if (sr & (RNG_SR_SEIS | RNG_SR_SECS)) {
- /* As per SoC TRM */
- clrbits_le32(pdata->base + RNG_SR, RNG_SR_SEIS);
- for (i = 0; i < 12; i++)
- readl(pdata->base + RNG_DR);
- if (readl(pdata->base + RNG_SR) & RNG_SR_SEIS) {
- log_err("RNG Noise");
- return -EIO;
- }
- /* start again */
- continue;
- }
-
- /*
- * Once the DRDY bit is set, the RNG_DR register can
- * be read four consecutive times.
- */
- count = 4;
- while (len && count) {
- reg = readl(pdata->base + RNG_DR);
- memcpy(data, &reg, min(len, sizeof(u32)));
- increment = min(len, sizeof(u32));
- data += increment;
- len -= increment;
- count--;
- }
- }
-
- return 0;
-}
-
-static int stm32_rng_init(struct stm32_rng_plat *pdata)
-{
- int err;
- u32 cr, sr;
-
- err = clk_enable(&pdata->clk);
- if (err)
- return err;
-
- cr = readl(pdata->base + RNG_CR);
-
- /* Disable CED */
- cr |= RNG_CR_CED;
- if (pdata->data->has_cond_reset) {
- cr |= RNG_CR_CONDRST;
- writel(cr, pdata->base + RNG_CR);
- cr &= ~RNG_CR_CONDRST;
- writel(cr, pdata->base + RNG_CR);
- err = readl_poll_timeout(pdata->base + RNG_CR, cr,
- (!(cr & RNG_CR_CONDRST)), 10000);
- if (err)
- return err;
- }
-
- /* clear error indicators */
- writel(0, pdata->base + RNG_SR);
-
- cr |= RNG_CR_RNGEN;
- writel(cr, pdata->base + RNG_CR);
-
- err = readl_poll_timeout(pdata->base + RNG_SR, sr,
- sr & RNG_SR_DRDY, 10000);
- return err;
-}
-
-static int stm32_rng_cleanup(struct stm32_rng_plat *pdata)
-{
- writel(0, pdata->base + RNG_CR);
-
- return clk_disable(&pdata->clk);
-}
-
-static int stm32_rng_probe(struct udevice *dev)
-{
- struct stm32_rng_plat *pdata = dev_get_plat(dev);
-
- pdata->data = (struct stm32_rng_data *)dev_get_driver_data(dev);
-
- reset_assert(&pdata->rst);
- udelay(20);
- reset_deassert(&pdata->rst);
-
- return stm32_rng_init(pdata);
-}
-
-static int stm32_rng_remove(struct udevice *dev)
-{
- struct stm32_rng_plat *pdata = dev_get_plat(dev);
-
- return stm32_rng_cleanup(pdata);
-}
-
-static int stm32_rng_of_to_plat(struct udevice *dev)
-{
- struct stm32_rng_plat *pdata = dev_get_plat(dev);
- int err;
-
- pdata->base = dev_read_addr(dev);
- if (!pdata->base)
- return -ENOMEM;
-
- err = clk_get_by_index(dev, 0, &pdata->clk);
- if (err)
- return err;
-
- err = reset_get_by_index(dev, 0, &pdata->rst);
- if (err)
- return err;
-
- return 0;
-}
-
-static const struct dm_rng_ops stm32_rng_ops = {
- .read = stm32_rng_read,
-};
-
-static const struct stm32_rng_data stm32mp13_rng_data = {
- .has_cond_reset = true,
-};
-
-static const struct stm32_rng_data stm32_rng_data = {
- .has_cond_reset = false,
-};
-
-static const struct udevice_id stm32_rng_match[] = {
- {.compatible = "st,stm32mp13-rng", .data = (ulong)&stm32mp13_rng_data},
- {.compatible = "st,stm32-rng", .data = (ulong)&stm32_rng_data},
- {},
-};
-
-U_BOOT_DRIVER(stm32_rng) = {
- .name = "stm32-rng",
- .id = UCLASS_RNG,
- .of_match = stm32_rng_match,
- .ops = &stm32_rng_ops,
- .probe = stm32_rng_probe,
- .remove = stm32_rng_remove,
- .plat_auto = sizeof(struct stm32_rng_plat),
- .of_to_plat = stm32_rng_of_to_plat,
-};