Philipp Hug has uploaded this change for review. ( https://review.coreboot.org/27435
Change subject: soc/sifive: driver for otp memory ......................................................................
soc/sifive: driver for otp memory
Provides minimal functionality to read the SOC s/n from the NeoFuse OTP memory.
Change-Id: I14b010ad9958931e0a98a76f76090fd7c66f19a0 Signed-off-by: Philipp Hug philipp@hug.cx --- M src/soc/sifive/fu540/Makefile.inc A src/soc/sifive/fu540/include/soc/otp.h A src/soc/sifive/fu540/otp.c 3 files changed, 118 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/35/27435/1
diff --git a/src/soc/sifive/fu540/Makefile.inc b/src/soc/sifive/fu540/Makefile.inc index 8a2f3a6..6a0355e 100644 --- a/src/soc/sifive/fu540/Makefile.inc +++ b/src/soc/sifive/fu540/Makefile.inc @@ -19,10 +19,12 @@
romstage-y += uart.c romstage-y += media.c +romstage-y += otp.c
ramstage-y += uart.c ramstage-y += media.c ramstage-y += cbmem.c +ramstage-y += otp.c
CPPFLAGS_common += -Isrc/soc/sifive/fu540/include
diff --git a/src/soc/sifive/fu540/include/soc/otp.h b/src/soc/sifive/fu540/include/soc/otp.h new file mode 100644 index 0000000..027d57f --- /dev/null +++ b/src/soc/sifive/fu540/include/soc/otp.h @@ -0,0 +1,22 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2018 Philipp Hug philipp@hug.cx + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __SOC_SIFIVE_HIFIVE_U_OTP_H__ +#define __SOC_SIFIVE_HIFIVE_U_OTP_H__ + +u32 otp_read_word(u8 idx); +u32 otp_read_serial(void); + +#endif /* __SOC_SIFIVE_HIFIFE_U_OTP_H__ */ diff --git a/src/soc/sifive/fu540/otp.c b/src/soc/sifive/fu540/otp.c new file mode 100644 index 0000000..2326ce2 --- /dev/null +++ b/src/soc/sifive/fu540/otp.c @@ -0,0 +1,94 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2018 Philipp Hug philipp@hug.cx + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <stddef.h> +#include <delay.h> +#include <arch/barrier.h> +#include <arch/io.h> +#include <console/uart.h> +#include <soc/addressmap.h> +#include <soc/otp.h> + +/* + * This is a driver for SiFive's one-time programmable memory, + * documented in the FU540 manual: + * https://www.sifive.com/documentation/chips/freedom-u540-c000-manual/ + */ + +typedef struct sifive_otp_registers { + 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 inpu */ + u32 ptrim; /* Repair function enable input */ + u32 pwe; /* Write enable input (defines program cycle) */ +} __packed; + +u32 otp_read_word(u8 idx) +{ + u32 w; + + struct sifive_otp_registers *regs = (void *)(FU540_OTP); + + // wake-up from stand-by + write32(®s->pdstb, 0x01); + + // enable repair function + write32(®s->ptrim, 0x01); + + // enable input + write32(®s->pce, 0x01); + + // adress to read + write32(®s->pa, idx); + + // cycle clock to read + write32(®s->pclk, 0x01); + mdelay(1); + + write32(®s->pclk, 0x00); + mdelay(1); + + w = read32(®s->pdout); + + // shutdown + write32(®s->pce, 0x00); + write32(®s->ptrim, 0x00); + write32(®s->pdstb, 0x00); + + return w; +} + +u32 otp_read_serial(void) +{ + u32 serial = 0; + u32 serial_n = 0; + for (int i = 0xfe; i > 0; i -= 2) { + serial = otp_read_word(i); + serial_n = otp_read_word(i+1); + if (serial == ~serial_n) + break; + } + return serial; +}