soc/sifive/fu540: Add driver for OTP memory
Provides minimal functionality to read the SOC s/n from the NeoFuse one time programmable memory. Change-Id: I14b010ad9958931e0a98a76f76090fd7c66f19a0 Signed-off-by: Philipp Hug <philipp@hug.cx> Reviewed-on: https://review.coreboot.org/27435 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Jonathan Neuschäfer <j.neuschaefer@gmx.net>
This commit is contained in:
parent
3b8ef2b01d
commit
ea81928e94
|
@ -18,7 +18,7 @@ The following things are still missing from this coreboot port:
|
||||||
- Placing the ramstage in DRAM
|
- Placing the ramstage in DRAM
|
||||||
- Starting the U54 cores
|
- Starting the U54 cores
|
||||||
- FU540 PIN configuration and GPIO access macros
|
- FU540 PIN configuration and GPIO access macros
|
||||||
- FU540 OTP driver and serial number read-out
|
- Provide serial number to payload (e.g. in device tree)
|
||||||
- Support for booting Linux on RISC-V
|
- Support for booting Linux on RISC-V
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -21,11 +21,13 @@ bootblock-y += bootblock.c
|
||||||
romstage-y += uart.c
|
romstage-y += uart.c
|
||||||
romstage-y += media.c
|
romstage-y += media.c
|
||||||
romstage-y += sdram.c
|
romstage-y += sdram.c
|
||||||
|
romstage-y += otp.c
|
||||||
|
|
||||||
ramstage-y += uart.c
|
ramstage-y += uart.c
|
||||||
ramstage-y += media.c
|
ramstage-y += media.c
|
||||||
ramstage-y += sdram.c
|
ramstage-y += sdram.c
|
||||||
ramstage-y += cbmem.c
|
ramstage-y += cbmem.c
|
||||||
|
ramstage-y += otp.c
|
||||||
|
|
||||||
CPPFLAGS_common += -Isrc/soc/sifive/fu540/include
|
CPPFLAGS_common += -Isrc/soc/sifive/fu540/include
|
||||||
|
|
||||||
|
|
|
@ -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(u16 idx);
|
||||||
|
u32 otp_read_serial(void);
|
||||||
|
|
||||||
|
#endif /* __SOC_SIFIVE_HIFIFE_U_OTP_H__ */
|
|
@ -0,0 +1,105 @@
|
||||||
|
/*
|
||||||
|
* 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/console.h>
|
||||||
|
#include <console/uart.h>
|
||||||
|
#include <soc/addressmap.h>
|
||||||
|
#include <soc/otp.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is a driver for the eMemory EG004K32TQ028XW01 NeoFuse
|
||||||
|
* One-Time-Programmable (OTP) memory used within the SiFive FU540.
|
||||||
|
* It is documented in the FU540 manual here:
|
||||||
|
* 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 input */
|
||||||
|
u32 ptrim; /* Repair function enable input */
|
||||||
|
u32 pwe; /* Write enable input (defines program cycle) */
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read a 32 bit value addressed by its index from the OTP.
|
||||||
|
* The FU540 stores 4096x32 bit (16KiB) values.
|
||||||
|
* Index 0x00-0xff are reserved for SiFive internal use. (first 1KiB)
|
||||||
|
*/
|
||||||
|
|
||||||
|
u32 otp_read_word(u16 idx)
|
||||||
|
{
|
||||||
|
u32 w;
|
||||||
|
|
||||||
|
if (idx >= 0x1000)
|
||||||
|
die("otp: idx out of bounds");
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
// address 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);
|
||||||
|
|
||||||
|
// shut down
|
||||||
|
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;
|
||||||
|
}
|
Loading…
Reference in New Issue