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" 1183c9f4caSPaolo Bonzini #include "hw/hw.h" 12*64552b6bSMarkus Armbruster #include "hw/irq.h" 131de7afc9SPaolo Bonzini #include "qemu/timer.h" 1471538323SPeter Maydell #include "qemu/bitops.h" 1583c9f4caSPaolo Bonzini #include "hw/sysbus.h" 160d09e41aSPaolo Bonzini #include "hw/arm/primecell.h" 179c17d615SPaolo Bonzini #include "sysemu/sysemu.h" 1803dd024fSPaolo Bonzini #include "qemu/log.h" 190b8fa32fSMarkus Armbruster #include "qemu/module.h" 20e69954b9Spbrook 21e69954b9Spbrook #define LOCK_VALUE 0xa05f 22e69954b9Spbrook 23ba4ea5bdSAndreas Färber #define TYPE_ARM_SYSCTL "realview_sysctl" 24ba4ea5bdSAndreas Färber #define ARM_SYSCTL(obj) \ 25ba4ea5bdSAndreas Färber OBJECT_CHECK(arm_sysctl_state, (obj), TYPE_ARM_SYSCTL) 26ba4ea5bdSAndreas Färber 27e69954b9Spbrook typedef struct { 28ba4ea5bdSAndreas Färber SysBusDevice parent_obj; 29ba4ea5bdSAndreas Färber 30460d7c53SAvi Kivity MemoryRegion iomem; 31242ea2c6SPeter Maydell qemu_irq pl110_mux_ctrl; 32242ea2c6SPeter Maydell 33e69954b9Spbrook uint32_t sys_id; 34e69954b9Spbrook uint32_t leds; 35e69954b9Spbrook uint16_t lockval; 36e69954b9Spbrook uint32_t cfgdata1; 37e69954b9Spbrook uint32_t cfgdata2; 38e69954b9Spbrook uint32_t flags; 39e69954b9Spbrook uint32_t nvflags; 40e69954b9Spbrook uint32_t resetlevel; 4126e92f65SPaul Brook uint32_t proc_id; 42b50ff6f5SPeter Maydell uint32_t sys_mci; 4334933c8cSPeter Maydell uint32_t sys_cfgdata; 4434933c8cSPeter Maydell uint32_t sys_cfgctrl; 4534933c8cSPeter Maydell uint32_t sys_cfgstat; 46242ea2c6SPeter Maydell uint32_t sys_clcd; 471f81f94bSPeter Maydell uint32_t mb_clock[6]; 481f81f94bSPeter Maydell uint32_t *db_clock; 498bd4824aSPeter Maydell uint32_t db_num_vsensors; 508bd4824aSPeter Maydell uint32_t *db_voltage; 511f81f94bSPeter Maydell uint32_t db_num_clocks; 521f81f94bSPeter Maydell uint32_t *db_clock_reset; 53e69954b9Spbrook } arm_sysctl_state; 54e69954b9Spbrook 55b5ad0ae7SPeter Maydell static const VMStateDescription vmstate_arm_sysctl = { 56b5ad0ae7SPeter Maydell .name = "realview_sysctl", 571f81f94bSPeter Maydell .version_id = 4, 58b5ad0ae7SPeter Maydell .minimum_version_id = 1, 59b5ad0ae7SPeter Maydell .fields = (VMStateField[]) { 60b5ad0ae7SPeter Maydell VMSTATE_UINT32(leds, arm_sysctl_state), 61b5ad0ae7SPeter Maydell VMSTATE_UINT16(lockval, arm_sysctl_state), 62b5ad0ae7SPeter Maydell VMSTATE_UINT32(cfgdata1, arm_sysctl_state), 63b5ad0ae7SPeter Maydell VMSTATE_UINT32(cfgdata2, arm_sysctl_state), 64b5ad0ae7SPeter Maydell VMSTATE_UINT32(flags, arm_sysctl_state), 65b5ad0ae7SPeter Maydell VMSTATE_UINT32(nvflags, arm_sysctl_state), 66b5ad0ae7SPeter Maydell VMSTATE_UINT32(resetlevel, arm_sysctl_state), 6734933c8cSPeter Maydell VMSTATE_UINT32_V(sys_mci, arm_sysctl_state, 2), 6834933c8cSPeter Maydell VMSTATE_UINT32_V(sys_cfgdata, arm_sysctl_state, 2), 6934933c8cSPeter Maydell VMSTATE_UINT32_V(sys_cfgctrl, arm_sysctl_state, 2), 7034933c8cSPeter Maydell VMSTATE_UINT32_V(sys_cfgstat, arm_sysctl_state, 2), 71242ea2c6SPeter Maydell VMSTATE_UINT32_V(sys_clcd, arm_sysctl_state, 3), 721f81f94bSPeter Maydell VMSTATE_UINT32_ARRAY_V(mb_clock, arm_sysctl_state, 6, 4), 731f81f94bSPeter Maydell VMSTATE_VARRAY_UINT32(db_clock, arm_sysctl_state, db_num_clocks, 741f81f94bSPeter Maydell 4, vmstate_info_uint32, uint32_t), 75b5ad0ae7SPeter Maydell VMSTATE_END_OF_LIST() 76b5ad0ae7SPeter Maydell } 77b5ad0ae7SPeter Maydell }; 78b5ad0ae7SPeter Maydell 79b50ff6f5SPeter Maydell /* The PB926 actually uses a different format for 80b50ff6f5SPeter Maydell * its SYS_ID register. Fortunately the bits which are 81b50ff6f5SPeter Maydell * board type on later boards are distinct. 82b50ff6f5SPeter Maydell */ 83b50ff6f5SPeter Maydell #define BOARD_ID_PB926 0x100 84b50ff6f5SPeter Maydell #define BOARD_ID_EB 0x140 85b50ff6f5SPeter Maydell #define BOARD_ID_PBA8 0x178 86b50ff6f5SPeter Maydell #define BOARD_ID_PBX 0x182 8734933c8cSPeter Maydell #define BOARD_ID_VEXPRESS 0x190 88b50ff6f5SPeter Maydell 89b50ff6f5SPeter Maydell static int board_id(arm_sysctl_state *s) 90b50ff6f5SPeter Maydell { 91b50ff6f5SPeter Maydell /* Extract the board ID field from the SYS_ID register value */ 92b50ff6f5SPeter Maydell return (s->sys_id >> 16) & 0xfff; 93b50ff6f5SPeter Maydell } 94b50ff6f5SPeter Maydell 95be0f204aSPaul Brook static void arm_sysctl_reset(DeviceState *d) 96be0f204aSPaul Brook { 97ba4ea5bdSAndreas Färber arm_sysctl_state *s = ARM_SYSCTL(d); 981f81f94bSPeter Maydell int i; 99be0f204aSPaul Brook 100be0f204aSPaul Brook s->leds = 0; 101be0f204aSPaul Brook s->lockval = 0; 102be0f204aSPaul Brook s->cfgdata1 = 0; 103be0f204aSPaul Brook s->cfgdata2 = 0; 104be0f204aSPaul Brook s->flags = 0; 105be0f204aSPaul Brook s->resetlevel = 0; 1061f81f94bSPeter Maydell /* Motherboard oscillators (in Hz) */ 1071f81f94bSPeter Maydell s->mb_clock[0] = 50000000; /* Static memory clock: 50MHz */ 1081f81f94bSPeter Maydell s->mb_clock[1] = 23750000; /* motherboard CLCD clock: 23.75MHz */ 1091f81f94bSPeter Maydell s->mb_clock[2] = 24000000; /* IO FPGA peripheral clock: 24MHz */ 1101f81f94bSPeter Maydell s->mb_clock[3] = 24000000; /* IO FPGA reserved clock: 24MHz */ 1111f81f94bSPeter Maydell s->mb_clock[4] = 24000000; /* System bus global clock: 24MHz */ 1121f81f94bSPeter Maydell s->mb_clock[5] = 24000000; /* IO FPGA reserved clock: 24MHz */ 1131f81f94bSPeter Maydell /* Daughterboard oscillators: reset from property values */ 1141f81f94bSPeter Maydell for (i = 0; i < s->db_num_clocks; i++) { 1151f81f94bSPeter Maydell s->db_clock[i] = s->db_clock_reset[i]; 1161f81f94bSPeter Maydell } 117242ea2c6SPeter Maydell if (board_id(s) == BOARD_ID_VEXPRESS) { 118242ea2c6SPeter Maydell /* On VExpress this register will RAZ/WI */ 119242ea2c6SPeter Maydell s->sys_clcd = 0; 120242ea2c6SPeter Maydell } else { 121242ea2c6SPeter Maydell /* All others: CLCDID 0x1f, indicating VGA */ 122242ea2c6SPeter Maydell s->sys_clcd = 0x1f00; 123242ea2c6SPeter Maydell } 124be0f204aSPaul Brook } 125be0f204aSPaul Brook 126a8170e5eSAvi Kivity static uint64_t arm_sysctl_read(void *opaque, hwaddr offset, 127460d7c53SAvi Kivity unsigned size) 128e69954b9Spbrook { 129e69954b9Spbrook arm_sysctl_state *s = (arm_sysctl_state *)opaque; 130e69954b9Spbrook 131e69954b9Spbrook switch (offset) { 132e69954b9Spbrook case 0x00: /* ID */ 133e69954b9Spbrook return s->sys_id; 134e69954b9Spbrook case 0x04: /* SW */ 135e69954b9Spbrook /* General purpose hardware switches. 136e69954b9Spbrook We don't have a useful way of exposing these to the user. */ 137e69954b9Spbrook return 0; 138e69954b9Spbrook case 0x08: /* LED */ 139e69954b9Spbrook return s->leds; 140e69954b9Spbrook case 0x20: /* LOCK */ 141e69954b9Spbrook return s->lockval; 142e69954b9Spbrook case 0x0c: /* OSC0 */ 143e69954b9Spbrook case 0x10: /* OSC1 */ 144e69954b9Spbrook case 0x14: /* OSC2 */ 145e69954b9Spbrook case 0x18: /* OSC3 */ 146e69954b9Spbrook case 0x1c: /* OSC4 */ 147e69954b9Spbrook case 0x24: /* 100HZ */ 148e69954b9Spbrook /* ??? Implement these. */ 149e69954b9Spbrook return 0; 150e69954b9Spbrook case 0x28: /* CFGDATA1 */ 151e69954b9Spbrook return s->cfgdata1; 152e69954b9Spbrook case 0x2c: /* CFGDATA2 */ 153e69954b9Spbrook return s->cfgdata2; 154e69954b9Spbrook case 0x30: /* FLAGS */ 155e69954b9Spbrook return s->flags; 156e69954b9Spbrook case 0x38: /* NVFLAGS */ 157e69954b9Spbrook return s->nvflags; 158e69954b9Spbrook case 0x40: /* RESETCTL */ 15934933c8cSPeter Maydell if (board_id(s) == BOARD_ID_VEXPRESS) { 16034933c8cSPeter Maydell /* reserved: RAZ/WI */ 16134933c8cSPeter Maydell return 0; 16234933c8cSPeter Maydell } 163e69954b9Spbrook return s->resetlevel; 164e69954b9Spbrook case 0x44: /* PCICTL */ 165e69954b9Spbrook return 1; 166e69954b9Spbrook case 0x48: /* MCI */ 167b50ff6f5SPeter Maydell return s->sys_mci; 168e69954b9Spbrook case 0x4c: /* FLASH */ 169e69954b9Spbrook return 0; 170e69954b9Spbrook case 0x50: /* CLCD */ 171242ea2c6SPeter Maydell return s->sys_clcd; 172e69954b9Spbrook case 0x54: /* CLCDSER */ 173e69954b9Spbrook return 0; 174e69954b9Spbrook case 0x58: /* BOOTCS */ 175e69954b9Spbrook return 0; 176e69954b9Spbrook case 0x5c: /* 24MHz */ 17773bcb24dSRutuja Shah return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24000000, 17873bcb24dSRutuja Shah NANOSECONDS_PER_SECOND); 179e69954b9Spbrook case 0x60: /* MISC */ 180e69954b9Spbrook return 0; 181e69954b9Spbrook case 0x84: /* PROCID0 */ 18226e92f65SPaul Brook return s->proc_id; 183e69954b9Spbrook case 0x88: /* PROCID1 */ 184e69954b9Spbrook return 0xff000000; 185e69954b9Spbrook case 0x64: /* DMAPSR0 */ 186e69954b9Spbrook case 0x68: /* DMAPSR1 */ 187e69954b9Spbrook case 0x6c: /* DMAPSR2 */ 188e69954b9Spbrook case 0x70: /* IOSEL */ 189e69954b9Spbrook case 0x74: /* PLDCTL */ 190e69954b9Spbrook case 0x80: /* BUSID */ 191e69954b9Spbrook case 0x8c: /* OSCRESET0 */ 192e69954b9Spbrook case 0x90: /* OSCRESET1 */ 193e69954b9Spbrook case 0x94: /* OSCRESET2 */ 194e69954b9Spbrook case 0x98: /* OSCRESET3 */ 195e69954b9Spbrook case 0x9c: /* OSCRESET4 */ 196e69954b9Spbrook case 0xc0: /* SYS_TEST_OSC0 */ 197e69954b9Spbrook case 0xc4: /* SYS_TEST_OSC1 */ 198e69954b9Spbrook case 0xc8: /* SYS_TEST_OSC2 */ 199e69954b9Spbrook case 0xcc: /* SYS_TEST_OSC3 */ 200e69954b9Spbrook case 0xd0: /* SYS_TEST_OSC4 */ 201e69954b9Spbrook return 0; 20234933c8cSPeter Maydell case 0xa0: /* SYS_CFGDATA */ 20334933c8cSPeter Maydell if (board_id(s) != BOARD_ID_VEXPRESS) { 20434933c8cSPeter Maydell goto bad_reg; 20534933c8cSPeter Maydell } 20634933c8cSPeter Maydell return s->sys_cfgdata; 20734933c8cSPeter Maydell case 0xa4: /* SYS_CFGCTRL */ 20834933c8cSPeter Maydell if (board_id(s) != BOARD_ID_VEXPRESS) { 20934933c8cSPeter Maydell goto bad_reg; 21034933c8cSPeter Maydell } 21134933c8cSPeter Maydell return s->sys_cfgctrl; 21234933c8cSPeter Maydell case 0xa8: /* SYS_CFGSTAT */ 21334933c8cSPeter Maydell if (board_id(s) != BOARD_ID_VEXPRESS) { 21434933c8cSPeter Maydell goto bad_reg; 21534933c8cSPeter Maydell } 21634933c8cSPeter Maydell return s->sys_cfgstat; 217e69954b9Spbrook default: 21834933c8cSPeter Maydell bad_reg: 2190c896f06SPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 2200c896f06SPeter Maydell "arm_sysctl_read: Bad register offset 0x%x\n", 2210c896f06SPeter Maydell (int)offset); 222e69954b9Spbrook return 0; 223e69954b9Spbrook } 224e69954b9Spbrook } 225e69954b9Spbrook 22671538323SPeter Maydell /* SYS_CFGCTRL functions */ 22771538323SPeter Maydell #define SYS_CFG_OSC 1 22871538323SPeter Maydell #define SYS_CFG_VOLT 2 22971538323SPeter Maydell #define SYS_CFG_AMP 3 23071538323SPeter Maydell #define SYS_CFG_TEMP 4 23171538323SPeter Maydell #define SYS_CFG_RESET 5 23271538323SPeter Maydell #define SYS_CFG_SCC 6 23371538323SPeter Maydell #define SYS_CFG_MUXFPGA 7 23471538323SPeter Maydell #define SYS_CFG_SHUTDOWN 8 23571538323SPeter Maydell #define SYS_CFG_REBOOT 9 23671538323SPeter Maydell #define SYS_CFG_DVIMODE 11 23771538323SPeter Maydell #define SYS_CFG_POWER 12 23871538323SPeter Maydell #define SYS_CFG_ENERGY 13 23971538323SPeter Maydell 24071538323SPeter Maydell /* SYS_CFGCTRL site field values */ 24171538323SPeter Maydell #define SYS_CFG_SITE_MB 0 24271538323SPeter Maydell #define SYS_CFG_SITE_DB1 1 24371538323SPeter Maydell #define SYS_CFG_SITE_DB2 2 24471538323SPeter Maydell 24571538323SPeter Maydell /** 24671538323SPeter Maydell * vexpress_cfgctrl_read: 24771538323SPeter Maydell * @s: arm_sysctl_state pointer 24871538323SPeter Maydell * @dcc, @function, @site, @position, @device: split out values from 24971538323SPeter Maydell * SYS_CFGCTRL register 25071538323SPeter Maydell * @val: pointer to where to put the read data on success 25171538323SPeter Maydell * 25271538323SPeter Maydell * Handle a VExpress SYS_CFGCTRL register read. On success, return true and 25371538323SPeter Maydell * write the read value to *val. On failure, return false (and val may 25471538323SPeter Maydell * or may not be written to). 25571538323SPeter Maydell */ 25671538323SPeter Maydell static bool vexpress_cfgctrl_read(arm_sysctl_state *s, unsigned int dcc, 25771538323SPeter Maydell unsigned int function, unsigned int site, 25871538323SPeter Maydell unsigned int position, unsigned int device, 25971538323SPeter Maydell uint32_t *val) 26071538323SPeter Maydell { 26171538323SPeter Maydell /* We don't support anything other than DCC 0, board stack position 0 26271538323SPeter Maydell * or sites other than motherboard/daughterboard: 26371538323SPeter Maydell */ 26471538323SPeter Maydell if (dcc != 0 || position != 0 || 26571538323SPeter Maydell (site != SYS_CFG_SITE_MB && site != SYS_CFG_SITE_DB1)) { 26671538323SPeter Maydell goto cfgctrl_unimp; 26771538323SPeter Maydell } 26871538323SPeter Maydell 26971538323SPeter Maydell switch (function) { 2708bd4824aSPeter Maydell case SYS_CFG_VOLT: 2718bd4824aSPeter Maydell if (site == SYS_CFG_SITE_DB1 && device < s->db_num_vsensors) { 2728bd4824aSPeter Maydell *val = s->db_voltage[device]; 2738bd4824aSPeter Maydell return true; 2748bd4824aSPeter Maydell } 2758bd4824aSPeter Maydell if (site == SYS_CFG_SITE_MB && device == 0) { 2768bd4824aSPeter Maydell /* There is only one motherboard voltage sensor: 2778bd4824aSPeter Maydell * VIO : 3.3V : bus voltage between mother and daughterboard 2788bd4824aSPeter Maydell */ 2798bd4824aSPeter Maydell *val = 3300000; 2808bd4824aSPeter Maydell return true; 2818bd4824aSPeter Maydell } 2828bd4824aSPeter Maydell break; 2831f81f94bSPeter Maydell case SYS_CFG_OSC: 284ec1efab9SPeter Maydell if (site == SYS_CFG_SITE_MB && device < ARRAY_SIZE(s->mb_clock)) { 2851f81f94bSPeter Maydell /* motherboard clock */ 2861f81f94bSPeter Maydell *val = s->mb_clock[device]; 2871f81f94bSPeter Maydell return true; 2881f81f94bSPeter Maydell } 2891f81f94bSPeter Maydell if (site == SYS_CFG_SITE_DB1 && device < s->db_num_clocks) { 2901f81f94bSPeter Maydell /* daughterboard clock */ 2911f81f94bSPeter Maydell *val = s->db_clock[device]; 2921f81f94bSPeter Maydell return true; 2931f81f94bSPeter Maydell } 2941f81f94bSPeter Maydell break; 29571538323SPeter Maydell default: 29671538323SPeter Maydell break; 29771538323SPeter Maydell } 29871538323SPeter Maydell 29971538323SPeter Maydell cfgctrl_unimp: 30071538323SPeter Maydell qemu_log_mask(LOG_UNIMP, 30171538323SPeter Maydell "arm_sysctl: Unimplemented SYS_CFGCTRL read of function " 30271538323SPeter Maydell "0x%x DCC 0x%x site 0x%x position 0x%x device 0x%x\n", 30371538323SPeter Maydell function, dcc, site, position, device); 30471538323SPeter Maydell return false; 30571538323SPeter Maydell } 30671538323SPeter Maydell 30771538323SPeter Maydell /** 30871538323SPeter Maydell * vexpress_cfgctrl_write: 30971538323SPeter Maydell * @s: arm_sysctl_state pointer 31071538323SPeter Maydell * @dcc, @function, @site, @position, @device: split out values from 31171538323SPeter Maydell * SYS_CFGCTRL register 31271538323SPeter Maydell * @val: data to write 31371538323SPeter Maydell * 31471538323SPeter Maydell * Handle a VExpress SYS_CFGCTRL register write. On success, return true. 31571538323SPeter Maydell * On failure, return false. 31671538323SPeter Maydell */ 31771538323SPeter Maydell static bool vexpress_cfgctrl_write(arm_sysctl_state *s, unsigned int dcc, 31871538323SPeter Maydell unsigned int function, unsigned int site, 31971538323SPeter Maydell unsigned int position, unsigned int device, 32071538323SPeter Maydell uint32_t val) 32171538323SPeter Maydell { 32271538323SPeter Maydell /* We don't support anything other than DCC 0, board stack position 0 32371538323SPeter Maydell * or sites other than motherboard/daughterboard: 32471538323SPeter Maydell */ 32571538323SPeter Maydell if (dcc != 0 || position != 0 || 32671538323SPeter Maydell (site != SYS_CFG_SITE_MB && site != SYS_CFG_SITE_DB1)) { 32771538323SPeter Maydell goto cfgctrl_unimp; 32871538323SPeter Maydell } 32971538323SPeter Maydell 33071538323SPeter Maydell switch (function) { 3311f81f94bSPeter Maydell case SYS_CFG_OSC: 332ec1efab9SPeter Maydell if (site == SYS_CFG_SITE_MB && device < ARRAY_SIZE(s->mb_clock)) { 3331f81f94bSPeter Maydell /* motherboard clock */ 3341f81f94bSPeter Maydell s->mb_clock[device] = val; 3351f81f94bSPeter Maydell return true; 3361f81f94bSPeter Maydell } 3371f81f94bSPeter Maydell if (site == SYS_CFG_SITE_DB1 && device < s->db_num_clocks) { 3381f81f94bSPeter Maydell /* daughterboard clock */ 3391f81f94bSPeter Maydell s->db_clock[device] = val; 3401f81f94bSPeter Maydell return true; 3411f81f94bSPeter Maydell } 3421f81f94bSPeter Maydell break; 3438ff05c98SPeter Maydell case SYS_CFG_MUXFPGA: 3448ff05c98SPeter Maydell if (site == SYS_CFG_SITE_MB && device == 0) { 3458ff05c98SPeter Maydell /* Select whether video output comes from motherboard 3468ff05c98SPeter Maydell * or daughterboard: log and ignore as QEMU doesn't 3478ff05c98SPeter Maydell * support this. 3488ff05c98SPeter Maydell */ 3498ff05c98SPeter Maydell qemu_log_mask(LOG_UNIMP, "arm_sysctl: selection of video output " 3508ff05c98SPeter Maydell "not supported, ignoring\n"); 3518ff05c98SPeter Maydell return true; 3528ff05c98SPeter Maydell } 3538ff05c98SPeter Maydell break; 35471538323SPeter Maydell case SYS_CFG_SHUTDOWN: 35571538323SPeter Maydell if (site == SYS_CFG_SITE_MB && device == 0) { 356cf83f140SEric Blake qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); 35771538323SPeter Maydell return true; 35871538323SPeter Maydell } 35971538323SPeter Maydell break; 36071538323SPeter Maydell case SYS_CFG_REBOOT: 36171538323SPeter Maydell if (site == SYS_CFG_SITE_MB && device == 0) { 362cf83f140SEric Blake qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); 36371538323SPeter Maydell return true; 36471538323SPeter Maydell } 36571538323SPeter Maydell break; 366291155cbSPeter Maydell case SYS_CFG_DVIMODE: 367291155cbSPeter Maydell if (site == SYS_CFG_SITE_MB && device == 0) { 368291155cbSPeter Maydell /* Selecting DVI mode is meaningless for QEMU: we will 369291155cbSPeter Maydell * always display the output correctly according to the 370291155cbSPeter Maydell * pixel height/width programmed into the CLCD controller. 371291155cbSPeter Maydell */ 372291155cbSPeter Maydell return true; 373291155cbSPeter Maydell } 37471538323SPeter Maydell default: 37571538323SPeter Maydell break; 37671538323SPeter Maydell } 37771538323SPeter Maydell 37871538323SPeter Maydell cfgctrl_unimp: 37971538323SPeter Maydell qemu_log_mask(LOG_UNIMP, 38071538323SPeter Maydell "arm_sysctl: Unimplemented SYS_CFGCTRL write of function " 38171538323SPeter Maydell "0x%x DCC 0x%x site 0x%x position 0x%x device 0x%x\n", 38271538323SPeter Maydell function, dcc, site, position, device); 38371538323SPeter Maydell return false; 38471538323SPeter Maydell } 38571538323SPeter Maydell 386a8170e5eSAvi Kivity static void arm_sysctl_write(void *opaque, hwaddr offset, 387460d7c53SAvi Kivity uint64_t val, unsigned size) 388e69954b9Spbrook { 389e69954b9Spbrook arm_sysctl_state *s = (arm_sysctl_state *)opaque; 390e69954b9Spbrook 391e69954b9Spbrook switch (offset) { 392e69954b9Spbrook case 0x08: /* LED */ 393e69954b9Spbrook s->leds = val; 394bf4229d3SPeter Maydell break; 395e69954b9Spbrook case 0x0c: /* OSC0 */ 396e69954b9Spbrook case 0x10: /* OSC1 */ 397e69954b9Spbrook case 0x14: /* OSC2 */ 398e69954b9Spbrook case 0x18: /* OSC3 */ 399e69954b9Spbrook case 0x1c: /* OSC4 */ 400e69954b9Spbrook /* ??? */ 401e69954b9Spbrook break; 402e69954b9Spbrook case 0x20: /* LOCK */ 403e69954b9Spbrook if (val == LOCK_VALUE) 404e69954b9Spbrook s->lockval = val; 405e69954b9Spbrook else 406e69954b9Spbrook s->lockval = val & 0x7fff; 407e69954b9Spbrook break; 408e69954b9Spbrook case 0x28: /* CFGDATA1 */ 409e69954b9Spbrook /* ??? Need to implement this. */ 410e69954b9Spbrook s->cfgdata1 = val; 411e69954b9Spbrook break; 412e69954b9Spbrook case 0x2c: /* CFGDATA2 */ 413e69954b9Spbrook /* ??? Need to implement this. */ 414e69954b9Spbrook s->cfgdata2 = val; 415e69954b9Spbrook break; 416e69954b9Spbrook case 0x30: /* FLAGSSET */ 417e69954b9Spbrook s->flags |= val; 418e69954b9Spbrook break; 419e69954b9Spbrook case 0x34: /* FLAGSCLR */ 420e69954b9Spbrook s->flags &= ~val; 421e69954b9Spbrook break; 422e69954b9Spbrook case 0x38: /* NVFLAGSSET */ 423e69954b9Spbrook s->nvflags |= val; 424e69954b9Spbrook break; 425e69954b9Spbrook case 0x3c: /* NVFLAGSCLR */ 426e69954b9Spbrook s->nvflags &= ~val; 427e69954b9Spbrook break; 428e69954b9Spbrook case 0x40: /* RESETCTL */ 429b2887c43SJean-Christophe DUBOIS switch (board_id(s)) { 430b2887c43SJean-Christophe DUBOIS case BOARD_ID_PB926: 431e69954b9Spbrook if (s->lockval == LOCK_VALUE) { 432e69954b9Spbrook s->resetlevel = val; 433b2887c43SJean-Christophe DUBOIS if (val & 0x100) { 434cf83f140SEric Blake qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); 435e69954b9Spbrook } 436b2887c43SJean-Christophe DUBOIS } 437b2887c43SJean-Christophe DUBOIS break; 438b2887c43SJean-Christophe DUBOIS case BOARD_ID_PBX: 439b2887c43SJean-Christophe DUBOIS case BOARD_ID_PBA8: 440b2887c43SJean-Christophe DUBOIS if (s->lockval == LOCK_VALUE) { 441b2887c43SJean-Christophe DUBOIS s->resetlevel = val; 442b2887c43SJean-Christophe DUBOIS if (val & 0x04) { 443cf83f140SEric Blake qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); 444b2887c43SJean-Christophe DUBOIS } 445b2887c43SJean-Christophe DUBOIS } 446b2887c43SJean-Christophe DUBOIS break; 447b2887c43SJean-Christophe DUBOIS case BOARD_ID_VEXPRESS: 448b2887c43SJean-Christophe DUBOIS case BOARD_ID_EB: 449b2887c43SJean-Christophe DUBOIS default: 450b2887c43SJean-Christophe DUBOIS /* reserved: RAZ/WI */ 451b2887c43SJean-Christophe DUBOIS break; 452b2887c43SJean-Christophe DUBOIS } 453e69954b9Spbrook break; 454e69954b9Spbrook case 0x44: /* PCICTL */ 455e69954b9Spbrook /* nothing to do. */ 456e69954b9Spbrook break; 457e69954b9Spbrook case 0x4c: /* FLASH */ 458242ea2c6SPeter Maydell break; 459e69954b9Spbrook case 0x50: /* CLCD */ 460242ea2c6SPeter Maydell switch (board_id(s)) { 461242ea2c6SPeter Maydell case BOARD_ID_PB926: 462242ea2c6SPeter Maydell /* On 926 bits 13:8 are R/O, bits 1:0 control 463242ea2c6SPeter Maydell * the mux that defines how to interpret the PL110 464242ea2c6SPeter Maydell * graphics format, and other bits are r/w but we 465242ea2c6SPeter Maydell * don't implement them to do anything. 466242ea2c6SPeter Maydell */ 467242ea2c6SPeter Maydell s->sys_clcd &= 0x3f00; 468242ea2c6SPeter Maydell s->sys_clcd |= val & ~0x3f00; 469242ea2c6SPeter Maydell qemu_set_irq(s->pl110_mux_ctrl, val & 3); 470242ea2c6SPeter Maydell break; 471242ea2c6SPeter Maydell case BOARD_ID_EB: 472242ea2c6SPeter Maydell /* The EB is the same except that there is no mux since 473242ea2c6SPeter Maydell * the EB has a PL111. 474242ea2c6SPeter Maydell */ 475242ea2c6SPeter Maydell s->sys_clcd &= 0x3f00; 476242ea2c6SPeter Maydell s->sys_clcd |= val & ~0x3f00; 477242ea2c6SPeter Maydell break; 478242ea2c6SPeter Maydell case BOARD_ID_PBA8: 479242ea2c6SPeter Maydell case BOARD_ID_PBX: 480242ea2c6SPeter Maydell /* On PBA8 and PBX bit 7 is r/w and all other bits 481242ea2c6SPeter Maydell * are either r/o or RAZ/WI. 482242ea2c6SPeter Maydell */ 483242ea2c6SPeter Maydell s->sys_clcd &= (1 << 7); 484242ea2c6SPeter Maydell s->sys_clcd |= val & ~(1 << 7); 485242ea2c6SPeter Maydell break; 486242ea2c6SPeter Maydell case BOARD_ID_VEXPRESS: 487242ea2c6SPeter Maydell default: 488242ea2c6SPeter Maydell /* On VExpress this register is unimplemented and will RAZ/WI */ 489242ea2c6SPeter Maydell break; 490242ea2c6SPeter Maydell } 491bf4229d3SPeter Maydell break; 492e69954b9Spbrook case 0x54: /* CLCDSER */ 493e69954b9Spbrook case 0x64: /* DMAPSR0 */ 494e69954b9Spbrook case 0x68: /* DMAPSR1 */ 495e69954b9Spbrook case 0x6c: /* DMAPSR2 */ 496e69954b9Spbrook case 0x70: /* IOSEL */ 497e69954b9Spbrook case 0x74: /* PLDCTL */ 498e69954b9Spbrook case 0x80: /* BUSID */ 499e69954b9Spbrook case 0x84: /* PROCID0 */ 500e69954b9Spbrook case 0x88: /* PROCID1 */ 501e69954b9Spbrook case 0x8c: /* OSCRESET0 */ 502e69954b9Spbrook case 0x90: /* OSCRESET1 */ 503e69954b9Spbrook case 0x94: /* OSCRESET2 */ 504e69954b9Spbrook case 0x98: /* OSCRESET3 */ 505e69954b9Spbrook case 0x9c: /* OSCRESET4 */ 506e69954b9Spbrook break; 50734933c8cSPeter Maydell case 0xa0: /* SYS_CFGDATA */ 50834933c8cSPeter Maydell if (board_id(s) != BOARD_ID_VEXPRESS) { 50934933c8cSPeter Maydell goto bad_reg; 51034933c8cSPeter Maydell } 51134933c8cSPeter Maydell s->sys_cfgdata = val; 51234933c8cSPeter Maydell return; 51334933c8cSPeter Maydell case 0xa4: /* SYS_CFGCTRL */ 51434933c8cSPeter Maydell if (board_id(s) != BOARD_ID_VEXPRESS) { 51534933c8cSPeter Maydell goto bad_reg; 51634933c8cSPeter Maydell } 51771538323SPeter Maydell /* Undefined bits [19:18] are RAZ/WI, and writing to 51871538323SPeter Maydell * the start bit just triggers the action; it always reads 51971538323SPeter Maydell * as zero. 52071538323SPeter Maydell */ 52171538323SPeter Maydell s->sys_cfgctrl = val & ~((3 << 18) | (1 << 31)); 52271538323SPeter Maydell if (val & (1 << 31)) { 52371538323SPeter Maydell /* Start bit set -- actually do something */ 52471538323SPeter Maydell unsigned int dcc = extract32(s->sys_cfgctrl, 26, 4); 52571538323SPeter Maydell unsigned int function = extract32(s->sys_cfgctrl, 20, 6); 52671538323SPeter Maydell unsigned int site = extract32(s->sys_cfgctrl, 16, 2); 52771538323SPeter Maydell unsigned int position = extract32(s->sys_cfgctrl, 12, 4); 52871538323SPeter Maydell unsigned int device = extract32(s->sys_cfgctrl, 0, 12); 52934933c8cSPeter Maydell s->sys_cfgstat = 1; /* complete */ 53071538323SPeter Maydell if (s->sys_cfgctrl & (1 << 30)) { 53171538323SPeter Maydell if (!vexpress_cfgctrl_write(s, dcc, function, site, position, 53271538323SPeter Maydell device, s->sys_cfgdata)) { 53334933c8cSPeter Maydell s->sys_cfgstat |= 2; /* error */ 53434933c8cSPeter Maydell } 53571538323SPeter Maydell } else { 53671538323SPeter Maydell uint32_t val; 53771538323SPeter Maydell if (!vexpress_cfgctrl_read(s, dcc, function, site, position, 53871538323SPeter Maydell device, &val)) { 53971538323SPeter Maydell s->sys_cfgstat |= 2; /* error */ 54071538323SPeter Maydell } else { 54171538323SPeter Maydell s->sys_cfgdata = val; 54271538323SPeter Maydell } 54371538323SPeter Maydell } 54471538323SPeter Maydell } 545706872a5SChristoffer Dall s->sys_cfgctrl &= ~(1 << 31); 54634933c8cSPeter Maydell return; 54734933c8cSPeter Maydell case 0xa8: /* SYS_CFGSTAT */ 54834933c8cSPeter Maydell if (board_id(s) != BOARD_ID_VEXPRESS) { 54934933c8cSPeter Maydell goto bad_reg; 55034933c8cSPeter Maydell } 55134933c8cSPeter Maydell s->sys_cfgstat = val & 3; 55234933c8cSPeter Maydell return; 55334933c8cSPeter Maydell default: 55434933c8cSPeter Maydell bad_reg: 5550c896f06SPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 5560c896f06SPeter Maydell "arm_sysctl_write: Bad register offset 0x%x\n", 5570c896f06SPeter Maydell (int)offset); 558e69954b9Spbrook return; 559e69954b9Spbrook } 560e69954b9Spbrook } 561e69954b9Spbrook 562460d7c53SAvi Kivity static const MemoryRegionOps arm_sysctl_ops = { 563460d7c53SAvi Kivity .read = arm_sysctl_read, 564460d7c53SAvi Kivity .write = arm_sysctl_write, 565460d7c53SAvi Kivity .endianness = DEVICE_NATIVE_ENDIAN, 566e69954b9Spbrook }; 567e69954b9Spbrook 568b50ff6f5SPeter Maydell static void arm_sysctl_gpio_set(void *opaque, int line, int level) 569b50ff6f5SPeter Maydell { 570b50ff6f5SPeter Maydell arm_sysctl_state *s = (arm_sysctl_state *)opaque; 571b50ff6f5SPeter Maydell switch (line) { 572b50ff6f5SPeter Maydell case ARM_SYSCTL_GPIO_MMC_WPROT: 573b50ff6f5SPeter Maydell { 574b50ff6f5SPeter Maydell /* For PB926 and EB write-protect is bit 2 of SYS_MCI; 575b50ff6f5SPeter Maydell * for all later boards it is bit 1. 576b50ff6f5SPeter Maydell */ 577b50ff6f5SPeter Maydell int bit = 2; 578b50ff6f5SPeter Maydell if ((board_id(s) == BOARD_ID_PB926) || (board_id(s) == BOARD_ID_EB)) { 579b50ff6f5SPeter Maydell bit = 4; 580b50ff6f5SPeter Maydell } 581b50ff6f5SPeter Maydell s->sys_mci &= ~bit; 582b50ff6f5SPeter Maydell if (level) { 583b50ff6f5SPeter Maydell s->sys_mci |= bit; 584b50ff6f5SPeter Maydell } 585b50ff6f5SPeter Maydell break; 586b50ff6f5SPeter Maydell } 587b50ff6f5SPeter Maydell case ARM_SYSCTL_GPIO_MMC_CARDIN: 588b50ff6f5SPeter Maydell s->sys_mci &= ~1; 589b50ff6f5SPeter Maydell if (level) { 590b50ff6f5SPeter Maydell s->sys_mci |= 1; 591b50ff6f5SPeter Maydell } 592b50ff6f5SPeter Maydell break; 593b50ff6f5SPeter Maydell } 594b50ff6f5SPeter Maydell } 595b50ff6f5SPeter Maydell 5961f56f50aSPeter Maydell static void arm_sysctl_init(Object *obj) 597e69954b9Spbrook { 5981f56f50aSPeter Maydell DeviceState *dev = DEVICE(obj); 5991f56f50aSPeter Maydell SysBusDevice *sd = SYS_BUS_DEVICE(obj); 600ba4ea5bdSAndreas Färber arm_sysctl_state *s = ARM_SYSCTL(obj); 601e69954b9Spbrook 6023c161542SPaolo Bonzini memory_region_init_io(&s->iomem, OBJECT(dev), &arm_sysctl_ops, s, 6033c161542SPaolo Bonzini "arm-sysctl", 0x1000); 6041f56f50aSPeter Maydell sysbus_init_mmio(sd, &s->iomem); 6051f56f50aSPeter Maydell qdev_init_gpio_in(dev, arm_sysctl_gpio_set, 2); 6061f56f50aSPeter Maydell qdev_init_gpio_out(dev, &s->pl110_mux_ctrl, 1); 607e69954b9Spbrook } 60882634c2dSPaul Brook 6091f81f94bSPeter Maydell static void arm_sysctl_realize(DeviceState *d, Error **errp) 6101f81f94bSPeter Maydell { 611ba4ea5bdSAndreas Färber arm_sysctl_state *s = ARM_SYSCTL(d); 612ba4ea5bdSAndreas Färber 6131f81f94bSPeter Maydell s->db_clock = g_new0(uint32_t, s->db_num_clocks); 6141f81f94bSPeter Maydell } 6151f81f94bSPeter Maydell 6168bd4824aSPeter Maydell static void arm_sysctl_finalize(Object *obj) 6178bd4824aSPeter Maydell { 618ba4ea5bdSAndreas Färber arm_sysctl_state *s = ARM_SYSCTL(obj); 619ba4ea5bdSAndreas Färber 6208bd4824aSPeter Maydell g_free(s->db_voltage); 6211f81f94bSPeter Maydell g_free(s->db_clock); 6221f81f94bSPeter Maydell g_free(s->db_clock_reset); 6238bd4824aSPeter Maydell } 6248bd4824aSPeter Maydell 625999e12bbSAnthony Liguori static Property arm_sysctl_properties[] = { 626e325775bSGerd Hoffmann DEFINE_PROP_UINT32("sys_id", arm_sysctl_state, sys_id, 0), 62726e92f65SPaul Brook DEFINE_PROP_UINT32("proc_id", arm_sysctl_state, proc_id, 0), 6288bd4824aSPeter Maydell /* Daughterboard power supply voltages (as reported via SYS_CFG) */ 6298bd4824aSPeter Maydell DEFINE_PROP_ARRAY("db-voltage", arm_sysctl_state, db_num_vsensors, 6308bd4824aSPeter Maydell db_voltage, qdev_prop_uint32, uint32_t), 6311f81f94bSPeter Maydell /* Daughterboard clock reset values (as reported via SYS_CFG) */ 6321f81f94bSPeter Maydell DEFINE_PROP_ARRAY("db-clock", arm_sysctl_state, db_num_clocks, 6331f81f94bSPeter Maydell db_clock_reset, qdev_prop_uint32, uint32_t), 634e325775bSGerd Hoffmann DEFINE_PROP_END_OF_LIST(), 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; 64239bffca2SAnthony Liguori dc->reset = arm_sysctl_reset; 64339bffca2SAnthony Liguori dc->vmsd = &vmstate_arm_sysctl; 64439bffca2SAnthony Liguori dc->props = 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