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 "exec/address-spaces.h" 202d8f048cSHavard Skinnemoen #include "hw/arm/boot.h" 212d8f048cSHavard Skinnemoen #include "hw/arm/npcm7xx.h" 222d8f048cSHavard Skinnemoen #include "hw/char/serial.h" 232d8f048cSHavard Skinnemoen #include "hw/loader.h" 242d8f048cSHavard Skinnemoen #include "hw/misc/unimp.h" 250be12dc7SHao Wu #include "hw/qdev-clock.h" 262d8f048cSHavard Skinnemoen #include "hw/qdev-properties.h" 272d8f048cSHavard Skinnemoen #include "qapi/error.h" 282d8f048cSHavard Skinnemoen #include "qemu/units.h" 292d8f048cSHavard Skinnemoen #include "sysemu/sysemu.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 6777c05b0bSHao Wu 682ddae9ccSHavard Skinnemoen /* Clock configuration values to be fixed up when bypassing bootloader */ 692ddae9ccSHavard Skinnemoen 702ddae9ccSHavard Skinnemoen /* Run PLL1 at 1600 MHz */ 712ddae9ccSHavard Skinnemoen #define NPCM7XX_PLLCON1_FIXUP_VAL (0x00402101) 722ddae9ccSHavard Skinnemoen /* Run the CPU from PLL1 and UART from PLL2 */ 732ddae9ccSHavard Skinnemoen #define NPCM7XX_CLKSEL_FIXUP_VAL (0x004aaba9) 742ddae9ccSHavard Skinnemoen 752d8f048cSHavard Skinnemoen /* 762d8f048cSHavard Skinnemoen * Interrupt lines going into the GIC. This does not include internal Cortex-A9 772d8f048cSHavard Skinnemoen * interrupts. 782d8f048cSHavard Skinnemoen */ 792d8f048cSHavard Skinnemoen enum NPCM7xxInterrupt { 8077c05b0bSHao Wu NPCM7XX_ADC_IRQ = 0, 812d8f048cSHavard Skinnemoen NPCM7XX_UART0_IRQ = 2, 822d8f048cSHavard Skinnemoen NPCM7XX_UART1_IRQ, 832d8f048cSHavard Skinnemoen NPCM7XX_UART2_IRQ, 842d8f048cSHavard Skinnemoen NPCM7XX_UART3_IRQ, 85*77586436SDoug Evans NPCM7XX_EMC1RX_IRQ = 15, 86*77586436SDoug Evans NPCM7XX_EMC1TX_IRQ, 872d8f048cSHavard Skinnemoen NPCM7XX_TIMER0_IRQ = 32, /* Timer Module 0 */ 882d8f048cSHavard Skinnemoen NPCM7XX_TIMER1_IRQ, 892d8f048cSHavard Skinnemoen NPCM7XX_TIMER2_IRQ, 902d8f048cSHavard Skinnemoen NPCM7XX_TIMER3_IRQ, 912d8f048cSHavard Skinnemoen NPCM7XX_TIMER4_IRQ, 922d8f048cSHavard Skinnemoen NPCM7XX_TIMER5_IRQ, /* Timer Module 1 */ 932d8f048cSHavard Skinnemoen NPCM7XX_TIMER6_IRQ, 942d8f048cSHavard Skinnemoen NPCM7XX_TIMER7_IRQ, 952d8f048cSHavard Skinnemoen NPCM7XX_TIMER8_IRQ, 962d8f048cSHavard Skinnemoen NPCM7XX_TIMER9_IRQ, 972d8f048cSHavard Skinnemoen NPCM7XX_TIMER10_IRQ, /* Timer Module 2 */ 982d8f048cSHavard Skinnemoen NPCM7XX_TIMER11_IRQ, 992d8f048cSHavard Skinnemoen NPCM7XX_TIMER12_IRQ, 1002d8f048cSHavard Skinnemoen NPCM7XX_TIMER13_IRQ, 1012d8f048cSHavard Skinnemoen NPCM7XX_TIMER14_IRQ, 1027d378ed6SHao Wu NPCM7XX_WDG0_IRQ = 47, /* Timer Module 0 Watchdog */ 1037d378ed6SHao Wu NPCM7XX_WDG1_IRQ, /* Timer Module 1 Watchdog */ 1047d378ed6SHao Wu NPCM7XX_WDG2_IRQ, /* Timer Module 2 Watchdog */ 105e23e7b12SHavard Skinnemoen NPCM7XX_EHCI_IRQ = 61, 106e23e7b12SHavard Skinnemoen NPCM7XX_OHCI_IRQ = 62, 10794e77879SHao Wu NPCM7XX_SMBUS0_IRQ = 64, 10894e77879SHao Wu NPCM7XX_SMBUS1_IRQ, 10994e77879SHao Wu NPCM7XX_SMBUS2_IRQ, 11094e77879SHao Wu NPCM7XX_SMBUS3_IRQ, 11194e77879SHao Wu NPCM7XX_SMBUS4_IRQ, 11294e77879SHao Wu NPCM7XX_SMBUS5_IRQ, 11394e77879SHao Wu NPCM7XX_SMBUS6_IRQ, 11494e77879SHao Wu NPCM7XX_SMBUS7_IRQ, 11594e77879SHao Wu NPCM7XX_SMBUS8_IRQ, 11694e77879SHao Wu NPCM7XX_SMBUS9_IRQ, 11794e77879SHao Wu NPCM7XX_SMBUS10_IRQ, 11894e77879SHao Wu NPCM7XX_SMBUS11_IRQ, 11994e77879SHao Wu NPCM7XX_SMBUS12_IRQ, 12094e77879SHao Wu NPCM7XX_SMBUS13_IRQ, 12194e77879SHao Wu NPCM7XX_SMBUS14_IRQ, 12294e77879SHao Wu NPCM7XX_SMBUS15_IRQ, 1231e943c58SHao Wu NPCM7XX_PWM0_IRQ = 93, /* PWM module 0 */ 1241e943c58SHao Wu NPCM7XX_PWM1_IRQ, /* PWM module 1 */ 125*77586436SDoug Evans NPCM7XX_EMC2RX_IRQ = 114, 126*77586436SDoug Evans NPCM7XX_EMC2TX_IRQ, 127526dbbe0SHavard Skinnemoen NPCM7XX_GPIO0_IRQ = 116, 128526dbbe0SHavard Skinnemoen NPCM7XX_GPIO1_IRQ, 129526dbbe0SHavard Skinnemoen NPCM7XX_GPIO2_IRQ, 130526dbbe0SHavard Skinnemoen NPCM7XX_GPIO3_IRQ, 131526dbbe0SHavard Skinnemoen NPCM7XX_GPIO4_IRQ, 132526dbbe0SHavard Skinnemoen NPCM7XX_GPIO5_IRQ, 133526dbbe0SHavard Skinnemoen NPCM7XX_GPIO6_IRQ, 134526dbbe0SHavard Skinnemoen NPCM7XX_GPIO7_IRQ, 1352d8f048cSHavard Skinnemoen }; 1362d8f048cSHavard Skinnemoen 1372d8f048cSHavard Skinnemoen /* Total number of GIC interrupts, including internal Cortex-A9 interrupts. */ 1382d8f048cSHavard Skinnemoen #define NPCM7XX_NUM_IRQ (160) 1392d8f048cSHavard Skinnemoen 1402d8f048cSHavard Skinnemoen /* Register base address for each Timer Module */ 1412d8f048cSHavard Skinnemoen static const hwaddr npcm7xx_tim_addr[] = { 1422d8f048cSHavard Skinnemoen 0xf0008000, 1432d8f048cSHavard Skinnemoen 0xf0009000, 1442d8f048cSHavard Skinnemoen 0xf000a000, 1452d8f048cSHavard Skinnemoen }; 1462d8f048cSHavard Skinnemoen 1472d8f048cSHavard Skinnemoen /* Register base address for each 16550 UART */ 1482d8f048cSHavard Skinnemoen static const hwaddr npcm7xx_uart_addr[] = { 1492d8f048cSHavard Skinnemoen 0xf0001000, 1502d8f048cSHavard Skinnemoen 0xf0002000, 1512d8f048cSHavard Skinnemoen 0xf0003000, 1522d8f048cSHavard Skinnemoen 0xf0004000, 1532d8f048cSHavard Skinnemoen }; 1542d8f048cSHavard Skinnemoen 155b821242cSHavard Skinnemoen /* Direct memory-mapped access to SPI0 CS0-1. */ 156b821242cSHavard Skinnemoen static const hwaddr npcm7xx_fiu0_flash_addr[] = { 157b821242cSHavard Skinnemoen 0x80000000, /* CS0 */ 158b821242cSHavard Skinnemoen 0x88000000, /* CS1 */ 159b821242cSHavard Skinnemoen }; 160b821242cSHavard Skinnemoen 161b821242cSHavard Skinnemoen /* Direct memory-mapped access to SPI3 CS0-3. */ 162b821242cSHavard Skinnemoen static const hwaddr npcm7xx_fiu3_flash_addr[] = { 163b821242cSHavard Skinnemoen 0xa0000000, /* CS0 */ 164b821242cSHavard Skinnemoen 0xa8000000, /* CS1 */ 165b821242cSHavard Skinnemoen 0xb0000000, /* CS2 */ 166b821242cSHavard Skinnemoen 0xb8000000, /* CS3 */ 167b821242cSHavard Skinnemoen }; 168b821242cSHavard Skinnemoen 1691e943c58SHao Wu /* Register base address for each PWM Module */ 1701e943c58SHao Wu static const hwaddr npcm7xx_pwm_addr[] = { 1711e943c58SHao Wu 0xf0103000, 1721e943c58SHao Wu 0xf0104000, 1731e943c58SHao Wu }; 1741e943c58SHao Wu 17594e77879SHao Wu /* Direct memory-mapped access to each SMBus Module. */ 17694e77879SHao Wu static const hwaddr npcm7xx_smbus_addr[] = { 17794e77879SHao Wu 0xf0080000, 17894e77879SHao Wu 0xf0081000, 17994e77879SHao Wu 0xf0082000, 18094e77879SHao Wu 0xf0083000, 18194e77879SHao Wu 0xf0084000, 18294e77879SHao Wu 0xf0085000, 18394e77879SHao Wu 0xf0086000, 18494e77879SHao Wu 0xf0087000, 18594e77879SHao Wu 0xf0088000, 18694e77879SHao Wu 0xf0089000, 18794e77879SHao Wu 0xf008a000, 18894e77879SHao Wu 0xf008b000, 18994e77879SHao Wu 0xf008c000, 19094e77879SHao Wu 0xf008d000, 19194e77879SHao Wu 0xf008e000, 19294e77879SHao Wu 0xf008f000, 19394e77879SHao Wu }; 19494e77879SHao Wu 195*77586436SDoug Evans /* Register base address for each EMC Module */ 196*77586436SDoug Evans static const hwaddr npcm7xx_emc_addr[] = { 197*77586436SDoug Evans 0xf0825000, 198*77586436SDoug Evans 0xf0826000, 199*77586436SDoug Evans }; 200*77586436SDoug Evans 201b821242cSHavard Skinnemoen static const struct { 202526dbbe0SHavard Skinnemoen hwaddr regs_addr; 203526dbbe0SHavard Skinnemoen uint32_t unconnected_pins; 204526dbbe0SHavard Skinnemoen uint32_t reset_pu; 205526dbbe0SHavard Skinnemoen uint32_t reset_pd; 206526dbbe0SHavard Skinnemoen uint32_t reset_osrc; 207526dbbe0SHavard Skinnemoen uint32_t reset_odsc; 208526dbbe0SHavard Skinnemoen } npcm7xx_gpio[] = { 209526dbbe0SHavard Skinnemoen { 210526dbbe0SHavard Skinnemoen .regs_addr = 0xf0010000, 211526dbbe0SHavard Skinnemoen .reset_pu = 0xff03ffff, 212526dbbe0SHavard Skinnemoen .reset_pd = 0x00fc0000, 213526dbbe0SHavard Skinnemoen }, { 214526dbbe0SHavard Skinnemoen .regs_addr = 0xf0011000, 215526dbbe0SHavard Skinnemoen .unconnected_pins = 0x0000001e, 216526dbbe0SHavard Skinnemoen .reset_pu = 0xfefffe07, 217526dbbe0SHavard Skinnemoen .reset_pd = 0x010001e0, 218526dbbe0SHavard Skinnemoen }, { 219526dbbe0SHavard Skinnemoen .regs_addr = 0xf0012000, 220526dbbe0SHavard Skinnemoen .reset_pu = 0x780fffff, 221526dbbe0SHavard Skinnemoen .reset_pd = 0x07f00000, 222526dbbe0SHavard Skinnemoen .reset_odsc = 0x00700000, 223526dbbe0SHavard Skinnemoen }, { 224526dbbe0SHavard Skinnemoen .regs_addr = 0xf0013000, 225526dbbe0SHavard Skinnemoen .reset_pu = 0x00fc0000, 226526dbbe0SHavard Skinnemoen .reset_pd = 0xff000000, 227526dbbe0SHavard Skinnemoen }, { 228526dbbe0SHavard Skinnemoen .regs_addr = 0xf0014000, 229526dbbe0SHavard Skinnemoen .reset_pu = 0xffffffff, 230526dbbe0SHavard Skinnemoen }, { 231526dbbe0SHavard Skinnemoen .regs_addr = 0xf0015000, 232526dbbe0SHavard Skinnemoen .reset_pu = 0xbf83f801, 233526dbbe0SHavard Skinnemoen .reset_pd = 0x007c0000, 234526dbbe0SHavard Skinnemoen .reset_osrc = 0x000000f1, 235526dbbe0SHavard Skinnemoen .reset_odsc = 0x3f9f80f1, 236526dbbe0SHavard Skinnemoen }, { 237526dbbe0SHavard Skinnemoen .regs_addr = 0xf0016000, 238526dbbe0SHavard Skinnemoen .reset_pu = 0xfc00f801, 239526dbbe0SHavard Skinnemoen .reset_pd = 0x000007fe, 240526dbbe0SHavard Skinnemoen .reset_odsc = 0x00000800, 241526dbbe0SHavard Skinnemoen }, { 242526dbbe0SHavard Skinnemoen .regs_addr = 0xf0017000, 243526dbbe0SHavard Skinnemoen .unconnected_pins = 0xffffff00, 244526dbbe0SHavard Skinnemoen .reset_pu = 0x0000007f, 245526dbbe0SHavard Skinnemoen .reset_osrc = 0x0000007f, 246526dbbe0SHavard Skinnemoen .reset_odsc = 0x0000007f, 247526dbbe0SHavard Skinnemoen }, 248526dbbe0SHavard Skinnemoen }; 249526dbbe0SHavard Skinnemoen 250526dbbe0SHavard Skinnemoen static const struct { 251b821242cSHavard Skinnemoen const char *name; 252b821242cSHavard Skinnemoen hwaddr regs_addr; 253b821242cSHavard Skinnemoen int cs_count; 254b821242cSHavard Skinnemoen const hwaddr *flash_addr; 255b821242cSHavard Skinnemoen } npcm7xx_fiu[] = { 256b821242cSHavard Skinnemoen { 257b821242cSHavard Skinnemoen .name = "fiu0", 258b821242cSHavard Skinnemoen .regs_addr = 0xfb000000, 259b821242cSHavard Skinnemoen .cs_count = ARRAY_SIZE(npcm7xx_fiu0_flash_addr), 260b821242cSHavard Skinnemoen .flash_addr = npcm7xx_fiu0_flash_addr, 261b821242cSHavard Skinnemoen }, { 262b821242cSHavard Skinnemoen .name = "fiu3", 263b821242cSHavard Skinnemoen .regs_addr = 0xc0000000, 264b821242cSHavard Skinnemoen .cs_count = ARRAY_SIZE(npcm7xx_fiu3_flash_addr), 265b821242cSHavard Skinnemoen .flash_addr = npcm7xx_fiu3_flash_addr, 266b821242cSHavard Skinnemoen }, 267b821242cSHavard Skinnemoen }; 268b821242cSHavard Skinnemoen 2692ddae9ccSHavard Skinnemoen static void npcm7xx_write_board_setup(ARMCPU *cpu, 2702ddae9ccSHavard Skinnemoen const struct arm_boot_info *info) 2712ddae9ccSHavard Skinnemoen { 2722ddae9ccSHavard Skinnemoen uint32_t board_setup[] = { 2732ddae9ccSHavard Skinnemoen 0xe59f0010, /* ldr r0, clk_base_addr */ 2742ddae9ccSHavard Skinnemoen 0xe59f1010, /* ldr r1, pllcon1_value */ 2752ddae9ccSHavard Skinnemoen 0xe5801010, /* str r1, [r0, #16] */ 2762ddae9ccSHavard Skinnemoen 0xe59f100c, /* ldr r1, clksel_value */ 2772ddae9ccSHavard Skinnemoen 0xe5801004, /* str r1, [r0, #4] */ 2782ddae9ccSHavard Skinnemoen 0xe12fff1e, /* bx lr */ 2792ddae9ccSHavard Skinnemoen NPCM7XX_CLK_BA, 2802ddae9ccSHavard Skinnemoen NPCM7XX_PLLCON1_FIXUP_VAL, 2812ddae9ccSHavard Skinnemoen NPCM7XX_CLKSEL_FIXUP_VAL, 2822ddae9ccSHavard Skinnemoen }; 2832ddae9ccSHavard Skinnemoen int i; 2842ddae9ccSHavard Skinnemoen 2852ddae9ccSHavard Skinnemoen for (i = 0; i < ARRAY_SIZE(board_setup); i++) { 2862ddae9ccSHavard Skinnemoen board_setup[i] = tswap32(board_setup[i]); 2872ddae9ccSHavard Skinnemoen } 2882ddae9ccSHavard Skinnemoen rom_add_blob_fixed("board-setup", board_setup, sizeof(board_setup), 2892ddae9ccSHavard Skinnemoen info->board_setup_addr); 2902ddae9ccSHavard Skinnemoen } 2912ddae9ccSHavard Skinnemoen 2922d8f048cSHavard Skinnemoen static void npcm7xx_write_secondary_boot(ARMCPU *cpu, 2932d8f048cSHavard Skinnemoen const struct arm_boot_info *info) 2942d8f048cSHavard Skinnemoen { 2952d8f048cSHavard Skinnemoen /* 2962d8f048cSHavard Skinnemoen * The default smpboot stub halts the secondary CPU with a 'wfi' 2972d8f048cSHavard Skinnemoen * instruction, but the arch/arm/mach-npcm/platsmp.c in the Linux kernel 2982d8f048cSHavard Skinnemoen * does not send an IPI to wake it up, so the second CPU fails to boot. So 2992d8f048cSHavard Skinnemoen * we need to provide our own smpboot stub that can not use 'wfi', it has 3002d8f048cSHavard Skinnemoen * to spin the secondary CPU until the first CPU writes to the SCRPAD reg. 3012d8f048cSHavard Skinnemoen */ 3022d8f048cSHavard Skinnemoen uint32_t smpboot[] = { 3032d8f048cSHavard Skinnemoen 0xe59f2018, /* ldr r2, bootreg_addr */ 3042d8f048cSHavard Skinnemoen 0xe3a00000, /* mov r0, #0 */ 3052d8f048cSHavard Skinnemoen 0xe5820000, /* str r0, [r2] */ 3062d8f048cSHavard Skinnemoen 0xe320f002, /* wfe */ 3072d8f048cSHavard Skinnemoen 0xe5921000, /* ldr r1, [r2] */ 3082d8f048cSHavard Skinnemoen 0xe1110001, /* tst r1, r1 */ 3092d8f048cSHavard Skinnemoen 0x0afffffb, /* beq <wfe> */ 3102d8f048cSHavard Skinnemoen 0xe12fff11, /* bx r1 */ 3112d8f048cSHavard Skinnemoen NPCM7XX_SMP_BOOTREG_ADDR, 3122d8f048cSHavard Skinnemoen }; 3132d8f048cSHavard Skinnemoen int i; 3142d8f048cSHavard Skinnemoen 3152d8f048cSHavard Skinnemoen for (i = 0; i < ARRAY_SIZE(smpboot); i++) { 3162d8f048cSHavard Skinnemoen smpboot[i] = tswap32(smpboot[i]); 3172d8f048cSHavard Skinnemoen } 3182d8f048cSHavard Skinnemoen 3192d8f048cSHavard Skinnemoen rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot), 3202d8f048cSHavard Skinnemoen NPCM7XX_SMP_LOADER_START); 3212d8f048cSHavard Skinnemoen } 3222d8f048cSHavard Skinnemoen 3232d8f048cSHavard Skinnemoen static struct arm_boot_info npcm7xx_binfo = { 3242d8f048cSHavard Skinnemoen .loader_start = NPCM7XX_LOADER_START, 3252d8f048cSHavard Skinnemoen .smp_loader_start = NPCM7XX_SMP_LOADER_START, 3262d8f048cSHavard Skinnemoen .smp_bootreg_addr = NPCM7XX_SMP_BOOTREG_ADDR, 3272d8f048cSHavard Skinnemoen .gic_cpu_if_addr = NPCM7XX_GIC_CPU_IF_ADDR, 3282d8f048cSHavard Skinnemoen .write_secondary_boot = npcm7xx_write_secondary_boot, 3292d8f048cSHavard Skinnemoen .board_id = -1, 3302ddae9ccSHavard Skinnemoen .board_setup_addr = NPCM7XX_BOARD_SETUP_ADDR, 3312ddae9ccSHavard Skinnemoen .write_board_setup = npcm7xx_write_board_setup, 3322d8f048cSHavard Skinnemoen }; 3332d8f048cSHavard Skinnemoen 3342d8f048cSHavard Skinnemoen void npcm7xx_load_kernel(MachineState *machine, NPCM7xxState *soc) 3352d8f048cSHavard Skinnemoen { 3362d8f048cSHavard Skinnemoen NPCM7xxClass *sc = NPCM7XX_GET_CLASS(soc); 3372d8f048cSHavard Skinnemoen 3382d8f048cSHavard Skinnemoen npcm7xx_binfo.ram_size = machine->ram_size; 3392d8f048cSHavard Skinnemoen npcm7xx_binfo.nb_cpus = sc->num_cpus; 3402d8f048cSHavard Skinnemoen 3412d8f048cSHavard Skinnemoen arm_load_kernel(&soc->cpu[0], machine, &npcm7xx_binfo); 3422d8f048cSHavard Skinnemoen } 3432d8f048cSHavard Skinnemoen 344c752bb07SHavard Skinnemoen static void npcm7xx_init_fuses(NPCM7xxState *s) 345c752bb07SHavard Skinnemoen { 346c752bb07SHavard Skinnemoen NPCM7xxClass *nc = NPCM7XX_GET_CLASS(s); 347c752bb07SHavard Skinnemoen uint32_t value; 348c752bb07SHavard Skinnemoen 349c752bb07SHavard Skinnemoen /* 350c752bb07SHavard Skinnemoen * The initial mask of disabled modules indicates the chip derivative (e.g. 351c752bb07SHavard Skinnemoen * NPCM750 or NPCM730). 352c752bb07SHavard Skinnemoen */ 353c752bb07SHavard Skinnemoen value = tswap32(nc->disabled_modules); 354c752bb07SHavard Skinnemoen npcm7xx_otp_array_write(&s->fuse_array, &value, NPCM7XX_FUSE_DERIVATIVE, 355c752bb07SHavard Skinnemoen sizeof(value)); 356c752bb07SHavard Skinnemoen } 357c752bb07SHavard Skinnemoen 35877c05b0bSHao Wu static void npcm7xx_write_adc_calibration(NPCM7xxState *s) 35977c05b0bSHao Wu { 36077c05b0bSHao Wu /* Both ADC and the fuse array must have realized. */ 36177c05b0bSHao Wu QEMU_BUILD_BUG_ON(sizeof(s->adc.calibration_r_values) != 4); 36277c05b0bSHao Wu npcm7xx_otp_array_write(&s->fuse_array, s->adc.calibration_r_values, 36377c05b0bSHao Wu NPCM7XX_FUSE_ADC_CALIB, sizeof(s->adc.calibration_r_values)); 36477c05b0bSHao Wu } 36577c05b0bSHao Wu 3662d8f048cSHavard Skinnemoen static qemu_irq npcm7xx_irq(NPCM7xxState *s, int n) 3672d8f048cSHavard Skinnemoen { 3682d8f048cSHavard Skinnemoen return qdev_get_gpio_in(DEVICE(&s->a9mpcore), n); 3692d8f048cSHavard Skinnemoen } 3702d8f048cSHavard Skinnemoen 3712d8f048cSHavard Skinnemoen static void npcm7xx_init(Object *obj) 3722d8f048cSHavard Skinnemoen { 3732d8f048cSHavard Skinnemoen NPCM7xxState *s = NPCM7XX(obj); 3742d8f048cSHavard Skinnemoen int i; 3752d8f048cSHavard Skinnemoen 3762d8f048cSHavard Skinnemoen for (i = 0; i < NPCM7XX_MAX_NUM_CPUS; i++) { 3772d8f048cSHavard Skinnemoen object_initialize_child(obj, "cpu[*]", &s->cpu[i], 3782d8f048cSHavard Skinnemoen ARM_CPU_TYPE_NAME("cortex-a9")); 3792d8f048cSHavard Skinnemoen } 3802d8f048cSHavard Skinnemoen 3812d8f048cSHavard Skinnemoen object_initialize_child(obj, "a9mpcore", &s->a9mpcore, TYPE_A9MPCORE_PRIV); 3822d8f048cSHavard Skinnemoen object_initialize_child(obj, "gcr", &s->gcr, TYPE_NPCM7XX_GCR); 3832d8f048cSHavard Skinnemoen object_property_add_alias(obj, "power-on-straps", OBJECT(&s->gcr), 3842d8f048cSHavard Skinnemoen "power-on-straps"); 3852d8f048cSHavard Skinnemoen object_initialize_child(obj, "clk", &s->clk, TYPE_NPCM7XX_CLK); 386c752bb07SHavard Skinnemoen object_initialize_child(obj, "otp1", &s->key_storage, 387c752bb07SHavard Skinnemoen TYPE_NPCM7XX_KEY_STORAGE); 388c752bb07SHavard Skinnemoen object_initialize_child(obj, "otp2", &s->fuse_array, 389c752bb07SHavard Skinnemoen TYPE_NPCM7XX_FUSE_ARRAY); 3901351f892SHavard Skinnemoen object_initialize_child(obj, "mc", &s->mc, TYPE_NPCM7XX_MC); 391326ccfe2SHavard Skinnemoen object_initialize_child(obj, "rng", &s->rng, TYPE_NPCM7XX_RNG); 39277c05b0bSHao Wu object_initialize_child(obj, "adc", &s->adc, TYPE_NPCM7XX_ADC); 3932d8f048cSHavard Skinnemoen 3942d8f048cSHavard Skinnemoen for (i = 0; i < ARRAY_SIZE(s->tim); i++) { 3952d8f048cSHavard Skinnemoen object_initialize_child(obj, "tim[*]", &s->tim[i], TYPE_NPCM7XX_TIMER); 3962d8f048cSHavard Skinnemoen } 397b821242cSHavard Skinnemoen 398526dbbe0SHavard Skinnemoen for (i = 0; i < ARRAY_SIZE(s->gpio); i++) { 399526dbbe0SHavard Skinnemoen object_initialize_child(obj, "gpio[*]", &s->gpio[i], TYPE_NPCM7XX_GPIO); 400526dbbe0SHavard Skinnemoen } 401526dbbe0SHavard Skinnemoen 40294e77879SHao Wu for (i = 0; i < ARRAY_SIZE(s->smbus); i++) { 40394e77879SHao Wu object_initialize_child(obj, "smbus[*]", &s->smbus[i], 40494e77879SHao Wu TYPE_NPCM7XX_SMBUS); 40594e77879SHao Wu } 40694e77879SHao Wu 407e23e7b12SHavard Skinnemoen object_initialize_child(obj, "ehci", &s->ehci, TYPE_NPCM7XX_EHCI); 408e23e7b12SHavard Skinnemoen object_initialize_child(obj, "ohci", &s->ohci, TYPE_SYSBUS_OHCI); 409e23e7b12SHavard Skinnemoen 410b821242cSHavard Skinnemoen QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_fiu) != ARRAY_SIZE(s->fiu)); 411b821242cSHavard Skinnemoen for (i = 0; i < ARRAY_SIZE(s->fiu); i++) { 412b821242cSHavard Skinnemoen object_initialize_child(obj, npcm7xx_fiu[i].name, &s->fiu[i], 413b821242cSHavard Skinnemoen TYPE_NPCM7XX_FIU); 414b821242cSHavard Skinnemoen } 4151e943c58SHao Wu 4161e943c58SHao Wu for (i = 0; i < ARRAY_SIZE(s->pwm); i++) { 4171e943c58SHao Wu object_initialize_child(obj, "pwm[*]", &s->pwm[i], TYPE_NPCM7XX_PWM); 4181e943c58SHao Wu } 419*77586436SDoug Evans 420*77586436SDoug Evans for (i = 0; i < ARRAY_SIZE(s->emc); i++) { 421*77586436SDoug Evans object_initialize_child(obj, "emc[*]", &s->emc[i], TYPE_NPCM7XX_EMC); 422*77586436SDoug Evans } 4232d8f048cSHavard Skinnemoen } 4242d8f048cSHavard Skinnemoen 4252d8f048cSHavard Skinnemoen static void npcm7xx_realize(DeviceState *dev, Error **errp) 4262d8f048cSHavard Skinnemoen { 4272d8f048cSHavard Skinnemoen NPCM7xxState *s = NPCM7XX(dev); 4282d8f048cSHavard Skinnemoen NPCM7xxClass *nc = NPCM7XX_GET_CLASS(s); 4292d8f048cSHavard Skinnemoen int i; 4302d8f048cSHavard Skinnemoen 4312d8f048cSHavard Skinnemoen if (memory_region_size(s->dram) > NPCM7XX_DRAM_SZ) { 4322d8f048cSHavard Skinnemoen error_setg(errp, "%s: NPCM7xx cannot address more than %" PRIu64 4332d8f048cSHavard Skinnemoen " MiB of DRAM", __func__, NPCM7XX_DRAM_SZ / MiB); 4342d8f048cSHavard Skinnemoen return; 4352d8f048cSHavard Skinnemoen } 4362d8f048cSHavard Skinnemoen 4372d8f048cSHavard Skinnemoen /* CPUs */ 4382d8f048cSHavard Skinnemoen for (i = 0; i < nc->num_cpus; i++) { 4392d8f048cSHavard Skinnemoen object_property_set_int(OBJECT(&s->cpu[i]), "mp-affinity", 4402d8f048cSHavard Skinnemoen arm_cpu_mp_affinity(i, NPCM7XX_MAX_NUM_CPUS), 4412d8f048cSHavard Skinnemoen &error_abort); 4422d8f048cSHavard Skinnemoen object_property_set_int(OBJECT(&s->cpu[i]), "reset-cbar", 4432d8f048cSHavard Skinnemoen NPCM7XX_GIC_CPU_IF_ADDR, &error_abort); 4442d8f048cSHavard Skinnemoen object_property_set_bool(OBJECT(&s->cpu[i]), "reset-hivecs", true, 4452d8f048cSHavard Skinnemoen &error_abort); 4462d8f048cSHavard Skinnemoen 4472d8f048cSHavard Skinnemoen /* Disable security extensions. */ 4482d8f048cSHavard Skinnemoen object_property_set_bool(OBJECT(&s->cpu[i]), "has_el3", false, 4492d8f048cSHavard Skinnemoen &error_abort); 4502d8f048cSHavard Skinnemoen 4512d8f048cSHavard Skinnemoen if (!qdev_realize(DEVICE(&s->cpu[i]), NULL, errp)) { 4522d8f048cSHavard Skinnemoen return; 4532d8f048cSHavard Skinnemoen } 4542d8f048cSHavard Skinnemoen } 4552d8f048cSHavard Skinnemoen 4562d8f048cSHavard Skinnemoen /* A9MPCORE peripherals. Can only fail if we pass bad parameters here. */ 4572d8f048cSHavard Skinnemoen object_property_set_int(OBJECT(&s->a9mpcore), "num-cpu", nc->num_cpus, 4582d8f048cSHavard Skinnemoen &error_abort); 4592d8f048cSHavard Skinnemoen object_property_set_int(OBJECT(&s->a9mpcore), "num-irq", NPCM7XX_NUM_IRQ, 4602d8f048cSHavard Skinnemoen &error_abort); 4612d8f048cSHavard Skinnemoen sysbus_realize(SYS_BUS_DEVICE(&s->a9mpcore), &error_abort); 4622d8f048cSHavard Skinnemoen sysbus_mmio_map(SYS_BUS_DEVICE(&s->a9mpcore), 0, NPCM7XX_CPUP_BA); 4632d8f048cSHavard Skinnemoen 4642d8f048cSHavard Skinnemoen for (i = 0; i < nc->num_cpus; i++) { 4652d8f048cSHavard Skinnemoen sysbus_connect_irq(SYS_BUS_DEVICE(&s->a9mpcore), i, 4662d8f048cSHavard Skinnemoen qdev_get_gpio_in(DEVICE(&s->cpu[i]), ARM_CPU_IRQ)); 4672d8f048cSHavard Skinnemoen sysbus_connect_irq(SYS_BUS_DEVICE(&s->a9mpcore), i + nc->num_cpus, 4682d8f048cSHavard Skinnemoen qdev_get_gpio_in(DEVICE(&s->cpu[i]), ARM_CPU_FIQ)); 4692d8f048cSHavard Skinnemoen } 4702d8f048cSHavard Skinnemoen 4712d8f048cSHavard Skinnemoen /* L2 cache controller */ 4722d8f048cSHavard Skinnemoen sysbus_create_simple("l2x0", NPCM7XX_L2C_BA, NULL); 4732d8f048cSHavard Skinnemoen 4742d8f048cSHavard Skinnemoen /* System Global Control Registers (GCR). Can fail due to user input. */ 4752d8f048cSHavard Skinnemoen object_property_set_int(OBJECT(&s->gcr), "disabled-modules", 4762d8f048cSHavard Skinnemoen nc->disabled_modules, &error_abort); 4772d8f048cSHavard Skinnemoen object_property_add_const_link(OBJECT(&s->gcr), "dram-mr", OBJECT(s->dram)); 4782d8f048cSHavard Skinnemoen if (!sysbus_realize(SYS_BUS_DEVICE(&s->gcr), errp)) { 4792d8f048cSHavard Skinnemoen return; 4802d8f048cSHavard Skinnemoen } 4812d8f048cSHavard Skinnemoen sysbus_mmio_map(SYS_BUS_DEVICE(&s->gcr), 0, NPCM7XX_GCR_BA); 4822d8f048cSHavard Skinnemoen 4832d8f048cSHavard Skinnemoen /* Clock Control Registers (CLK). Cannot fail. */ 4842d8f048cSHavard Skinnemoen sysbus_realize(SYS_BUS_DEVICE(&s->clk), &error_abort); 4852d8f048cSHavard Skinnemoen sysbus_mmio_map(SYS_BUS_DEVICE(&s->clk), 0, NPCM7XX_CLK_BA); 4862d8f048cSHavard Skinnemoen 487c752bb07SHavard Skinnemoen /* OTP key storage and fuse strap array. Cannot fail. */ 488c752bb07SHavard Skinnemoen sysbus_realize(SYS_BUS_DEVICE(&s->key_storage), &error_abort); 489c752bb07SHavard Skinnemoen sysbus_mmio_map(SYS_BUS_DEVICE(&s->key_storage), 0, NPCM7XX_OTP1_BA); 490c752bb07SHavard Skinnemoen sysbus_realize(SYS_BUS_DEVICE(&s->fuse_array), &error_abort); 491c752bb07SHavard Skinnemoen sysbus_mmio_map(SYS_BUS_DEVICE(&s->fuse_array), 0, NPCM7XX_OTP2_BA); 492c752bb07SHavard Skinnemoen npcm7xx_init_fuses(s); 493c752bb07SHavard Skinnemoen 4941351f892SHavard Skinnemoen /* Fake Memory Controller (MC). Cannot fail. */ 4951351f892SHavard Skinnemoen sysbus_realize(SYS_BUS_DEVICE(&s->mc), &error_abort); 4961351f892SHavard Skinnemoen sysbus_mmio_map(SYS_BUS_DEVICE(&s->mc), 0, NPCM7XX_MC_BA); 4971351f892SHavard Skinnemoen 49877c05b0bSHao Wu /* ADC Modules. Cannot fail. */ 49977c05b0bSHao Wu qdev_connect_clock_in(DEVICE(&s->adc), "clock", qdev_get_clock_out( 50077c05b0bSHao Wu DEVICE(&s->clk), "adc-clock")); 50177c05b0bSHao Wu sysbus_realize(SYS_BUS_DEVICE(&s->adc), &error_abort); 50277c05b0bSHao Wu sysbus_mmio_map(SYS_BUS_DEVICE(&s->adc), 0, NPCM7XX_ADC_BA); 50377c05b0bSHao Wu sysbus_connect_irq(SYS_BUS_DEVICE(&s->adc), 0, 50477c05b0bSHao Wu npcm7xx_irq(s, NPCM7XX_ADC_IRQ)); 50577c05b0bSHao Wu npcm7xx_write_adc_calibration(s); 50677c05b0bSHao Wu 5072d8f048cSHavard Skinnemoen /* Timer Modules (TIM). Cannot fail. */ 5082d8f048cSHavard Skinnemoen QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_tim_addr) != ARRAY_SIZE(s->tim)); 5092d8f048cSHavard Skinnemoen for (i = 0; i < ARRAY_SIZE(s->tim); i++) { 5102d8f048cSHavard Skinnemoen SysBusDevice *sbd = SYS_BUS_DEVICE(&s->tim[i]); 5112d8f048cSHavard Skinnemoen int first_irq; 5122d8f048cSHavard Skinnemoen int j; 5132d8f048cSHavard Skinnemoen 5140be12dc7SHao Wu /* Connect the timer clock. */ 5150be12dc7SHao Wu qdev_connect_clock_in(DEVICE(&s->tim[i]), "clock", qdev_get_clock_out( 5160be12dc7SHao Wu DEVICE(&s->clk), "timer-clock")); 5170be12dc7SHao Wu 5182d8f048cSHavard Skinnemoen sysbus_realize(sbd, &error_abort); 5192d8f048cSHavard Skinnemoen sysbus_mmio_map(sbd, 0, npcm7xx_tim_addr[i]); 5202d8f048cSHavard Skinnemoen 5212d8f048cSHavard Skinnemoen first_irq = NPCM7XX_TIMER0_IRQ + i * NPCM7XX_TIMERS_PER_CTRL; 5222d8f048cSHavard Skinnemoen for (j = 0; j < NPCM7XX_TIMERS_PER_CTRL; j++) { 5232d8f048cSHavard Skinnemoen qemu_irq irq = npcm7xx_irq(s, first_irq + j); 5242d8f048cSHavard Skinnemoen sysbus_connect_irq(sbd, j, irq); 5252d8f048cSHavard Skinnemoen } 5267d378ed6SHao Wu 5277d378ed6SHao Wu /* IRQ for watchdogs */ 5287d378ed6SHao Wu sysbus_connect_irq(sbd, NPCM7XX_TIMERS_PER_CTRL, 5297d378ed6SHao Wu npcm7xx_irq(s, NPCM7XX_WDG0_IRQ + i)); 5307d378ed6SHao Wu /* GPIO that connects clk module with watchdog */ 5317d378ed6SHao Wu qdev_connect_gpio_out_named(DEVICE(&s->tim[i]), 5327d378ed6SHao Wu NPCM7XX_WATCHDOG_RESET_GPIO_OUT, 0, 5337d378ed6SHao Wu qdev_get_gpio_in_named(DEVICE(&s->clk), 5347d378ed6SHao Wu NPCM7XX_WATCHDOG_RESET_GPIO_IN, i)); 5352d8f048cSHavard Skinnemoen } 5362d8f048cSHavard Skinnemoen 5372d8f048cSHavard Skinnemoen /* UART0..3 (16550 compatible) */ 5382d8f048cSHavard Skinnemoen for (i = 0; i < ARRAY_SIZE(npcm7xx_uart_addr); i++) { 5392d8f048cSHavard Skinnemoen serial_mm_init(get_system_memory(), npcm7xx_uart_addr[i], 2, 5402d8f048cSHavard Skinnemoen npcm7xx_irq(s, NPCM7XX_UART0_IRQ + i), 115200, 5412d8f048cSHavard Skinnemoen serial_hd(i), DEVICE_LITTLE_ENDIAN); 5422d8f048cSHavard Skinnemoen } 5432d8f048cSHavard Skinnemoen 544326ccfe2SHavard Skinnemoen /* Random Number Generator. Cannot fail. */ 545326ccfe2SHavard Skinnemoen sysbus_realize(SYS_BUS_DEVICE(&s->rng), &error_abort); 546326ccfe2SHavard Skinnemoen sysbus_mmio_map(SYS_BUS_DEVICE(&s->rng), 0, NPCM7XX_RNG_BA); 547326ccfe2SHavard Skinnemoen 548526dbbe0SHavard Skinnemoen /* GPIO modules. Cannot fail. */ 549526dbbe0SHavard Skinnemoen QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_gpio) != ARRAY_SIZE(s->gpio)); 550526dbbe0SHavard Skinnemoen for (i = 0; i < ARRAY_SIZE(s->gpio); i++) { 551526dbbe0SHavard Skinnemoen Object *obj = OBJECT(&s->gpio[i]); 552526dbbe0SHavard Skinnemoen 553526dbbe0SHavard Skinnemoen object_property_set_uint(obj, "reset-pullup", 554526dbbe0SHavard Skinnemoen npcm7xx_gpio[i].reset_pu, &error_abort); 555526dbbe0SHavard Skinnemoen object_property_set_uint(obj, "reset-pulldown", 556526dbbe0SHavard Skinnemoen npcm7xx_gpio[i].reset_pd, &error_abort); 557526dbbe0SHavard Skinnemoen object_property_set_uint(obj, "reset-osrc", 558526dbbe0SHavard Skinnemoen npcm7xx_gpio[i].reset_osrc, &error_abort); 559526dbbe0SHavard Skinnemoen object_property_set_uint(obj, "reset-odsc", 560526dbbe0SHavard Skinnemoen npcm7xx_gpio[i].reset_odsc, &error_abort); 561526dbbe0SHavard Skinnemoen sysbus_realize(SYS_BUS_DEVICE(obj), &error_abort); 562526dbbe0SHavard Skinnemoen sysbus_mmio_map(SYS_BUS_DEVICE(obj), 0, npcm7xx_gpio[i].regs_addr); 563526dbbe0SHavard Skinnemoen sysbus_connect_irq(SYS_BUS_DEVICE(obj), 0, 564526dbbe0SHavard Skinnemoen npcm7xx_irq(s, NPCM7XX_GPIO0_IRQ + i)); 565526dbbe0SHavard Skinnemoen } 566526dbbe0SHavard Skinnemoen 56794e77879SHao Wu /* SMBus modules. Cannot fail. */ 56894e77879SHao Wu QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_smbus_addr) != ARRAY_SIZE(s->smbus)); 56994e77879SHao Wu for (i = 0; i < ARRAY_SIZE(s->smbus); i++) { 57094e77879SHao Wu Object *obj = OBJECT(&s->smbus[i]); 57194e77879SHao Wu 57294e77879SHao Wu sysbus_realize(SYS_BUS_DEVICE(obj), &error_abort); 57394e77879SHao Wu sysbus_mmio_map(SYS_BUS_DEVICE(obj), 0, npcm7xx_smbus_addr[i]); 57494e77879SHao Wu sysbus_connect_irq(SYS_BUS_DEVICE(obj), 0, 57594e77879SHao Wu npcm7xx_irq(s, NPCM7XX_SMBUS0_IRQ + i)); 57694e77879SHao Wu } 57794e77879SHao Wu 578e23e7b12SHavard Skinnemoen /* USB Host */ 579e23e7b12SHavard Skinnemoen object_property_set_bool(OBJECT(&s->ehci), "companion-enable", true, 580e23e7b12SHavard Skinnemoen &error_abort); 581e23e7b12SHavard Skinnemoen sysbus_realize(SYS_BUS_DEVICE(&s->ehci), &error_abort); 582e23e7b12SHavard Skinnemoen sysbus_mmio_map(SYS_BUS_DEVICE(&s->ehci), 0, NPCM7XX_EHCI_BA); 583e23e7b12SHavard Skinnemoen sysbus_connect_irq(SYS_BUS_DEVICE(&s->ehci), 0, 584e23e7b12SHavard Skinnemoen npcm7xx_irq(s, NPCM7XX_EHCI_IRQ)); 585e23e7b12SHavard Skinnemoen 586e23e7b12SHavard Skinnemoen object_property_set_str(OBJECT(&s->ohci), "masterbus", "usb-bus.0", 587e23e7b12SHavard Skinnemoen &error_abort); 588e23e7b12SHavard Skinnemoen object_property_set_uint(OBJECT(&s->ohci), "num-ports", 1, &error_abort); 589e23e7b12SHavard Skinnemoen sysbus_realize(SYS_BUS_DEVICE(&s->ohci), &error_abort); 590e23e7b12SHavard Skinnemoen sysbus_mmio_map(SYS_BUS_DEVICE(&s->ohci), 0, NPCM7XX_OHCI_BA); 591e23e7b12SHavard Skinnemoen sysbus_connect_irq(SYS_BUS_DEVICE(&s->ohci), 0, 592e23e7b12SHavard Skinnemoen npcm7xx_irq(s, NPCM7XX_OHCI_IRQ)); 593e23e7b12SHavard Skinnemoen 5941e943c58SHao Wu /* PWM Modules. Cannot fail. */ 5951e943c58SHao Wu QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_pwm_addr) != ARRAY_SIZE(s->pwm)); 5961e943c58SHao Wu for (i = 0; i < ARRAY_SIZE(s->pwm); i++) { 5971e943c58SHao Wu SysBusDevice *sbd = SYS_BUS_DEVICE(&s->pwm[i]); 5981e943c58SHao Wu 5991e943c58SHao Wu qdev_connect_clock_in(DEVICE(&s->pwm[i]), "clock", qdev_get_clock_out( 6001e943c58SHao Wu DEVICE(&s->clk), "apb3-clock")); 6011e943c58SHao Wu sysbus_realize(sbd, &error_abort); 6021e943c58SHao Wu sysbus_mmio_map(sbd, 0, npcm7xx_pwm_addr[i]); 6031e943c58SHao Wu sysbus_connect_irq(sbd, i, npcm7xx_irq(s, NPCM7XX_PWM0_IRQ + i)); 6041e943c58SHao Wu } 6051e943c58SHao Wu 606b821242cSHavard Skinnemoen /* 607*77586436SDoug Evans * EMC Modules. Cannot fail. 608*77586436SDoug Evans * The mapping of the device to its netdev backend works as follows: 609*77586436SDoug Evans * emc[i] = nd_table[i] 610*77586436SDoug Evans * This works around the inability to specify the netdev property for the 611*77586436SDoug Evans * emc device: it's not pluggable and thus the -device option can't be 612*77586436SDoug Evans * used. 613*77586436SDoug Evans */ 614*77586436SDoug Evans QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_emc_addr) != ARRAY_SIZE(s->emc)); 615*77586436SDoug Evans QEMU_BUILD_BUG_ON(ARRAY_SIZE(s->emc) != 2); 616*77586436SDoug Evans for (i = 0; i < ARRAY_SIZE(s->emc); i++) { 617*77586436SDoug Evans s->emc[i].emc_num = i; 618*77586436SDoug Evans SysBusDevice *sbd = SYS_BUS_DEVICE(&s->emc[i]); 619*77586436SDoug Evans if (nd_table[i].used) { 620*77586436SDoug Evans qemu_check_nic_model(&nd_table[i], TYPE_NPCM7XX_EMC); 621*77586436SDoug Evans qdev_set_nic_properties(DEVICE(sbd), &nd_table[i]); 622*77586436SDoug Evans } 623*77586436SDoug Evans /* 624*77586436SDoug Evans * The device exists regardless of whether it's connected to a QEMU 625*77586436SDoug Evans * netdev backend. So always instantiate it even if there is no 626*77586436SDoug Evans * backend. 627*77586436SDoug Evans */ 628*77586436SDoug Evans sysbus_realize(sbd, &error_abort); 629*77586436SDoug Evans sysbus_mmio_map(sbd, 0, npcm7xx_emc_addr[i]); 630*77586436SDoug Evans int tx_irq = i == 0 ? NPCM7XX_EMC1TX_IRQ : NPCM7XX_EMC2TX_IRQ; 631*77586436SDoug Evans int rx_irq = i == 0 ? NPCM7XX_EMC1RX_IRQ : NPCM7XX_EMC2RX_IRQ; 632*77586436SDoug Evans /* 633*77586436SDoug Evans * N.B. The values for the second argument sysbus_connect_irq are 634*77586436SDoug Evans * chosen to match the registration order in npcm7xx_emc_realize. 635*77586436SDoug Evans */ 636*77586436SDoug Evans sysbus_connect_irq(sbd, 0, npcm7xx_irq(s, tx_irq)); 637*77586436SDoug Evans sysbus_connect_irq(sbd, 1, npcm7xx_irq(s, rx_irq)); 638*77586436SDoug Evans } 639*77586436SDoug Evans 640*77586436SDoug Evans /* 641b821242cSHavard Skinnemoen * Flash Interface Unit (FIU). Can fail if incorrect number of chip selects 642b821242cSHavard Skinnemoen * specified, but this is a programming error. 643b821242cSHavard Skinnemoen */ 644b821242cSHavard Skinnemoen QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_fiu) != ARRAY_SIZE(s->fiu)); 645b821242cSHavard Skinnemoen for (i = 0; i < ARRAY_SIZE(s->fiu); i++) { 646b821242cSHavard Skinnemoen SysBusDevice *sbd = SYS_BUS_DEVICE(&s->fiu[i]); 647b821242cSHavard Skinnemoen int j; 648b821242cSHavard Skinnemoen 649b821242cSHavard Skinnemoen object_property_set_int(OBJECT(sbd), "cs-count", 650b821242cSHavard Skinnemoen npcm7xx_fiu[i].cs_count, &error_abort); 651b821242cSHavard Skinnemoen sysbus_realize(sbd, &error_abort); 652b821242cSHavard Skinnemoen 653b821242cSHavard Skinnemoen sysbus_mmio_map(sbd, 0, npcm7xx_fiu[i].regs_addr); 654b821242cSHavard Skinnemoen for (j = 0; j < npcm7xx_fiu[i].cs_count; j++) { 655b821242cSHavard Skinnemoen sysbus_mmio_map(sbd, j + 1, npcm7xx_fiu[i].flash_addr[j]); 656b821242cSHavard Skinnemoen } 657b821242cSHavard Skinnemoen } 658b821242cSHavard Skinnemoen 6592d8f048cSHavard Skinnemoen /* RAM2 (SRAM) */ 6602d8f048cSHavard Skinnemoen memory_region_init_ram(&s->sram, OBJECT(dev), "ram2", 6612d8f048cSHavard Skinnemoen NPCM7XX_RAM2_SZ, &error_abort); 6622d8f048cSHavard Skinnemoen memory_region_add_subregion(get_system_memory(), NPCM7XX_RAM2_BA, &s->sram); 6632d8f048cSHavard Skinnemoen 6642d8f048cSHavard Skinnemoen /* RAM3 (SRAM) */ 6652d8f048cSHavard Skinnemoen memory_region_init_ram(&s->ram3, OBJECT(dev), "ram3", 6662d8f048cSHavard Skinnemoen NPCM7XX_RAM3_SZ, &error_abort); 6672d8f048cSHavard Skinnemoen memory_region_add_subregion(get_system_memory(), NPCM7XX_RAM3_BA, &s->ram3); 6682d8f048cSHavard Skinnemoen 6692d8f048cSHavard Skinnemoen /* Internal ROM */ 6702d8f048cSHavard Skinnemoen memory_region_init_rom(&s->irom, OBJECT(dev), "irom", NPCM7XX_ROM_SZ, 6712d8f048cSHavard Skinnemoen &error_abort); 6722d8f048cSHavard Skinnemoen memory_region_add_subregion(get_system_memory(), NPCM7XX_ROM_BA, &s->irom); 6732d8f048cSHavard Skinnemoen 6742d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.shm", 0xc0001000, 4 * KiB); 6752d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.vdmx", 0xe0800000, 4 * KiB); 6762d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.pcierc", 0xe1000000, 64 * KiB); 6772d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.kcs", 0xf0007000, 4 * KiB); 6782d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.gfxi", 0xf000e000, 4 * KiB); 6792d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.espi", 0xf009f000, 4 * KiB); 6802d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.peci", 0xf0100000, 4 * KiB); 6812d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.siox[1]", 0xf0101000, 4 * KiB); 6822d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.siox[2]", 0xf0102000, 4 * KiB); 6832d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.mft[0]", 0xf0180000, 4 * KiB); 6842d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.mft[1]", 0xf0181000, 4 * KiB); 6852d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.mft[2]", 0xf0182000, 4 * KiB); 6862d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.mft[3]", 0xf0183000, 4 * KiB); 6872d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.mft[4]", 0xf0184000, 4 * KiB); 6882d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.mft[5]", 0xf0185000, 4 * KiB); 6892d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.mft[6]", 0xf0186000, 4 * KiB); 6902d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.mft[7]", 0xf0187000, 4 * KiB); 6912d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.pspi1", 0xf0200000, 4 * KiB); 6922d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.pspi2", 0xf0201000, 4 * KiB); 6932d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.ahbpci", 0xf0400000, 1 * MiB); 6942d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.mcphy", 0xf05f0000, 64 * KiB); 6952d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.gmac1", 0xf0802000, 8 * KiB); 6962d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.gmac2", 0xf0804000, 8 * KiB); 6972d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.vcd", 0xf0810000, 64 * KiB); 6982d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.ece", 0xf0820000, 8 * KiB); 6992d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.vdma", 0xf0822000, 8 * KiB); 7002d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.usbd[0]", 0xf0830000, 4 * KiB); 7012d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.usbd[1]", 0xf0831000, 4 * KiB); 7022d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.usbd[2]", 0xf0832000, 4 * KiB); 7032d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.usbd[3]", 0xf0833000, 4 * KiB); 7042d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.usbd[4]", 0xf0834000, 4 * KiB); 7052d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.usbd[5]", 0xf0835000, 4 * KiB); 7062d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.usbd[6]", 0xf0836000, 4 * KiB); 7072d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.usbd[7]", 0xf0837000, 4 * KiB); 7082d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.usbd[8]", 0xf0838000, 4 * KiB); 7092d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.usbd[9]", 0xf0839000, 4 * KiB); 7102d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.sd", 0xf0840000, 8 * KiB); 7112d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.mmc", 0xf0842000, 8 * KiB); 7122d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.pcimbx", 0xf0848000, 512 * KiB); 7132d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.aes", 0xf0858000, 4 * KiB); 7142d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.des", 0xf0859000, 4 * KiB); 7152d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.sha", 0xf085a000, 4 * KiB); 7162d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.secacc", 0xf085b000, 4 * KiB); 7172d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.spixcs0", 0xf8000000, 16 * MiB); 7182d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.spixcs1", 0xf9000000, 16 * MiB); 7192d8f048cSHavard Skinnemoen create_unimplemented_device("npcm7xx.spix", 0xfb001000, 4 * KiB); 7202d8f048cSHavard Skinnemoen } 7212d8f048cSHavard Skinnemoen 7222d8f048cSHavard Skinnemoen static Property npcm7xx_properties[] = { 7232d8f048cSHavard Skinnemoen DEFINE_PROP_LINK("dram-mr", NPCM7xxState, dram, TYPE_MEMORY_REGION, 7242d8f048cSHavard Skinnemoen MemoryRegion *), 7252d8f048cSHavard Skinnemoen DEFINE_PROP_END_OF_LIST(), 7262d8f048cSHavard Skinnemoen }; 7272d8f048cSHavard Skinnemoen 7282d8f048cSHavard Skinnemoen static void npcm7xx_class_init(ObjectClass *oc, void *data) 7292d8f048cSHavard Skinnemoen { 7302d8f048cSHavard Skinnemoen DeviceClass *dc = DEVICE_CLASS(oc); 7312d8f048cSHavard Skinnemoen 7322d8f048cSHavard Skinnemoen dc->realize = npcm7xx_realize; 7332d8f048cSHavard Skinnemoen dc->user_creatable = false; 7342d8f048cSHavard Skinnemoen device_class_set_props(dc, npcm7xx_properties); 7352d8f048cSHavard Skinnemoen } 7362d8f048cSHavard Skinnemoen 7372d8f048cSHavard Skinnemoen static void npcm730_class_init(ObjectClass *oc, void *data) 7382d8f048cSHavard Skinnemoen { 7392d8f048cSHavard Skinnemoen NPCM7xxClass *nc = NPCM7XX_CLASS(oc); 7402d8f048cSHavard Skinnemoen 7412d8f048cSHavard Skinnemoen /* NPCM730 is optimized for data center use, so no graphics, etc. */ 7422d8f048cSHavard Skinnemoen nc->disabled_modules = 0x00300395; 7432d8f048cSHavard Skinnemoen nc->num_cpus = 2; 7442d8f048cSHavard Skinnemoen } 7452d8f048cSHavard Skinnemoen 7462d8f048cSHavard Skinnemoen static void npcm750_class_init(ObjectClass *oc, void *data) 7472d8f048cSHavard Skinnemoen { 7482d8f048cSHavard Skinnemoen NPCM7xxClass *nc = NPCM7XX_CLASS(oc); 7492d8f048cSHavard Skinnemoen 7502d8f048cSHavard Skinnemoen /* NPCM750 has 2 cores and a full set of peripherals */ 7512d8f048cSHavard Skinnemoen nc->disabled_modules = 0x00000000; 7522d8f048cSHavard Skinnemoen nc->num_cpus = 2; 7532d8f048cSHavard Skinnemoen } 7542d8f048cSHavard Skinnemoen 7552d8f048cSHavard Skinnemoen static const TypeInfo npcm7xx_soc_types[] = { 7562d8f048cSHavard Skinnemoen { 7572d8f048cSHavard Skinnemoen .name = TYPE_NPCM7XX, 7582d8f048cSHavard Skinnemoen .parent = TYPE_DEVICE, 7592d8f048cSHavard Skinnemoen .instance_size = sizeof(NPCM7xxState), 7602d8f048cSHavard Skinnemoen .instance_init = npcm7xx_init, 7612d8f048cSHavard Skinnemoen .class_size = sizeof(NPCM7xxClass), 7622d8f048cSHavard Skinnemoen .class_init = npcm7xx_class_init, 7632d8f048cSHavard Skinnemoen .abstract = true, 7642d8f048cSHavard Skinnemoen }, { 7652d8f048cSHavard Skinnemoen .name = TYPE_NPCM730, 7662d8f048cSHavard Skinnemoen .parent = TYPE_NPCM7XX, 7672d8f048cSHavard Skinnemoen .class_init = npcm730_class_init, 7682d8f048cSHavard Skinnemoen }, { 7692d8f048cSHavard Skinnemoen .name = TYPE_NPCM750, 7702d8f048cSHavard Skinnemoen .parent = TYPE_NPCM7XX, 7712d8f048cSHavard Skinnemoen .class_init = npcm750_class_init, 7722d8f048cSHavard Skinnemoen }, 7732d8f048cSHavard Skinnemoen }; 7742d8f048cSHavard Skinnemoen 7752d8f048cSHavard Skinnemoen DEFINE_TYPES(npcm7xx_soc_types); 776