[PATCH u-boot-mvebu v2 1/5] arm: mvebu: a37xx: Add support for reading NB and SB fuse OTP value
Stefan Roese
sr at denx.de
Fri Feb 18 15:15:31 CET 2022
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 at kernel.org>
> Reviewed-by: Marek Behún <marek.behun at nic.cz>
Reviewed-by: Stefan Roese <sr at 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 at 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 at 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
--
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 at denx.de
More information about the U-Boot
mailing list