17
#include "qemu/osdep.h"
19
#include "hw/nvram/npcm7xx_otp.h"
20
#include "migration/vmstate.h"
21
#include "qapi/error.h"
22
#include "qemu/bitops.h"
24
#include "qemu/module.h"
25
#include "qemu/units.h"
28
#define NPCM7XX_OTP_REGS_SIZE (4 * KiB)
31
typedef enum NPCM7xxOTPRegister {
37
NPCM7XX_OTP_FKEYIND = 0x0010 / sizeof(uint32_t),
38
NPCM7XX_OTP_FUSTRAP = 0x0010 / sizeof(uint32_t),
44
#define FST_RIEN BIT(2)
45
#define FST_RDST BIT(1)
47
#define FST_RO_MASK (FST_RDST | FST_RDY)
49
#define FADDR_BYTEADDR(rv) extract32((rv), 0, 10)
50
#define FADDR_BITPOS(rv) extract32((rv), 10, 3)
52
#define FDATA_CLEAR 0x00000001
54
#define FCFG_FDIS BIT(31)
55
#define FCFG_FCFGLK_MASK 0x00ff0000
57
#define FCTL_PROG_CMD1 0x00000001
58
#define FCTL_PROG_CMD2 0xbf79e5d0
59
#define FCTL_READ_CMD 0x00000002
69
struct NPCM7xxOTPClass {
70
SysBusDeviceClass parent;
72
const MemoryRegionOps *mmio_ops;
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)
80
static uint8_t ecc_encode_nibble(uint8_t n)
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;
92
void npcm7xx_otp_array_write(NPCM7xxOTPState *s, const void *data,
93
unsigned int offset, unsigned int len)
95
const uint8_t *src = data;
96
uint8_t *dst = &s->array[offset];
101
*dst++ = ecc_encode_nibble(extract8(c, 0, 4));
102
*dst++ = ecc_encode_nibble(extract8(c, 4, 4));
107
static uint64_t npcm7xx_otp_read(NPCM7xxOTPState *s, NPCM7xxOTPRegister 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];
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);
126
qemu_log_mask(LOG_GUEST_ERROR, "%s: read from invalid offset 0x%zx\n",
127
DEVICE(s)->canonical_path, reg * sizeof(uint32_t));
135
static void npcm7xx_otp_read_array(NPCM7xxOTPState *s)
137
uint32_t faddr = s->regs[NPCM7XX_OTP_FADDR];
139
s->regs[NPCM7XX_OTP_FDATA] = s->array[FADDR_BYTEADDR(faddr)];
140
s->regs[NPCM7XX_OTP_FST] |= FST_RDST | FST_RDY;
144
static void npcm7xx_otp_program_array(NPCM7xxOTPState *s)
146
uint32_t faddr = s->regs[NPCM7XX_OTP_FADDR];
149
s->array[FADDR_BYTEADDR(faddr)] |= (1U << FADDR_BITPOS(faddr));
150
s->regs[NPCM7XX_OTP_FST] |= FST_RDST | FST_RDY;
154
static uint32_t npcm7xx_otp_compute_fcfg(uint32_t cur_value, uint32_t new_value)
163
lock_mask = (cur_value & FCFG_FCFGLK_MASK) >> 8;
164
lock_mask |= lock_mask >> 8;
166
value = cur_value & (FCFG_FDIS | FCFG_FCFGLK_MASK);
168
value |= cur_value & lock_mask;
170
value |= new_value & ~lock_mask;
176
static void npcm7xx_otp_write(NPCM7xxOTPState *s, NPCM7xxOTPRegister reg,
180
case NPCM7XX_OTP_FST:
182
if (value & FST_RDST) {
183
s->regs[NPCM7XX_OTP_FST] &= ~FST_RDST;
186
value &= ~FST_RO_MASK;
187
value |= s->regs[NPCM7XX_OTP_FST] & FST_RO_MASK;
190
case NPCM7XX_OTP_FADDR:
193
case NPCM7XX_OTP_FDATA:
198
if (value == FDATA_CLEAR) {
201
value = s->regs[NPCM7XX_OTP_FDATA];
205
case NPCM7XX_OTP_FCFG:
206
value = npcm7xx_otp_compute_fcfg(s->regs[NPCM7XX_OTP_FCFG], value);
209
case NPCM7XX_OTP_FCTL:
212
npcm7xx_otp_read_array(s);
228
if (s->regs[NPCM7XX_OTP_FCTL] == FCTL_PROG_CMD1) {
229
npcm7xx_otp_program_array(s);
234
qemu_log_mask(LOG_GUEST_ERROR,
235
"%s: unrecognized FCNTL value 0x%" PRIx32 "\n",
236
DEVICE(s)->canonical_path, value);
239
if (value != FCTL_PROG_CMD1) {
245
qemu_log_mask(LOG_GUEST_ERROR, "%s: write to invalid offset 0x%zx\n",
246
DEVICE(s)->canonical_path, reg * sizeof(uint32_t));
250
s->regs[reg] = value;
254
static uint64_t npcm7xx_fuse_array_read(void *opaque, hwaddr addr,
257
NPCM7xxOTPRegister reg = addr / sizeof(uint32_t);
258
NPCM7xxOTPState *s = opaque;
265
if (reg != NPCM7XX_OTP_FUSTRAP) {
266
value = npcm7xx_otp_read(s, reg);
271
memcpy(fustrap, &s->array[0], sizeof(fustrap));
274
value = (fustrap[0] & fustrap[1]) | (fustrap[0] & fustrap[2]) |
275
(fustrap[1] & fustrap[2]);
282
static void npcm7xx_fuse_array_write(void *opaque, hwaddr addr, uint64_t v,
285
NPCM7xxOTPRegister reg = addr / sizeof(uint32_t);
286
NPCM7xxOTPState *s = opaque;
292
if (reg != NPCM7XX_OTP_FUSTRAP) {
293
npcm7xx_otp_write(s, reg, v);
297
static const MemoryRegionOps npcm7xx_fuse_array_ops = {
298
.read = npcm7xx_fuse_array_read,
299
.write = npcm7xx_fuse_array_write,
300
.endianness = DEVICE_LITTLE_ENDIAN,
302
.min_access_size = 4,
303
.max_access_size = 4,
309
static uint64_t npcm7xx_key_storage_read(void *opaque, hwaddr addr,
312
NPCM7xxOTPRegister reg = addr / sizeof(uint32_t);
313
NPCM7xxOTPState *s = opaque;
319
if (reg != NPCM7XX_OTP_FKEYIND) {
320
return npcm7xx_otp_read(s, reg);
323
qemu_log_mask(LOG_UNIMP, "%s: FKEYIND is not implemented\n", __func__);
325
return s->regs[NPCM7XX_OTP_FKEYIND];
329
static void npcm7xx_key_storage_write(void *opaque, hwaddr addr, uint64_t v,
332
NPCM7xxOTPRegister reg = addr / sizeof(uint32_t);
333
NPCM7xxOTPState *s = opaque;
339
if (reg != NPCM7XX_OTP_FKEYIND) {
340
npcm7xx_otp_write(s, reg, v);
344
qemu_log_mask(LOG_UNIMP, "%s: FKEYIND is not implemented\n", __func__);
346
s->regs[NPCM7XX_OTP_FKEYIND] = v;
349
static const MemoryRegionOps npcm7xx_key_storage_ops = {
350
.read = npcm7xx_key_storage_read,
351
.write = npcm7xx_key_storage_write,
352
.endianness = DEVICE_LITTLE_ENDIAN,
354
.min_access_size = 4,
355
.max_access_size = 4,
360
static void npcm7xx_otp_enter_reset(Object *obj, ResetType type)
362
NPCM7xxOTPState *s = NPCM7XX_OTP(obj);
364
memset(s->regs, 0, sizeof(s->regs));
366
s->regs[NPCM7XX_OTP_FST] = 0x00000001;
367
s->regs[NPCM7XX_OTP_FCFG] = 0x20000000;
370
static void npcm7xx_otp_realize(DeviceState *dev, Error **errp)
372
NPCM7xxOTPClass *oc = NPCM7XX_OTP_GET_CLASS(dev);
373
NPCM7xxOTPState *s = NPCM7XX_OTP(dev);
374
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
376
memset(s->array, 0, sizeof(s->array));
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);
383
static const VMStateDescription vmstate_npcm7xx_otp = {
384
.name = "npcm7xx-otp",
386
.minimum_version_id = 0,
387
.fields = (const 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(),
394
static void npcm7xx_otp_class_init(ObjectClass *klass, void *data)
396
ResettableClass *rc = RESETTABLE_CLASS(klass);
397
DeviceClass *dc = DEVICE_CLASS(klass);
399
QEMU_BUILD_BUG_ON(NPCM7XX_OTP_REGS_END > NPCM7XX_OTP_NR_REGS);
401
dc->realize = npcm7xx_otp_realize;
402
dc->vmsd = &vmstate_npcm7xx_otp;
403
rc->phases.enter = npcm7xx_otp_enter_reset;
406
static void npcm7xx_key_storage_class_init(ObjectClass *klass, void *data)
408
NPCM7xxOTPClass *oc = NPCM7XX_OTP_CLASS(klass);
410
oc->mmio_ops = &npcm7xx_key_storage_ops;
413
static void npcm7xx_fuse_array_class_init(ObjectClass *klass, void *data)
415
NPCM7xxOTPClass *oc = NPCM7XX_OTP_CLASS(klass);
417
oc->mmio_ops = &npcm7xx_fuse_array_ops;
420
static const TypeInfo npcm7xx_otp_types[] = {
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,
430
.name = TYPE_NPCM7XX_KEY_STORAGE,
431
.parent = TYPE_NPCM7XX_OTP,
432
.class_init = npcm7xx_key_storage_class_init,
435
.name = TYPE_NPCM7XX_FUSE_ARRAY,
436
.parent = TYPE_NPCM7XX_OTP,
437
.class_init = npcm7xx_fuse_array_class_init,
440
DEFINE_TYPES(npcm7xx_otp_types);