npcm7xx_otp.c (13174B)
1/* 2 * Nuvoton NPCM7xx OTP (Fuse Array) Interface 3 * 4 * Copyright 2020 Google LLC 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License as published by the 8 * Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * for more details. 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/* Each module has 4 KiB of register space. Only a fraction of it is used. */ 28#define NPCM7XX_OTP_REGS_SIZE (4 * KiB) 29 30/* 32-bit register indices. */ 31typedef enum NPCM7xxOTPRegister { 32 NPCM7XX_OTP_FST, 33 NPCM7XX_OTP_FADDR, 34 NPCM7XX_OTP_FDATA, 35 NPCM7XX_OTP_FCFG, 36 /* Offset 0x10 is FKEYIND in OTP1, FUSTRAP in OTP2 */ 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/* Register field definitions. */ 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 * struct NPCM7xxOTPClass - OTP module class. 63 * @parent: System bus device class. 64 * @mmio_ops: MMIO register operations for this type of module. 65 * 66 * The two OTP modules (key-storage and fuse-array) have slightly different 67 * behavior, so we give them different MMIO register operations. 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/* Common register read handler for both OTP classes. */ 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/* Read a byte from the OTP array into the data register. */ 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/* Program a byte from the data register into the OTP array. */ 144static void npcm7xx_otp_program_array(NPCM7xxOTPState *s) 145{ 146 uint32_t faddr = s->regs[NPCM7XX_OTP_FADDR]; 147 148 /* Bits can only go 0->1, never 1->0. */ 149 s->array[FADDR_BYTEADDR(faddr)] |= (1U << FADDR_BITPOS(faddr)); 150 s->regs[NPCM7XX_OTP_FST] |= FST_RDST | FST_RDY; 151} 152 153/* Compute the next value of the FCFG register. */ 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 * FCFGLK holds sticky bits 16..23, indicating which bits in FPRGLK (8..15) 161 * and FRDLK (0..7) that are read-only. 162 */ 163 lock_mask = (cur_value & FCFG_FCFGLK_MASK) >> 8; 164 lock_mask |= lock_mask >> 8; 165 /* FDIS and FCFGLK bits are sticky (write 1 to set; can't clear). */ 166 value = cur_value & (FCFG_FDIS | FCFG_FCFGLK_MASK); 167 /* Preserve read-only bits in FPRGLK and FRDLK */ 168 value |= cur_value & lock_mask; 169 /* Set all bits that aren't read-only. */ 170 value |= new_value & ~lock_mask; 171 172 return value; 173} 174 175/* Common register write handler for both OTP classes. */ 176static void npcm7xx_otp_write(NPCM7xxOTPState *s, NPCM7xxOTPRegister reg, 177 uint32_t value) 178{ 179 switch (reg) { 180 case NPCM7XX_OTP_FST: 181 /* RDST is cleared by writing 1 to it. */ 182 if (value & FST_RDST) { 183 s->regs[NPCM7XX_OTP_FST] &= ~FST_RDST; 184 } 185 /* Preserve read-only and write-one-to-clear bits */ 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 * This register is cleared by writing a magic value to it; no other 196 * values can be written. 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 * Programming requires writing two separate magic values to this 218 * register; this is the first one. Just store it so it can be 219 * verified later when the second magic value is received. 220 */ 221 break; 222 223 case FCTL_PROG_CMD2: 224 /* 225 * Only initiate programming if we received the first half of the 226 * command immediately before this one. 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/* Register read handler specific to the fuse array OTP module. */ 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 * Only the Fuse Strap register needs special handling; all other registers 263 * work the same way for both kinds of OTP modules. 264 */ 265 if (reg != NPCM7XX_OTP_FUSTRAP) { 266 value = npcm7xx_otp_read(s, reg); 267 } else { 268 /* FUSTRAP is stored as three copies in the OTP array. */ 269 uint32_t fustrap[3]; 270 271 memcpy(fustrap, &s->array[0], sizeof(fustrap)); 272 273 /* Determine value by a majority vote on each bit. */ 274 value = (fustrap[0] & fustrap[1]) | (fustrap[0] & fustrap[2]) | 275 (fustrap[1] & fustrap[2]); 276 } 277 278 return value; 279} 280 281/* Register write handler specific to the fuse array OTP module. */ 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 * The Fuse Strap register is read-only. Other registers are handled by 290 * common code. 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/* Register read handler specific to the key storage OTP module. */ 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 * Only the Fuse Key Index register needs special handling; all other 317 * registers work the same way for both kinds of OTP modules. 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/* Register write handler specific to the key storage OTP module. */ 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 * Only the Fuse Key Index register needs special handling; all other 337 * registers work the same way for both kinds of OTP modules. 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);