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