qemu/hw/nvram/npcm7xx_otp.c
<<
>>
Prefs
   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);
 441