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