qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

npcm7xx_fiu.c (17981B)


      1 /*
      2  * Nuvoton NPCM7xx Flash Interface Unit (FIU)
      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/irq.h"
     20 #include "hw/qdev-properties.h"
     21 #include "hw/ssi/npcm7xx_fiu.h"
     22 #include "migration/vmstate.h"
     23 #include "qapi/error.h"
     24 #include "qemu/error-report.h"
     25 #include "qemu/log.h"
     26 #include "qemu/module.h"
     27 #include "qemu/units.h"
     28 
     29 #include "trace.h"
     30 
     31 /* Up to 128 MiB of flash may be accessed directly as memory. */
     32 #define NPCM7XX_FIU_FLASH_WINDOW_SIZE (128 * MiB)
     33 
     34 /* Each module has 4 KiB of register space. Only a fraction of it is used. */
     35 #define NPCM7XX_FIU_CTRL_REGS_SIZE (4 * KiB)
     36 
     37 /* 32-bit FIU register indices. */
     38 enum NPCM7xxFIURegister {
     39     NPCM7XX_FIU_DRD_CFG,
     40     NPCM7XX_FIU_DWR_CFG,
     41     NPCM7XX_FIU_UMA_CFG,
     42     NPCM7XX_FIU_UMA_CTS,
     43     NPCM7XX_FIU_UMA_CMD,
     44     NPCM7XX_FIU_UMA_ADDR,
     45     NPCM7XX_FIU_PRT_CFG,
     46     NPCM7XX_FIU_UMA_DW0 = 0x0020 / sizeof(uint32_t),
     47     NPCM7XX_FIU_UMA_DW1,
     48     NPCM7XX_FIU_UMA_DW2,
     49     NPCM7XX_FIU_UMA_DW3,
     50     NPCM7XX_FIU_UMA_DR0,
     51     NPCM7XX_FIU_UMA_DR1,
     52     NPCM7XX_FIU_UMA_DR2,
     53     NPCM7XX_FIU_UMA_DR3,
     54     NPCM7XX_FIU_PRT_CMD0,
     55     NPCM7XX_FIU_PRT_CMD1,
     56     NPCM7XX_FIU_PRT_CMD2,
     57     NPCM7XX_FIU_PRT_CMD3,
     58     NPCM7XX_FIU_PRT_CMD4,
     59     NPCM7XX_FIU_PRT_CMD5,
     60     NPCM7XX_FIU_PRT_CMD6,
     61     NPCM7XX_FIU_PRT_CMD7,
     62     NPCM7XX_FIU_PRT_CMD8,
     63     NPCM7XX_FIU_PRT_CMD9,
     64     NPCM7XX_FIU_CFG = 0x78 / sizeof(uint32_t),
     65     NPCM7XX_FIU_REGS_END,
     66 };
     67 
     68 /* FIU_{DRD,DWR,UMA,PTR}_CFG cannot be written when this bit is set. */
     69 #define NPCM7XX_FIU_CFG_LCK BIT(31)
     70 
     71 /* Direct Read configuration register fields. */
     72 #define FIU_DRD_CFG_ADDSIZ(rv) extract32(rv, 16, 2)
     73 #define FIU_ADDSIZ_3BYTES 0
     74 #define FIU_ADDSIZ_4BYTES 1
     75 #define FIU_DRD_CFG_DBW(rv) extract32(rv, 12, 2)
     76 #define FIU_DRD_CFG_ACCTYPE(rv) extract32(rv, 8, 2)
     77 #define FIU_DRD_CFG_RDCMD(rv) extract32(rv, 0, 8)
     78 
     79 /* Direct Write configuration register fields. */
     80 #define FIU_DWR_CFG_ADDSIZ(rv) extract32(rv, 16, 2)
     81 #define FIU_DWR_CFG_WRCMD(rv) extract32(rv, 0, 8)
     82 
     83 /* User-Mode Access register fields. */
     84 
     85 /* Command Mode Lock and the bits protected by it. */
     86 #define FIU_UMA_CFG_CMMLCK BIT(30)
     87 #define FIU_UMA_CFG_CMMLCK_MASK 0x00000403
     88 
     89 #define FIU_UMA_CFG_RDATSIZ(rv) extract32(rv, 24, 5)
     90 #define FIU_UMA_CFG_DBSIZ(rv) extract32(rv, 21, 3)
     91 #define FIU_UMA_CFG_WDATSIZ(rv) extract32(rv, 16, 5)
     92 #define FIU_UMA_CFG_ADDSIZ(rv) extract32(rv, 11, 3)
     93 #define FIU_UMA_CFG_CMDSIZ(rv) extract32(rv, 10, 1)
     94 #define FIU_UMA_CFG_DBPCK(rv) extract32(rv, 6, 2)
     95 
     96 #define FIU_UMA_CTS_RDYIE BIT(25)
     97 #define FIU_UMA_CTS_RDYST BIT(24)
     98 #define FIU_UMA_CTS_SW_CS BIT(16)
     99 #define FIU_UMA_CTS_DEV_NUM(rv) extract32(rv, 8, 2)
    100 #define FIU_UMA_CTS_EXEC_DONE BIT(0)
    101 
    102 /*
    103  * Returns the index of flash in the fiu->flash array. This corresponds to the
    104  * chip select ID of the flash.
    105  */
    106 static unsigned npcm7xx_fiu_cs_index(NPCM7xxFIUState *fiu,
    107                                      NPCM7xxFIUFlash *flash)
    108 {
    109     int index = flash - fiu->flash;
    110 
    111     g_assert(index >= 0 && index < fiu->cs_count);
    112 
    113     return index;
    114 }
    115 
    116 /* Assert the chip select specified in the UMA Control/Status Register. */
    117 static void npcm7xx_fiu_select(NPCM7xxFIUState *s, unsigned cs_id)
    118 {
    119     trace_npcm7xx_fiu_select(DEVICE(s)->canonical_path, cs_id);
    120 
    121     if (cs_id < s->cs_count) {
    122         qemu_irq_lower(s->cs_lines[cs_id]);
    123         s->active_cs = cs_id;
    124     } else {
    125         qemu_log_mask(LOG_GUEST_ERROR,
    126                       "%s: UMA to CS%d; this module has only %d chip selects",
    127                       DEVICE(s)->canonical_path, cs_id, s->cs_count);
    128         s->active_cs = -1;
    129     }
    130 }
    131 
    132 /* Deassert the currently active chip select. */
    133 static void npcm7xx_fiu_deselect(NPCM7xxFIUState *s)
    134 {
    135     if (s->active_cs < 0) {
    136         return;
    137     }
    138 
    139     trace_npcm7xx_fiu_deselect(DEVICE(s)->canonical_path, s->active_cs);
    140 
    141     qemu_irq_raise(s->cs_lines[s->active_cs]);
    142     s->active_cs = -1;
    143 }
    144 
    145 /* Direct flash memory read handler. */
    146 static uint64_t npcm7xx_fiu_flash_read(void *opaque, hwaddr addr,
    147                                        unsigned int size)
    148 {
    149     NPCM7xxFIUFlash *f = opaque;
    150     NPCM7xxFIUState *fiu = f->fiu;
    151     uint64_t value = 0;
    152     uint32_t drd_cfg;
    153     int dummy_cycles;
    154     int i;
    155 
    156     if (fiu->active_cs != -1) {
    157         qemu_log_mask(LOG_GUEST_ERROR,
    158                       "%s: direct flash read with CS%d already active",
    159                       DEVICE(fiu)->canonical_path, fiu->active_cs);
    160     }
    161 
    162     npcm7xx_fiu_select(fiu, npcm7xx_fiu_cs_index(fiu, f));
    163 
    164     drd_cfg = fiu->regs[NPCM7XX_FIU_DRD_CFG];
    165     ssi_transfer(fiu->spi, FIU_DRD_CFG_RDCMD(drd_cfg));
    166 
    167     switch (FIU_DRD_CFG_ADDSIZ(drd_cfg)) {
    168     case FIU_ADDSIZ_4BYTES:
    169         ssi_transfer(fiu->spi, extract32(addr, 24, 8));
    170         /* fall through */
    171     case FIU_ADDSIZ_3BYTES:
    172         ssi_transfer(fiu->spi, extract32(addr, 16, 8));
    173         ssi_transfer(fiu->spi, extract32(addr, 8, 8));
    174         ssi_transfer(fiu->spi, extract32(addr, 0, 8));
    175         break;
    176 
    177     default:
    178         qemu_log_mask(LOG_GUEST_ERROR, "%s: bad address size %d\n",
    179                       DEVICE(fiu)->canonical_path, FIU_DRD_CFG_ADDSIZ(drd_cfg));
    180         break;
    181     }
    182 
    183     /* Flash chip model expects one transfer per dummy bit, not byte */
    184     dummy_cycles =
    185         (FIU_DRD_CFG_DBW(drd_cfg) * 8) >> FIU_DRD_CFG_ACCTYPE(drd_cfg);
    186     for (i = 0; i < dummy_cycles; i++) {
    187         ssi_transfer(fiu->spi, 0);
    188     }
    189 
    190     for (i = 0; i < size; i++) {
    191         value = deposit64(value, 8 * i, 8, ssi_transfer(fiu->spi, 0));
    192     }
    193 
    194     trace_npcm7xx_fiu_flash_read(DEVICE(fiu)->canonical_path, fiu->active_cs,
    195                                  addr, size, value);
    196 
    197     npcm7xx_fiu_deselect(fiu);
    198 
    199     return value;
    200 }
    201 
    202 /* Direct flash memory write handler. */
    203 static void npcm7xx_fiu_flash_write(void *opaque, hwaddr addr, uint64_t v,
    204                                     unsigned int size)
    205 {
    206     NPCM7xxFIUFlash *f = opaque;
    207     NPCM7xxFIUState *fiu = f->fiu;
    208     uint32_t dwr_cfg;
    209     unsigned cs_id;
    210     int i;
    211 
    212     if (fiu->active_cs != -1) {
    213         qemu_log_mask(LOG_GUEST_ERROR,
    214                       "%s: direct flash write with CS%d already active",
    215                       DEVICE(fiu)->canonical_path, fiu->active_cs);
    216     }
    217 
    218     cs_id = npcm7xx_fiu_cs_index(fiu, f);
    219     trace_npcm7xx_fiu_flash_write(DEVICE(fiu)->canonical_path, cs_id, addr,
    220                                   size, v);
    221     npcm7xx_fiu_select(fiu, cs_id);
    222 
    223     dwr_cfg = fiu->regs[NPCM7XX_FIU_DWR_CFG];
    224     ssi_transfer(fiu->spi, FIU_DWR_CFG_WRCMD(dwr_cfg));
    225 
    226     switch (FIU_DWR_CFG_ADDSIZ(dwr_cfg)) {
    227     case FIU_ADDSIZ_4BYTES:
    228         ssi_transfer(fiu->spi, extract32(addr, 24, 8));
    229         /* fall through */
    230     case FIU_ADDSIZ_3BYTES:
    231         ssi_transfer(fiu->spi, extract32(addr, 16, 8));
    232         ssi_transfer(fiu->spi, extract32(addr, 8, 8));
    233         ssi_transfer(fiu->spi, extract32(addr, 0, 8));
    234         break;
    235 
    236     default:
    237         qemu_log_mask(LOG_GUEST_ERROR, "%s: bad address size %d\n",
    238                       DEVICE(fiu)->canonical_path, FIU_DWR_CFG_ADDSIZ(dwr_cfg));
    239         break;
    240     }
    241 
    242     for (i = 0; i < size; i++) {
    243         ssi_transfer(fiu->spi, extract64(v, i * 8, 8));
    244     }
    245 
    246     npcm7xx_fiu_deselect(fiu);
    247 }
    248 
    249 static const MemoryRegionOps npcm7xx_fiu_flash_ops = {
    250     .read = npcm7xx_fiu_flash_read,
    251     .write = npcm7xx_fiu_flash_write,
    252     .endianness = DEVICE_LITTLE_ENDIAN,
    253     .valid = {
    254         .min_access_size = 1,
    255         .max_access_size = 8,
    256         .unaligned = true,
    257     },
    258 };
    259 
    260 /* Control register read handler. */
    261 static uint64_t npcm7xx_fiu_ctrl_read(void *opaque, hwaddr addr,
    262                                       unsigned int size)
    263 {
    264     hwaddr reg = addr / sizeof(uint32_t);
    265     NPCM7xxFIUState *s = opaque;
    266     uint32_t value;
    267 
    268     if (reg < NPCM7XX_FIU_NR_REGS) {
    269         value = s->regs[reg];
    270     } else {
    271         qemu_log_mask(LOG_GUEST_ERROR,
    272                       "%s: read from invalid offset 0x%" PRIx64 "\n",
    273                       DEVICE(s)->canonical_path, addr);
    274         value = 0;
    275     }
    276 
    277     trace_npcm7xx_fiu_ctrl_read(DEVICE(s)->canonical_path, addr, value);
    278 
    279     return value;
    280 }
    281 
    282 /* Send the specified number of address bytes from the UMA address register. */
    283 static void send_address(SSIBus *spi, unsigned int addsiz, uint32_t addr)
    284 {
    285     switch (addsiz) {
    286     case 4:
    287         ssi_transfer(spi, extract32(addr, 24, 8));
    288         /* fall through */
    289     case 3:
    290         ssi_transfer(spi, extract32(addr, 16, 8));
    291         /* fall through */
    292     case 2:
    293         ssi_transfer(spi, extract32(addr, 8, 8));
    294         /* fall through */
    295     case 1:
    296         ssi_transfer(spi, extract32(addr, 0, 8));
    297         /* fall through */
    298     case 0:
    299         break;
    300     }
    301 }
    302 
    303 /* Send the number of dummy bits specified in the UMA config register. */
    304 static void send_dummy_bits(SSIBus *spi, uint32_t uma_cfg, uint32_t uma_cmd)
    305 {
    306     unsigned int bits_per_clock = 1U << FIU_UMA_CFG_DBPCK(uma_cfg);
    307     unsigned int i;
    308 
    309     for (i = 0; i < FIU_UMA_CFG_DBSIZ(uma_cfg); i++) {
    310         /* Use bytes 0 and 1 first, then keep repeating byte 2 */
    311         unsigned int field = (i < 2) ? ((i + 1) * 8) : 24;
    312         unsigned int j;
    313 
    314         for (j = 0; j < 8; j += bits_per_clock) {
    315             ssi_transfer(spi, extract32(uma_cmd, field + j, bits_per_clock));
    316         }
    317     }
    318 }
    319 
    320 /* Perform a User-Mode Access transaction. */
    321 static void npcm7xx_fiu_uma_transaction(NPCM7xxFIUState *s)
    322 {
    323     uint32_t uma_cts = s->regs[NPCM7XX_FIU_UMA_CTS];
    324     uint32_t uma_cfg;
    325     unsigned int i;
    326 
    327     /* SW_CS means the CS is already forced low, so don't touch it. */
    328     if (uma_cts & FIU_UMA_CTS_SW_CS) {
    329         int cs_id = FIU_UMA_CTS_DEV_NUM(s->regs[NPCM7XX_FIU_UMA_CTS]);
    330         npcm7xx_fiu_select(s, cs_id);
    331     }
    332 
    333     /* Send command, if present. */
    334     uma_cfg = s->regs[NPCM7XX_FIU_UMA_CFG];
    335     if (FIU_UMA_CFG_CMDSIZ(uma_cfg) > 0) {
    336         ssi_transfer(s->spi, extract32(s->regs[NPCM7XX_FIU_UMA_CMD], 0, 8));
    337     }
    338 
    339     /* Send address, if present. */
    340     send_address(s->spi, FIU_UMA_CFG_ADDSIZ(uma_cfg),
    341                  s->regs[NPCM7XX_FIU_UMA_ADDR]);
    342 
    343     /* Write data, if present. */
    344     for (i = 0; i < FIU_UMA_CFG_WDATSIZ(uma_cfg); i++) {
    345         unsigned int reg =
    346             (i < 16) ? (NPCM7XX_FIU_UMA_DW0 + i / 4) : NPCM7XX_FIU_UMA_DW3;
    347         unsigned int field = (i % 4) * 8;
    348 
    349         ssi_transfer(s->spi, extract32(s->regs[reg], field, 8));
    350     }
    351 
    352     /* Send dummy bits, if present. */
    353     send_dummy_bits(s->spi, uma_cfg, s->regs[NPCM7XX_FIU_UMA_CMD]);
    354 
    355     /* Read data, if present. */
    356     for (i = 0; i < FIU_UMA_CFG_RDATSIZ(uma_cfg); i++) {
    357         unsigned int reg = NPCM7XX_FIU_UMA_DR0 + i / 4;
    358         unsigned int field = (i % 4) * 8;
    359         uint8_t c;
    360 
    361         c = ssi_transfer(s->spi, 0);
    362         if (reg <= NPCM7XX_FIU_UMA_DR3) {
    363             s->regs[reg] = deposit32(s->regs[reg], field, 8, c);
    364         }
    365     }
    366 
    367     /* Again, don't touch CS if the user is forcing it low. */
    368     if (uma_cts & FIU_UMA_CTS_SW_CS) {
    369         npcm7xx_fiu_deselect(s);
    370     }
    371 
    372     /* RDYST means a command has completed since it was cleared. */
    373     s->regs[NPCM7XX_FIU_UMA_CTS] |= FIU_UMA_CTS_RDYST;
    374     /* EXEC_DONE means Execute Command / Not Done, so clear it here. */
    375     s->regs[NPCM7XX_FIU_UMA_CTS] &= ~FIU_UMA_CTS_EXEC_DONE;
    376 }
    377 
    378 /* Control register write handler. */
    379 static void npcm7xx_fiu_ctrl_write(void *opaque, hwaddr addr, uint64_t v,
    380                                    unsigned int size)
    381 {
    382     hwaddr reg = addr / sizeof(uint32_t);
    383     NPCM7xxFIUState *s = opaque;
    384     uint32_t value = v;
    385 
    386     trace_npcm7xx_fiu_ctrl_write(DEVICE(s)->canonical_path, addr, value);
    387 
    388     switch (reg) {
    389     case NPCM7XX_FIU_UMA_CFG:
    390         if (s->regs[reg] & FIU_UMA_CFG_CMMLCK) {
    391             value &= ~FIU_UMA_CFG_CMMLCK_MASK;
    392             value |= (s->regs[reg] & FIU_UMA_CFG_CMMLCK_MASK);
    393         }
    394         /* fall through */
    395     case NPCM7XX_FIU_DRD_CFG:
    396     case NPCM7XX_FIU_DWR_CFG:
    397         if (s->regs[reg] & NPCM7XX_FIU_CFG_LCK) {
    398             qemu_log_mask(LOG_GUEST_ERROR,
    399                           "%s: write to locked register @ 0x%" PRIx64 "\n",
    400                           DEVICE(s)->canonical_path, addr);
    401             return;
    402         }
    403         s->regs[reg] = value;
    404         break;
    405 
    406     case NPCM7XX_FIU_UMA_CTS:
    407         if (value & FIU_UMA_CTS_RDYST) {
    408             value &= ~FIU_UMA_CTS_RDYST;
    409         } else {
    410             value |= s->regs[reg] & FIU_UMA_CTS_RDYST;
    411         }
    412         if ((s->regs[reg] ^ value) & FIU_UMA_CTS_SW_CS) {
    413             if (value & FIU_UMA_CTS_SW_CS) {
    414                 /*
    415                  * Don't drop CS if there's a transfer in progress, or we're
    416                  * about to start one.
    417                  */
    418                 if (!((value | s->regs[reg]) & FIU_UMA_CTS_EXEC_DONE)) {
    419                     npcm7xx_fiu_deselect(s);
    420                 }
    421             } else {
    422                 int cs_id = FIU_UMA_CTS_DEV_NUM(s->regs[NPCM7XX_FIU_UMA_CTS]);
    423                 npcm7xx_fiu_select(s, cs_id);
    424             }
    425         }
    426         s->regs[reg] = value | (s->regs[reg] & FIU_UMA_CTS_EXEC_DONE);
    427         if (value & FIU_UMA_CTS_EXEC_DONE) {
    428             npcm7xx_fiu_uma_transaction(s);
    429         }
    430         break;
    431 
    432     case NPCM7XX_FIU_UMA_DR0 ... NPCM7XX_FIU_UMA_DR3:
    433         qemu_log_mask(LOG_GUEST_ERROR,
    434                       "%s: write to read-only register @ 0x%" PRIx64 "\n",
    435                       DEVICE(s)->canonical_path, addr);
    436         return;
    437 
    438     case NPCM7XX_FIU_PRT_CFG:
    439     case NPCM7XX_FIU_PRT_CMD0 ... NPCM7XX_FIU_PRT_CMD9:
    440         qemu_log_mask(LOG_UNIMP, "%s: PRT is not implemented\n", __func__);
    441         break;
    442 
    443     case NPCM7XX_FIU_UMA_CMD:
    444     case NPCM7XX_FIU_UMA_ADDR:
    445     case NPCM7XX_FIU_UMA_DW0 ... NPCM7XX_FIU_UMA_DW3:
    446     case NPCM7XX_FIU_CFG:
    447         s->regs[reg] = value;
    448         break;
    449 
    450     default:
    451         qemu_log_mask(LOG_GUEST_ERROR,
    452                       "%s: write to invalid offset 0x%" PRIx64 "\n",
    453                       DEVICE(s)->canonical_path, addr);
    454         return;
    455     }
    456 }
    457 
    458 static const MemoryRegionOps npcm7xx_fiu_ctrl_ops = {
    459     .read = npcm7xx_fiu_ctrl_read,
    460     .write = npcm7xx_fiu_ctrl_write,
    461     .endianness = DEVICE_LITTLE_ENDIAN,
    462     .valid = {
    463         .min_access_size = 4,
    464         .max_access_size = 4,
    465         .unaligned = false,
    466     },
    467 };
    468 
    469 static void npcm7xx_fiu_enter_reset(Object *obj, ResetType type)
    470 {
    471     NPCM7xxFIUState *s = NPCM7XX_FIU(obj);
    472 
    473     trace_npcm7xx_fiu_enter_reset(DEVICE(obj)->canonical_path, type);
    474 
    475     memset(s->regs, 0, sizeof(s->regs));
    476 
    477     s->regs[NPCM7XX_FIU_DRD_CFG] = 0x0300100b;
    478     s->regs[NPCM7XX_FIU_DWR_CFG] = 0x03000002;
    479     s->regs[NPCM7XX_FIU_UMA_CFG] = 0x00000400;
    480     s->regs[NPCM7XX_FIU_UMA_CTS] = 0x00010000;
    481     s->regs[NPCM7XX_FIU_UMA_CMD] = 0x0000000b;
    482     s->regs[NPCM7XX_FIU_PRT_CFG] = 0x00000400;
    483     s->regs[NPCM7XX_FIU_CFG] = 0x0000000b;
    484 }
    485 
    486 static void npcm7xx_fiu_hold_reset(Object *obj)
    487 {
    488     NPCM7xxFIUState *s = NPCM7XX_FIU(obj);
    489     int i;
    490 
    491     trace_npcm7xx_fiu_hold_reset(DEVICE(obj)->canonical_path);
    492 
    493     for (i = 0; i < s->cs_count; i++) {
    494         qemu_irq_raise(s->cs_lines[i]);
    495     }
    496 }
    497 
    498 static void npcm7xx_fiu_realize(DeviceState *dev, Error **errp)
    499 {
    500     NPCM7xxFIUState *s = NPCM7XX_FIU(dev);
    501     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
    502     int i;
    503 
    504     if (s->cs_count <= 0) {
    505         error_setg(errp, "%s: %d chip selects specified, need at least one",
    506                    dev->canonical_path, s->cs_count);
    507         return;
    508     }
    509 
    510     s->spi = ssi_create_bus(dev, "spi");
    511     s->cs_lines = g_new0(qemu_irq, s->cs_count);
    512     qdev_init_gpio_out_named(DEVICE(s), s->cs_lines, "cs", s->cs_count);
    513     s->flash = g_new0(NPCM7xxFIUFlash, s->cs_count);
    514 
    515     /*
    516      * Register the control registers region first. It may be followed by one
    517      * or more direct flash access regions.
    518      */
    519     memory_region_init_io(&s->mmio, OBJECT(s), &npcm7xx_fiu_ctrl_ops, s, "ctrl",
    520                           NPCM7XX_FIU_CTRL_REGS_SIZE);
    521     sysbus_init_mmio(sbd, &s->mmio);
    522 
    523     for (i = 0; i < s->cs_count; i++) {
    524         NPCM7xxFIUFlash *flash = &s->flash[i];
    525         flash->fiu = s;
    526         memory_region_init_io(&flash->direct_access, OBJECT(s),
    527                               &npcm7xx_fiu_flash_ops, &s->flash[i], "flash",
    528                               NPCM7XX_FIU_FLASH_WINDOW_SIZE);
    529         sysbus_init_mmio(sbd, &flash->direct_access);
    530     }
    531 }
    532 
    533 static const VMStateDescription vmstate_npcm7xx_fiu = {
    534     .name = "npcm7xx-fiu",
    535     .version_id = 0,
    536     .minimum_version_id = 0,
    537     .fields = (VMStateField[]) {
    538         VMSTATE_INT32(active_cs, NPCM7xxFIUState),
    539         VMSTATE_UINT32_ARRAY(regs, NPCM7xxFIUState, NPCM7XX_FIU_NR_REGS),
    540         VMSTATE_END_OF_LIST(),
    541     },
    542 };
    543 
    544 static Property npcm7xx_fiu_properties[] = {
    545     DEFINE_PROP_INT32("cs-count", NPCM7xxFIUState, cs_count, 0),
    546     DEFINE_PROP_END_OF_LIST(),
    547 };
    548 
    549 static void npcm7xx_fiu_class_init(ObjectClass *klass, void *data)
    550 {
    551     ResettableClass *rc = RESETTABLE_CLASS(klass);
    552     DeviceClass *dc = DEVICE_CLASS(klass);
    553 
    554     QEMU_BUILD_BUG_ON(NPCM7XX_FIU_REGS_END > NPCM7XX_FIU_NR_REGS);
    555 
    556     dc->desc = "NPCM7xx Flash Interface Unit";
    557     dc->realize = npcm7xx_fiu_realize;
    558     dc->vmsd = &vmstate_npcm7xx_fiu;
    559     rc->phases.enter = npcm7xx_fiu_enter_reset;
    560     rc->phases.hold = npcm7xx_fiu_hold_reset;
    561     device_class_set_props(dc, npcm7xx_fiu_properties);
    562 }
    563 
    564 static const TypeInfo npcm7xx_fiu_types[] = {
    565     {
    566         .name = TYPE_NPCM7XX_FIU,
    567         .parent = TYPE_SYS_BUS_DEVICE,
    568         .instance_size = sizeof(NPCM7xxFIUState),
    569         .class_init = npcm7xx_fiu_class_init,
    570     },
    571 };
    572 DEFINE_TYPES(npcm7xx_fiu_types);