[U-Boot] [PATCH v1 0/4] Update STM32MP1 machine

This series : _ fixes TAMP_BOOT_CONTEXT which is updated twice _ adds bsec IP driver (Boot and Security and OTP control) _ adds FUSE command support _ updates machine to use OTP to store MAC address and serial number
Patrick Delaunay (4): stm32mp1: remove the second TAMP_BOOT_CONTEXT update stm32mp1: add bsec driver stm32mp1: add FUSE command support stm32mp1: use OTP to configure MAC address and serial number
MAINTAINERS | 1 + arch/arm/Kconfig | 1 + arch/arm/mach-stm32mp/Makefile | 8 +- arch/arm/mach-stm32mp/bsec.c | 431 +++++++++++++++++++++++++++++ arch/arm/mach-stm32mp/cpu.c | 81 ++++++ arch/arm/mach-stm32mp/include/mach/stm32.h | 5 + arch/arm/mach-stm32mp/spl.c | 3 - configs/stm32mp15_basic_defconfig | 1 + drivers/misc/Kconfig | 9 + drivers/misc/Makefile | 1 + drivers/misc/stm32mp_fuse.c | 116 ++++++++ 11 files changed, 652 insertions(+), 5 deletions(-) create mode 100644 arch/arm/mach-stm32mp/bsec.c create mode 100644 drivers/misc/stm32mp_fuse.c

