1c0d4eb83SSteffen Görtz /* 2c0d4eb83SSteffen Görtz * Nordic Semiconductor nRF51 non-volatile memory 3c0d4eb83SSteffen Görtz * 4c0d4eb83SSteffen Görtz * It provides an interface to erase regions in flash memory. 5c0d4eb83SSteffen Görtz * Furthermore it provides the user and factory information registers. 6c0d4eb83SSteffen Görtz * 7c0d4eb83SSteffen Görtz * Reference Manual: http://infocenter.nordicsemi.com/pdf/nRF51_RM_v3.0.pdf 8c0d4eb83SSteffen Görtz * 9c0d4eb83SSteffen Görtz * See nRF51 reference manual and product sheet sections: 10c0d4eb83SSteffen Görtz * + Non-Volatile Memory Controller (NVMC) 11c0d4eb83SSteffen Görtz * + Factory Information Configuration Registers (FICR) 12c0d4eb83SSteffen Görtz * + User Information Configuration Registers (UICR) 13c0d4eb83SSteffen Görtz * 14c0d4eb83SSteffen Görtz * Copyright 2018 Steffen Görtz <contrib@steffen-goertz.de> 15c0d4eb83SSteffen Görtz * 16c0d4eb83SSteffen Görtz * This code is licensed under the GPL version 2 or later. See 17c0d4eb83SSteffen Görtz * the COPYING file in the top-level directory. 18c0d4eb83SSteffen Görtz */ 19c0d4eb83SSteffen Görtz 20c0d4eb83SSteffen Görtz #include "qemu/osdep.h" 21c0d4eb83SSteffen Görtz #include "qapi/error.h" 22c0d4eb83SSteffen Görtz #include "qemu/log.h" 230b8fa32fSMarkus Armbruster #include "qemu/module.h" 24c0d4eb83SSteffen Görtz #include "exec/address-spaces.h" 25c0d4eb83SSteffen Görtz #include "hw/arm/nrf51.h" 26c0d4eb83SSteffen Görtz #include "hw/nvram/nrf51_nvm.h" 27*a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h" 28d6454270SMarkus Armbruster #include "migration/vmstate.h" 29c0d4eb83SSteffen Görtz 30c0d4eb83SSteffen Görtz /* 31c0d4eb83SSteffen Görtz * FICR Registers Assignments 32c0d4eb83SSteffen Görtz * CODEPAGESIZE 0x010 33c0d4eb83SSteffen Görtz * CODESIZE 0x014 34c0d4eb83SSteffen Görtz * CLENR0 0x028 35c0d4eb83SSteffen Görtz * PPFC 0x02C 36c0d4eb83SSteffen Görtz * NUMRAMBLOCK 0x034 37c0d4eb83SSteffen Görtz * SIZERAMBLOCKS 0x038 38c0d4eb83SSteffen Görtz * SIZERAMBLOCK[0] 0x038 39c0d4eb83SSteffen Görtz * SIZERAMBLOCK[1] 0x03C 40c0d4eb83SSteffen Görtz * SIZERAMBLOCK[2] 0x040 41c0d4eb83SSteffen Görtz * SIZERAMBLOCK[3] 0x044 42c0d4eb83SSteffen Görtz * CONFIGID 0x05C 43c0d4eb83SSteffen Görtz * DEVICEID[0] 0x060 44c0d4eb83SSteffen Görtz * DEVICEID[1] 0x064 45c0d4eb83SSteffen Görtz * ER[0] 0x080 46c0d4eb83SSteffen Görtz * ER[1] 0x084 47c0d4eb83SSteffen Görtz * ER[2] 0x088 48c0d4eb83SSteffen Görtz * ER[3] 0x08C 49c0d4eb83SSteffen Görtz * IR[0] 0x090 50c0d4eb83SSteffen Görtz * IR[1] 0x094 51c0d4eb83SSteffen Görtz * IR[2] 0x098 52c0d4eb83SSteffen Görtz * IR[3] 0x09C 53c0d4eb83SSteffen Görtz * DEVICEADDRTYPE 0x0A0 54c0d4eb83SSteffen Görtz * DEVICEADDR[0] 0x0A4 55c0d4eb83SSteffen Görtz * DEVICEADDR[1] 0x0A8 56c0d4eb83SSteffen Görtz * OVERRIDEEN 0x0AC 57c0d4eb83SSteffen Görtz * NRF_1MBIT[0] 0x0B0 58c0d4eb83SSteffen Görtz * NRF_1MBIT[1] 0x0B4 59c0d4eb83SSteffen Görtz * NRF_1MBIT[2] 0x0B8 60c0d4eb83SSteffen Görtz * NRF_1MBIT[3] 0x0BC 61c0d4eb83SSteffen Görtz * NRF_1MBIT[4] 0x0C0 62c0d4eb83SSteffen Görtz * BLE_1MBIT[0] 0x0EC 63c0d4eb83SSteffen Görtz * BLE_1MBIT[1] 0x0F0 64c0d4eb83SSteffen Görtz * BLE_1MBIT[2] 0x0F4 65c0d4eb83SSteffen Görtz * BLE_1MBIT[3] 0x0F8 66c0d4eb83SSteffen Görtz * BLE_1MBIT[4] 0x0FC 67c0d4eb83SSteffen Görtz */ 68c0d4eb83SSteffen Görtz static const uint32_t ficr_content[64] = { 69c0d4eb83SSteffen Görtz 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000400, 70c0d4eb83SSteffen Görtz 0x00000100, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000002, 0x00002000, 71c0d4eb83SSteffen Görtz 0x00002000, 0x00002000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 72c0d4eb83SSteffen Görtz 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 73c0d4eb83SSteffen Görtz 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000003, 74c0d4eb83SSteffen Görtz 0x12345678, 0x9ABCDEF1, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 75c0d4eb83SSteffen Görtz 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 76c0d4eb83SSteffen Görtz 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 77c0d4eb83SSteffen Görtz 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 78c0d4eb83SSteffen Görtz 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 79c0d4eb83SSteffen Görtz 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 80c0d4eb83SSteffen Görtz 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 81c0d4eb83SSteffen Görtz 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF 82c0d4eb83SSteffen Görtz }; 83c0d4eb83SSteffen Görtz 84c0d4eb83SSteffen Görtz static uint64_t ficr_read(void *opaque, hwaddr offset, unsigned int size) 85c0d4eb83SSteffen Görtz { 86c0d4eb83SSteffen Görtz assert(offset < sizeof(ficr_content)); 87c0d4eb83SSteffen Görtz return ficr_content[offset / 4]; 88c0d4eb83SSteffen Görtz } 89c0d4eb83SSteffen Görtz 90c0d4eb83SSteffen Görtz static void ficr_write(void *opaque, hwaddr offset, uint64_t value, 91c0d4eb83SSteffen Görtz unsigned int size) 92c0d4eb83SSteffen Görtz { 93c0d4eb83SSteffen Görtz /* Intentionally do nothing */ 94c0d4eb83SSteffen Görtz } 95c0d4eb83SSteffen Görtz 96c0d4eb83SSteffen Görtz static const MemoryRegionOps ficr_ops = { 97c0d4eb83SSteffen Görtz .read = ficr_read, 98c0d4eb83SSteffen Görtz .write = ficr_write, 99c0d4eb83SSteffen Görtz .impl.min_access_size = 4, 100c0d4eb83SSteffen Görtz .impl.max_access_size = 4, 101c0d4eb83SSteffen Görtz .endianness = DEVICE_LITTLE_ENDIAN 102c0d4eb83SSteffen Görtz }; 103c0d4eb83SSteffen Görtz 104c0d4eb83SSteffen Görtz /* 105c0d4eb83SSteffen Görtz * UICR Registers Assignments 106c0d4eb83SSteffen Görtz * CLENR0 0x000 107c0d4eb83SSteffen Görtz * RBPCONF 0x004 108c0d4eb83SSteffen Görtz * XTALFREQ 0x008 109c0d4eb83SSteffen Görtz * FWID 0x010 110c0d4eb83SSteffen Görtz * BOOTLOADERADDR 0x014 111c0d4eb83SSteffen Görtz * NRFFW[0] 0x014 112c0d4eb83SSteffen Görtz * NRFFW[1] 0x018 113c0d4eb83SSteffen Görtz * NRFFW[2] 0x01C 114c0d4eb83SSteffen Görtz * NRFFW[3] 0x020 115c0d4eb83SSteffen Görtz * NRFFW[4] 0x024 116c0d4eb83SSteffen Görtz * NRFFW[5] 0x028 117c0d4eb83SSteffen Görtz * NRFFW[6] 0x02C 118c0d4eb83SSteffen Görtz * NRFFW[7] 0x030 119c0d4eb83SSteffen Görtz * NRFFW[8] 0x034 120c0d4eb83SSteffen Görtz * NRFFW[9] 0x038 121c0d4eb83SSteffen Görtz * NRFFW[10] 0x03C 122c0d4eb83SSteffen Görtz * NRFFW[11] 0x040 123c0d4eb83SSteffen Görtz * NRFFW[12] 0x044 124c0d4eb83SSteffen Görtz * NRFFW[13] 0x048 125c0d4eb83SSteffen Görtz * NRFFW[14] 0x04C 126c0d4eb83SSteffen Görtz * NRFHW[0] 0x050 127c0d4eb83SSteffen Görtz * NRFHW[1] 0x054 128c0d4eb83SSteffen Görtz * NRFHW[2] 0x058 129c0d4eb83SSteffen Görtz * NRFHW[3] 0x05C 130c0d4eb83SSteffen Görtz * NRFHW[4] 0x060 131c0d4eb83SSteffen Görtz * NRFHW[5] 0x064 132c0d4eb83SSteffen Görtz * NRFHW[6] 0x068 133c0d4eb83SSteffen Görtz * NRFHW[7] 0x06C 134c0d4eb83SSteffen Görtz * NRFHW[8] 0x070 135c0d4eb83SSteffen Görtz * NRFHW[9] 0x074 136c0d4eb83SSteffen Görtz * NRFHW[10] 0x078 137c0d4eb83SSteffen Görtz * NRFHW[11] 0x07C 138c0d4eb83SSteffen Görtz * CUSTOMER[0] 0x080 139c0d4eb83SSteffen Görtz * CUSTOMER[1] 0x084 140c0d4eb83SSteffen Görtz * CUSTOMER[2] 0x088 141c0d4eb83SSteffen Görtz * CUSTOMER[3] 0x08C 142c0d4eb83SSteffen Görtz * CUSTOMER[4] 0x090 143c0d4eb83SSteffen Görtz * CUSTOMER[5] 0x094 144c0d4eb83SSteffen Görtz * CUSTOMER[6] 0x098 145c0d4eb83SSteffen Görtz * CUSTOMER[7] 0x09C 146c0d4eb83SSteffen Görtz * CUSTOMER[8] 0x0A0 147c0d4eb83SSteffen Görtz * CUSTOMER[9] 0x0A4 148c0d4eb83SSteffen Görtz * CUSTOMER[10] 0x0A8 149c0d4eb83SSteffen Görtz * CUSTOMER[11] 0x0AC 150c0d4eb83SSteffen Görtz * CUSTOMER[12] 0x0B0 151c0d4eb83SSteffen Görtz * CUSTOMER[13] 0x0B4 152c0d4eb83SSteffen Görtz * CUSTOMER[14] 0x0B8 153c0d4eb83SSteffen Görtz * CUSTOMER[15] 0x0BC 154c0d4eb83SSteffen Görtz * CUSTOMER[16] 0x0C0 155c0d4eb83SSteffen Görtz * CUSTOMER[17] 0x0C4 156c0d4eb83SSteffen Görtz * CUSTOMER[18] 0x0C8 157c0d4eb83SSteffen Görtz * CUSTOMER[19] 0x0CC 158c0d4eb83SSteffen Görtz * CUSTOMER[20] 0x0D0 159c0d4eb83SSteffen Görtz * CUSTOMER[21] 0x0D4 160c0d4eb83SSteffen Görtz * CUSTOMER[22] 0x0D8 161c0d4eb83SSteffen Görtz * CUSTOMER[23] 0x0DC 162c0d4eb83SSteffen Görtz * CUSTOMER[24] 0x0E0 163c0d4eb83SSteffen Görtz * CUSTOMER[25] 0x0E4 164c0d4eb83SSteffen Görtz * CUSTOMER[26] 0x0E8 165c0d4eb83SSteffen Görtz * CUSTOMER[27] 0x0EC 166c0d4eb83SSteffen Görtz * CUSTOMER[28] 0x0F0 167c0d4eb83SSteffen Görtz * CUSTOMER[29] 0x0F4 168c0d4eb83SSteffen Görtz * CUSTOMER[30] 0x0F8 169c0d4eb83SSteffen Görtz * CUSTOMER[31] 0x0FC 170c0d4eb83SSteffen Görtz */ 171c0d4eb83SSteffen Görtz 172c0d4eb83SSteffen Görtz static uint64_t uicr_read(void *opaque, hwaddr offset, unsigned int size) 173c0d4eb83SSteffen Görtz { 174c0d4eb83SSteffen Görtz NRF51NVMState *s = NRF51_NVM(opaque); 175c0d4eb83SSteffen Görtz 176c0d4eb83SSteffen Görtz assert(offset < sizeof(s->uicr_content)); 177c0d4eb83SSteffen Görtz return s->uicr_content[offset / 4]; 178c0d4eb83SSteffen Görtz } 179c0d4eb83SSteffen Görtz 180c0d4eb83SSteffen Görtz static void uicr_write(void *opaque, hwaddr offset, uint64_t value, 181c0d4eb83SSteffen Görtz unsigned int size) 182c0d4eb83SSteffen Görtz { 183c0d4eb83SSteffen Görtz NRF51NVMState *s = NRF51_NVM(opaque); 184c0d4eb83SSteffen Görtz 185c0d4eb83SSteffen Görtz assert(offset < sizeof(s->uicr_content)); 186c0d4eb83SSteffen Görtz s->uicr_content[offset / 4] = value; 187c0d4eb83SSteffen Görtz } 188c0d4eb83SSteffen Görtz 189c0d4eb83SSteffen Görtz static const MemoryRegionOps uicr_ops = { 190c0d4eb83SSteffen Görtz .read = uicr_read, 191c0d4eb83SSteffen Görtz .write = uicr_write, 192c0d4eb83SSteffen Görtz .impl.min_access_size = 4, 193c0d4eb83SSteffen Görtz .impl.max_access_size = 4, 194c0d4eb83SSteffen Görtz .endianness = DEVICE_LITTLE_ENDIAN 195c0d4eb83SSteffen Görtz }; 196c0d4eb83SSteffen Görtz 197c0d4eb83SSteffen Görtz 198c0d4eb83SSteffen Görtz static uint64_t io_read(void *opaque, hwaddr offset, unsigned int size) 199c0d4eb83SSteffen Görtz { 200c0d4eb83SSteffen Görtz NRF51NVMState *s = NRF51_NVM(opaque); 201c0d4eb83SSteffen Görtz uint64_t r = 0; 202c0d4eb83SSteffen Görtz 203c0d4eb83SSteffen Görtz switch (offset) { 204c0d4eb83SSteffen Görtz case NRF51_NVMC_READY: 205c0d4eb83SSteffen Görtz r = NRF51_NVMC_READY_READY; 206c0d4eb83SSteffen Görtz break; 207c0d4eb83SSteffen Görtz case NRF51_NVMC_CONFIG: 208c0d4eb83SSteffen Görtz r = s->config; 209c0d4eb83SSteffen Görtz break; 210c0d4eb83SSteffen Görtz default: 211c0d4eb83SSteffen Görtz qemu_log_mask(LOG_GUEST_ERROR, 212c0d4eb83SSteffen Görtz "%s: bad read offset 0x%" HWADDR_PRIx "\n", __func__, offset); 213c0d4eb83SSteffen Görtz break; 214c0d4eb83SSteffen Görtz } 215c0d4eb83SSteffen Görtz 216c0d4eb83SSteffen Görtz return r; 217c0d4eb83SSteffen Görtz } 218c0d4eb83SSteffen Görtz 219c0d4eb83SSteffen Görtz static void io_write(void *opaque, hwaddr offset, uint64_t value, 220c0d4eb83SSteffen Görtz unsigned int size) 221c0d4eb83SSteffen Görtz { 222c0d4eb83SSteffen Görtz NRF51NVMState *s = NRF51_NVM(opaque); 223c0d4eb83SSteffen Görtz 224c0d4eb83SSteffen Görtz switch (offset) { 225c0d4eb83SSteffen Görtz case NRF51_NVMC_CONFIG: 226c0d4eb83SSteffen Görtz s->config = value & NRF51_NVMC_CONFIG_MASK; 227c0d4eb83SSteffen Görtz break; 228c0d4eb83SSteffen Görtz case NRF51_NVMC_ERASEPCR0: 229c0d4eb83SSteffen Görtz case NRF51_NVMC_ERASEPCR1: 230c0d4eb83SSteffen Görtz if (s->config & NRF51_NVMC_CONFIG_EEN) { 231c0d4eb83SSteffen Görtz /* Mask in-page sub address */ 232c0d4eb83SSteffen Görtz value &= ~(NRF51_PAGE_SIZE - 1); 233c0d4eb83SSteffen Görtz if (value <= (s->flash_size - NRF51_PAGE_SIZE)) { 234c0d4eb83SSteffen Görtz memset(s->storage + value, 0xFF, NRF51_PAGE_SIZE); 235c0d4eb83SSteffen Görtz memory_region_flush_rom_device(&s->flash, value, 236c0d4eb83SSteffen Görtz NRF51_PAGE_SIZE); 237c0d4eb83SSteffen Görtz } 238c0d4eb83SSteffen Görtz } else { 239c0d4eb83SSteffen Görtz qemu_log_mask(LOG_GUEST_ERROR, 240c0d4eb83SSteffen Görtz "%s: Flash erase at 0x%" HWADDR_PRIx" while flash not erasable.\n", 241c0d4eb83SSteffen Görtz __func__, offset); 242c0d4eb83SSteffen Görtz } 243c0d4eb83SSteffen Görtz break; 244c0d4eb83SSteffen Görtz case NRF51_NVMC_ERASEALL: 245c0d4eb83SSteffen Görtz if (value == NRF51_NVMC_ERASE) { 246c0d4eb83SSteffen Görtz if (s->config & NRF51_NVMC_CONFIG_EEN) { 247c0d4eb83SSteffen Görtz memset(s->storage, 0xFF, s->flash_size); 248c0d4eb83SSteffen Görtz memory_region_flush_rom_device(&s->flash, 0, s->flash_size); 249c0d4eb83SSteffen Görtz memset(s->uicr_content, 0xFF, sizeof(s->uicr_content)); 250c0d4eb83SSteffen Görtz } else { 251c0d4eb83SSteffen Görtz qemu_log_mask(LOG_GUEST_ERROR, "%s: Flash not erasable.\n", 252c0d4eb83SSteffen Görtz __func__); 253c0d4eb83SSteffen Görtz } 254c0d4eb83SSteffen Görtz } 255c0d4eb83SSteffen Görtz break; 256c0d4eb83SSteffen Görtz case NRF51_NVMC_ERASEUICR: 257c0d4eb83SSteffen Görtz if (value == NRF51_NVMC_ERASE) { 258c0d4eb83SSteffen Görtz memset(s->uicr_content, 0xFF, sizeof(s->uicr_content)); 259c0d4eb83SSteffen Görtz } 260c0d4eb83SSteffen Görtz break; 261c0d4eb83SSteffen Görtz 262c0d4eb83SSteffen Görtz default: 263c0d4eb83SSteffen Görtz qemu_log_mask(LOG_GUEST_ERROR, 264c0d4eb83SSteffen Görtz "%s: bad write offset 0x%" HWADDR_PRIx "\n", __func__, offset); 265c0d4eb83SSteffen Görtz } 266c0d4eb83SSteffen Görtz } 267c0d4eb83SSteffen Görtz 268c0d4eb83SSteffen Görtz static const MemoryRegionOps io_ops = { 269c0d4eb83SSteffen Görtz .read = io_read, 270c0d4eb83SSteffen Görtz .write = io_write, 271c0d4eb83SSteffen Görtz .impl.min_access_size = 4, 272c0d4eb83SSteffen Görtz .impl.max_access_size = 4, 273c0d4eb83SSteffen Görtz .endianness = DEVICE_LITTLE_ENDIAN, 274c0d4eb83SSteffen Görtz }; 275c0d4eb83SSteffen Görtz 276c0d4eb83SSteffen Görtz 277c0d4eb83SSteffen Görtz static void flash_write(void *opaque, hwaddr offset, uint64_t value, 278c0d4eb83SSteffen Görtz unsigned int size) 279c0d4eb83SSteffen Görtz { 280c0d4eb83SSteffen Görtz NRF51NVMState *s = NRF51_NVM(opaque); 281c0d4eb83SSteffen Görtz 282c0d4eb83SSteffen Görtz if (s->config & NRF51_NVMC_CONFIG_WEN) { 283c0d4eb83SSteffen Görtz uint32_t oldval; 284c0d4eb83SSteffen Görtz 285c0d4eb83SSteffen Görtz assert(offset + size <= s->flash_size); 286c0d4eb83SSteffen Görtz 287c0d4eb83SSteffen Görtz /* NOR Flash only allows bits to be flipped from 1's to 0's on write */ 288c0d4eb83SSteffen Görtz oldval = ldl_le_p(s->storage + offset); 289c0d4eb83SSteffen Görtz oldval &= value; 290c0d4eb83SSteffen Görtz stl_le_p(s->storage + offset, oldval); 291c0d4eb83SSteffen Görtz 292c0d4eb83SSteffen Görtz memory_region_flush_rom_device(&s->flash, offset, size); 293c0d4eb83SSteffen Görtz } else { 294c0d4eb83SSteffen Görtz qemu_log_mask(LOG_GUEST_ERROR, 295c0d4eb83SSteffen Görtz "%s: Flash write 0x%" HWADDR_PRIx" while flash not writable.\n", 296c0d4eb83SSteffen Görtz __func__, offset); 297c0d4eb83SSteffen Görtz } 298c0d4eb83SSteffen Görtz } 299c0d4eb83SSteffen Görtz 300c0d4eb83SSteffen Görtz 301c0d4eb83SSteffen Görtz 302c0d4eb83SSteffen Görtz static const MemoryRegionOps flash_ops = { 303c0d4eb83SSteffen Görtz .write = flash_write, 304c0d4eb83SSteffen Görtz .valid.min_access_size = 4, 305c0d4eb83SSteffen Görtz .valid.max_access_size = 4, 306c0d4eb83SSteffen Görtz .endianness = DEVICE_LITTLE_ENDIAN, 307c0d4eb83SSteffen Görtz }; 308c0d4eb83SSteffen Görtz 309c0d4eb83SSteffen Görtz static void nrf51_nvm_init(Object *obj) 310c0d4eb83SSteffen Görtz { 311c0d4eb83SSteffen Görtz NRF51NVMState *s = NRF51_NVM(obj); 312c0d4eb83SSteffen Görtz SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 313c0d4eb83SSteffen Görtz 314c0d4eb83SSteffen Görtz memory_region_init_io(&s->mmio, obj, &io_ops, s, "nrf51_soc.nvmc", 315c0d4eb83SSteffen Görtz NRF51_NVMC_SIZE); 316c0d4eb83SSteffen Görtz sysbus_init_mmio(sbd, &s->mmio); 317c0d4eb83SSteffen Görtz 318c0d4eb83SSteffen Görtz memory_region_init_io(&s->ficr, obj, &ficr_ops, s, "nrf51_soc.ficr", 319c0d4eb83SSteffen Görtz sizeof(ficr_content)); 320c0d4eb83SSteffen Görtz sysbus_init_mmio(sbd, &s->ficr); 321c0d4eb83SSteffen Görtz 322c0d4eb83SSteffen Görtz memory_region_init_io(&s->uicr, obj, &uicr_ops, s, "nrf51_soc.uicr", 323c0d4eb83SSteffen Görtz sizeof(s->uicr_content)); 324c0d4eb83SSteffen Görtz sysbus_init_mmio(sbd, &s->uicr); 325c0d4eb83SSteffen Görtz } 326c0d4eb83SSteffen Görtz 327c0d4eb83SSteffen Görtz static void nrf51_nvm_realize(DeviceState *dev, Error **errp) 328c0d4eb83SSteffen Görtz { 329c0d4eb83SSteffen Görtz NRF51NVMState *s = NRF51_NVM(dev); 330c0d4eb83SSteffen Görtz Error *err = NULL; 331c0d4eb83SSteffen Görtz 332c0d4eb83SSteffen Görtz memory_region_init_rom_device(&s->flash, OBJECT(dev), &flash_ops, s, 333c0d4eb83SSteffen Görtz "nrf51_soc.flash", s->flash_size, &err); 334c0d4eb83SSteffen Görtz if (err) { 335c0d4eb83SSteffen Görtz error_propagate(errp, err); 336c0d4eb83SSteffen Görtz return; 337c0d4eb83SSteffen Görtz } 338c0d4eb83SSteffen Görtz 339c0d4eb83SSteffen Görtz s->storage = memory_region_get_ram_ptr(&s->flash); 340c0d4eb83SSteffen Görtz sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->flash); 341c0d4eb83SSteffen Görtz } 342c0d4eb83SSteffen Görtz 343c0d4eb83SSteffen Görtz static void nrf51_nvm_reset(DeviceState *dev) 344c0d4eb83SSteffen Görtz { 345c0d4eb83SSteffen Görtz NRF51NVMState *s = NRF51_NVM(dev); 346c0d4eb83SSteffen Görtz 347c0d4eb83SSteffen Görtz s->config = 0x00; 348c0d4eb83SSteffen Görtz memset(s->uicr_content, 0xFF, sizeof(s->uicr_content)); 349c0d4eb83SSteffen Görtz } 350c0d4eb83SSteffen Görtz 351c0d4eb83SSteffen Görtz static Property nrf51_nvm_properties[] = { 352c0d4eb83SSteffen Görtz DEFINE_PROP_UINT32("flash-size", NRF51NVMState, flash_size, 0x40000), 353c0d4eb83SSteffen Görtz DEFINE_PROP_END_OF_LIST(), 354c0d4eb83SSteffen Görtz }; 355c0d4eb83SSteffen Görtz 356c0d4eb83SSteffen Görtz static const VMStateDescription vmstate_nvm = { 357c0d4eb83SSteffen Görtz .name = "nrf51_soc.nvm", 358c0d4eb83SSteffen Görtz .version_id = 1, 359c0d4eb83SSteffen Görtz .minimum_version_id = 1, 360c0d4eb83SSteffen Görtz .fields = (VMStateField[]) { 361c0d4eb83SSteffen Görtz VMSTATE_UINT32_ARRAY(uicr_content, NRF51NVMState, 362c0d4eb83SSteffen Görtz NRF51_UICR_FIXTURE_SIZE), 363c0d4eb83SSteffen Görtz VMSTATE_UINT32(config, NRF51NVMState), 364c0d4eb83SSteffen Görtz VMSTATE_END_OF_LIST() 365c0d4eb83SSteffen Görtz } 366c0d4eb83SSteffen Görtz }; 367c0d4eb83SSteffen Görtz 368c0d4eb83SSteffen Görtz static void nrf51_nvm_class_init(ObjectClass *klass, void *data) 369c0d4eb83SSteffen Görtz { 370c0d4eb83SSteffen Görtz DeviceClass *dc = DEVICE_CLASS(klass); 371c0d4eb83SSteffen Görtz 372c0d4eb83SSteffen Görtz dc->props = nrf51_nvm_properties; 373c0d4eb83SSteffen Görtz dc->vmsd = &vmstate_nvm; 374c0d4eb83SSteffen Görtz dc->realize = nrf51_nvm_realize; 375c0d4eb83SSteffen Görtz dc->reset = nrf51_nvm_reset; 376c0d4eb83SSteffen Görtz } 377c0d4eb83SSteffen Görtz 378c0d4eb83SSteffen Görtz static const TypeInfo nrf51_nvm_info = { 379c0d4eb83SSteffen Görtz .name = TYPE_NRF51_NVM, 380c0d4eb83SSteffen Görtz .parent = TYPE_SYS_BUS_DEVICE, 381c0d4eb83SSteffen Görtz .instance_size = sizeof(NRF51NVMState), 382c0d4eb83SSteffen Görtz .instance_init = nrf51_nvm_init, 383c0d4eb83SSteffen Görtz .class_init = nrf51_nvm_class_init 384c0d4eb83SSteffen Görtz }; 385c0d4eb83SSteffen Görtz 386c0d4eb83SSteffen Görtz static void nrf51_nvm_register_types(void) 387c0d4eb83SSteffen Görtz { 388c0d4eb83SSteffen Görtz type_register_static(&nrf51_nvm_info); 389c0d4eb83SSteffen Görtz } 390c0d4eb83SSteffen Görtz 391c0d4eb83SSteffen Görtz type_init(nrf51_nvm_register_types) 392