coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
otp.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <delay.h>
4 #include <device/mmio.h>
5 #include <console/console.h>
6 #include <console/uart.h>
7 #include <soc/addressmap.h>
8 #include <soc/otp.h>
9 
10 /*
11  * This is a driver for the eMemory EG004K32TQ028XW01 NeoFuse
12  * One-Time-Programmable (OTP) memory used within the SiFive FU540.
13  * It is documented in the FU540 manual here:
14  * https://www.sifive.com/documentation/chips/freedom-u540-c000-manual/
15  */
16 
18  u32 pa; /* Address input */
19  u32 paio; /* Program address input */
20  u32 pas; /* Program redundancy cell selection input */
21  u32 pce; /* OTP Macro enable input */
22  u32 pclk; /* Clock input */
23  u32 pdin; /* Write data input */
24  u32 pdout; /* Read data output */
25  u32 pdstb; /* Deep standby mode enable input (active low) */
26  u32 pprog; /* Program mode enable input */
27  u32 ptc; /* Test column enable input */
28  u32 ptm; /* Test mode enable input */
29  u32 ptm_rep;/* Repair function test mode enable input */
30  u32 ptr; /* Test row enable input */
31  u32 ptrim; /* Repair function enable input */
32  u32 pwe; /* Write enable input (defines program cycle) */
34 
35 /*
36  * Read a 32 bit value addressed by its index from the OTP.
37  * The FU540 stores 4096x32 bit (16KiB) values.
38  * Index 0x00-0xff are reserved for SiFive internal use. (first 1KiB)
39  */
40 
42 {
43  u32 w;
44 
45  if (idx >= 0x1000)
46  die("otp: idx out of bounds");
47 
48  struct sifive_otp_registers *regs = (void *)(FU540_OTP);
49 
50  // wake up from stand-by
51  write32(&regs->pdstb, 0x01);
52 
53  // enable repair function
54  write32(&regs->ptrim, 0x01);
55 
56  // enable input
57  write32(&regs->pce, 0x01);
58 
59  // address to read
60  write32(&regs->pa, idx);
61 
62  // cycle clock to read
63  write32(&regs->pclk, 0x01);
64  mdelay(1);
65 
66  write32(&regs->pclk, 0x00);
67  mdelay(1);
68 
69  w = read32(&regs->pdout);
70 
71  // shut down
72  write32(&regs->pce, 0x00);
73  write32(&regs->ptrim, 0x00);
74  write32(&regs->pdstb, 0x00);
75 
76  return w;
77 }
78 
80 {
81  u32 serial = 0;
82  u32 serial_n = 0;
83  for (int i = 0xfe; i > 0; i -= 2) {
84  serial = otp_read_word(i);
85  serial_n = otp_read_word(i+1);
86  if (serial == ~serial_n)
87  break;
88  }
89  return serial;
90 }
static void write32(void *addr, uint32_t val)
Definition: mmio.h:40
static uint32_t read32(const void *addr)
Definition: mmio.h:22
void __noreturn die(const char *fmt,...)
Definition: die.c:17
void mdelay(unsigned int msecs)
Definition: delay.c:2
unsigned int serial
Definition: edid.c:52
u32 otp_read_serial(void)
Definition: otp.c:79
struct sifive_otp_registers __packed
u32 otp_read_word(u16 idx)
Definition: otp.c:41
#define FU540_OTP
Definition: addressmap.h:14
uint32_t u32
Definition: stdint.h:51
uint16_t u16
Definition: stdint.h:48