[PATCH u-boot-mvebu 0/5] arm: mvebu: a37xx: Add support for reading OTP

Add support for reading NB fuse OTP, SB fuse OTP and Security OTP values via U-Boot fuse API on Armada 37xx boards.
Pali Rohár (5): arm: mvebu: a37xx: Add support for reading NB and SB fuse OTP value arm: mvebu: a37xx: Enable fuse command on all Armada 3720 boards arm: mvebu: a37xx: Move generic mbox code to arch/arm/mach-mvebu arm: mvebu: a37xx: Extend mbox_do_cmd() code arm: mvebu: a37xx: Add support for reading Security OTP values
arch/arm/mach-mvebu/Kconfig | 1 + arch/arm/mach-mvebu/Makefile | 3 + arch/arm/mach-mvebu/armada3700/Makefile | 3 +- arch/arm/mach-mvebu/armada3700/efuse.c | 172 ++++++++++++++++++++ arch/arm/mach-mvebu/armada3700/mbox.c | 79 +++++++++ arch/arm/mach-mvebu/include/mach/mbox.h | 40 +++++ board/CZ.NIC/turris_mox/mox_sp.c | 73 +-------- configs/mvebu_db-88f3720_defconfig | 2 + configs/mvebu_espressobin-88f3720_defconfig | 2 + configs/turris_mox_defconfig | 2 + configs/uDPU_defconfig | 2 + 11 files changed, 308 insertions(+), 71 deletions(-) create mode 100644 arch/arm/mach-mvebu/armada3700/efuse.c create mode 100644 arch/arm/mach-mvebu/armada3700/mbox.c create mode 100644 arch/arm/mach-mvebu/include/mach/mbox.h

Implement it via U-Boot fuse API.
Banks 0-43 are reserved for accessing Security OTP (not implemented yet). Bank 44 is used for accessing North Bridge OTP (69 bits via words 0-2). Bank 45 is used for accessing South Bridge OTP (97 bits via words 0-3).
Write support is not implemented yet as it looks like that both North and South Bridge OTPs are already burned in factory with some data. Meaning of some bits of North Bridge are documented in WTMI source code. Meaning of bits in South Bridge is unknown.
Signed-off-by: Pali Rohár pali@kernel.org --- arch/arm/mach-mvebu/Kconfig | 1 + arch/arm/mach-mvebu/Makefile | 3 + arch/arm/mach-mvebu/armada3700/Makefile | 1 + arch/arm/mach-mvebu/armada3700/efuse.c | 136 ++++++++++++++++++++++++ 4 files changed, 141 insertions(+) create mode 100644 arch/arm/mach-mvebu/armada3700/efuse.c
diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig index d23cc0c760f1..659c4fe2380a 100644 --- a/arch/arm/mach-mvebu/Kconfig +++ b/arch/arm/mach-mvebu/Kconfig @@ -44,6 +44,7 @@ config ARMADA_XP config ARMADA_3700 bool select ARM64 + select HAVE_MVEBU_EFUSE
# Armada 7K and 8K are very similar - use only one Kconfig symbol for both config ARMADA_8K diff --git a/arch/arm/mach-mvebu/Makefile b/arch/arm/mach-mvebu/Makefile index a5a20877dda6..1b451889d242 100644 --- a/arch/arm/mach-mvebu/Makefile +++ b/arch/arm/mach-mvebu/Makefile @@ -27,7 +27,10 @@ obj-$(CONFIG_ARMADA_375) += ../../../drivers/ddr/marvell/axp/xor.o obj-$(CONFIG_ARMADA_38X) += ../../../drivers/ddr/marvell/a38x/xor.o obj-$(CONFIG_ARMADA_XP) += ../../../drivers/ddr/marvell/axp/xor.o obj-$(CONFIG_ARMADA_MSYS) += ../../../drivers/ddr/marvell/axp/xor.o + +ifdef CONFIG_ARMADA_38X obj-$(CONFIG_MVEBU_EFUSE) += efuse.o +endif
extra-y += kwbimage.cfg
diff --git a/arch/arm/mach-mvebu/armada3700/Makefile b/arch/arm/mach-mvebu/armada3700/Makefile index 031b3e854e36..cd74726cc778 100644 --- a/arch/arm/mach-mvebu/armada3700/Makefile +++ b/arch/arm/mach-mvebu/armada3700/Makefile @@ -3,3 +3,4 @@ # Copyright (C) 2016 Stefan Roese sr@denx.de
obj-y = cpu.o +obj-$(CONFIG_MVEBU_EFUSE) += efuse.o diff --git a/arch/arm/mach-mvebu/armada3700/efuse.c b/arch/arm/mach-mvebu/armada3700/efuse.c new file mode 100644 index 000000000000..03778f17ea49 --- /dev/null +++ b/arch/arm/mach-mvebu/armada3700/efuse.c @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) 2017 Marvell International Ltd. + * (C) 2021 Pali Rohár pali@kernel.org + */ + +#include <config.h> +#include <common.h> +#include <asm/io.h> +#include <linux/delay.h> +#include <mach/soc.h> + +#define OTP_NB_REG_BASE ((void __iomem *)MVEBU_REGISTER(0x12600)) +#define OTP_SB_REG_BASE ((void __iomem *)MVEBU_REGISTER(0x1A200)) + +#define OTP_CONTROL_OFF 0x00 +#define OTP_MODE_BIT BIT(15) +#define OTP_RPTR_RST_BIT BIT(14) +#define OTP_POR_B_BIT BIT(13) +#define OTP_PRDT_BIT BIT(3) +#define OTP_READ_PORT_OFF 0x04 +#define OTP_READ_POINTER_OFF 0x08 +#define OTP_PTR_INC_BIT BIT(8) + +static void otp_read_parallel(void __iomem *base, u32 *data, u32 count) +{ + u32 regval; + + /* 1. Clear OTP_MODE_NB to parallel mode */ + regval = readl(base + OTP_CONTROL_OFF); + regval &= ~OTP_MODE_BIT; + writel(regval, base + OTP_CONTROL_OFF); + + /* 2. Set OTP_POR_B_NB enter normal operation */ + regval = readl(base + OTP_CONTROL_OFF); + regval |= OTP_POR_B_BIT; + writel(regval, base + OTP_CONTROL_OFF); + + /* 3. Set OTP_PTR_INC_NB to auto-increment pointer after each read */ + regval = readl(base + OTP_READ_POINTER_OFF); + regval |= OTP_PTR_INC_BIT; + writel(regval, base + OTP_READ_POINTER_OFF); + + /* 4. Set OTP_RPTR_RST_NB, then clear the same field */ + regval = readl(base + OTP_CONTROL_OFF); + regval |= OTP_RPTR_RST_BIT; + writel(regval, base + OTP_CONTROL_OFF); + + regval = readl(base + OTP_CONTROL_OFF); + regval &= ~OTP_RPTR_RST_BIT; + writel(regval, base + OTP_CONTROL_OFF); + + /* 5. Toggle OTP_PRDT_NB + * a. Set OTP_PRDT_NB to 1. + * b. Clear OTP_PRDT_NB to 0. + * c. Wait for a minimum of 100 ns. + * d. Set OTP_PRDT_NB to 1 + */ + regval = readl(base + OTP_CONTROL_OFF); + regval |= OTP_PRDT_BIT; + writel(regval, base + OTP_CONTROL_OFF); + + regval = readl(base + OTP_CONTROL_OFF); + regval &= ~OTP_PRDT_BIT; + writel(regval, base + OTP_CONTROL_OFF); + + ndelay(100); + + regval = readl(base + OTP_CONTROL_OFF); + regval |= OTP_PRDT_BIT; + writel(regval, base + OTP_CONTROL_OFF); + + while (count-- > 0) { + /* 6. Read the content of OTP 32-bits at a time */ + ndelay(100000); + *(data++) = readl(base + OTP_READ_PORT_OFF); + } +} + +/* + * Banks 0-43 are used for accessing Security OTP (44 rows with 67 bits via 44 banks and words 0-2) + * Bank 44 is used for accessing North Bridge OTP (69 bits via words 0-2) + * Bank 45 is used for accessing South Bridge OTP (97 bits via words 0-3) + */ + +#define RWTM_ROWS 44 +#define RWTM_MAX_BANK (RWTM_ROWS - 1) +#define RWTM_ROW_WORDS 3 +#define OTP_NB_BANK RWTM_ROWS +#define OTP_NB_WORDS 3 +#define OTP_SB_BANK (RWTM_ROWS + 1) +#define OTP_SB_WORDS 4 + +int fuse_read(u32 bank, u32 word, u32 *val) +{ + if (bank <= RWTM_MAX_BANK) { + if (word >= RWTM_ROW_WORDS) + return -EINVAL; + /* TODO: not implemented yet */ + return -ENOSYS; + } else if (bank == OTP_NB_BANK) { + u32 data[OTP_NB_WORDS]; + if (word >= OTP_NB_WORDS) + return -EINVAL; + otp_read_parallel(OTP_NB_REG_BASE, data, OTP_NB_WORDS); + *val = data[word]; + return 0; + } else if (bank == OTP_SB_BANK) { + u32 data[OTP_SB_WORDS]; + if (word >= OTP_SB_WORDS) + return -EINVAL; + otp_read_parallel(OTP_SB_REG_BASE, data, OTP_SB_WORDS); + *val = data[word]; + return 0; + } else { + return -EINVAL; + } +} + +int fuse_prog(u32 bank, u32 word, u32 val) +{ + /* TODO: not implemented yet */ + return -ENOSYS; +} + +int fuse_sense(u32 bank, u32 word, u32 *val) +{ + /* not supported */ + return -ENOSYS; +} + +int fuse_override(u32 bank, u32 word, u32 val) +{ + /* not supported */ + return -ENOSYS; +}

On Thu, 17 Feb 2022 10:26:15 +0100 Pali Rohár pali@kernel.org wrote:
Implement it via U-Boot fuse API.
nitpick: In commit messages I prefer not to refer to commit title, i.e. instead of Implement it via U-Boot fuse API. I would write Implement reading NB and SB fuses of Armada 37xx SOC via U-Boot fuse API. as the first sentence.
Banks 0-43 are reserved for accessing Security OTP (not implemented yet). Bank 44 is used for accessing North Bridge OTP (69 bits via words 0-2). Bank 45 is used for accessing South Bridge OTP (97 bits via words 0-3).
Write support is not implemented yet as it looks like that both North
^because/since
and South Bridge OTPs are already burned in factory with some data. Meaning
^The meaning
of some bits of North Bridge are documented in WTMI source code. Meaning of
^is (or meaningS are) ^The meaning of
bits in South Bridge is unknown.
Otherwise
Reviewed-by: Marek Behún marek.behun@nic.cz

Allows to read OTP bits via U-Boot fuse command on all Armada 3720 boards.
Signed-off-by: Pali Rohár pali@kernel.org --- configs/mvebu_db-88f3720_defconfig | 2 ++ configs/mvebu_espressobin-88f3720_defconfig | 2 ++ configs/turris_mox_defconfig | 2 ++ configs/uDPU_defconfig | 2 ++ 4 files changed, 8 insertions(+)
diff --git a/configs/mvebu_db-88f3720_defconfig b/configs/mvebu_db-88f3720_defconfig index b600217692f1..6cc90fa54266 100644 --- a/configs/mvebu_db-88f3720_defconfig +++ b/configs/mvebu_db-88f3720_defconfig @@ -5,6 +5,7 @@ CONFIG_SYS_TEXT_BASE=0x00000000 CONFIG_SYS_MALLOC_F_LEN=0x2000 CONFIG_NR_DRAM_BANKS=1 CONFIG_TARGET_MVEBU_ARMADA_37XX=y +CONFIG_MVEBU_EFUSE=y CONFIG_ENV_SIZE=0x10000 CONFIG_ENV_OFFSET=0x3f0000 CONFIG_ENV_SECT_SIZE=0x10000 @@ -24,6 +25,7 @@ CONFIG_DISPLAY_BOARDINFO_LATE=y CONFIG_ARCH_EARLY_INIT_R=y CONFIG_BOARD_EARLY_INIT_F=y # CONFIG_CMD_FLASH is not set +CONFIG_CMD_FUSE=y CONFIG_CMD_GPIO=y CONFIG_CMD_I2C=y CONFIG_CMD_MMC=y diff --git a/configs/mvebu_espressobin-88f3720_defconfig b/configs/mvebu_espressobin-88f3720_defconfig index 4b8206a38f1b..f8196eab82e5 100644 --- a/configs/mvebu_espressobin-88f3720_defconfig +++ b/configs/mvebu_espressobin-88f3720_defconfig @@ -5,6 +5,7 @@ CONFIG_SYS_TEXT_BASE=0x00000000 CONFIG_SYS_MALLOC_F_LEN=0x2000 CONFIG_NR_DRAM_BANKS=1 CONFIG_TARGET_MVEBU_ARMADA_37XX=y +CONFIG_MVEBU_EFUSE=y CONFIG_ENV_SIZE=0x10000 CONFIG_ENV_OFFSET=0x3F0000 CONFIG_ENV_SECT_SIZE=0x10000 @@ -26,6 +27,7 @@ CONFIG_ARCH_EARLY_INIT_R=y CONFIG_BOARD_EARLY_INIT_F=y CONFIG_BOARD_LATE_INIT=y # CONFIG_CMD_FLASH is not set +CONFIG_CMD_FUSE=y CONFIG_CMD_GPIO=y CONFIG_CMD_GPT=y CONFIG_CMD_I2C=y diff --git a/configs/turris_mox_defconfig b/configs/turris_mox_defconfig index 84a0b4c2b20e..25e417c94562 100644 --- a/configs/turris_mox_defconfig +++ b/configs/turris_mox_defconfig @@ -5,6 +5,7 @@ CONFIG_SYS_TEXT_BASE=0x00000000 CONFIG_SYS_MALLOC_F_LEN=0x2000 CONFIG_NR_DRAM_BANKS=2 CONFIG_TARGET_TURRIS_MOX=y +CONFIG_MVEBU_EFUSE=y CONFIG_ENV_SIZE=0x10000 CONFIG_ENV_OFFSET=0x180000 CONFIG_ENV_SECT_SIZE=0x10000 @@ -31,6 +32,7 @@ CONFIG_MISC_INIT_R=y CONFIG_CMD_SHA1SUM=y CONFIG_CMD_CLK=y # CONFIG_CMD_FLASH is not set +CONFIG_CMD_FUSE=y CONFIG_CMD_GPIO=y CONFIG_CMD_GPT=y CONFIG_CMD_I2C=y diff --git a/configs/uDPU_defconfig b/configs/uDPU_defconfig index b5f2115e6332..7698e080e2a2 100644 --- a/configs/uDPU_defconfig +++ b/configs/uDPU_defconfig @@ -4,6 +4,7 @@ CONFIG_ARCH_MVEBU=y CONFIG_SYS_TEXT_BASE=0x00000000 CONFIG_SYS_MALLOC_F_LEN=0x2000 CONFIG_TARGET_MVEBU_ARMADA_37XX=y +CONFIG_MVEBU_EFUSE=y CONFIG_ENV_SIZE=0x10000 CONFIG_ENV_OFFSET=0x180000 CONFIG_ENV_SECT_SIZE=0x10000 @@ -29,6 +30,7 @@ CONFIG_SYS_PROMPT="uDPU>> " # CONFIG_CMD_IMI is not set # CONFIG_CMD_XIMG is not set # CONFIG_CMD_FLASH is not set +CONFIG_CMD_FUSE=y CONFIG_CMD_GPIO=y CONFIG_CMD_I2C=y CONFIG_CMD_MMC=y

On Thu, 17 Feb 2022 10:26:16 +0100 Pali Rohár pali@kernel.org wrote:
Allows to read OTP bits via U-Boot fuse command on all Armada 3720 boards.
^Allow (we use present simple in commit messages)
otherwise Reviewed-by: Marek Behún marek.behun@nic.cz

