1 /* SPDX-License-Identifier: GPL-2.0-only */
4 #include <device/mmio.h>
5 #include <console/console.h>
6 #include <console/uart.h>
7 #include <soc/addressmap.h>
11 * This is a driver for the eMemory EG004K32TQ028XW01 NeoFuse
12 * One-Time-Programmable (OTP) memory used within the SiFive FU740.
13 * It is documented in the FU740 manual here:
14 * https://www.sifive.com/documentation/chips/freedom-u740-c000-manual/
17 struct sifive_otp_registers
{
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) */
36 * Read a 32 bit value addressed by its index from the OTP.
37 * The FU740 stores 4096x32 bit (16KiB) values.
38 * Index 0x00-0xff are reserved for SiFive internal use. (first 1KiB)
41 u32
otp_read_word(u16 idx
)
46 die("otp: idx out of bounds");
48 struct sifive_otp_registers
*regs
= (void *)(FU740_OTP
);
50 // wake up from stand-by
51 write32(®s
->pdstb
, 0x01);
53 // enable repair function
54 write32(®s
->ptrim
, 0x01);
57 write32(®s
->pce
, 0x01);
60 write32(®s
->pa
, idx
);
62 // cycle clock to read
63 write32(®s
->pclk
, 0x01);
66 write32(®s
->pclk
, 0x00);
69 w
= read32(®s
->pdout
);
72 write32(®s
->pce
, 0x00);
73 write32(®s
->ptrim
, 0x00);
74 write32(®s
->pdstb
, 0x00);
79 u32
otp_read_serial(void)
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
)