xref: /qemu/hw/arm/npcm7xx.c (revision 750245ed7ce2a426a4eaf026f1af3a21fbdc19dc)
12d8f048cSHavard Skinnemoen /*
22d8f048cSHavard Skinnemoen  * Nuvoton NPCM7xx SoC family.
32d8f048cSHavard Skinnemoen  *
42d8f048cSHavard Skinnemoen  * Copyright 2020 Google LLC
52d8f048cSHavard Skinnemoen  *
62d8f048cSHavard Skinnemoen  * This program is free software; you can redistribute it and/or modify it
72d8f048cSHavard Skinnemoen  * under the terms of the GNU General Public License as published by the
82d8f048cSHavard Skinnemoen  * Free Software Foundation; either version 2 of the License, or
92d8f048cSHavard Skinnemoen  * (at your option) any later version.
102d8f048cSHavard Skinnemoen  *
112d8f048cSHavard Skinnemoen  * This program is distributed in the hope that it will be useful, but WITHOUT
122d8f048cSHavard Skinnemoen  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
132d8f048cSHavard Skinnemoen  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
142d8f048cSHavard Skinnemoen  * for more details.
152d8f048cSHavard Skinnemoen  */
162d8f048cSHavard Skinnemoen 
172d8f048cSHavard Skinnemoen #include "qemu/osdep.h"
182d8f048cSHavard Skinnemoen 
192d8f048cSHavard Skinnemoen #include "hw/arm/boot.h"
202d8f048cSHavard Skinnemoen #include "hw/arm/npcm7xx.h"
212d8f048cSHavard Skinnemoen #include "hw/char/serial.h"
222d8f048cSHavard Skinnemoen #include "hw/loader.h"
232d8f048cSHavard Skinnemoen #include "hw/misc/unimp.h"
240be12dc7SHao Wu #include "hw/qdev-clock.h"
252d8f048cSHavard Skinnemoen #include "hw/qdev-properties.h"
262d8f048cSHavard Skinnemoen #include "qapi/error.h"
272d8f048cSHavard Skinnemoen #include "qemu/units.h"
282d8f048cSHavard Skinnemoen #include "sysemu/sysemu.h"
292d8f048cSHavard Skinnemoen 
302d8f048cSHavard Skinnemoen /*
312d8f048cSHavard Skinnemoen  * This covers the whole MMIO space. We'll use this to catch any MMIO accesses
322d8f048cSHavard Skinnemoen  * that aren't handled by any device.
332d8f048cSHavard Skinnemoen  */
342d8f048cSHavard Skinnemoen #define NPCM7XX_MMIO_BA         (0x80000000)
352d8f048cSHavard Skinnemoen #define NPCM7XX_MMIO_SZ         (0x7ffd0000)
362d8f048cSHavard Skinnemoen 
37c752bb07SHavard Skinnemoen /* OTP key storage and fuse strap array */
38c752bb07SHavard Skinnemoen #define NPCM7XX_OTP1_BA         (0xf0189000)
39c752bb07SHavard Skinnemoen #define NPCM7XX_OTP2_BA         (0xf018a000)
40c752bb07SHavard Skinnemoen 
412d8f048cSHavard Skinnemoen /* Core system modules. */
422d8f048cSHavard Skinnemoen #define NPCM7XX_L2C_BA          (0xf03fc000)
432d8f048cSHavard Skinnemoen #define NPCM7XX_CPUP_BA         (0xf03fe000)
442d8f048cSHavard Skinnemoen #define NPCM7XX_GCR_BA          (0xf0800000)
452d8f048cSHavard Skinnemoen #define NPCM7XX_CLK_BA          (0xf0801000)
461351f892SHavard Skinnemoen #define NPCM7XX_MC_BA           (0xf0824000)
47326ccfe2SHavard Skinnemoen #define NPCM7XX_RNG_BA          (0xf000b000)
482d8f048cSHavard Skinnemoen 
49e23e7b12SHavard Skinnemoen /* USB Host modules */
50e23e7b12SHavard Skinnemoen #define NPCM7XX_EHCI_BA         (0xf0806000)
51e23e7b12SHavard Skinnemoen #define NPCM7XX_OHCI_BA         (0xf0807000)
52e23e7b12SHavard Skinnemoen 
5377c05b0bSHao Wu /* ADC Module */
5477c05b0bSHao Wu #define NPCM7XX_ADC_BA          (0xf000c000)
5577c05b0bSHao Wu 
562d8f048cSHavard Skinnemoen /* Internal AHB SRAM */
572d8f048cSHavard Skinnemoen #define NPCM7XX_RAM3_BA         (0xc0008000)
582d8f048cSHavard Skinnemoen #define NPCM7XX_RAM3_SZ         (4 * KiB)
592d8f048cSHavard Skinnemoen 
602d8f048cSHavard Skinnemoen /* Memory blocks at the end of the address space */
612d8f048cSHavard Skinnemoen #define NPCM7XX_RAM2_BA         (0xfffd0000)
622d8f048cSHavard Skinnemoen #define NPCM7XX_RAM2_SZ         (128 * KiB)
632d8f048cSHavard Skinnemoen #define NPCM7XX_ROM_BA          (0xffff0000)
642d8f048cSHavard Skinnemoen #define NPCM7XX_ROM_SZ          (64 * KiB)
652d8f048cSHavard Skinnemoen 
660a9df6cbSShengtan Mao /* SDHCI Modules */
670a9df6cbSShengtan Mao #define NPCM7XX_MMC_BA          (0xf0842000)
6877c05b0bSHao Wu 
692ddae9ccSHavard Skinnemoen /* Clock configuration values to be fixed up when bypassing bootloader */
702ddae9ccSHavard Skinnemoen 
712ddae9ccSHavard Skinnemoen /* Run PLL1 at 1600 MHz */
722ddae9ccSHavard Skinnemoen #define NPCM7XX_PLLCON1_FIXUP_VAL   (0x00402101)
732ddae9ccSHavard Skinnemoen /* Run the CPU from PLL1 and UART from PLL2 */
742ddae9ccSHavard Skinnemoen #define NPCM7XX_CLKSEL_FIXUP_VAL    (0x004aaba9)
752ddae9ccSHavard Skinnemoen 
762d8f048cSHavard Skinnemoen /*
772d8f048cSHavard Skinnemoen  * Interrupt lines going into the GIC. This does not include internal Cortex-A9
782d8f048cSHavard Skinnemoen  * interrupts.
792d8f048cSHavard Skinnemoen  */
802d8f048cSHavard Skinnemoen enum NPCM7xxInterrupt {
8177c05b0bSHao Wu     NPCM7XX_ADC_IRQ             = 0,
822d8f048cSHavard Skinnemoen     NPCM7XX_UART0_IRQ           = 2,
832d8f048cSHavard Skinnemoen     NPCM7XX_UART1_IRQ,
842d8f048cSHavard Skinnemoen     NPCM7XX_UART2_IRQ,
852d8f048cSHavard Skinnemoen     NPCM7XX_UART3_IRQ,
8677586436SDoug Evans     NPCM7XX_EMC1RX_IRQ          = 15,
8777586436SDoug Evans     NPCM7XX_EMC1TX_IRQ,
880a9df6cbSShengtan Mao     NPCM7XX_MMC_IRQ             = 26,
894d120d7dSHao Wu     NPCM7XX_PSPI2_IRQ           = 28,
904d120d7dSHao Wu     NPCM7XX_PSPI1_IRQ           = 31,
912d8f048cSHavard Skinnemoen     NPCM7XX_TIMER0_IRQ          = 32,   /* Timer Module 0 */
922d8f048cSHavard Skinnemoen     NPCM7XX_TIMER1_IRQ,
932d8f048cSHavard Skinnemoen     NPCM7XX_TIMER2_IRQ,
942d8f048cSHavard Skinnemoen     NPCM7XX_TIMER3_IRQ,
952d8f048cSHavard Skinnemoen     NPCM7XX_TIMER4_IRQ,
962d8f048cSHavard Skinnemoen     NPCM7XX_TIMER5_IRQ,                 /* Timer Module 1 */
972d8f048cSHavard Skinnemoen     NPCM7XX_TIMER6_IRQ,
982d8f048cSHavard Skinnemoen     NPCM7XX_TIMER7_IRQ,
992d8f048cSHavard Skinnemoen     NPCM7XX_TIMER8_IRQ,
1002d8f048cSHavard Skinnemoen     NPCM7XX_TIMER9_IRQ,
1012d8f048cSHavard Skinnemoen     NPCM7XX_TIMER10_IRQ,                /* Timer Module 2 */
1022d8f048cSHavard Skinnemoen     NPCM7XX_TIMER11_IRQ,
1032d8f048cSHavard Skinnemoen     NPCM7XX_TIMER12_IRQ,
1042d8f048cSHavard Skinnemoen     NPCM7XX_TIMER13_IRQ,
1052d8f048cSHavard Skinnemoen     NPCM7XX_TIMER14_IRQ,
1067d378ed6SHao Wu     NPCM7XX_WDG0_IRQ            = 47,   /* Timer Module 0 Watchdog */
1077d378ed6SHao Wu     NPCM7XX_WDG1_IRQ,                   /* Timer Module 1 Watchdog */
1087d378ed6SHao Wu     NPCM7XX_WDG2_IRQ,                   /* Timer Module 2 Watchdog */
109e23e7b12SHavard Skinnemoen     NPCM7XX_EHCI_IRQ            = 61,
110e23e7b12SHavard Skinnemoen     NPCM7XX_OHCI_IRQ            = 62,
11194e77879SHao Wu     NPCM7XX_SMBUS0_IRQ          = 64,
11294e77879SHao Wu     NPCM7XX_SMBUS1_IRQ,
11394e77879SHao Wu     NPCM7XX_SMBUS2_IRQ,
11494e77879SHao Wu     NPCM7XX_SMBUS3_IRQ,
11594e77879SHao Wu     NPCM7XX_SMBUS4_IRQ,
11694e77879SHao Wu     NPCM7XX_SMBUS5_IRQ,
11794e77879SHao Wu     NPCM7XX_SMBUS6_IRQ,
11894e77879SHao Wu     NPCM7XX_SMBUS7_IRQ,
11994e77879SHao Wu     NPCM7XX_SMBUS8_IRQ,
12094e77879SHao Wu     NPCM7XX_SMBUS9_IRQ,
12194e77879SHao Wu     NPCM7XX_SMBUS10_IRQ,
12294e77879SHao Wu     NPCM7XX_SMBUS11_IRQ,
12394e77879SHao Wu     NPCM7XX_SMBUS12_IRQ,
12494e77879SHao Wu     NPCM7XX_SMBUS13_IRQ,
12594e77879SHao Wu     NPCM7XX_SMBUS14_IRQ,
12694e77879SHao Wu     NPCM7XX_SMBUS15_IRQ,
1271e943c58SHao Wu     NPCM7XX_PWM0_IRQ            = 93,   /* PWM module 0 */
1281e943c58SHao Wu     NPCM7XX_PWM1_IRQ,                   /* PWM module 1 */
129fc11115fSHao Wu     NPCM7XX_MFT0_IRQ            = 96,   /* MFT module 0 */
130fc11115fSHao Wu     NPCM7XX_MFT1_IRQ,                   /* MFT module 1 */
131fc11115fSHao Wu     NPCM7XX_MFT2_IRQ,                   /* MFT module 2 */
132fc11115fSHao Wu     NPCM7XX_MFT3_IRQ,                   /* MFT module 3 */
133fc11115fSHao Wu     NPCM7XX_MFT4_IRQ,                   /* MFT module 4 */
134fc11115fSHao Wu     NPCM7XX_MFT5_IRQ,                   /* MFT module 5 */
135fc11115fSHao Wu     NPCM7XX_MFT6_IRQ,                   /* MFT module 6 */
136fc11115fSHao Wu     NPCM7XX_MFT7_IRQ,                   /* MFT module 7 */
13777586436SDoug Evans     NPCM7XX_EMC2RX_IRQ          = 114,
13877586436SDoug Evans     NPCM7XX_EMC2TX_IRQ,
139526dbbe0SHavard Skinnemoen     NPCM7XX_GPIO0_IRQ           = 116,
140526dbbe0SHavard Skinnemoen     NPCM7XX_GPIO1_IRQ,
141526dbbe0SHavard Skinnemoen     NPCM7XX_GPIO2_IRQ,
142526dbbe0SHavard Skinnemoen     NPCM7XX_GPIO3_IRQ,
143526dbbe0SHavard Skinnemoen     NPCM7XX_GPIO4_IRQ,
144526dbbe0SHavard Skinnemoen     NPCM7XX_GPIO5_IRQ,
145526dbbe0SHavard Skinnemoen     NPCM7XX_GPIO6_IRQ,
146526dbbe0SHavard Skinnemoen     NPCM7XX_GPIO7_IRQ,
1472d8f048cSHavard Skinnemoen };
1482d8f048cSHavard Skinnemoen 
1492d8f048cSHavard Skinnemoen /* Total number of GIC interrupts, including internal Cortex-A9 interrupts. */
1502d8f048cSHavard Skinnemoen #define NPCM7XX_NUM_IRQ         (160)
1512d8f048cSHavard Skinnemoen 
1522d8f048cSHavard Skinnemoen /* Register base address for each Timer Module */
1532d8f048cSHavard Skinnemoen static const hwaddr npcm7xx_tim_addr[] = {
1542d8f048cSHavard Skinnemoen     0xf0008000,
1552d8f048cSHavard Skinnemoen     0xf0009000,
1562d8f048cSHavard Skinnemoen     0xf000a000,
1572d8f048cSHavard Skinnemoen };
1582d8f048cSHavard Skinnemoen 
1592d8f048cSHavard Skinnemoen /* Register base address for each 16550 UART */
1602d8f048cSHavard Skinnemoen static const hwaddr npcm7xx_uart_addr[] = {
1612d8f048cSHavard Skinnemoen     0xf0001000,
1622d8f048cSHavard Skinnemoen     0xf0002000,
1632d8f048cSHavard Skinnemoen     0xf0003000,
1642d8f048cSHavard Skinnemoen     0xf0004000,
1652d8f048cSHavard Skinnemoen };
1662d8f048cSHavard Skinnemoen 
167b821242cSHavard Skinnemoen /* Direct memory-mapped access to SPI0 CS0-1. */
168b821242cSHavard Skinnemoen static const hwaddr npcm7xx_fiu0_flash_addr[] = {
169b821242cSHavard Skinnemoen     0x80000000, /* CS0 */
170b821242cSHavard Skinnemoen     0x88000000, /* CS1 */
171b821242cSHavard Skinnemoen };
172b821242cSHavard Skinnemoen 
173b821242cSHavard Skinnemoen /* Direct memory-mapped access to SPI3 CS0-3. */
174b821242cSHavard Skinnemoen static const hwaddr npcm7xx_fiu3_flash_addr[] = {
175b821242cSHavard Skinnemoen     0xa0000000, /* CS0 */
176b821242cSHavard Skinnemoen     0xa8000000, /* CS1 */
177b821242cSHavard Skinnemoen     0xb0000000, /* CS2 */
178b821242cSHavard Skinnemoen     0xb8000000, /* CS3 */
179b821242cSHavard Skinnemoen };
180b821242cSHavard Skinnemoen 
1811e943c58SHao Wu /* Register base address for each PWM Module */
1821e943c58SHao Wu static const hwaddr npcm7xx_pwm_addr[] = {
1831e943c58SHao Wu     0xf0103000,
1841e943c58SHao Wu     0xf0104000,
1851e943c58SHao Wu };
1861e943c58SHao Wu 
187fc11115fSHao Wu /* Register base address for each MFT Module */
188fc11115fSHao Wu static const hwaddr npcm7xx_mft_addr[] = {
189fc11115fSHao Wu     0xf0180000,
190fc11115fSHao Wu     0xf0181000,
191fc11115fSHao Wu     0xf0182000,
192fc11115fSHao Wu     0xf0183000,
193fc11115fSHao Wu     0xf0184000,
194fc11115fSHao Wu     0xf0185000,
195fc11115fSHao Wu     0xf0186000,
196fc11115fSHao Wu     0xf0187000,
197fc11115fSHao Wu };
198fc11115fSHao Wu 
19994e77879SHao Wu /* Direct memory-mapped access to each SMBus Module. */
20094e77879SHao Wu static const hwaddr npcm7xx_smbus_addr[] = {
20194e77879SHao Wu     0xf0080000,
20294e77879SHao Wu     0xf0081000,
20394e77879SHao Wu     0xf0082000,
20494e77879SHao Wu     0xf0083000,
20594e77879SHao Wu     0xf0084000,
20694e77879SHao Wu     0xf0085000,
20794e77879SHao Wu     0xf0086000,
20894e77879SHao Wu     0xf0087000,
20994e77879SHao Wu     0xf0088000,
21094e77879SHao Wu     0xf0089000,
21194e77879SHao Wu     0xf008a000,
21294e77879SHao Wu     0xf008b000,
21394e77879SHao Wu     0xf008c000,
21494e77879SHao Wu     0xf008d000,
21594e77879SHao Wu     0xf008e000,
21694e77879SHao Wu     0xf008f000,
21794e77879SHao Wu };
21894e77879SHao Wu 
21977586436SDoug Evans /* Register base address for each EMC Module */
22077586436SDoug Evans static const hwaddr npcm7xx_emc_addr[] = {
22177586436SDoug Evans     0xf0825000,
22277586436SDoug Evans     0xf0826000,
22377586436SDoug Evans };
22477586436SDoug Evans 
2254d120d7dSHao Wu /* Register base address for each PSPI Module */
2264d120d7dSHao Wu static const hwaddr npcm7xx_pspi_addr[] = {
2274d120d7dSHao Wu     0xf0200000,
2284d120d7dSHao Wu     0xf0201000,
2294d120d7dSHao Wu };
2304d120d7dSHao Wu 
231b821242cSHavard Skinnemoen static const struct {
232526dbbe0SHavard Skinnemoen     hwaddr regs_addr;
233526dbbe0SHavard Skinnemoen     uint32_t unconnected_pins;
234526dbbe0SHavard Skinnemoen     uint32_t reset_pu;
235526dbbe0SHavard Skinnemoen     uint32_t reset_pd;
236526dbbe0SHavard Skinnemoen     uint32_t reset_osrc;
237526dbbe0SHavard Skinnemoen     uint32_t reset_odsc;
238526dbbe0SHavard Skinnemoen } npcm7xx_gpio[] = {
239526dbbe0SHavard Skinnemoen     {
240526dbbe0SHavard Skinnemoen         .regs_addr = 0xf0010000,
241526dbbe0SHavard Skinnemoen         .reset_pu = 0xff03ffff,
242526dbbe0SHavard Skinnemoen         .reset_pd = 0x00fc0000,
243526dbbe0SHavard Skinnemoen     }, {
244526dbbe0SHavard Skinnemoen         .regs_addr = 0xf0011000,
245526dbbe0SHavard Skinnemoen         .unconnected_pins = 0x0000001e,
246526dbbe0SHavard Skinnemoen         .reset_pu = 0xfefffe07,
247526dbbe0SHavard Skinnemoen         .reset_pd = 0x010001e0,
248526dbbe0SHavard Skinnemoen     }, {
249526dbbe0SHavard Skinnemoen         .regs_addr = 0xf0012000,
250526dbbe0SHavard Skinnemoen         .reset_pu = 0x780fffff,
251526dbbe0SHavard Skinnemoen         .reset_pd = 0x07f00000,
252526dbbe0SHavard Skinnemoen         .reset_odsc = 0x00700000,
253526dbbe0SHavard Skinnemoen     }, {
254526dbbe0SHavard Skinnemoen         .regs_addr = 0xf0013000,
255526dbbe0SHavard Skinnemoen         .reset_pu = 0x00fc0000,
256526dbbe0SHavard Skinnemoen         .reset_pd = 0xff000000,
257526dbbe0SHavard Skinnemoen     }, {
258526dbbe0SHavard Skinnemoen         .regs_addr = 0xf0014000,
259526dbbe0SHavard Skinnemoen         .reset_pu = 0xffffffff,
260526dbbe0SHavard Skinnemoen     }, {
261526dbbe0SHavard Skinnemoen         .regs_addr = 0xf0015000,
262526dbbe0SHavard Skinnemoen         .reset_pu = 0xbf83f801,
263526dbbe0SHavard Skinnemoen         .reset_pd = 0x007c0000,
264526dbbe0SHavard Skinnemoen         .reset_osrc = 0x000000f1,
265526dbbe0SHavard Skinnemoen         .reset_odsc = 0x3f9f80f1,
266526dbbe0SHavard Skinnemoen     }, {
267526dbbe0SHavard Skinnemoen         .regs_addr = 0xf0016000,
268526dbbe0SHavard Skinnemoen         .reset_pu = 0xfc00f801,
269526dbbe0SHavard Skinnemoen         .reset_pd = 0x000007fe,
270526dbbe0SHavard Skinnemoen         .reset_odsc = 0x00000800,
271526dbbe0SHavard Skinnemoen     }, {
272526dbbe0SHavard Skinnemoen         .regs_addr = 0xf0017000,
273526dbbe0SHavard Skinnemoen         .unconnected_pins = 0xffffff00,
274526dbbe0SHavard Skinnemoen         .reset_pu = 0x0000007f,
275526dbbe0SHavard Skinnemoen         .reset_osrc = 0x0000007f,
276526dbbe0SHavard Skinnemoen         .reset_odsc = 0x0000007f,
277526dbbe0SHavard Skinnemoen     },
278526dbbe0SHavard Skinnemoen };
279526dbbe0SHavard Skinnemoen 
280526dbbe0SHavard Skinnemoen static const struct {
281b821242cSHavard Skinnemoen     const char *name;
282b821242cSHavard Skinnemoen     hwaddr regs_addr;
283b821242cSHavard Skinnemoen     int cs_count;
284b821242cSHavard Skinnemoen     const hwaddr *flash_addr;
285b821242cSHavard Skinnemoen } npcm7xx_fiu[] = {
286b821242cSHavard Skinnemoen     {
287b821242cSHavard Skinnemoen         .name = "fiu0",
288b821242cSHavard Skinnemoen         .regs_addr = 0xfb000000,
289b821242cSHavard Skinnemoen         .cs_count = ARRAY_SIZE(npcm7xx_fiu0_flash_addr),
290b821242cSHavard Skinnemoen         .flash_addr = npcm7xx_fiu0_flash_addr,
291b821242cSHavard Skinnemoen     }, {
292b821242cSHavard Skinnemoen         .name = "fiu3",
293b821242cSHavard Skinnemoen         .regs_addr = 0xc0000000,
294b821242cSHavard Skinnemoen         .cs_count = ARRAY_SIZE(npcm7xx_fiu3_flash_addr),
295b821242cSHavard Skinnemoen         .flash_addr = npcm7xx_fiu3_flash_addr,
296b821242cSHavard Skinnemoen     },
297b821242cSHavard Skinnemoen };
298b821242cSHavard Skinnemoen 
2992ddae9ccSHavard Skinnemoen static void npcm7xx_write_board_setup(ARMCPU *cpu,
3002ddae9ccSHavard Skinnemoen                                       const struct arm_boot_info *info)
3012ddae9ccSHavard Skinnemoen {
3022ddae9ccSHavard Skinnemoen     uint32_t board_setup[] = {
3032ddae9ccSHavard Skinnemoen         0xe59f0010,     /* ldr r0, clk_base_addr */
3042ddae9ccSHavard Skinnemoen         0xe59f1010,     /* ldr r1, pllcon1_value */
3052ddae9ccSHavard Skinnemoen         0xe5801010,     /* str r1, [r0, #16] */
3062ddae9ccSHavard Skinnemoen         0xe59f100c,     /* ldr r1, clksel_value */
3072ddae9ccSHavard Skinnemoen         0xe5801004,     /* str r1, [r0, #4] */
3082ddae9ccSHavard Skinnemoen         0xe12fff1e,     /* bx lr */
3092ddae9ccSHavard Skinnemoen         NPCM7XX_CLK_BA,
3102ddae9ccSHavard Skinnemoen         NPCM7XX_PLLCON1_FIXUP_VAL,
3112ddae9ccSHavard Skinnemoen         NPCM7XX_CLKSEL_FIXUP_VAL,
3122ddae9ccSHavard Skinnemoen     };
3132ddae9ccSHavard Skinnemoen     int i;
3142ddae9ccSHavard Skinnemoen 
3152ddae9ccSHavard Skinnemoen     for (i = 0; i < ARRAY_SIZE(board_setup); i++) {
3162ddae9ccSHavard Skinnemoen         board_setup[i] = tswap32(board_setup[i]);
3172ddae9ccSHavard Skinnemoen     }
3182ddae9ccSHavard Skinnemoen     rom_add_blob_fixed("board-setup", board_setup, sizeof(board_setup),
3192ddae9ccSHavard Skinnemoen                        info->board_setup_addr);
3202ddae9ccSHavard Skinnemoen }
3212ddae9ccSHavard Skinnemoen 
3222d8f048cSHavard Skinnemoen static void npcm7xx_write_secondary_boot(ARMCPU *cpu,
3232d8f048cSHavard Skinnemoen                                          const struct arm_boot_info *info)
3242d8f048cSHavard Skinnemoen {
3252d8f048cSHavard Skinnemoen     /*
3262d8f048cSHavard Skinnemoen      * The default smpboot stub halts the secondary CPU with a 'wfi'
3272d8f048cSHavard Skinnemoen      * instruction, but the arch/arm/mach-npcm/platsmp.c in the Linux kernel
3282d8f048cSHavard Skinnemoen      * does not send an IPI to wake it up, so the second CPU fails to boot. So
3292d8f048cSHavard Skinnemoen      * we need to provide our own smpboot stub that can not use 'wfi', it has
3302d8f048cSHavard Skinnemoen      * to spin the secondary CPU until the first CPU writes to the SCRPAD reg.
3312d8f048cSHavard Skinnemoen      */
3322d8f048cSHavard Skinnemoen     uint32_t smpboot[] = {
3332d8f048cSHavard Skinnemoen         0xe59f2018,     /* ldr r2, bootreg_addr */
3342d8f048cSHavard Skinnemoen         0xe3a00000,     /* mov r0, #0 */
3352d8f048cSHavard Skinnemoen         0xe5820000,     /* str r0, [r2] */
3362d8f048cSHavard Skinnemoen         0xe320f002,     /* wfe */
3372d8f048cSHavard Skinnemoen         0xe5921000,     /* ldr r1, [r2] */
3382d8f048cSHavard Skinnemoen         0xe1110001,     /* tst r1, r1 */
3392d8f048cSHavard Skinnemoen         0x0afffffb,     /* beq <wfe> */
3402d8f048cSHavard Skinnemoen         0xe12fff11,     /* bx r1 */
3412d8f048cSHavard Skinnemoen         NPCM7XX_SMP_BOOTREG_ADDR,
3422d8f048cSHavard Skinnemoen     };
3432d8f048cSHavard Skinnemoen     int i;
3442d8f048cSHavard Skinnemoen 
3452d8f048cSHavard Skinnemoen     for (i = 0; i < ARRAY_SIZE(smpboot); i++) {
3462d8f048cSHavard Skinnemoen         smpboot[i] = tswap32(smpboot[i]);
3472d8f048cSHavard Skinnemoen     }
3482d8f048cSHavard Skinnemoen 
3492d8f048cSHavard Skinnemoen     rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot),
3502d8f048cSHavard Skinnemoen                        NPCM7XX_SMP_LOADER_START);
3512d8f048cSHavard Skinnemoen }
3522d8f048cSHavard Skinnemoen 
3532d8f048cSHavard Skinnemoen static struct arm_boot_info npcm7xx_binfo = {
3542d8f048cSHavard Skinnemoen     .loader_start           = NPCM7XX_LOADER_START,
3552d8f048cSHavard Skinnemoen     .smp_loader_start       = NPCM7XX_SMP_LOADER_START,
3562d8f048cSHavard Skinnemoen     .smp_bootreg_addr       = NPCM7XX_SMP_BOOTREG_ADDR,
3572d8f048cSHavard Skinnemoen     .gic_cpu_if_addr        = NPCM7XX_GIC_CPU_IF_ADDR,
3582d8f048cSHavard Skinnemoen     .write_secondary_boot   = npcm7xx_write_secondary_boot,
3592d8f048cSHavard Skinnemoen     .board_id               = -1,
3602ddae9ccSHavard Skinnemoen     .board_setup_addr       = NPCM7XX_BOARD_SETUP_ADDR,
3612ddae9ccSHavard Skinnemoen     .write_board_setup      = npcm7xx_write_board_setup,
3622d8f048cSHavard Skinnemoen };
3632d8f048cSHavard Skinnemoen 
3642d8f048cSHavard Skinnemoen void npcm7xx_load_kernel(MachineState *machine, NPCM7xxState *soc)
3652d8f048cSHavard Skinnemoen {
3662d8f048cSHavard Skinnemoen     npcm7xx_binfo.ram_size = machine->ram_size;
3672d8f048cSHavard Skinnemoen 
3682d8f048cSHavard Skinnemoen     arm_load_kernel(&soc->cpu[0], machine, &npcm7xx_binfo);
3692d8f048cSHavard Skinnemoen }
3702d8f048cSHavard Skinnemoen 
371c752bb07SHavard Skinnemoen static void npcm7xx_init_fuses(NPCM7xxState *s)
372c752bb07SHavard Skinnemoen {
373c752bb07SHavard Skinnemoen     NPCM7xxClass *nc = NPCM7XX_GET_CLASS(s);
374c752bb07SHavard Skinnemoen     uint32_t value;
375c752bb07SHavard Skinnemoen 
376c752bb07SHavard Skinnemoen     /*
377c752bb07SHavard Skinnemoen      * The initial mask of disabled modules indicates the chip derivative (e.g.
378c752bb07SHavard Skinnemoen      * NPCM750 or NPCM730).
379c752bb07SHavard Skinnemoen      */
380c752bb07SHavard Skinnemoen     value = tswap32(nc->disabled_modules);
381c752bb07SHavard Skinnemoen     npcm7xx_otp_array_write(&s->fuse_array, &value, NPCM7XX_FUSE_DERIVATIVE,
382c752bb07SHavard Skinnemoen                             sizeof(value));
383c752bb07SHavard Skinnemoen }
384c752bb07SHavard Skinnemoen 
38577c05b0bSHao Wu static void npcm7xx_write_adc_calibration(NPCM7xxState *s)
38677c05b0bSHao Wu {
38777c05b0bSHao Wu     /* Both ADC and the fuse array must have realized. */
38877c05b0bSHao Wu     QEMU_BUILD_BUG_ON(sizeof(s->adc.calibration_r_values) != 4);
38977c05b0bSHao Wu     npcm7xx_otp_array_write(&s->fuse_array, s->adc.calibration_r_values,
39077c05b0bSHao Wu             NPCM7XX_FUSE_ADC_CALIB, sizeof(s->adc.calibration_r_values));
39177c05b0bSHao Wu }
39277c05b0bSHao Wu 
3932d8f048cSHavard Skinnemoen static qemu_irq npcm7xx_irq(NPCM7xxState *s, int n)
3942d8f048cSHavard Skinnemoen {
3952d8f048cSHavard Skinnemoen     return qdev_get_gpio_in(DEVICE(&s->a9mpcore), n);
3962d8f048cSHavard Skinnemoen }
3972d8f048cSHavard Skinnemoen 
3982d8f048cSHavard Skinnemoen static void npcm7xx_init(Object *obj)
3992d8f048cSHavard Skinnemoen {
4002d8f048cSHavard Skinnemoen     NPCM7xxState *s = NPCM7XX(obj);
4012d8f048cSHavard Skinnemoen     int i;
4022d8f048cSHavard Skinnemoen 
4032d8f048cSHavard Skinnemoen     for (i = 0; i < NPCM7XX_MAX_NUM_CPUS; i++) {
4042d8f048cSHavard Skinnemoen         object_initialize_child(obj, "cpu[*]", &s->cpu[i],
4052d8f048cSHavard Skinnemoen                                 ARM_CPU_TYPE_NAME("cortex-a9"));
4062d8f048cSHavard Skinnemoen     }
4072d8f048cSHavard Skinnemoen 
4082d8f048cSHavard Skinnemoen     object_initialize_child(obj, "a9mpcore", &s->a9mpcore, TYPE_A9MPCORE_PRIV);
4092d8f048cSHavard Skinnemoen     object_initialize_child(obj, "gcr", &s->gcr, TYPE_NPCM7XX_GCR);
4102d8f048cSHavard Skinnemoen     object_property_add_alias(obj, "power-on-straps", OBJECT(&s->gcr),
4112d8f048cSHavard Skinnemoen                               "power-on-straps");
4122d8f048cSHavard Skinnemoen     object_initialize_child(obj, "clk", &s->clk, TYPE_NPCM7XX_CLK);
413c752bb07SHavard Skinnemoen     object_initialize_child(obj, "otp1", &s->key_storage,
414c752bb07SHavard Skinnemoen                             TYPE_NPCM7XX_KEY_STORAGE);
415c752bb07SHavard Skinnemoen     object_initialize_child(obj, "otp2", &s->fuse_array,
416c752bb07SHavard Skinnemoen                             TYPE_NPCM7XX_FUSE_ARRAY);
4171351f892SHavard Skinnemoen     object_initialize_child(obj, "mc", &s->mc, TYPE_NPCM7XX_MC);
418326ccfe2SHavard Skinnemoen     object_initialize_child(obj, "rng", &s->rng, TYPE_NPCM7XX_RNG);
41977c05b0bSHao Wu     object_initialize_child(obj, "adc", &s->adc, TYPE_NPCM7XX_ADC);
4202d8f048cSHavard Skinnemoen 
4212d8f048cSHavard Skinnemoen     for (i = 0; i < ARRAY_SIZE(s->tim); i++) {
4222d8f048cSHavard Skinnemoen         object_initialize_child(obj, "tim[*]", &s->tim[i], TYPE_NPCM7XX_TIMER);
4232d8f048cSHavard Skinnemoen     }
424b821242cSHavard Skinnemoen 
425526dbbe0SHavard Skinnemoen     for (i = 0; i < ARRAY_SIZE(s->gpio); i++) {
426526dbbe0SHavard Skinnemoen         object_initialize_child(obj, "gpio[*]", &s->gpio[i], TYPE_NPCM7XX_GPIO);
427526dbbe0SHavard Skinnemoen     }
428526dbbe0SHavard Skinnemoen 
42994e77879SHao Wu     for (i = 0; i < ARRAY_SIZE(s->smbus); i++) {
43094e77879SHao Wu         object_initialize_child(obj, "smbus[*]", &s->smbus[i],
43194e77879SHao Wu                                 TYPE_NPCM7XX_SMBUS);
43294e77879SHao Wu     }
43394e77879SHao Wu 
434e23e7b12SHavard Skinnemoen     object_initialize_child(obj, "ehci", &s->ehci, TYPE_NPCM7XX_EHCI);
435e23e7b12SHavard Skinnemoen     object_initialize_child(obj, "ohci", &s->ohci, TYPE_SYSBUS_OHCI);
436e23e7b12SHavard Skinnemoen 
437b821242cSHavard Skinnemoen     QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_fiu) != ARRAY_SIZE(s->fiu));
438b821242cSHavard Skinnemoen     for (i = 0; i < ARRAY_SIZE(s->fiu); i++) {
439b821242cSHavard Skinnemoen         object_initialize_child(obj, npcm7xx_fiu[i].name, &s->fiu[i],
440b821242cSHavard Skinnemoen                                 TYPE_NPCM7XX_FIU);
441b821242cSHavard Skinnemoen     }
4421e943c58SHao Wu 
4431e943c58SHao Wu     for (i = 0; i < ARRAY_SIZE(s->pwm); i++) {
4441e943c58SHao Wu         object_initialize_child(obj, "pwm[*]", &s->pwm[i], TYPE_NPCM7XX_PWM);
4451e943c58SHao Wu     }
44677586436SDoug Evans 
447fc11115fSHao Wu     for (i = 0; i < ARRAY_SIZE(s->mft); i++) {
448fc11115fSHao Wu         object_initialize_child(obj, "mft[*]", &s->mft[i], TYPE_NPCM7XX_MFT);
449fc11115fSHao Wu     }
450fc11115fSHao Wu 
45177586436SDoug Evans     for (i = 0; i < ARRAY_SIZE(s->emc); i++) {
45277586436SDoug Evans         object_initialize_child(obj, "emc[*]", &s->emc[i], TYPE_NPCM7XX_EMC);
45377586436SDoug Evans     }
4540a9df6cbSShengtan Mao 
4554d120d7dSHao Wu     for (i = 0; i < ARRAY_SIZE(s->pspi); i++) {
4564d120d7dSHao Wu         object_initialize_child(obj, "pspi[*]", &s->pspi[i], TYPE_NPCM_PSPI);
4574d120d7dSHao Wu     }
4584d120d7dSHao Wu 
4590a9df6cbSShengtan Mao     object_initialize_child(obj, "mmc", &s->mmc, TYPE_NPCM7XX_SDHCI);
4602d8f048cSHavard Skinnemoen }
4612d8f048cSHavard Skinnemoen 
4622d8f048cSHavard Skinnemoen static void npcm7xx_realize(DeviceState *dev, Error **errp)
4632d8f048cSHavard Skinnemoen {
4642d8f048cSHavard Skinnemoen     NPCM7xxState *s = NPCM7XX(dev);
4652d8f048cSHavard Skinnemoen     NPCM7xxClass *nc = NPCM7XX_GET_CLASS(s);
4662d8f048cSHavard Skinnemoen     int i;
4672d8f048cSHavard Skinnemoen 
4682d8f048cSHavard Skinnemoen     if (memory_region_size(s->dram) > NPCM7XX_DRAM_SZ) {
4692d8f048cSHavard Skinnemoen         error_setg(errp, "%s: NPCM7xx cannot address more than %" PRIu64
4702d8f048cSHavard Skinnemoen                    " MiB of DRAM", __func__, NPCM7XX_DRAM_SZ / MiB);
4712d8f048cSHavard Skinnemoen         return;
4722d8f048cSHavard Skinnemoen     }
4732d8f048cSHavard Skinnemoen 
4742d8f048cSHavard Skinnemoen     /* CPUs */
4752d8f048cSHavard Skinnemoen     for (i = 0; i < nc->num_cpus; i++) {
4762d8f048cSHavard Skinnemoen         object_property_set_int(OBJECT(&s->cpu[i]), "mp-affinity",
477*750245edSRichard Henderson                                 arm_build_mp_affinity(i, NPCM7XX_MAX_NUM_CPUS),
4782d8f048cSHavard Skinnemoen                                 &error_abort);
4792d8f048cSHavard Skinnemoen         object_property_set_int(OBJECT(&s->cpu[i]), "reset-cbar",
4802d8f048cSHavard Skinnemoen                                 NPCM7XX_GIC_CPU_IF_ADDR, &error_abort);
4812d8f048cSHavard Skinnemoen         object_property_set_bool(OBJECT(&s->cpu[i]), "reset-hivecs", true,
4822d8f048cSHavard Skinnemoen                                  &error_abort);
4832d8f048cSHavard Skinnemoen 
4842d8f048cSHavard Skinnemoen         /* Disable security extensions. */
4852d8f048cSHavard Skinnemoen         object_property_set_bool(OBJECT(&s->cpu[i]), "has_el3", false,
4862d8f048cSHavard Skinnemoen                                  &error_abort);
4872d8f048cSHavard Skinnemoen 
4882d8f048cSHavard Skinnemoen         if (!qdev_realize(DEVICE(&s->cpu[i]), NULL, errp)) {
4892d8f048cSHavard Skinnemoen             return;
4902d8f048cSHavard Skinnemoen         }
4912d8f048cSHavard Skinnemoen     }
4922d8f048cSHavard Skinnemoen 
4932d8f048cSHavard Skinnemoen     /* A9MPCORE peripherals. Can only fail if we pass bad parameters here. */
4942d8f048cSHavard Skinnemoen     object_property_set_int(OBJECT(&s->a9mpcore), "num-cpu", nc->num_cpus,
4952d8f048cSHavard Skinnemoen                             &error_abort);
4962d8f048cSHavard Skinnemoen     object_property_set_int(OBJECT(&s->a9mpcore), "num-irq", NPCM7XX_NUM_IRQ,
4972d8f048cSHavard Skinnemoen                             &error_abort);
4982d8f048cSHavard Skinnemoen     sysbus_realize(SYS_BUS_DEVICE(&s->a9mpcore), &error_abort);
4992d8f048cSHavard Skinnemoen     sysbus_mmio_map(SYS_BUS_DEVICE(&s->a9mpcore), 0, NPCM7XX_CPUP_BA);
5002d8f048cSHavard Skinnemoen 
5012d8f048cSHavard Skinnemoen     for (i = 0; i < nc->num_cpus; i++) {
5022d8f048cSHavard Skinnemoen         sysbus_connect_irq(SYS_BUS_DEVICE(&s->a9mpcore), i,
5032d8f048cSHavard Skinnemoen                            qdev_get_gpio_in(DEVICE(&s->cpu[i]), ARM_CPU_IRQ));
5042d8f048cSHavard Skinnemoen         sysbus_connect_irq(SYS_BUS_DEVICE(&s->a9mpcore), i + nc->num_cpus,
5052d8f048cSHavard Skinnemoen                            qdev_get_gpio_in(DEVICE(&s->cpu[i]), ARM_CPU_FIQ));
5062d8f048cSHavard Skinnemoen     }
5072d8f048cSHavard Skinnemoen 
5082d8f048cSHavard Skinnemoen     /* L2 cache controller */
5092d8f048cSHavard Skinnemoen     sysbus_create_simple("l2x0", NPCM7XX_L2C_BA, NULL);
5102d8f048cSHavard Skinnemoen 
5112d8f048cSHavard Skinnemoen     /* System Global Control Registers (GCR). Can fail due to user input. */
5122d8f048cSHavard Skinnemoen     object_property_set_int(OBJECT(&s->gcr), "disabled-modules",
5132d8f048cSHavard Skinnemoen                             nc->disabled_modules, &error_abort);
5142d8f048cSHavard Skinnemoen     object_property_add_const_link(OBJECT(&s->gcr), "dram-mr", OBJECT(s->dram));
5152d8f048cSHavard Skinnemoen     if (!sysbus_realize(SYS_BUS_DEVICE(&s->gcr), errp)) {
5162d8f048cSHavard Skinnemoen         return;
5172d8f048cSHavard Skinnemoen     }
5182d8f048cSHavard Skinnemoen     sysbus_mmio_map(SYS_BUS_DEVICE(&s->gcr), 0, NPCM7XX_GCR_BA);
5192d8f048cSHavard Skinnemoen 
5202d8f048cSHavard Skinnemoen     /* Clock Control Registers (CLK). Cannot fail. */
5212d8f048cSHavard Skinnemoen     sysbus_realize(SYS_BUS_DEVICE(&s->clk), &error_abort);
5222d8f048cSHavard Skinnemoen     sysbus_mmio_map(SYS_BUS_DEVICE(&s->clk), 0, NPCM7XX_CLK_BA);
5232d8f048cSHavard Skinnemoen 
524c752bb07SHavard Skinnemoen     /* OTP key storage and fuse strap array. Cannot fail. */
525c752bb07SHavard Skinnemoen     sysbus_realize(SYS_BUS_DEVICE(&s->key_storage), &error_abort);
526c752bb07SHavard Skinnemoen     sysbus_mmio_map(SYS_BUS_DEVICE(&s->key_storage), 0, NPCM7XX_OTP1_BA);
527c752bb07SHavard Skinnemoen     sysbus_realize(SYS_BUS_DEVICE(&s->fuse_array), &error_abort);
528c752bb07SHavard Skinnemoen     sysbus_mmio_map(SYS_BUS_DEVICE(&s->fuse_array), 0, NPCM7XX_OTP2_BA);
529c752bb07SHavard Skinnemoen     npcm7xx_init_fuses(s);
530c752bb07SHavard Skinnemoen 
5311351f892SHavard Skinnemoen     /* Fake Memory Controller (MC). Cannot fail. */
5321351f892SHavard Skinnemoen     sysbus_realize(SYS_BUS_DEVICE(&s->mc), &error_abort);
5331351f892SHavard Skinnemoen     sysbus_mmio_map(SYS_BUS_DEVICE(&s->mc), 0, NPCM7XX_MC_BA);
5341351f892SHavard Skinnemoen 
53577c05b0bSHao Wu     /* ADC Modules. Cannot fail. */
53677c05b0bSHao Wu     qdev_connect_clock_in(DEVICE(&s->adc), "clock", qdev_get_clock_out(
53777c05b0bSHao Wu                           DEVICE(&s->clk), "adc-clock"));
53877c05b0bSHao Wu     sysbus_realize(SYS_BUS_DEVICE(&s->adc), &error_abort);
53977c05b0bSHao Wu     sysbus_mmio_map(SYS_BUS_DEVICE(&s->adc), 0, NPCM7XX_ADC_BA);
54077c05b0bSHao Wu     sysbus_connect_irq(SYS_BUS_DEVICE(&s->adc), 0,
54177c05b0bSHao Wu             npcm7xx_irq(s, NPCM7XX_ADC_IRQ));
54277c05b0bSHao Wu     npcm7xx_write_adc_calibration(s);
54377c05b0bSHao Wu 
5442d8f048cSHavard Skinnemoen     /* Timer Modules (TIM). Cannot fail. */
5452d8f048cSHavard Skinnemoen     QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_tim_addr) != ARRAY_SIZE(s->tim));
5462d8f048cSHavard Skinnemoen     for (i = 0; i < ARRAY_SIZE(s->tim); i++) {
5472d8f048cSHavard Skinnemoen         SysBusDevice *sbd = SYS_BUS_DEVICE(&s->tim[i]);
5482d8f048cSHavard Skinnemoen         int first_irq;
5492d8f048cSHavard Skinnemoen         int j;
5502d8f048cSHavard Skinnemoen 
5510be12dc7SHao Wu         /* Connect the timer clock. */
5520be12dc7SHao Wu         qdev_connect_clock_in(DEVICE(&s->tim[i]), "clock", qdev_get_clock_out(
5530be12dc7SHao Wu                     DEVICE(&s->clk), "timer-clock"));
5540be12dc7SHao Wu 
5552d8f048cSHavard Skinnemoen         sysbus_realize(sbd, &error_abort);
5562d8f048cSHavard Skinnemoen         sysbus_mmio_map(sbd, 0, npcm7xx_tim_addr[i]);
5572d8f048cSHavard Skinnemoen 
5582d8f048cSHavard Skinnemoen         first_irq = NPCM7XX_TIMER0_IRQ + i * NPCM7XX_TIMERS_PER_CTRL;
5592d8f048cSHavard Skinnemoen         for (j = 0; j < NPCM7XX_TIMERS_PER_CTRL; j++) {
5602d8f048cSHavard Skinnemoen             qemu_irq irq = npcm7xx_irq(s, first_irq + j);
5612d8f048cSHavard Skinnemoen             sysbus_connect_irq(sbd, j, irq);
5622d8f048cSHavard Skinnemoen         }
5637d378ed6SHao Wu 
5647d378ed6SHao Wu         /* IRQ for watchdogs */
5657d378ed6SHao Wu         sysbus_connect_irq(sbd, NPCM7XX_TIMERS_PER_CTRL,
5667d378ed6SHao Wu                 npcm7xx_irq(s, NPCM7XX_WDG0_IRQ + i));
5677d378ed6SHao Wu         /* GPIO that connects clk module with watchdog */
5687d378ed6SHao Wu         qdev_connect_gpio_out_named(DEVICE(&s->tim[i]),
5697d378ed6SHao Wu                 NPCM7XX_WATCHDOG_RESET_GPIO_OUT, 0,
5707d378ed6SHao Wu                 qdev_get_gpio_in_named(DEVICE(&s->clk),
5717d378ed6SHao Wu                         NPCM7XX_WATCHDOG_RESET_GPIO_IN, i));
5722d8f048cSHavard Skinnemoen     }
5732d8f048cSHavard Skinnemoen 
5742d8f048cSHavard Skinnemoen     /* UART0..3 (16550 compatible) */
5752d8f048cSHavard Skinnemoen     for (i = 0; i < ARRAY_SIZE(npcm7xx_uart_addr); i++) {
5762d8f048cSHavard Skinnemoen         serial_mm_init(get_system_memory(), npcm7xx_uart_addr[i], 2,
5772d8f048cSHavard Skinnemoen                        npcm7xx_irq(s, NPCM7XX_UART0_IRQ + i), 115200,
5782d8f048cSHavard Skinnemoen                        serial_hd(i), DEVICE_LITTLE_ENDIAN);
5792d8f048cSHavard Skinnemoen     }
5802d8f048cSHavard Skinnemoen 
581326ccfe2SHavard Skinnemoen     /* Random Number Generator. Cannot fail. */
582326ccfe2SHavard Skinnemoen     sysbus_realize(SYS_BUS_DEVICE(&s->rng), &error_abort);
583326ccfe2SHavard Skinnemoen     sysbus_mmio_map(SYS_BUS_DEVICE(&s->rng), 0, NPCM7XX_RNG_BA);
584326ccfe2SHavard Skinnemoen 
585526dbbe0SHavard Skinnemoen     /* GPIO modules. Cannot fail. */
586526dbbe0SHavard Skinnemoen     QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_gpio) != ARRAY_SIZE(s->gpio));
587526dbbe0SHavard Skinnemoen     for (i = 0; i < ARRAY_SIZE(s->gpio); i++) {
588526dbbe0SHavard Skinnemoen         Object *obj = OBJECT(&s->gpio[i]);
589526dbbe0SHavard Skinnemoen 
590526dbbe0SHavard Skinnemoen         object_property_set_uint(obj, "reset-pullup",
591526dbbe0SHavard Skinnemoen                                  npcm7xx_gpio[i].reset_pu, &error_abort);
592526dbbe0SHavard Skinnemoen         object_property_set_uint(obj, "reset-pulldown",
593526dbbe0SHavard Skinnemoen                                  npcm7xx_gpio[i].reset_pd, &error_abort);
594526dbbe0SHavard Skinnemoen         object_property_set_uint(obj, "reset-osrc",
595526dbbe0SHavard Skinnemoen                                  npcm7xx_gpio[i].reset_osrc, &error_abort);
596526dbbe0SHavard Skinnemoen         object_property_set_uint(obj, "reset-odsc",
597526dbbe0SHavard Skinnemoen                                  npcm7xx_gpio[i].reset_odsc, &error_abort);
598526dbbe0SHavard Skinnemoen         sysbus_realize(SYS_BUS_DEVICE(obj), &error_abort);
599526dbbe0SHavard Skinnemoen         sysbus_mmio_map(SYS_BUS_DEVICE(obj), 0, npcm7xx_gpio[i].regs_addr);
600526dbbe0SHavard Skinnemoen         sysbus_connect_irq(SYS_BUS_DEVICE(obj), 0,
601526dbbe0SHavard Skinnemoen                            npcm7xx_irq(s, NPCM7XX_GPIO0_IRQ + i));
602526dbbe0SHavard Skinnemoen     }
603526dbbe0SHavard Skinnemoen 
60494e77879SHao Wu     /* SMBus modules. Cannot fail. */
60594e77879SHao Wu     QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_smbus_addr) != ARRAY_SIZE(s->smbus));
60694e77879SHao Wu     for (i = 0; i < ARRAY_SIZE(s->smbus); i++) {
60794e77879SHao Wu         Object *obj = OBJECT(&s->smbus[i]);
60894e77879SHao Wu 
60994e77879SHao Wu         sysbus_realize(SYS_BUS_DEVICE(obj), &error_abort);
61094e77879SHao Wu         sysbus_mmio_map(SYS_BUS_DEVICE(obj), 0, npcm7xx_smbus_addr[i]);
61194e77879SHao Wu         sysbus_connect_irq(SYS_BUS_DEVICE(obj), 0,
61294e77879SHao Wu                            npcm7xx_irq(s, NPCM7XX_SMBUS0_IRQ + i));
61394e77879SHao Wu     }
61494e77879SHao Wu 
615e23e7b12SHavard Skinnemoen     /* USB Host */
616e23e7b12SHavard Skinnemoen     object_property_set_bool(OBJECT(&s->ehci), "companion-enable", true,
617e23e7b12SHavard Skinnemoen                              &error_abort);
618e23e7b12SHavard Skinnemoen     sysbus_realize(SYS_BUS_DEVICE(&s->ehci), &error_abort);
619e23e7b12SHavard Skinnemoen     sysbus_mmio_map(SYS_BUS_DEVICE(&s->ehci), 0, NPCM7XX_EHCI_BA);
620e23e7b12SHavard Skinnemoen     sysbus_connect_irq(SYS_BUS_DEVICE(&s->ehci), 0,
621e23e7b12SHavard Skinnemoen                        npcm7xx_irq(s, NPCM7XX_EHCI_IRQ));
622e23e7b12SHavard Skinnemoen 
623e23e7b12SHavard Skinnemoen     object_property_set_str(OBJECT(&s->ohci), "masterbus", "usb-bus.0",
624e23e7b12SHavard Skinnemoen                             &error_abort);
625e23e7b12SHavard Skinnemoen     object_property_set_uint(OBJECT(&s->ohci), "num-ports", 1, &error_abort);
626e23e7b12SHavard Skinnemoen     sysbus_realize(SYS_BUS_DEVICE(&s->ohci), &error_abort);
627e23e7b12SHavard Skinnemoen     sysbus_mmio_map(SYS_BUS_DEVICE(&s->ohci), 0, NPCM7XX_OHCI_BA);
628e23e7b12SHavard Skinnemoen     sysbus_connect_irq(SYS_BUS_DEVICE(&s->ohci), 0,
629e23e7b12SHavard Skinnemoen                        npcm7xx_irq(s, NPCM7XX_OHCI_IRQ));
630e23e7b12SHavard Skinnemoen 
6311e943c58SHao Wu     /* PWM Modules. Cannot fail. */
6321e943c58SHao Wu     QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_pwm_addr) != ARRAY_SIZE(s->pwm));
6331e943c58SHao Wu     for (i = 0; i < ARRAY_SIZE(s->pwm); i++) {
6341e943c58SHao Wu         SysBusDevice *sbd = SYS_BUS_DEVICE(&s->pwm[i]);
6351e943c58SHao Wu 
6361e943c58SHao Wu         qdev_connect_clock_in(DEVICE(&s->pwm[i]), "clock", qdev_get_clock_out(
6371e943c58SHao Wu                     DEVICE(&s->clk), "apb3-clock"));
6381e943c58SHao Wu         sysbus_realize(sbd, &error_abort);
6391e943c58SHao Wu         sysbus_mmio_map(sbd, 0, npcm7xx_pwm_addr[i]);
6401e943c58SHao Wu         sysbus_connect_irq(sbd, i, npcm7xx_irq(s, NPCM7XX_PWM0_IRQ + i));
6411e943c58SHao Wu     }
6421e943c58SHao Wu 
643fc11115fSHao Wu     /* MFT Modules. Cannot fail. */
644fc11115fSHao Wu     QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_mft_addr) != ARRAY_SIZE(s->mft));
645fc11115fSHao Wu     for (i = 0; i < ARRAY_SIZE(s->mft); i++) {
646fc11115fSHao Wu         SysBusDevice *sbd = SYS_BUS_DEVICE(&s->mft[i]);
647fc11115fSHao Wu 
648fc11115fSHao Wu         qdev_connect_clock_in(DEVICE(&s->mft[i]), "clock-in",
649fc11115fSHao Wu                               qdev_get_clock_out(DEVICE(&s->clk),
650fc11115fSHao Wu                                                  "apb4-clock"));
651fc11115fSHao Wu         sysbus_realize(sbd, &error_abort);
652fc11115fSHao Wu         sysbus_mmio_map(sbd, 0, npcm7xx_mft_addr[i]);
653fc11115fSHao Wu         sysbus_connect_irq(sbd, 0, npcm7xx_irq(s, NPCM7XX_MFT0_IRQ + i));
654fc11115fSHao Wu     }
655fc11115fSHao Wu 
656b821242cSHavard Skinnemoen     /*
65777586436SDoug Evans      * EMC Modules. Cannot fail.
65877586436SDoug Evans      * The mapping of the device to its netdev backend works as follows:
65977586436SDoug Evans      * emc[i] = nd_table[i]
66077586436SDoug Evans      * This works around the inability to specify the netdev property for the
66177586436SDoug Evans      * emc device: it's not pluggable and thus the -device option can't be
66277586436SDoug Evans      * used.
66377586436SDoug Evans      */
66477586436SDoug Evans     QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_emc_addr) != ARRAY_SIZE(s->emc));
66577586436SDoug Evans     QEMU_BUILD_BUG_ON(ARRAY_SIZE(s->emc) != 2);
66677586436SDoug Evans     for (i = 0; i < ARRAY_SIZE(s->emc); i++) {
66777586436SDoug Evans         s->emc[i].emc_num = i;
66877586436SDoug Evans         SysBusDevice *sbd = SYS_BUS_DEVICE(&s->emc[i]);
66977586436SDoug Evans         if (nd_table[i].used) {
67077586436SDoug Evans             qemu_check_nic_model(&nd_table[i], TYPE_NPCM7XX_EMC);
67177586436SDoug Evans             qdev_set_nic_properties(DEVICE(sbd), &nd_table[i]);
67277586436SDoug Evans         }
67377586436SDoug Evans         /*
67477586436SDoug Evans          * The device exists regardless of whether it's connected to a QEMU
67577586436SDoug Evans          * netdev backend. So always instantiate it even if there is no
67677586436SDoug Evans          * backend.
67777586436SDoug Evans          */
67877586436SDoug Evans         sysbus_realize(sbd, &error_abort);
67977586436SDoug Evans         sysbus_mmio_map(sbd, 0, npcm7xx_emc_addr[i]);
68077586436SDoug Evans         int tx_irq = i == 0 ? NPCM7XX_EMC1TX_IRQ : NPCM7XX_EMC2TX_IRQ;
68177586436SDoug Evans         int rx_irq = i == 0 ? NPCM7XX_EMC1RX_IRQ : NPCM7XX_EMC2RX_IRQ;
68277586436SDoug Evans         /*
68377586436SDoug Evans          * N.B. The values for the second argument sysbus_connect_irq are
68477586436SDoug Evans          * chosen to match the registration order in npcm7xx_emc_realize.
68577586436SDoug Evans          */
68677586436SDoug Evans         sysbus_connect_irq(sbd, 0, npcm7xx_irq(s, tx_irq));
68777586436SDoug Evans         sysbus_connect_irq(sbd, 1, npcm7xx_irq(s, rx_irq));
68877586436SDoug Evans     }
68977586436SDoug Evans 
69077586436SDoug Evans     /*
691b821242cSHavard Skinnemoen      * Flash Interface Unit (FIU). Can fail if incorrect number of chip selects
692b821242cSHavard Skinnemoen      * specified, but this is a programming error.
693b821242cSHavard Skinnemoen      */
694b821242cSHavard Skinnemoen     QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_fiu) != ARRAY_SIZE(s->fiu));
695b821242cSHavard Skinnemoen     for (i = 0; i < ARRAY_SIZE(s->fiu); i++) {
696b821242cSHavard Skinnemoen         SysBusDevice *sbd = SYS_BUS_DEVICE(&s->fiu[i]);
697b821242cSHavard Skinnemoen         int j;
698b821242cSHavard Skinnemoen 
699b821242cSHavard Skinnemoen         object_property_set_int(OBJECT(sbd), "cs-count",
700b821242cSHavard Skinnemoen                                 npcm7xx_fiu[i].cs_count, &error_abort);
701b821242cSHavard Skinnemoen         sysbus_realize(sbd, &error_abort);
702b821242cSHavard Skinnemoen 
703b821242cSHavard Skinnemoen         sysbus_mmio_map(sbd, 0, npcm7xx_fiu[i].regs_addr);
704b821242cSHavard Skinnemoen         for (j = 0; j < npcm7xx_fiu[i].cs_count; j++) {
705b821242cSHavard Skinnemoen             sysbus_mmio_map(sbd, j + 1, npcm7xx_fiu[i].flash_addr[j]);
706b821242cSHavard Skinnemoen         }
707b821242cSHavard Skinnemoen     }
708b821242cSHavard Skinnemoen 
7092d8f048cSHavard Skinnemoen     /* RAM2 (SRAM) */
7102d8f048cSHavard Skinnemoen     memory_region_init_ram(&s->sram, OBJECT(dev), "ram2",
7112d8f048cSHavard Skinnemoen                            NPCM7XX_RAM2_SZ, &error_abort);
7122d8f048cSHavard Skinnemoen     memory_region_add_subregion(get_system_memory(), NPCM7XX_RAM2_BA, &s->sram);
7132d8f048cSHavard Skinnemoen 
7142d8f048cSHavard Skinnemoen     /* RAM3 (SRAM) */
7152d8f048cSHavard Skinnemoen     memory_region_init_ram(&s->ram3, OBJECT(dev), "ram3",
7162d8f048cSHavard Skinnemoen                            NPCM7XX_RAM3_SZ, &error_abort);
7172d8f048cSHavard Skinnemoen     memory_region_add_subregion(get_system_memory(), NPCM7XX_RAM3_BA, &s->ram3);
7182d8f048cSHavard Skinnemoen 
7192d8f048cSHavard Skinnemoen     /* Internal ROM */
7202d8f048cSHavard Skinnemoen     memory_region_init_rom(&s->irom, OBJECT(dev), "irom", NPCM7XX_ROM_SZ,
7212d8f048cSHavard Skinnemoen                            &error_abort);
7222d8f048cSHavard Skinnemoen     memory_region_add_subregion(get_system_memory(), NPCM7XX_ROM_BA, &s->irom);
7232d8f048cSHavard Skinnemoen 
7240a9df6cbSShengtan Mao     /* SDHCI */
7250a9df6cbSShengtan Mao     sysbus_realize(SYS_BUS_DEVICE(&s->mmc), &error_abort);
7260a9df6cbSShengtan Mao     sysbus_mmio_map(SYS_BUS_DEVICE(&s->mmc), 0, NPCM7XX_MMC_BA);
7270a9df6cbSShengtan Mao     sysbus_connect_irq(SYS_BUS_DEVICE(&s->mmc), 0,
7280a9df6cbSShengtan Mao             npcm7xx_irq(s, NPCM7XX_MMC_IRQ));
7290a9df6cbSShengtan Mao 
7304d120d7dSHao Wu     /* PSPI */
7314d120d7dSHao Wu     QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_pspi_addr) != ARRAY_SIZE(s->pspi));
7324d120d7dSHao Wu     for (i = 0; i < ARRAY_SIZE(s->pspi); i++) {
7334d120d7dSHao Wu         SysBusDevice *sbd = SYS_BUS_DEVICE(&s->pspi[i]);
7344d120d7dSHao Wu         int irq = (i == 0) ? NPCM7XX_PSPI1_IRQ : NPCM7XX_PSPI2_IRQ;
7354d120d7dSHao Wu 
7364d120d7dSHao Wu         sysbus_realize(sbd, &error_abort);
7374d120d7dSHao Wu         sysbus_mmio_map(sbd, 0, npcm7xx_pspi_addr[i]);
7384d120d7dSHao Wu         sysbus_connect_irq(sbd, 0, npcm7xx_irq(s, irq));
7394d120d7dSHao Wu     }
7404d120d7dSHao Wu 
7412d8f048cSHavard Skinnemoen     create_unimplemented_device("npcm7xx.shm",          0xc0001000,   4 * KiB);
7422d8f048cSHavard Skinnemoen     create_unimplemented_device("npcm7xx.vdmx",         0xe0800000,   4 * KiB);
7432d8f048cSHavard Skinnemoen     create_unimplemented_device("npcm7xx.pcierc",       0xe1000000,  64 * KiB);
7442d8f048cSHavard Skinnemoen     create_unimplemented_device("npcm7xx.kcs",          0xf0007000,   4 * KiB);
7452d8f048cSHavard Skinnemoen     create_unimplemented_device("npcm7xx.gfxi",         0xf000e000,   4 * KiB);
7462d8f048cSHavard Skinnemoen     create_unimplemented_device("npcm7xx.espi",         0xf009f000,   4 * KiB);
7472d8f048cSHavard Skinnemoen     create_unimplemented_device("npcm7xx.peci",         0xf0100000,   4 * KiB);
7482d8f048cSHavard Skinnemoen     create_unimplemented_device("npcm7xx.siox[1]",      0xf0101000,   4 * KiB);
7492d8f048cSHavard Skinnemoen     create_unimplemented_device("npcm7xx.siox[2]",      0xf0102000,   4 * KiB);
7502d8f048cSHavard Skinnemoen     create_unimplemented_device("npcm7xx.ahbpci",       0xf0400000,   1 * MiB);
7512d8f048cSHavard Skinnemoen     create_unimplemented_device("npcm7xx.mcphy",        0xf05f0000,  64 * KiB);
7522d8f048cSHavard Skinnemoen     create_unimplemented_device("npcm7xx.gmac1",        0xf0802000,   8 * KiB);
7532d8f048cSHavard Skinnemoen     create_unimplemented_device("npcm7xx.gmac2",        0xf0804000,   8 * KiB);
7542d8f048cSHavard Skinnemoen     create_unimplemented_device("npcm7xx.vcd",          0xf0810000,  64 * KiB);
7552d8f048cSHavard Skinnemoen     create_unimplemented_device("npcm7xx.ece",          0xf0820000,   8 * KiB);
7562d8f048cSHavard Skinnemoen     create_unimplemented_device("npcm7xx.vdma",         0xf0822000,   8 * KiB);
7572d8f048cSHavard Skinnemoen     create_unimplemented_device("npcm7xx.usbd[0]",      0xf0830000,   4 * KiB);
7582d8f048cSHavard Skinnemoen     create_unimplemented_device("npcm7xx.usbd[1]",      0xf0831000,   4 * KiB);
7592d8f048cSHavard Skinnemoen     create_unimplemented_device("npcm7xx.usbd[2]",      0xf0832000,   4 * KiB);
7602d8f048cSHavard Skinnemoen     create_unimplemented_device("npcm7xx.usbd[3]",      0xf0833000,   4 * KiB);
7612d8f048cSHavard Skinnemoen     create_unimplemented_device("npcm7xx.usbd[4]",      0xf0834000,   4 * KiB);
7622d8f048cSHavard Skinnemoen     create_unimplemented_device("npcm7xx.usbd[5]",      0xf0835000,   4 * KiB);
7632d8f048cSHavard Skinnemoen     create_unimplemented_device("npcm7xx.usbd[6]",      0xf0836000,   4 * KiB);
7642d8f048cSHavard Skinnemoen     create_unimplemented_device("npcm7xx.usbd[7]",      0xf0837000,   4 * KiB);
7652d8f048cSHavard Skinnemoen     create_unimplemented_device("npcm7xx.usbd[8]",      0xf0838000,   4 * KiB);
7662d8f048cSHavard Skinnemoen     create_unimplemented_device("npcm7xx.usbd[9]",      0xf0839000,   4 * KiB);
7672d8f048cSHavard Skinnemoen     create_unimplemented_device("npcm7xx.sd",           0xf0840000,   8 * KiB);
7682d8f048cSHavard Skinnemoen     create_unimplemented_device("npcm7xx.pcimbx",       0xf0848000, 512 * KiB);
7692d8f048cSHavard Skinnemoen     create_unimplemented_device("npcm7xx.aes",          0xf0858000,   4 * KiB);
7702d8f048cSHavard Skinnemoen     create_unimplemented_device("npcm7xx.des",          0xf0859000,   4 * KiB);
7712d8f048cSHavard Skinnemoen     create_unimplemented_device("npcm7xx.sha",          0xf085a000,   4 * KiB);
7722d8f048cSHavard Skinnemoen     create_unimplemented_device("npcm7xx.secacc",       0xf085b000,   4 * KiB);
7732d8f048cSHavard Skinnemoen     create_unimplemented_device("npcm7xx.spixcs0",      0xf8000000,  16 * MiB);
7742d8f048cSHavard Skinnemoen     create_unimplemented_device("npcm7xx.spixcs1",      0xf9000000,  16 * MiB);
7752d8f048cSHavard Skinnemoen     create_unimplemented_device("npcm7xx.spix",         0xfb001000,   4 * KiB);
7762d8f048cSHavard Skinnemoen }
7772d8f048cSHavard Skinnemoen 
7782d8f048cSHavard Skinnemoen static Property npcm7xx_properties[] = {
7792d8f048cSHavard Skinnemoen     DEFINE_PROP_LINK("dram-mr", NPCM7xxState, dram, TYPE_MEMORY_REGION,
7802d8f048cSHavard Skinnemoen                      MemoryRegion *),
7812d8f048cSHavard Skinnemoen     DEFINE_PROP_END_OF_LIST(),
7822d8f048cSHavard Skinnemoen };
7832d8f048cSHavard Skinnemoen 
7842d8f048cSHavard Skinnemoen static void npcm7xx_class_init(ObjectClass *oc, void *data)
7852d8f048cSHavard Skinnemoen {
7862d8f048cSHavard Skinnemoen     DeviceClass *dc = DEVICE_CLASS(oc);
7872d8f048cSHavard Skinnemoen 
7882d8f048cSHavard Skinnemoen     dc->realize = npcm7xx_realize;
7892d8f048cSHavard Skinnemoen     dc->user_creatable = false;
7902d8f048cSHavard Skinnemoen     device_class_set_props(dc, npcm7xx_properties);
7912d8f048cSHavard Skinnemoen }
7922d8f048cSHavard Skinnemoen 
7932d8f048cSHavard Skinnemoen static void npcm730_class_init(ObjectClass *oc, void *data)
7942d8f048cSHavard Skinnemoen {
7952d8f048cSHavard Skinnemoen     NPCM7xxClass *nc = NPCM7XX_CLASS(oc);
7962d8f048cSHavard Skinnemoen 
7972d8f048cSHavard Skinnemoen     /* NPCM730 is optimized for data center use, so no graphics, etc. */
7982d8f048cSHavard Skinnemoen     nc->disabled_modules = 0x00300395;
7992d8f048cSHavard Skinnemoen     nc->num_cpus = 2;
8002d8f048cSHavard Skinnemoen }
8012d8f048cSHavard Skinnemoen 
8022d8f048cSHavard Skinnemoen static void npcm750_class_init(ObjectClass *oc, void *data)
8032d8f048cSHavard Skinnemoen {
8042d8f048cSHavard Skinnemoen     NPCM7xxClass *nc = NPCM7XX_CLASS(oc);
8052d8f048cSHavard Skinnemoen 
8062d8f048cSHavard Skinnemoen     /* NPCM750 has 2 cores and a full set of peripherals */
8072d8f048cSHavard Skinnemoen     nc->disabled_modules = 0x00000000;
8082d8f048cSHavard Skinnemoen     nc->num_cpus = 2;
8092d8f048cSHavard Skinnemoen }
8102d8f048cSHavard Skinnemoen 
8112d8f048cSHavard Skinnemoen static const TypeInfo npcm7xx_soc_types[] = {
8122d8f048cSHavard Skinnemoen     {
8132d8f048cSHavard Skinnemoen         .name           = TYPE_NPCM7XX,
8142d8f048cSHavard Skinnemoen         .parent         = TYPE_DEVICE,
8152d8f048cSHavard Skinnemoen         .instance_size  = sizeof(NPCM7xxState),
8162d8f048cSHavard Skinnemoen         .instance_init  = npcm7xx_init,
8172d8f048cSHavard Skinnemoen         .class_size     = sizeof(NPCM7xxClass),
8182d8f048cSHavard Skinnemoen         .class_init     = npcm7xx_class_init,
8192d8f048cSHavard Skinnemoen         .abstract       = true,
8202d8f048cSHavard Skinnemoen     }, {
8212d8f048cSHavard Skinnemoen         .name           = TYPE_NPCM730,
8222d8f048cSHavard Skinnemoen         .parent         = TYPE_NPCM7XX,
8232d8f048cSHavard Skinnemoen         .class_init     = npcm730_class_init,
8242d8f048cSHavard Skinnemoen     }, {
8252d8f048cSHavard Skinnemoen         .name           = TYPE_NPCM750,
8262d8f048cSHavard Skinnemoen         .parent         = TYPE_NPCM7XX,
8272d8f048cSHavard Skinnemoen         .class_init     = npcm750_class_init,
8282d8f048cSHavard Skinnemoen     },
8292d8f048cSHavard Skinnemoen };
8302d8f048cSHavard Skinnemoen 
8312d8f048cSHavard Skinnemoen DEFINE_TYPES(npcm7xx_soc_types);
832