Generic A3720 mbox code is currently in Turris Mox specific board file board/CZ.NIC/turris_mox/mox_sp.c. Move it to board independent arch file arch/arm/mach-mvebu/armada3700/mbox.c.
Signed-off-by: Pali Rohár pali@kernel.org --- arch/arm/mach-mvebu/armada3700/Makefile | 2 +- arch/arm/mach-mvebu/armada3700/mbox.c | 67 ++++++++++++++++++++++++ arch/arm/mach-mvebu/include/mach/mbox.h | 23 +++++++++ board/CZ.NIC/turris_mox/mox_sp.c | 69 +------------------------ 4 files changed, 92 insertions(+), 69 deletions(-) create mode 100644 arch/arm/mach-mvebu/armada3700/mbox.c create mode 100644 arch/arm/mach-mvebu/include/mach/mbox.h
diff --git a/arch/arm/mach-mvebu/armada3700/Makefile b/arch/arm/mach-mvebu/armada3700/Makefile index cd74726cc778..98350a41e04b 100644 --- a/arch/arm/mach-mvebu/armada3700/Makefile +++ b/arch/arm/mach-mvebu/armada3700/Makefile @@ -2,5 +2,5 @@ # # Copyright (C) 2016 Stefan Roese sr@denx.de
-obj-y = cpu.o +obj-y = cpu.o mbox.o obj-$(CONFIG_MVEBU_EFUSE) += efuse.o diff --git a/arch/arm/mach-mvebu/armada3700/mbox.c b/arch/arm/mach-mvebu/armada3700/mbox.c new file mode 100644 index 000000000000..cb86b967c2eb --- /dev/null +++ b/arch/arm/mach-mvebu/armada3700/mbox.c @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018 Marek Behun marek.behun@nic.cz + */ + +#include <common.h> +#include <asm/arch/soc.h> +#include <asm/io.h> +#include <linux/bitops.h> +#include <linux/delay.h> +#include <mach/mbox.h> + +#define RWTM_BASE (MVEBU_REGISTER(0xb0000)) +#define RWTM_CMD_PARAM(i) (size_t)(RWTM_BASE + (i) * 4) +#define RWTM_CMD (RWTM_BASE + 0x40) +#define RWTM_CMD_RETSTATUS (RWTM_BASE + 0x80) +#define RWTM_CMD_STATUS(i) (size_t)(RWTM_BASE + 0x84 + (i) * 4) + +#define RWTM_HOST_INT_RESET (RWTM_BASE + 0xc8) +#define RWTM_HOST_INT_MASK (RWTM_BASE + 0xcc) +#define SP_CMD_COMPLETE BIT(0) + +#define MBOX_STS_SUCCESS (0x0 << 30) +#define MBOX_STS_FAIL (0x1 << 30) +#define MBOX_STS_BADCMD (0x2 << 30) +#define MBOX_STS_LATER (0x3 << 30) +#define MBOX_STS_ERROR(s) ((s) & (3 << 30)) +#define MBOX_STS_VALUE(s) (((s) >> 10) & 0xfffff) +#define MBOX_STS_CMD(s) ((s) & 0x3ff) + +int mbox_do_cmd(enum mbox_cmd cmd, u32 *out, int nout) +{ + const int tries = 50; + int i; + u32 status; + + clrbits_le32(RWTM_HOST_INT_MASK, SP_CMD_COMPLETE); + + writel(cmd, RWTM_CMD); + + for (i = 0; i < tries; ++i) { + mdelay(10); + if (readl(RWTM_HOST_INT_RESET) & SP_CMD_COMPLETE) + break; + } + + if (i == tries) { + /* if timed out, don't read status */ + setbits_le32(RWTM_HOST_INT_RESET, SP_CMD_COMPLETE); + return -ETIMEDOUT; + } + + for (i = 0; i < nout; ++i) + out[i] = readl(RWTM_CMD_STATUS(i)); + status = readl(RWTM_CMD_RETSTATUS); + + setbits_le32(RWTM_HOST_INT_RESET, SP_CMD_COMPLETE); + + if (MBOX_STS_CMD(status) != cmd) + return -EIO; + else if (MBOX_STS_ERROR(status) == MBOX_STS_FAIL) + return -(int)MBOX_STS_VALUE(status); + else if (MBOX_STS_ERROR(status) != MBOX_STS_SUCCESS) + return -EIO; + else + return MBOX_STS_VALUE(status); +} diff --git a/arch/arm/mach-mvebu/include/mach/mbox.h b/arch/arm/mach-mvebu/include/mach/mbox.h new file mode 100644 index 000000000000..981204935832 --- /dev/null +++ b/arch/arm/mach-mvebu/include/mach/mbox.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2018 Marek Behun marek.behun@nic.cz + */ + +#ifndef _MVEBU_MBOX_H +#define _MVEBU_MBOX_H + +enum mbox_cmd { + MBOX_CMD_GET_RANDOM = 1, + MBOX_CMD_BOARD_INFO, + MBOX_CMD_ECDSA_PUB_KEY, + MBOX_CMD_HASH, + MBOX_CMD_SIGN, + MBOX_CMD_VERIFY, + + MBOX_CMD_OTP_READ, + MBOX_CMD_OTP_WRITE, +}; + +int mbox_do_cmd(enum mbox_cmd cmd, u32 *in, int nout); + +#endif diff --git a/board/CZ.NIC/turris_mox/mox_sp.c b/board/CZ.NIC/turris_mox/mox_sp.c index cc57b9f095f7..4de067bbebbb 100644 --- a/board/CZ.NIC/turris_mox/mox_sp.c +++ b/board/CZ.NIC/turris_mox/mox_sp.c @@ -8,74 +8,7 @@ #include <asm/io.h> #include <linux/bitops.h> #include <linux/delay.h> - -#define RWTM_BASE (MVEBU_REGISTER(0xb0000)) -#define RWTM_CMD_PARAM(i) (size_t)(RWTM_BASE + (i) * 4) -#define RWTM_CMD (RWTM_BASE + 0x40) -#define RWTM_CMD_RETSTATUS (RWTM_BASE + 0x80) -#define RWTM_CMD_STATUS(i) (size_t)(RWTM_BASE + 0x84 + (i) * 4) - -#define RWTM_HOST_INT_RESET (RWTM_BASE + 0xc8) -#define RWTM_HOST_INT_MASK (RWTM_BASE + 0xcc) -#define SP_CMD_COMPLETE BIT(0) - -#define MBOX_STS_SUCCESS (0x0 << 30) -#define MBOX_STS_FAIL (0x1 << 30) -#define MBOX_STS_BADCMD (0x2 << 30) -#define MBOX_STS_LATER (0x3 << 30) -#define MBOX_STS_ERROR(s) ((s) & (3 << 30)) -#define MBOX_STS_VALUE(s) (((s) >> 10) & 0xfffff) -#define MBOX_STS_CMD(s) ((s) & 0x3ff) - -enum mbox_cmd { - MBOX_CMD_GET_RANDOM = 1, - MBOX_CMD_BOARD_INFO, - MBOX_CMD_ECDSA_PUB_KEY, - MBOX_CMD_HASH, - MBOX_CMD_SIGN, - MBOX_CMD_VERIFY, - - MBOX_CMD_OTP_READ, - MBOX_CMD_OTP_WRITE -}; - -static int mbox_do_cmd(enum mbox_cmd cmd, u32 *out, int nout) -{ - const int tries = 50; - int i; - u32 status; - - clrbits_le32(RWTM_HOST_INT_MASK, SP_CMD_COMPLETE); - - writel(cmd, RWTM_CMD); - - for (i = 0; i < tries; ++i) { - mdelay(10); - if (readl(RWTM_HOST_INT_RESET) & SP_CMD_COMPLETE) - break; - } - - if (i == tries) { - /* if timed out, don't read status */ - setbits_le32(RWTM_HOST_INT_RESET, SP_CMD_COMPLETE); - return -ETIMEDOUT; - } - - for (i = 0; i < nout; ++i) - out[i] = readl(RWTM_CMD_STATUS(i)); - status = readl(RWTM_CMD_RETSTATUS); - - setbits_le32(RWTM_HOST_INT_RESET, SP_CMD_COMPLETE); - - if (MBOX_STS_CMD(status) != cmd) - return -EIO; - else if (MBOX_STS_ERROR(status) == MBOX_STS_FAIL) - return -(int)MBOX_STS_VALUE(status); - else if (MBOX_STS_ERROR(status) != MBOX_STS_SUCCESS) - return -EIO; - else - return MBOX_STS_VALUE(status); -} +#include <mach/mbox.h>
const char *mox_sp_get_ecdsa_public_key(void) {

On Thu, 17 Feb 2022 10:26:17 +0100 Pali Rohár pali@kernel.org wrote:
Generic A3720 mbox code is currently in Turris Mox specific board file board/CZ.NIC/turris_mox/mox_sp.c. Move it to board independent arch file arch/arm/mach-mvebu/armada3700/mbox.c.
Reviewed-by: Marek Behún marek.behun@nic.cz

Allow to specify input parameters, define all available mbox commands supported by CZ.NIC secure firmware + Marvell fuse.bin firmware and fix parsing response from Marvell OTP commands.
Signed-off-by: Pali Rohár pali@kernel.org --- arch/arm/mach-mvebu/armada3700/mbox.c | 16 ++++++++++++++-- arch/arm/mach-mvebu/include/mach/mbox.h | 19 ++++++++++++++++++- board/CZ.NIC/turris_mox/mox_sp.c | 4 ++-- 3 files changed, 34 insertions(+), 5 deletions(-)
diff --git a/arch/arm/mach-mvebu/armada3700/mbox.c b/arch/arm/mach-mvebu/armada3700/mbox.c index cb86b967c2eb..b67346d524bf 100644 --- a/arch/arm/mach-mvebu/armada3700/mbox.c +++ b/arch/arm/mach-mvebu/armada3700/mbox.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Marek Behun marek.behun@nic.cz + * Copyright (C) 2021 Pali Rohár pali@kernel.org */
#include <common.h> @@ -15,6 +16,7 @@ #define RWTM_CMD (RWTM_BASE + 0x40) #define RWTM_CMD_RETSTATUS (RWTM_BASE + 0x80) #define RWTM_CMD_STATUS(i) (size_t)(RWTM_BASE + 0x84 + (i) * 4) +#define MAX_ARGS 16
#define RWTM_HOST_INT_RESET (RWTM_BASE + 0xc8) #define RWTM_HOST_INT_MASK (RWTM_BASE + 0xcc) @@ -27,15 +29,23 @@ #define MBOX_STS_ERROR(s) ((s) & (3 << 30)) #define MBOX_STS_VALUE(s) (((s) >> 10) & 0xfffff) #define MBOX_STS_CMD(s) ((s) & 0x3ff) +#define MBOX_STS_MARVELL_ERROR(s) ((s) == 0 ? 0 : (s) == 2 ? ETIMEDOUT : (s) == 3 ? EINVAL : (s) == 4 ? ENOSYS : EIO)
-int mbox_do_cmd(enum mbox_cmd cmd, u32 *out, int nout) +int mbox_do_cmd(enum mbox_cmd cmd, u32 *in, int nin, u32 *out, int nout) { const int tries = 50; int i; u32 status;
+ if (nin > MAX_ARGS || nout > MAX_ARGS) + return -EINVAL; + clrbits_le32(RWTM_HOST_INT_MASK, SP_CMD_COMPLETE);
+ for (i = 0; i < nin; i++) + writel(in[i], RWTM_CMD_PARAM(i)); + for (; i < MAX_ARGS; i++) + writel(0x0, RWTM_CMD_PARAM(i)); writel(cmd, RWTM_CMD);
for (i = 0; i < tries; ++i) { @@ -57,9 +67,11 @@ int mbox_do_cmd(enum mbox_cmd cmd, u32 *out, int nout) setbits_le32(RWTM_HOST_INT_RESET, SP_CMD_COMPLETE);
if (MBOX_STS_CMD(status) != cmd) - return -EIO; + return -MBOX_STS_MARVELL_ERROR(status); else if (MBOX_STS_ERROR(status) == MBOX_STS_FAIL) return -(int)MBOX_STS_VALUE(status); + else if (MBOX_STS_ERROR(status) == MBOX_STS_BADCMD) + return -ENOSYS; else if (MBOX_STS_ERROR(status) != MBOX_STS_SUCCESS) return -EIO; else diff --git a/arch/arm/mach-mvebu/include/mach/mbox.h b/arch/arm/mach-mvebu/include/mach/mbox.h index 981204935832..f1cb55f2bfe7 100644 --- a/arch/arm/mach-mvebu/include/mach/mbox.h +++ b/arch/arm/mach-mvebu/include/mach/mbox.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0+ */ /* * Copyright (C) 2018 Marek Behun marek.behun@nic.cz + * Copyright (C) 2021 Pali Rohár pali@kernel.org */
#ifndef _MVEBU_MBOX_H @@ -16,8 +17,24 @@ enum mbox_cmd {
MBOX_CMD_OTP_READ, MBOX_CMD_OTP_WRITE, + + MBOX_CMD_REBOOT, + + /* OTP read commands supported by Marvell fuse.bin firmware */ + MBOX_CMD_OTP_READ_1B = 257, + MBOX_CMD_OTP_READ_8B, + MBOX_CMD_OTP_READ_32B, + MBOX_CMD_OTP_READ_64B, + MBOX_CMD_OTP_READ_256B, + + /* OTP write commands supported by Marvell fuse.bin firmware */ + MBOX_CMD_OTP_WRITE_1B = 513, + MBOX_CMD_OTP_WRITE_8B, + MBOX_CMD_OTP_WRITE_32B, + MBOX_CMD_OTP_WRITE_64B, + MBOX_CMD_OTP_WRITE_256B, };
-int mbox_do_cmd(enum mbox_cmd cmd, u32 *in, int nout); +int mbox_do_cmd(enum mbox_cmd cmd, u32 *in, int nin, u32 *out, int nout);
#endif diff --git a/board/CZ.NIC/turris_mox/mox_sp.c b/board/CZ.NIC/turris_mox/mox_sp.c index 4de067bbebbb..93e96b014fca 100644 --- a/board/CZ.NIC/turris_mox/mox_sp.c +++ b/board/CZ.NIC/turris_mox/mox_sp.c @@ -19,7 +19,7 @@ const char *mox_sp_get_ecdsa_public_key(void) if (public_key[0]) return public_key;
- res = mbox_do_cmd(MBOX_CMD_ECDSA_PUB_KEY, out, 16); + res = mbox_do_cmd(MBOX_CMD_ECDSA_PUB_KEY, NULL, 0, out, 16); if (res < 0) return NULL;
@@ -47,7 +47,7 @@ int mbox_sp_get_board_info(u64 *sn, u8 *mac1, u8 *mac2, int *bv, int *ram) u32 out[8]; int res;
- res = mbox_do_cmd(MBOX_CMD_BOARD_INFO, out, 8); + res = mbox_do_cmd(MBOX_CMD_BOARD_INFO, NULL, 0, out, 8); if (res < 0) return res;

On Thu, 17 Feb 2022 10:26:18 +0100 Pali Rohár pali@kernel.org wrote:
Allow to specify input parameters, define all available mbox commands supported by CZ.NIC secure firmware + Marvell fuse.bin firmware and fix
CZ.NIC's and also Marvell's
parsing response from Marvell OTP commands.
Signed-off-by: Pali Rohár pali@kernel.org
...
#define MBOX_STS_ERROR(s) ((s) & (3 << 30)) #define MBOX_STS_VALUE(s) (((s) >> 10) & 0xfffff) #define MBOX_STS_CMD(s) ((s) & 0x3ff) +#define MBOX_STS_MARVELL_ERROR(s) ((s) == 0 ? 0 : (s) == 2 ? ETIMEDOUT : (s) == 3 ? EINVAL : (s) == 4 ? ENOSYS : EIO)
This is starting to become too complicated for a macro :-( What do you think about converting all these to a static function? Something like
static int mbox_parse_status(u32 status, u16 *cmd, u32 *value, bool marvell) { ... }
#ifndef _MVEBU_MBOX_H @@ -16,8 +17,24 @@ enum mbox_cmd {
MBOX_CMD_OTP_READ, MBOX_CMD_OTP_WRITE,
- MBOX_CMD_REBOOT,
- /* OTP read commands supported by Marvell fuse.bin firmware */
Marvell's
- MBOX_CMD_OTP_READ_1B = 257,
- MBOX_CMD_OTP_READ_8B,
- MBOX_CMD_OTP_READ_32B,
- MBOX_CMD_OTP_READ_64B,
- MBOX_CMD_OTP_READ_256B,
- /* OTP write commands supported by Marvell fuse.bin firmware */
Marvell's

On Thursday 17 February 2022 15:16:33 Marek Behún wrote:
On Thu, 17 Feb 2022 10:26:18 +0100 Pali Rohár pali@kernel.org wrote:
Allow to specify input parameters, define all available mbox commands supported by CZ.NIC secure firmware + Marvell fuse.bin firmware and fix
CZ.NIC's and also Marvell's
parsing response from Marvell OTP commands.
Signed-off-by: Pali Rohár pali@kernel.org
...
#define MBOX_STS_ERROR(s) ((s) & (3 << 30)) #define MBOX_STS_VALUE(s) (((s) >> 10) & 0xfffff) #define MBOX_STS_CMD(s) ((s) & 0x3ff) +#define MBOX_STS_MARVELL_ERROR(s) ((s) == 0 ? 0 : (s) == 2 ? ETIMEDOUT : (s) == 3 ? EINVAL : (s) == 4 ? ENOSYS : EIO)
This is starting to become too complicated for a macro :-(
It is straightforward switch macro. I can reformat it to be more readable, e.g.:
#define MBOX_STS_MARVELL_ERROR(s) ((s) == 0 ? 0 : \ (s) == 2 ? ETIMEDOUT : \ (s) == 3 ? EINVAL : \ (s) == 4 ? ENOSYS : \ EIO)
What do you think about converting all these to a static function? Something like
static int mbox_parse_status(u32 status, u16 *cmd, u32 *value, bool marvell) { ... }
#ifndef _MVEBU_MBOX_H @@ -16,8 +17,24 @@ enum mbox_cmd {
MBOX_CMD_OTP_READ, MBOX_CMD_OTP_WRITE,
- MBOX_CMD_REBOOT,
- /* OTP read commands supported by Marvell fuse.bin firmware */
Marvell's
- MBOX_CMD_OTP_READ_1B = 257,
- MBOX_CMD_OTP_READ_8B,
- MBOX_CMD_OTP_READ_32B,
- MBOX_CMD_OTP_READ_64B,
- MBOX_CMD_OTP_READ_256B,
- /* OTP write commands supported by Marvell fuse.bin firmware */
Marvell's

On Thu, 17 Feb 2022 18:13:17 +0100 Pali Rohár pali@kernel.org wrote:
On Thursday 17 February 2022 15:16:33 Marek Behún wrote:
On Thu, 17 Feb 2022 10:26:18 +0100 Pali Rohár pali@kernel.org wrote:
Allow to specify input parameters, define all available mbox commands supported by CZ.NIC secure firmware + Marvell fuse.bin firmware and fix
CZ.NIC's and also Marvell's
parsing response from Marvell OTP commands.
Signed-off-by: Pali Rohár pali@kernel.org
...
#define MBOX_STS_ERROR(s) ((s) & (3 << 30)) #define MBOX_STS_VALUE(s) (((s) >> 10) & 0xfffff) #define MBOX_STS_CMD(s) ((s) & 0x3ff) +#define MBOX_STS_MARVELL_ERROR(s) ((s) == 0 ? 0 : (s) == 2 ? ETIMEDOUT : (s) == 3 ? EINVAL : (s) == 4 ? ENOSYS : EIO)
This is starting to become too complicated for a macro :-(
It is straightforward switch macro. I can reformat it to be more readable, e.g.:
#define MBOX_STS_MARVELL_ERROR(s) ((s) == 0 ? 0 : \ (s) == 2 ? ETIMEDOUT : \ (s) == 3 ? EINVAL : \ (s) == 4 ? ENOSYS : \ EIO)
I would still prefer static functions for such expressions, but this formatting is better then nothing. If you resend with this formatting, you can add my Reviewed-by.
Marek

Only secure CM3 core can access Security OTP. It is not possible via A53 core on which is running U-Boot. Marvell for this purpose defined mbox API for sending OTP commands between CM and A53 cores.
Implement this Marvell mbox API via U-Boot fuse API.
Banks 0-43 are used for accessing Security OTP (44 rows with 67 bits via 44 banks and words 0-2).
Write support is not implemented yet.
Signed-off-by: Pali Rohár pali@kernel.org --- arch/arm/mach-mvebu/armada3700/efuse.c | 40 ++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-)
diff --git a/arch/arm/mach-mvebu/armada3700/efuse.c b/arch/arm/mach-mvebu/armada3700/efuse.c index 03778f17ea49..274d9c72c073 100644 --- a/arch/arm/mach-mvebu/armada3700/efuse.c +++ b/arch/arm/mach-mvebu/armada3700/efuse.c @@ -8,6 +8,7 @@ #include <common.h> #include <asm/io.h> #include <linux/delay.h> +#include <mach/mbox.h> #include <mach/soc.h>
#define OTP_NB_REG_BASE ((void __iomem *)MVEBU_REGISTER(0x12600)) @@ -77,6 +78,42 @@ static void otp_read_parallel(void __iomem *base, u32 *data, u32 count) } }
+static int rwtm_otp_read(u8 row, u32 word, u32 *data) +{ + u32 out[3]; + u32 in[2]; + int res; + + /* + * MBOX_CMD_OTP_READ_32B command is supported by Marvell fuse.bin + * firmware and also by new (yet unreleased) CZ.NIC wtmi firmware. + * But this command does not provide access to lock bit. + */ + if (word < 2) { + in[0] = row; + in[1] = word * 32; + res = mbox_do_cmd(MBOX_CMD_OTP_READ_32B, in, 2, out, 2); + if (res != -ENOSYS) { + if (!res) + *data = out[0]; + return res; + } + /* Fallback for old version of CZ.NIC wtmi firmware. */ + } + + /* + * MBOX_CMD_OTP_READ command is supported only by CZ.NIC wtmi firmware + * (in all versions) and provide access to all bits, including lock bit. + * Note that CZ.NIC wtmi firmware may be compiled to disallow access to + * OTP (for security reasons), so this command may fail too. + */ + in[0] = row; + res = mbox_do_cmd(MBOX_CMD_OTP_READ, in, 1, out, 3); + if (!res) + *data = out[word]; + return res; +} + /* * Banks 0-43 are used for accessing Security OTP (44 rows with 67 bits via 44 banks and words 0-2) * Bank 44 is used for accessing North Bridge OTP (69 bits via words 0-2) @@ -96,8 +133,7 @@ int fuse_read(u32 bank, u32 word, u32 *val) if (bank <= RWTM_MAX_BANK) { if (word >= RWTM_ROW_WORDS) return -EINVAL; - /* TODO: not implemented yet */ - return -ENOSYS; + return rwtm_otp_read(bank, word, val); } else if (bank == OTP_NB_BANK) { u32 data[OTP_NB_WORDS]; if (word >= OTP_NB_WORDS)

On Thu, 17 Feb 2022 10:26:19 +0100 Pali Rohár pali@kernel.org wrote:
Only secure CM3 core can access Security OTP. It is not possible via A53
It is not possible for the A53 core (on which U-Boot is running) to read it directly.
core on which is running U-Boot. Marvell for this purpose defined mbox API
For this purpose Marvell defined...
for sending OTP commands between CM and A53 cores.
^CM3
Implement this Marvell mbox API via U-Boot fuse API.
Implement these Marvell fuse reading mbox commands via ....
Banks 0-43 are used for accessing Security OTP (44 rows with 67 bits via 44 banks and words 0-2).
Note that of the 67 bits, the 3 upper bits are: 1 lock bit and 2 auxiliary bits (meant for testing during the manufacture of the SOC, as I understand it).
Also note that the lock bit and the auxiliary bits are not readable via Marvell commands.
With CZ.NIC's commands the lock bit is readable.
Write support is not implemented yet.
Signed-off-by: Pali Rohár pali@kernel.org
arch/arm/mach-mvebu/armada3700/efuse.c | 40 ++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-)
diff --git a/arch/arm/mach-mvebu/armada3700/efuse.c b/arch/arm/mach-mvebu/armada3700/efuse.c index 03778f17ea49..274d9c72c073 100644 --- a/arch/arm/mach-mvebu/armada3700/efuse.c +++ b/arch/arm/mach-mvebu/armada3700/efuse.c @@ -8,6 +8,7 @@ #include <common.h> #include <asm/io.h> #include <linux/delay.h> +#include <mach/mbox.h> #include <mach/soc.h>
#define OTP_NB_REG_BASE ((void __iomem *)MVEBU_REGISTER(0x12600)) @@ -77,6 +78,42 @@ static void otp_read_parallel(void __iomem *base, u32 *data, u32 count) } }
+static int rwtm_otp_read(u8 row, u32 word, u32 *data) +{
- u32 out[3];
- u32 in[2];
- int res;
- /*
* MBOX_CMD_OTP_READ_32B command is supported by Marvell fuse.bin
* firmware and also by new (yet unreleased) CZ.NIC wtmi firmware.
Marvell's, CZ.NIC's, and drop the "(yet unreleased)", because you'll need to send another patch that drops it afterwards.
* But this command does not provide access to lock bit.
*/
- if (word < 2) {
in[0] = row;
in[1] = word * 32;
res = mbox_do_cmd(MBOX_CMD_OTP_READ_32B, in, 2, out, 2);
if (res != -ENOSYS) {
if (!res)
*data = out[0];
return res;
}
/* Fallback for old version of CZ.NIC wtmi firmware. */
- }
I am afraid this is not correct, because Marvell's firmware reads the efuse without Error Correction. So it is possible for Marvell's command to return different value than CZ.NIC's command.
You need to determine whether CZ.NIC's command is supported, and use it if it is, otherwise use Marvell's command. Or you need to define whether and when the Error Correction is supposed to be used, or something.
But doing what you are doing here can make Turris MOX boards read different values. I know of at least one board where serial number or MAC address needs Error Correction.
Marek

On Thursday 17 February 2022 15:31:10 Marek Behún wrote:
On Thu, 17 Feb 2022 10:26:19 +0100 Pali Rohár pali@kernel.org wrote:
Only secure CM3 core can access Security OTP. It is not possible via A53
It is not possible for the A53 core (on which U-Boot is running) to read it directly.
core on which is running U-Boot. Marvell for this purpose defined mbox API
For this purpose Marvell defined...
for sending OTP commands between CM and A53 cores.
^CM3
Implement this Marvell mbox API via U-Boot fuse API.
Implement these Marvell fuse reading mbox commands via ....
Banks 0-43 are used for accessing Security OTP (44 rows with 67 bits via 44 banks and words 0-2).
Note that of the 67 bits, the 3 upper bits are: 1 lock bit and 2 auxiliary bits (meant for testing during the manufacture of the SOC, as I understand it).
Also note that the lock bit and the auxiliary bits are not readable via Marvell commands.
With CZ.NIC's commands the lock bit is readable.
Write support is not implemented yet.
Signed-off-by: Pali Rohár pali@kernel.org
arch/arm/mach-mvebu/armada3700/efuse.c | 40 ++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-)
diff --git a/arch/arm/mach-mvebu/armada3700/efuse.c b/arch/arm/mach-mvebu/armada3700/efuse.c index 03778f17ea49..274d9c72c073 100644 --- a/arch/arm/mach-mvebu/armada3700/efuse.c +++ b/arch/arm/mach-mvebu/armada3700/efuse.c @@ -8,6 +8,7 @@ #include <common.h> #include <asm/io.h> #include <linux/delay.h> +#include <mach/mbox.h> #include <mach/soc.h>
#define OTP_NB_REG_BASE ((void __iomem *)MVEBU_REGISTER(0x12600)) @@ -77,6 +78,42 @@ static void otp_read_parallel(void __iomem *base, u32 *data, u32 count) } }
+static int rwtm_otp_read(u8 row, u32 word, u32 *data) +{
- u32 out[3];
- u32 in[2];
- int res;
- /*
* MBOX_CMD_OTP_READ_32B command is supported by Marvell fuse.bin
* firmware and also by new (yet unreleased) CZ.NIC wtmi firmware.
Marvell's, CZ.NIC's, and drop the "(yet unreleased)", because you'll need to send another patch that drops it afterwards.
* But this command does not provide access to lock bit.
*/
- if (word < 2) {
in[0] = row;
in[1] = word * 32;
res = mbox_do_cmd(MBOX_CMD_OTP_READ_32B, in, 2, out, 2);
if (res != -ENOSYS) {
if (!res)
*data = out[0];
return res;
}
/* Fallback for old version of CZ.NIC wtmi firmware. */
- }
I am afraid this is not correct, because Marvell's firmware reads the efuse without Error Correction. So it is possible for Marvell's command to return different value than CZ.NIC's command.
You need to determine whether CZ.NIC's command is supported, and use it if it is, otherwise use Marvell's command. Or you need to define whether and when the Error Correction is supposed to be used, or something.
Seems that this U-Boot fuse API is low level API, so it probably would be better to always read without ECC correction (which is provided by Marvell OTP API). As ECC is stored in other bits, it is possible to read everything needed for ECC correction via this API.
This could simplify patch: Lock bit read via CZ.NIC API (as there is no other API) and other bits read via Marvell API (which is going to be supported also by CZ.NIC firmware).
But doing what you are doing here can make Turris MOX boards read different values. I know of at least one board where serial number or MAC address needs Error Correction.
Marek

On Thu, 17 Feb 2022 17:50:31 +0100 Pali Rohár pali@kernel.org wrote:
On Thursday 17 February 2022 15:31:10 Marek Behún wrote:
On Thu, 17 Feb 2022 10:26:19 +0100 Pali Rohár pali@kernel.org wrote:
Only secure CM3 core can access Security OTP. It is not possible via A53
It is not possible for the A53 core (on which U-Boot is running) to read it directly.
core on which is running U-Boot. Marvell for this purpose defined mbox API
For this purpose Marvell defined...
for sending OTP commands between CM and A53 cores.
^CM3
Implement this Marvell mbox API via U-Boot fuse API.
Implement these Marvell fuse reading mbox commands via ....
Banks 0-43 are used for accessing Security OTP (44 rows with 67 bits via 44 banks and words 0-2).
Note that of the 67 bits, the 3 upper bits are: 1 lock bit and 2 auxiliary bits (meant for testing during the manufacture of the SOC, as I understand it).
Also note that the lock bit and the auxiliary bits are not readable via Marvell commands.
With CZ.NIC's commands the lock bit is readable.
Write support is not implemented yet.
Signed-off-by: Pali Rohár pali@kernel.org
arch/arm/mach-mvebu/armada3700/efuse.c | 40 ++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-)
diff --git a/arch/arm/mach-mvebu/armada3700/efuse.c b/arch/arm/mach-mvebu/armada3700/efuse.c index 03778f17ea49..274d9c72c073 100644 --- a/arch/arm/mach-mvebu/armada3700/efuse.c +++ b/arch/arm/mach-mvebu/armada3700/efuse.c @@ -8,6 +8,7 @@ #include <common.h> #include <asm/io.h> #include <linux/delay.h> +#include <mach/mbox.h> #include <mach/soc.h>
#define OTP_NB_REG_BASE ((void __iomem *)MVEBU_REGISTER(0x12600)) @@ -77,6 +78,42 @@ static void otp_read_parallel(void __iomem *base, u32 *data, u32 count) } }
+static int rwtm_otp_read(u8 row, u32 word, u32 *data) +{
- u32 out[3];
- u32 in[2];
- int res;
- /*
* MBOX_CMD_OTP_READ_32B command is supported by Marvell fuse.bin
* firmware and also by new (yet unreleased) CZ.NIC wtmi firmware.
Marvell's, CZ.NIC's, and drop the "(yet unreleased)", because you'll need to send another patch that drops it afterwards.
* But this command does not provide access to lock bit.
*/
- if (word < 2) {
in[0] = row;
in[1] = word * 32;
res = mbox_do_cmd(MBOX_CMD_OTP_READ_32B, in, 2, out, 2);
if (res != -ENOSYS) {
if (!res)
*data = out[0];
return res;
}
/* Fallback for old version of CZ.NIC wtmi firmware. */
- }
I am afraid this is not correct, because Marvell's firmware reads the efuse without Error Correction. So it is possible for Marvell's command to return different value than CZ.NIC's command.
You need to determine whether CZ.NIC's command is supported, and use it if it is, otherwise use Marvell's command. Or you need to define whether and when the Error Correction is supposed to be used, or something.
Seems that this U-Boot fuse API is low level API, so it probably would be better to always read without ECC correction (which is provided by Marvell OTP API). As ECC is stored in other bits, it is possible to read everything needed for ECC correction via this API.
This could simplify patch: Lock bit read via CZ.NIC API (as there is no other API) and other bits read via Marvell API (which is going to be supported also by CZ.NIC firmware).
Ok, as long as turris_mox.c reads OTP with Error Correction, fuse can be kept low level.
Marek
But doing what you are doing here can make Turris MOX boards read different values. I know of at least one board where serial number or MAC address needs Error Correction.
Marek

On Thursday 17 February 2022 15:31:10 Marek Behún wrote:
* But this command does not provide access to lock bit.
*/
- if (word < 2) {
in[0] = row;
in[1] = word * 32;
res = mbox_do_cmd(MBOX_CMD_OTP_READ_32B, in, 2, out, 2);
if (res != -ENOSYS) {
if (!res)
*data = out[0];
return res;
}
/* Fallback for old version of CZ.NIC wtmi firmware. */
- }
I am afraid this is not correct, because Marvell's firmware reads the efuse without Error Correction. So it is possible for Marvell's command to return different value than CZ.NIC's command.
This is not truth. CZ.NIC firmware for MBOX_CMD_OTP_READ command calls efuse_read_row_no_ecc which is not doing error correction too.
So both commands return same value, without error correction.

On Tue, 22 Feb 2022 21:47:57 +0100 Pali Rohár pali@kernel.org wrote:
On Thursday 17 February 2022 15:31:10 Marek Behún wrote:
* But this command does not provide access to lock bit.
*/
- if (word < 2) {
in[0] = row;
in[1] = word * 32;
res = mbox_do_cmd(MBOX_CMD_OTP_READ_32B, in, 2, out, 2);
if (res != -ENOSYS) {
if (!res)
*data = out[0];
return res;
}
/* Fallback for old version of CZ.NIC wtmi firmware. */
- }
I am afraid this is not correct, because Marvell's firmware reads the efuse without Error Correction. So it is possible for Marvell's command to return different value than CZ.NIC's command.
This is not truth. CZ.NIC firmware for MBOX_CMD_OTP_READ command calls efuse_read_row_no_ecc which is not doing error correction too.
So both commands return same value, without error correction.
Seems that I have trouble remembering what how I have actually implemented it :) Oh well. Sorry about this.

Add support for reading NB fuse OTP, SB fuse OTP and Security OTP values via U-Boot fuse API on Armada 37xx boards.
Pali Rohár (5): arm: mvebu: a37xx: Add support for reading NB and SB fuse OTP value arm: mvebu: a37xx: Enable fuse command on all Armada 3720 boards arm: mvebu: a37xx: Move generic mbox code to arch/arm/mach-mvebu arm: mvebu: a37xx: Extend mbox_do_cmd() code arm: mvebu: a37xx: Add support for reading Security OTP values
arch/arm/mach-mvebu/Kconfig | 1 + arch/arm/mach-mvebu/Makefile | 3 + arch/arm/mach-mvebu/armada3700/Makefile | 3 +- arch/arm/mach-mvebu/armada3700/efuse.c | 170 ++++++++++++++++++++ arch/arm/mach-mvebu/armada3700/mbox.c | 83 ++++++++++ arch/arm/mach-mvebu/include/mach/mbox.h | 40 +++++ board/CZ.NIC/turris_mox/mox_sp.c | 73 +-------- configs/mvebu_db-88f3720_defconfig | 2 + configs/mvebu_espressobin-88f3720_defconfig | 2 + configs/turris_mox_defconfig | 2 + configs/uDPU_defconfig | 2 + 11 files changed, 310 insertions(+), 71 deletions(-) create mode 100644 arch/arm/mach-mvebu/armada3700/efuse.c create mode 100644 arch/arm/mach-mvebu/armada3700/mbox.c create mode 100644 arch/arm/mach-mvebu/include/mach/mbox.h

Implement reading NB and SB fuses of Armada 37xx SOC via U-Boot fuse API.
Banks 0-43 are reserved for accessing Security OTP (not implemented yet). Bank 44 is used for accessing North Bridge OTP (69 bits via words 0-2). Bank 45 is used for accessing South Bridge OTP (97 bits via words 0-3).
Write support is not implemented yet because it looks like that both North and South Bridge OTPs are already burned in factory with some data. The meaning of some bits of North Bridge is documented in WTMI source code. The meaning of bits in South Bridge is unknown.
Signed-off-by: Pali Rohár pali@kernel.org Reviewed-by: Marek Behún marek.behun@nic.cz --- arch/arm/mach-mvebu/Kconfig | 1 + arch/arm/mach-mvebu/Makefile | 3 + arch/arm/mach-mvebu/armada3700/Makefile | 1 + arch/arm/mach-mvebu/armada3700/efuse.c | 136 ++++++++++++++++++++++++ 4 files changed, 141 insertions(+) create mode 100644 arch/arm/mach-mvebu/armada3700/efuse.c
diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig index d23cc0c760f1..659c4fe2380a 100644 --- a/arch/arm/mach-mvebu/Kconfig +++ b/arch/arm/mach-mvebu/Kconfig @@ -44,6 +44,7 @@ config ARMADA_XP config ARMADA_3700 bool select ARM64 + select HAVE_MVEBU_EFUSE
# Armada 7K and 8K are very similar - use only one Kconfig symbol for both config ARMADA_8K diff --git a/arch/arm/mach-mvebu/Makefile b/arch/arm/mach-mvebu/Makefile index a5a20877dda6..1b451889d242 100644 --- a/arch/arm/mach-mvebu/Makefile +++ b/arch/arm/mach-mvebu/Makefile @@ -27,7 +27,10 @@ obj-$(CONFIG_ARMADA_375) += ../../../drivers/ddr/marvell/axp/xor.o obj-$(CONFIG_ARMADA_38X) += ../../../drivers/ddr/marvell/a38x/xor.o obj-$(CONFIG_ARMADA_XP) += ../../../drivers/ddr/marvell/axp/xor.o obj-$(CONFIG_ARMADA_MSYS) += ../../../drivers/ddr/marvell/axp/xor.o + +ifdef CONFIG_ARMADA_38X obj-$(CONFIG_MVEBU_EFUSE) += efuse.o +endif
extra-y += kwbimage.cfg
diff --git a/arch/arm/mach-mvebu/armada3700/Makefile b/arch/arm/mach-mvebu/armada3700/Makefile index 031b3e854e36..cd74726cc778 100644 --- a/arch/arm/mach-mvebu/armada3700/Makefile +++ b/arch/arm/mach-mvebu/armada3700/Makefile @@ -3,3 +3,4 @@ # Copyright (C) 2016 Stefan Roese sr@denx.de
obj-y = cpu.o +obj-$(CONFIG_MVEBU_EFUSE) += efuse.o diff --git a/arch/arm/mach-mvebu/armada3700/efuse.c b/arch/arm/mach-mvebu/armada3700/efuse.c new file mode 100644 index 000000000000..03778f17ea49 --- /dev/null +++ b/arch/arm/mach-mvebu/armada3700/efuse.c @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) 2017 Marvell International Ltd. + * (C) 2021 Pali Rohár pali@kernel.org + */ + +#include <config.h> +#include <common.h> +#include <asm/io.h> +#include <linux/delay.h> +#include <mach/soc.h> + +#define OTP_NB_REG_BASE ((void __iomem *)MVEBU_REGISTER(0x12600)) +#define OTP_SB_REG_BASE ((void __iomem *)MVEBU_REGISTER(0x1A200)) + +#define OTP_CONTROL_OFF 0x00 +#define OTP_MODE_BIT BIT(15) +#define OTP_RPTR_RST_BIT BIT(14) +#define OTP_POR_B_BIT BIT(13) +#define OTP_PRDT_BIT BIT(3) +#define OTP_READ_PORT_OFF 0x04 +#define OTP_READ_POINTER_OFF 0x08 +#define OTP_PTR_INC_BIT BIT(8) + +static void otp_read_parallel(void __iomem *base, u32 *data, u32 count) +{ + u32 regval; + + /* 1. Clear OTP_MODE_NB to parallel mode */ + regval = readl(base + OTP_CONTROL_OFF); + regval &= ~OTP_MODE_BIT; + writel(regval, base + OTP_CONTROL_OFF); + + /* 2. Set OTP_POR_B_NB enter normal operation */ + regval = readl(base + OTP_CONTROL_OFF); + regval |= OTP_POR_B_BIT; + writel(regval, base + OTP_CONTROL_OFF); + + /* 3. Set OTP_PTR_INC_NB to auto-increment pointer after each read */ + regval = readl(base + OTP_READ_POINTER_OFF); + regval |= OTP_PTR_INC_BIT; + writel(regval, base + OTP_READ_POINTER_OFF); + + /* 4. Set OTP_RPTR_RST_NB, then clear the same field */ + regval = readl(base + OTP_CONTROL_OFF); + regval |= OTP_RPTR_RST_BIT; + writel(regval, base + OTP_CONTROL_OFF); + + regval = readl(base + OTP_CONTROL_OFF); + regval &= ~OTP_RPTR_RST_BIT; + writel(regval, base + OTP_CONTROL_OFF); + + /* 5. Toggle OTP_PRDT_NB + * a. Set OTP_PRDT_NB to 1. + * b. Clear OTP_PRDT_NB to 0. + * c. Wait for a minimum of 100 ns. + * d. Set OTP_PRDT_NB to 1 + */ + regval = readl(base + OTP_CONTROL_OFF); + regval |= OTP_PRDT_BIT; + writel(regval, base + OTP_CONTROL_OFF); + + regval = readl(base + OTP_CONTROL_OFF); + regval &= ~OTP_PRDT_BIT; + writel(regval, base + OTP_CONTROL_OFF); + + ndelay(100); + + regval = readl(base + OTP_CONTROL_OFF); + regval |= OTP_PRDT_BIT; + writel(regval, base + OTP_CONTROL_OFF); + + while (count-- > 0) { + /* 6. Read the content of OTP 32-bits at a time */ + ndelay(100000); + *(data++) = readl(base + OTP_READ_PORT_OFF); + } +} + +/* + * Banks 0-43 are used for accessing Security OTP (44 rows with 67 bits via 44 banks and words 0-2) + * Bank 44 is used for accessing North Bridge OTP (69 bits via words 0-2) + * Bank 45 is used for accessing South Bridge OTP (97 bits via words 0-3) + */ + +#define RWTM_ROWS 44 +#define RWTM_MAX_BANK (RWTM_ROWS - 1) +#define RWTM_ROW_WORDS 3 +#define OTP_NB_BANK RWTM_ROWS +#define OTP_NB_WORDS 3 +#define OTP_SB_BANK (RWTM_ROWS + 1) +#define OTP_SB_WORDS 4 + +int fuse_read(u32 bank, u32 word, u32 *val) +{ + if (bank <= RWTM_MAX_BANK) { + if (word >= RWTM_ROW_WORDS) + return -EINVAL; + /* TODO: not implemented yet */ + return -ENOSYS; + } else if (bank == OTP_NB_BANK) { + u32 data[OTP_NB_WORDS]; + if (word >= OTP_NB_WORDS) + return -EINVAL; + otp_read_parallel(OTP_NB_REG_BASE, data, OTP_NB_WORDS); + *val = data[word]; + return 0; + } else if (bank == OTP_SB_BANK) { + u32 data[OTP_SB_WORDS]; + if (word >= OTP_SB_WORDS) + return -EINVAL; + otp_read_parallel(OTP_SB_REG_BASE, data, OTP_SB_WORDS); + *val = data[word]; + return 0; + } else { + return -EINVAL; + } +} + +int fuse_prog(u32 bank, u32 word, u32 val) +{ + /* TODO: not implemented yet */ + return -ENOSYS; +} + +int fuse_sense(u32 bank, u32 word, u32 *val) +{ + /* not supported */ + return -ENOSYS; +} + +int fuse_override(u32 bank, u32 word, u32 val) +{ + /* not supported */ + return -ENOSYS; +}

On 2/17/22 19:50, Pali Rohár wrote:
Implement reading NB and SB fuses of Armada 37xx SOC via U-Boot fuse API.
Banks 0-43 are reserved for accessing Security OTP (not implemented yet). Bank 44 is used for accessing North Bridge OTP (69 bits via words 0-2). Bank 45 is used for accessing South Bridge OTP (97 bits via words 0-3).
Write support is not implemented yet because it looks like that both North and South Bridge OTPs are already burned in factory with some data. The meaning of some bits of North Bridge is documented in WTMI source code. The meaning of bits in South Bridge is unknown.
Signed-off-by: Pali Rohár pali@kernel.org Reviewed-by: Marek Behún marek.behun@nic.cz
Reviewed-by: Stefan Roese sr@denx.de
Thanks, Stefan
arch/arm/mach-mvebu/Kconfig | 1 + arch/arm/mach-mvebu/Makefile | 3 + arch/arm/mach-mvebu/armada3700/Makefile | 1 + arch/arm/mach-mvebu/armada3700/efuse.c | 136 ++++++++++++++++++++++++ 4 files changed, 141 insertions(+) create mode 100644 arch/arm/mach-mvebu/armada3700/efuse.c
diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig index d23cc0c760f1..659c4fe2380a 100644 --- a/arch/arm/mach-mvebu/Kconfig +++ b/arch/arm/mach-mvebu/Kconfig @@ -44,6 +44,7 @@ config ARMADA_XP config ARMADA_3700 bool select ARM64
select HAVE_MVEBU_EFUSE
# Armada 7K and 8K are very similar - use only one Kconfig symbol for both config ARMADA_8K
diff --git a/arch/arm/mach-mvebu/Makefile b/arch/arm/mach-mvebu/Makefile index a5a20877dda6..1b451889d242 100644 --- a/arch/arm/mach-mvebu/Makefile +++ b/arch/arm/mach-mvebu/Makefile @@ -27,7 +27,10 @@ obj-$(CONFIG_ARMADA_375) += ../../../drivers/ddr/marvell/axp/xor.o obj-$(CONFIG_ARMADA_38X) += ../../../drivers/ddr/marvell/a38x/xor.o obj-$(CONFIG_ARMADA_XP) += ../../../drivers/ddr/marvell/axp/xor.o obj-$(CONFIG_ARMADA_MSYS) += ../../../drivers/ddr/marvell/axp/xor.o
+ifdef CONFIG_ARMADA_38X obj-$(CONFIG_MVEBU_EFUSE) += efuse.o +endif
extra-y += kwbimage.cfg
diff --git a/arch/arm/mach-mvebu/armada3700/Makefile b/arch/arm/mach-mvebu/armada3700/Makefile index 031b3e854e36..cd74726cc778 100644 --- a/arch/arm/mach-mvebu/armada3700/Makefile +++ b/arch/arm/mach-mvebu/armada3700/Makefile @@ -3,3 +3,4 @@ # Copyright (C) 2016 Stefan Roese sr@denx.de
obj-y = cpu.o +obj-$(CONFIG_MVEBU_EFUSE) += efuse.o diff --git a/arch/arm/mach-mvebu/armada3700/efuse.c b/arch/arm/mach-mvebu/armada3700/efuse.c new file mode 100644 index 000000000000..03778f17ea49 --- /dev/null +++ b/arch/arm/mach-mvebu/armada3700/efuse.c @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- (C) 2017 Marvell International Ltd.
- (C) 2021 Pali Rohár pali@kernel.org
- */
+#include <config.h> +#include <common.h> +#include <asm/io.h> +#include <linux/delay.h> +#include <mach/soc.h>
+#define OTP_NB_REG_BASE ((void __iomem *)MVEBU_REGISTER(0x12600)) +#define OTP_SB_REG_BASE ((void __iomem *)MVEBU_REGISTER(0x1A200))
+#define OTP_CONTROL_OFF 0x00 +#define OTP_MODE_BIT BIT(15) +#define OTP_RPTR_RST_BIT BIT(14) +#define OTP_POR_B_BIT BIT(13) +#define OTP_PRDT_BIT BIT(3) +#define OTP_READ_PORT_OFF 0x04 +#define OTP_READ_POINTER_OFF 0x08 +#define OTP_PTR_INC_BIT BIT(8)
+static void otp_read_parallel(void __iomem *base, u32 *data, u32 count) +{
- u32 regval;
- /* 1. Clear OTP_MODE_NB to parallel mode */
- regval = readl(base + OTP_CONTROL_OFF);
- regval &= ~OTP_MODE_BIT;
- writel(regval, base + OTP_CONTROL_OFF);
- /* 2. Set OTP_POR_B_NB enter normal operation */
- regval = readl(base + OTP_CONTROL_OFF);
- regval |= OTP_POR_B_BIT;
- writel(regval, base + OTP_CONTROL_OFF);
- /* 3. Set OTP_PTR_INC_NB to auto-increment pointer after each read */
- regval = readl(base + OTP_READ_POINTER_OFF);
- regval |= OTP_PTR_INC_BIT;
- writel(regval, base + OTP_READ_POINTER_OFF);
- /* 4. Set OTP_RPTR_RST_NB, then clear the same field */
- regval = readl(base + OTP_CONTROL_OFF);
- regval |= OTP_RPTR_RST_BIT;
- writel(regval, base + OTP_CONTROL_OFF);
- regval = readl(base + OTP_CONTROL_OFF);
- regval &= ~OTP_RPTR_RST_BIT;
- writel(regval, base + OTP_CONTROL_OFF);
- /* 5. Toggle OTP_PRDT_NB
* a. Set OTP_PRDT_NB to 1.
* b. Clear OTP_PRDT_NB to 0.
* c. Wait for a minimum of 100 ns.
* d. Set OTP_PRDT_NB to 1
*/
- regval = readl(base + OTP_CONTROL_OFF);
- regval |= OTP_PRDT_BIT;
- writel(regval, base + OTP_CONTROL_OFF);
- regval = readl(base + OTP_CONTROL_OFF);
- regval &= ~OTP_PRDT_BIT;
- writel(regval, base + OTP_CONTROL_OFF);
- ndelay(100);
- regval = readl(base + OTP_CONTROL_OFF);
- regval |= OTP_PRDT_BIT;
- writel(regval, base + OTP_CONTROL_OFF);
- while (count-- > 0) {
/* 6. Read the content of OTP 32-bits at a time */
ndelay(100000);
*(data++) = readl(base + OTP_READ_PORT_OFF);
- }
+}
+/*
- Banks 0-43 are used for accessing Security OTP (44 rows with 67 bits via 44 banks and words 0-2)
- Bank 44 is used for accessing North Bridge OTP (69 bits via words 0-2)
- Bank 45 is used for accessing South Bridge OTP (97 bits via words 0-3)
- */
+#define RWTM_ROWS 44 +#define RWTM_MAX_BANK (RWTM_ROWS - 1) +#define RWTM_ROW_WORDS 3 +#define OTP_NB_BANK RWTM_ROWS +#define OTP_NB_WORDS 3 +#define OTP_SB_BANK (RWTM_ROWS + 1) +#define OTP_SB_WORDS 4
+int fuse_read(u32 bank, u32 word, u32 *val) +{
- if (bank <= RWTM_MAX_BANK) {
if (word >= RWTM_ROW_WORDS)
return -EINVAL;
/* TODO: not implemented yet */
return -ENOSYS;
- } else if (bank == OTP_NB_BANK) {
u32 data[OTP_NB_WORDS];
if (word >= OTP_NB_WORDS)
return -EINVAL;
otp_read_parallel(OTP_NB_REG_BASE, data, OTP_NB_WORDS);
*val = data[word];
return 0;
- } else if (bank == OTP_SB_BANK) {
u32 data[OTP_SB_WORDS];
if (word >= OTP_SB_WORDS)
return -EINVAL;
otp_read_parallel(OTP_SB_REG_BASE, data, OTP_SB_WORDS);
*val = data[word];
return 0;
- } else {
return -EINVAL;
- }
+}
+int fuse_prog(u32 bank, u32 word, u32 val) +{
- /* TODO: not implemented yet */
- return -ENOSYS;
+}
+int fuse_sense(u32 bank, u32 word, u32 *val) +{
- /* not supported */
- return -ENOSYS;
+}
+int fuse_override(u32 bank, u32 word, u32 val) +{
- /* not supported */
- return -ENOSYS;
+}
Viele Grüße, Stefan Roese

Allow to read OTP bits via U-Boot fuse command on all Armada 3720 boards.
Signed-off-by: Pali Rohár pali@kernel.org Reviewed-by: Marek Behún marek.behun@nic.cz --- configs/mvebu_db-88f3720_defconfig | 2 ++ configs/mvebu_espressobin-88f3720_defconfig | 2 ++ configs/turris_mox_defconfig | 2 ++ configs/uDPU_defconfig | 2 ++ 4 files changed, 8 insertions(+)
diff --git a/configs/mvebu_db-88f3720_defconfig b/configs/mvebu_db-88f3720_defconfig index b600217692f1..6cc90fa54266 100644 --- a/configs/mvebu_db-88f3720_defconfig +++ b/configs/mvebu_db-88f3720_defconfig @@ -5,6 +5,7 @@ CONFIG_SYS_TEXT_BASE=0x00000000 CONFIG_SYS_MALLOC_F_LEN=0x2000 CONFIG_NR_DRAM_BANKS=1 CONFIG_TARGET_MVEBU_ARMADA_37XX=y +CONFIG_MVEBU_EFUSE=y CONFIG_ENV_SIZE=0x10000 CONFIG_ENV_OFFSET=0x3f0000 CONFIG_ENV_SECT_SIZE=0x10000 @@ -24,6 +25,7 @@ CONFIG_DISPLAY_BOARDINFO_LATE=y CONFIG_ARCH_EARLY_INIT_R=y CONFIG_BOARD_EARLY_INIT_F=y # CONFIG_CMD_FLASH is not set +CONFIG_CMD_FUSE=y CONFIG_CMD_GPIO=y CONFIG_CMD_I2C=y CONFIG_CMD_MMC=y diff --git a/configs/mvebu_espressobin-88f3720_defconfig b/configs/mvebu_espressobin-88f3720_defconfig index 4b8206a38f1b..f8196eab82e5 100644 --- a/configs/mvebu_espressobin-88f3720_defconfig +++ b/configs/mvebu_espressobin-88f3720_defconfig @@ -5,6 +5,7 @@ CONFIG_SYS_TEXT_BASE=0x00000000 CONFIG_SYS_MALLOC_F_LEN=0x2000 CONFIG_NR_DRAM_BANKS=1 CONFIG_TARGET_MVEBU_ARMADA_37XX=y +CONFIG_MVEBU_EFUSE=y CONFIG_ENV_SIZE=0x10000 CONFIG_ENV_OFFSET=0x3F0000 CONFIG_ENV_SECT_SIZE=0x10000 @@ -26,6 +27,7 @@ CONFIG_ARCH_EARLY_INIT_R=y CONFIG_BOARD_EARLY_INIT_F=y CONFIG_BOARD_LATE_INIT=y # CONFIG_CMD_FLASH is not set +CONFIG_CMD_FUSE=y CONFIG_CMD_GPIO=y CONFIG_CMD_GPT=y CONFIG_CMD_I2C=y diff --git a/configs/turris_mox_defconfig b/configs/turris_mox_defconfig index 84a0b4c2b20e..25e417c94562 100644 --- a/configs/turris_mox_defconfig +++ b/configs/turris_mox_defconfig @@ -5,6 +5,7 @@ CONFIG_SYS_TEXT_BASE=0x00000000 CONFIG_SYS_MALLOC_F_LEN=0x2000 CONFIG_NR_DRAM_BANKS=2 CONFIG_TARGET_TURRIS_MOX=y +CONFIG_MVEBU_EFUSE=y CONFIG_ENV_SIZE=0x10000 CONFIG_ENV_OFFSET=0x180000 CONFIG_ENV_SECT_SIZE=0x10000 @@ -31,6 +32,7 @@ CONFIG_MISC_INIT_R=y CONFIG_CMD_SHA1SUM=y CONFIG_CMD_CLK=y # CONFIG_CMD_FLASH is not set +CONFIG_CMD_FUSE=y CONFIG_CMD_GPIO=y CONFIG_CMD_GPT=y CONFIG_CMD_I2C=y diff --git a/configs/uDPU_defconfig b/configs/uDPU_defconfig index b5f2115e6332..7698e080e2a2 100644 --- a/configs/uDPU_defconfig +++ b/configs/uDPU_defconfig @@ -4,6 +4,7 @@ CONFIG_ARCH_MVEBU=y CONFIG_SYS_TEXT_BASE=0x00000000 CONFIG_SYS_MALLOC_F_LEN=0x2000 CONFIG_TARGET_MVEBU_ARMADA_37XX=y +CONFIG_MVEBU_EFUSE=y CONFIG_ENV_SIZE=0x10000 CONFIG_ENV_OFFSET=0x180000 CONFIG_ENV_SECT_SIZE=0x10000 @@ -29,6 +30,7 @@ CONFIG_SYS_PROMPT="uDPU>> " # CONFIG_CMD_IMI is not set # CONFIG_CMD_XIMG is not set # CONFIG_CMD_FLASH is not set +CONFIG_CMD_FUSE=y CONFIG_CMD_GPIO=y CONFIG_CMD_I2C=y CONFIG_CMD_MMC=y

On 2/17/22 19:50, Pali Rohár wrote:
Allow to read OTP bits via U-Boot fuse command on all Armada 3720 boards.
Signed-off-by: Pali Rohár pali@kernel.org Reviewed-by: Marek Behún marek.behun@nic.cz
Reviewed-by: Stefan Roese sr@denx.de
Thanks, Stefan
configs/mvebu_db-88f3720_defconfig | 2 ++ configs/mvebu_espressobin-88f3720_defconfig | 2 ++ configs/turris_mox_defconfig | 2 ++ configs/uDPU_defconfig | 2 ++ 4 files changed, 8 insertions(+)
diff --git a/configs/mvebu_db-88f3720_defconfig b/configs/mvebu_db-88f3720_defconfig index b600217692f1..6cc90fa54266 100644 --- a/configs/mvebu_db-88f3720_defconfig +++ b/configs/mvebu_db-88f3720_defconfig @@ -5,6 +5,7 @@ CONFIG_SYS_TEXT_BASE=0x00000000 CONFIG_SYS_MALLOC_F_LEN=0x2000 CONFIG_NR_DRAM_BANKS=1 CONFIG_TARGET_MVEBU_ARMADA_37XX=y +CONFIG_MVEBU_EFUSE=y CONFIG_ENV_SIZE=0x10000 CONFIG_ENV_OFFSET=0x3f0000 CONFIG_ENV_SECT_SIZE=0x10000 @@ -24,6 +25,7 @@ CONFIG_DISPLAY_BOARDINFO_LATE=y CONFIG_ARCH_EARLY_INIT_R=y CONFIG_BOARD_EARLY_INIT_F=y # CONFIG_CMD_FLASH is not set +CONFIG_CMD_FUSE=y CONFIG_CMD_GPIO=y CONFIG_CMD_I2C=y CONFIG_CMD_MMC=y diff --git a/configs/mvebu_espressobin-88f3720_defconfig b/configs/mvebu_espressobin-88f3720_defconfig index 4b8206a38f1b..f8196eab82e5 100644 --- a/configs/mvebu_espressobin-88f3720_defconfig +++ b/configs/mvebu_espressobin-88f3720_defconfig @@ -5,6 +5,7 @@ CONFIG_SYS_TEXT_BASE=0x00000000 CONFIG_SYS_MALLOC_F_LEN=0x2000 CONFIG_NR_DRAM_BANKS=1 CONFIG_TARGET_MVEBU_ARMADA_37XX=y +CONFIG_MVEBU_EFUSE=y CONFIG_ENV_SIZE=0x10000 CONFIG_ENV_OFFSET=0x3F0000 CONFIG_ENV_SECT_SIZE=0x10000 @@ -26,6 +27,7 @@ CONFIG_ARCH_EARLY_INIT_R=y CONFIG_BOARD_EARLY_INIT_F=y CONFIG_BOARD_LATE_INIT=y # CONFIG_CMD_FLASH is not set +CONFIG_CMD_FUSE=y CONFIG_CMD_GPIO=y CONFIG_CMD_GPT=y CONFIG_CMD_I2C=y diff --git a/configs/turris_mox_defconfig b/configs/turris_mox_defconfig index 84a0b4c2b20e..25e417c94562 100644 --- a/configs/turris_mox_defconfig +++ b/configs/turris_mox_defconfig @@ -5,6 +5,7 @@ CONFIG_SYS_TEXT_BASE=0x00000000 CONFIG_SYS_MALLOC_F_LEN=0x2000 CONFIG_NR_DRAM_BANKS=2 CONFIG_TARGET_TURRIS_MOX=y +CONFIG_MVEBU_EFUSE=y CONFIG_ENV_SIZE=0x10000 CONFIG_ENV_OFFSET=0x180000 CONFIG_ENV_SECT_SIZE=0x10000 @@ -31,6 +32,7 @@ CONFIG_MISC_INIT_R=y CONFIG_CMD_SHA1SUM=y CONFIG_CMD_CLK=y # CONFIG_CMD_FLASH is not set +CONFIG_CMD_FUSE=y CONFIG_CMD_GPIO=y CONFIG_CMD_GPT=y CONFIG_CMD_I2C=y diff --git a/configs/uDPU_defconfig b/configs/uDPU_defconfig index b5f2115e6332..7698e080e2a2 100644 --- a/configs/uDPU_defconfig +++ b/configs/uDPU_defconfig @@ -4,6 +4,7 @@ CONFIG_ARCH_MVEBU=y CONFIG_SYS_TEXT_BASE=0x00000000 CONFIG_SYS_MALLOC_F_LEN=0x2000 CONFIG_TARGET_MVEBU_ARMADA_37XX=y +CONFIG_MVEBU_EFUSE=y CONFIG_ENV_SIZE=0x10000 CONFIG_ENV_OFFSET=0x180000 CONFIG_ENV_SECT_SIZE=0x10000 @@ -29,6 +30,7 @@ CONFIG_SYS_PROMPT="uDPU>> " # CONFIG_CMD_IMI is not set # CONFIG_CMD_XIMG is not set # CONFIG_CMD_FLASH is not set +CONFIG_CMD_FUSE=y CONFIG_CMD_GPIO=y CONFIG_CMD_I2C=y CONFIG_CMD_MMC=y
Viele Grüße, Stefan Roese

Generic A3720 mbox code is currently in Turris Mox specific board file board/CZ.NIC/turris_mox/mox_sp.c. Move it to board independent arch file arch/arm/mach-mvebu/armada3700/mbox.c.
Signed-off-by: Pali Rohár pali@kernel.org Reviewed-by: Marek Behún marek.behun@nic.cz --- arch/arm/mach-mvebu/armada3700/Makefile | 2 +- arch/arm/mach-mvebu/armada3700/mbox.c | 67 ++++++++++++++++++++++++ arch/arm/mach-mvebu/include/mach/mbox.h | 23 +++++++++ board/CZ.NIC/turris_mox/mox_sp.c | 69 +------------------------ 4 files changed, 92 insertions(+), 69 deletions(-) create mode 100644 arch/arm/mach-mvebu/armada3700/mbox.c create mode 100644 arch/arm/mach-mvebu/include/mach/mbox.h
diff --git a/arch/arm/mach-mvebu/armada3700/Makefile b/arch/arm/mach-mvebu/armada3700/Makefile index cd74726cc778..98350a41e04b 100644 --- a/arch/arm/mach-mvebu/armada3700/Makefile +++ b/arch/arm/mach-mvebu/armada3700/Makefile @@ -2,5 +2,5 @@ # # Copyright (C) 2016 Stefan Roese sr@denx.de
-obj-y = cpu.o +obj-y = cpu.o mbox.o obj-$(CONFIG_MVEBU_EFUSE) += efuse.o diff --git a/arch/arm/mach-mvebu/armada3700/mbox.c b/arch/arm/mach-mvebu/armada3700/mbox.c new file mode 100644 index 000000000000..cb86b967c2eb --- /dev/null +++ b/arch/arm/mach-mvebu/armada3700/mbox.c @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018 Marek Behun marek.behun@nic.cz + */ + +#include <common.h> +#include <asm/arch/soc.h> +#include <asm/io.h> +#include <linux/bitops.h> +#include <linux/delay.h> +#include <mach/mbox.h> + +#define RWTM_BASE (MVEBU_REGISTER(0xb0000)) +#define RWTM_CMD_PARAM(i) (size_t)(RWTM_BASE + (i) * 4) +#define RWTM_CMD (RWTM_BASE + 0x40) +#define RWTM_CMD_RETSTATUS (RWTM_BASE + 0x80) +#define RWTM_CMD_STATUS(i) (size_t)(RWTM_BASE + 0x84 + (i) * 4) + +#define RWTM_HOST_INT_RESET (RWTM_BASE + 0xc8) +#define RWTM_HOST_INT_MASK (RWTM_BASE + 0xcc) +#define SP_CMD_COMPLETE BIT(0) + +#define MBOX_STS_SUCCESS (0x0 << 30) +#define MBOX_STS_FAIL (0x1 << 30) +#define MBOX_STS_BADCMD (0x2 << 30) +#define MBOX_STS_LATER (0x3 << 30) +#define MBOX_STS_ERROR(s) ((s) & (3 << 30)) +#define MBOX_STS_VALUE(s) (((s) >> 10) & 0xfffff) +#define MBOX_STS_CMD(s) ((s) & 0x3ff) + +int mbox_do_cmd(enum mbox_cmd cmd, u32 *out, int nout) +{ + const int tries = 50; + int i; + u32 status; + + clrbits_le32(RWTM_HOST_INT_MASK, SP_CMD_COMPLETE); + + writel(cmd, RWTM_CMD); + + for (i = 0; i < tries; ++i) { + mdelay(10); + if (readl(RWTM_HOST_INT_RESET) & SP_CMD_COMPLETE) + break; + } + + if (i == tries) { + /* if timed out, don't read status */ + setbits_le32(RWTM_HOST_INT_RESET, SP_CMD_COMPLETE); + return -ETIMEDOUT; + } + + for (i = 0; i < nout; ++i) + out[i] = readl(RWTM_CMD_STATUS(i)); + status = readl(RWTM_CMD_RETSTATUS); + + setbits_le32(RWTM_HOST_INT_RESET, SP_CMD_COMPLETE); + + if (MBOX_STS_CMD(status) != cmd) + return -EIO; + else if (MBOX_STS_ERROR(status) == MBOX_STS_FAIL) + return -(int)MBOX_STS_VALUE(status); + else if (MBOX_STS_ERROR(status) != MBOX_STS_SUCCESS) + return -EIO; + else + return MBOX_STS_VALUE(status); +} diff --git a/arch/arm/mach-mvebu/include/mach/mbox.h b/arch/arm/mach-mvebu/include/mach/mbox.h new file mode 100644 index 000000000000..981204935832 --- /dev/null +++ b/arch/arm/mach-mvebu/include/mach/mbox.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2018 Marek Behun marek.behun@nic.cz + */ + +#ifndef _MVEBU_MBOX_H +#define _MVEBU_MBOX_H + +enum mbox_cmd { + MBOX_CMD_GET_RANDOM = 1, + MBOX_CMD_BOARD_INFO, + MBOX_CMD_ECDSA_PUB_KEY, + MBOX_CMD_HASH, + MBOX_CMD_SIGN, + MBOX_CMD_VERIFY, + + MBOX_CMD_OTP_READ, + MBOX_CMD_OTP_WRITE, +}; + +int mbox_do_cmd(enum mbox_cmd cmd, u32 *in, int nout); + +#endif diff --git a/board/CZ.NIC/turris_mox/mox_sp.c b/board/CZ.NIC/turris_mox/mox_sp.c index cc57b9f095f7..4de067bbebbb 100644 --- a/board/CZ.NIC/turris_mox/mox_sp.c +++ b/board/CZ.NIC/turris_mox/mox_sp.c @@ -8,74 +8,7 @@ #include <asm/io.h> #include <linux/bitops.h> #include <linux/delay.h> - -#define RWTM_BASE (MVEBU_REGISTER(0xb0000)) -#define RWTM_CMD_PARAM(i) (size_t)(RWTM_BASE + (i) * 4) -#define RWTM_CMD (RWTM_BASE + 0x40) -#define RWTM_CMD_RETSTATUS (RWTM_BASE + 0x80) -#define RWTM_CMD_STATUS(i) (size_t)(RWTM_BASE + 0x84 + (i) * 4) - -#define RWTM_HOST_INT_RESET (RWTM_BASE + 0xc8) -#define RWTM_HOST_INT_MASK (RWTM_BASE + 0xcc) -#define SP_CMD_COMPLETE BIT(0) - -#define MBOX_STS_SUCCESS (0x0 << 30) -#define MBOX_STS_FAIL (0x1 << 30) -#define MBOX_STS_BADCMD (0x2 << 30) -#define MBOX_STS_LATER (0x3 << 30) -#define MBOX_STS_ERROR(s) ((s) & (3 << 30)) -#define MBOX_STS_VALUE(s) (((s) >> 10) & 0xfffff) -#define MBOX_STS_CMD(s) ((s) & 0x3ff) - -enum mbox_cmd { - MBOX_CMD_GET_RANDOM = 1, - MBOX_CMD_BOARD_INFO, - MBOX_CMD_ECDSA_PUB_KEY, - MBOX_CMD_HASH, - MBOX_CMD_SIGN, - MBOX_CMD_VERIFY, - - MBOX_CMD_OTP_READ, - MBOX_CMD_OTP_WRITE -}; - -static int mbox_do_cmd(enum mbox_cmd cmd, u32 *out, int nout) -{ - const int tries = 50; - int i; - u32 status; - - clrbits_le32(RWTM_HOST_INT_MASK, SP_CMD_COMPLETE); - - writel(cmd, RWTM_CMD); - - for (i = 0; i < tries; ++i) { - mdelay(10); - if (readl(RWTM_HOST_INT_RESET) & SP_CMD_COMPLETE) - break; - } - - if (i == tries) { - /* if timed out, don't read status */ - setbits_le32(RWTM_HOST_INT_RESET, SP_CMD_COMPLETE); - return -ETIMEDOUT; - } - - for (i = 0; i < nout; ++i) - out[i] = readl(RWTM_CMD_STATUS(i)); - status = readl(RWTM_CMD_RETSTATUS); - - setbits_le32(RWTM_HOST_INT_RESET, SP_CMD_COMPLETE); - - if (MBOX_STS_CMD(status) != cmd) - return -EIO; - else if (MBOX_STS_ERROR(status) == MBOX_STS_FAIL) - return -(int)MBOX_STS_VALUE(status); - else if (MBOX_STS_ERROR(status) != MBOX_STS_SUCCESS) - return -EIO; - else - return MBOX_STS_VALUE(status); -} +#include <mach/mbox.h>
const char *mox_sp_get_ecdsa_public_key(void) {

On 2/17/22 19:50, Pali Rohár wrote:
Generic A3720 mbox code is currently in Turris Mox specific board file board/CZ.NIC/turris_mox/mox_sp.c. Move it to board independent arch file arch/arm/mach-mvebu/armada3700/mbox.c.
Signed-off-by: Pali Rohár pali@kernel.org Reviewed-by: Marek Behún marek.behun@nic.cz
Reviewed-by: Stefan Roese sr@denx.de
Thanks, Stefan
arch/arm/mach-mvebu/armada3700/Makefile | 2 +- arch/arm/mach-mvebu/armada3700/mbox.c | 67 ++++++++++++++++++++++++ arch/arm/mach-mvebu/include/mach/mbox.h | 23 +++++++++ board/CZ.NIC/turris_mox/mox_sp.c | 69 +------------------------ 4 files changed, 92 insertions(+), 69 deletions(-) create mode 100644 arch/arm/mach-mvebu/armada3700/mbox.c create mode 100644 arch/arm/mach-mvebu/include/mach/mbox.h
diff --git a/arch/arm/mach-mvebu/armada3700/Makefile b/arch/arm/mach-mvebu/armada3700/Makefile index cd74726cc778..98350a41e04b 100644 --- a/arch/arm/mach-mvebu/armada3700/Makefile +++ b/arch/arm/mach-mvebu/armada3700/Makefile @@ -2,5 +2,5 @@ # # Copyright (C) 2016 Stefan Roese sr@denx.de
-obj-y = cpu.o +obj-y = cpu.o mbox.o obj-$(CONFIG_MVEBU_EFUSE) += efuse.o diff --git a/arch/arm/mach-mvebu/armada3700/mbox.c b/arch/arm/mach-mvebu/armada3700/mbox.c new file mode 100644 index 000000000000..cb86b967c2eb --- /dev/null +++ b/arch/arm/mach-mvebu/armada3700/mbox.c @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Copyright (C) 2018 Marek Behun marek.behun@nic.cz
- */
+#include <common.h> +#include <asm/arch/soc.h> +#include <asm/io.h> +#include <linux/bitops.h> +#include <linux/delay.h> +#include <mach/mbox.h>
+#define RWTM_BASE (MVEBU_REGISTER(0xb0000)) +#define RWTM_CMD_PARAM(i) (size_t)(RWTM_BASE + (i) * 4) +#define RWTM_CMD (RWTM_BASE + 0x40) +#define RWTM_CMD_RETSTATUS (RWTM_BASE + 0x80) +#define RWTM_CMD_STATUS(i) (size_t)(RWTM_BASE + 0x84 + (i) * 4)
+#define RWTM_HOST_INT_RESET (RWTM_BASE + 0xc8) +#define RWTM_HOST_INT_MASK (RWTM_BASE + 0xcc) +#define SP_CMD_COMPLETE BIT(0)
+#define MBOX_STS_SUCCESS (0x0 << 30) +#define MBOX_STS_FAIL (0x1 << 30) +#define MBOX_STS_BADCMD (0x2 << 30) +#define MBOX_STS_LATER (0x3 << 30) +#define MBOX_STS_ERROR(s) ((s) & (3 << 30)) +#define MBOX_STS_VALUE(s) (((s) >> 10) & 0xfffff) +#define MBOX_STS_CMD(s) ((s) & 0x3ff)
+int mbox_do_cmd(enum mbox_cmd cmd, u32 *out, int nout) +{
- const int tries = 50;
- int i;
- u32 status;
- clrbits_le32(RWTM_HOST_INT_MASK, SP_CMD_COMPLETE);
- writel(cmd, RWTM_CMD);
- for (i = 0; i < tries; ++i) {
mdelay(10);
if (readl(RWTM_HOST_INT_RESET) & SP_CMD_COMPLETE)
break;
- }
- if (i == tries) {
/* if timed out, don't read status */
setbits_le32(RWTM_HOST_INT_RESET, SP_CMD_COMPLETE);
return -ETIMEDOUT;
- }
- for (i = 0; i < nout; ++i)
out[i] = readl(RWTM_CMD_STATUS(i));
- status = readl(RWTM_CMD_RETSTATUS);
- setbits_le32(RWTM_HOST_INT_RESET, SP_CMD_COMPLETE);
- if (MBOX_STS_CMD(status) != cmd)
return -EIO;
- else if (MBOX_STS_ERROR(status) == MBOX_STS_FAIL)
return -(int)MBOX_STS_VALUE(status);
- else if (MBOX_STS_ERROR(status) != MBOX_STS_SUCCESS)
return -EIO;
- else
return MBOX_STS_VALUE(status);
+} diff --git a/arch/arm/mach-mvebu/include/mach/mbox.h b/arch/arm/mach-mvebu/include/mach/mbox.h new file mode 100644 index 000000000000..981204935832 --- /dev/null +++ b/arch/arm/mach-mvebu/include/mach/mbox.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- Copyright (C) 2018 Marek Behun marek.behun@nic.cz
- */
+#ifndef _MVEBU_MBOX_H +#define _MVEBU_MBOX_H
+enum mbox_cmd {
- MBOX_CMD_GET_RANDOM = 1,
- MBOX_CMD_BOARD_INFO,
- MBOX_CMD_ECDSA_PUB_KEY,
- MBOX_CMD_HASH,
- MBOX_CMD_SIGN,
- MBOX_CMD_VERIFY,
- MBOX_CMD_OTP_READ,
- MBOX_CMD_OTP_WRITE,
+};
+int mbox_do_cmd(enum mbox_cmd cmd, u32 *in, int nout);
+#endif diff --git a/board/CZ.NIC/turris_mox/mox_sp.c b/board/CZ.NIC/turris_mox/mox_sp.c index cc57b9f095f7..4de067bbebbb 100644 --- a/board/CZ.NIC/turris_mox/mox_sp.c +++ b/board/CZ.NIC/turris_mox/mox_sp.c @@ -8,74 +8,7 @@ #include <asm/io.h> #include <linux/bitops.h> #include <linux/delay.h>
-#define RWTM_BASE (MVEBU_REGISTER(0xb0000)) -#define RWTM_CMD_PARAM(i) (size_t)(RWTM_BASE + (i) * 4) -#define RWTM_CMD (RWTM_BASE + 0x40) -#define RWTM_CMD_RETSTATUS (RWTM_BASE + 0x80) -#define RWTM_CMD_STATUS(i) (size_t)(RWTM_BASE + 0x84 + (i) * 4)
-#define RWTM_HOST_INT_RESET (RWTM_BASE + 0xc8) -#define RWTM_HOST_INT_MASK (RWTM_BASE + 0xcc) -#define SP_CMD_COMPLETE BIT(0)
-#define MBOX_STS_SUCCESS (0x0 << 30) -#define MBOX_STS_FAIL (0x1 << 30) -#define MBOX_STS_BADCMD (0x2 << 30) -#define MBOX_STS_LATER (0x3 << 30) -#define MBOX_STS_ERROR(s) ((s) & (3 << 30)) -#define MBOX_STS_VALUE(s) (((s) >> 10) & 0xfffff) -#define MBOX_STS_CMD(s) ((s) & 0x3ff)
-enum mbox_cmd {
- MBOX_CMD_GET_RANDOM = 1,
- MBOX_CMD_BOARD_INFO,
- MBOX_CMD_ECDSA_PUB_KEY,
- MBOX_CMD_HASH,
- MBOX_CMD_SIGN,
- MBOX_CMD_VERIFY,
- MBOX_CMD_OTP_READ,
- MBOX_CMD_OTP_WRITE
-};
-static int mbox_do_cmd(enum mbox_cmd cmd, u32 *out, int nout) -{
- const int tries = 50;
- int i;
- u32 status;
- clrbits_le32(RWTM_HOST_INT_MASK, SP_CMD_COMPLETE);
- writel(cmd, RWTM_CMD);
- for (i = 0; i < tries; ++i) {
mdelay(10);
if (readl(RWTM_HOST_INT_RESET) & SP_CMD_COMPLETE)
break;
- }
- if (i == tries) {
/* if timed out, don't read status */
setbits_le32(RWTM_HOST_INT_RESET, SP_CMD_COMPLETE);
return -ETIMEDOUT;
- }
- for (i = 0; i < nout; ++i)
out[i] = readl(RWTM_CMD_STATUS(i));
- status = readl(RWTM_CMD_RETSTATUS);
- setbits_le32(RWTM_HOST_INT_RESET, SP_CMD_COMPLETE);
- if (MBOX_STS_CMD(status) != cmd)
return -EIO;
- else if (MBOX_STS_ERROR(status) == MBOX_STS_FAIL)
return -(int)MBOX_STS_VALUE(status);
- else if (MBOX_STS_ERROR(status) != MBOX_STS_SUCCESS)
return -EIO;
- else
return MBOX_STS_VALUE(status);
-} +#include <mach/mbox.h>
const char *mox_sp_get_ecdsa_public_key(void) {
Viele Grüße, Stefan Roese

Allow to specify input parameters, define all available mbox commands supported by CZ.NIC's secure firmware and also Marvell's fuse.bin firmware and fix parsing response from Marvell OTP commands.
Signed-off-by: Pali Rohár pali@kernel.org Reviewed-by: Marek Behún marek.behun@nic.cz --- arch/arm/mach-mvebu/armada3700/mbox.c | 20 ++++++++++++++++++-- arch/arm/mach-mvebu/include/mach/mbox.h | 19 ++++++++++++++++++- board/CZ.NIC/turris_mox/mox_sp.c | 4 ++-- 3 files changed, 38 insertions(+), 5 deletions(-)
diff --git a/arch/arm/mach-mvebu/armada3700/mbox.c b/arch/arm/mach-mvebu/armada3700/mbox.c index cb86b967c2eb..eb1f82845f0f 100644 --- a/arch/arm/mach-mvebu/armada3700/mbox.c +++ b/arch/arm/mach-mvebu/armada3700/mbox.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Marek Behun marek.behun@nic.cz + * Copyright (C) 2021 Pali Rohár pali@kernel.org */
#include <common.h> @@ -15,6 +16,7 @@ #define RWTM_CMD (RWTM_BASE + 0x40) #define RWTM_CMD_RETSTATUS (RWTM_BASE + 0x80) #define RWTM_CMD_STATUS(i) (size_t)(RWTM_BASE + 0x84 + (i) * 4) +#define MAX_ARGS 16
#define RWTM_HOST_INT_RESET (RWTM_BASE + 0xc8) #define RWTM_HOST_INT_MASK (RWTM_BASE + 0xcc) @@ -27,15 +29,27 @@ #define MBOX_STS_ERROR(s) ((s) & (3 << 30)) #define MBOX_STS_VALUE(s) (((s) >> 10) & 0xfffff) #define MBOX_STS_CMD(s) ((s) & 0x3ff) +#define MBOX_STS_MARVELL_ERROR(s) ((s) == 0 ? 0 : \ + (s) == 2 ? ETIMEDOUT : \ + (s) == 3 ? EINVAL : \ + (s) == 4 ? ENOSYS : \ + EIO)
-int mbox_do_cmd(enum mbox_cmd cmd, u32 *out, int nout) +int mbox_do_cmd(enum mbox_cmd cmd, u32 *in, int nin, u32 *out, int nout) { const int tries = 50; int i; u32 status;
+ if (nin > MAX_ARGS || nout > MAX_ARGS) + return -EINVAL; + clrbits_le32(RWTM_HOST_INT_MASK, SP_CMD_COMPLETE);
+ for (i = 0; i < nin; i++) + writel(in[i], RWTM_CMD_PARAM(i)); + for (; i < MAX_ARGS; i++) + writel(0x0, RWTM_CMD_PARAM(i)); writel(cmd, RWTM_CMD);
for (i = 0; i < tries; ++i) { @@ -57,9 +71,11 @@ int mbox_do_cmd(enum mbox_cmd cmd, u32 *out, int nout) setbits_le32(RWTM_HOST_INT_RESET, SP_CMD_COMPLETE);
if (MBOX_STS_CMD(status) != cmd) - return -EIO; + return -MBOX_STS_MARVELL_ERROR(status); else if (MBOX_STS_ERROR(status) == MBOX_STS_FAIL) return -(int)MBOX_STS_VALUE(status); + else if (MBOX_STS_ERROR(status) == MBOX_STS_BADCMD) + return -ENOSYS; else if (MBOX_STS_ERROR(status) != MBOX_STS_SUCCESS) return -EIO; else diff --git a/arch/arm/mach-mvebu/include/mach/mbox.h b/arch/arm/mach-mvebu/include/mach/mbox.h index 981204935832..f1cb55f2bfe7 100644 --- a/arch/arm/mach-mvebu/include/mach/mbox.h +++ b/arch/arm/mach-mvebu/include/mach/mbox.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0+ */ /* * Copyright (C) 2018 Marek Behun marek.behun@nic.cz + * Copyright (C) 2021 Pali Rohár pali@kernel.org */
#ifndef _MVEBU_MBOX_H @@ -16,8 +17,24 @@ enum mbox_cmd {
MBOX_CMD_OTP_READ, MBOX_CMD_OTP_WRITE, + + MBOX_CMD_REBOOT, + + /* OTP read commands supported by Marvell fuse.bin firmware */ + MBOX_CMD_OTP_READ_1B = 257, + MBOX_CMD_OTP_READ_8B, + MBOX_CMD_OTP_READ_32B, + MBOX_CMD_OTP_READ_64B, + MBOX_CMD_OTP_READ_256B, + + /* OTP write commands supported by Marvell fuse.bin firmware */ + MBOX_CMD_OTP_WRITE_1B = 513, + MBOX_CMD_OTP_WRITE_8B, + MBOX_CMD_OTP_WRITE_32B, + MBOX_CMD_OTP_WRITE_64B, + MBOX_CMD_OTP_WRITE_256B, };
-int mbox_do_cmd(enum mbox_cmd cmd, u32 *in, int nout); +int mbox_do_cmd(enum mbox_cmd cmd, u32 *in, int nin, u32 *out, int nout);
#endif diff --git a/board/CZ.NIC/turris_mox/mox_sp.c b/board/CZ.NIC/turris_mox/mox_sp.c index 4de067bbebbb..93e96b014fca 100644 --- a/board/CZ.NIC/turris_mox/mox_sp.c +++ b/board/CZ.NIC/turris_mox/mox_sp.c @@ -19,7 +19,7 @@ const char *mox_sp_get_ecdsa_public_key(void) if (public_key[0]) return public_key;
- res = mbox_do_cmd(MBOX_CMD_ECDSA_PUB_KEY, out, 16); + res = mbox_do_cmd(MBOX_CMD_ECDSA_PUB_KEY, NULL, 0, out, 16); if (res < 0) return NULL;
@@ -47,7 +47,7 @@ int mbox_sp_get_board_info(u64 *sn, u8 *mac1, u8 *mac2, int *bv, int *ram) u32 out[8]; int res;
- res = mbox_do_cmd(MBOX_CMD_BOARD_INFO, out, 8); + res = mbox_do_cmd(MBOX_CMD_BOARD_INFO, NULL, 0, out, 8); if (res < 0) return res;

On 2/17/22 19:50, Pali Rohár wrote:
Allow to specify input parameters, define all available mbox commands supported by CZ.NIC's secure firmware and also Marvell's fuse.bin firmware and fix parsing response from Marvell OTP commands.
Signed-off-by: Pali Rohár pali@kernel.org Reviewed-by: Marek Behún marek.behun@nic.cz
Reviewed-by: Stefan Roese sr@denx.de
Thanks, Stefan
arch/arm/mach-mvebu/armada3700/mbox.c | 20 ++++++++++++++++++-- arch/arm/mach-mvebu/include/mach/mbox.h | 19 ++++++++++++++++++- board/CZ.NIC/turris_mox/mox_sp.c | 4 ++-- 3 files changed, 38 insertions(+), 5 deletions(-)
diff --git a/arch/arm/mach-mvebu/armada3700/mbox.c b/arch/arm/mach-mvebu/armada3700/mbox.c index cb86b967c2eb..eb1f82845f0f 100644 --- a/arch/arm/mach-mvebu/armada3700/mbox.c +++ b/arch/arm/mach-mvebu/armada3700/mbox.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ /*
- Copyright (C) 2018 Marek Behun marek.behun@nic.cz
- Copyright (C) 2021 Pali Rohár pali@kernel.org
*/
#include <common.h>
@@ -15,6 +16,7 @@ #define RWTM_CMD (RWTM_BASE + 0x40) #define RWTM_CMD_RETSTATUS (RWTM_BASE + 0x80) #define RWTM_CMD_STATUS(i) (size_t)(RWTM_BASE + 0x84 + (i) * 4) +#define MAX_ARGS 16
#define RWTM_HOST_INT_RESET (RWTM_BASE + 0xc8) #define RWTM_HOST_INT_MASK (RWTM_BASE + 0xcc) @@ -27,15 +29,27 @@ #define MBOX_STS_ERROR(s) ((s) & (3 << 30)) #define MBOX_STS_VALUE(s) (((s) >> 10) & 0xfffff) #define MBOX_STS_CMD(s) ((s) & 0x3ff) +#define MBOX_STS_MARVELL_ERROR(s) ((s) == 0 ? 0 : \
(s) == 2 ? ETIMEDOUT : \
(s) == 3 ? EINVAL : \
(s) == 4 ? ENOSYS : \
EIO)
-int mbox_do_cmd(enum mbox_cmd cmd, u32 *out, int nout) +int mbox_do_cmd(enum mbox_cmd cmd, u32 *in, int nin, u32 *out, int nout) { const int tries = 50; int i; u32 status;
if (nin > MAX_ARGS || nout > MAX_ARGS)
return -EINVAL;
clrbits_le32(RWTM_HOST_INT_MASK, SP_CMD_COMPLETE);
for (i = 0; i < nin; i++)
writel(in[i], RWTM_CMD_PARAM(i));
for (; i < MAX_ARGS; i++)
writel(0x0, RWTM_CMD_PARAM(i));
writel(cmd, RWTM_CMD);
for (i = 0; i < tries; ++i) {
@@ -57,9 +71,11 @@ int mbox_do_cmd(enum mbox_cmd cmd, u32 *out, int nout) setbits_le32(RWTM_HOST_INT_RESET, SP_CMD_COMPLETE);
if (MBOX_STS_CMD(status) != cmd)
return -EIO;
else if (MBOX_STS_ERROR(status) == MBOX_STS_FAIL) return -(int)MBOX_STS_VALUE(status);return -MBOX_STS_MARVELL_ERROR(status);
- else if (MBOX_STS_ERROR(status) == MBOX_STS_BADCMD)
else if (MBOX_STS_ERROR(status) != MBOX_STS_SUCCESS) return -EIO; elsereturn -ENOSYS;
diff --git a/arch/arm/mach-mvebu/include/mach/mbox.h b/arch/arm/mach-mvebu/include/mach/mbox.h index 981204935832..f1cb55f2bfe7 100644 --- a/arch/arm/mach-mvebu/include/mach/mbox.h +++ b/arch/arm/mach-mvebu/include/mach/mbox.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0+ */ /*
- Copyright (C) 2018 Marek Behun marek.behun@nic.cz
- Copyright (C) 2021 Pali Rohár pali@kernel.org
*/
#ifndef _MVEBU_MBOX_H
@@ -16,8 +17,24 @@ enum mbox_cmd {
MBOX_CMD_OTP_READ, MBOX_CMD_OTP_WRITE,
- MBOX_CMD_REBOOT,
- /* OTP read commands supported by Marvell fuse.bin firmware */
- MBOX_CMD_OTP_READ_1B = 257,
- MBOX_CMD_OTP_READ_8B,
- MBOX_CMD_OTP_READ_32B,
- MBOX_CMD_OTP_READ_64B,
- MBOX_CMD_OTP_READ_256B,
- /* OTP write commands supported by Marvell fuse.bin firmware */
- MBOX_CMD_OTP_WRITE_1B = 513,
- MBOX_CMD_OTP_WRITE_8B,
- MBOX_CMD_OTP_WRITE_32B,
- MBOX_CMD_OTP_WRITE_64B,
- MBOX_CMD_OTP_WRITE_256B, };
-int mbox_do_cmd(enum mbox_cmd cmd, u32 *in, int nout); +int mbox_do_cmd(enum mbox_cmd cmd, u32 *in, int nin, u32 *out, int nout);
#endif diff --git a/board/CZ.NIC/turris_mox/mox_sp.c b/board/CZ.NIC/turris_mox/mox_sp.c index 4de067bbebbb..93e96b014fca 100644 --- a/board/CZ.NIC/turris_mox/mox_sp.c +++ b/board/CZ.NIC/turris_mox/mox_sp.c @@ -19,7 +19,7 @@ const char *mox_sp_get_ecdsa_public_key(void) if (public_key[0]) return public_key;
- res = mbox_do_cmd(MBOX_CMD_ECDSA_PUB_KEY, out, 16);
- res = mbox_do_cmd(MBOX_CMD_ECDSA_PUB_KEY, NULL, 0, out, 16); if (res < 0) return NULL;
@@ -47,7 +47,7 @@ int mbox_sp_get_board_info(u64 *sn, u8 *mac1, u8 *mac2, int *bv, int *ram) u32 out[8]; int res;
- res = mbox_do_cmd(MBOX_CMD_BOARD_INFO, out, 8);
- res = mbox_do_cmd(MBOX_CMD_BOARD_INFO, NULL, 0, out, 8); if (res < 0) return res;
Viele Grüße, Stefan Roese

It is not possible for the A53 core (on which U-Boot is running) to read it directly. For this purpose Marvell defined mbox API for sending OTP commands between CM3 and A53 cores.
Implement these Marvell fuse reading mbox commands via U-Boot fuse API.
Banks 0-43 are used for accessing Security OTP (44 rows with 67 bits via 44 banks and words 0-2).
Note that of the 67 bits, the 3 upper bits are: 1 lock bit and 2 auxiliary bits (meant for testing during the manufacture of the SOC, as I understand it).
Also note that the lock bit and the auxiliary bits are not readable via Marvell commands.
With CZ.NIC's commands the lock bit is readable.
Write support is not implemented yet.
Signed-off-by: Pali Rohár pali@kernel.org --- arch/arm/mach-mvebu/armada3700/efuse.c | 38 ++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-)
diff --git a/arch/arm/mach-mvebu/armada3700/efuse.c b/arch/arm/mach-mvebu/armada3700/efuse.c index 03778f17ea49..fcf6edd08ce1 100644 --- a/arch/arm/mach-mvebu/armada3700/efuse.c +++ b/arch/arm/mach-mvebu/armada3700/efuse.c @@ -8,6 +8,7 @@ #include <common.h> #include <asm/io.h> #include <linux/delay.h> +#include <mach/mbox.h> #include <mach/soc.h>
#define OTP_NB_REG_BASE ((void __iomem *)MVEBU_REGISTER(0x12600)) @@ -77,6 +78,40 @@ static void otp_read_parallel(void __iomem *base, u32 *data, u32 count) } }
+static int rwtm_otp_read(u8 row, u32 word, u32 *data) +{ + u32 out[3]; + u32 in[2]; + int res = -EINVAL; + + if (word < 2) { + /* + * MBOX_CMD_OTP_READ_32B command is supported by Marvell + * fuse.bin firmware and also by new CZ.NIC wtmi firmware. + * This command returns raw bits without ECC corrections. + * It does not provide access to the lock bit. + */ + in[0] = row; + in[1] = word * 32; + res = mbox_do_cmd(MBOX_CMD_OTP_READ_32B, in, 2, out, 2); + if (!res) + *data = out[0]; + } else if (word == 2) { + /* + * MBOX_CMD_OTP_READ command is supported only by CZ.NIC wtmi + * firmware and provide access to all bits, including lock bit. + * But this command does ECC correction of returned bits. So + * use it only for accessing lock bit. + */ + in[0] = row; + res = mbox_do_cmd(MBOX_CMD_OTP_READ, in, 1, out, 3); + if (!res) + *data = out[2]; + } + + return res; +} + /* * Banks 0-43 are used for accessing Security OTP (44 rows with 67 bits via 44 banks and words 0-2) * Bank 44 is used for accessing North Bridge OTP (69 bits via words 0-2) @@ -96,8 +131,7 @@ int fuse_read(u32 bank, u32 word, u32 *val) if (bank <= RWTM_MAX_BANK) { if (word >= RWTM_ROW_WORDS) return -EINVAL; - /* TODO: not implemented yet */ - return -ENOSYS; + return rwtm_otp_read(bank, word, val); } else if (bank == OTP_NB_BANK) { u32 data[OTP_NB_WORDS]; if (word >= OTP_NB_WORDS)

On Thu, 17 Feb 2022 19:50:46 +0100 Pali Rohár pali@kernel.org wrote:
It is not possible for the A53 core (on which U-Boot is running) to read it directly. For this purpose Marvell defined mbox API for sending OTP commands between CM3 and A53 cores.
Implement these Marvell fuse reading mbox commands via U-Boot fuse API.
Banks 0-43 are used for accessing Security OTP (44 rows with 67 bits via 44 banks and words 0-2).
Note that of the 67 bits, the 3 upper bits are: 1 lock bit and 2 auxiliary bits (meant for testing during the manufacture of the SOC, as I understand it).
Also note that the lock bit and the auxiliary bits are not readable via Marvell commands.
With CZ.NIC's commands the lock bit is readable.
Write support is not implemented yet.
Signed-off-by: Pali Rohár pali@kernel.org
arch/arm/mach-mvebu/armada3700/efuse.c | 38 ++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-)
diff --git a/arch/arm/mach-mvebu/armada3700/efuse.c b/arch/arm/mach-mvebu/armada3700/efuse.c index 03778f17ea49..fcf6edd08ce1 100644 --- a/arch/arm/mach-mvebu/armada3700/efuse.c +++ b/arch/arm/mach-mvebu/armada3700/efuse.c @@ -8,6 +8,7 @@ #include <common.h> #include <asm/io.h> #include <linux/delay.h> +#include <mach/mbox.h> #include <mach/soc.h>
#define OTP_NB_REG_BASE ((void __iomem *)MVEBU_REGISTER(0x12600)) @@ -77,6 +78,40 @@ static void otp_read_parallel(void __iomem *base, u32 *data, u32 count) } }
+static int rwtm_otp_read(u8 row, u32 word, u32 *data) +{
- u32 out[3];
- u32 in[2];
- int res = -EINVAL;
- if (word < 2) {
/*
* MBOX_CMD_OTP_READ_32B command is supported by Marvell
* fuse.bin firmware and also by new CZ.NIC wtmi firmware.
* This command returns raw bits without ECC corrections.
* It does not provide access to the lock bit.
*/
in[0] = row;
in[1] = word * 32;
res = mbox_do_cmd(MBOX_CMD_OTP_READ_32B, in, 2, out, 2);
if (!res)
*data = out[0];
- } else if (word == 2) {
/*
* MBOX_CMD_OTP_READ command is supported only by CZ.NIC wtmi
* firmware and provide
nitpick: *provides
Reviewed-by: Marek Behún marek.behun@nic.cz

On 2/17/22 19:50, Pali Rohár wrote:
It is not possible for the A53 core (on which U-Boot is running) to read it directly. For this purpose Marvell defined mbox API for sending OTP commands between CM3 and A53 cores.
Implement these Marvell fuse reading mbox commands via U-Boot fuse API.
Banks 0-43 are used for accessing Security OTP (44 rows with 67 bits via 44 banks and words 0-2).
Note that of the 67 bits, the 3 upper bits are: 1 lock bit and 2 auxiliary bits (meant for testing during the manufacture of the SOC, as I understand it).
Also note that the lock bit and the auxiliary bits are not readable via Marvell commands.
With CZ.NIC's commands the lock bit is readable.
Write support is not implemented yet.
Signed-off-by: Pali Rohár pali@kernel.org
Reviewed-by: Stefan Roese sr@denx.de
Thanks, Stefan
arch/arm/mach-mvebu/armada3700/efuse.c | 38 ++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-)
diff --git a/arch/arm/mach-mvebu/armada3700/efuse.c b/arch/arm/mach-mvebu/armada3700/efuse.c index 03778f17ea49..fcf6edd08ce1 100644 --- a/arch/arm/mach-mvebu/armada3700/efuse.c +++ b/arch/arm/mach-mvebu/armada3700/efuse.c @@ -8,6 +8,7 @@ #include <common.h> #include <asm/io.h> #include <linux/delay.h> +#include <mach/mbox.h> #include <mach/soc.h>
#define OTP_NB_REG_BASE ((void __iomem *)MVEBU_REGISTER(0x12600)) @@ -77,6 +78,40 @@ static void otp_read_parallel(void __iomem *base, u32 *data, u32 count) } }
+static int rwtm_otp_read(u8 row, u32 word, u32 *data) +{
- u32 out[3];
- u32 in[2];
- int res = -EINVAL;
- if (word < 2) {
/*
* MBOX_CMD_OTP_READ_32B command is supported by Marvell
* fuse.bin firmware and also by new CZ.NIC wtmi firmware.
* This command returns raw bits without ECC corrections.
* It does not provide access to the lock bit.
*/
in[0] = row;
in[1] = word * 32;
res = mbox_do_cmd(MBOX_CMD_OTP_READ_32B, in, 2, out, 2);
if (!res)
*data = out[0];
- } else if (word == 2) {
/*
* MBOX_CMD_OTP_READ command is supported only by CZ.NIC wtmi
* firmware and provide access to all bits, including lock bit.
* But this command does ECC correction of returned bits. So
* use it only for accessing lock bit.
*/
in[0] = row;
res = mbox_do_cmd(MBOX_CMD_OTP_READ, in, 1, out, 3);
if (!res)
*data = out[2];
- }
- return res;
+}
- /*
- Banks 0-43 are used for accessing Security OTP (44 rows with 67 bits via 44 banks and words 0-2)
- Bank 44 is used for accessing North Bridge OTP (69 bits via words 0-2)
@@ -96,8 +131,7 @@ int fuse_read(u32 bank, u32 word, u32 *val) if (bank <= RWTM_MAX_BANK) { if (word >= RWTM_ROW_WORDS) return -EINVAL;
/* TODO: not implemented yet */
return -ENOSYS;
} else if (bank == OTP_NB_BANK) { u32 data[OTP_NB_WORDS]; if (word >= OTP_NB_WORDS)return rwtm_otp_read(bank, word, val);
Viele Grüße, Stefan Roese

On Thursday 17 February 2022 19:50:46 Pali Rohár wrote:
It is not possible for the A53 core (on which U-Boot is running) to read it directly. For this purpose Marvell defined mbox API for sending OTP commands between CM3 and A53 cores.
Implement these Marvell fuse reading mbox commands via U-Boot fuse API.
Banks 0-43 are used for accessing Security OTP (44 rows with 67 bits via 44 banks and words 0-2).
Note that of the 67 bits, the 3 upper bits are: 1 lock bit and 2 auxiliary bits (meant for testing during the manufacture of the SOC, as I understand it).
Also note that the lock bit and the auxiliary bits are not readable via Marvell commands.
With CZ.NIC's commands the lock bit is readable.
Write support is not implemented yet.
Signed-off-by: Pali Rohár pali@kernel.org
arch/arm/mach-mvebu/armada3700/efuse.c | 38 ++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-)
diff --git a/arch/arm/mach-mvebu/armada3700/efuse.c b/arch/arm/mach-mvebu/armada3700/efuse.c index 03778f17ea49..fcf6edd08ce1 100644 --- a/arch/arm/mach-mvebu/armada3700/efuse.c +++ b/arch/arm/mach-mvebu/armada3700/efuse.c @@ -8,6 +8,7 @@ #include <common.h> #include <asm/io.h> #include <linux/delay.h> +#include <mach/mbox.h> #include <mach/soc.h>
#define OTP_NB_REG_BASE ((void __iomem *)MVEBU_REGISTER(0x12600)) @@ -77,6 +78,40 @@ static void otp_read_parallel(void __iomem *base, u32 *data, u32 count) } }
+static int rwtm_otp_read(u8 row, u32 word, u32 *data) +{
- u32 out[3];
- u32 in[2];
- int res = -EINVAL;
- if (word < 2) {
/*
* MBOX_CMD_OTP_READ_32B command is supported by Marvell
* fuse.bin firmware and also by new CZ.NIC wtmi firmware.
* This command returns raw bits without ECC corrections.
* It does not provide access to the lock bit.
*/
in[0] = row;
in[1] = word * 32;
res = mbox_do_cmd(MBOX_CMD_OTP_READ_32B, in, 2, out, 2);
if (!res)
*data = out[0];
- } else if (word == 2) {
/*
* MBOX_CMD_OTP_READ command is supported only by CZ.NIC wtmi
* firmware and provide access to all bits, including lock bit.
* But this command does ECC correction of returned bits. So
* use it only for accessing lock bit.
MBOX_CMD_OTP_READ (like MBOX_CMD_OTP_READ_32B) does not do ECC correction, I have verified it. So above comment is not correct.
*/
in[0] = row;
res = mbox_do_cmd(MBOX_CMD_OTP_READ, in, 1, out, 3);
if (!res)
*data = out[2];
- }
- return res;
+}
/*
- Banks 0-43 are used for accessing Security OTP (44 rows with 67 bits via 44 banks and words 0-2)
- Bank 44 is used for accessing North Bridge OTP (69 bits via words 0-2)
@@ -96,8 +131,7 @@ int fuse_read(u32 bank, u32 word, u32 *val) if (bank <= RWTM_MAX_BANK) { if (word >= RWTM_ROW_WORDS) return -EINVAL;
/* TODO: not implemented yet */
return -ENOSYS;
} else if (bank == OTP_NB_BANK) { u32 data[OTP_NB_WORDS]; if (word >= OTP_NB_WORDS)return rwtm_otp_read(bank, word, val);
-- 2.20.1

Add support for reading NB fuse OTP, SB fuse OTP and Security OTP values via U-Boot fuse API on Armada 37xx boards.
Changes in v3: * Updated comment in patch 5/5 about MBOX_CMD_OTP_READ command * In patch 5/5 fixed number of output arguments for MBOX_CMD_OTP_READ_32B command
Pali Rohár (5): arm: mvebu: a37xx: Add support for reading NB and SB fuse OTP value arm: mvebu: a37xx: Enable fuse command on all Armada 3720 boards arm: mvebu: a37xx: Move generic mbox code to arch/arm/mach-mvebu arm: mvebu: a37xx: Extend mbox_do_cmd() code arm: mvebu: a37xx: Add support for reading Security OTP values
arch/arm/mach-mvebu/Kconfig | 1 + arch/arm/mach-mvebu/Makefile | 3 + arch/arm/mach-mvebu/armada3700/Makefile | 3 +- arch/arm/mach-mvebu/armada3700/efuse.c | 171 ++++++++++++++++++++ arch/arm/mach-mvebu/armada3700/mbox.c | 83 ++++++++++ arch/arm/mach-mvebu/include/mach/mbox.h | 40 +++++ board/CZ.NIC/turris_mox/mox_sp.c | 73 +-------- configs/mvebu_db-88f3720_defconfig | 2 + configs/mvebu_espressobin-88f3720_defconfig | 2 + configs/turris_mox_defconfig | 2 + configs/uDPU_defconfig | 2 + 11 files changed, 311 insertions(+), 71 deletions(-) create mode 100644 arch/arm/mach-mvebu/armada3700/efuse.c create mode 100644 arch/arm/mach-mvebu/armada3700/mbox.c create mode 100644 arch/arm/mach-mvebu/include/mach/mbox.h

Implement reading NB and SB fuses of Armada 37xx SOC via U-Boot fuse API.
Banks 0-43 are reserved for accessing Security OTP (not implemented yet). Bank 44 is used for accessing North Bridge OTP (69 bits via words 0-2). Bank 45 is used for accessing South Bridge OTP (97 bits via words 0-3).
Write support is not implemented yet because it looks like that both North and South Bridge OTPs are already burned in factory with some data. The meaning of some bits of North Bridge is documented in WTMI source code. The meaning of bits in South Bridge is unknown.
Signed-off-by: Pali Rohár pali@kernel.org Reviewed-by: Marek Behún marek.behun@nic.cz Reviewed-by: Stefan Roese sr@denx.de --- arch/arm/mach-mvebu/Kconfig | 1 + arch/arm/mach-mvebu/Makefile | 3 + arch/arm/mach-mvebu/armada3700/Makefile | 1 + arch/arm/mach-mvebu/armada3700/efuse.c | 136 ++++++++++++++++++++++++ 4 files changed, 141 insertions(+) create mode 100644 arch/arm/mach-mvebu/armada3700/efuse.c
diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig index 7d487f270b51..81ba1d9f6423 100644 --- a/arch/arm/mach-mvebu/Kconfig +++ b/arch/arm/mach-mvebu/Kconfig @@ -44,6 +44,7 @@ config ARMADA_XP config ARMADA_3700 bool select ARM64 + select HAVE_MVEBU_EFUSE
# Armada 7K and 8K are very similar - use only one Kconfig symbol for both config ARMADA_8K diff --git a/arch/arm/mach-mvebu/Makefile b/arch/arm/mach-mvebu/Makefile index a5a20877dda6..1b451889d242 100644 --- a/arch/arm/mach-mvebu/Makefile +++ b/arch/arm/mach-mvebu/Makefile @@ -27,7 +27,10 @@ obj-$(CONFIG_ARMADA_375) += ../../../drivers/ddr/marvell/axp/xor.o obj-$(CONFIG_ARMADA_38X) += ../../../drivers/ddr/marvell/a38x/xor.o obj-$(CONFIG_ARMADA_XP) += ../../../drivers/ddr/marvell/axp/xor.o obj-$(CONFIG_ARMADA_MSYS) += ../../../drivers/ddr/marvell/axp/xor.o + +ifdef CONFIG_ARMADA_38X obj-$(CONFIG_MVEBU_EFUSE) += efuse.o +endif
extra-y += kwbimage.cfg
diff --git a/arch/arm/mach-mvebu/armada3700/Makefile b/arch/arm/mach-mvebu/armada3700/Makefile index 031b3e854e36..cd74726cc778 100644 --- a/arch/arm/mach-mvebu/armada3700/Makefile +++ b/arch/arm/mach-mvebu/armada3700/Makefile @@ -3,3 +3,4 @@ # Copyright (C) 2016 Stefan Roese sr@denx.de
obj-y = cpu.o +obj-$(CONFIG_MVEBU_EFUSE) += efuse.o diff --git a/arch/arm/mach-mvebu/armada3700/efuse.c b/arch/arm/mach-mvebu/armada3700/efuse.c new file mode 100644 index 000000000000..03778f17ea49 --- /dev/null +++ b/arch/arm/mach-mvebu/armada3700/efuse.c @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) 2017 Marvell International Ltd. + * (C) 2021 Pali Rohár pali@kernel.org + */ + +#include <config.h> +#include <common.h> +#include <asm/io.h> +#include <linux/delay.h> +#include <mach/soc.h> + +#define OTP_NB_REG_BASE ((void __iomem *)MVEBU_REGISTER(0x12600)) +#define OTP_SB_REG_BASE ((void __iomem *)MVEBU_REGISTER(0x1A200)) + +#define OTP_CONTROL_OFF 0x00 +#define OTP_MODE_BIT BIT(15) +#define OTP_RPTR_RST_BIT BIT(14) +#define OTP_POR_B_BIT BIT(13) +#define OTP_PRDT_BIT BIT(3) +#define OTP_READ_PORT_OFF 0x04 +#define OTP_READ_POINTER_OFF 0x08 +#define OTP_PTR_INC_BIT BIT(8) + +static void otp_read_parallel(void __iomem *base, u32 *data, u32 count) +{ + u32 regval; + + /* 1. Clear OTP_MODE_NB to parallel mode */ + regval = readl(base + OTP_CONTROL_OFF); + regval &= ~OTP_MODE_BIT; + writel(regval, base + OTP_CONTROL_OFF); + + /* 2. Set OTP_POR_B_NB enter normal operation */ + regval = readl(base + OTP_CONTROL_OFF); + regval |= OTP_POR_B_BIT; + writel(regval, base + OTP_CONTROL_OFF); + + /* 3. Set OTP_PTR_INC_NB to auto-increment pointer after each read */ + regval = readl(base + OTP_READ_POINTER_OFF); + regval |= OTP_PTR_INC_BIT; + writel(regval, base + OTP_READ_POINTER_OFF); + + /* 4. Set OTP_RPTR_RST_NB, then clear the same field */ + regval = readl(base + OTP_CONTROL_OFF); + regval |= OTP_RPTR_RST_BIT; + writel(regval, base + OTP_CONTROL_OFF); + + regval = readl(base + OTP_CONTROL_OFF); + regval &= ~OTP_RPTR_RST_BIT; + writel(regval, base + OTP_CONTROL_OFF); + + /* 5. Toggle OTP_PRDT_NB + * a. Set OTP_PRDT_NB to 1. + * b. Clear OTP_PRDT_NB to 0. + * c. Wait for a minimum of 100 ns. + * d. Set OTP_PRDT_NB to 1 + */ + regval = readl(base + OTP_CONTROL_OFF); + regval |= OTP_PRDT_BIT; + writel(regval, base + OTP_CONTROL_OFF); + + regval = readl(base + OTP_CONTROL_OFF); + regval &= ~OTP_PRDT_BIT; + writel(regval, base + OTP_CONTROL_OFF); + + ndelay(100); + + regval = readl(base + OTP_CONTROL_OFF); + regval |= OTP_PRDT_BIT; + writel(regval, base + OTP_CONTROL_OFF); + + while (count-- > 0) { + /* 6. Read the content of OTP 32-bits at a time */ + ndelay(100000); + *(data++) = readl(base + OTP_READ_PORT_OFF); + } +} + +/* + * Banks 0-43 are used for accessing Security OTP (44 rows with 67 bits via 44 banks and words 0-2) + * Bank 44 is used for accessing North Bridge OTP (69 bits via words 0-2) + * Bank 45 is used for accessing South Bridge OTP (97 bits via words 0-3) + */ + +#define RWTM_ROWS 44 +#define RWTM_MAX_BANK (RWTM_ROWS - 1) +#define RWTM_ROW_WORDS 3 +#define OTP_NB_BANK RWTM_ROWS +#define OTP_NB_WORDS 3 +#define OTP_SB_BANK (RWTM_ROWS + 1) +#define OTP_SB_WORDS 4 + +int fuse_read(u32 bank, u32 word, u32 *val) +{ + if (bank <= RWTM_MAX_BANK) { + if (word >= RWTM_ROW_WORDS) + return -EINVAL; + /* TODO: not implemented yet */ + return -ENOSYS; + } else if (bank == OTP_NB_BANK) { + u32 data[OTP_NB_WORDS]; + if (word >= OTP_NB_WORDS) + return -EINVAL; + otp_read_parallel(OTP_NB_REG_BASE, data, OTP_NB_WORDS); + *val = data[word]; + return 0; + } else if (bank == OTP_SB_BANK) { + u32 data[OTP_SB_WORDS]; + if (word >= OTP_SB_WORDS) + return -EINVAL; + otp_read_parallel(OTP_SB_REG_BASE, data, OTP_SB_WORDS); + *val = data[word]; + return 0; + } else { + return -EINVAL; + } +} + +int fuse_prog(u32 bank, u32 word, u32 val) +{ + /* TODO: not implemented yet */ + return -ENOSYS; +} + +int fuse_sense(u32 bank, u32 word, u32 *val) +{ + /* not supported */ + return -ENOSYS; +} + +int fuse_override(u32 bank, u32 word, u32 val) +{ + /* not supported */ + return -ENOSYS; +}

Allow to read OTP bits via U-Boot fuse command on all Armada 3720 boards.
Signed-off-by: Pali Rohár pali@kernel.org Reviewed-by: Marek Behún marek.behun@nic.cz Reviewed-by: Stefan Roese sr@denx.de --- configs/mvebu_db-88f3720_defconfig | 2 ++ configs/mvebu_espressobin-88f3720_defconfig | 2 ++ configs/turris_mox_defconfig | 2 ++ configs/uDPU_defconfig | 2 ++ 4 files changed, 8 insertions(+)
diff --git a/configs/mvebu_db-88f3720_defconfig b/configs/mvebu_db-88f3720_defconfig index b600217692f1..6cc90fa54266 100644 --- a/configs/mvebu_db-88f3720_defconfig +++ b/configs/mvebu_db-88f3720_defconfig @@ -5,6 +5,7 @@ CONFIG_SYS_TEXT_BASE=0x00000000 CONFIG_SYS_MALLOC_F_LEN=0x2000 CONFIG_NR_DRAM_BANKS=1 CONFIG_TARGET_MVEBU_ARMADA_37XX=y +CONFIG_MVEBU_EFUSE=y CONFIG_ENV_SIZE=0x10000 CONFIG_ENV_OFFSET=0x3f0000 CONFIG_ENV_SECT_SIZE=0x10000 @@ -24,6 +25,7 @@ CONFIG_DISPLAY_BOARDINFO_LATE=y CONFIG_ARCH_EARLY_INIT_R=y CONFIG_BOARD_EARLY_INIT_F=y # CONFIG_CMD_FLASH is not set +CONFIG_CMD_FUSE=y CONFIG_CMD_GPIO=y CONFIG_CMD_I2C=y CONFIG_CMD_MMC=y diff --git a/configs/mvebu_espressobin-88f3720_defconfig b/configs/mvebu_espressobin-88f3720_defconfig index 4b8206a38f1b..f8196eab82e5 100644 --- a/configs/mvebu_espressobin-88f3720_defconfig +++ b/configs/mvebu_espressobin-88f3720_defconfig @@ -5,6 +5,7 @@ CONFIG_SYS_TEXT_BASE=0x00000000 CONFIG_SYS_MALLOC_F_LEN=0x2000 CONFIG_NR_DRAM_BANKS=1 CONFIG_TARGET_MVEBU_ARMADA_37XX=y +CONFIG_MVEBU_EFUSE=y CONFIG_ENV_SIZE=0x10000 CONFIG_ENV_OFFSET=0x3F0000 CONFIG_ENV_SECT_SIZE=0x10000 @@ -26,6 +27,7 @@ CONFIG_ARCH_EARLY_INIT_R=y CONFIG_BOARD_EARLY_INIT_F=y CONFIG_BOARD_LATE_INIT=y # CONFIG_CMD_FLASH is not set +CONFIG_CMD_FUSE=y CONFIG_CMD_GPIO=y CONFIG_CMD_GPT=y CONFIG_CMD_I2C=y diff --git a/configs/turris_mox_defconfig b/configs/turris_mox_defconfig index 84a0b4c2b20e..25e417c94562 100644 --- a/configs/turris_mox_defconfig +++ b/configs/turris_mox_defconfig @@ -5,6 +5,7 @@ CONFIG_SYS_TEXT_BASE=0x00000000 CONFIG_SYS_MALLOC_F_LEN=0x2000 CONFIG_NR_DRAM_BANKS=2 CONFIG_TARGET_TURRIS_MOX=y +CONFIG_MVEBU_EFUSE=y CONFIG_ENV_SIZE=0x10000 CONFIG_ENV_OFFSET=0x180000 CONFIG_ENV_SECT_SIZE=0x10000 @@ -31,6 +32,7 @@ CONFIG_MISC_INIT_R=y CONFIG_CMD_SHA1SUM=y CONFIG_CMD_CLK=y # CONFIG_CMD_FLASH is not set +CONFIG_CMD_FUSE=y CONFIG_CMD_GPIO=y CONFIG_CMD_GPT=y CONFIG_CMD_I2C=y diff --git a/configs/uDPU_defconfig b/configs/uDPU_defconfig index b5f2115e6332..7698e080e2a2 100644 --- a/configs/uDPU_defconfig +++ b/configs/uDPU_defconfig @@ -4,6 +4,7 @@ CONFIG_ARCH_MVEBU=y CONFIG_SYS_TEXT_BASE=0x00000000 CONFIG_SYS_MALLOC_F_LEN=0x2000 CONFIG_TARGET_MVEBU_ARMADA_37XX=y +CONFIG_MVEBU_EFUSE=y CONFIG_ENV_SIZE=0x10000 CONFIG_ENV_OFFSET=0x180000 CONFIG_ENV_SECT_SIZE=0x10000 @@ -29,6 +30,7 @@ CONFIG_SYS_PROMPT="uDPU>> " # CONFIG_CMD_IMI is not set # CONFIG_CMD_XIMG is not set # CONFIG_CMD_FLASH is not set +CONFIG_CMD_FUSE=y CONFIG_CMD_GPIO=y CONFIG_CMD_I2C=y CONFIG_CMD_MMC=y

Generic A3720 mbox code is currently in Turris Mox specific board file board/CZ.NIC/turris_mox/mox_sp.c. Move it to board independent arch file arch/arm/mach-mvebu/armada3700/mbox.c.
Signed-off-by: Pali Rohár pali@kernel.org Reviewed-by: Marek Behún marek.behun@nic.cz Reviewed-by: Stefan Roese sr@denx.de --- arch/arm/mach-mvebu/armada3700/Makefile | 2 +- arch/arm/mach-mvebu/armada3700/mbox.c | 67 ++++++++++++++++++++++++ arch/arm/mach-mvebu/include/mach/mbox.h | 23 +++++++++ board/CZ.NIC/turris_mox/mox_sp.c | 69 +------------------------ 4 files changed, 92 insertions(+), 69 deletions(-) create mode 100644 arch/arm/mach-mvebu/armada3700/mbox.c create mode 100644 arch/arm/mach-mvebu/include/mach/mbox.h
diff --git a/arch/arm/mach-mvebu/armada3700/Makefile b/arch/arm/mach-mvebu/armada3700/Makefile index cd74726cc778..98350a41e04b 100644 --- a/arch/arm/mach-mvebu/armada3700/Makefile +++ b/arch/arm/mach-mvebu/armada3700/Makefile @@ -2,5 +2,5 @@ # # Copyright (C) 2016 Stefan Roese sr@denx.de
-obj-y = cpu.o +obj-y = cpu.o mbox.o obj-$(CONFIG_MVEBU_EFUSE) += efuse.o diff --git a/arch/arm/mach-mvebu/armada3700/mbox.c b/arch/arm/mach-mvebu/armada3700/mbox.c new file mode 100644 index 000000000000..cb86b967c2eb --- /dev/null +++ b/arch/arm/mach-mvebu/armada3700/mbox.c @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018 Marek Behun marek.behun@nic.cz + */ + +#include <common.h> +#include <asm/arch/soc.h> +#include <asm/io.h> +#include <linux/bitops.h> +#include <linux/delay.h> +#include <mach/mbox.h> + +#define RWTM_BASE (MVEBU_REGISTER(0xb0000)) +#define RWTM_CMD_PARAM(i) (size_t)(RWTM_BASE + (i) * 4) +#define RWTM_CMD (RWTM_BASE + 0x40) +#define RWTM_CMD_RETSTATUS (RWTM_BASE + 0x80) +#define RWTM_CMD_STATUS(i) (size_t)(RWTM_BASE + 0x84 + (i) * 4) + +#define RWTM_HOST_INT_RESET (RWTM_BASE + 0xc8) +#define RWTM_HOST_INT_MASK (RWTM_BASE + 0xcc) +#define SP_CMD_COMPLETE BIT(0) + +#define MBOX_STS_SUCCESS (0x0 << 30) +#define MBOX_STS_FAIL (0x1 << 30) +#define MBOX_STS_BADCMD (0x2 << 30) +#define MBOX_STS_LATER (0x3 << 30) +#define MBOX_STS_ERROR(s) ((s) & (3 << 30)) +#define MBOX_STS_VALUE(s) (((s) >> 10) & 0xfffff) +#define MBOX_STS_CMD(s) ((s) & 0x3ff) + +int mbox_do_cmd(enum mbox_cmd cmd, u32 *out, int nout) +{ + const int tries = 50; + int i; + u32 status; + + clrbits_le32(RWTM_HOST_INT_MASK, SP_CMD_COMPLETE); + + writel(cmd, RWTM_CMD); + + for (i = 0; i < tries; ++i) { + mdelay(10); + if (readl(RWTM_HOST_INT_RESET) & SP_CMD_COMPLETE) + break; + } + + if (i == tries) { + /* if timed out, don't read status */ + setbits_le32(RWTM_HOST_INT_RESET, SP_CMD_COMPLETE); + return -ETIMEDOUT; + } + + for (i = 0; i < nout; ++i) + out[i] = readl(RWTM_CMD_STATUS(i)); + status = readl(RWTM_CMD_RETSTATUS); + + setbits_le32(RWTM_HOST_INT_RESET, SP_CMD_COMPLETE); + + if (MBOX_STS_CMD(status) != cmd) + return -EIO; + else if (MBOX_STS_ERROR(status) == MBOX_STS_FAIL) + return -(int)MBOX_STS_VALUE(status); + else if (MBOX_STS_ERROR(status) != MBOX_STS_SUCCESS) + return -EIO; + else + return MBOX_STS_VALUE(status); +} diff --git a/arch/arm/mach-mvebu/include/mach/mbox.h b/arch/arm/mach-mvebu/include/mach/mbox.h new file mode 100644 index 000000000000..981204935832 --- /dev/null +++ b/arch/arm/mach-mvebu/include/mach/mbox.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2018 Marek Behun marek.behun@nic.cz + */ + +#ifndef _MVEBU_MBOX_H +#define _MVEBU_MBOX_H + +enum mbox_cmd { + MBOX_CMD_GET_RANDOM = 1, + MBOX_CMD_BOARD_INFO, + MBOX_CMD_ECDSA_PUB_KEY, + MBOX_CMD_HASH, + MBOX_CMD_SIGN, + MBOX_CMD_VERIFY, + + MBOX_CMD_OTP_READ, + MBOX_CMD_OTP_WRITE, +}; + +int mbox_do_cmd(enum mbox_cmd cmd, u32 *in, int nout); + +#endif diff --git a/board/CZ.NIC/turris_mox/mox_sp.c b/board/CZ.NIC/turris_mox/mox_sp.c index cc57b9f095f7..4de067bbebbb 100644 --- a/board/CZ.NIC/turris_mox/mox_sp.c +++ b/board/CZ.NIC/turris_mox/mox_sp.c @@ -8,74 +8,7 @@ #include <asm/io.h> #include <linux/bitops.h> #include <linux/delay.h> - -#define RWTM_BASE (MVEBU_REGISTER(0xb0000)) -#define RWTM_CMD_PARAM(i) (size_t)(RWTM_BASE + (i) * 4) -#define RWTM_CMD (RWTM_BASE + 0x40) -#define RWTM_CMD_RETSTATUS (RWTM_BASE + 0x80) -#define RWTM_CMD_STATUS(i) (size_t)(RWTM_BASE + 0x84 + (i) * 4) - -#define RWTM_HOST_INT_RESET (RWTM_BASE + 0xc8) -#define RWTM_HOST_INT_MASK (RWTM_BASE + 0xcc) -#define SP_CMD_COMPLETE BIT(0) - -#define MBOX_STS_SUCCESS (0x0 << 30) -#define MBOX_STS_FAIL (0x1 << 30) -#define MBOX_STS_BADCMD (0x2 << 30) -#define MBOX_STS_LATER (0x3 << 30) -#define MBOX_STS_ERROR(s) ((s) & (3 << 30)) -#define MBOX_STS_VALUE(s) (((s) >> 10) & 0xfffff) -#define MBOX_STS_CMD(s) ((s) & 0x3ff) - -enum mbox_cmd { - MBOX_CMD_GET_RANDOM = 1, - MBOX_CMD_BOARD_INFO, - MBOX_CMD_ECDSA_PUB_KEY, - MBOX_CMD_HASH, - MBOX_CMD_SIGN, - MBOX_CMD_VERIFY, - - MBOX_CMD_OTP_READ, - MBOX_CMD_OTP_WRITE -}; - -static int mbox_do_cmd(enum mbox_cmd cmd, u32 *out, int nout) -{ - const int tries = 50; - int i; - u32 status; - - clrbits_le32(RWTM_HOST_INT_MASK, SP_CMD_COMPLETE); - - writel(cmd, RWTM_CMD); - - for (i = 0; i < tries; ++i) { - mdelay(10); - if (readl(RWTM_HOST_INT_RESET) & SP_CMD_COMPLETE) - break; - } - - if (i == tries) { - /* if timed out, don't read status */ - setbits_le32(RWTM_HOST_INT_RESET, SP_CMD_COMPLETE); - return -ETIMEDOUT; - } - - for (i = 0; i < nout; ++i) - out[i] = readl(RWTM_CMD_STATUS(i)); - status = readl(RWTM_CMD_RETSTATUS); - - setbits_le32(RWTM_HOST_INT_RESET, SP_CMD_COMPLETE); - - if (MBOX_STS_CMD(status) != cmd) - return -EIO; - else if (MBOX_STS_ERROR(status) == MBOX_STS_FAIL) - return -(int)MBOX_STS_VALUE(status); - else if (MBOX_STS_ERROR(status) != MBOX_STS_SUCCESS) - return -EIO; - else - return MBOX_STS_VALUE(status); -} +#include <mach/mbox.h>
const char *mox_sp_get_ecdsa_public_key(void) {

Allow to specify input parameters, define all available mbox commands supported by CZ.NIC's secure firmware and also Marvell's fuse.bin firmware and fix parsing response from Marvell OTP commands.
Signed-off-by: Pali Rohár pali@kernel.org Reviewed-by: Marek Behún marek.behun@nic.cz Reviewed-by: Stefan Roese sr@denx.de --- arch/arm/mach-mvebu/armada3700/mbox.c | 20 ++++++++++++++++++-- arch/arm/mach-mvebu/include/mach/mbox.h | 19 ++++++++++++++++++- board/CZ.NIC/turris_mox/mox_sp.c | 4 ++-- 3 files changed, 38 insertions(+), 5 deletions(-)
diff --git a/arch/arm/mach-mvebu/armada3700/mbox.c b/arch/arm/mach-mvebu/armada3700/mbox.c index cb86b967c2eb..eb1f82845f0f 100644 --- a/arch/arm/mach-mvebu/armada3700/mbox.c +++ b/arch/arm/mach-mvebu/armada3700/mbox.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Marek Behun marek.behun@nic.cz + * Copyright (C) 2021 Pali Rohár pali@kernel.org */
#include <common.h> @@ -15,6 +16,7 @@ #define RWTM_CMD (RWTM_BASE + 0x40) #define RWTM_CMD_RETSTATUS (RWTM_BASE + 0x80) #define RWTM_CMD_STATUS(i) (size_t)(RWTM_BASE + 0x84 + (i) * 4) +#define MAX_ARGS 16
#define RWTM_HOST_INT_RESET (RWTM_BASE + 0xc8) #define RWTM_HOST_INT_MASK (RWTM_BASE + 0xcc) @@ -27,15 +29,27 @@ #define MBOX_STS_ERROR(s) ((s) & (3 << 30)) #define MBOX_STS_VALUE(s) (((s) >> 10) & 0xfffff) #define MBOX_STS_CMD(s) ((s) & 0x3ff) +#define MBOX_STS_MARVELL_ERROR(s) ((s) == 0 ? 0 : \ + (s) == 2 ? ETIMEDOUT : \ + (s) == 3 ? EINVAL : \ + (s) == 4 ? ENOSYS : \ + EIO)
-int mbox_do_cmd(enum mbox_cmd cmd, u32 *out, int nout) +int mbox_do_cmd(enum mbox_cmd cmd, u32 *in, int nin, u32 *out, int nout) { const int tries = 50; int i; u32 status;
+ if (nin > MAX_ARGS || nout > MAX_ARGS) + return -EINVAL; + clrbits_le32(RWTM_HOST_INT_MASK, SP_CMD_COMPLETE);
+ for (i = 0; i < nin; i++) + writel(in[i], RWTM_CMD_PARAM(i)); + for (; i < MAX_ARGS; i++) + writel(0x0, RWTM_CMD_PARAM(i)); writel(cmd, RWTM_CMD);
for (i = 0; i < tries; ++i) { @@ -57,9 +71,11 @@ int mbox_do_cmd(enum mbox_cmd cmd, u32 *out, int nout) setbits_le32(RWTM_HOST_INT_RESET, SP_CMD_COMPLETE);
if (MBOX_STS_CMD(status) != cmd) - return -EIO; + return -MBOX_STS_MARVELL_ERROR(status); else if (MBOX_STS_ERROR(status) == MBOX_STS_FAIL) return -(int)MBOX_STS_VALUE(status); + else if (MBOX_STS_ERROR(status) == MBOX_STS_BADCMD) + return -ENOSYS; else if (MBOX_STS_ERROR(status) != MBOX_STS_SUCCESS) return -EIO; else diff --git a/arch/arm/mach-mvebu/include/mach/mbox.h b/arch/arm/mach-mvebu/include/mach/mbox.h index 981204935832..f1cb55f2bfe7 100644 --- a/arch/arm/mach-mvebu/include/mach/mbox.h +++ b/arch/arm/mach-mvebu/include/mach/mbox.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0+ */ /* * Copyright (C) 2018 Marek Behun marek.behun@nic.cz + * Copyright (C) 2021 Pali Rohár pali@kernel.org */
#ifndef _MVEBU_MBOX_H @@ -16,8 +17,24 @@ enum mbox_cmd {
MBOX_CMD_OTP_READ, MBOX_CMD_OTP_WRITE, + + MBOX_CMD_REBOOT, + + /* OTP read commands supported by Marvell fuse.bin firmware */ + MBOX_CMD_OTP_READ_1B = 257, + MBOX_CMD_OTP_READ_8B, + MBOX_CMD_OTP_READ_32B, + MBOX_CMD_OTP_READ_64B, + MBOX_CMD_OTP_READ_256B, + + /* OTP write commands supported by Marvell fuse.bin firmware */ + MBOX_CMD_OTP_WRITE_1B = 513, + MBOX_CMD_OTP_WRITE_8B, + MBOX_CMD_OTP_WRITE_32B, + MBOX_CMD_OTP_WRITE_64B, + MBOX_CMD_OTP_WRITE_256B, };
-int mbox_do_cmd(enum mbox_cmd cmd, u32 *in, int nout); +int mbox_do_cmd(enum mbox_cmd cmd, u32 *in, int nin, u32 *out, int nout);
#endif diff --git a/board/CZ.NIC/turris_mox/mox_sp.c b/board/CZ.NIC/turris_mox/mox_sp.c index 4de067bbebbb..93e96b014fca 100644 --- a/board/CZ.NIC/turris_mox/mox_sp.c +++ b/board/CZ.NIC/turris_mox/mox_sp.c @@ -19,7 +19,7 @@ const char *mox_sp_get_ecdsa_public_key(void) if (public_key[0]) return public_key;
- res = mbox_do_cmd(MBOX_CMD_ECDSA_PUB_KEY, out, 16); + res = mbox_do_cmd(MBOX_CMD_ECDSA_PUB_KEY, NULL, 0, out, 16); if (res < 0) return NULL;
@@ -47,7 +47,7 @@ int mbox_sp_get_board_info(u64 *sn, u8 *mac1, u8 *mac2, int *bv, int *ram) u32 out[8]; int res;
- res = mbox_do_cmd(MBOX_CMD_BOARD_INFO, out, 8); + res = mbox_do_cmd(MBOX_CMD_BOARD_INFO, NULL, 0, out, 8); if (res < 0) return res;

It is not possible for the A53 core (on which U-Boot is running) to read it directly. For this purpose Marvell defined mbox API for sending OTP commands between CM3 and A53 cores.
Implement these Marvell fuse reading mbox commands via U-Boot fuse API.
Banks 0-43 are used for accessing Security OTP (44 rows with 67 bits via 44 banks and words 0-2).
Note that of the 67 bits, the 3 upper bits are: 1 lock bit and 2 auxiliary bits (meant for testing during the manufacture of the SOC, as I understand it).
Also note that the lock bit and the auxiliary bits are not readable via Marvell commands.
With CZ.NIC's commands the lock bit is readable.
Write support is not implemented yet.
Signed-off-by: Pali Rohár pali@kernel.org Reviewed-by: Marek Behún marek.behun@nic.cz Reviewed-by: Stefan Roese sr@denx.de --- arch/arm/mach-mvebu/armada3700/efuse.c | 39 ++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-)
diff --git a/arch/arm/mach-mvebu/armada3700/efuse.c b/arch/arm/mach-mvebu/armada3700/efuse.c index 03778f17ea49..50c73f36c565 100644 --- a/arch/arm/mach-mvebu/armada3700/efuse.c +++ b/arch/arm/mach-mvebu/armada3700/efuse.c @@ -8,6 +8,7 @@ #include <common.h> #include <asm/io.h> #include <linux/delay.h> +#include <mach/mbox.h> #include <mach/soc.h>
#define OTP_NB_REG_BASE ((void __iomem *)MVEBU_REGISTER(0x12600)) @@ -77,6 +78,41 @@ static void otp_read_parallel(void __iomem *base, u32 *data, u32 count) } }
+static int rwtm_otp_read(u8 row, u32 word, u32 *data) +{ + u32 out[3]; + u32 in[2]; + int res = -EINVAL; + + if (word < 2) { + /* + * MBOX_CMD_OTP_READ_32B command is supported by Marvell + * fuse.bin firmware and also by new CZ.NIC wtmi firmware. + * This command returns raw bits without ECC corrections. + * It does not provide access to the lock bit. + */ + in[0] = row; + in[1] = word * 32; + res = mbox_do_cmd(MBOX_CMD_OTP_READ_32B, in, 2, out, 1); + if (!res) + *data = out[0]; + } else if (word == 2) { + /* + * MBOX_CMD_OTP_READ command is supported only by new CZ.NIC + * wtmi firmware and provides access to all bits, including + * lock bit without doing ECC corrections. For compatibility + * with Marvell fuse.bin firmware, use this command only for + * accessing lock bit. + */ + in[0] = row; + res = mbox_do_cmd(MBOX_CMD_OTP_READ, in, 1, out, 3); + if (!res) + *data = out[2]; + } + + return res; +} + /* * Banks 0-43 are used for accessing Security OTP (44 rows with 67 bits via 44 banks and words 0-2) * Bank 44 is used for accessing North Bridge OTP (69 bits via words 0-2) @@ -96,8 +132,7 @@ int fuse_read(u32 bank, u32 word, u32 *val) if (bank <= RWTM_MAX_BANK) { if (word >= RWTM_ROW_WORDS) return -EINVAL; - /* TODO: not implemented yet */ - return -ENOSYS; + return rwtm_otp_read(bank, word, val); } else if (bank == OTP_NB_BANK) { u32 data[OTP_NB_WORDS]; if (word >= OTP_NB_WORDS)

Hello! Is v3 series Ok now?
On Wednesday 23 February 2022 14:15:44 Pali Rohár wrote:
Add support for reading NB fuse OTP, SB fuse OTP and Security OTP values via U-Boot fuse API on Armada 37xx boards.
Changes in v3:
- Updated comment in patch 5/5 about MBOX_CMD_OTP_READ command
- In patch 5/5 fixed number of output arguments for MBOX_CMD_OTP_READ_32B command
Pali Rohár (5): arm: mvebu: a37xx: Add support for reading NB and SB fuse OTP value arm: mvebu: a37xx: Enable fuse command on all Armada 3720 boards arm: mvebu: a37xx: Move generic mbox code to arch/arm/mach-mvebu arm: mvebu: a37xx: Extend mbox_do_cmd() code arm: mvebu: a37xx: Add support for reading Security OTP values
arch/arm/mach-mvebu/Kconfig | 1 + arch/arm/mach-mvebu/Makefile | 3 + arch/arm/mach-mvebu/armada3700/Makefile | 3 +- arch/arm/mach-mvebu/armada3700/efuse.c | 171 ++++++++++++++++++++ arch/arm/mach-mvebu/armada3700/mbox.c | 83 ++++++++++ arch/arm/mach-mvebu/include/mach/mbox.h | 40 +++++ board/CZ.NIC/turris_mox/mox_sp.c | 73 +-------- configs/mvebu_db-88f3720_defconfig | 2 + configs/mvebu_espressobin-88f3720_defconfig | 2 + configs/turris_mox_defconfig | 2 + configs/uDPU_defconfig | 2 + 11 files changed, 311 insertions(+), 71 deletions(-) create mode 100644 arch/arm/mach-mvebu/armada3700/efuse.c create mode 100644 arch/arm/mach-mvebu/armada3700/mbox.c create mode 100644 arch/arm/mach-mvebu/include/mach/mbox.h
-- 2.20.1

On 3/8/22 12:42, Pali Rohár wrote:
Hello! Is v3 series Ok now?
I don't have any objections. I plan to pull this patch series in the next merge window, as we are at rc3 now already.
Thanks, Stefan
On Wednesday 23 February 2022 14:15:44 Pali Rohár wrote:
Add support for reading NB fuse OTP, SB fuse OTP and Security OTP values via U-Boot fuse API on Armada 37xx boards.
Changes in v3:
- Updated comment in patch 5/5 about MBOX_CMD_OTP_READ command
- In patch 5/5 fixed number of output arguments for MBOX_CMD_OTP_READ_32B command
Pali Rohár (5): arm: mvebu: a37xx: Add support for reading NB and SB fuse OTP value arm: mvebu: a37xx: Enable fuse command on all Armada 3720 boards arm: mvebu: a37xx: Move generic mbox code to arch/arm/mach-mvebu arm: mvebu: a37xx: Extend mbox_do_cmd() code arm: mvebu: a37xx: Add support for reading Security OTP values
arch/arm/mach-mvebu/Kconfig | 1 + arch/arm/mach-mvebu/Makefile | 3 + arch/arm/mach-mvebu/armada3700/Makefile | 3 +- arch/arm/mach-mvebu/armada3700/efuse.c | 171 ++++++++++++++++++++ arch/arm/mach-mvebu/armada3700/mbox.c | 83 ++++++++++ arch/arm/mach-mvebu/include/mach/mbox.h | 40 +++++ board/CZ.NIC/turris_mox/mox_sp.c | 73 +-------- configs/mvebu_db-88f3720_defconfig | 2 + configs/mvebu_espressobin-88f3720_defconfig | 2 + configs/turris_mox_defconfig | 2 + configs/uDPU_defconfig | 2 + 11 files changed, 311 insertions(+), 71 deletions(-) create mode 100644 arch/arm/mach-mvebu/armada3700/efuse.c create mode 100644 arch/arm/mach-mvebu/armada3700/mbox.c create mode 100644 arch/arm/mach-mvebu/include/mach/mbox.h
-- 2.20.1
Viele Grüße, Stefan Roese

On Tuesday 08 March 2022 12:57:37 Stefan Roese wrote:
On 3/8/22 12:42, Pali Rohár wrote:
Hello! Is v3 series Ok now?
I don't have any objections. I plan to pull this patch series in the next merge window, as we are at rc3 now already.
PING?
Thanks, Stefan
On Wednesday 23 February 2022 14:15:44 Pali Rohár wrote:
Add support for reading NB fuse OTP, SB fuse OTP and Security OTP values via U-Boot fuse API on Armada 37xx boards.
Changes in v3:
- Updated comment in patch 5/5 about MBOX_CMD_OTP_READ command
- In patch 5/5 fixed number of output arguments for MBOX_CMD_OTP_READ_32B command
Pali Rohár (5): arm: mvebu: a37xx: Add support for reading NB and SB fuse OTP value arm: mvebu: a37xx: Enable fuse command on all Armada 3720 boards arm: mvebu: a37xx: Move generic mbox code to arch/arm/mach-mvebu arm: mvebu: a37xx: Extend mbox_do_cmd() code arm: mvebu: a37xx: Add support for reading Security OTP values
arch/arm/mach-mvebu/Kconfig | 1 + arch/arm/mach-mvebu/Makefile | 3 + arch/arm/mach-mvebu/armada3700/Makefile | 3 +- arch/arm/mach-mvebu/armada3700/efuse.c | 171 ++++++++++++++++++++ arch/arm/mach-mvebu/armada3700/mbox.c | 83 ++++++++++ arch/arm/mach-mvebu/include/mach/mbox.h | 40 +++++ board/CZ.NIC/turris_mox/mox_sp.c | 73 +-------- configs/mvebu_db-88f3720_defconfig | 2 + configs/mvebu_espressobin-88f3720_defconfig | 2 + configs/turris_mox_defconfig | 2 + configs/uDPU_defconfig | 2 + 11 files changed, 311 insertions(+), 71 deletions(-) create mode 100644 arch/arm/mach-mvebu/armada3700/efuse.c create mode 100644 arch/arm/mach-mvebu/armada3700/mbox.c create mode 100644 arch/arm/mach-mvebu/include/mach/mbox.h
-- 2.20.1
Viele Grüße, Stefan Roese
-- DENX Software Engineering GmbH, Managing Director: Wolfgang Denk HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-51 Fax: (+49)-8142-66989-80 Email: sr@denx.de

On 4/20/22 20:22, Pali Rohár wrote:
On Tuesday 08 March 2022 12:57:37 Stefan Roese wrote:
On 3/8/22 12:42, Pali Rohár wrote:
Hello! Is v3 series Ok now?
I don't have any objections. I plan to pull this patch series in the next merge window, as we are at rc3 now already.
PING?
Yes, I know. Sorry, just back from vacation and business trip. I'll try to handle the patch backlog today and/or tomorrow. ;)
Thanks, Stefan
Thanks, Stefan
On Wednesday 23 February 2022 14:15:44 Pali Rohár wrote:
Add support for reading NB fuse OTP, SB fuse OTP and Security OTP values via U-Boot fuse API on Armada 37xx boards.
Changes in v3:
- Updated comment in patch 5/5 about MBOX_CMD_OTP_READ command
- In patch 5/5 fixed number of output arguments for MBOX_CMD_OTP_READ_32B command
Pali Rohár (5): arm: mvebu: a37xx: Add support for reading NB and SB fuse OTP value arm: mvebu: a37xx: Enable fuse command on all Armada 3720 boards arm: mvebu: a37xx: Move generic mbox code to arch/arm/mach-mvebu arm: mvebu: a37xx: Extend mbox_do_cmd() code arm: mvebu: a37xx: Add support for reading Security OTP values
arch/arm/mach-mvebu/Kconfig | 1 + arch/arm/mach-mvebu/Makefile | 3 + arch/arm/mach-mvebu/armada3700/Makefile | 3 +- arch/arm/mach-mvebu/armada3700/efuse.c | 171 ++++++++++++++++++++ arch/arm/mach-mvebu/armada3700/mbox.c | 83 ++++++++++ arch/arm/mach-mvebu/include/mach/mbox.h | 40 +++++ board/CZ.NIC/turris_mox/mox_sp.c | 73 +-------- configs/mvebu_db-88f3720_defconfig | 2 + configs/mvebu_espressobin-88f3720_defconfig | 2 + configs/turris_mox_defconfig | 2 + configs/uDPU_defconfig | 2 + 11 files changed, 311 insertions(+), 71 deletions(-) create mode 100644 arch/arm/mach-mvebu/armada3700/efuse.c create mode 100644 arch/arm/mach-mvebu/armada3700/mbox.c create mode 100644 arch/arm/mach-mvebu/include/mach/mbox.h
-- 2.20.1
Viele Grüße, Stefan Roese
-- DENX Software Engineering GmbH, Managing Director: Wolfgang Denk HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-51 Fax: (+49)-8142-66989-80 Email: sr@denx.de
Viele Grüße, Stefan Roese

On 2/23/22 14:15, Pali Rohár wrote:
Add support for reading NB fuse OTP, SB fuse OTP and Security OTP values via U-Boot fuse API on Armada 37xx boards.
Changes in v3:
- Updated comment in patch 5/5 about MBOX_CMD_OTP_READ command
- In patch 5/5 fixed number of output arguments for MBOX_CMD_OTP_READ_32B command
Pali Rohár (5): arm: mvebu: a37xx: Add support for reading NB and SB fuse OTP value arm: mvebu: a37xx: Enable fuse command on all Armada 3720 boards arm: mvebu: a37xx: Move generic mbox code to arch/arm/mach-mvebu arm: mvebu: a37xx: Extend mbox_do_cmd() code arm: mvebu: a37xx: Add support for reading Security OTP values
arch/arm/mach-mvebu/Kconfig | 1 + arch/arm/mach-mvebu/Makefile | 3 + arch/arm/mach-mvebu/armada3700/Makefile | 3 +- arch/arm/mach-mvebu/armada3700/efuse.c | 171 ++++++++++++++++++++ arch/arm/mach-mvebu/armada3700/mbox.c | 83 ++++++++++ arch/arm/mach-mvebu/include/mach/mbox.h | 40 +++++ board/CZ.NIC/turris_mox/mox_sp.c | 73 +-------- configs/mvebu_db-88f3720_defconfig | 2 + configs/mvebu_espressobin-88f3720_defconfig | 2 + configs/turris_mox_defconfig | 2 + configs/uDPU_defconfig | 2 + 11 files changed, 311 insertions(+), 71 deletions(-) create mode 100644 arch/arm/mach-mvebu/armada3700/efuse.c create mode 100644 arch/arm/mach-mvebu/armada3700/mbox.c create mode 100644 arch/arm/mach-mvebu/include/mach/mbox.h
Applied to u-boot-marvell/master
Thanks, Stefan
participants (3)
-
Marek Behún
-
Pali Rohár
-
Stefan Roese