1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17#include "qemu/osdep.h"
18
19#include "hw/nvram/npcm7xx_otp.h"
20#include "migration/vmstate.h"
21#include "qapi/error.h"
22#include "qemu/bitops.h"
23#include "qemu/log.h"
24#include "qemu/module.h"
25#include "qemu/units.h"
26
27
28#define NPCM7XX_OTP_REGS_SIZE (4 * KiB)
29
30
31typedef enum NPCM7xxOTPRegister {
32 NPCM7XX_OTP_FST,
33 NPCM7XX_OTP_FADDR,
34 NPCM7XX_OTP_FDATA,
35 NPCM7XX_OTP_FCFG,
36
37 NPCM7XX_OTP_FKEYIND = 0x0010 / sizeof(uint32_t),
38 NPCM7XX_OTP_FUSTRAP = 0x0010 / sizeof(uint32_t),
39 NPCM7XX_OTP_FCTL,
40 NPCM7XX_OTP_REGS_END,
41} NPCM7xxOTPRegister;
42
43
44#define FST_RIEN BIT(2)
45#define FST_RDST BIT(1)
46#define FST_RDY BIT(0)
47#define FST_RO_MASK (FST_RDST | FST_RDY)
48
49#define FADDR_BYTEADDR(rv) extract32((rv), 0, 10)
50#define FADDR_BITPOS(rv) extract32((rv), 10, 3)
51
52#define FDATA_CLEAR 0x00000001
53
54#define FCFG_FDIS BIT(31)
55#define FCFG_FCFGLK_MASK 0x00ff0000
56
57#define FCTL_PROG_CMD1 0x00000001
58#define FCTL_PROG_CMD2 0xbf79e5d0
59#define FCTL_READ_CMD 0x00000002
60
61
62
63
64
65
66
67
68
69struct NPCM7xxOTPClass {
70 SysBusDeviceClass parent;
71
72 const MemoryRegionOps *mmio_ops;
73};
74
75#define NPCM7XX_OTP_CLASS(klass) \
76 OBJECT_CLASS_CHECK(NPCM7xxOTPClass, (klass), TYPE_NPCM7XX_OTP)
77#define NPCM7XX_OTP_GET_CLASS(obj) \
78 OBJECT_GET_CLASS(NPCM7xxOTPClass, (obj), TYPE_NPCM7XX_OTP)
79
80static uint8_t ecc_encode_nibble(uint8_t n)
81{
82 uint8_t result = n;
83
84 result |= (((n >> 0) & 1) ^ ((n >> 1) & 1)) << 4;
85 result |= (((n >> 2) & 1) ^ ((n >> 3) & 1)) << 5;
86 result |= (((n >> 0) & 1) ^ ((n >> 2) & 1)) << 6;
87 result |= (((n >> 1) & 1) ^ ((n >> 3) & 1)) << 7;
88
89 return result;
90}
91
92void npcm7xx_otp_array_write(NPCM7xxOTPState *s, const void *data,
93 unsigned int offset, unsigned int len)
94{
95 const uint8_t *src = data;
96 uint8_t *dst = &s->array[offset];
97
98 while (len-- > 0) {
99 uint8_t c = *src++;
100
101 *dst++ = ecc_encode_nibble(extract8(c, 0, 4));
102 *dst++ = ecc_encode_nibble(extract8(c, 4, 4));
103 }
104}
105
106
107static uint64_t npcm7xx_otp_read(NPCM7xxOTPState *s, NPCM7xxOTPRegister reg)
108{
109 uint32_t value = 0;
110
111 switch (reg) {
112 case NPCM7XX_OTP_FST:
113 case NPCM7XX_OTP_FADDR:
114 case NPCM7XX_OTP_FDATA:
115 case NPCM7XX_OTP_FCFG:
116 value = s->regs[reg];
117 break;
118
119 case NPCM7XX_OTP_FCTL:
120 qemu_log_mask(LOG_GUEST_ERROR,
121 "%s: read from write-only FCTL register\n",
122 DEVICE(s)->canonical_path);
123 break;
124
125 default:
126 qemu_log_mask(LOG_GUEST_ERROR, "%s: read from invalid offset 0x%zx\n",
127 DEVICE(s)->canonical_path, reg * sizeof(uint32_t));
128 break;
129 }
130
131 return value;
132}
133
134
135static void npcm7xx_otp_read_array(NPCM7xxOTPState *s)
136{
137 uint32_t faddr = s->regs[NPCM7XX_OTP_FADDR];
138
139 s->regs[NPCM7XX_OTP_FDATA] = s->array[FADDR_BYTEADDR(faddr)];
140 s->regs[NPCM7XX_OTP_FST] |= FST_RDST | FST_RDY;
141}
142
143
144static void npcm7xx_otp_program_array(NPCM7xxOTPState *s)
145{
146 uint32_t faddr = s->regs[NPCM7XX_OTP_FADDR];
147
148
149 s->array[FADDR_BYTEADDR(faddr)] |= (1U << FADDR_BITPOS(faddr));
150 s->regs[NPCM7XX_OTP_FST] |= FST_RDST | FST_RDY;
151}
152
153
154static uint32_t npcm7xx_otp_compute_fcfg(uint32_t cur_value, uint32_t new_value)
155{
156 uint32_t lock_mask;
157 uint32_t value;
158
159
160
161
162
163 lock_mask = (cur_value & FCFG_FCFGLK_MASK) >> 8;
164 lock_mask |= lock_mask >> 8;
165
166 value = cur_value & (FCFG_FDIS | FCFG_FCFGLK_MASK);
167
168 value |= cur_value & lock_mask;
169
170 value |= new_value & ~lock_mask;
171
172 return value;
173}
174
175
176static void npcm7xx_otp_write(NPCM7xxOTPState *s, NPCM7xxOTPRegister reg,
177 uint32_t value)
178{
179 switch (reg) {
180 case NPCM7XX_OTP_FST:
181
182 if (value & FST_RDST) {
183 s->regs[NPCM7XX_OTP_FST] &= ~FST_RDST;
184 }
185
186 value &= ~FST_RO_MASK;
187 value |= s->regs[NPCM7XX_OTP_FST] & FST_RO_MASK;
188 break;
189
190 case NPCM7XX_OTP_FADDR:
191 break;
192
193 case NPCM7XX_OTP_FDATA:
194
195
196
197
198 if (value == FDATA_CLEAR) {
199 value = 0;
200 } else {
201 value = s->regs[NPCM7XX_OTP_FDATA];
202 }
203 break;
204
205 case NPCM7XX_OTP_FCFG:
206 value = npcm7xx_otp_compute_fcfg(s->regs[NPCM7XX_OTP_FCFG], value);
207 break;
208
209 case NPCM7XX_OTP_FCTL:
210 switch (value) {
211 case FCTL_READ_CMD:
212 npcm7xx_otp_read_array(s);
213 break;
214
215 case FCTL_PROG_CMD1:
216
217
218
219
220
221 break;
222
223 case FCTL_PROG_CMD2:
224
225
226
227
228 if (s->regs[NPCM7XX_OTP_FCTL] == FCTL_PROG_CMD1) {
229 npcm7xx_otp_program_array(s);
230 }
231 break;
232
233 default:
234 qemu_log_mask(LOG_GUEST_ERROR,
235 "%s: unrecognized FCNTL value 0x%" PRIx32 "\n",
236 DEVICE(s)->canonical_path, value);
237 break;
238 }
239 if (value != FCTL_PROG_CMD1) {
240 value = 0;
241 }
242 break;
243
244 default:
245 qemu_log_mask(LOG_GUEST_ERROR, "%s: write to invalid offset 0x%zx\n",
246 DEVICE(s)->canonical_path, reg * sizeof(uint32_t));
247 return;
248 }
249
250 s->regs[reg] = value;
251}
252
253
254static uint64_t npcm7xx_fuse_array_read(void *opaque, hwaddr addr,
255 unsigned int size)
256{
257 NPCM7xxOTPRegister reg = addr / sizeof(uint32_t);
258 NPCM7xxOTPState *s = opaque;
259 uint32_t value;
260
261
262
263
264
265 if (reg != NPCM7XX_OTP_FUSTRAP) {
266 value = npcm7xx_otp_read(s, reg);
267 } else {
268
269 uint32_t fustrap[3];
270
271 memcpy(fustrap, &s->array[0], sizeof(fustrap));
272
273
274 value = (fustrap[0] & fustrap[1]) | (fustrap[0] & fustrap[2]) |
275 (fustrap[1] & fustrap[2]);
276 }
277
278 return value;
279}
280
281
282static void npcm7xx_fuse_array_write(void *opaque, hwaddr addr, uint64_t v,
283 unsigned int size)
284{
285 NPCM7xxOTPRegister reg = addr / sizeof(uint32_t);
286 NPCM7xxOTPState *s = opaque;
287
288
289
290
291
292 if (reg != NPCM7XX_OTP_FUSTRAP) {
293 npcm7xx_otp_write(s, reg, v);
294 }
295}
296
297static const MemoryRegionOps npcm7xx_fuse_array_ops = {
298 .read = npcm7xx_fuse_array_read,
299 .write = npcm7xx_fuse_array_write,
300 .endianness = DEVICE_LITTLE_ENDIAN,
301 .valid = {
302 .min_access_size = 4,
303 .max_access_size = 4,
304 .unaligned = false,
305 },
306};
307
308
309static uint64_t npcm7xx_key_storage_read(void *opaque, hwaddr addr,
310 unsigned int size)
311{
312 NPCM7xxOTPRegister reg = addr / sizeof(uint32_t);
313 NPCM7xxOTPState *s = opaque;
314
315
316
317
318
319 if (reg != NPCM7XX_OTP_FKEYIND) {
320 return npcm7xx_otp_read(s, reg);
321 }
322
323 qemu_log_mask(LOG_UNIMP, "%s: FKEYIND is not implemented\n", __func__);
324
325 return s->regs[NPCM7XX_OTP_FKEYIND];
326}
327
328
329static void npcm7xx_key_storage_write(void *opaque, hwaddr addr, uint64_t v,
330 unsigned int size)
331{
332 NPCM7xxOTPRegister reg = addr / sizeof(uint32_t);
333 NPCM7xxOTPState *s = opaque;
334
335
336
337
338
339 if (reg != NPCM7XX_OTP_FKEYIND) {
340 npcm7xx_otp_write(s, reg, v);
341 return;
342 }
343
344 qemu_log_mask(LOG_UNIMP, "%s: FKEYIND is not implemented\n", __func__);
345
346 s->regs[NPCM7XX_OTP_FKEYIND] = v;
347}
348
349static const MemoryRegionOps npcm7xx_key_storage_ops = {
350 .read = npcm7xx_key_storage_read,
351 .write = npcm7xx_key_storage_write,
352 .endianness = DEVICE_LITTLE_ENDIAN,
353 .valid = {
354 .min_access_size = 4,
355 .max_access_size = 4,
356 .unaligned = false,
357 },
358};
359
360static void npcm7xx_otp_enter_reset(Object *obj, ResetType type)
361{
362 NPCM7xxOTPState *s = NPCM7XX_OTP(obj);
363
364 memset(s->regs, 0, sizeof(s->regs));
365
366 s->regs[NPCM7XX_OTP_FST] = 0x00000001;
367 s->regs[NPCM7XX_OTP_FCFG] = 0x20000000;
368}
369
370static void npcm7xx_otp_realize(DeviceState *dev, Error **errp)
371{
372 NPCM7xxOTPClass *oc = NPCM7XX_OTP_GET_CLASS(dev);
373 NPCM7xxOTPState *s = NPCM7XX_OTP(dev);
374 SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
375
376 memset(s->array, 0, sizeof(s->array));
377
378 memory_region_init_io(&s->mmio, OBJECT(s), oc->mmio_ops, s, "regs",
379 NPCM7XX_OTP_REGS_SIZE);
380 sysbus_init_mmio(sbd, &s->mmio);
381}
382
383static const VMStateDescription vmstate_npcm7xx_otp = {
384 .name = "npcm7xx-otp",
385 .version_id = 0,
386 .minimum_version_id = 0,
387 .fields = (VMStateField[]) {
388 VMSTATE_UINT32_ARRAY(regs, NPCM7xxOTPState, NPCM7XX_OTP_NR_REGS),
389 VMSTATE_UINT8_ARRAY(array, NPCM7xxOTPState, NPCM7XX_OTP_ARRAY_BYTES),
390 VMSTATE_END_OF_LIST(),
391 },
392};
393
394static void npcm7xx_otp_class_init(ObjectClass *klass, void *data)
395{
396 ResettableClass *rc = RESETTABLE_CLASS(klass);
397 DeviceClass *dc = DEVICE_CLASS(klass);
398
399 QEMU_BUILD_BUG_ON(NPCM7XX_OTP_REGS_END > NPCM7XX_OTP_NR_REGS);
400
401 dc->realize = npcm7xx_otp_realize;
402 dc->vmsd = &vmstate_npcm7xx_otp;
403 rc->phases.enter = npcm7xx_otp_enter_reset;
404}
405
406static void npcm7xx_key_storage_class_init(ObjectClass *klass, void *data)
407{
408 NPCM7xxOTPClass *oc = NPCM7XX_OTP_CLASS(klass);
409
410 oc->mmio_ops = &npcm7xx_key_storage_ops;
411}
412
413static void npcm7xx_fuse_array_class_init(ObjectClass *klass, void *data)
414{
415 NPCM7xxOTPClass *oc = NPCM7XX_OTP_CLASS(klass);
416
417 oc->mmio_ops = &npcm7xx_fuse_array_ops;
418}
419
420static const TypeInfo npcm7xx_otp_types[] = {
421 {
422 .name = TYPE_NPCM7XX_OTP,
423 .parent = TYPE_SYS_BUS_DEVICE,
424 .instance_size = sizeof(NPCM7xxOTPState),
425 .class_size = sizeof(NPCM7xxOTPClass),
426 .class_init = npcm7xx_otp_class_init,
427 .abstract = true,
428 },
429 {
430 .name = TYPE_NPCM7XX_KEY_STORAGE,
431 .parent = TYPE_NPCM7XX_OTP,
432 .class_init = npcm7xx_key_storage_class_init,
433 },
434 {
435 .name = TYPE_NPCM7XX_FUSE_ARRAY,
436 .parent = TYPE_NPCM7XX_OTP,
437 .class_init = npcm7xx_fuse_array_class_init,
438 },
439};
440DEFINE_TYPES(npcm7xx_otp_types);
441