1e69954b9Spbrook /* 2e69954b9Spbrook * Status and system control registers for ARM RealView/Versatile boards. 3e69954b9Spbrook * 49ee6e8bbSpbrook * Copyright (c) 2006-2007 CodeSourcery. 5e69954b9Spbrook * Written by Paul Brook 6e69954b9Spbrook * 78e31bf38SMatthew Fernandez * This code is licensed under the GPL. 8e69954b9Spbrook */ 9e69954b9Spbrook 100d1c9782SPeter Maydell #include "qemu/osdep.h" 1164552b6bSMarkus Armbruster #include "hw/irq.h" 12a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h" 131de7afc9SPaolo Bonzini #include "qemu/timer.h" 1432cad1ffSPhilippe Mathieu-Daudé #include "system/runstate.h" 1571538323SPeter Maydell #include "qemu/bitops.h" 1683c9f4caSPaolo Bonzini #include "hw/sysbus.h" 17d6454270SMarkus Armbruster #include "migration/vmstate.h" 180d09e41aSPaolo Bonzini #include "hw/arm/primecell.h" 1903dd024fSPaolo Bonzini #include "qemu/log.h" 200b8fa32fSMarkus Armbruster #include "qemu/module.h" 21db1015e9SEduardo Habkost #include "qom/object.h" 22e69954b9Spbrook 23e69954b9Spbrook #define LOCK_VALUE 0xa05f 24e69954b9Spbrook 25ba4ea5bdSAndreas Färber #define TYPE_ARM_SYSCTL "realview_sysctl" 268063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(arm_sysctl_state, ARM_SYSCTL) 27ba4ea5bdSAndreas Färber 28db1015e9SEduardo Habkost struct arm_sysctl_state { 29ba4ea5bdSAndreas Färber SysBusDevice parent_obj; 30ba4ea5bdSAndreas Färber 31460d7c53SAvi Kivity MemoryRegion iomem; 32242ea2c6SPeter Maydell qemu_irq pl110_mux_ctrl; 33242ea2c6SPeter Maydell 34e69954b9Spbrook uint32_t sys_id; 35e69954b9Spbrook uint32_t leds; 36e69954b9Spbrook uint16_t lockval; 37e69954b9Spbrook uint32_t cfgdata1; 38e69954b9Spbrook uint32_t cfgdata2; 39e69954b9Spbrook uint32_t flags; 40e69954b9Spbrook uint32_t nvflags; 41e69954b9Spbrook uint32_t resetlevel; 4226e92f65SPaul Brook uint32_t proc_id; 43b50ff6f5SPeter Maydell uint32_t sys_mci; 4434933c8cSPeter Maydell uint32_t sys_cfgdata; 4534933c8cSPeter Maydell uint32_t sys_cfgctrl; 4634933c8cSPeter Maydell uint32_t sys_cfgstat; 47242ea2c6SPeter Maydell uint32_t sys_clcd; 481f81f94bSPeter Maydell uint32_t mb_clock[6]; 491f81f94bSPeter Maydell uint32_t *db_clock; 508bd4824aSPeter Maydell uint32_t db_num_vsensors; 518bd4824aSPeter Maydell uint32_t *db_voltage; 521f81f94bSPeter Maydell uint32_t db_num_clocks; 531f81f94bSPeter Maydell uint32_t *db_clock_reset; 54db1015e9SEduardo Habkost }; 55e69954b9Spbrook 56b5ad0ae7SPeter Maydell static const VMStateDescription vmstate_arm_sysctl = { 57b5ad0ae7SPeter Maydell .name = "realview_sysctl", 581f81f94bSPeter Maydell .version_id = 4, 59b5ad0ae7SPeter Maydell .minimum_version_id = 1, 60e4ea952fSRichard Henderson .fields = (const VMStateField[]) { 61b5ad0ae7SPeter Maydell VMSTATE_UINT32(leds, arm_sysctl_state), 62b5ad0ae7SPeter Maydell VMSTATE_UINT16(lockval, arm_sysctl_state), 63b5ad0ae7SPeter Maydell VMSTATE_UINT32(cfgdata1, arm_sysctl_state), 64b5ad0ae7SPeter Maydell VMSTATE_UINT32(cfgdata2, arm_sysctl_state), 65b5ad0ae7SPeter Maydell VMSTATE_UINT32(flags, arm_sysctl_state), 66b5ad0ae7SPeter Maydell VMSTATE_UINT32(nvflags, arm_sysctl_state), 67b5ad0ae7SPeter Maydell VMSTATE_UINT32(resetlevel, arm_sysctl_state), 6834933c8cSPeter Maydell VMSTATE_UINT32_V(sys_mci, arm_sysctl_state, 2), 6934933c8cSPeter Maydell VMSTATE_UINT32_V(sys_cfgdata, arm_sysctl_state, 2), 7034933c8cSPeter Maydell VMSTATE_UINT32_V(sys_cfgctrl, arm_sysctl_state, 2), 7134933c8cSPeter Maydell VMSTATE_UINT32_V(sys_cfgstat, arm_sysctl_state, 2), 72242ea2c6SPeter Maydell VMSTATE_UINT32_V(sys_clcd, arm_sysctl_state, 3), 731f81f94bSPeter Maydell VMSTATE_UINT32_ARRAY_V(mb_clock, arm_sysctl_state, 6, 4), 741f81f94bSPeter Maydell VMSTATE_VARRAY_UINT32(db_clock, arm_sysctl_state, db_num_clocks, 751f81f94bSPeter Maydell 4, vmstate_info_uint32, uint32_t), 76b5ad0ae7SPeter Maydell VMSTATE_END_OF_LIST() 77b5ad0ae7SPeter Maydell } 78b5ad0ae7SPeter Maydell }; 79b5ad0ae7SPeter Maydell 80b50ff6f5SPeter Maydell /* The PB926 actually uses a different format for 81b50ff6f5SPeter Maydell * its SYS_ID register. Fortunately the bits which are 82b50ff6f5SPeter Maydell * board type on later boards are distinct. 83b50ff6f5SPeter Maydell */ 84b50ff6f5SPeter Maydell #define BOARD_ID_PB926 0x100 85b50ff6f5SPeter Maydell #define BOARD_ID_EB 0x140 86b50ff6f5SPeter Maydell #define BOARD_ID_PBA8 0x178 87b50ff6f5SPeter Maydell #define BOARD_ID_PBX 0x182 8834933c8cSPeter Maydell #define BOARD_ID_VEXPRESS 0x190 89b50ff6f5SPeter Maydell 90b50ff6f5SPeter Maydell static int board_id(arm_sysctl_state *s) 91b50ff6f5SPeter Maydell { 92b50ff6f5SPeter Maydell /* Extract the board ID field from the SYS_ID register value */ 93b50ff6f5SPeter Maydell return (s->sys_id >> 16) & 0xfff; 94b50ff6f5SPeter Maydell } 95b50ff6f5SPeter Maydell 96be0f204aSPaul Brook static void arm_sysctl_reset(DeviceState *d) 97be0f204aSPaul Brook { 98ba4ea5bdSAndreas Färber arm_sysctl_state *s = ARM_SYSCTL(d); 991f81f94bSPeter Maydell int i; 100be0f204aSPaul Brook 101be0f204aSPaul Brook s->leds = 0; 102be0f204aSPaul Brook s->lockval = 0; 103be0f204aSPaul Brook s->cfgdata1 = 0; 104be0f204aSPaul Brook s->cfgdata2 = 0; 105be0f204aSPaul Brook s->flags = 0; 106be0f204aSPaul Brook s->resetlevel = 0; 1071f81f94bSPeter Maydell /* Motherboard oscillators (in Hz) */ 1081f81f94bSPeter Maydell s->mb_clock[0] = 50000000; /* Static memory clock: 50MHz */ 1091f81f94bSPeter Maydell s->mb_clock[1] = 23750000; /* motherboard CLCD clock: 23.75MHz */ 1101f81f94bSPeter Maydell s->mb_clock[2] = 24000000; /* IO FPGA peripheral clock: 24MHz */ 1111f81f94bSPeter Maydell s->mb_clock[3] = 24000000; /* IO FPGA reserved clock: 24MHz */ 1121f81f94bSPeter Maydell s->mb_clock[4] = 24000000; /* System bus global clock: 24MHz */ 1131f81f94bSPeter Maydell s->mb_clock[5] = 24000000; /* IO FPGA reserved clock: 24MHz */ 1141f81f94bSPeter Maydell /* Daughterboard oscillators: reset from property values */ 1151f81f94bSPeter Maydell for (i = 0; i < s->db_num_clocks; i++) { 1161f81f94bSPeter Maydell s->db_clock[i] = s->db_clock_reset[i]; 1171f81f94bSPeter Maydell } 118242ea2c6SPeter Maydell if (board_id(s) == BOARD_ID_VEXPRESS) { 119242ea2c6SPeter Maydell /* On VExpress this register will RAZ/WI */ 120242ea2c6SPeter Maydell s->sys_clcd = 0; 121242ea2c6SPeter Maydell } else { 122242ea2c6SPeter Maydell /* All others: CLCDID 0x1f, indicating VGA */ 123242ea2c6SPeter Maydell s->sys_clcd = 0x1f00; 124242ea2c6SPeter Maydell } 125be0f204aSPaul Brook } 126be0f204aSPaul Brook 127a8170e5eSAvi Kivity static uint64_t arm_sysctl_read(void *opaque, hwaddr offset, 128460d7c53SAvi Kivity unsigned size) 129e69954b9Spbrook { 130e69954b9Spbrook arm_sysctl_state *s = (arm_sysctl_state *)opaque; 131e69954b9Spbrook 132e69954b9Spbrook switch (offset) { 133e69954b9Spbrook case 0x00: /* ID */ 134e69954b9Spbrook return s->sys_id; 135e69954b9Spbrook case 0x04: /* SW */ 136e69954b9Spbrook /* General purpose hardware switches. 137e69954b9Spbrook We don't have a useful way of exposing these to the user. */ 138e69954b9Spbrook return 0; 139e69954b9Spbrook case 0x08: /* LED */ 140e69954b9Spbrook return s->leds; 141e69954b9Spbrook case 0x20: /* LOCK */ 142e69954b9Spbrook return s->lockval; 143e69954b9Spbrook case 0x0c: /* OSC0 */ 144e69954b9Spbrook case 0x10: /* OSC1 */ 145e69954b9Spbrook case 0x14: /* OSC2 */ 146e69954b9Spbrook case 0x18: /* OSC3 */ 147e69954b9Spbrook case 0x1c: /* OSC4 */ 148e69954b9Spbrook case 0x24: /* 100HZ */ 149e69954b9Spbrook /* ??? Implement these. */ 150e69954b9Spbrook return 0; 151e69954b9Spbrook case 0x28: /* CFGDATA1 */ 152e69954b9Spbrook return s->cfgdata1; 153e69954b9Spbrook case 0x2c: /* CFGDATA2 */ 154e69954b9Spbrook return s->cfgdata2; 155e69954b9Spbrook case 0x30: /* FLAGS */ 156e69954b9Spbrook return s->flags; 157e69954b9Spbrook case 0x38: /* NVFLAGS */ 158e69954b9Spbrook return s->nvflags; 159e69954b9Spbrook case 0x40: /* RESETCTL */ 16034933c8cSPeter Maydell if (board_id(s) == BOARD_ID_VEXPRESS) { 16134933c8cSPeter Maydell /* reserved: RAZ/WI */ 16234933c8cSPeter Maydell return 0; 16334933c8cSPeter Maydell } 164e69954b9Spbrook return s->resetlevel; 165e69954b9Spbrook case 0x44: /* PCICTL */ 166e69954b9Spbrook return 1; 167e69954b9Spbrook case 0x48: /* MCI */ 168b50ff6f5SPeter Maydell return s->sys_mci; 169e69954b9Spbrook case 0x4c: /* FLASH */ 170e69954b9Spbrook return 0; 171e69954b9Spbrook case 0x50: /* CLCD */ 172242ea2c6SPeter Maydell return s->sys_clcd; 173e69954b9Spbrook case 0x54: /* CLCDSER */ 174e69954b9Spbrook return 0; 175e69954b9Spbrook case 0x58: /* BOOTCS */ 176e69954b9Spbrook return 0; 177e69954b9Spbrook case 0x5c: /* 24MHz */ 17873bcb24dSRutuja Shah return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24000000, 17973bcb24dSRutuja Shah NANOSECONDS_PER_SECOND); 180e69954b9Spbrook case 0x60: /* MISC */ 181e69954b9Spbrook return 0; 182e69954b9Spbrook case 0x84: /* PROCID0 */ 18326e92f65SPaul Brook return s->proc_id; 184e69954b9Spbrook case 0x88: /* PROCID1 */ 185e69954b9Spbrook return 0xff000000; 186e69954b9Spbrook case 0x64: /* DMAPSR0 */ 187e69954b9Spbrook case 0x68: /* DMAPSR1 */ 188e69954b9Spbrook case 0x6c: /* DMAPSR2 */ 189e69954b9Spbrook case 0x70: /* IOSEL */ 190e69954b9Spbrook case 0x74: /* PLDCTL */ 191e69954b9Spbrook case 0x80: /* BUSID */ 192e69954b9Spbrook case 0x8c: /* OSCRESET0 */ 193e69954b9Spbrook case 0x90: /* OSCRESET1 */ 194e69954b9Spbrook case 0x94: /* OSCRESET2 */ 195e69954b9Spbrook case 0x98: /* OSCRESET3 */ 196e69954b9Spbrook case 0x9c: /* OSCRESET4 */ 197e69954b9Spbrook case 0xc0: /* SYS_TEST_OSC0 */ 198e69954b9Spbrook case 0xc4: /* SYS_TEST_OSC1 */ 199e69954b9Spbrook case 0xc8: /* SYS_TEST_OSC2 */ 200e69954b9Spbrook case 0xcc: /* SYS_TEST_OSC3 */ 201e69954b9Spbrook case 0xd0: /* SYS_TEST_OSC4 */ 202e69954b9Spbrook return 0; 20334933c8cSPeter Maydell case 0xa0: /* SYS_CFGDATA */ 20434933c8cSPeter Maydell if (board_id(s) != BOARD_ID_VEXPRESS) { 20534933c8cSPeter Maydell goto bad_reg; 20634933c8cSPeter Maydell } 20734933c8cSPeter Maydell return s->sys_cfgdata; 20834933c8cSPeter Maydell case 0xa4: /* SYS_CFGCTRL */ 20934933c8cSPeter Maydell if (board_id(s) != BOARD_ID_VEXPRESS) { 21034933c8cSPeter Maydell goto bad_reg; 21134933c8cSPeter Maydell } 21234933c8cSPeter Maydell return s->sys_cfgctrl; 21334933c8cSPeter Maydell case 0xa8: /* SYS_CFGSTAT */ 21434933c8cSPeter Maydell if (board_id(s) != BOARD_ID_VEXPRESS) { 21534933c8cSPeter Maydell goto bad_reg; 21634933c8cSPeter Maydell } 21734933c8cSPeter Maydell return s->sys_cfgstat; 218e69954b9Spbrook default: 21934933c8cSPeter Maydell bad_reg: 2200c896f06SPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 2210c896f06SPeter Maydell "arm_sysctl_read: Bad register offset 0x%x\n", 2220c896f06SPeter Maydell (int)offset); 223e69954b9Spbrook return 0; 224e69954b9Spbrook } 225e69954b9Spbrook } 226e69954b9Spbrook 22771538323SPeter Maydell /* SYS_CFGCTRL functions */ 22871538323SPeter Maydell #define SYS_CFG_OSC 1 22971538323SPeter Maydell #define SYS_CFG_VOLT 2 23071538323SPeter Maydell #define SYS_CFG_AMP 3 23171538323SPeter Maydell #define SYS_CFG_TEMP 4 23271538323SPeter Maydell #define SYS_CFG_RESET 5 23371538323SPeter Maydell #define SYS_CFG_SCC 6 23471538323SPeter Maydell #define SYS_CFG_MUXFPGA 7 23571538323SPeter Maydell #define SYS_CFG_SHUTDOWN 8 23671538323SPeter Maydell #define SYS_CFG_REBOOT 9 23771538323SPeter Maydell #define SYS_CFG_DVIMODE 11 23871538323SPeter Maydell #define SYS_CFG_POWER 12 23971538323SPeter Maydell #define SYS_CFG_ENERGY 13 24071538323SPeter Maydell 24171538323SPeter Maydell /* SYS_CFGCTRL site field values */ 24271538323SPeter Maydell #define SYS_CFG_SITE_MB 0 24371538323SPeter Maydell #define SYS_CFG_SITE_DB1 1 24471538323SPeter Maydell #define SYS_CFG_SITE_DB2 2 24571538323SPeter Maydell 24671538323SPeter Maydell /** 24771538323SPeter Maydell * vexpress_cfgctrl_read: 24871538323SPeter Maydell * @s: arm_sysctl_state pointer 24971538323SPeter Maydell * @dcc, @function, @site, @position, @device: split out values from 25071538323SPeter Maydell * SYS_CFGCTRL register 25171538323SPeter Maydell * @val: pointer to where to put the read data on success 25271538323SPeter Maydell * 25371538323SPeter Maydell * Handle a VExpress SYS_CFGCTRL register read. On success, return true and 25471538323SPeter Maydell * write the read value to *val. On failure, return false (and val may 25571538323SPeter Maydell * or may not be written to). 25671538323SPeter Maydell */ 25771538323SPeter Maydell static bool vexpress_cfgctrl_read(arm_sysctl_state *s, unsigned int dcc, 25871538323SPeter Maydell unsigned int function, unsigned int site, 25971538323SPeter Maydell unsigned int position, unsigned int device, 26071538323SPeter Maydell uint32_t *val) 26171538323SPeter Maydell { 26271538323SPeter Maydell /* We don't support anything other than DCC 0, board stack position 0 26371538323SPeter Maydell * or sites other than motherboard/daughterboard: 26471538323SPeter Maydell */ 26571538323SPeter Maydell if (dcc != 0 || position != 0 || 26671538323SPeter Maydell (site != SYS_CFG_SITE_MB && site != SYS_CFG_SITE_DB1)) { 26771538323SPeter Maydell goto cfgctrl_unimp; 26871538323SPeter Maydell } 26971538323SPeter Maydell 27071538323SPeter Maydell switch (function) { 2718bd4824aSPeter Maydell case SYS_CFG_VOLT: 2728bd4824aSPeter Maydell if (site == SYS_CFG_SITE_DB1 && device < s->db_num_vsensors) { 2738bd4824aSPeter Maydell *val = s->db_voltage[device]; 2748bd4824aSPeter Maydell return true; 2758bd4824aSPeter Maydell } 2768bd4824aSPeter Maydell if (site == SYS_CFG_SITE_MB && device == 0) { 2778bd4824aSPeter Maydell /* There is only one motherboard voltage sensor: 2788bd4824aSPeter Maydell * VIO : 3.3V : bus voltage between mother and daughterboard 2798bd4824aSPeter Maydell */ 2808bd4824aSPeter Maydell *val = 3300000; 2818bd4824aSPeter Maydell return true; 2828bd4824aSPeter Maydell } 2838bd4824aSPeter Maydell break; 2841f81f94bSPeter Maydell case SYS_CFG_OSC: 285ec1efab9SPeter Maydell if (site == SYS_CFG_SITE_MB && device < ARRAY_SIZE(s->mb_clock)) { 2861f81f94bSPeter Maydell /* motherboard clock */ 2871f81f94bSPeter Maydell *val = s->mb_clock[device]; 2881f81f94bSPeter Maydell return true; 2891f81f94bSPeter Maydell } 2901f81f94bSPeter Maydell if (site == SYS_CFG_SITE_DB1 && device < s->db_num_clocks) { 2911f81f94bSPeter Maydell /* daughterboard clock */ 2921f81f94bSPeter Maydell *val = s->db_clock[device]; 2931f81f94bSPeter Maydell return true; 2941f81f94bSPeter Maydell } 2951f81f94bSPeter Maydell break; 29671538323SPeter Maydell default: 29771538323SPeter Maydell break; 29871538323SPeter Maydell } 29971538323SPeter Maydell 30071538323SPeter Maydell cfgctrl_unimp: 30171538323SPeter Maydell qemu_log_mask(LOG_UNIMP, 30271538323SPeter Maydell "arm_sysctl: Unimplemented SYS_CFGCTRL read of function " 30371538323SPeter Maydell "0x%x DCC 0x%x site 0x%x position 0x%x device 0x%x\n", 30471538323SPeter Maydell function, dcc, site, position, device); 30571538323SPeter Maydell return false; 30671538323SPeter Maydell } 30771538323SPeter Maydell 30871538323SPeter Maydell /** 30971538323SPeter Maydell * vexpress_cfgctrl_write: 31071538323SPeter Maydell * @s: arm_sysctl_state pointer 31171538323SPeter Maydell * @dcc, @function, @site, @position, @device: split out values from 31271538323SPeter Maydell * SYS_CFGCTRL register 31371538323SPeter Maydell * @val: data to write 31471538323SPeter Maydell * 31571538323SPeter Maydell * Handle a VExpress SYS_CFGCTRL register write. On success, return true. 31671538323SPeter Maydell * On failure, return false. 31771538323SPeter Maydell */ 31871538323SPeter Maydell static bool vexpress_cfgctrl_write(arm_sysctl_state *s, unsigned int dcc, 31971538323SPeter Maydell unsigned int function, unsigned int site, 32071538323SPeter Maydell unsigned int position, unsigned int device, 32171538323SPeter Maydell uint32_t val) 32271538323SPeter Maydell { 32371538323SPeter Maydell /* We don't support anything other than DCC 0, board stack position 0 32471538323SPeter Maydell * or sites other than motherboard/daughterboard: 32571538323SPeter Maydell */ 32671538323SPeter Maydell if (dcc != 0 || position != 0 || 32771538323SPeter Maydell (site != SYS_CFG_SITE_MB && site != SYS_CFG_SITE_DB1)) { 32871538323SPeter Maydell goto cfgctrl_unimp; 32971538323SPeter Maydell } 33071538323SPeter Maydell 33171538323SPeter Maydell switch (function) { 3321f81f94bSPeter Maydell case SYS_CFG_OSC: 333ec1efab9SPeter Maydell if (site == SYS_CFG_SITE_MB && device < ARRAY_SIZE(s->mb_clock)) { 3341f81f94bSPeter Maydell /* motherboard clock */ 3351f81f94bSPeter Maydell s->mb_clock[device] = val; 3361f81f94bSPeter Maydell return true; 3371f81f94bSPeter Maydell } 3381f81f94bSPeter Maydell if (site == SYS_CFG_SITE_DB1 && device < s->db_num_clocks) { 3391f81f94bSPeter Maydell /* daughterboard clock */ 3401f81f94bSPeter Maydell s->db_clock[device] = val; 3411f81f94bSPeter Maydell return true; 3421f81f94bSPeter Maydell } 3431f81f94bSPeter Maydell break; 3448ff05c98SPeter Maydell case SYS_CFG_MUXFPGA: 3458ff05c98SPeter Maydell if (site == SYS_CFG_SITE_MB && device == 0) { 3468ff05c98SPeter Maydell /* Select whether video output comes from motherboard 3478ff05c98SPeter Maydell * or daughterboard: log and ignore as QEMU doesn't 3488ff05c98SPeter Maydell * support this. 3498ff05c98SPeter Maydell */ 3508ff05c98SPeter Maydell qemu_log_mask(LOG_UNIMP, "arm_sysctl: selection of video output " 3518ff05c98SPeter Maydell "not supported, ignoring\n"); 3528ff05c98SPeter Maydell return true; 3538ff05c98SPeter Maydell } 3548ff05c98SPeter Maydell break; 35571538323SPeter Maydell case SYS_CFG_SHUTDOWN: 35671538323SPeter Maydell if (site == SYS_CFG_SITE_MB && device == 0) { 357cf83f140SEric Blake qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); 35871538323SPeter Maydell return true; 35971538323SPeter Maydell } 36071538323SPeter Maydell break; 36171538323SPeter Maydell case SYS_CFG_REBOOT: 36271538323SPeter Maydell if (site == SYS_CFG_SITE_MB && device == 0) { 363cf83f140SEric Blake qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); 36471538323SPeter Maydell return true; 36571538323SPeter Maydell } 36671538323SPeter Maydell break; 367291155cbSPeter Maydell case SYS_CFG_DVIMODE: 368291155cbSPeter Maydell if (site == SYS_CFG_SITE_MB && device == 0) { 369291155cbSPeter Maydell /* Selecting DVI mode is meaningless for QEMU: we will 370291155cbSPeter Maydell * always display the output correctly according to the 371291155cbSPeter Maydell * pixel height/width programmed into the CLCD controller. 372291155cbSPeter Maydell */ 373291155cbSPeter Maydell return true; 374291155cbSPeter Maydell } 37571538323SPeter Maydell default: 37671538323SPeter Maydell break; 37771538323SPeter Maydell } 37871538323SPeter Maydell 37971538323SPeter Maydell cfgctrl_unimp: 38071538323SPeter Maydell qemu_log_mask(LOG_UNIMP, 38171538323SPeter Maydell "arm_sysctl: Unimplemented SYS_CFGCTRL write of function " 38271538323SPeter Maydell "0x%x DCC 0x%x site 0x%x position 0x%x device 0x%x\n", 38371538323SPeter Maydell function, dcc, site, position, device); 38471538323SPeter Maydell return false; 38571538323SPeter Maydell } 38671538323SPeter Maydell 387a8170e5eSAvi Kivity static void arm_sysctl_write(void *opaque, hwaddr offset, 388460d7c53SAvi Kivity uint64_t val, unsigned size) 389e69954b9Spbrook { 390e69954b9Spbrook arm_sysctl_state *s = (arm_sysctl_state *)opaque; 391e69954b9Spbrook 392e69954b9Spbrook switch (offset) { 393e69954b9Spbrook case 0x08: /* LED */ 394e69954b9Spbrook s->leds = val; 395bf4229d3SPeter Maydell break; 396e69954b9Spbrook case 0x0c: /* OSC0 */ 397e69954b9Spbrook case 0x10: /* OSC1 */ 398e69954b9Spbrook case 0x14: /* OSC2 */ 399e69954b9Spbrook case 0x18: /* OSC3 */ 400e69954b9Spbrook case 0x1c: /* OSC4 */ 401e69954b9Spbrook /* ??? */ 402e69954b9Spbrook break; 403e69954b9Spbrook case 0x20: /* LOCK */ 404e69954b9Spbrook if (val == LOCK_VALUE) 405e69954b9Spbrook s->lockval = val; 406e69954b9Spbrook else 407e69954b9Spbrook s->lockval = val & 0x7fff; 408e69954b9Spbrook break; 409e69954b9Spbrook case 0x28: /* CFGDATA1 */ 410e69954b9Spbrook /* ??? Need to implement this. */ 411e69954b9Spbrook s->cfgdata1 = val; 412e69954b9Spbrook break; 413e69954b9Spbrook case 0x2c: /* CFGDATA2 */ 414e69954b9Spbrook /* ??? Need to implement this. */ 415e69954b9Spbrook s->cfgdata2 = val; 416e69954b9Spbrook break; 417e69954b9Spbrook case 0x30: /* FLAGSSET */ 418e69954b9Spbrook s->flags |= val; 419e69954b9Spbrook break; 420e69954b9Spbrook case 0x34: /* FLAGSCLR */ 421e69954b9Spbrook s->flags &= ~val; 422e69954b9Spbrook break; 423e69954b9Spbrook case 0x38: /* NVFLAGSSET */ 424e69954b9Spbrook s->nvflags |= val; 425e69954b9Spbrook break; 426e69954b9Spbrook case 0x3c: /* NVFLAGSCLR */ 427e69954b9Spbrook s->nvflags &= ~val; 428e69954b9Spbrook break; 429e69954b9Spbrook case 0x40: /* RESETCTL */ 430b2887c43SJean-Christophe DUBOIS switch (board_id(s)) { 431b2887c43SJean-Christophe DUBOIS case BOARD_ID_PB926: 432e69954b9Spbrook if (s->lockval == LOCK_VALUE) { 433e69954b9Spbrook s->resetlevel = val; 434b2887c43SJean-Christophe DUBOIS if (val & 0x100) { 435cf83f140SEric Blake qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); 436e69954b9Spbrook } 437b2887c43SJean-Christophe DUBOIS } 438b2887c43SJean-Christophe DUBOIS break; 439b2887c43SJean-Christophe DUBOIS case BOARD_ID_PBX: 440b2887c43SJean-Christophe DUBOIS case BOARD_ID_PBA8: 441b2887c43SJean-Christophe DUBOIS if (s->lockval == LOCK_VALUE) { 442b2887c43SJean-Christophe DUBOIS s->resetlevel = val; 443b2887c43SJean-Christophe DUBOIS if (val & 0x04) { 444cf83f140SEric Blake qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); 445b2887c43SJean-Christophe DUBOIS } 446b2887c43SJean-Christophe DUBOIS } 447b2887c43SJean-Christophe DUBOIS break; 448b2887c43SJean-Christophe DUBOIS case BOARD_ID_VEXPRESS: 449b2887c43SJean-Christophe DUBOIS case BOARD_ID_EB: 450b2887c43SJean-Christophe DUBOIS default: 451b2887c43SJean-Christophe DUBOIS /* reserved: RAZ/WI */ 452b2887c43SJean-Christophe DUBOIS break; 453b2887c43SJean-Christophe DUBOIS } 454e69954b9Spbrook break; 455e69954b9Spbrook case 0x44: /* PCICTL */ 456e69954b9Spbrook /* nothing to do. */ 457e69954b9Spbrook break; 458e69954b9Spbrook case 0x4c: /* FLASH */ 459242ea2c6SPeter Maydell break; 460e69954b9Spbrook case 0x50: /* CLCD */ 461242ea2c6SPeter Maydell switch (board_id(s)) { 462242ea2c6SPeter Maydell case BOARD_ID_PB926: 463242ea2c6SPeter Maydell /* On 926 bits 13:8 are R/O, bits 1:0 control 464242ea2c6SPeter Maydell * the mux that defines how to interpret the PL110 465242ea2c6SPeter Maydell * graphics format, and other bits are r/w but we 466242ea2c6SPeter Maydell * don't implement them to do anything. 467242ea2c6SPeter Maydell */ 468242ea2c6SPeter Maydell s->sys_clcd &= 0x3f00; 469242ea2c6SPeter Maydell s->sys_clcd |= val & ~0x3f00; 470242ea2c6SPeter Maydell qemu_set_irq(s->pl110_mux_ctrl, val & 3); 471242ea2c6SPeter Maydell break; 472242ea2c6SPeter Maydell case BOARD_ID_EB: 473242ea2c6SPeter Maydell /* The EB is the same except that there is no mux since 474242ea2c6SPeter Maydell * the EB has a PL111. 475242ea2c6SPeter Maydell */ 476242ea2c6SPeter Maydell s->sys_clcd &= 0x3f00; 477242ea2c6SPeter Maydell s->sys_clcd |= val & ~0x3f00; 478242ea2c6SPeter Maydell break; 479242ea2c6SPeter Maydell case BOARD_ID_PBA8: 480242ea2c6SPeter Maydell case BOARD_ID_PBX: 481242ea2c6SPeter Maydell /* On PBA8 and PBX bit 7 is r/w and all other bits 482242ea2c6SPeter Maydell * are either r/o or RAZ/WI. 483242ea2c6SPeter Maydell */ 484242ea2c6SPeter Maydell s->sys_clcd &= (1 << 7); 485242ea2c6SPeter Maydell s->sys_clcd |= val & ~(1 << 7); 486242ea2c6SPeter Maydell break; 487242ea2c6SPeter Maydell case BOARD_ID_VEXPRESS: 488242ea2c6SPeter Maydell default: 489242ea2c6SPeter Maydell /* On VExpress this register is unimplemented and will RAZ/WI */ 490242ea2c6SPeter Maydell break; 491242ea2c6SPeter Maydell } 492bf4229d3SPeter Maydell break; 493e69954b9Spbrook case 0x54: /* CLCDSER */ 494e69954b9Spbrook case 0x64: /* DMAPSR0 */ 495e69954b9Spbrook case 0x68: /* DMAPSR1 */ 496e69954b9Spbrook case 0x6c: /* DMAPSR2 */ 497e69954b9Spbrook case 0x70: /* IOSEL */ 498e69954b9Spbrook case 0x74: /* PLDCTL */ 499e69954b9Spbrook case 0x80: /* BUSID */ 500e69954b9Spbrook case 0x84: /* PROCID0 */ 501e69954b9Spbrook case 0x88: /* PROCID1 */ 502e69954b9Spbrook case 0x8c: /* OSCRESET0 */ 503e69954b9Spbrook case 0x90: /* OSCRESET1 */ 504e69954b9Spbrook case 0x94: /* OSCRESET2 */ 505e69954b9Spbrook case 0x98: /* OSCRESET3 */ 506e69954b9Spbrook case 0x9c: /* OSCRESET4 */ 507e69954b9Spbrook break; 50834933c8cSPeter Maydell case 0xa0: /* SYS_CFGDATA */ 50934933c8cSPeter Maydell if (board_id(s) != BOARD_ID_VEXPRESS) { 51034933c8cSPeter Maydell goto bad_reg; 51134933c8cSPeter Maydell } 51234933c8cSPeter Maydell s->sys_cfgdata = val; 51334933c8cSPeter Maydell return; 51434933c8cSPeter Maydell case 0xa4: /* SYS_CFGCTRL */ 51534933c8cSPeter Maydell if (board_id(s) != BOARD_ID_VEXPRESS) { 51634933c8cSPeter Maydell goto bad_reg; 51734933c8cSPeter Maydell } 51871538323SPeter Maydell /* Undefined bits [19:18] are RAZ/WI, and writing to 51971538323SPeter Maydell * the start bit just triggers the action; it always reads 52071538323SPeter Maydell * as zero. 52171538323SPeter Maydell */ 52271538323SPeter Maydell s->sys_cfgctrl = val & ~((3 << 18) | (1 << 31)); 523*906853e1SAnastasia Belova if (extract64(val, 31, 1)) { 52471538323SPeter Maydell /* Start bit set -- actually do something */ 52571538323SPeter Maydell unsigned int dcc = extract32(s->sys_cfgctrl, 26, 4); 52671538323SPeter Maydell unsigned int function = extract32(s->sys_cfgctrl, 20, 6); 52771538323SPeter Maydell unsigned int site = extract32(s->sys_cfgctrl, 16, 2); 52871538323SPeter Maydell unsigned int position = extract32(s->sys_cfgctrl, 12, 4); 52971538323SPeter Maydell unsigned int device = extract32(s->sys_cfgctrl, 0, 12); 53034933c8cSPeter Maydell s->sys_cfgstat = 1; /* complete */ 53171538323SPeter Maydell if (s->sys_cfgctrl & (1 << 30)) { 53271538323SPeter Maydell if (!vexpress_cfgctrl_write(s, dcc, function, site, position, 53371538323SPeter Maydell device, s->sys_cfgdata)) { 53434933c8cSPeter Maydell s->sys_cfgstat |= 2; /* error */ 53534933c8cSPeter Maydell } 53671538323SPeter Maydell } else { 537b2e7e204SPeter Maydell uint32_t data; 53871538323SPeter Maydell if (!vexpress_cfgctrl_read(s, dcc, function, site, position, 539b2e7e204SPeter Maydell device, &data)) { 54071538323SPeter Maydell s->sys_cfgstat |= 2; /* error */ 54171538323SPeter Maydell } else { 542b2e7e204SPeter Maydell s->sys_cfgdata = data; 54371538323SPeter Maydell } 54471538323SPeter Maydell } 54571538323SPeter Maydell } 546706872a5SChristoffer Dall s->sys_cfgctrl &= ~(1 << 31); 54734933c8cSPeter Maydell return; 54834933c8cSPeter Maydell case 0xa8: /* SYS_CFGSTAT */ 54934933c8cSPeter Maydell if (board_id(s) != BOARD_ID_VEXPRESS) { 55034933c8cSPeter Maydell goto bad_reg; 55134933c8cSPeter Maydell } 55234933c8cSPeter Maydell s->sys_cfgstat = val & 3; 55334933c8cSPeter Maydell return; 55434933c8cSPeter Maydell default: 55534933c8cSPeter Maydell bad_reg: 5560c896f06SPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 5570c896f06SPeter Maydell "arm_sysctl_write: Bad register offset 0x%x\n", 5580c896f06SPeter Maydell (int)offset); 559e69954b9Spbrook return; 560e69954b9Spbrook } 561e69954b9Spbrook } 562e69954b9Spbrook 563460d7c53SAvi Kivity static const MemoryRegionOps arm_sysctl_ops = { 564460d7c53SAvi Kivity .read = arm_sysctl_read, 565460d7c53SAvi Kivity .write = arm_sysctl_write, 566460d7c53SAvi Kivity .endianness = DEVICE_NATIVE_ENDIAN, 567e69954b9Spbrook }; 568e69954b9Spbrook 569b50ff6f5SPeter Maydell static void arm_sysctl_gpio_set(void *opaque, int line, int level) 570b50ff6f5SPeter Maydell { 571b50ff6f5SPeter Maydell arm_sysctl_state *s = (arm_sysctl_state *)opaque; 572b50ff6f5SPeter Maydell switch (line) { 573b50ff6f5SPeter Maydell case ARM_SYSCTL_GPIO_MMC_WPROT: 574b50ff6f5SPeter Maydell { 575b50ff6f5SPeter Maydell /* For PB926 and EB write-protect is bit 2 of SYS_MCI; 576b50ff6f5SPeter Maydell * for all later boards it is bit 1. 577b50ff6f5SPeter Maydell */ 578b50ff6f5SPeter Maydell int bit = 2; 579b50ff6f5SPeter Maydell if ((board_id(s) == BOARD_ID_PB926) || (board_id(s) == BOARD_ID_EB)) { 580b50ff6f5SPeter Maydell bit = 4; 581b50ff6f5SPeter Maydell } 582b50ff6f5SPeter Maydell s->sys_mci &= ~bit; 583b50ff6f5SPeter Maydell if (level) { 584b50ff6f5SPeter Maydell s->sys_mci |= bit; 585b50ff6f5SPeter Maydell } 586b50ff6f5SPeter Maydell break; 587b50ff6f5SPeter Maydell } 588b50ff6f5SPeter Maydell case ARM_SYSCTL_GPIO_MMC_CARDIN: 589b50ff6f5SPeter Maydell s->sys_mci &= ~1; 590b50ff6f5SPeter Maydell if (level) { 591b50ff6f5SPeter Maydell s->sys_mci |= 1; 592b50ff6f5SPeter Maydell } 593b50ff6f5SPeter Maydell break; 594b50ff6f5SPeter Maydell } 595b50ff6f5SPeter Maydell } 596b50ff6f5SPeter Maydell 5971f56f50aSPeter Maydell static void arm_sysctl_init(Object *obj) 598e69954b9Spbrook { 5991f56f50aSPeter Maydell DeviceState *dev = DEVICE(obj); 6001f56f50aSPeter Maydell SysBusDevice *sd = SYS_BUS_DEVICE(obj); 601ba4ea5bdSAndreas Färber arm_sysctl_state *s = ARM_SYSCTL(obj); 602e69954b9Spbrook 6033c161542SPaolo Bonzini memory_region_init_io(&s->iomem, OBJECT(dev), &arm_sysctl_ops, s, 6043c161542SPaolo Bonzini "arm-sysctl", 0x1000); 6051f56f50aSPeter Maydell sysbus_init_mmio(sd, &s->iomem); 6061f56f50aSPeter Maydell qdev_init_gpio_in(dev, arm_sysctl_gpio_set, 2); 6071f56f50aSPeter Maydell qdev_init_gpio_out(dev, &s->pl110_mux_ctrl, 1); 608e69954b9Spbrook } 60982634c2dSPaul Brook 6101f81f94bSPeter Maydell static void arm_sysctl_realize(DeviceState *d, Error **errp) 6111f81f94bSPeter Maydell { 612ba4ea5bdSAndreas Färber arm_sysctl_state *s = ARM_SYSCTL(d); 613ba4ea5bdSAndreas Färber 6141f81f94bSPeter Maydell s->db_clock = g_new0(uint32_t, s->db_num_clocks); 6151f81f94bSPeter Maydell } 6161f81f94bSPeter Maydell 6178bd4824aSPeter Maydell static void arm_sysctl_finalize(Object *obj) 6188bd4824aSPeter Maydell { 619ba4ea5bdSAndreas Färber arm_sysctl_state *s = ARM_SYSCTL(obj); 620ba4ea5bdSAndreas Färber 6218bd4824aSPeter Maydell g_free(s->db_voltage); 6221f81f94bSPeter Maydell g_free(s->db_clock); 6231f81f94bSPeter Maydell g_free(s->db_clock_reset); 6248bd4824aSPeter Maydell } 6258bd4824aSPeter Maydell 62630029973SRichard Henderson static const Property arm_sysctl_properties[] = { 627e325775bSGerd Hoffmann DEFINE_PROP_UINT32("sys_id", arm_sysctl_state, sys_id, 0), 62826e92f65SPaul Brook DEFINE_PROP_UINT32("proc_id", arm_sysctl_state, proc_id, 0), 6298bd4824aSPeter Maydell /* Daughterboard power supply voltages (as reported via SYS_CFG) */ 6308bd4824aSPeter Maydell DEFINE_PROP_ARRAY("db-voltage", arm_sysctl_state, db_num_vsensors, 6318bd4824aSPeter Maydell db_voltage, qdev_prop_uint32, uint32_t), 6321f81f94bSPeter Maydell /* Daughterboard clock reset values (as reported via SYS_CFG) */ 6331f81f94bSPeter Maydell DEFINE_PROP_ARRAY("db-clock", arm_sysctl_state, db_num_clocks, 6341f81f94bSPeter Maydell db_clock_reset, qdev_prop_uint32, uint32_t), 635999e12bbSAnthony Liguori }; 636999e12bbSAnthony Liguori 637999e12bbSAnthony Liguori static void arm_sysctl_class_init(ObjectClass *klass, void *data) 638999e12bbSAnthony Liguori { 63939bffca2SAnthony Liguori DeviceClass *dc = DEVICE_CLASS(klass); 640999e12bbSAnthony Liguori 6411f81f94bSPeter Maydell dc->realize = arm_sysctl_realize; 642e3d08143SPeter Maydell device_class_set_legacy_reset(dc, arm_sysctl_reset); 64339bffca2SAnthony Liguori dc->vmsd = &vmstate_arm_sysctl; 6444f67d30bSMarc-André Lureau device_class_set_props(dc, arm_sysctl_properties); 645ee6847d1SGerd Hoffmann } 646999e12bbSAnthony Liguori 6478c43a6f0SAndreas Färber static const TypeInfo arm_sysctl_info = { 648ba4ea5bdSAndreas Färber .name = TYPE_ARM_SYSCTL, 64939bffca2SAnthony Liguori .parent = TYPE_SYS_BUS_DEVICE, 65039bffca2SAnthony Liguori .instance_size = sizeof(arm_sysctl_state), 6511f56f50aSPeter Maydell .instance_init = arm_sysctl_init, 6528bd4824aSPeter Maydell .instance_finalize = arm_sysctl_finalize, 653999e12bbSAnthony Liguori .class_init = arm_sysctl_class_init, 654ee6847d1SGerd Hoffmann }; 655ee6847d1SGerd Hoffmann 65683f7d43aSAndreas Färber static void arm_sysctl_register_types(void) 65782634c2dSPaul Brook { 65839bffca2SAnthony Liguori type_register_static(&arm_sysctl_info); 65982634c2dSPaul Brook } 66082634c2dSPaul Brook 66183f7d43aSAndreas Färber type_init(arm_sysctl_register_types) 662