• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 FU740.
13  * It is documented in the FU740 manual here:
14  * https://www.sifive.com/documentation/chips/freedom-u740-c000-manual/
15  */
16 
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) */
33 } __packed;
34 
35 /*
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)
39  */
40 
otp_read_word(u16 idx)41 u32 otp_read_word(u16 idx)
42 {
43 	u32 w;
44 
45 	if (idx >= 0x1000)
46 		die("otp: idx out of bounds");
47 
48 	struct sifive_otp_registers *regs = (void *)(FU740_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 
otp_read_serial(void)79 u32 otp_read_serial(void)
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 }
91