1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#include <common.h>
21#include <dm/device.h>
22#include <dm/read.h>
23#include <linux/bitops.h>
24#include <linux/delay.h>
25#include <linux/io.h>
26#include <misc.h>
27
28#define BYTES_PER_FUSE 4
29
30#define PA_RESET_VAL 0x00
31#define PAS_RESET_VAL 0x00
32#define PAIO_RESET_VAL 0x00
33#define PDIN_RESET_VAL 0x00
34#define PTM_RESET_VAL 0x00
35
36#define PCLK_ENABLE_VAL BIT(0)
37#define PCLK_DISABLE_VAL 0x00
38
39#define PWE_WRITE_ENABLE BIT(0)
40#define PWE_WRITE_DISABLE 0x00
41
42#define PTM_FUSE_PROGRAM_VAL BIT(1)
43
44#define PCE_ENABLE_INPUT BIT(0)
45#define PCE_DISABLE_INPUT 0x00
46
47#define PPROG_ENABLE_INPUT BIT(0)
48#define PPROG_DISABLE_INPUT 0x00
49
50#define PTRIM_ENABLE_INPUT BIT(0)
51#define PTRIM_DISABLE_INPUT 0x00
52
53#define PDSTB_DEEP_STANDBY_ENABLE BIT(0)
54#define PDSTB_DEEP_STANDBY_DISABLE 0x00
55
56
57#define TPW_DELAY 20
58
59
60#define TPWI_DELAY 5
61
62
63#define TASP_DELAY 1
64
65
66#define TCD_DELAY 40
67
68
69#define TKL_DELAY 10
70
71
72#define TMS_DELAY 1
73
74struct sifive_otp_regs {
75 u32 pa;
76 u32 paio;
77 u32 pas;
78 u32 pce;
79 u32 pclk;
80 u32 pdin;
81 u32 pdout;
82 u32 pdstb;
83 u32 pprog;
84 u32 ptc;
85 u32 ptm;
86 u32 ptm_rep;
87 u32 ptr;
88 u32 ptrim;
89 u32 pwe;
90};
91
92struct sifive_otp_plat {
93 struct sifive_otp_regs __iomem *regs;
94 u32 total_fuses;
95};
96
97
98
99
100static int sifive_otp_read(struct udevice *dev, int offset,
101 void *buf, int size)
102{
103 struct sifive_otp_plat *plat = dev_get_plat(dev);
104 struct sifive_otp_regs *regs = (struct sifive_otp_regs *)plat->regs;
105
106
107 if ((size % BYTES_PER_FUSE) || (offset % BYTES_PER_FUSE)) {
108 printf("%s: size and offset must be multiple of 4.\n",
109 __func__);
110 return -EINVAL;
111 }
112
113 int fuseidx = offset / BYTES_PER_FUSE;
114 int fusecount = size / BYTES_PER_FUSE;
115
116
117 if (offset < 0 || size < 0)
118 return -EINVAL;
119 if (fuseidx >= plat->total_fuses)
120 return -EINVAL;
121 if ((fuseidx + fusecount) > plat->total_fuses)
122 return -EINVAL;
123
124 u32 fusebuf[fusecount];
125
126
127 writel(PDSTB_DEEP_STANDBY_ENABLE, ®s->pdstb);
128 writel(PTRIM_ENABLE_INPUT, ®s->ptrim);
129 writel(PCE_ENABLE_INPUT, ®s->pce);
130
131
132 for (unsigned int i = 0; i < fusecount; i++, fuseidx++) {
133 writel(fuseidx, ®s->pa);
134
135
136 writel(PCLK_ENABLE_VAL, ®s->pclk);
137 ndelay(TCD_DELAY * 1000);
138 writel(PCLK_DISABLE_VAL, ®s->pclk);
139 ndelay(TKL_DELAY * 1000);
140
141
142 fusebuf[i] = readl(®s->pdout);
143 }
144
145
146 writel(PCE_DISABLE_INPUT, ®s->pce);
147 writel(PTRIM_DISABLE_INPUT, ®s->ptrim);
148 writel(PDSTB_DEEP_STANDBY_DISABLE, ®s->pdstb);
149
150
151 memcpy(buf, fusebuf, size);
152
153 return size;
154}
155
156
157
158
159
160
161
162static int sifive_otp_write(struct udevice *dev, int offset,
163 const void *buf, int size)
164{
165 struct sifive_otp_plat *plat = dev_get_plat(dev);
166 struct sifive_otp_regs *regs = (struct sifive_otp_regs *)plat->regs;
167
168
169 if ((size % BYTES_PER_FUSE) || (offset % BYTES_PER_FUSE)) {
170 printf("%s: size and offset must be multiple of 4.\n",
171 __func__);
172 return -EINVAL;
173 }
174
175 int fuseidx = offset / BYTES_PER_FUSE;
176 int fusecount = size / BYTES_PER_FUSE;
177 u32 *write_buf = (u32 *)buf;
178 u32 write_data;
179 int i, pas, bit;
180
181
182 if (offset < 0 || size < 0)
183 return -EINVAL;
184 if (fuseidx >= plat->total_fuses)
185 return -EINVAL;
186 if ((fuseidx + fusecount) > plat->total_fuses)
187 return -EINVAL;
188
189
190 writel(PDSTB_DEEP_STANDBY_ENABLE, ®s->pdstb);
191 writel(PTRIM_ENABLE_INPUT, ®s->ptrim);
192
193
194 writel(PCLK_DISABLE_VAL, ®s->pclk);
195 writel(PA_RESET_VAL, ®s->pa);
196 writel(PAS_RESET_VAL, ®s->pas);
197 writel(PAIO_RESET_VAL, ®s->paio);
198 writel(PDIN_RESET_VAL, ®s->pdin);
199 writel(PWE_WRITE_DISABLE, ®s->pwe);
200 writel(PTM_FUSE_PROGRAM_VAL, ®s->ptm);
201 ndelay(TMS_DELAY * 1000);
202
203 writel(PCE_ENABLE_INPUT, ®s->pce);
204 writel(PPROG_ENABLE_INPUT, ®s->pprog);
205
206
207 for (i = 0; i < fusecount; i++, fuseidx++) {
208 writel(fuseidx, ®s->pa);
209 write_data = *(write_buf++);
210
211 for (pas = 0; pas < 2; pas++) {
212 writel(pas, ®s->pas);
213
214 for (bit = 0; bit < 32; bit++) {
215 writel(bit, ®s->paio);
216 writel(((write_data >> bit) & 1),
217 ®s->pdin);
218 ndelay(TASP_DELAY * 1000);
219
220 writel(PWE_WRITE_ENABLE, ®s->pwe);
221 udelay(TPW_DELAY);
222 writel(PWE_WRITE_DISABLE, ®s->pwe);
223 udelay(TPWI_DELAY);
224 }
225 }
226
227 writel(PAS_RESET_VAL, ®s->pas);
228 }
229
230
231 writel(PWE_WRITE_DISABLE, ®s->pwe);
232 writel(PPROG_DISABLE_INPUT, ®s->pprog);
233 writel(PCE_DISABLE_INPUT, ®s->pce);
234 writel(PTM_RESET_VAL, ®s->ptm);
235
236 writel(PTRIM_DISABLE_INPUT, ®s->ptrim);
237 writel(PDSTB_DEEP_STANDBY_DISABLE, ®s->pdstb);
238
239 return size;
240}
241
242static int sifive_otp_of_to_plat(struct udevice *dev)
243{
244 struct sifive_otp_plat *plat = dev_get_plat(dev);
245 int ret;
246
247 plat->regs = dev_read_addr_ptr(dev);
248
249 ret = dev_read_u32(dev, "fuse-count", &plat->total_fuses);
250 if (ret < 0) {
251 pr_err("\"fuse-count\" not found\n");
252 return ret;
253 }
254
255 return 0;
256}
257
258static const struct misc_ops sifive_otp_ops = {
259 .read = sifive_otp_read,
260 .write = sifive_otp_write,
261};
262
263static const struct udevice_id sifive_otp_ids[] = {
264 { .compatible = "sifive,fu540-c000-otp" },
265 {}
266};
267
268U_BOOT_DRIVER(sifive_otp) = {
269 .name = "sifive_otp",
270 .id = UCLASS_MISC,
271 .of_match = sifive_otp_ids,
272 .of_to_plat = sifive_otp_of_to_plat,
273 .plat_auto = sizeof(struct sifive_otp_plat),
274 .ops = &sifive_otp_ops,
275};
276