xref: /qemu/hw/nvram/nrf51_nvm.c (revision a27bd6c7)
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