
On Wed, Mar 11, 2020 at 3:03 PM Pragnesh Patel pragnesh.patel@sifive.com wrote:
Use the OTP DM driver to set the serial environment variable.
Signed-off-by: Pragnesh Patel pragnesh.patel@sifive.com
arch/riscv/dts/fu540-c000-u-boot.dtsi | 14 +++ .../dts/hifive-unleashed-a00-u-boot.dtsi | 6 + board/sifive/fu540/Kconfig | 2 + board/sifive/fu540/fu540.c | 113 +++++++----------- 4 files changed, 62 insertions(+), 73 deletions(-) create mode 100644 arch/riscv/dts/fu540-c000-u-boot.dtsi create mode 100644 arch/riscv/dts/hifive-unleashed-a00-u-boot.dtsi
diff --git a/arch/riscv/dts/fu540-c000-u-boot.dtsi b/arch/riscv/dts/fu540-c000-u-boot.dtsi new file mode 100644 index 0000000000..31fd113c7d --- /dev/null +++ b/arch/riscv/dts/fu540-c000-u-boot.dtsi @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- (C) Copyright 2019 SiFive, Inc
nits: 2020?
- */
+/ {
soc {
otp: otp@10070000 {
compatible = "sifive,fu540-otp";
reg = <0x0 0x10070000 0x0 0x0FFF>;
fuse-count = <0x1000>;
Add status = "disabled" here?
};
};
+}; diff --git a/arch/riscv/dts/hifive-unleashed-a00-u-boot.dtsi b/arch/riscv/dts/hifive-unleashed-a00-u-boot.dtsi new file mode 100644 index 0000000000..bec0d19134 --- /dev/null +++ b/arch/riscv/dts/hifive-unleashed-a00-u-boot.dtsi @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Copyright (C) 2019 SiFive, Inc
nits: 2020?
- */
+#include "fu540-c000-u-boot.dtsi"
Add
&otp { status = "okay"; }
here?
diff --git a/board/sifive/fu540/Kconfig b/board/sifive/fu540/Kconfig index 5ca21474de..900197bbb2 100644 --- a/board/sifive/fu540/Kconfig +++ b/board/sifive/fu540/Kconfig @@ -48,5 +48,7 @@ config BOARD_SPECIFIC_OPTIONS # dummy imply SIFIVE_GPIO imply CMD_GPIO imply SMP
imply MISC
imply SIFIVE_OTP
endif diff --git a/board/sifive/fu540/fu540.c b/board/sifive/fu540/fu540.c index 47a2090251..6c642b3082 100644 --- a/board/sifive/fu540/fu540.c +++ b/board/sifive/fu540/fu540.c @@ -10,94 +10,61 @@ #include <dm.h> #include <linux/delay.h> #include <linux/io.h> +#include <misc.h>
+/*
- This define is a value used for error/unknown serial.
- If we really care about distinguishing errors and 0 is
- valid, we'll need a different one.
- */
+#define ERROR_READING_SERIAL_NUMBER 0
#ifdef CONFIG_MISC_INIT_R
-#define FU540_OTP_BASE_ADDR 0x10070000
-struct fu540_otp_regs {
u32 pa; /* Address input */
u32 paio; /* Program address input */
u32 pas; /* Program redundancy cell selection input */
u32 pce; /* OTP Macro enable input */
u32 pclk; /* Clock input */
u32 pdin; /* Write data input */
u32 pdout; /* Read data output */
u32 pdstb; /* Deep standby mode enable input (active low) */
u32 pprog; /* Program mode enable input */
u32 ptc; /* Test column enable input */
u32 ptm; /* Test mode enable input */
u32 ptm_rep;/* Repair function test mode enable input */
u32 ptr; /* Test row enable input */
u32 ptrim; /* Repair function enable input */
u32 pwe; /* Write enable input (defines program cycle) */
-} __packed;
-#define BYTES_PER_FUSE 4 -#define NUM_FUSES 0x1000
-static int fu540_otp_read(int offset, void *buf, int size) +#if CONFIG_IS_ENABLED(SIFIVE_OTP) +static u32 otp_read_serialnum(struct udevice *dev) {
struct fu540_otp_regs *regs = (void __iomem *)FU540_OTP_BASE_ADDR;
unsigned int i;
int fuseidx = offset / BYTES_PER_FUSE;
int fusecount = size / BYTES_PER_FUSE;
u32 fusebuf[fusecount];
/* check bounds */
if (offset < 0 || size < 0)
return -EINVAL;
if (fuseidx >= NUM_FUSES)
return -EINVAL;
if ((fuseidx + fusecount) > NUM_FUSES)
return -EINVAL;
/* init OTP */
writel(0x01, ®s->pdstb); /* wake up from stand-by */
writel(0x01, ®s->ptrim); /* enable repair function */
writel(0x01, ®s->pce); /* enable input */
/* read all requested fuses */
for (i = 0; i < fusecount; i++, fuseidx++) {
writel(fuseidx, ®s->pa);
/* cycle clock to read */
writel(0x01, ®s->pclk);
mdelay(1);
writel(0x00, ®s->pclk);
mdelay(1);
/* read the value */
fusebuf[i] = readl(®s->pdout);
}
int ret;
u32 serial[2] = {0};
/* shut down */
writel(0, ®s->pce);
writel(0, ®s->ptrim);
writel(0, ®s->pdstb);
for (int i = 0xfe * 4; i > 0; i -= 8) {
ret = misc_read(dev, i, serial, sizeof(serial));
/* copy out */
memcpy(buf, fusebuf, size);
if (ret != sizeof(serial)) {
printf("%s: error reading serial from OTP\n", __func__);
break;
}
return 0;
if (serial[0] == ~serial[1])
return serial[0];
}
return ERROR_READING_SERIAL_NUMBER;
} +#endif
static u32 fu540_read_serialnum(void) {
u32 serial = ERROR_READING_SERIAL_NUMBER;
+#if CONFIG_IS_ENABLED(SIFIVE_OTP)
struct udevice *dev; int ret;
u32 serial[2] = {0};
for (int i = 0xfe * 4; i > 0; i -= 8) {
ret = fu540_otp_read(i, serial, sizeof(serial));
if (ret) {
printf("%s: error reading from OTP\n", __func__);
break;
}
if (serial[0] == ~serial[1])
return serial[0];
// init OTP
Use /* */ comment format
ret = uclass_get_device_by_driver(UCLASS_MISC,
DM_GET_DRIVER(sifive_otp), &dev);
if (ret) {
debug("%s: could not find otp device\n", __func__);
return serial; }
return 0;
// read serial from OTP and set env var
Use /* */ comment format
serial = otp_read_serialnum(dev);
+#endif
return serial;
}
static void fu540_setup_macaddr(u32 serialnum)
Regards, Bin