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)41u32 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(®s->pdstb, 0x01); 52 53 // enable repair function 54 write32(®s->ptrim, 0x01); 55 56 // enable input 57 write32(®s->pce, 0x01); 58 59 // address to read 60 write32(®s->pa, idx); 61 62 // cycle clock to read 63 write32(®s->pclk, 0x01); 64 mdelay(1); 65 66 write32(®s->pclk, 0x00); 67 mdelay(1); 68 69 w = read32(®s->pdout); 70 71 // shut down 72 write32(®s->pce, 0x00); 73 write32(®s->ptrim, 0x00); 74 write32(®s->pdstb, 0x00); 75 76 return w; 77 } 78 otp_read_serial(void)79u32 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