diff options
| author | Marek BehĂșn <kabel@kernel.org> | 2024-04-04 09:51:06 +0200 | 
|---|---|---|
| committer | Stefan Roese <sr@denx.de> | 2024-04-04 10:45:27 +0200 | 
| commit | 8593e2e909fe24ddc180d3fe82eec9debe9cfb20 (patch) | |
| tree | 74e6503e5539e35ef51782bdb7ecb55c7d929618 /drivers/misc/turris_omnia_mcu.c | |
| parent | 144c01678a10683657cade783e791a0061d66320 (diff) | |
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>
Diffstat (limited to 'drivers/misc/turris_omnia_mcu.c')
| -rw-r--r-- | drivers/misc/turris_omnia_mcu.c | 57 | 
1 files changed, 57 insertions, 0 deletions
| diff --git a/drivers/misc/turris_omnia_mcu.c b/drivers/misc/turris_omnia_mcu.c index 77a0424d61c..6b2f17c0002 100644 --- a/drivers/misc/turris_omnia_mcu.c +++ b/drivers/misc/turris_omnia_mcu.c @@ -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;  } | 
