[PATCH] arm: mvebu: Add support for reading LD0 and LD1 eFuse

Armada 385 contains 64 lines of HD eFuse and 2 lines of LD eFuse. HD eFuse is used for secure boot and each line is 64 bits long + 1 lock bit. LD eFuse lines are 256 bits long + 1 lock bit. LD 0 line is reserved for Marvell Internal Use and LD 1 line is for General Purpose Data. U-Boot already contains HD eFuse reading and programming support.
This patch implements LD eFuse reading support. LD 0 line is mapped to U-Boot fuse bank 64 and LD 1 line to fuse bank 65.
LD 0 Marvell Internal Use line seems that was burned in factory with some data and can be read by U-Boot fuse command:
=> fuse read 64 0 9
LD 1 General Purpose Data line is by default empty and can be read by U-Boot fuse command:
=> fuse read 65 0 9
Signed-off-by: Pali Rohár pali@kernel.org --- arch/arm/mach-mvebu/efuse.c | 28 ++++++++++++++++++++++++ arch/arm/mach-mvebu/include/mach/efuse.h | 5 +++++ 2 files changed, 33 insertions(+)
diff --git a/arch/arm/mach-mvebu/efuse.c b/arch/arm/mach-mvebu/efuse.c index c79eee98fe98..80318c339eb7 100644 --- a/arch/arm/mach-mvebu/efuse.c +++ b/arch/arm/mach-mvebu/efuse.c @@ -27,6 +27,7 @@
enum { MVEBU_EFUSE_CTRL_PROGRAM_ENABLE = (1 << 31), + MVEBU_EFUSE_LD1_SELECT = (1 << 6), };
struct mvebu_hd_efuse { @@ -39,8 +40,10 @@ struct mvebu_hd_efuse { #ifndef DRY_RUN static struct mvebu_hd_efuse *efuses = (struct mvebu_hd_efuse *)(MBUS_EFUSE_BASE + 0xF9000); +static u32 *ld_efuses = (void *)MBUS_EFUSE_BASE + 0xF8F00; #else static struct mvebu_hd_efuse efuses[EFUSE_LINE_MAX + 1]; +static u32 ld_efuses[EFUSE_LD_WORDS]; #endif
static int efuse_initialised; @@ -169,6 +172,21 @@ int mvebu_read_efuse(int nr, struct efuse_val *val) return 0; }
+void mvebu_read_ld_efuse(int ld1, u32 *line) +{ + int i; + +#ifndef DRY_RUN + if (ld1) + setbits_le32(MVEBU_EFUSE_CONTROL, MVEBU_EFUSE_LD1_SELECT); + else + clrbits_le32(MVEBU_EFUSE_CONTROL, MVEBU_EFUSE_LD1_SELECT); +#endif + + for (i = 0; i < EFUSE_LD_WORDS; i++) + line[i] = readl(ld_efuses + i); +} + int mvebu_write_efuse(int nr, struct efuse_val *val) { return prog_efuse(nr, val, ~0, ~0); @@ -199,8 +217,18 @@ static int valid_prog_words; int fuse_read(u32 bank, u32 word, u32 *val) { struct efuse_val fuse_line; + u32 ld_line[EFUSE_LD_WORDS]; int res;
+ if ((bank == EFUSE_LD0_LINE || bank == EFUSE_LD1_LINE) && word < EFUSE_LD_WORDS) { + res = mvebu_efuse_init_hw(); + if (res) + return res; + mvebu_read_ld_efuse(bank == EFUSE_LD1_LINE, ld_line); + *val = ld_line[word]; + return 0; + } + if (bank < EFUSE_LINE_MIN || bank > EFUSE_LINE_MAX || word > 2) return -EINVAL;
diff --git a/arch/arm/mach-mvebu/include/mach/efuse.h b/arch/arm/mach-mvebu/include/mach/efuse.h index bbc5844d849c..122e735f2fc7 100644 --- a/arch/arm/mach-mvebu/include/mach/efuse.h +++ b/arch/arm/mach-mvebu/include/mach/efuse.h @@ -53,8 +53,13 @@ enum efuse_line {
EFUSE_LINE_MIN = 0, EFUSE_LINE_MAX = 63, + + EFUSE_LD0_LINE = 64, + EFUSE_LD1_LINE = 65, };
+#define EFUSE_LD_WORDS 9 + #endif
int mvebu_efuse_init_hw(void);

On Wed, 6 Apr 2022 14:18:18 +0200 Pali Rohár pali@kernel.org wrote:
Armada 385 contains 64 lines of HD eFuse and 2 lines of LD eFuse. HD eFuse is used for secure boot and each line is 64 bits long + 1 lock bit. LD eFuse lines are 256 bits long + 1 lock bit. LD 0 line is reserved for Marvell Internal Use and LD 1 line is for General Purpose Data. U-Boot already contains HD eFuse reading and programming support.
This patch implements LD eFuse reading support. LD 0 line is mapped to U-Boot fuse bank 64 and LD 1 line to fuse bank 65.
LD 0 Marvell Internal Use line seems that was burned in factory with some data and can be read by U-Boot fuse command:
=> fuse read 64 0 9
LD 1 General Purpose Data line is by default empty and can be read by U-Boot fuse command:
=> fuse read 65 0 9
Signed-off-by: Pali Rohár pali@kernel.org
I am not sure whether this can be used safely on Turris Omnia - there was some issue with voltage or something, I know for sure that burning does not work on Omnia, but I am not sure if the issue also prevents stable reading.
Are the values you read always the same? Even across power cycles?
Marek

On Wednesday 06 April 2022 21:21:59 Marek Behún wrote:
On Wed, 6 Apr 2022 14:18:18 +0200 Pali Rohár pali@kernel.org wrote:
Armada 385 contains 64 lines of HD eFuse and 2 lines of LD eFuse. HD eFuse is used for secure boot and each line is 64 bits long + 1 lock bit. LD eFuse lines are 256 bits long + 1 lock bit. LD 0 line is reserved for Marvell Internal Use and LD 1 line is for General Purpose Data. U-Boot already contains HD eFuse reading and programming support.
This patch implements LD eFuse reading support. LD 0 line is mapped to U-Boot fuse bank 64 and LD 1 line to fuse bank 65.
LD 0 Marvell Internal Use line seems that was burned in factory with some data and can be read by U-Boot fuse command:
=> fuse read 64 0 9
LD 1 General Purpose Data line is by default empty and can be read by U-Boot fuse command:
=> fuse read 65 0 9
Signed-off-by: Pali Rohár pali@kernel.org
I am not sure whether this can be used safely on Turris Omnia - there was some issue with voltage or something, I know for sure that burning does not work on Omnia, but I am not sure if the issue also prevents stable reading.
On A385 there is errata only for programming OTP bits.
Are the values you read always the same? Even across power cycles?
Marek
Reading is working fine and is stable also after power cycles. Marvell Internal Use contains data which are same after more reads.

On Thu, 7 Apr 2022 13:53:23 +0200 Pali Rohár pali@kernel.org wrote:
On Wednesday 06 April 2022 21:21:59 Marek Behún wrote:
On Wed, 6 Apr 2022 14:18:18 +0200 Pali Rohár pali@kernel.org wrote:
Armada 385 contains 64 lines of HD eFuse and 2 lines of LD eFuse. HD eFuse is used for secure boot and each line is 64 bits long + 1 lock bit. LD eFuse lines are 256 bits long + 1 lock bit. LD 0 line is reserved for Marvell Internal Use and LD 1 line is for General Purpose Data. U-Boot already contains HD eFuse reading and programming support.
This patch implements LD eFuse reading support. LD 0 line is mapped to U-Boot fuse bank 64 and LD 1 line to fuse bank 65.
LD 0 Marvell Internal Use line seems that was burned in factory with some data and can be read by U-Boot fuse command:
=> fuse read 64 0 9
LD 1 General Purpose Data line is by default empty and can be read by U-Boot fuse command:
=> fuse read 65 0 9
Signed-off-by: Pali Rohár pali@kernel.org
I am not sure whether this can be used safely on Turris Omnia - there was some issue with voltage or something, I know for sure that burning does not work on Omnia, but I am not sure if the issue also prevents stable reading.
On A385 there is errata only for programming OTP bits.
Are the values you read always the same? Even across power cycles?
Marek
Reading is working fine and is stable also after power cycles. Marvell Internal Use contains data which are same after more reads.
In that case Reviewed-by: Marek Behún marek.behun@nic.cz

On 4/6/22 14:18, Pali Rohár wrote:
Armada 385 contains 64 lines of HD eFuse and 2 lines of LD eFuse. HD eFuse is used for secure boot and each line is 64 bits long + 1 lock bit. LD eFuse lines are 256 bits long + 1 lock bit. LD 0 line is reserved for Marvell Internal Use and LD 1 line is for General Purpose Data. U-Boot already contains HD eFuse reading and programming support.
This patch implements LD eFuse reading support. LD 0 line is mapped to U-Boot fuse bank 64 and LD 1 line to fuse bank 65.
LD 0 Marvell Internal Use line seems that was burned in factory with some data and can be read by U-Boot fuse command:
=> fuse read 64 0 9
LD 1 General Purpose Data line is by default empty and can be read by U-Boot fuse command:
=> fuse read 65 0 9
Signed-off-by: Pali Rohár pali@kernel.org
Applied to u-boot-marvell/master
Thanks, Stefan
arch/arm/mach-mvebu/efuse.c | 28 ++++++++++++++++++++++++ arch/arm/mach-mvebu/include/mach/efuse.h | 5 +++++ 2 files changed, 33 insertions(+)
diff --git a/arch/arm/mach-mvebu/efuse.c b/arch/arm/mach-mvebu/efuse.c index c79eee98fe98..80318c339eb7 100644 --- a/arch/arm/mach-mvebu/efuse.c +++ b/arch/arm/mach-mvebu/efuse.c @@ -27,6 +27,7 @@
enum { MVEBU_EFUSE_CTRL_PROGRAM_ENABLE = (1 << 31),
MVEBU_EFUSE_LD1_SELECT = (1 << 6), };
struct mvebu_hd_efuse {
@@ -39,8 +40,10 @@ struct mvebu_hd_efuse { #ifndef DRY_RUN static struct mvebu_hd_efuse *efuses = (struct mvebu_hd_efuse *)(MBUS_EFUSE_BASE + 0xF9000); +static u32 *ld_efuses = (void *)MBUS_EFUSE_BASE + 0xF8F00; #else static struct mvebu_hd_efuse efuses[EFUSE_LINE_MAX + 1]; +static u32 ld_efuses[EFUSE_LD_WORDS]; #endif
static int efuse_initialised; @@ -169,6 +172,21 @@ int mvebu_read_efuse(int nr, struct efuse_val *val) return 0; }
+void mvebu_read_ld_efuse(int ld1, u32 *line) +{
- int i;
+#ifndef DRY_RUN
- if (ld1)
setbits_le32(MVEBU_EFUSE_CONTROL, MVEBU_EFUSE_LD1_SELECT);
- else
clrbits_le32(MVEBU_EFUSE_CONTROL, MVEBU_EFUSE_LD1_SELECT);
+#endif
- for (i = 0; i < EFUSE_LD_WORDS; i++)
line[i] = readl(ld_efuses + i);
+}
- int mvebu_write_efuse(int nr, struct efuse_val *val) { return prog_efuse(nr, val, ~0, ~0);
@@ -199,8 +217,18 @@ static int valid_prog_words; int fuse_read(u32 bank, u32 word, u32 *val) { struct efuse_val fuse_line;
u32 ld_line[EFUSE_LD_WORDS]; int res;
if ((bank == EFUSE_LD0_LINE || bank == EFUSE_LD1_LINE) && word < EFUSE_LD_WORDS) {
res = mvebu_efuse_init_hw();
if (res)
return res;
mvebu_read_ld_efuse(bank == EFUSE_LD1_LINE, ld_line);
*val = ld_line[word];
return 0;
}
if (bank < EFUSE_LINE_MIN || bank > EFUSE_LINE_MAX || word > 2) return -EINVAL;
diff --git a/arch/arm/mach-mvebu/include/mach/efuse.h b/arch/arm/mach-mvebu/include/mach/efuse.h index bbc5844d849c..122e735f2fc7 100644 --- a/arch/arm/mach-mvebu/include/mach/efuse.h +++ b/arch/arm/mach-mvebu/include/mach/efuse.h @@ -53,8 +53,13 @@ enum efuse_line {
EFUSE_LINE_MIN = 0, EFUSE_LINE_MAX = 63,
- EFUSE_LD0_LINE = 64,
- EFUSE_LD1_LINE = 65, };
+#define EFUSE_LD_WORDS 9
#endif
int mvebu_efuse_init_hw(void);
Viele Grüße, Stefan Roese
participants (3)
-
Marek Behún
-
Pali Rohár
-
Stefan Roese