misc: turris_omnia_mcu: Add support for rng provided by MCU

Add support for true random number generator provided by the MCU on
Turris Omnia. The MCU firmware supports TRNG if the FEAT_TRNG bit is set
in features. In that case we bind the rng driver.

Signed-off-by: Marek Behún <kabel@kernel.org>
Reviewed-by: Stefan Roese <sr@denx.de>
This commit is contained in:
Marek Behún 2024-04-04 09:51:06 +02:00 committed by Stefan Roese
parent 144c01678a
commit 8593e2e909
3 changed files with 59 additions and 0 deletions

View File

@ -107,6 +107,7 @@ CONFIG_NVME_PCI=y
CONFIG_PCI_MVEBU=y
CONFIG_PINCTRL=y
CONFIG_PINCTRL_ARMADA_38X=y
CONFIG_DM_RNG=y
CONFIG_DM_RTC=y
CONFIG_RTC_ARMADA38X=y
CONFIG_SERIAL_PROBE_ALL=y

View File

@ -509,6 +509,7 @@ config TURRIS_OMNIA_MCU
bool "Enable Turris Omnia MCU driver"
depends on DM_I2C
depends on DM_GPIO
depends on DM_RNG
depends on SYSRESET
default y if TARGET_TURRIS_OMNIA
help

View File

@ -5,15 +5,20 @@
*/
#include <common.h>
#include <console.h>
#include <dm.h>
#include <dm/lists.h>
#include <i2c.h>
#include <rng.h>
#include <sysreset.h>
#include <turris-omnia-mcu-interface.h>
#include <asm/byteorder.h>
#include <asm/gpio.h>
#include <linux/delay.h>
#include <linux/log2.h>
#define CMD_TRNG_MAX_ENTROPY_LEN 64
struct turris_omnia_mcu_info {
u32 features;
};
@ -282,6 +287,49 @@ U_BOOT_DRIVER(turris_omnia_mcu_sysreset) = {
.ops = &omnia_sysreset_ops,
};
static int omnia_rng_read(struct udevice *dev, void *data, size_t count)
{
u8 buf[1 + CMD_TRNG_MAX_ENTROPY_LEN];
size_t len;
int ret;
while (count) {
ret = dm_i2c_read(dev->parent, CMD_TRNG_COLLECT_ENTROPY, buf,
sizeof(buf));
if (ret)
return ret;
len = min_t(size_t, buf[0],
min_t(size_t, CMD_TRNG_MAX_ENTROPY_LEN, count));
if (!len) {
/* wait 500ms (fail if interrupted), then try again */
for (int i = 0; i < 5; ++i) {
mdelay(100);
if (ctrlc())
return -EINTR;
}
continue;
}
memcpy(data, &buf[1], len);
data += len;
count -= len;
}
return 0;
}
static const struct dm_rng_ops omnia_rng_ops = {
.read = omnia_rng_read,
};
U_BOOT_DRIVER(turris_omnia_mcu_trng) = {
.name = "turris-omnia-mcu-trng",
.id = UCLASS_RNG,
.ops = &omnia_rng_ops,
};
static int turris_omnia_mcu_bind(struct udevice *dev)
{
/* bind MCU GPIOs as a child device */
@ -336,6 +384,15 @@ static int turris_omnia_mcu_probe(struct udevice *dev)
return ret;
}
/* bind rng if trng is supported */
if (info->features & FEAT_TRNG) {
ret = device_bind_driver_to_node(dev, "turris-omnia-mcu-trng",
"turris-omnia-mcu-trng",
dev_ofnode(dev), NULL);
if (ret < 0)
return ret;
}
return 0;
}