From: Patrick Delaunay patrick.delaunay@st.com
The register TAMP_BOOT_CONTEXT is already updated in get_bootmode() in cpu.c and no need to be done twice.
Signed-off-by: Patrick Delaunay patrick.delaunay@st.com Signed-off-by: Patrice Chotard patrice.chotard@st.com ---
arch/arm/mach-stm32mp/spl.c | 3 --- 1 file changed, 3 deletions(-)
diff --git a/arch/arm/mach-stm32mp/spl.c b/arch/arm/mach-stm32mp/spl.c index b56f0c5381c3..790973e8b6e9 100644 --- a/arch/arm/mach-stm32mp/spl.c +++ b/arch/arm/mach-stm32mp/spl.c @@ -14,9 +14,6 @@ u32 spl_boot_device(void)
boot_mode = (readl(TAMP_BOOT_CONTEXT) & TAMP_BOOT_MODE_MASK) >> TAMP_BOOT_MODE_SHIFT; - clrsetbits_le32(TAMP_BOOT_CONTEXT, - TAMP_BOOT_MODE_MASK, - boot_mode << TAMP_BOOT_MODE_SHIFT);
switch (boot_mode) { case BOOT_FLASH_SD_1:

On Thu, May 17, 2018 at 03:24:04PM +0200, Patrice Chotard wrote:
From: Patrick Delaunay patrick.delaunay@st.com
The register TAMP_BOOT_CONTEXT is already updated in get_bootmode() in cpu.c and no need to be done twice.
Signed-off-by: Patrick Delaunay patrick.delaunay@st.com Signed-off-by: Patrice Chotard patrice.chotard@st.com
Applied to u-boot/master, thanks!

From: Patrick Delaunay patrick.delaunay@st.com
Add a MISC driver with read and write access to BSEC IP (Boot and Security and OTP control) - offset 0: shadowed values - offset 0x80000000: OTP fuse box values (SAFMEM)
Signed-off-by: Patrick Delaunay patrick.delaunay@st.com Signed-off-by: Patrice Chotard patrice.chotard@st.com ---
arch/arm/mach-stm32mp/Makefile | 8 +- arch/arm/mach-stm32mp/bsec.c | 431 +++++++++++++++++++++++++++++ arch/arm/mach-stm32mp/include/mach/stm32.h | 5 + 3 files changed, 442 insertions(+), 2 deletions(-) create mode 100644 arch/arm/mach-stm32mp/bsec.c
diff --git a/arch/arm/mach-stm32mp/Makefile b/arch/arm/mach-stm32mp/Makefile index 08ee642d9086..f59ced5ee1b1 100644 --- a/arch/arm/mach-stm32mp/Makefile +++ b/arch/arm/mach-stm32mp/Makefile @@ -1,4 +1,4 @@ -# SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +# SPDX-License-Identifier: GPL-2.0+ # # Copyright (C) 2018, STMicroelectronics - All Rights Reserved # @@ -7,6 +7,10 @@ obj-y += cpu.o obj-y += dram_init.o obj-y += syscon.o
-obj-$(CONFIG_SPL_BUILD) += spl.o +ifdef CONFIG_SPL_BUILD +obj-y += spl.o +else +obj-y += bsec.o +endif obj-$(CONFIG_ARMV7_PSCI) += psci.o obj-$(CONFIG_$(SPL_)DM_REGULATOR) += pwr_regulator.o diff --git a/arch/arm/mach-stm32mp/bsec.c b/arch/arm/mach-stm32mp/bsec.c new file mode 100644 index 000000000000..0e152efc045f --- /dev/null +++ b/arch/arm/mach-stm32mp/bsec.c @@ -0,0 +1,431 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + */ + +#include <common.h> +#include <dm.h> +#include <misc.h> +#include <asm/io.h> +#include <linux/iopoll.h> + +#define BSEC_OTP_MAX_VALUE 95 + +#define BSEC_TIMEOUT_US 10000 + +/* BSEC REGISTER OFFSET (base relative) */ +#define BSEC_OTP_CONF_OFF 0x000 +#define BSEC_OTP_CTRL_OFF 0x004 +#define BSEC_OTP_WRDATA_OFF 0x008 +#define BSEC_OTP_STATUS_OFF 0x00C +#define BSEC_OTP_LOCK_OFF 0x010 +#define BSEC_DISTURBED_OFF 0x01C +#define BSEC_ERROR_OFF 0x034 +#define BSEC_SPLOCK_OFF 0x064 /* Program safmem sticky lock */ +#define BSEC_SWLOCK_OFF 0x07C /* write in OTP sticky lock */ +#define BSEC_SRLOCK_OFF 0x094 /* shadowing sticky lock */ +#define BSEC_OTP_DATA_OFF 0x200 + +/* BSEC_CONFIGURATION Register MASK */ +#define BSEC_CONF_POWER_UP 0x001 + +/* BSEC_CONTROL Register */ +#define BSEC_READ 0x000 +#define BSEC_WRITE 0x100 + +/* LOCK Register */ +#define OTP_LOCK_MASK 0x1F +#define OTP_LOCK_BANK_SHIFT 0x05 +#define OTP_LOCK_BIT_MASK 0x01 + +/* STATUS Register */ +#define BSEC_MODE_BUSY_MASK 0x08 +#define BSEC_MODE_PROGFAIL_MASK 0x10 +#define BSEC_MODE_PWR_MASK 0x20 + +/* + * OTP Lock services definition + * Value must corresponding to the bit number in the register + */ +#define BSEC_LOCK_PROGRAM 0x04 + +/** + * bsec_check_error() - Check status of one otp + * @base: base address of bsec IP + * @otp: otp number (0 - BSEC_OTP_MAX_VALUE) + * Return: 0 if no error, -EAGAIN or -ENOTSUPP + */ +static u32 bsec_check_error(u32 base, u32 otp) +{ + u32 bit; + u32 bank; + + bit = 1 << (otp & OTP_LOCK_MASK); + bank = ((otp >> OTP_LOCK_BANK_SHIFT) & OTP_LOCK_MASK) * sizeof(u32); + + if (readl(base + BSEC_DISTURBED_OFF + bank) & bit) + return -EAGAIN; + else if (readl(base + BSEC_ERROR_OFF + bank) & bit) + return -ENOTSUPP; + + return 0; +} + +/** + * bsec_lock() - manage lock for each type SR/SP/SW + * @address: address of bsec IP register + * @otp: otp number (0 - BSEC_OTP_MAX_VALUE) + * Return: true if locked else false + */ +static bool bsec_read_lock(u32 address, u32 otp) +{ + u32 bit; + u32 bank; + + bit = 1 << (otp & OTP_LOCK_MASK); + bank = ((otp >> OTP_LOCK_BANK_SHIFT) & OTP_LOCK_MASK) * sizeof(u32); + + return !!(readl(address + bank) & bit); +} + +/** + * bsec_read_SR_lock() - read SR lock (Shadowing) + * @base: base address of bsec IP + * @otp: otp number (0 - BSEC_OTP_MAX_VALUE) + * Return: true if locked else false + */ +static bool bsec_read_SR_lock(u32 base, u32 otp) +{ + return bsec_read_lock(base + BSEC_SRLOCK_OFF, otp); +} + +/** + * bsec_read_SP_lock() - read SP lock (program Lock) + * @base: base address of bsec IP + * @otp: otp number (0 - BSEC_OTP_MAX_VALUE) + * Return: true if locked else false + */ +static bool bsec_read_SP_lock(u32 base, u32 otp) +{ + return bsec_read_lock(base + BSEC_SPLOCK_OFF, otp); +} + +/** + * bsec_SW_lock() - manage SW lock (Write in Shadow) + * @base: base address of bsec IP + * @otp: otp number (0 - BSEC_OTP_MAX_VALUE) + * Return: true if locked else false + */ +static bool bsec_read_SW_lock(u32 base, u32 otp) +{ + return bsec_read_lock(base + BSEC_SWLOCK_OFF, otp); +} + +/** + * bsec_power_safmem() - Activate or deactivate safmem power + * @base: base address of bsec IP + * @power: true to power up , false to power down + * Return: 0 if succeed + */ +static int bsec_power_safmem(u32 base, bool power) +{ + u32 val; + u32 mask; + + if (power) { + setbits_le32(base + BSEC_OTP_CONF_OFF, BSEC_CONF_POWER_UP); + mask = BSEC_MODE_PWR_MASK; + } else { + clrbits_le32(base + BSEC_OTP_CONF_OFF, BSEC_CONF_POWER_UP); + mask = 0; + } + + /* waiting loop */ + return readl_poll_timeout(base + BSEC_OTP_STATUS_OFF, + val, (val & BSEC_MODE_PWR_MASK) == mask, + BSEC_TIMEOUT_US); +} + +/** + * bsec_shadow_register() - copy safmen otp to bsec data + * @base: base address of bsec IP + * @otp: otp number (0 - BSEC_OTP_MAX_VALUE) + * Return: 0 if no error + */ +static int bsec_shadow_register(u32 base, u32 otp) +{ + u32 val; + int ret; + bool power_up = false; + + /* check if shadowing of otp is locked */ + if (bsec_read_SR_lock(base, otp)) + pr_debug("bsec : OTP %d is locked and refreshed with 0\n", otp); + + /* check if safemem is power up */ + val = readl(base + BSEC_OTP_STATUS_OFF); + if (!(val & BSEC_MODE_PWR_MASK)) { + ret = bsec_power_safmem(base, true); + if (ret) + return ret; + power_up = 1; + } + /* set BSEC_OTP_CTRL_OFF with the otp value*/ + writel(otp | BSEC_READ, base + BSEC_OTP_CTRL_OFF); + + /* check otp status*/ + ret = readl_poll_timeout(base + BSEC_OTP_STATUS_OFF, + val, (val & BSEC_MODE_BUSY_MASK) == 0, + BSEC_TIMEOUT_US); + if (ret) + return ret; + + ret = bsec_check_error(base, otp); + + if (power_up) + bsec_power_safmem(base, false); + + return ret; +} + +/** + * bsec_read_shadow() - read an otp data value from shadow + * @base: base address of bsec IP + * @val: read value + * @otp: otp number (0 - BSEC_OTP_MAX_VALUE) + * Return: 0 if no error + */ +static int bsec_read_shadow(u32 base, u32 *val, u32 otp) +{ + *val = readl(base + BSEC_OTP_DATA_OFF + otp * sizeof(u32)); + + return bsec_check_error(base, otp); +} + +/** + * bsec_write_shadow() - write value in BSEC data register in shadow + * @base: base address of bsec IP + * @val: value to write + * @otp: otp number (0 - BSEC_OTP_MAX_VALUE) + * Return: 0 if no error + */ +static int bsec_write_shadow(u32 base, u32 val, u32 otp) +{ + /* check if programming of otp is locked */ + if (bsec_read_SW_lock(base, otp)) + pr_debug("bsec : OTP %d is lock, write will be ignore\n", otp); + + writel(val, base + BSEC_OTP_DATA_OFF + otp * sizeof(u32)); + + return bsec_check_error(base, otp); +} + +/** + * bsec_program_otp() - program a bit in SAFMEM + * @base: base address of bsec IP + * @val: value to program + * @otp: otp number (0 - BSEC_OTP_MAX_VALUE) + * after the function the otp data is not refreshed in shadow + * Return: 0 if no error + */ +static int bsec_program_otp(long base, u32 val, u32 otp) +{ + u32 ret; + bool power_up = false; + + if (bsec_read_SP_lock(base, otp)) + pr_debug("bsec : OTP %d locked, prog will be ignore\n", otp); + + if (readl(base + BSEC_OTP_LOCK_OFF) & (1 << BSEC_LOCK_PROGRAM)) + pr_debug("bsec : Global lock, prog will be ignore\n"); + + /* check if safemem is power up */ + if (!(readl(base + BSEC_OTP_STATUS_OFF) & BSEC_MODE_PWR_MASK)) { + ret = bsec_power_safmem(base, true); + if (ret) + return ret; + + power_up = true; + } + /* set value in write register*/ + writel(val, base + BSEC_OTP_WRDATA_OFF); + + /* set BSEC_OTP_CTRL_OFF with the otp value */ + writel(otp | BSEC_WRITE, base + BSEC_OTP_CTRL_OFF); + + /* check otp status*/ + ret = readl_poll_timeout(base + BSEC_OTP_STATUS_OFF, + val, (val & BSEC_MODE_BUSY_MASK) == 0, + BSEC_TIMEOUT_US); + if (ret) + return ret; + + if (val & BSEC_MODE_PROGFAIL_MASK) + ret = -EACCES; + else + ret = bsec_check_error(base, otp); + + if (power_up) + bsec_power_safmem(base, false); + + return ret; +} + +/* BSEC MISC driver *******************************************************/ +struct stm32mp_bsec_platdata { + u32 base; +}; + +static int stm32mp_bsec_read_otp(struct udevice *dev, u32 *val, u32 otp) +{ + struct stm32mp_bsec_platdata *plat = dev_get_platdata(dev); + u32 tmp_data = 0; + int ret; + + /* read current shadow value */ + ret = bsec_read_shadow(plat->base, &tmp_data, otp); + if (ret) + return ret; + + /* copy otp in shadow */ + ret = bsec_shadow_register(plat->base, otp); + if (ret) + return ret; + + ret = bsec_read_shadow(plat->base, val, otp); + if (ret) + return ret; + + /* restore shadow value */ + ret = bsec_write_shadow(plat->base, tmp_data, otp); + return ret; +} + +static int stm32mp_bsec_read_shadow(struct udevice *dev, u32 *val, u32 otp) +{ + struct stm32mp_bsec_platdata *plat = dev_get_platdata(dev); + + return bsec_read_shadow(plat->base, val, otp); +} + +static int stm32mp_bsec_write_otp(struct udevice *dev, u32 val, u32 otp) +{ + struct stm32mp_bsec_platdata *plat = dev_get_platdata(dev); + + return bsec_program_otp(plat->base, val, otp); +} + +static int stm32mp_bsec_write_shadow(struct udevice *dev, u32 val, u32 otp) +{ + struct stm32mp_bsec_platdata *plat = dev_get_platdata(dev); + + return bsec_write_shadow(plat->base, val, otp); +} + +static int stm32mp_bsec_read(struct udevice *dev, int offset, + void *buf, int size) +{ + int ret; + int i; + bool shadow = true; + int nb_otp = size / sizeof(u32); + int otp; + + if (offset >= STM32_BSEC_OTP_OFFSET) { + offset -= STM32_BSEC_OTP_OFFSET; + shadow = false; + } + otp = offset / sizeof(u32); + + if (otp < 0 || (otp + nb_otp - 1) > BSEC_OTP_MAX_VALUE) { + dev_err(dev, "wrong value for otp, max value : %i\n", + BSEC_OTP_MAX_VALUE); + return -EINVAL; + } + + for (i = otp; i < (otp + nb_otp); i++) { + u32 *addr = &((u32 *)buf)[i - otp]; + + if (shadow) + ret = stm32mp_bsec_read_shadow(dev, addr, i); + else + ret = stm32mp_bsec_read_otp(dev, addr, i); + + if (ret) + break; + } + return ret; +} + +static int stm32mp_bsec_write(struct udevice *dev, int offset, + const void *buf, int size) +{ + int ret = 0; + int i; + bool shadow = true; + int nb_otp = size / sizeof(u32); + int otp; + + if (offset >= STM32_BSEC_OTP_OFFSET) { + offset -= STM32_BSEC_OTP_OFFSET; + shadow = false; + } + otp = offset / sizeof(u32); + + if (otp < 0 || (otp + nb_otp - 1) > BSEC_OTP_MAX_VALUE) { + dev_err(dev, "wrong value for otp, max value : %d\n", + BSEC_OTP_MAX_VALUE); + return -EINVAL; + } + + for (i = otp; i < otp + nb_otp; i++) { + u32 *val = &((u32 *)buf)[i - otp]; + + if (shadow) + ret = stm32mp_bsec_write_shadow(dev, *val, i); + else + ret = stm32mp_bsec_write_otp(dev, *val, i); + if (ret) + break; + } + return ret; +} + +static const struct misc_ops stm32mp_bsec_ops = { + .read = stm32mp_bsec_read, + .write = stm32mp_bsec_write, +}; + +static int stm32mp_bsec_ofdata_to_platdata(struct udevice *dev) +{ + struct stm32mp_bsec_platdata *plat = dev_get_platdata(dev); + + plat->base = (u32)dev_read_addr_ptr(dev); + + return 0; +} + +static const struct udevice_id stm32mp_bsec_ids[] = { + { .compatible = "st,stm32mp-bsec" }, + {} +}; + +U_BOOT_DRIVER(stm32mp_bsec) = { + .name = "stm32mp_bsec", + .id = UCLASS_MISC, + .of_match = stm32mp_bsec_ids, + .ofdata_to_platdata = stm32mp_bsec_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct stm32mp_bsec_platdata), + .ops = &stm32mp_bsec_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + +/* bsec IP is not present in device tee, manage IP address by platdata */ +static struct stm32mp_bsec_platdata stm32_bsec_platdata = { + .base = STM32_BSEC_BASE, +}; + +U_BOOT_DEVICE(stm32mp_bsec) = { + .name = "stm32mp_bsec", + .platdata = &stm32_bsec_platdata, +}; diff --git a/arch/arm/mach-stm32mp/include/mach/stm32.h b/arch/arm/mach-stm32mp/include/mach/stm32.h index 129f9f558eac..5d0bdca1787d 100644 --- a/arch/arm/mach-stm32mp/include/mach/stm32.h +++ b/arch/arm/mach-stm32mp/include/mach/stm32.h @@ -13,6 +13,7 @@ #define STM32_RCC_BASE 0x50000000 #define STM32_PWR_BASE 0x50001000 #define STM32_DBGMCU_BASE 0x50081000 +#define STM32_BSEC_BASE 0x5C005000 #define STM32_TZC_BASE 0x5C006000 #define STM32_ETZPC_BASE 0x5C007000 #define STM32_TAMP_BASE 0x5C00A000 @@ -95,5 +96,9 @@ enum boot_device { #define TAMP_BOOT_DEVICE_MASK GENMASK(7, 4) #define TAMP_BOOT_INSTANCE_MASK GENMASK(3, 0)
+/* offset used for BSEC driver: misc_read and misc_write */ +#define STM32_BSEC_SHADOW_OFFSET 0x0 +#define STM32_BSEC_OTP_OFFSET 0x80000000 + #endif /* __ASSEMBLY__*/ #endif /* _MACH_STM32_H_ */

On Thu, May 17, 2018 at 03:24:05PM +0200, Patrice Chotard wrote:
From: Patrick Delaunay patrick.delaunay@st.com
Add a MISC driver with read and write access to BSEC IP (Boot and Security and OTP control)
- offset 0: shadowed values
- offset 0x80000000: OTP fuse box values (SAFMEM)
Signed-off-by: Patrick Delaunay patrick.delaunay@st.com Signed-off-by: Patrice Chotard patrice.chotard@st.com
Applied to u-boot/master, thanks!

From: Patrick Delaunay patrick.delaunay@st.com
Add support of fuse command (read/write/program/sense) on bank 0 to access to BSEC SAFMEM (4096 OTP bits).
Signed-off-by: Patrick Delaunay patrick.delaunay@st.com Signed-off-by: Patrice Chotard patrice.chotard@st.com ---
MAINTAINERS | 1 + arch/arm/Kconfig | 1 + configs/stm32mp15_basic_defconfig | 1 + drivers/misc/Kconfig | 9 +++ drivers/misc/Makefile | 1 + drivers/misc/stm32mp_fuse.c | 116 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 129 insertions(+) create mode 100644 drivers/misc/stm32mp_fuse.c
diff --git a/MAINTAINERS b/MAINTAINERS index 5670917b41b9..3209dcd31844 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -204,6 +204,7 @@ M: Patrick Delaunay patrick.delaunay@st.com S: Maintained F: arch/arm/mach-stm32mp F: drivers/clk/clk_stm32mp1.c +F: drivers/misc/stm32mp_fuse.c F: drivers/ram/stm32mp1/
ARM STM STV0991 diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index c9d6e0a42418..5bd6749309b7 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1214,6 +1214,7 @@ config ARCH_STM32MP select DM_SERIAL select OF_CONTROL select OF_LIBFDT + select MISC select PINCTRL select REGMAP select SUPPORT_SPL diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig index b1c3690c0094..9e43cc969850 100644 --- a/configs/stm32mp15_basic_defconfig +++ b/configs/stm32mp15_basic_defconfig @@ -18,6 +18,7 @@ CONFIG_SYS_PROMPT="STM32MP> " # CONFIG_CMD_EXPORTENV is not set # CONFIG_CMD_IMPORTENV is not set CONFIG_CMD_MEMINFO=y +CONFIG_CMD_FUSE=y CONFIG_CMD_GPIO=y CONFIG_CMD_GPT=y CONFIG_CMD_I2C=y diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index be900cf4d6ec..17b3a805a2d5 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -158,6 +158,15 @@ config PCA9551_I2C_ADDR help The I2C address of the PCA9551 LED controller.
+config STM32MP_FUSE + bool "Enable STM32MP fuse wrapper providing the fuse API" + depends on ARCH_STM32MP && MISC + default y if CMD_FUSE + help + If you say Y here, you will get support for the fuse API (OTP) + for STM32MP architecture. + This API is needed for CMD_FUSE. + config STM32_RCC bool "Enable RCC driver for the STM32 SoC's family" depends on STM32 && MISC diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index e362609d62a4..4ce9d213f06f 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -51,5 +51,6 @@ obj-$(CONFIG_WINBOND_W83627) += winbond_w83627.o obj-$(CONFIG_QFW) += qfw.o obj-$(CONFIG_ROCKCHIP_EFUSE) += rockchip-efuse.o obj-$(CONFIG_STM32_RCC) += stm32_rcc.o +obj-$(CONFIG_STM32MP_FUSE) += stm32mp_fuse.o obj-$(CONFIG_SYS_DPAA_QBMAN) += fsl_portals.o obj-$(CONFIG_GDSYS_RXAUI_CTRL) += gdsys_rxaui_ctrl.o diff --git a/drivers/misc/stm32mp_fuse.c b/drivers/misc/stm32mp_fuse.c new file mode 100644 index 000000000000..2d661351a17c --- /dev/null +++ b/drivers/misc/stm32mp_fuse.c @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + */ + +#include <common.h> +#include <command.h> +#include <misc.h> +#include <errno.h> +#include <dm/device.h> +#include <dm/uclass.h> + +#define STM32MP_OTP_BANK 0 + +/* + * The 'fuse' command API + */ +int fuse_read(u32 bank, u32 word, u32 *val) +{ + int ret = 0; + struct udevice *dev; + + switch (bank) { + case STM32MP_OTP_BANK: + ret = uclass_get_device_by_driver(UCLASS_MISC, + DM_GET_DRIVER(stm32mp_bsec), + &dev); + if (ret) + return ret; + ret = misc_read(dev, word * 4 + STM32_BSEC_SHADOW_OFFSET, + val, 4); + break; + + default: + printf("stm32mp %s: wrong value for bank %i\n", __func__, bank); + ret = -EINVAL; + break; + } + + return ret; +} + +int fuse_prog(u32 bank, u32 word, u32 val) +{ + struct udevice *dev; + int ret; + + switch (bank) { + case STM32MP_OTP_BANK: + ret = uclass_get_device_by_driver(UCLASS_MISC, + DM_GET_DRIVER(stm32mp_bsec), + &dev); + if (ret) + return ret; + ret = misc_write(dev, word * 4 + STM32_BSEC_OTP_OFFSET, + &val, 4); + break; + + default: + printf("stm32mp %s: wrong value for bank %i\n", __func__, bank); + ret = -EINVAL; + break; + } + + return ret; +} + +int fuse_sense(u32 bank, u32 word, u32 *val) +{ + struct udevice *dev; + int ret; + + switch (bank) { + case STM32MP_OTP_BANK: + ret = uclass_get_device_by_driver(UCLASS_MISC, + DM_GET_DRIVER(stm32mp_bsec), + &dev); + if (ret) + return ret; + ret = misc_read(dev, word * 4 + STM32_BSEC_OTP_OFFSET, val, 4); + break; + + default: + printf("stm32mp %s: wrong value for bank %i\n", __func__, bank); + ret = -EINVAL; + break; + } + + return ret; +} + +int fuse_override(u32 bank, u32 word, u32 val) +{ + struct udevice *dev; + int ret; + + switch (bank) { + case STM32MP_OTP_BANK: + ret = uclass_get_device_by_driver(UCLASS_MISC, + DM_GET_DRIVER(stm32mp_bsec), + &dev); + if (ret) + return ret; + ret = misc_write(dev, word * 4 + STM32_BSEC_SHADOW_OFFSET, + &val, 4); + break; + + default: + printf("stm32mp %s: wrong value for bank %i\n", + __func__, bank); + ret = -EINVAL; + break; + } + + return ret; +}

On Thu, May 17, 2018 at 03:24:06PM +0200, Patrice Chotard wrote:
From: Patrick Delaunay patrick.delaunay@st.com
Add support of fuse command (read/write/program/sense) on bank 0 to access to BSEC SAFMEM (4096 OTP bits).
Signed-off-by: Patrick Delaunay patrick.delaunay@st.com Signed-off-by: Patrice Chotard patrice.chotard@st.com
Applied to u-boot/master, thanks!

From: Patrick Delaunay patrick.delaunay@st.com
Use OTP57 and 58 for MAC address - OTP57 = MAC address bits [31:0] - OTP58 = MAC address bit [47:32] stored in OTP LSB's
Use manufacture information in OTP13 to OTP15 to build unique chip id saved in env variable "serial#" (used for USB device enumeration)
Signed-off-by: Patrick Delaunay patrick.delaunay@st.com Signed-off-by: Patrice Chotard patrice.chotard@st.com ---
arch/arm/mach-stm32mp/cpu.c | 81 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+)
diff --git a/arch/arm/mach-stm32mp/cpu.c b/arch/arm/mach-stm32mp/cpu.c index 2deee0961822..0e01f8e61385 100644 --- a/arch/arm/mach-stm32mp/cpu.c +++ b/arch/arm/mach-stm32mp/cpu.c @@ -5,9 +5,12 @@ #include <common.h> #include <clk.h> #include <debug_uart.h> +#include <environment.h> +#include <misc.h> #include <asm/io.h> #include <asm/arch/stm32.h> #include <asm/arch/sys_proto.h> +#include <dm/device.h> #include <dm/uclass.h>
/* RCC register */ @@ -51,6 +54,10 @@ #define BOOTROM_INSTANCE_MASK GENMASK(31, 16) #define BOOTROM_INSTANCE_SHIFT 16
+/* BSEC OTP index */ +#define BSEC_OTP_SERIAL 13 +#define BSEC_OTP_MAC 57 + #if !defined(CONFIG_SPL) || defined(CONFIG_SPL_BUILD) static void security_init(void) { @@ -274,9 +281,83 @@ static void setup_boot_mode(void) } }
+/* + * If there is no MAC address in the environment, then it will be initialized + * (silently) from the value in the OTP. + */ +static int setup_mac_address(void) +{ +#if defined(CONFIG_NET) + int ret; + int i; + u32 otp[2]; + uchar enetaddr[6]; + struct udevice *dev; + + /* MAC already in environment */ + if (eth_env_get_enetaddr("ethaddr", enetaddr)) + return 0; + + ret = uclass_get_device_by_driver(UCLASS_MISC, + DM_GET_DRIVER(stm32mp_bsec), + &dev); + if (ret) + return ret; + + ret = misc_read(dev, BSEC_OTP_MAC * 4 + STM32_BSEC_OTP_OFFSET, + otp, sizeof(otp)); + if (ret) + return ret; + + for (i = 0; i < 6; i++) + enetaddr[i] = ((uint8_t *)&otp)[i]; + + if (!is_valid_ethaddr(enetaddr)) { + pr_err("invalid MAC address in OTP %pM", enetaddr); + return -EINVAL; + } + pr_debug("OTP MAC address = %pM\n", enetaddr); + ret = !eth_env_set_enetaddr("ethaddr", enetaddr); + if (!ret) + pr_err("Failed to set mac address %pM from OTP: %d\n", + enetaddr, ret); +#endif + + return 0; +} + +static int setup_serial_number(void) +{ + char serial_string[25]; + u32 otp[3] = {0, 0, 0 }; + struct udevice *dev; + int ret; + + if (env_get("serial#")) + return 0; + + ret = uclass_get_device_by_driver(UCLASS_MISC, + DM_GET_DRIVER(stm32mp_bsec), + &dev); + if (ret) + return ret; + + ret = misc_read(dev, BSEC_OTP_SERIAL * 4 + STM32_BSEC_OTP_OFFSET, + otp, sizeof(otp)); + if (ret) + return ret; + + sprintf(serial_string, "%08x%08x%08x", otp[0], otp[1], otp[2]); + env_set("serial#", serial_string); + + return 0; +} + int arch_misc_init(void) { setup_boot_mode(); + setup_mac_address(); + setup_serial_number();
return 0; }

On Thu, May 17, 2018 at 03:24:07PM +0200, Patrice Chotard wrote:
From: Patrick Delaunay patrick.delaunay@st.com
Use OTP57 and 58 for MAC address
- OTP57 = MAC address bits [31:0]
- OTP58 = MAC address bit [47:32] stored in OTP LSB's
Use manufacture information in OTP13 to OTP15 to build unique chip id saved in env variable "serial#" (used for USB device enumeration)
Signed-off-by: Patrick Delaunay patrick.delaunay@st.com Signed-off-by: Patrice Chotard patrice.chotard@st.com
Applied to u-boot/master, thanks!
participants (2)
-
Patrice Chotard
-
Tom Rini