xref: /qemu/hw/arm/npcm8xx.c (revision 12d1a768bdfea6e27a3a829228840d72507613a1)
1ae0c4d1aSHao Wu /*
2ae0c4d1aSHao Wu  * Nuvoton NPCM8xx SoC family.
3ae0c4d1aSHao Wu  *
4ae0c4d1aSHao Wu  * Copyright 2022 Google LLC
5ae0c4d1aSHao Wu  *
6ae0c4d1aSHao Wu  * This program is free software; you can redistribute it and/or modify it
7ae0c4d1aSHao Wu  * under the terms of the GNU General Public License as published by the
8ae0c4d1aSHao Wu  * Free Software Foundation; either version 2 of the License, or
9ae0c4d1aSHao Wu  * (at your option) any later version.
10ae0c4d1aSHao Wu  *
11ae0c4d1aSHao Wu  * This program is distributed in the hope that it will be useful, but WITHOUT
12ae0c4d1aSHao Wu  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13ae0c4d1aSHao Wu  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14ae0c4d1aSHao Wu  * for more details.
15ae0c4d1aSHao Wu  */
16ae0c4d1aSHao Wu 
17ae0c4d1aSHao Wu #include "qemu/osdep.h"
18ae0c4d1aSHao Wu 
19ae0c4d1aSHao Wu #include "hw/boards.h"
20ae0c4d1aSHao Wu #include "hw/arm/boot.h"
21ae0c4d1aSHao Wu #include "hw/arm/bsa.h"
22ae0c4d1aSHao Wu #include "hw/arm/npcm8xx.h"
23ae0c4d1aSHao Wu #include "hw/char/serial-mm.h"
24ae0c4d1aSHao Wu #include "hw/intc/arm_gic.h"
25ae0c4d1aSHao Wu #include "hw/loader.h"
26ae0c4d1aSHao Wu #include "hw/misc/unimp.h"
27ae0c4d1aSHao Wu #include "hw/qdev-clock.h"
28ae0c4d1aSHao Wu #include "hw/qdev-properties.h"
29ae0c4d1aSHao Wu #include "qapi/error.h"
30ae0c4d1aSHao Wu #include "qemu/units.h"
31ae0c4d1aSHao Wu #include "system/system.h"
32ae0c4d1aSHao Wu 
33ae0c4d1aSHao Wu /*
34ae0c4d1aSHao Wu  * This covers the whole MMIO space. We'll use this to catch any MMIO accesses
35ae0c4d1aSHao Wu  * that aren't handled by a device.
36ae0c4d1aSHao Wu  */
37ae0c4d1aSHao Wu #define NPCM8XX_MMIO_BA         0x80000000
38ae0c4d1aSHao Wu #define NPCM8XX_MMIO_SZ         0x7ffd0000
39ae0c4d1aSHao Wu 
40ae0c4d1aSHao Wu /* OTP fuse array */
41ae0c4d1aSHao Wu #define NPCM8XX_OTP_BA          0xf0189000
42ae0c4d1aSHao Wu 
43ae0c4d1aSHao Wu /* GIC Distributor */
44ae0c4d1aSHao Wu #define NPCM8XX_GICD_BA         0xdfff9000
45ae0c4d1aSHao Wu #define NPCM8XX_GICC_BA         0xdfffa000
46ae0c4d1aSHao Wu 
47ae0c4d1aSHao Wu /* Core system modules. */
48ae0c4d1aSHao Wu #define NPCM8XX_CPUP_BA         0xf03fe000
49ae0c4d1aSHao Wu #define NPCM8XX_GCR_BA          0xf0800000
50ae0c4d1aSHao Wu #define NPCM8XX_CLK_BA          0xf0801000
51ae0c4d1aSHao Wu #define NPCM8XX_MC_BA           0xf0824000
52ae0c4d1aSHao Wu #define NPCM8XX_RNG_BA          0xf000b000
53ae0c4d1aSHao Wu 
54ae0c4d1aSHao Wu /* ADC Module */
55ae0c4d1aSHao Wu #define NPCM8XX_ADC_BA          0xf000c000
56ae0c4d1aSHao Wu 
57ae0c4d1aSHao Wu /* Internal AHB SRAM */
58ae0c4d1aSHao Wu #define NPCM8XX_RAM3_BA         0xc0008000
59ae0c4d1aSHao Wu #define NPCM8XX_RAM3_SZ         (4 * KiB)
60ae0c4d1aSHao Wu 
61ae0c4d1aSHao Wu /* Memory blocks at the end of the address space */
62ae0c4d1aSHao Wu #define NPCM8XX_RAM2_BA         0xfffb0000
63ae0c4d1aSHao Wu #define NPCM8XX_RAM2_SZ         (256 * KiB)
64ae0c4d1aSHao Wu #define NPCM8XX_ROM_BA          0xffff0100
65ae0c4d1aSHao Wu #define NPCM8XX_ROM_SZ          (64 * KiB)
66ae0c4d1aSHao Wu 
67ae0c4d1aSHao Wu /* SDHCI Modules */
68ae0c4d1aSHao Wu #define NPCM8XX_MMC_BA          0xf0842000
69ae0c4d1aSHao Wu 
70ae0c4d1aSHao Wu /* Run PLL1 at 1600 MHz */
71ae0c4d1aSHao Wu #define NPCM8XX_PLLCON1_FIXUP_VAL   0x00402101
72ae0c4d1aSHao Wu /* Run the CPU from PLL1 and UART from PLL2 */
73ae0c4d1aSHao Wu #define NPCM8XX_CLKSEL_FIXUP_VAL    0x004aaba9
74ae0c4d1aSHao Wu 
75ae0c4d1aSHao Wu /* Clock configuration values to be fixed up when bypassing bootloader */
76ae0c4d1aSHao Wu 
77ae0c4d1aSHao Wu /*
78ae0c4d1aSHao Wu  * Interrupt lines going into the GIC. This does not include internal Cortex-A35
79ae0c4d1aSHao Wu  * interrupts.
80ae0c4d1aSHao Wu  */
81ae0c4d1aSHao Wu enum NPCM8xxInterrupt {
82ae0c4d1aSHao Wu     NPCM8XX_ADC_IRQ             = 0,
83ae0c4d1aSHao Wu     NPCM8XX_PECI_IRQ            = 6,
84ae0c4d1aSHao Wu     NPCM8XX_KCS_HIB_IRQ         = 9,
85ae0c4d1aSHao Wu     NPCM8XX_MMC_IRQ             = 26,
86ae0c4d1aSHao Wu     NPCM8XX_TIMER0_IRQ          = 32,   /* Timer Module 0 */
87ae0c4d1aSHao Wu     NPCM8XX_TIMER1_IRQ,
88ae0c4d1aSHao Wu     NPCM8XX_TIMER2_IRQ,
89ae0c4d1aSHao Wu     NPCM8XX_TIMER3_IRQ,
90ae0c4d1aSHao Wu     NPCM8XX_TIMER4_IRQ,
91ae0c4d1aSHao Wu     NPCM8XX_TIMER5_IRQ,                 /* Timer Module 1 */
92ae0c4d1aSHao Wu     NPCM8XX_TIMER6_IRQ,
93ae0c4d1aSHao Wu     NPCM8XX_TIMER7_IRQ,
94ae0c4d1aSHao Wu     NPCM8XX_TIMER8_IRQ,
95ae0c4d1aSHao Wu     NPCM8XX_TIMER9_IRQ,
96ae0c4d1aSHao Wu     NPCM8XX_TIMER10_IRQ,                /* Timer Module 2 */
97ae0c4d1aSHao Wu     NPCM8XX_TIMER11_IRQ,
98ae0c4d1aSHao Wu     NPCM8XX_TIMER12_IRQ,
99ae0c4d1aSHao Wu     NPCM8XX_TIMER13_IRQ,
100ae0c4d1aSHao Wu     NPCM8XX_TIMER14_IRQ,
101ae0c4d1aSHao Wu     NPCM8XX_WDG0_IRQ            = 47,   /* Timer Module 0 Watchdog */
102ae0c4d1aSHao Wu     NPCM8XX_WDG1_IRQ,                   /* Timer Module 1 Watchdog */
103ae0c4d1aSHao Wu     NPCM8XX_WDG2_IRQ,                   /* Timer Module 2 Watchdog */
104ae0c4d1aSHao Wu     NPCM8XX_EHCI1_IRQ           = 61,
105ae0c4d1aSHao Wu     NPCM8XX_OHCI1_IRQ,
106ae0c4d1aSHao Wu     NPCM8XX_EHCI2_IRQ,
107ae0c4d1aSHao Wu     NPCM8XX_OHCI2_IRQ,
108ae0c4d1aSHao Wu     NPCM8XX_PWM0_IRQ            = 93,   /* PWM module 0 */
109ae0c4d1aSHao Wu     NPCM8XX_PWM1_IRQ,                   /* PWM module 1 */
110ae0c4d1aSHao Wu     NPCM8XX_MFT0_IRQ            = 96,   /* MFT module 0 */
111ae0c4d1aSHao Wu     NPCM8XX_MFT1_IRQ,                   /* MFT module 1 */
112ae0c4d1aSHao Wu     NPCM8XX_MFT2_IRQ,                   /* MFT module 2 */
113ae0c4d1aSHao Wu     NPCM8XX_MFT3_IRQ,                   /* MFT module 3 */
114ae0c4d1aSHao Wu     NPCM8XX_MFT4_IRQ,                   /* MFT module 4 */
115ae0c4d1aSHao Wu     NPCM8XX_MFT5_IRQ,                   /* MFT module 5 */
116ae0c4d1aSHao Wu     NPCM8XX_MFT6_IRQ,                   /* MFT module 6 */
117ae0c4d1aSHao Wu     NPCM8XX_MFT7_IRQ,                   /* MFT module 7 */
118ae0c4d1aSHao Wu     NPCM8XX_PCI_MBOX1_IRQ       = 105,
119ae0c4d1aSHao Wu     NPCM8XX_PCI_MBOX2_IRQ,
120ae0c4d1aSHao Wu     NPCM8XX_GPIO0_IRQ           = 116,
121ae0c4d1aSHao Wu     NPCM8XX_GPIO1_IRQ,
122ae0c4d1aSHao Wu     NPCM8XX_GPIO2_IRQ,
123ae0c4d1aSHao Wu     NPCM8XX_GPIO3_IRQ,
124ae0c4d1aSHao Wu     NPCM8XX_GPIO4_IRQ,
125ae0c4d1aSHao Wu     NPCM8XX_GPIO5_IRQ,
126ae0c4d1aSHao Wu     NPCM8XX_GPIO6_IRQ,
127ae0c4d1aSHao Wu     NPCM8XX_GPIO7_IRQ,
128ae0c4d1aSHao Wu     NPCM8XX_SMBUS0_IRQ          = 128,
129ae0c4d1aSHao Wu     NPCM8XX_SMBUS1_IRQ,
130ae0c4d1aSHao Wu     NPCM8XX_SMBUS2_IRQ,
131ae0c4d1aSHao Wu     NPCM8XX_SMBUS3_IRQ,
132ae0c4d1aSHao Wu     NPCM8XX_SMBUS4_IRQ,
133ae0c4d1aSHao Wu     NPCM8XX_SMBUS5_IRQ,
134ae0c4d1aSHao Wu     NPCM8XX_SMBUS6_IRQ,
135ae0c4d1aSHao Wu     NPCM8XX_SMBUS7_IRQ,
136ae0c4d1aSHao Wu     NPCM8XX_SMBUS8_IRQ,
137ae0c4d1aSHao Wu     NPCM8XX_SMBUS9_IRQ,
138ae0c4d1aSHao Wu     NPCM8XX_SMBUS10_IRQ,
139ae0c4d1aSHao Wu     NPCM8XX_SMBUS11_IRQ,
140ae0c4d1aSHao Wu     NPCM8XX_SMBUS12_IRQ,
141ae0c4d1aSHao Wu     NPCM8XX_SMBUS13_IRQ,
142ae0c4d1aSHao Wu     NPCM8XX_SMBUS14_IRQ,
143ae0c4d1aSHao Wu     NPCM8XX_SMBUS15_IRQ,
144ae0c4d1aSHao Wu     NPCM8XX_SMBUS16_IRQ,
145ae0c4d1aSHao Wu     NPCM8XX_SMBUS17_IRQ,
146ae0c4d1aSHao Wu     NPCM8XX_SMBUS18_IRQ,
147ae0c4d1aSHao Wu     NPCM8XX_SMBUS19_IRQ,
148ae0c4d1aSHao Wu     NPCM8XX_SMBUS20_IRQ,
149ae0c4d1aSHao Wu     NPCM8XX_SMBUS21_IRQ,
150ae0c4d1aSHao Wu     NPCM8XX_SMBUS22_IRQ,
151ae0c4d1aSHao Wu     NPCM8XX_SMBUS23_IRQ,
152ae0c4d1aSHao Wu     NPCM8XX_SMBUS24_IRQ,
153ae0c4d1aSHao Wu     NPCM8XX_SMBUS25_IRQ,
154ae0c4d1aSHao Wu     NPCM8XX_SMBUS26_IRQ,
155ae0c4d1aSHao Wu     NPCM8XX_UART0_IRQ           = 192,
156ae0c4d1aSHao Wu     NPCM8XX_UART1_IRQ,
157ae0c4d1aSHao Wu     NPCM8XX_UART2_IRQ,
158ae0c4d1aSHao Wu     NPCM8XX_UART3_IRQ,
159ae0c4d1aSHao Wu     NPCM8XX_UART4_IRQ,
160ae0c4d1aSHao Wu     NPCM8XX_UART5_IRQ,
161ae0c4d1aSHao Wu     NPCM8XX_UART6_IRQ,
162ae0c4d1aSHao Wu };
163ae0c4d1aSHao Wu 
164ae0c4d1aSHao Wu /* Total number of GIC interrupts, including internal Cortex-A35 interrupts. */
165ae0c4d1aSHao Wu #define NPCM8XX_NUM_IRQ         (288)
166ae0c4d1aSHao Wu #define NPCM8XX_PPI_BASE(cpu)   \
167ae0c4d1aSHao Wu     ((NPCM8XX_NUM_IRQ - GIC_INTERNAL) + (cpu) * GIC_INTERNAL)
168ae0c4d1aSHao Wu 
169ae0c4d1aSHao Wu /* Register base address for each Timer Module */
170ae0c4d1aSHao Wu static const hwaddr npcm8xx_tim_addr[] = {
171ae0c4d1aSHao Wu     0xf0008000,
172ae0c4d1aSHao Wu     0xf0009000,
173ae0c4d1aSHao Wu     0xf000a000,
174ae0c4d1aSHao Wu };
175ae0c4d1aSHao Wu 
176ae0c4d1aSHao Wu /* Register base address for each 16550 UART */
177ae0c4d1aSHao Wu static const hwaddr npcm8xx_uart_addr[] = {
178ae0c4d1aSHao Wu     0xf0000000,
179ae0c4d1aSHao Wu     0xf0001000,
180ae0c4d1aSHao Wu     0xf0002000,
181ae0c4d1aSHao Wu     0xf0003000,
182ae0c4d1aSHao Wu     0xf0004000,
183ae0c4d1aSHao Wu     0xf0005000,
184ae0c4d1aSHao Wu     0xf0006000,
185ae0c4d1aSHao Wu };
186ae0c4d1aSHao Wu 
187ae0c4d1aSHao Wu /* Direct memory-mapped access to SPI0 CS0-1. */
188ae0c4d1aSHao Wu static const hwaddr npcm8xx_fiu0_flash_addr[] = {
189ae0c4d1aSHao Wu     0x80000000, /* CS0 */
190ae0c4d1aSHao Wu     0x88000000, /* CS1 */
191ae0c4d1aSHao Wu };
192ae0c4d1aSHao Wu 
193ae0c4d1aSHao Wu /* Direct memory-mapped access to SPI1 CS0-3. */
194ae0c4d1aSHao Wu static const hwaddr npcm8xx_fiu1_flash_addr[] = {
195ae0c4d1aSHao Wu     0x90000000, /* CS0 */
196ae0c4d1aSHao Wu     0x91000000, /* CS1 */
197ae0c4d1aSHao Wu     0x92000000, /* CS2 */
198ae0c4d1aSHao Wu     0x93000000, /* CS3 */
199ae0c4d1aSHao Wu };
200ae0c4d1aSHao Wu 
201ae0c4d1aSHao Wu /* Direct memory-mapped access to SPI3 CS0-3. */
202ae0c4d1aSHao Wu static const hwaddr npcm8xx_fiu3_flash_addr[] = {
203ae0c4d1aSHao Wu     0xa0000000, /* CS0 */
204ae0c4d1aSHao Wu     0xa8000000, /* CS1 */
205ae0c4d1aSHao Wu     0xb0000000, /* CS2 */
206ae0c4d1aSHao Wu     0xb8000000, /* CS3 */
207ae0c4d1aSHao Wu };
208ae0c4d1aSHao Wu 
209ae0c4d1aSHao Wu /* Register base address for each PWM Module */
210ae0c4d1aSHao Wu static const hwaddr npcm8xx_pwm_addr[] = {
211ae0c4d1aSHao Wu     0xf0103000,
212ae0c4d1aSHao Wu     0xf0104000,
213ae0c4d1aSHao Wu     0xf0105000,
214ae0c4d1aSHao Wu };
215ae0c4d1aSHao Wu 
216ae0c4d1aSHao Wu /* Register base address for each MFT Module */
217ae0c4d1aSHao Wu static const hwaddr npcm8xx_mft_addr[] = {
218ae0c4d1aSHao Wu     0xf0180000,
219ae0c4d1aSHao Wu     0xf0181000,
220ae0c4d1aSHao Wu     0xf0182000,
221ae0c4d1aSHao Wu     0xf0183000,
222ae0c4d1aSHao Wu     0xf0184000,
223ae0c4d1aSHao Wu     0xf0185000,
224ae0c4d1aSHao Wu     0xf0186000,
225ae0c4d1aSHao Wu     0xf0187000,
226ae0c4d1aSHao Wu };
227ae0c4d1aSHao Wu 
228ae0c4d1aSHao Wu /* Direct memory-mapped access to each SMBus Module. */
229ae0c4d1aSHao Wu static const hwaddr npcm8xx_smbus_addr[] = {
230ae0c4d1aSHao Wu     0xf0080000,
231ae0c4d1aSHao Wu     0xf0081000,
232ae0c4d1aSHao Wu     0xf0082000,
233ae0c4d1aSHao Wu     0xf0083000,
234ae0c4d1aSHao Wu     0xf0084000,
235ae0c4d1aSHao Wu     0xf0085000,
236ae0c4d1aSHao Wu     0xf0086000,
237ae0c4d1aSHao Wu     0xf0087000,
238ae0c4d1aSHao Wu     0xf0088000,
239ae0c4d1aSHao Wu     0xf0089000,
240ae0c4d1aSHao Wu     0xf008a000,
241ae0c4d1aSHao Wu     0xf008b000,
242ae0c4d1aSHao Wu     0xf008c000,
243ae0c4d1aSHao Wu     0xf008d000,
244ae0c4d1aSHao Wu     0xf008e000,
245ae0c4d1aSHao Wu     0xf008f000,
246ae0c4d1aSHao Wu     0xfff00000,
247ae0c4d1aSHao Wu     0xfff01000,
248ae0c4d1aSHao Wu     0xfff02000,
249ae0c4d1aSHao Wu     0xfff03000,
250ae0c4d1aSHao Wu     0xfff04000,
251ae0c4d1aSHao Wu     0xfff05000,
252ae0c4d1aSHao Wu     0xfff06000,
253ae0c4d1aSHao Wu     0xfff07000,
254ae0c4d1aSHao Wu     0xfff08000,
255ae0c4d1aSHao Wu     0xfff09000,
256ae0c4d1aSHao Wu     0xfff0a000,
257ae0c4d1aSHao Wu };
258ae0c4d1aSHao Wu 
259ae0c4d1aSHao Wu /* Register base address for each USB host EHCI registers */
260ae0c4d1aSHao Wu static const hwaddr npcm8xx_ehci_addr[] = {
261ae0c4d1aSHao Wu     0xf0828100,
262ae0c4d1aSHao Wu     0xf082a100,
263ae0c4d1aSHao Wu };
264ae0c4d1aSHao Wu 
265ae0c4d1aSHao Wu /* Register base address for each USB host OHCI registers */
266ae0c4d1aSHao Wu static const hwaddr npcm8xx_ohci_addr[] = {
267ae0c4d1aSHao Wu     0xf0829000,
268ae0c4d1aSHao Wu     0xf082b000,
269ae0c4d1aSHao Wu };
270ae0c4d1aSHao Wu 
271ae0c4d1aSHao Wu static const struct {
272ae0c4d1aSHao Wu     hwaddr regs_addr;
273ae0c4d1aSHao Wu     uint32_t reset_pu;
274ae0c4d1aSHao Wu     uint32_t reset_pd;
275ae0c4d1aSHao Wu     uint32_t reset_osrc;
276ae0c4d1aSHao Wu     uint32_t reset_odsc;
277ae0c4d1aSHao Wu } npcm8xx_gpio[] = {
278ae0c4d1aSHao Wu     {
279ae0c4d1aSHao Wu         .regs_addr = 0xf0010000,
280ae0c4d1aSHao Wu         .reset_pu = 0x00000300,
281ae0c4d1aSHao Wu         .reset_pd = 0x000f0000,
282ae0c4d1aSHao Wu     }, {
283ae0c4d1aSHao Wu         .regs_addr = 0xf0011000,
284ae0c4d1aSHao Wu         .reset_pu = 0xe0fefe01,
285ae0c4d1aSHao Wu         .reset_pd = 0x07000000,
286ae0c4d1aSHao Wu     }, {
287ae0c4d1aSHao Wu         .regs_addr = 0xf0012000,
288ae0c4d1aSHao Wu         .reset_pu = 0xc00fffff,
289ae0c4d1aSHao Wu         .reset_pd = 0x3ff00000,
290ae0c4d1aSHao Wu     }, {
291ae0c4d1aSHao Wu         .regs_addr = 0xf0013000,
292ae0c4d1aSHao Wu         .reset_pd = 0x00003000,
293ae0c4d1aSHao Wu     }, {
294ae0c4d1aSHao Wu         .regs_addr = 0xf0014000,
295ae0c4d1aSHao Wu         .reset_pu = 0xffff0000,
296ae0c4d1aSHao Wu     }, {
297ae0c4d1aSHao Wu         .regs_addr = 0xf0015000,
298ae0c4d1aSHao Wu         .reset_pu = 0xff8387fe,
299ae0c4d1aSHao Wu         .reset_pd = 0x007c0001,
300ae0c4d1aSHao Wu         .reset_osrc = 0x08000000,
301ae0c4d1aSHao Wu     }, {
302ae0c4d1aSHao Wu         .regs_addr = 0xf0016000,
303ae0c4d1aSHao Wu         .reset_pu = 0x00000801,
304ae0c4d1aSHao Wu         .reset_pd = 0x00000302,
305ae0c4d1aSHao Wu     }, {
306ae0c4d1aSHao Wu         .regs_addr = 0xf0017000,
307ae0c4d1aSHao Wu         .reset_pu = 0x000002ff,
308ae0c4d1aSHao Wu         .reset_pd = 0x00000c00,
309ae0c4d1aSHao Wu     },
310ae0c4d1aSHao Wu };
311ae0c4d1aSHao Wu 
312ae0c4d1aSHao Wu static const struct {
313ae0c4d1aSHao Wu     const char *name;
314ae0c4d1aSHao Wu     hwaddr regs_addr;
315ae0c4d1aSHao Wu     int cs_count;
316ae0c4d1aSHao Wu     const hwaddr *flash_addr;
317ae0c4d1aSHao Wu     size_t flash_size;
318ae0c4d1aSHao Wu } npcm8xx_fiu[] = {
319ae0c4d1aSHao Wu     {
320ae0c4d1aSHao Wu         .name = "fiu0",
321ae0c4d1aSHao Wu         .regs_addr = 0xfb000000,
322ae0c4d1aSHao Wu         .cs_count = ARRAY_SIZE(npcm8xx_fiu0_flash_addr),
323ae0c4d1aSHao Wu         .flash_addr = npcm8xx_fiu0_flash_addr,
324ae0c4d1aSHao Wu         .flash_size = 128 * MiB,
325ae0c4d1aSHao Wu     },
326ae0c4d1aSHao Wu     {
327ae0c4d1aSHao Wu         .name = "fiu1",
328ae0c4d1aSHao Wu         .regs_addr = 0xfb002000,
329ae0c4d1aSHao Wu         .cs_count = ARRAY_SIZE(npcm8xx_fiu1_flash_addr),
330ae0c4d1aSHao Wu         .flash_addr = npcm8xx_fiu1_flash_addr,
331ae0c4d1aSHao Wu         .flash_size = 16 * MiB,
332ae0c4d1aSHao Wu     }, {
333ae0c4d1aSHao Wu         .name = "fiu3",
334ae0c4d1aSHao Wu         .regs_addr = 0xc0000000,
335ae0c4d1aSHao Wu         .cs_count = ARRAY_SIZE(npcm8xx_fiu3_flash_addr),
336ae0c4d1aSHao Wu         .flash_addr = npcm8xx_fiu3_flash_addr,
337ae0c4d1aSHao Wu         .flash_size = 128 * MiB,
338ae0c4d1aSHao Wu     },
339ae0c4d1aSHao Wu };
340ae0c4d1aSHao Wu 
341ae0c4d1aSHao Wu static struct arm_boot_info npcm8xx_binfo = {
342ae0c4d1aSHao Wu     .loader_start           = NPCM8XX_LOADER_START,
343ae0c4d1aSHao Wu     .smp_loader_start       = NPCM8XX_SMP_LOADER_START,
344ae0c4d1aSHao Wu     .smp_bootreg_addr       = NPCM8XX_SMP_BOOTREG_ADDR,
345ae0c4d1aSHao Wu     .gic_cpu_if_addr        = NPCM8XX_GICC_BA,
346ae0c4d1aSHao Wu     .secure_boot            = false,
347ae0c4d1aSHao Wu     .board_id               = -1,
348ae0c4d1aSHao Wu     .board_setup_addr       = NPCM8XX_BOARD_SETUP_ADDR,
349ae0c4d1aSHao Wu };
350ae0c4d1aSHao Wu 
351ae0c4d1aSHao Wu void npcm8xx_load_kernel(MachineState *machine, NPCM8xxState *soc)
352ae0c4d1aSHao Wu {
353ae0c4d1aSHao Wu     npcm8xx_binfo.ram_size = machine->ram_size;
354ae0c4d1aSHao Wu 
355ae0c4d1aSHao Wu     arm_load_kernel(&soc->cpu[0], machine, &npcm8xx_binfo);
356ae0c4d1aSHao Wu }
357ae0c4d1aSHao Wu 
358ae0c4d1aSHao Wu static void npcm8xx_init_fuses(NPCM8xxState *s)
359ae0c4d1aSHao Wu {
360ae0c4d1aSHao Wu     NPCM8xxClass *nc = NPCM8XX_GET_CLASS(s);
361ae0c4d1aSHao Wu     uint32_t value;
362ae0c4d1aSHao Wu 
363ae0c4d1aSHao Wu     /*
364ae0c4d1aSHao Wu      * The initial mask of disabled modules indicates the chip derivative (e.g.
365ae0c4d1aSHao Wu      * NPCM750 or NPCM730).
366ae0c4d1aSHao Wu      */
367ae0c4d1aSHao Wu     value = cpu_to_le32(nc->disabled_modules);
368ae0c4d1aSHao Wu     npcm7xx_otp_array_write(&s->fuse_array, &value, NPCM7XX_FUSE_DERIVATIVE,
369ae0c4d1aSHao Wu                             sizeof(value));
370ae0c4d1aSHao Wu }
371ae0c4d1aSHao Wu 
372ae0c4d1aSHao Wu static void npcm8xx_write_adc_calibration(NPCM8xxState *s)
373ae0c4d1aSHao Wu {
374ae0c4d1aSHao Wu     /* Both ADC and the fuse array must have realized. */
375ae0c4d1aSHao Wu     QEMU_BUILD_BUG_ON(sizeof(s->adc.calibration_r_values) != 4);
376ae0c4d1aSHao Wu     npcm7xx_otp_array_write(&s->fuse_array, s->adc.calibration_r_values,
377ae0c4d1aSHao Wu             NPCM7XX_FUSE_ADC_CALIB, sizeof(s->adc.calibration_r_values));
378ae0c4d1aSHao Wu }
379ae0c4d1aSHao Wu 
380ae0c4d1aSHao Wu static qemu_irq npcm8xx_irq(NPCM8xxState *s, int n)
381ae0c4d1aSHao Wu {
382ae0c4d1aSHao Wu     return qdev_get_gpio_in(DEVICE(&s->gic), n);
383ae0c4d1aSHao Wu }
384ae0c4d1aSHao Wu 
385ae0c4d1aSHao Wu static void npcm8xx_init(Object *obj)
386ae0c4d1aSHao Wu {
387ae0c4d1aSHao Wu     NPCM8xxState *s = NPCM8XX(obj);
388ae0c4d1aSHao Wu     int i;
389ae0c4d1aSHao Wu 
390ae0c4d1aSHao Wu     object_initialize_child(obj, "cpu-cluster", &s->cpu_cluster,
391ae0c4d1aSHao Wu                             TYPE_CPU_CLUSTER);
392ae0c4d1aSHao Wu     for (i = 0; i < NPCM8XX_MAX_NUM_CPUS; i++) {
393ae0c4d1aSHao Wu         object_initialize_child(OBJECT(&s->cpu_cluster), "cpu[*]", &s->cpu[i],
394ae0c4d1aSHao Wu                                 ARM_CPU_TYPE_NAME("cortex-a35"));
395ae0c4d1aSHao Wu     }
396ae0c4d1aSHao Wu     object_initialize_child(obj, "gic", &s->gic, TYPE_ARM_GIC);
397ae0c4d1aSHao Wu     object_initialize_child(obj, "gcr", &s->gcr, TYPE_NPCM8XX_GCR);
398ae0c4d1aSHao Wu     object_property_add_alias(obj, "power-on-straps", OBJECT(&s->gcr),
399ae0c4d1aSHao Wu                               "power-on-straps");
400ae0c4d1aSHao Wu     object_initialize_child(obj, "clk", &s->clk, TYPE_NPCM8XX_CLK);
401ae0c4d1aSHao Wu     object_initialize_child(obj, "otp", &s->fuse_array,
402ae0c4d1aSHao Wu                             TYPE_NPCM7XX_FUSE_ARRAY);
403ae0c4d1aSHao Wu     object_initialize_child(obj, "mc", &s->mc, TYPE_NPCM7XX_MC);
404ae0c4d1aSHao Wu     object_initialize_child(obj, "rng", &s->rng, TYPE_NPCM7XX_RNG);
405ae0c4d1aSHao Wu     object_initialize_child(obj, "adc", &s->adc, TYPE_NPCM7XX_ADC);
406ae0c4d1aSHao Wu 
407ae0c4d1aSHao Wu     for (i = 0; i < ARRAY_SIZE(s->tim); i++) {
408ae0c4d1aSHao Wu         object_initialize_child(obj, "tim[*]", &s->tim[i], TYPE_NPCM7XX_TIMER);
409ae0c4d1aSHao Wu     }
410ae0c4d1aSHao Wu 
411ae0c4d1aSHao Wu     for (i = 0; i < ARRAY_SIZE(s->gpio); i++) {
412ae0c4d1aSHao Wu         object_initialize_child(obj, "gpio[*]", &s->gpio[i], TYPE_NPCM7XX_GPIO);
413ae0c4d1aSHao Wu     }
414ae0c4d1aSHao Wu 
415ae0c4d1aSHao Wu 
416ae0c4d1aSHao Wu     for (i = 0; i < ARRAY_SIZE(s->smbus); i++) {
417ae0c4d1aSHao Wu         object_initialize_child(obj, "smbus[*]", &s->smbus[i],
418ae0c4d1aSHao Wu                                 TYPE_NPCM7XX_SMBUS);
419ae0c4d1aSHao Wu         DEVICE(&s->smbus[i])->id = g_strdup_printf("smbus[%d]", i);
420ae0c4d1aSHao Wu     }
421ae0c4d1aSHao Wu 
422ae0c4d1aSHao Wu     for (i = 0; i < ARRAY_SIZE(s->ehci); i++) {
423ae0c4d1aSHao Wu         object_initialize_child(obj, "ehci[*]", &s->ehci[i], TYPE_NPCM7XX_EHCI);
424ae0c4d1aSHao Wu     }
425ae0c4d1aSHao Wu     for (i = 0; i < ARRAY_SIZE(s->ohci); i++) {
426ae0c4d1aSHao Wu         object_initialize_child(obj, "ohci[*]", &s->ohci[i], TYPE_SYSBUS_OHCI);
427ae0c4d1aSHao Wu     }
428ae0c4d1aSHao Wu 
429ae0c4d1aSHao Wu     QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm8xx_fiu) != ARRAY_SIZE(s->fiu));
430ae0c4d1aSHao Wu     for (i = 0; i < ARRAY_SIZE(s->fiu); i++) {
431ae0c4d1aSHao Wu         object_initialize_child(obj, npcm8xx_fiu[i].name, &s->fiu[i],
432ae0c4d1aSHao Wu                                 TYPE_NPCM7XX_FIU);
433ae0c4d1aSHao Wu     }
434ae0c4d1aSHao Wu 
435ae0c4d1aSHao Wu     for (i = 0; i < ARRAY_SIZE(s->pwm); i++) {
436ae0c4d1aSHao Wu         object_initialize_child(obj, "pwm[*]", &s->pwm[i], TYPE_NPCM7XX_PWM);
437ae0c4d1aSHao Wu     }
438ae0c4d1aSHao Wu 
439ae0c4d1aSHao Wu     for (i = 0; i < ARRAY_SIZE(s->mft); i++) {
440ae0c4d1aSHao Wu         object_initialize_child(obj, "mft[*]", &s->mft[i], TYPE_NPCM7XX_MFT);
441ae0c4d1aSHao Wu     }
442ae0c4d1aSHao Wu 
443ae0c4d1aSHao Wu     object_initialize_child(obj, "mmc", &s->mmc, TYPE_NPCM7XX_SDHCI);
444ae0c4d1aSHao Wu }
445ae0c4d1aSHao Wu 
446ae0c4d1aSHao Wu static void npcm8xx_realize(DeviceState *dev, Error **errp)
447ae0c4d1aSHao Wu {
448ae0c4d1aSHao Wu     NPCM8xxState *s = NPCM8XX(dev);
449ae0c4d1aSHao Wu     NPCM8xxClass *nc = NPCM8XX_GET_CLASS(s);
450ae0c4d1aSHao Wu     int i;
451ae0c4d1aSHao Wu 
452ae0c4d1aSHao Wu     if (memory_region_size(s->dram) > NPCM8XX_DRAM_SZ) {
453ae0c4d1aSHao Wu         error_setg(errp, "%s: NPCM8xx cannot address more than %" PRIu64
454ae0c4d1aSHao Wu                    " MiB of DRAM", __func__, NPCM8XX_DRAM_SZ / MiB);
455ae0c4d1aSHao Wu         return;
456ae0c4d1aSHao Wu     }
457ae0c4d1aSHao Wu 
458ae0c4d1aSHao Wu     /* CPUs */
459ae0c4d1aSHao Wu     for (i = 0; i < nc->num_cpus; i++) {
460ae0c4d1aSHao Wu         object_property_set_int(OBJECT(&s->cpu[i]), "mp-affinity",
461ae0c4d1aSHao Wu                                 arm_build_mp_affinity(i, NPCM8XX_MAX_NUM_CPUS),
462ae0c4d1aSHao Wu                                 &error_abort);
463ae0c4d1aSHao Wu         object_property_set_bool(OBJECT(&s->cpu[i]), "reset-hivecs", true,
464ae0c4d1aSHao Wu                                  &error_abort);
465ae0c4d1aSHao Wu         object_property_set_int(OBJECT(&s->cpu[i]), "core-count",
466ae0c4d1aSHao Wu                                 nc->num_cpus, &error_abort);
467ae0c4d1aSHao Wu 
468ae0c4d1aSHao Wu         /* Disable security extensions. */
469ae0c4d1aSHao Wu         object_property_set_bool(OBJECT(&s->cpu[i]), "has_el3", false,
470ae0c4d1aSHao Wu                                  &error_abort);
471ae0c4d1aSHao Wu 
472ae0c4d1aSHao Wu         if (!qdev_realize(DEVICE(&s->cpu[i]), NULL, errp)) {
473ae0c4d1aSHao Wu             return;
474ae0c4d1aSHao Wu         }
475ae0c4d1aSHao Wu     }
476ae0c4d1aSHao Wu 
477ae0c4d1aSHao Wu     /* ARM GIC for Cortex A35. Can only fail if we pass bad parameters here. */
478ae0c4d1aSHao Wu     object_property_set_uint(OBJECT(&s->gic), "num-cpu", nc->num_cpus, errp);
479ae0c4d1aSHao Wu     object_property_set_uint(OBJECT(&s->gic), "num-irq", NPCM8XX_NUM_IRQ, errp);
480ae0c4d1aSHao Wu     object_property_set_uint(OBJECT(&s->gic), "revision", 2, errp);
481ae0c4d1aSHao Wu     object_property_set_bool(OBJECT(&s->gic), "has-security-extensions", true,
482ae0c4d1aSHao Wu                              errp);
483ae0c4d1aSHao Wu     if (!sysbus_realize(SYS_BUS_DEVICE(&s->gic), errp)) {
484ae0c4d1aSHao Wu         return;
485ae0c4d1aSHao Wu     }
486ae0c4d1aSHao Wu     for (i = 0; i < nc->num_cpus; i++) {
487ae0c4d1aSHao Wu         sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), i,
488ae0c4d1aSHao Wu                            qdev_get_gpio_in(DEVICE(&s->cpu[i]), ARM_CPU_IRQ));
489ae0c4d1aSHao Wu         sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), i + nc->num_cpus,
490ae0c4d1aSHao Wu                            qdev_get_gpio_in(DEVICE(&s->cpu[i]), ARM_CPU_FIQ));
491ae0c4d1aSHao Wu         sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), i + nc->num_cpus * 2,
492ae0c4d1aSHao Wu                            qdev_get_gpio_in(DEVICE(&s->cpu[i]), ARM_CPU_VIRQ));
493ae0c4d1aSHao Wu         sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), i + nc->num_cpus * 3,
494ae0c4d1aSHao Wu                            qdev_get_gpio_in(DEVICE(&s->cpu[i]), ARM_CPU_VFIQ));
495ae0c4d1aSHao Wu 
496ae0c4d1aSHao Wu         qdev_connect_gpio_out(DEVICE(&s->cpu[i]), GTIMER_PHYS,
497ae0c4d1aSHao Wu             qdev_get_gpio_in(DEVICE(&s->gic),
498ae0c4d1aSHao Wu                 NPCM8XX_PPI_BASE(i) + ARCH_TIMER_NS_EL1_IRQ));
499ae0c4d1aSHao Wu         qdev_connect_gpio_out(DEVICE(&s->cpu[i]), GTIMER_VIRT,
500ae0c4d1aSHao Wu             qdev_get_gpio_in(DEVICE(&s->gic),
501ae0c4d1aSHao Wu                 NPCM8XX_PPI_BASE(i) + ARCH_TIMER_VIRT_IRQ));
502ae0c4d1aSHao Wu         qdev_connect_gpio_out(DEVICE(&s->cpu[i]), GTIMER_HYP,
503ae0c4d1aSHao Wu             qdev_get_gpio_in(DEVICE(&s->gic),
504ae0c4d1aSHao Wu                 NPCM8XX_PPI_BASE(i) + ARCH_TIMER_NS_EL2_IRQ));
505ae0c4d1aSHao Wu         qdev_connect_gpio_out(DEVICE(&s->cpu[i]), GTIMER_SEC,
506ae0c4d1aSHao Wu             qdev_get_gpio_in(DEVICE(&s->gic),
507ae0c4d1aSHao Wu                 NPCM8XX_PPI_BASE(i) + ARCH_TIMER_S_EL1_IRQ));
508ae0c4d1aSHao Wu     }
509ae0c4d1aSHao Wu     sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 0, NPCM8XX_GICD_BA);
510ae0c4d1aSHao Wu     sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 1, NPCM8XX_GICC_BA);
511ae0c4d1aSHao Wu 
512ae0c4d1aSHao Wu     /* CPU cluster */
513ae0c4d1aSHao Wu     qdev_prop_set_uint32(DEVICE(&s->cpu_cluster), "cluster-id", 0);
514ae0c4d1aSHao Wu     qdev_realize(DEVICE(&s->cpu_cluster), NULL, &error_fatal);
515ae0c4d1aSHao Wu 
516ae0c4d1aSHao Wu     /* System Global Control Registers (GCR). Can fail due to user input. */
517ae0c4d1aSHao Wu     object_property_set_int(OBJECT(&s->gcr), "disabled-modules",
518ae0c4d1aSHao Wu                             nc->disabled_modules, &error_abort);
519ae0c4d1aSHao Wu     object_property_add_const_link(OBJECT(&s->gcr), "dram-mr", OBJECT(s->dram));
520ae0c4d1aSHao Wu     if (!sysbus_realize(SYS_BUS_DEVICE(&s->gcr), errp)) {
521ae0c4d1aSHao Wu         return;
522ae0c4d1aSHao Wu     }
523ae0c4d1aSHao Wu     sysbus_mmio_map(SYS_BUS_DEVICE(&s->gcr), 0, NPCM8XX_GCR_BA);
524ae0c4d1aSHao Wu 
525ae0c4d1aSHao Wu     /* Clock Control Registers (CLK). Cannot fail. */
526ae0c4d1aSHao Wu     sysbus_realize(SYS_BUS_DEVICE(&s->clk), &error_abort);
527ae0c4d1aSHao Wu     sysbus_mmio_map(SYS_BUS_DEVICE(&s->clk), 0, NPCM8XX_CLK_BA);
528ae0c4d1aSHao Wu 
529ae0c4d1aSHao Wu     /* OTP fuse strap array. Cannot fail. */
530ae0c4d1aSHao Wu     sysbus_realize(SYS_BUS_DEVICE(&s->fuse_array), &error_abort);
531ae0c4d1aSHao Wu     sysbus_mmio_map(SYS_BUS_DEVICE(&s->fuse_array), 0, NPCM8XX_OTP_BA);
532ae0c4d1aSHao Wu     npcm8xx_init_fuses(s);
533ae0c4d1aSHao Wu 
534ae0c4d1aSHao Wu     /* Fake Memory Controller (MC). Cannot fail. */
535ae0c4d1aSHao Wu     sysbus_realize(SYS_BUS_DEVICE(&s->mc), &error_abort);
536ae0c4d1aSHao Wu     sysbus_mmio_map(SYS_BUS_DEVICE(&s->mc), 0, NPCM8XX_MC_BA);
537ae0c4d1aSHao Wu 
538ae0c4d1aSHao Wu     /* ADC Modules. Cannot fail. */
539ae0c4d1aSHao Wu     qdev_connect_clock_in(DEVICE(&s->adc), "clock", qdev_get_clock_out(
540ae0c4d1aSHao Wu                           DEVICE(&s->clk), "adc-clock"));
541ae0c4d1aSHao Wu     sysbus_realize(SYS_BUS_DEVICE(&s->adc), &error_abort);
542ae0c4d1aSHao Wu     sysbus_mmio_map(SYS_BUS_DEVICE(&s->adc), 0, NPCM8XX_ADC_BA);
543ae0c4d1aSHao Wu     sysbus_connect_irq(SYS_BUS_DEVICE(&s->adc), 0,
544ae0c4d1aSHao Wu                        npcm8xx_irq(s, NPCM8XX_ADC_IRQ));
545ae0c4d1aSHao Wu     npcm8xx_write_adc_calibration(s);
546ae0c4d1aSHao Wu 
547ae0c4d1aSHao Wu     /* Timer Modules (TIM). Cannot fail. */
548ae0c4d1aSHao Wu     QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm8xx_tim_addr) != ARRAY_SIZE(s->tim));
549ae0c4d1aSHao Wu     for (i = 0; i < ARRAY_SIZE(s->tim); i++) {
550ae0c4d1aSHao Wu         SysBusDevice *sbd = SYS_BUS_DEVICE(&s->tim[i]);
551ae0c4d1aSHao Wu         int first_irq;
552ae0c4d1aSHao Wu         int j;
553ae0c4d1aSHao Wu 
554ae0c4d1aSHao Wu         /* Connect the timer clock. */
555ae0c4d1aSHao Wu         qdev_connect_clock_in(DEVICE(&s->tim[i]), "clock", qdev_get_clock_out(
556ae0c4d1aSHao Wu                     DEVICE(&s->clk), "timer-clock"));
557ae0c4d1aSHao Wu 
558ae0c4d1aSHao Wu         sysbus_realize(sbd, &error_abort);
559ae0c4d1aSHao Wu         sysbus_mmio_map(sbd, 0, npcm8xx_tim_addr[i]);
560ae0c4d1aSHao Wu 
561ae0c4d1aSHao Wu         first_irq = NPCM8XX_TIMER0_IRQ + i * NPCM7XX_TIMERS_PER_CTRL;
562ae0c4d1aSHao Wu         for (j = 0; j < NPCM7XX_TIMERS_PER_CTRL; j++) {
563ae0c4d1aSHao Wu             qemu_irq irq = npcm8xx_irq(s, first_irq + j);
564ae0c4d1aSHao Wu             sysbus_connect_irq(sbd, j, irq);
565ae0c4d1aSHao Wu         }
566ae0c4d1aSHao Wu 
567ae0c4d1aSHao Wu         /* IRQ for watchdogs */
568ae0c4d1aSHao Wu         sysbus_connect_irq(sbd, NPCM7XX_TIMERS_PER_CTRL,
569ae0c4d1aSHao Wu                 npcm8xx_irq(s, NPCM8XX_WDG0_IRQ + i));
570ae0c4d1aSHao Wu         /* GPIO that connects clk module with watchdog */
571ae0c4d1aSHao Wu         qdev_connect_gpio_out_named(DEVICE(&s->tim[i]),
572ae0c4d1aSHao Wu                 NPCM7XX_WATCHDOG_RESET_GPIO_OUT, 0,
573ae0c4d1aSHao Wu                 qdev_get_gpio_in_named(DEVICE(&s->clk),
574ae0c4d1aSHao Wu                         NPCM7XX_WATCHDOG_RESET_GPIO_IN, i));
575ae0c4d1aSHao Wu     }
576ae0c4d1aSHao Wu 
577ae0c4d1aSHao Wu     /* UART0..6 (16550 compatible) */
578ae0c4d1aSHao Wu     for (i = 0; i < ARRAY_SIZE(npcm8xx_uart_addr); i++) {
579ae0c4d1aSHao Wu         serial_mm_init(get_system_memory(), npcm8xx_uart_addr[i], 2,
580ae0c4d1aSHao Wu                        npcm8xx_irq(s, NPCM8XX_UART0_IRQ + i), 115200,
581ae0c4d1aSHao Wu                        serial_hd(i), DEVICE_LITTLE_ENDIAN);
582ae0c4d1aSHao Wu     }
583ae0c4d1aSHao Wu 
584ae0c4d1aSHao Wu     /* Random Number Generator. Cannot fail. */
585ae0c4d1aSHao Wu     sysbus_realize(SYS_BUS_DEVICE(&s->rng), &error_abort);
586ae0c4d1aSHao Wu     sysbus_mmio_map(SYS_BUS_DEVICE(&s->rng), 0, NPCM8XX_RNG_BA);
587ae0c4d1aSHao Wu 
588ae0c4d1aSHao Wu     /* GPIO modules. Cannot fail. */
589ae0c4d1aSHao Wu     QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm8xx_gpio) != ARRAY_SIZE(s->gpio));
590ae0c4d1aSHao Wu     for (i = 0; i < ARRAY_SIZE(s->gpio); i++) {
591ae0c4d1aSHao Wu         Object *obj = OBJECT(&s->gpio[i]);
592ae0c4d1aSHao Wu 
593ae0c4d1aSHao Wu         object_property_set_uint(obj, "reset-pullup",
594ae0c4d1aSHao Wu                                  npcm8xx_gpio[i].reset_pu, &error_abort);
595ae0c4d1aSHao Wu         object_property_set_uint(obj, "reset-pulldown",
596ae0c4d1aSHao Wu                                  npcm8xx_gpio[i].reset_pd, &error_abort);
597ae0c4d1aSHao Wu         object_property_set_uint(obj, "reset-osrc",
598ae0c4d1aSHao Wu                                  npcm8xx_gpio[i].reset_osrc, &error_abort);
599ae0c4d1aSHao Wu         object_property_set_uint(obj, "reset-odsc",
600ae0c4d1aSHao Wu                                  npcm8xx_gpio[i].reset_odsc, &error_abort);
601ae0c4d1aSHao Wu         sysbus_realize(SYS_BUS_DEVICE(obj), &error_abort);
602ae0c4d1aSHao Wu         sysbus_mmio_map(SYS_BUS_DEVICE(obj), 0, npcm8xx_gpio[i].regs_addr);
603ae0c4d1aSHao Wu         sysbus_connect_irq(SYS_BUS_DEVICE(obj), 0,
604ae0c4d1aSHao Wu                            npcm8xx_irq(s, NPCM8XX_GPIO0_IRQ + i));
605ae0c4d1aSHao Wu     }
606ae0c4d1aSHao Wu 
607ae0c4d1aSHao Wu     /* SMBus modules. Cannot fail. */
608ae0c4d1aSHao Wu     QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm8xx_smbus_addr) != ARRAY_SIZE(s->smbus));
609ae0c4d1aSHao Wu     for (i = 0; i < ARRAY_SIZE(s->smbus); i++) {
610ae0c4d1aSHao Wu         Object *obj = OBJECT(&s->smbus[i]);
611ae0c4d1aSHao Wu 
612ae0c4d1aSHao Wu         sysbus_realize(SYS_BUS_DEVICE(obj), &error_abort);
613ae0c4d1aSHao Wu         sysbus_mmio_map(SYS_BUS_DEVICE(obj), 0, npcm8xx_smbus_addr[i]);
614ae0c4d1aSHao Wu         sysbus_connect_irq(SYS_BUS_DEVICE(obj), 0,
615ae0c4d1aSHao Wu                            npcm8xx_irq(s, NPCM8XX_SMBUS0_IRQ + i));
616ae0c4d1aSHao Wu     }
617ae0c4d1aSHao Wu 
618ae0c4d1aSHao Wu     /* USB Host */
619ae0c4d1aSHao Wu     QEMU_BUILD_BUG_ON(ARRAY_SIZE(s->ohci) != ARRAY_SIZE(s->ehci));
620ae0c4d1aSHao Wu     for (i = 0; i < ARRAY_SIZE(s->ehci); i++) {
621ae0c4d1aSHao Wu         object_property_set_bool(OBJECT(&s->ehci[i]), "companion-enable", true,
622ae0c4d1aSHao Wu                                  &error_abort);
623ae0c4d1aSHao Wu         sysbus_realize(SYS_BUS_DEVICE(&s->ehci[i]), &error_abort);
624ae0c4d1aSHao Wu         sysbus_mmio_map(SYS_BUS_DEVICE(&s->ehci[i]), 0, npcm8xx_ehci_addr[i]);
625ae0c4d1aSHao Wu         sysbus_connect_irq(SYS_BUS_DEVICE(&s->ehci[i]), 0,
626ae0c4d1aSHao Wu                            npcm8xx_irq(s, NPCM8XX_EHCI1_IRQ + 2 * i));
627ae0c4d1aSHao Wu     }
628ae0c4d1aSHao Wu     for (i = 0; i < ARRAY_SIZE(s->ohci); i++) {
629ae0c4d1aSHao Wu         object_property_set_str(OBJECT(&s->ohci[i]), "masterbus", "usb-bus.0",
630ae0c4d1aSHao Wu                                 &error_abort);
631ae0c4d1aSHao Wu         object_property_set_uint(OBJECT(&s->ohci[i]), "num-ports", 1,
632ae0c4d1aSHao Wu                                  &error_abort);
633ae0c4d1aSHao Wu         object_property_set_uint(OBJECT(&s->ohci[i]), "firstport", i,
634ae0c4d1aSHao Wu                                  &error_abort);
635ae0c4d1aSHao Wu         sysbus_realize(SYS_BUS_DEVICE(&s->ohci[i]), &error_abort);
636ae0c4d1aSHao Wu         sysbus_mmio_map(SYS_BUS_DEVICE(&s->ohci[i]), 0, npcm8xx_ohci_addr[i]);
637ae0c4d1aSHao Wu         sysbus_connect_irq(SYS_BUS_DEVICE(&s->ohci[i]), 0,
638ae0c4d1aSHao Wu                            npcm8xx_irq(s, NPCM8XX_OHCI1_IRQ + 2 * i));
639ae0c4d1aSHao Wu     }
640ae0c4d1aSHao Wu 
641ae0c4d1aSHao Wu     /* PWM Modules. Cannot fail. */
642ae0c4d1aSHao Wu     QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm8xx_pwm_addr) != ARRAY_SIZE(s->pwm));
643ae0c4d1aSHao Wu     for (i = 0; i < ARRAY_SIZE(s->pwm); i++) {
644ae0c4d1aSHao Wu         SysBusDevice *sbd = SYS_BUS_DEVICE(&s->pwm[i]);
645ae0c4d1aSHao Wu 
646ae0c4d1aSHao Wu         qdev_connect_clock_in(DEVICE(&s->pwm[i]), "clock", qdev_get_clock_out(
647ae0c4d1aSHao Wu                     DEVICE(&s->clk), "apb3-clock"));
648ae0c4d1aSHao Wu         sysbus_realize(sbd, &error_abort);
649ae0c4d1aSHao Wu         sysbus_mmio_map(sbd, 0, npcm8xx_pwm_addr[i]);
650ae0c4d1aSHao Wu         sysbus_connect_irq(sbd, i, npcm8xx_irq(s, NPCM8XX_PWM0_IRQ + i));
651ae0c4d1aSHao Wu     }
652ae0c4d1aSHao Wu 
653ae0c4d1aSHao Wu     /* MFT Modules. Cannot fail. */
654ae0c4d1aSHao Wu     QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm8xx_mft_addr) != ARRAY_SIZE(s->mft));
655ae0c4d1aSHao Wu     for (i = 0; i < ARRAY_SIZE(s->mft); i++) {
656ae0c4d1aSHao Wu         SysBusDevice *sbd = SYS_BUS_DEVICE(&s->mft[i]);
657ae0c4d1aSHao Wu 
658ae0c4d1aSHao Wu         qdev_connect_clock_in(DEVICE(&s->mft[i]), "clock-in",
659ae0c4d1aSHao Wu                               qdev_get_clock_out(DEVICE(&s->clk),
660ae0c4d1aSHao Wu                                                  "apb4-clock"));
661ae0c4d1aSHao Wu         sysbus_realize(sbd, &error_abort);
662ae0c4d1aSHao Wu         sysbus_mmio_map(sbd, 0, npcm8xx_mft_addr[i]);
663ae0c4d1aSHao Wu         sysbus_connect_irq(sbd, 0, npcm8xx_irq(s, NPCM8XX_MFT0_IRQ + i));
664ae0c4d1aSHao Wu     }
665ae0c4d1aSHao Wu 
666ae0c4d1aSHao Wu     /*
667ae0c4d1aSHao Wu      * Flash Interface Unit (FIU). Can fail if incorrect number of chip selects
668ae0c4d1aSHao Wu      * specified, but this is a programming error.
669ae0c4d1aSHao Wu      */
670ae0c4d1aSHao Wu     QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm8xx_fiu) != ARRAY_SIZE(s->fiu));
671ae0c4d1aSHao Wu     for (i = 0; i < ARRAY_SIZE(s->fiu); i++) {
672ae0c4d1aSHao Wu         SysBusDevice *sbd = SYS_BUS_DEVICE(&s->fiu[i]);
673ae0c4d1aSHao Wu         int j;
674ae0c4d1aSHao Wu 
675ae0c4d1aSHao Wu         object_property_set_int(OBJECT(sbd), "cs-count",
676ae0c4d1aSHao Wu                                 npcm8xx_fiu[i].cs_count, &error_abort);
677ae0c4d1aSHao Wu         object_property_set_int(OBJECT(sbd), "flash-size",
678ae0c4d1aSHao Wu                                 npcm8xx_fiu[i].flash_size, &error_abort);
679ae0c4d1aSHao Wu         sysbus_realize(sbd, &error_abort);
680ae0c4d1aSHao Wu 
681ae0c4d1aSHao Wu         sysbus_mmio_map(sbd, 0, npcm8xx_fiu[i].regs_addr);
682ae0c4d1aSHao Wu         for (j = 0; j < npcm8xx_fiu[i].cs_count; j++) {
683ae0c4d1aSHao Wu             sysbus_mmio_map(sbd, j + 1, npcm8xx_fiu[i].flash_addr[j]);
684ae0c4d1aSHao Wu         }
685ae0c4d1aSHao Wu     }
686ae0c4d1aSHao Wu 
687ae0c4d1aSHao Wu     /* RAM2 (SRAM) */
688ae0c4d1aSHao Wu     memory_region_init_ram(&s->sram, OBJECT(dev), "ram2",
689ae0c4d1aSHao Wu                            NPCM8XX_RAM2_SZ, &error_abort);
690ae0c4d1aSHao Wu     memory_region_add_subregion(get_system_memory(), NPCM8XX_RAM2_BA, &s->sram);
691ae0c4d1aSHao Wu 
692ae0c4d1aSHao Wu     /* RAM3 (SRAM) */
693ae0c4d1aSHao Wu     memory_region_init_ram(&s->ram3, OBJECT(dev), "ram3",
694ae0c4d1aSHao Wu                            NPCM8XX_RAM3_SZ, &error_abort);
695ae0c4d1aSHao Wu     memory_region_add_subregion(get_system_memory(), NPCM8XX_RAM3_BA, &s->ram3);
696ae0c4d1aSHao Wu 
697ae0c4d1aSHao Wu     /* Internal ROM */
698ae0c4d1aSHao Wu     memory_region_init_rom(&s->irom, OBJECT(dev), "irom", NPCM8XX_ROM_SZ,
699ae0c4d1aSHao Wu                            &error_abort);
700ae0c4d1aSHao Wu     memory_region_add_subregion(get_system_memory(), NPCM8XX_ROM_BA, &s->irom);
701ae0c4d1aSHao Wu 
702ae0c4d1aSHao Wu     /* SDHCI */
703ae0c4d1aSHao Wu     sysbus_realize(SYS_BUS_DEVICE(&s->mmc), &error_abort);
704ae0c4d1aSHao Wu     sysbus_mmio_map(SYS_BUS_DEVICE(&s->mmc), 0, NPCM8XX_MMC_BA);
705ae0c4d1aSHao Wu     sysbus_connect_irq(SYS_BUS_DEVICE(&s->mmc), 0,
706ae0c4d1aSHao Wu             npcm8xx_irq(s, NPCM8XX_MMC_IRQ));
707ae0c4d1aSHao Wu 
708ae0c4d1aSHao Wu 
709ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.shm",          0xc0001000,   4 * KiB);
710ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.gicextra",     0xdfffa000,  24 * KiB);
711ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.vdmx",         0xe0800000,   4 * KiB);
712ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.pcierc",       0xe1000000,  64 * KiB);
713ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.rootc",        0xe8000000, 128 * MiB);
714ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.kcs",          0xf0007000,   4 * KiB);
715ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.gfxi",         0xf000e000,   4 * KiB);
716ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.fsw",          0xf000f000,   4 * KiB);
717ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.bt",           0xf0030000,   4 * KiB);
718ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.espi",         0xf009f000,   4 * KiB);
719ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.peci",         0xf0100000,   4 * KiB);
720ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.siox[1]",      0xf0101000,   4 * KiB);
721ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.siox[2]",      0xf0102000,   4 * KiB);
722ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.tmps",         0xf0188000,   4 * KiB);
723ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.pspi",         0xf0201000,   4 * KiB);
724ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.viru1",        0xf0204000,   4 * KiB);
725ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.viru2",        0xf0205000,   4 * KiB);
726ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.jtm1",         0xf0208000,   4 * KiB);
727ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.jtm2",         0xf0209000,   4 * KiB);
728ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.flm0",         0xf0210000,   4 * KiB);
729ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.flm1",         0xf0211000,   4 * KiB);
730ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.flm2",         0xf0212000,   4 * KiB);
731ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.flm3",         0xf0213000,   4 * KiB);
732ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.ahbpci",       0xf0400000,   1 * MiB);
733ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.dap",          0xf0500000, 960 * KiB);
734ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.mcphy",        0xf05f0000,  64 * KiB);
735ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.pcs",          0xf0780000, 256 * KiB);
736ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.tsgen",        0xf07fc000,   8 * KiB);
737ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.gmac1",        0xf0802000,   8 * KiB);
738ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.gmac2",        0xf0804000,   8 * KiB);
739ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.gmac3",        0xf0806000,   8 * KiB);
740ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.gmac4",        0xf0808000,   8 * KiB);
741ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.copctl",       0xf080c000,   4 * KiB);
742ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.tipctl",       0xf080d000,   4 * KiB);
743ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.rst",          0xf080e000,   4 * KiB);
744ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.vcd",          0xf0810000,  64 * KiB);
745ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.ece",          0xf0820000,   8 * KiB);
746ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.vdma",         0xf0822000,   8 * KiB);
747ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.usbd[0]",      0xf0830000,   4 * KiB);
748ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.usbd[1]",      0xf0831000,   4 * KiB);
749ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.usbd[2]",      0xf0832000,   4 * KiB);
750ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.usbd[3]",      0xf0833000,   4 * KiB);
751ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.usbd[4]",      0xf0834000,   4 * KiB);
752ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.usbd[5]",      0xf0835000,   4 * KiB);
753ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.usbd[6]",      0xf0836000,   4 * KiB);
754ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.usbd[7]",      0xf0837000,   4 * KiB);
755ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.usbd[8]",      0xf0838000,   4 * KiB);
756ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.usbd[9]",      0xf0839000,   4 * KiB);
757ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.pci_mbox1",    0xf0848000,  64 * KiB);
758ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.gdma0",        0xf0850000,   4 * KiB);
759ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.gdma1",        0xf0851000,   4 * KiB);
760ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.gdma2",        0xf0852000,   4 * KiB);
761ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.aes",          0xf0858000,   4 * KiB);
762ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.des",          0xf0859000,   4 * KiB);
763ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.sha",          0xf085a000,   4 * KiB);
764ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.pci_mbox2",    0xf0868000,  64 * KiB);
765ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.i3c0",         0xfff10000,   4 * KiB);
766ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.i3c1",         0xfff11000,   4 * KiB);
767ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.i3c2",         0xfff12000,   4 * KiB);
768ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.i3c3",         0xfff13000,   4 * KiB);
769ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.i3c4",         0xfff14000,   4 * KiB);
770ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.i3c5",         0xfff15000,   4 * KiB);
771ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.spixcs0",      0xf8000000,  16 * MiB);
772ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.spixcs1",      0xf9000000,  16 * MiB);
773ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.spix",         0xfb001000,   4 * KiB);
774ae0c4d1aSHao Wu     create_unimplemented_device("npcm8xx.vect",         0xffff0000,   256);
775ae0c4d1aSHao Wu }
776ae0c4d1aSHao Wu 
777ae0c4d1aSHao Wu static const Property npcm8xx_properties[] = {
778ae0c4d1aSHao Wu     DEFINE_PROP_LINK("dram-mr", NPCM8xxState, dram, TYPE_MEMORY_REGION,
779ae0c4d1aSHao Wu                      MemoryRegion *),
780ae0c4d1aSHao Wu };
781ae0c4d1aSHao Wu 
782*12d1a768SPhilippe Mathieu-Daudé static void npcm8xx_class_init(ObjectClass *oc, const void *data)
783ae0c4d1aSHao Wu {
784ae0c4d1aSHao Wu     DeviceClass *dc = DEVICE_CLASS(oc);
785ae0c4d1aSHao Wu     NPCM8xxClass *nc = NPCM8XX_CLASS(oc);
786ae0c4d1aSHao Wu 
787ae0c4d1aSHao Wu     dc->realize = npcm8xx_realize;
788ae0c4d1aSHao Wu     dc->user_creatable = false;
789ae0c4d1aSHao Wu     nc->disabled_modules = 0x00000000;
790ae0c4d1aSHao Wu     nc->num_cpus = NPCM8XX_MAX_NUM_CPUS;
791ae0c4d1aSHao Wu     device_class_set_props(dc, npcm8xx_properties);
792ae0c4d1aSHao Wu }
793ae0c4d1aSHao Wu 
794ae0c4d1aSHao Wu static const TypeInfo npcm8xx_soc_types[] = {
795ae0c4d1aSHao Wu     {
796ae0c4d1aSHao Wu         .name           = TYPE_NPCM8XX,
797ae0c4d1aSHao Wu         .parent         = TYPE_DEVICE,
798ae0c4d1aSHao Wu         .instance_size  = sizeof(NPCM8xxState),
799ae0c4d1aSHao Wu         .instance_init  = npcm8xx_init,
800ae0c4d1aSHao Wu         .class_size     = sizeof(NPCM8xxClass),
801ae0c4d1aSHao Wu         .class_init     = npcm8xx_class_init,
802ae0c4d1aSHao Wu     },
803ae0c4d1aSHao Wu };
804ae0c4d1aSHao Wu 
805ae0c4d1aSHao Wu DEFINE_TYPES(npcm8xx_soc_types);
806