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 66*0a9df6cbSShengtan Mao /* SDHCI Modules */ 67*0a9df6cbSShengtan 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, 88*0a9df6cbSShengtan Mao NPCM7XX_MMC_IRQ = 26, 892d8f048cSHavard Skinnemoen NPCM7XX_TIMER0_IRQ = 32, /* Timer Module 0 */ 902d8f048cSHavard Skinnemoen NPCM7XX_TIMER1_IRQ, 912d8f048cSHavard Skinnemoen NPCM7XX_TIMER2_IRQ, 922d8f048cSHavard Skinnemoen NPCM7XX_TIMER3_IRQ, 932d8f048cSHavard Skinnemoen NPCM7XX_TIMER4_IRQ, 942d8f048cSHavard Skinnemoen NPCM7XX_TIMER5_IRQ, /* Timer Module 1 */ 952d8f048cSHavard Skinnemoen NPCM7XX_TIMER6_IRQ, 962d8f048cSHavard Skinnemoen NPCM7XX_TIMER7_IRQ, 972d8f048cSHavard Skinnemoen NPCM7XX_TIMER8_IRQ, 982d8f048cSHavard Skinnemoen NPCM7XX_TIMER9_IRQ, 992d8f048cSHavard Skinnemoen NPCM7XX_TIMER10_IRQ, /* Timer Module 2 */ 1002d8f048cSHavard Skinnemoen NPCM7XX_TIMER11_IRQ, 1012d8f048cSHavard Skinnemoen NPCM7XX_TIMER12_IRQ, 1022d8f048cSHavard Skinnemoen NPCM7XX_TIMER13_IRQ, 1032d8f048cSHavard Skinnemoen NPCM7XX_TIMER14_IRQ, 1047d378ed6SHao Wu NPCM7XX_WDG0_IRQ = 47, /* Timer Module 0 Watchdog */ 1057d378ed6SHao Wu NPCM7XX_WDG1_IRQ, /* Timer Module 1 Watchdog */ 1067d378ed6SHao Wu NPCM7XX_WDG2_IRQ, /* Timer Module 2 Watchdog */ 107e23e7b12SHavard Skinnemoen NPCM7XX_EHCI_IRQ = 61, 108e23e7b12SHavard Skinnemoen NPCM7XX_OHCI_IRQ = 62, 10994e77879SHao Wu NPCM7XX_SMBUS0_IRQ = 64, 11094e77879SHao Wu NPCM7XX_SMBUS1_IRQ, 11194e77879SHao Wu NPCM7XX_SMBUS2_IRQ, 11294e77879SHao Wu NPCM7XX_SMBUS3_IRQ, 11394e77879SHao Wu NPCM7XX_SMBUS4_IRQ, 11494e77879SHao Wu NPCM7XX_SMBUS5_IRQ, 11594e77879SHao Wu NPCM7XX_SMBUS6_IRQ, 11694e77879SHao Wu NPCM7XX_SMBUS7_IRQ, 11794e77879SHao Wu NPCM7XX_SMBUS8_IRQ, 11894e77879SHao Wu NPCM7XX_SMBUS9_IRQ, 11994e77879SHao Wu NPCM7XX_SMBUS10_IRQ, 12094e77879SHao Wu NPCM7XX_SMBUS11_IRQ, 12194e77879SHao Wu NPCM7XX_SMBUS12_IRQ, 12294e77879SHao Wu NPCM7XX_SMBUS13_IRQ, 12394e77879SHao Wu NPCM7XX_SMBUS14_IRQ, 12494e77879SHao Wu NPCM7XX_SMBUS15_IRQ, 1251e943c58SHao Wu NPCM7XX_PWM0_IRQ = 93, /* PWM module 0 */ 1261e943c58SHao Wu NPCM7XX_PWM1_IRQ, /* PWM module 1 */ 127fc11115fSHao Wu NPCM7XX_MFT0_IRQ = 96, /* MFT module 0 */ 128fc11115fSHao Wu NPCM7XX_MFT1_IRQ, /* MFT module 1 */ 129fc11115fSHao Wu NPCM7XX_MFT2_IRQ, /* MFT module 2 */ 130fc11115fSHao Wu NPCM7XX_MFT3_IRQ, /* MFT module 3 */ 131fc11115fSHao Wu NPCM7XX_MFT4_IRQ, /* MFT module 4 */ 132fc11115fSHao Wu NPCM7XX_MFT5_IRQ, /* MFT module 5 */ 133fc11115fSHao Wu NPCM7XX_MFT6_IRQ, /* MFT module 6 */ 134fc11115fSHao Wu NPCM7XX_MFT7_IRQ, /* MFT module 7 */ 13577586436SDoug Evans NPCM7XX_EMC2RX_IRQ = 114, 13677586436SDoug Evans NPCM7XX_EMC2TX_IRQ, 137526dbbe0SHavard Skinnemoen NPCM7XX_GPIO0_IRQ = 116, 138526dbbe0SHavard Skinnemoen NPCM7XX_GPIO1_IRQ, 139526dbbe0SHavard Skinnemoen NPCM7XX_GPIO2_IRQ, 140526dbbe0SHavard Skinnemoen NPCM7XX_GPIO3_IRQ, 141526dbbe0SHavard Skinnemoen NPCM7XX_GPIO4_IRQ, 142526dbbe0SHavard Skinnemoen NPCM7XX_GPIO5_IRQ, 143526dbbe0SHavard Skinnemoen NPCM7XX_GPIO6_IRQ, 144526dbbe0SHavard Skinnemoen NPCM7XX_GPIO7_IRQ, 1452d8f048cSHavard Skinnemoen }; 1462d8f048cSHavard Skinnemoen 1472d8f048cSHavard Skinnemoen /* Total number of GIC interrupts, including internal Cortex-A9 interrupts. */ 1482d8f048cSHavard Skinnemoen #define NPCM7XX_NUM_IRQ (160) 1492d8f048cSHavard Skinnemoen 1502d8f048cSHavard Skinnemoen /* Register base address for each Timer Module */ 1512d8f048cSHavard Skinnemoen static const hwaddr npcm7xx_tim_addr[] = { 1522d8f048cSHavard Skinnemoen 0xf0008000, 1532d8f048cSHavard Skinnemoen 0xf0009000, 1542d8f048cSHavard Skinnemoen 0xf000a000, 1552d8f048cSHavard Skinnemoen }; 1562d8f048cSHavard Skinnemoen 1572d8f048cSHavard Skinnemoen /* Register base address for each 16550 UART */ 1582d8f048cSHavard Skinnemoen static const hwaddr npcm7xx_uart_addr[] = { 1592d8f048cSHavard Skinnemoen 0xf0001000, 1602d8f048cSHavard Skinnemoen 0xf0002000, 1612d8f048cSHavard Skinnemoen 0xf0003000, 1622d8f048cSHavard Skinnemoen 0xf0004000, 1632d8f048cSHavard Skinnemoen }; 1642d8f048cSHavard Skinnemoen 165b821242cSHavard Skinnemoen /* Direct memory-mapped access to SPI0 CS0-1. */ 166b821242cSHavard Skinnemoen static const hwaddr npcm7xx_fiu0_flash_addr[] = { 167b821242cSHavard Skinnemoen 0x80000000, /* CS0 */ 168b821242cSHavard Skinnemoen 0x88000000, /* CS1 */ 169b821242cSHavard Skinnemoen }; 170b821242cSHavard Skinnemoen 171b821242cSHavard Skinnemoen /* Direct memory-mapped access to SPI3 CS0-3. */ 172b821242cSHavard Skinnemoen static const hwaddr npcm7xx_fiu3_flash_addr[] = { 173b821242cSHavard Skinnemoen 0xa0000000, /* CS0 */ 174b821242cSHavard Skinnemoen 0xa8000000, /* CS1 */ 175b821242cSHavard Skinnemoen 0xb0000000, /* CS2 */ 176b821242cSHavard Skinnemoen 0xb8000000, /* CS3 */ 177b821242cSHavard Skinnemoen }; 178b821242cSHavard Skinnemoen 1791e943c58SHao Wu /* Register base address for each PWM Module */ 1801e943c58SHao Wu static const hwaddr npcm7xx_pwm_addr[] = { 1811e943c58SHao Wu 0xf0103000, 1821e943c58SHao Wu 0xf0104000, 1831e943c58SHao Wu }; 1841e943c58SHao Wu 185fc11115fSHao Wu /* Register base address for each MFT Module */ 186fc11115fSHao Wu static const hwaddr npcm7xx_mft_addr[] = { 187fc11115fSHao Wu 0xf0180000, 188fc11115fSHao Wu 0xf0181000, 189fc11115fSHao Wu 0xf0182000, 190fc11115fSHao Wu 0xf0183000, 191fc11115fSHao Wu 0xf0184000, 192fc11115fSHao Wu 0xf0185000, 193fc11115fSHao Wu 0xf0186000, 194fc11115fSHao Wu 0xf0187000, 195fc11115fSHao Wu }; 196fc11115fSHao Wu 19794e77879SHao Wu /* Direct memory-mapped access to each SMBus Module. */ 19894e77879SHao Wu static const hwaddr npcm7xx_smbus_addr[] = { 19994e77879SHao Wu 0xf0080000, 20094e77879SHao Wu 0xf0081000, 20194e77879SHao Wu 0xf0082000, 20294e77879SHao Wu 0xf0083000, 20394e77879SHao Wu 0xf0084000, 20494e77879SHao Wu 0xf0085000, 20594e77879SHao Wu 0xf0086000, 20694e77879SHao Wu 0xf0087000, 20794e77879SHao Wu 0xf0088000, 20894e77879SHao Wu 0xf0089000, 20994e77879SHao Wu 0xf008a000, 21094e77879SHao Wu 0xf008b000, 21194e77879SHao Wu 0xf008c000, 21294e77879SHao Wu 0xf008d000, 21394e77879SHao Wu 0xf008e000, 21494e77879SHao Wu 0xf008f000, 21594e77879SHao Wu }; 21694e77879SHao Wu 21777586436SDoug Evans /* Register base address for each EMC Module */ 21877586436SDoug Evans static const hwaddr npcm7xx_emc_addr[] = { 21977586436SDoug Evans 0xf0825000, 22077586436SDoug Evans 0xf0826000, 22177586436SDoug Evans }; 22277586436SDoug Evans 223b821242cSHavard Skinnemoen static const struct { 224526dbbe0SHavard Skinnemoen hwaddr regs_addr; 225526dbbe0SHavard Skinnemoen uint32_t unconnected_pins; 226526dbbe0SHavard Skinnemoen uint32_t reset_pu; 227526dbbe0SHavard Skinnemoen uint32_t reset_pd; 228526dbbe0SHavard Skinnemoen uint32_t reset_osrc; 229526dbbe0SHavard Skinnemoen uint32_t reset_odsc; 230526dbbe0SHavard Skinnemoen } npcm7xx_gpio[] = { 231526dbbe0SHavard Skinnemoen { 232526dbbe0SHavard Skinnemoen .regs_addr = 0xf0010000, 233526dbbe0SHavard Skinnemoen .reset_pu = 0xff03ffff, 234526dbbe0SHavard Skinnemoen .reset_pd = 0x00fc0000, 235526dbbe0SHavard Skinnemoen }, { 236526dbbe0SHavard Skinnemoen .regs_addr = 0xf0011000, 237526dbbe0SHavard Skinnemoen .unconnected_pins = 0x0000001e, 238526dbbe0SHavard Skinnemoen .reset_pu = 0xfefffe07, 239526dbbe0SHavard Skinnemoen .reset_pd = 0x010001e0, 240526dbbe0SHavard Skinnemoen }, { 241526dbbe0SHavard Skinnemoen .regs_addr = 0xf0012000, 242526dbbe0SHavard Skinnemoen .reset_pu = 0x780fffff, 243526dbbe0SHavard Skinnemoen .reset_pd = 0x07f00000, 244526dbbe0SHavard Skinnemoen .reset_odsc = 0x00700000, 245526dbbe0SHavard Skinnemoen }, { 246526dbbe0SHavard Skinnemoen .regs_addr = 0xf0013000, 247526dbbe0SHavard Skinnemoen .reset_pu = 0x00fc0000, 248526dbbe0SHavard Skinnemoen .reset_pd = 0xff000000, 249526dbbe0SHavard Skinnemoen }, { 250526dbbe0SHavard Skinnemoen .regs_addr = 0xf0014000, 251526dbbe0SHavard Skinnemoen .reset_pu = 0xffffffff, 252526dbbe0SHavard Skinnemoen }, { 253526dbbe0SHavard Skinnemoen .regs_addr = 0xf0015000, 254526dbbe0SHavard Skinnemoen .reset_pu = 0xbf83f801, 255526dbbe0SHavard Skinnemoen .reset_pd = 0x007c0000, 256526dbbe0SHavard Skinnemoen .reset_osrc = 0x000000f1, 257526dbbe0SHavard Skinnemoen .reset_odsc = 0x3f9f80f1, 258526dbbe0SHavard Skinnemoen }, { 259526dbbe0SHavard Skinnemoen .regs_addr = 0xf0016000, 260526dbbe0SHavard Skinnemoen .reset_pu = 0xfc00f801, 261526dbbe0SHavard Skinnemoen .reset_pd = 0x000007fe, 262526dbbe0SHavard Skinnemoen .reset_odsc = 0x00000800, 263526dbbe0SHavard Skinnemoen }, { 264526dbbe0SHavard Skinnemoen .regs_addr = 0xf0017000, 265526dbbe0SHavard Skinnemoen .unconnected_pins = 0xffffff00, 266526dbbe0SHavard Skinnemoen .reset_pu = 0x0000007f, 267526dbbe0SHavard Skinnemoen .reset_osrc = 0x0000007f, 268526dbbe0SHavard Skinnemoen .reset_odsc = 0x0000007f, 269526dbbe0SHavard Skinnemoen }, 270526dbbe0SHavard Skinnemoen }; 271526dbbe0SHavard Skinnemoen 272526dbbe0SHavard Skinnemoen static const struct { 273b821242cSHavard Skinnemoen const char *name; 274b821242cSHavard Skinnemoen hwaddr regs_addr; 275b821242cSHavard Skinnemoen int cs_count; 276b821242cSHavard Skinnemoen const hwaddr *flash_addr; 277b821242cSHavard Skinnemoen } npcm7xx_fiu[] = { 278b821242cSHavard Skinnemoen { 279b821242cSHavard Skinnemoen .name = "fiu0", 280b821242cSHavard Skinnemoen .regs_addr = 0xfb000000, 281b821242cSHavard Skinnemoen .cs_count = ARRAY_SIZE(npcm7xx_fiu0_flash_addr), 282b821242cSHavard Skinnemoen .flash_addr = npcm7xx_fiu0_flash_addr, 283b821242cSHavard Skinnemoen }, { 284b821242cSHavard Skinnemoen .name = "fiu3", 285b821242cSHavard Skinnemoen .regs_addr = 0xc0000000, 286b821242cSHavard Skinnemoen .cs_count = ARRAY_SIZE(npcm7xx_fiu3_flash_addr), 287b821242cSHavard Skinnemoen .flash_addr = npcm7xx_fiu3_flash_addr, 288b821242cSHavard Skinnemoen }, 289b821242cSHavard Skinnemoen }; 290b821242cSHavard Skinnemoen 2912ddae9ccSHavard Skinnemoen static void npcm7xx_write_board_setup(ARMCPU *cpu, 2922ddae9ccSHavard Skinnemoen const struct arm_boot_info *info) 2932ddae9ccSHavard Skinnemoen { 2942ddae9ccSHavard Skinnemoen uint32_t board_setup[] = { 2952ddae9ccSHavard Skinnemoen 0xe59f0010, /* ldr r0, clk_base_addr */ 2962ddae9ccSHavard Skinnemoen 0xe59f1010, /* ldr r1, pllcon1_value */ 2972ddae9ccSHavard Skinnemoen 0xe5801010, /* str r1, [r0, #16] */ 2982ddae9ccSHavard Skinnemoen 0xe59f100c, /* ldr r1, clksel_value */ 2992ddae9ccSHavard Skinnemoen 0xe5801004, /* str r1, [r0, #4] */ 3002ddae9ccSHavard Skinnemoen 0xe12fff1e, /* bx lr */ 3012ddae9ccSHavard Skinnemoen NPCM7XX_CLK_BA, 3022ddae9ccSHavard Skinnemoen NPCM7XX_PLLCON1_FIXUP_VAL, 3032ddae9ccSHavard Skinnemoen NPCM7XX_CLKSEL_FIXUP_VAL, 3042ddae9ccSHavard Skinnemoen }; 3052ddae9ccSHavard Skinnemoen int i; 3062ddae9ccSHavard Skinnemoen 3072ddae9ccSHavard Skinnemoen for (i = 0; i < ARRAY_SIZE(board_setup); i++) { 3082ddae9ccSHavard Skinnemoen board_setup[i] = tswap32(board_setup[i]); 3092ddae9ccSHavard Skinnemoen } 3102ddae9ccSHavard Skinnemoen rom_add_blob_fixed("board-setup", board_setup, sizeof(board_setup), 3112ddae9ccSHavard Skinnemoen info->board_setup_addr); 3122ddae9ccSHavard Skinnemoen } 3132ddae9ccSHavard Skinnemoen 3142d8f048cSHavard Skinnemoen static void npcm7xx_write_secondary_boot(ARMCPU *cpu, 3152d8f048cSHavard Skinnemoen const struct arm_boot_info *info) 3162d8f048cSHavard Skinnemoen { 3172d8f048cSHavard Skinnemoen /* 3182d8f048cSHavard Skinnemoen * The default smpboot stub halts the secondary CPU with a 'wfi' 3192d8f048cSHavard Skinnemoen * instruction, but the arch/arm/mach-npcm/platsmp.c in the Linux kernel 3202d8f048cSHavard Skinnemoen * does not send an IPI to wake it up, so the second CPU fails to boot. So 3212d8f048cSHavard Skinnemoen * we need to provide our own smpboot stub that can not use 'wfi', it has 3222d8f048cSHavard Skinnemoen * to spin the secondary CPU until the first CPU writes to the SCRPAD reg. 3232d8f048cSHavard Skinnemoen */ 3242d8f048cSHavard Skinnemoen uint32_t smpboot[] = { 3252d8f048cSHavard Skinnemoen 0xe59f2018, /* ldr r2, bootreg_addr */ 3262d8f048cSHavard Skinnemoen 0xe3a00000, /* mov r0, #0 */ 3272d8f048cSHavard Skinnemoen 0xe5820000, /* str r0, [r2] */ 3282d8f048cSHavard Skinnemoen 0xe320f002, /* wfe */ 3292d8f048cSHavard Skinnemoen 0xe5921000, /* ldr r1, [r2] */ 3302d8f048cSHavard Skinnemoen 0xe1110001, /* tst r1, r1 */ 3312d8f048cSHavard Skinnemoen 0x0afffffb, /* beq <wfe> */ 3322d8f048cSHavard Skinnemoen 0xe12fff11, /* bx r1 */ 3332d8f048cSHavard Skinnemoen NPCM7XX_SMP_BOOTREG_ADDR, 3342d8f048cSHavard Skinnemoen }; 3352d8f048cSHavard Skinnemoen int i; 3362d8f048cSHavard Skinnemoen 3372d8f048cSHavard Skinnemoen for (i = 0; i < ARRAY_SIZE(smpboot); i++) { 3382d8f048cSHavard Skinnemoen smpboot[i] = tswap32(smpboot[i]); 3392d8f048cSHavard Skinnemoen } 3402d8f048cSHavard Skinnemoen 3412d8f048cSHavard Skinnemoen rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot), 3422d8f048cSHavard Skinnemoen NPCM7XX_SMP_LOADER_START); 3432d8f048cSHavard Skinnemoen } 3442d8f048cSHavard Skinnemoen 3452d8f048cSHavard Skinnemoen static struct arm_boot_info npcm7xx_binfo = { 3462d8f048cSHavard Skinnemoen .loader_start = NPCM7XX_LOADER_START, 3472d8f048cSHavard Skinnemoen .smp_loader_start = NPCM7XX_SMP_LOADER_START, 3482d8f048cSHavard Skinnemoen .smp_bootreg_addr = NPCM7XX_SMP_BOOTREG_ADDR, 3492d8f048cSHavard Skinnemoen .gic_cpu_if_addr = NPCM7XX_GIC_CPU_IF_ADDR, 3502d8f048cSHavard Skinnemoen .write_secondary_boot = npcm7xx_write_secondary_boot, 3512d8f048cSHavard Skinnemoen .board_id = -1, 3522ddae9ccSHavard Skinnemoen .board_setup_addr = NPCM7XX_BOARD_SETUP_ADDR, 3532ddae9ccSHavard Skinnemoen .write_board_setup = npcm7xx_write_board_setup, 3542d8f048cSHavard Skinnemoen }; 3552d8f048cSHavard Skinnemoen 3562d8f048cSHavard Skinnemoen void npcm7xx_load_kernel(MachineState *machine, NPCM7xxState *soc) 3572d8f048cSHavard Skinnemoen { 3582d8f048cSHavard Skinnemoen NPCM7xxClass *sc = NPCM7XX_GET_CLASS(soc); 3592d8f048cSHavard Skinnemoen 3602d8f048cSHavard Skinnemoen npcm7xx_binfo.ram_size = machine->ram_size; 3612d8f048cSHavard Skinnemoen npcm7xx_binfo.nb_cpus = sc->num_cpus; 3622d8f048cSHavard Skinnemoen 3632d8f048cSHavard Skinnemoen arm_load_kernel(&soc->cpu[0], machine, &npcm7xx_binfo); 3642d8f048cSHavard Skinnemoen } 3652d8f048cSHavard Skinnemoen 366c752bb07SHavard Skinnemoen static void npcm7xx_init_fuses(NPCM7xxState *s) 367c752bb07SHavard Skinnemoen { 368c752bb07SHavard Skinnemoen NPCM7xxClass *nc = NPCM7XX_GET_CLASS(s); 369c752bb07SHavard Skinnemoen uint32_t value; 370c752bb07SHavard Skinnemoen 371c752bb07SHavard Skinnemoen /* 372c752bb07SHavard Skinnemoen * The initial mask of disabled modules indicates the chip derivative (e.g. 373c752bb07SHavard Skinnemoen * NPCM750 or NPCM730). 374c752bb07SHavard Skinnemoen */ 375c752bb07SHavard Skinnemoen value = tswap32(nc->disabled_modules); 376c752bb07SHavard Skinnemoen npcm7xx_otp_array_write(&s->fuse_array, &value, NPCM7XX_FUSE_DERIVATIVE, 377c752bb07SHavard Skinnemoen sizeof(value)); 378c752bb07SHavard Skinnemoen } 379c752bb07SHavard Skinnemoen 38077c05b0bSHao Wu static void npcm7xx_write_adc_calibration(NPCM7xxState *s) 38177c05b0bSHao Wu { 38277c05b0bSHao Wu /* Both ADC and the fuse array must have realized. */ 38377c05b0bSHao Wu QEMU_BUILD_BUG_ON(sizeof(s->adc.calibration_r_values) != 4); 38477c05b0bSHao Wu npcm7xx_otp_array_write(&s->fuse_array, s->adc.calibration_r_values, 38577c05b0bSHao Wu NPCM7XX_FUSE_ADC_CALIB, sizeof(s->adc.calibration_r_values)); 38677c05b0bSHao Wu } 38777c05b0bSHao Wu 3882d8f048cSHavard Skinnemoen static qemu_irq npcm7xx_irq(NPCM7xxState *s, int n) 3892d8f048cSHavard Skinnemoen { 3902d8f048cSHavard Skinnemoen return qdev_get_gpio_in(DEVICE(&s->a9mpcore), n); 3912d8f048cSHavard Skinnemoen } 3922d8f048cSHavard Skinnemoen 3932d8f048cSHavard Skinnemoen static void npcm7xx_init(Object *obj) 3942d8f048cSHavard Skinnemoen { 3952d8f048cSHavard Skinnemoen NPCM7xxState *s = NPCM7XX(obj); 3962d8f048cSHavard Skinnemoen int i; 3972d8f048cSHavard Skinnemoen 3982d8f048cSHavard Skinnemoen for (i = 0; i < NPCM7XX_MAX_NUM_CPUS; i++) { 3992d8f048cSHavard Skinnemoen object_initialize_child(obj, "cpu[*]", &s->cpu[i], 4002d8f048cSHavard Skinnemoen ARM_CPU_TYPE_NAME("cortex-a9")); 4012d8f048cSHavard Skinnemoen } 4022d8f048cSHavard Skinnemoen 4032d8f048cSHavard Skinnemoen object_initialize_child(obj, "a9mpcore", &s->a9mpcore, TYPE_A9MPCORE_PRIV); 4042d8f048cSHavard Skinnemoen object_initialize_child(obj, "gcr", &s->gcr, TYPE_NPCM7XX_GCR); 4052d8f048cSHavard Skinnemoen object_property_add_alias(obj, "power-on-straps", OBJECT(&s->gcr), 4062d8f048cSHavard Skinnemoen "power-on-straps"); 4072d8f048cSHavard Skinnemoen object_initialize_child(obj, "clk", &s->clk, TYPE_NPCM7XX_CLK); 408c752bb07SHavard Skinnemoen object_initialize_child(obj, "otp1", &s->key_storage, 409c752bb07SHavard Skinnemoen TYPE_NPCM7XX_KEY_STORAGE); 410c752bb07SHavard Skinnemoen object_initialize_child(obj, "otp2", &s->fuse_array, 411c752bb07SHavard Skinnemoen TYPE_NPCM7XX_FUSE_ARRAY); 4121351f892SHavard Skinnemoen object_initialize_child(obj, "mc", &s->mc, TYPE_NPCM7XX_MC); 413326ccfe2SHavard Skinnemoen object_initialize_child(obj, "rng", &s->rng, TYPE_NPCM7XX_RNG); 41477c05b0bSHao Wu object_initialize_child(obj, "adc", &s->adc, TYPE_NPCM7XX_ADC); 4152d8f048cSHavard Skinnemoen 4162d8f048cSHavard Skinnemoen for (i = 0; i < ARRAY_SIZE(s->tim); i++) { 4172d8f048cSHavard Skinnemoen object_initialize_child(obj, "tim[*]", &s->tim[i], TYPE_NPCM7XX_TIMER); 4182d8f048cSHavard Skinnemoen } 419b821242cSHavard Skinnemoen 420526dbbe0SHavard Skinnemoen for (i = 0; i < ARRAY_SIZE(s->gpio); i++) { 421526dbbe0SHavard Skinnemoen object_initialize_child(obj, "gpio[*]", &s->gpio[i], TYPE_NPCM7XX_GPIO); 422526dbbe0SHavard Skinnemoen } 423526dbbe0SHavard Skinnemoen 42494e77879SHao Wu for (i = 0; i < ARRAY_SIZE(s->smbus); i++) { 42594e77879SHao Wu object_initialize_child(obj, "smbus[*]", &s->smbus[i], 42694e77879SHao Wu TYPE_NPCM7XX_SMBUS); 42794e77879SHao Wu } 42894e77879SHao Wu 429e23e7b12SHavard Skinnemoen object_initialize_child(obj, "ehci", &s->ehci, TYPE_NPCM7XX_EHCI); 430e23e7b12SHavard Skinnemoen object_initialize_child(obj, "ohci", &s->ohci, TYPE_SYSBUS_OHCI); 431e23e7b12SHavard Skinnemoen 432b821242cSHavard Skinnemoen QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_fiu) != ARRAY_SIZE(s->fiu)); 433b821242cSHavard Skinnemoen for (i = 0; i < ARRAY_SIZE(s->fiu); i++) { 434b821242cSHavard Skinnemoen object_initialize_child(obj, npcm7xx_fiu[i].name, &s->fiu[i], 435b821242cSHavard Skinnemoen TYPE_NPCM7XX_FIU); 436b821242cSHavard Skinnemoen } 4371e943c58SHao Wu 4381e943c58SHao Wu for (i = 0; i < ARRAY_SIZE(s->pwm); i++) { 4391e943c58SHao Wu object_initialize_child(obj, "pwm[*]", &s->pwm[i], TYPE_NPCM7XX_PWM); 4401e943c58SHao Wu } 44177586436SDoug Evans 442fc11115fSHao Wu for (i = 0; i < ARRAY_SIZE(s->mft); i++) { 443fc11115fSHao Wu object_initialize_child(obj, "mft[*]", &s->mft[i], TYPE_NPCM7XX_MFT); 444fc11115fSHao Wu } 445fc11115fSHao Wu 44677586436SDoug Evans for (i = 0; i < ARRAY_SIZE(s->emc); i++) { 44777586436SDoug Evans object_initialize_child(obj, "emc[*]", &s->emc[i], TYPE_NPCM7XX_EMC); 44877586436SDoug Evans } 449*0a9df6cbSShengtan Mao 450*0a9df6cbSShengtan Mao object_initialize_child(obj, "mmc", &s->mmc, TYPE_NPCM7XX_SDHCI); 4512d8f048cSHavard Skinnemoen } 4522d8f048cSHavard Skinnemoen 4532d8f048cSHavard Skinnemoen static void npcm7xx_realize(DeviceState *dev, Error **errp) 4542d8f048cSHavard Skinnemoen { 4552d8f048cSHavard Skinnemoen NPCM7xxState *s = NPCM7XX(dev); 4562d8f048cSHavard Skinnemoen NPCM7xxClass *nc = NPCM7XX_GET_CLASS(s); 4572d8f048cSHavard Skinnemoen int i; 4582d8f048cSHavard Skinnemoen 4592d8f048cSHavard Skinnemoen if (memory_region_size(s->dram) > NPCM7XX_DRAM_SZ) { 4602d8f048cSHavard Skinnemoen error_setg(errp, "%s: NPCM7xx cannot address more than %" PRIu64 4612d8f048cSHavard Skinnemoen " MiB of DRAM", __func__, NPCM7XX_DRAM_SZ / MiB); 4622d8f048cSHavard Skinnemoen return; 4632d8f048cSHavard Skinnemoen } 4642d8f048cSHavard Skinnemoen 4652d8f048cSHavard Skinnemoen /* CPUs */ 4662d8f048cSHavard Skinnemoen for (i = 0; i < nc->num_cpus; i++) { 4672d8f048cSHavard Skinnemoen object_property_set_int(OBJECT(&s->cpu[i]), "mp-affinity", 4682d8f048cSHavard Skinnemoen arm_cpu_mp_affinity(i, NPCM7XX_MAX_NUM_CPUS), 4692d8f048cSHavard Skinnemoen &error_abort); 4702d8f048cSHavard Skinnemoen object_property_set_int(OBJECT(&s->cpu[i]), "reset-cbar", 4712d8f048cSHavard Skinnemoen NPCM7XX_GIC_CPU_IF_ADDR, &error_abort); 4722d8f048cSHavard Skinnemoen object_property_set_bool(OBJECT(&s->cpu[i]), "reset-hivecs", true, 4732d8f048cSHavard Skinnemoen &error_abort); 4742d8f048cSHavard Skinnemoen 4752d8f048cSHavard Skinnemoen /* Disable security extensions. */ 4762d8f048cSHavard Skinnemoen object_property_set_bool(OBJECT(&s->cpu[i]), "has_el3", false, 4772d8f048cSHavard Skinnemoen &error_abort); 4782d8f048cSHavard Skinnemoen 4792d8f048cSHavard Skinnemoen if (!qdev_realize(DEVICE(&s->cpu[i]), NULL, errp)) { 4802d8f048cSHavard Skinnemoen return; 4812d8f048cSHavard Skinnemoen } 4822d8f048cSHavard Skinnemoen } 4832d8f048cSHavard Skinnemoen 4842d8f048cSHavard Skinnemoen /* A9MPCORE peripherals. Can only fail if we pass bad parameters here. */ 4852d8f048cSHavard Skinnemoen object_property_set_int(OBJECT(&s->a9mpcore), "num-cpu", nc->num_cpus, 4862d8f048cSHavard Skinnemoen &error_abort); 4872d8f048cSHavard Skinnemoen object_property_set_int(OBJECT(&s->a9mpcore), "num-irq", NPCM7XX_NUM_IRQ, 4882d8f048cSHavard Skinnemoen &error_abort); 4892d8f048cSHavard Skinnemoen sysbus_realize(SYS_BUS_DEVICE(&s->a9mpcore), &error_abort); 4902d8f048cSHavard Skinnemoen sysbus_mmio_map(SYS_BUS_DEVICE(&s->a9mpcore), 0, NPCM7XX_CPUP_BA); 4912d8f048cSHavard Skinnemoen 4922d8f048cSHavard Skinnemoen for (i = 0; i < nc->num_cpus; i++) { 4932d8f048cSHavard Skinnemoen sysbus_connect_irq(SYS_BUS_DEVICE(&s->a9mpcore), i, 4942d8f048cSHavard Skinnemoen qdev_get_gpio_in(DEVICE(&s->cpu[i]), ARM_CPU_IRQ)); 4952d8f048cSHavard Skinnemoen sysbus_connect_irq(SYS_BUS_DEVICE(&s->a9mpcore), i + nc->num_cpus, 4962d8f048cSHavard Skinnemoen qdev_get_gpio_in(DEVICE(&s->cpu[i]), ARM_CPU_FIQ)); 4972d8f048cSHavard Skinnemoen } 4982d8f048cSHavard Skinnemoen 4992d8f048cSHavard Skinnemoen /* L2 cache controller */ 5002d8f048cSHavard Skinnemoen sysbus_create_simple("l2x0", NPCM7XX_L2C_BA, NULL); 5012d8f048cSHavard Skinnemoen 5022d8f048cSHavard Skinnemoen /* System Global Control Registers (GCR). Can fail due to user input. */ 5032d8f048cSHavard Skinnemoen object_property_set_int(OBJECT(&s->gcr), "disabled-modules", 5042d8f048cSHavard Skinnemoen nc->disabled_modules, &error_abort); 5052d8f048cSHavard Skinnemoen object_property_add_const_link(OBJECT(&s->gcr), "dram-mr", OBJECT(s->dram)); 5062d8f048cSHavard Skinnemoen if (!sysbus_realize(SYS_BUS_DEVICE(&s->gcr), errp)) { 5072d8f048cSHavard Skinnemoen return; 5082d8f048cSHavard Skinnemoen } 5092d8f048cSHavard Skinnemoen sysbus_mmio_map(SYS_BUS_DEVICE(&s->gcr), 0, NPCM7XX_GCR_BA); 5102d8f048cSHavard Skinnemoen 5112d8f048cSHavard Skinnemoen /* Clock Control Registers (CLK). Cannot fail. */ 5122d8f048cSHavard Skinnemoen sysbus_realize(SYS_BUS_DEVICE(&s->clk), &error_abort); 5132d8f048cSHavard Skinnemoen sysbus_mmio_map(SYS_BUS_DEVICE(&s->clk), 0, NPCM7XX_CLK_BA); 5142d8f048cSHavard Skinnemoen 515c752bb07SHavard Skinnemoen /* OTP key storage and fuse strap array. Cannot fail. */ 516c752bb07SHavard Skinnemoen sysbus_realize(SYS_BUS_DEVICE(&s->key_storage), &error_abort); 517c752bb07SHavard Skinnemoen sysbus_mmio_map(SYS_BUS_DEVICE(&s->key_storage), 0, NPCM7XX_OTP1_BA); 518c752bb07SHavard Skinnemoen sysbus_realize(SYS_BUS_DEVICE(&s->fuse_array), &error_abort); 519c752bb07SHavard Skinnemoen sysbus_mmio_map(SYS_BUS_DEVICE(&s->fuse_array), 0, NPCM7XX_OTP2_BA); 520c752bb07SHavard Skinnemoen npcm7xx_init_fuses(s); 521c752bb07SHavard Skinnemoen 5221351f892SHavard Skinnemoen /* Fake Memory Controller (MC). Cannot fail. */ 5231351f892SHavard Skinnemoen sysbus_realize(SYS_BUS_DEVICE(&s->mc), &error_abort); 5241351f892SHavard Skinnemoen sysbus_mmio_map(SYS_BUS_DEVICE(&s->mc), 0, NPCM7XX_MC_BA); 5251351f892SHavard Skinnemoen 52677c05b0bSHao Wu /* ADC Modules. Cannot fail. */ 52777c05b0bSHao Wu qdev_connect_clock_in(DEVICE(&s->adc), "clock", qdev_get_clock_out( 52877c05b0bSHao Wu DEVICE(&s->clk), "adc-clock")); 52977c05b0bSHao Wu sysbus_realize(SYS_BUS_DEVICE(&s->adc), &error_abort); 53077c05b0bSHao Wu sysbus_mmio_map(SYS_BUS_DEVICE(&s->adc), 0, NPCM7XX_ADC_BA); 53177c05b0bSHao Wu sysbus_connect_irq(SYS_BUS_DEVICE(&s->adc), 0, 53277c05b0bSHao Wu npcm7xx_irq(s, NPCM7XX_ADC_IRQ)); 53377c05b0bSHao Wu npcm7xx_write_adc_calibration(s); 53477c05b0bSHao Wu 5352d8f048cSHavard Skinnemoen /* Timer Modules (TIM). Cannot fail. */ 5362d8f048cSHavard Skinnemoen QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_tim_addr) != ARRAY_SIZE(s->tim)); 5372d8f048cSHavard Skinnemoen for (i = 0; i < ARRAY_SIZE(s->tim); i++) { 5382d8f048cSHavard Skinnemoen SysBusDevice *sbd = SYS_BUS_DEVICE(&s->tim[i]); 5392d8f048cSHavard Skinnemoen int first_irq; 5402d8f048cSHavard Skinnemoen int j; 5412d8f048cSHavard Skinnemoen 5420be12dc7SHao Wu /* Connect the timer clock. */ 5430be12dc7SHao Wu qdev_connect_clock_in(DEVICE(&s->tim[i]), "clock", qdev_get_clock_out( 5440be12dc7SHao Wu DEVICE(&s->clk), "timer-clock")); 5450be12dc7SHao Wu 5462d8f048cSHavard Skinnemoen sysbus_realize(sbd, &error_abort); 5472d8f048cSHavard Skinnemoen sysbus_mmio_map(sbd, 0, npcm7xx_tim_addr[i]); 5482d8f048cSHavard Skinnemoen 5492d8f048cSHavard Skinnemoen first_irq = NPCM7XX_TIMER0_IRQ + i * NPCM7XX_TIMERS_PER_CTRL; 5502d8f048cSHavard Skinnemoen for (j = 0; j < NPCM7XX_TIMERS_PER_CTRL; j++) { 5512d8f048cSHavard Skinnemoen qemu_irq irq = npcm7xx_irq(s, first_irq + j); 5522d8f048cSHavard Skinnemoen sysbus_connect_irq(sbd, j, irq); 5532d8f048cSHavard Skinnemoen } 5547d378ed6SHao Wu 5557d378ed6SHao Wu /* IRQ for watchdogs */ 5567d378ed6SHao Wu sysbus_connect_irq(sbd, NPCM7XX_TIMERS_PER_CTRL, 5577d378ed6SHao Wu npcm7xx_irq(s, NPCM7XX_WDG0_IRQ + i)); 5587d378ed6SHao Wu /* GPIO that connects clk module with watchdog */ 5597d378ed6SHao Wu qdev_connect_gpio_out_named(DEVICE(&s->tim[i]), 5607d378ed6SHao Wu NPCM7XX_WATCHDOG_RESET_GPIO_OUT, 0, 5617d378ed6SHao Wu qdev_get_gpio_in_named(DEVICE(&s->clk), 5627d378ed6SHao Wu NPCM7XX_WATCHDOG_RESET_GPIO_IN, i)); 5632d8f048cSHavard Skinnemoen } 5642d8f048cSHavard Skinnemoen 5652d8f048cSHavard Skinnemoen /* UART0..3 (16550 compatible) */ 5662d8f048cSHavard Skinnemoen for (i = 0; i < ARRAY_SIZE(npcm7xx_uart_addr); i++) { 5672d8f048cSHavard Skinnemoen serial_mm_init(get_system_memory(), npcm7xx_uart_addr[i], 2, 5682d8f048cSHavard Skinnemoen npcm7xx_irq(s, NPCM7XX_UART0_IRQ + i), 115200, 5692d8f048cSHavard Skinnemoen serial_hd(i), DEVICE_LITTLE_ENDIAN); 5702d8f048cSHavard Skinnemoen } 5712d8f048cSHavard Skinnemoen 572326ccfe2SHavard Skinnemoen /* Random Number Generator. Cannot fail. */ 573326ccfe2SHavard Skinnemoen sysbus_realize(SYS_BUS_DEVICE(&s->rng), &error_abort); 574326ccfe2SHavard Skinnemoen sysbus_mmio_map(SYS_BUS_DEVICE(&s->rng), 0, NPCM7XX_RNG_BA); 575326ccfe2SHavard Skinnemoen 576526dbbe0SHavard Skinnemoen /* GPIO modules. Cannot fail. */ 577526dbbe0SHavard Skinnemoen QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_gpio) != ARRAY_SIZE(s->gpio)); 578526dbbe0SHavard Skinnemoen for (i = 0; i < ARRAY_SIZE(s->gpio); i++) { 579526dbbe0SHavard Skinnemoen Object *obj = OBJECT(&s->gpio[i]); 580526dbbe0SHavard Skinnemoen 581526dbbe0SHavard Skinnemoen object_property_set_uint(obj, "reset-pullup", 582526dbbe0SHavard Skinnemoen npcm7xx_gpio[i].reset_pu, &error_abort); 583526dbbe0SHavard Skinnemoen object_property_set_uint(obj, "reset-pulldown", 584526dbbe0SHavard Skinnemoen npcm7xx_gpio[i].reset_pd, &error_abort); 585526dbbe0SHavard Skinnemoen object_property_set_uint(obj, "reset-osrc", 586526dbbe0SHavard Skinnemoen npcm7xx_gpio[i].reset_osrc, &error_abort); 587526dbbe0SHavard Skinnemoen object_property_set_uint(obj, "reset-odsc", 588526dbbe0SHavard Skinnemoen npcm7xx_gpio[i].reset_odsc, &error_abort); 589526dbbe0SHavard Skinnemoen sysbus_realize(SYS_BUS_DEVICE(obj), &error_abort); 590526dbbe0SHavard Skinnemoen sysbus_mmio_map(SYS_BUS_DEVICE(obj), 0, npcm7xx_gpio[i].regs_addr); 591526dbbe0SHavard Skinnemoen sysbus_connect_irq(SYS_BUS_DEVICE(obj), 0, 592526dbbe0SHavard Skinnemoen npcm7xx_irq(s, NPCM7XX_GPIO0_IRQ + i)); 593526dbbe0SHavard Skinnemoen } 594526dbbe0SHavard Skinnemoen 59594e77879SHao Wu /* SMBus modules. Cannot fail. */ 59694e77879SHao Wu QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_smbus_addr) != ARRAY_SIZE(s->smbus)); 59794e77879SHao Wu for (i = 0; i < ARRAY_SIZE(s->smbus); i++) { 59894e77879SHao Wu Object *obj = OBJECT(&s->smbus[i]); 59994e77879SHao Wu 60094e77879SHao Wu sysbus_realize(SYS_BUS_DEVICE(obj), &error_abort); 60194e77879SHao Wu sysbus_mmio_map(SYS_BUS_DEVICE(obj), 0, npcm7xx_smbus_addr[i]); 60294e77879SHao Wu sysbus_connect_irq(SYS_BUS_DEVICE(obj), 0, 60394e77879SHao Wu npcm7xx_irq(s, NPCM7XX_SMBUS0_IRQ + i)); 60494e77879SHao Wu } 60594e77879SHao Wu 606e23e7b12SHavard Skinnemoen /* USB Host */ 607e23e7b12SHavard Skinnemoen object_property_set_bool(OBJECT(&s->ehci), "companion-enable", true, 608e23e7b12SHavard Skinnemoen &error_abort); 609e23e7b12SHavard Skinnemoen sysbus_realize(SYS_BUS_DEVICE(&s->ehci), &error_abort); 610e23e7b12SHavard Skinnemoen sysbus_mmio_map(SYS_BUS_DEVICE(&s->ehci), 0, NPCM7XX_EHCI_BA); 611e23e7b12SHavard Skinnemoen sysbus_connect_irq(SYS_BUS_DEVICE(&s->ehci), 0, 612e23e7b12SHavard Skinnemoen npcm7xx_irq(s, NPCM7XX_EHCI_IRQ)); 613e23e7b12SHavard Skinnemoen 614e23e7b12SHavard Skinnemoen object_property_set_str(OBJECT(&s->ohci), "masterbus", "usb-bus.0", 615e23e7b12SHavard Skinnemoen &error_abort); 616e23e7b12SHavard Skinnemoen object_property_set_uint(OBJECT(&s->ohci), "num-ports", 1, &error_abort); 617e23e7b12SHavard Skinnemoen sysbus_realize(SYS_BUS_DEVICE(&s->ohci), &error_abort); 618e23e7b12SHavard Skinnemoen sysbus_mmio_map(SYS_BUS_DEVICE(&s->ohci), 0, NPCM7XX_OHCI_BA); 619e23e7b12SHavard Skinnemoen sysbus_connect_irq(SYS_BUS_DEVICE(&s->ohci), 0, 620e23e7b12SHavard Skinnemoen npcm7xx_irq(s, NPCM7XX_OHCI_IRQ)); 621e23e7b12SHavard Skinnemoen 6221e943c58SHao Wu /* PWM Modules. Cannot fail. */ 6231e943c58SHao Wu QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_pwm_addr) != ARRAY_SIZE(s->pwm)); 6241e943c58SHao Wu for (i = 0; i < ARRAY_SIZE(s->pwm); i++) { 6251e943c58SHao Wu SysBusDevice *sbd = SYS_BUS_DEVICE(&s->pwm[i]); 6261e943c58SHao Wu 6271e943c58SHao Wu qdev_connect_clock_in(DEVICE(&s->pwm[i]), "clock", qdev_get_clock_out( 6281e943c58SHao Wu DEVICE(&s->clk), "apb3-clock")); 6291e943c58SHao Wu sysbus_realize(sbd, &error_abort); 6301e943c58SHao Wu sysbus_mmio_map(sbd, 0, npcm7xx_pwm_addr[i]); 6311e943c58SHao Wu sysbus_connect_irq(sbd, i, npcm7xx_irq(s, NPCM7XX_PWM0_IRQ + i)); 6321e943c58SHao Wu } 6331e943c58SHao Wu 634fc11115fSHao Wu /* MFT Modules. Cannot fail. */ 635fc11115fSHao Wu QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_mft_addr) != ARRAY_SIZE(s->mft)); 636fc11115fSHao Wu for (i = 0; i < ARRAY_SIZE(s->mft); i++) { 637fc11115fSHao Wu SysBusDevice *sbd = SYS_BUS_DEVICE(&s->mft[i]); 638fc11115fSHao Wu 639fc11115fSHao Wu qdev_connect_clock_in(DEVICE(&s->mft[i]), "clock-in", 640fc11115fSHao Wu qdev_get_clock_out(DEVICE(&s->clk), 641fc11115fSHao Wu "apb4-clock")); 642fc11115fSHao Wu sysbus_realize(sbd, &error_abort); 643fc11115fSHao Wu sysbus_mmio_map(sbd, 0, npcm7xx_mft_addr[i]); 644fc11115fSHao Wu sysbus_connect_irq(sbd, 0, npcm7xx_irq(s, NPCM7XX_MFT0_IRQ + i)); 645fc11115fSHao Wu } 646fc11115fSHao Wu 647b821242cSHavard Skinnemoen /* 64877586436SDoug Evans * EMC Modules. Cannot fail. 64977586436SDoug Evans * The mapping of the device to its netdev backend works as follows: 65077586436SDoug Evans * emc[i] = nd_table[i] 65177586436SDoug Evans * This works around the inability to specify the netdev property for the 65277586436SDoug Evans * emc device: it's not pluggable and thus the -device option can't be 65377586436SDoug Evans * used. 65477586436SDoug Evans */ 65577586436SDoug Evans QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_emc_addr) != ARRAY_SIZE(s->emc)); 65677586436SDoug Evans QEMU_BUILD_BUG_ON(ARRAY_SIZE(s->emc) != 2); 65777586436SDoug Evans for (i = 0; i < ARRAY_SIZE(s->emc); i++) { 65877586436SDoug Evans s->emc[i].emc_num = i; 65977586436SDoug Evans SysBusDevice *sbd = SYS_BUS_DEVICE(&s->emc[i]); 66077586436SDoug Evans if (nd_table[i].used) { 66177586436SDoug Evans qemu_check_nic_model(&nd_table[i], TYPE_NPCM7XX_EMC); 66277586436SDoug Evans qdev_set_nic_properties(DEVICE(sbd), &nd_table[i]); 66377586436SDoug Evans } 66477586436SDoug Evans /* 66577586436SDoug Evans * The device exists regardless of whether it's connected to a QEMU 66677586436SDoug Evans * netdev backend. So always instantiate it even if there is no 66777586436SDoug Evans * backend. 66877586436SDoug Evans */ 66977586436SDoug Evans sysbus_realize(sbd, &error_abort); 67077586436SDoug Evans sysbus_mmio_map(sbd, 0, npcm7xx_emc_addr[i]); 67177586436SDoug Evans int tx_irq = i == 0 ? NPCM7XX_EMC1TX_IRQ : NPCM7XX_EMC2TX_IRQ; 67277586436SDoug Evans int rx_irq = i == 0 ? NPCM7XX_EMC1RX_IRQ : NPCM7XX_EMC2RX_IRQ; 67377586436SDoug Evans /* 67477586436SDoug Evans * N.B. The values for the second argument sysbus_connect_irq are 67577586436SDoug Evans * chosen to match the registration order in npcm7xx_emc_realize. 67677586436SDoug Evans */ 67777586436SDoug Evans sysbus_connect_irq(sbd, 0, npcm7xx_irq(s, tx_irq)); 67877586436SDoug Evans sysbus_connect_irq(sbd, 1, npcm7xx_irq(s, rx_irq)); 67977586436SDoug Evans } 68077586436SDoug Evans 68177586436SDoug Evans /* 682b821242cSHavard Skinnemoen * Flash Interface Unit (FIU). Can fail if incorrect number of chip selects 683b821242cSHavard Skinnemoen * specified, but this is a programming error. 684b821242cSHavard Skinnemoen */ 685b821242cSHavard Skinnemoen QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_fiu) != ARRAY_SIZE(s->fiu)); 686b821242cSHavard Skinnemoen for (i = 0; i < ARRAY_SIZE(s->fiu); i++) { 687b821242cSHavard Skinnemoen SysBusDevice *sbd = SYS_BUS_DEVICE(&s->fiu[i]); 688b821242cSHavard Skinnemoen int j; 689b821242cSHavard Skinnemoen 690b821242cSHavard Skinnemoen object_property_set_int(OBJECT(sbd), "cs-count", 691b821242cSHavard Skinnemoen npcm7xx_fiu[i].cs_count, &error_abort); 692b821242cSHavard Skinnemoen sysbus_realize(sbd, &error_abort); 693b821242cSHavard Skinnemoen 694b821242cSHavard Skinnemoen sysbus_mmio_map(sbd, 0, npcm7xx_fiu[i].regs_addr); 695b821242cSHavard Skinnemoen for (j = 0; j < npcm7xx_fiu[i].cs_count; j++) { 696b821242cSHavard Skinnemoen sysbus_mmio_map(sbd, j + 1, npcm7xx_fiu[i].flash_addr[j]); 697b821242cSHavard Skinnemoen } 698b821242cSHavard Skinnemoen } 699b821242cSHavard Skinnemoen 7002d8f048cSHavard Skinnemoen /* RAM2 (SRAM) */ 7012d8f048cSHavard Skinnemoen memory_region_init_ram(&s->sram, OBJECT(dev), "ram2", 7022d8f048cSHavard Skinnemoen NPCM7XX_RAM2_SZ, &error_abort); 7032d8f048cSHavard Skinnemoen memory_region_add_subregion(get_system_memory(), NPCM7XX_RAM2_BA, &s->sram); 7042d8f048cSHavard Skinnemoen 7052d8f048cSHavard Skinnemoen /* RAM3 (SRAM) */ 7062d8f048cSHavard Skinnemoen memory_region_init_ram(&s->ram3, OBJECT(dev), "ram3", 7072d8f048cSHavard Skinnemoen NPCM7XX_RAM3_SZ, &error_abort); 7082d8f048cSHavard Skinnemoen memory_region_add_subregion(get_system_memory(), NPCM7XX_RAM3_BA, &s->ram3); 7092d8f048cSHavard Skinnemoen 7102d8f048cSHavard Skinnemoen /* Internal ROM */ 7112d8f048cSHavard Skinnemoen memory_region_init_rom(&s->irom, OBJECT(dev), "irom", NPCM7XX_ROM_SZ, 7122d8f048cSHavard Skinnemoen &error_abort); 7132d8f048cSHavard Skinnemoen memory_region_add_subregion(get_system_memory(), NPCM7XX_ROM_BA, &s->irom); 7142d8f048cSHavard Skinnemoen 715*0a9df6cbSShengtan Mao /* SDHCI */ 716*0a9df6cbSShengtan Mao sysbus_realize(SYS_BUS_DEVICE(&s->mmc), &error_abort); 717*0a9df6cbSShengtan Mao sysbus_mmio_map(SYS_BUS_DEVICE(&s->mmc), 0, NPCM7XX_MMC_BA); 718*0a9df6cbSShengtan Mao sysbus_connect_irq(SYS_BUS_DEVICE(&s->mmc), 0, 719*0a9df6cbSShengtan Mao npcm7xx_irq(s, NPCM7XX_MMC_IRQ)); 720*0a9df6cbSShengtan Mao 7212d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.shm", 0xc0001000, 4 * KiB); 7222d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.vdmx", 0xe0800000, 4 * KiB); 7232d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.pcierc", 0xe1000000, 64 * KiB); 7242d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.kcs", 0xf0007000, 4 * KiB); 7252d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.gfxi", 0xf000e000, 4 * KiB); 7262d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.espi", 0xf009f000, 4 * KiB); 7272d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.peci", 0xf0100000, 4 * KiB); 7282d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.siox[1]", 0xf0101000, 4 * KiB); 7292d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.siox[2]", 0xf0102000, 4 * KiB); 7302d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.pspi1", 0xf0200000, 4 * KiB); 7312d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.pspi2", 0xf0201000, 4 * KiB); 7322d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.ahbpci", 0xf0400000, 1 * MiB); 7332d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.mcphy", 0xf05f0000, 64 * KiB); 7342d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.gmac1", 0xf0802000, 8 * KiB); 7352d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.gmac2", 0xf0804000, 8 * KiB); 7362d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.vcd", 0xf0810000, 64 * KiB); 7372d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.ece", 0xf0820000, 8 * KiB); 7382d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.vdma", 0xf0822000, 8 * KiB); 7392d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.usbd[0]", 0xf0830000, 4 * KiB); 7402d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.usbd[1]", 0xf0831000, 4 * KiB); 7412d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.usbd[2]", 0xf0832000, 4 * KiB); 7422d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.usbd[3]", 0xf0833000, 4 * KiB); 7432d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.usbd[4]", 0xf0834000, 4 * KiB); 7442d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.usbd[5]", 0xf0835000, 4 * KiB); 7452d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.usbd[6]", 0xf0836000, 4 * KiB); 7462d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.usbd[7]", 0xf0837000, 4 * KiB); 7472d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.usbd[8]", 0xf0838000, 4 * KiB); 7482d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.usbd[9]", 0xf0839000, 4 * KiB); 7492d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.sd", 0xf0840000, 8 * KiB); 7502d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.pcimbx", 0xf0848000, 512 * KiB); 7512d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.aes", 0xf0858000, 4 * KiB); 7522d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.des", 0xf0859000, 4 * KiB); 7532d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.sha", 0xf085a000, 4 * KiB); 7542d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.secacc", 0xf085b000, 4 * KiB); 7552d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.spixcs0", 0xf8000000, 16 * MiB); 7562d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.spixcs1", 0xf9000000, 16 * MiB); 7572d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.spix", 0xfb001000, 4 * KiB); 7582d8f048cSHavard Skinnemoen } 7592d8f048cSHavard Skinnemoen 7602d8f048cSHavard Skinnemoen static Property npcm7xx_properties[] = { 7612d8f048cSHavard Skinnemoen DEFINE_PROP_LINK("dram-mr", NPCM7xxState, dram, TYPE_MEMORY_REGION, 7622d8f048cSHavard Skinnemoen MemoryRegion *), 7632d8f048cSHavard Skinnemoen DEFINE_PROP_END_OF_LIST(), 7642d8f048cSHavard Skinnemoen }; 7652d8f048cSHavard Skinnemoen 7662d8f048cSHavard Skinnemoen static void npcm7xx_class_init(ObjectClass *oc, void *data) 7672d8f048cSHavard Skinnemoen { 7682d8f048cSHavard Skinnemoen DeviceClass *dc = DEVICE_CLASS(oc); 7692d8f048cSHavard Skinnemoen 7702d8f048cSHavard Skinnemoen dc->realize = npcm7xx_realize; 7712d8f048cSHavard Skinnemoen dc->user_creatable = false; 7722d8f048cSHavard Skinnemoen device_class_set_props(dc, npcm7xx_properties); 7732d8f048cSHavard Skinnemoen } 7742d8f048cSHavard Skinnemoen 7752d8f048cSHavard Skinnemoen static void npcm730_class_init(ObjectClass *oc, void *data) 7762d8f048cSHavard Skinnemoen { 7772d8f048cSHavard Skinnemoen NPCM7xxClass *nc = NPCM7XX_CLASS(oc); 7782d8f048cSHavard Skinnemoen 7792d8f048cSHavard Skinnemoen /* NPCM730 is optimized for data center use, so no graphics, etc. */ 7802d8f048cSHavard Skinnemoen nc->disabled_modules = 0x00300395; 7812d8f048cSHavard Skinnemoen nc->num_cpus = 2; 7822d8f048cSHavard Skinnemoen } 7832d8f048cSHavard Skinnemoen 7842d8f048cSHavard Skinnemoen static void npcm750_class_init(ObjectClass *oc, void *data) 7852d8f048cSHavard Skinnemoen { 7862d8f048cSHavard Skinnemoen NPCM7xxClass *nc = NPCM7XX_CLASS(oc); 7872d8f048cSHavard Skinnemoen 7882d8f048cSHavard Skinnemoen /* NPCM750 has 2 cores and a full set of peripherals */ 7892d8f048cSHavard Skinnemoen nc->disabled_modules = 0x00000000; 7902d8f048cSHavard Skinnemoen nc->num_cpus = 2; 7912d8f048cSHavard Skinnemoen } 7922d8f048cSHavard Skinnemoen 7932d8f048cSHavard Skinnemoen static const TypeInfo npcm7xx_soc_types[] = { 7942d8f048cSHavard Skinnemoen { 7952d8f048cSHavard Skinnemoen .name = TYPE_NPCM7XX, 7962d8f048cSHavard Skinnemoen .parent = TYPE_DEVICE, 7972d8f048cSHavard Skinnemoen .instance_size = sizeof(NPCM7xxState), 7982d8f048cSHavard Skinnemoen .instance_init = npcm7xx_init, 7992d8f048cSHavard Skinnemoen .class_size = sizeof(NPCM7xxClass), 8002d8f048cSHavard Skinnemoen .class_init = npcm7xx_class_init, 8012d8f048cSHavard Skinnemoen .abstract = true, 8022d8f048cSHavard Skinnemoen }, { 8032d8f048cSHavard Skinnemoen .name = TYPE_NPCM730, 8042d8f048cSHavard Skinnemoen .parent = TYPE_NPCM7XX, 8052d8f048cSHavard Skinnemoen .class_init = npcm730_class_init, 8062d8f048cSHavard Skinnemoen }, { 8072d8f048cSHavard Skinnemoen .name = TYPE_NPCM750, 8082d8f048cSHavard Skinnemoen .parent = TYPE_NPCM7XX, 8092d8f048cSHavard Skinnemoen .class_init = npcm750_class_init, 8102d8f048cSHavard Skinnemoen }, 8112d8f048cSHavard Skinnemoen }; 8122d8f048cSHavard Skinnemoen 8132d8f048cSHavard Skinnemoen DEFINE_TYPES(npcm7xx_soc_types); 814