blob: e00086aeaed9a05eaa64719d286f7f5da72cafce [file] [log] [blame]
Maximilian Brune2ccb8e72024-01-14 21:59:27 +06001/* 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
17struct 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
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(&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
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}