From e28bee8ee654b81f4688a505e56ade0692174b5c Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 3 Apr 2013 18:06:08 +0200 Subject: hw: move other devices to hw/misc/, configure with default-configs/ Signed-off-by: Paolo Bonzini --- default-configs/arm-softmmu.mak | 4 + default-configs/i386-softmmu.mak | 3 + default-configs/sparc-softmmu.mak | 1 + default-configs/x86_64-softmmu.mak | 3 + hw/a9scu.c | 164 ----- hw/arm/Makefile.objs | 11 +- hw/arm_sysctl.c | 649 ------------------ hw/cbus.c | 618 ------------------ hw/debugexit.c | 75 --- hw/eccmemctl.c | 340 ---------- hw/exynos4210_pmu.c | 499 -------------- hw/i386/Makefile.objs | 4 - hw/imx_ccm.c | 321 --------- hw/lm32/Makefile.objs | 7 - hw/lm32_sys.c | 172 ----- hw/milkymist-hpdmc.c | 170 ----- hw/milkymist-pfpu.c | 544 ---------------- hw/misc/Makefile.objs | 23 + hw/misc/a9scu.c | 164 +++++ hw/misc/arm_sysctl.c | 649 ++++++++++++++++++ hw/misc/cbus.c | 618 ++++++++++++++++++ hw/misc/debugexit.c | 75 +++ hw/misc/eccmemctl.c | 340 ++++++++++ hw/misc/exynos4210_pmu.c | 499 ++++++++++++++ hw/misc/imx_ccm.c | 321 +++++++++ hw/misc/lm32_sys.c | 172 +++++ hw/misc/milkymist-hpdmc.c | 170 +++++ hw/misc/milkymist-pfpu.c | 544 ++++++++++++++++ hw/misc/mst_fpga.c | 263 ++++++++ hw/misc/omap_clk.c | 1264 ++++++++++++++++++++++++++++++++++++ hw/misc/omap_gpmc.c | 894 +++++++++++++++++++++++++ hw/misc/omap_l4.c | 162 +++++ hw/misc/omap_sdrc.c | 168 +++++ hw/misc/omap_tap.c | 116 ++++ hw/misc/pc-testdev.c | 187 ++++++ hw/misc/pxa2xx_pcmcia.c | 207 ++++++ hw/misc/sga.c | 63 ++ hw/misc/slavio_misc.c | 508 +++++++++++++++ hw/misc/vmport.c | 170 +++++ hw/misc/zynq_slcr.c | 536 +++++++++++++++ hw/mst_fpga.c | 263 -------- hw/omap_clk.c | 1264 ------------------------------------ hw/omap_gpmc.c | 894 ------------------------- hw/omap_l4.c | 162 ----- hw/omap_sdrc.c | 168 ----- hw/omap_tap.c | 116 ---- hw/pc-testdev.c | 187 ------ hw/pxa2xx_pcmcia.c | 207 ------ hw/sga.c | 63 -- hw/slavio_misc.c | 508 --------------- hw/sparc/Makefile.objs | 5 - hw/vmport.c | 170 ----- hw/zynq_slcr.c | 536 --------------- 53 files changed, 8125 insertions(+), 8116 deletions(-) delete mode 100644 hw/a9scu.c delete mode 100644 hw/arm_sysctl.c delete mode 100644 hw/cbus.c delete mode 100644 hw/debugexit.c delete mode 100644 hw/eccmemctl.c delete mode 100644 hw/exynos4210_pmu.c delete mode 100644 hw/imx_ccm.c delete mode 100644 hw/lm32_sys.c delete mode 100644 hw/milkymist-hpdmc.c delete mode 100644 hw/milkymist-pfpu.c create mode 100644 hw/misc/a9scu.c create mode 100644 hw/misc/arm_sysctl.c create mode 100644 hw/misc/cbus.c create mode 100644 hw/misc/debugexit.c create mode 100644 hw/misc/eccmemctl.c create mode 100644 hw/misc/exynos4210_pmu.c create mode 100644 hw/misc/imx_ccm.c create mode 100644 hw/misc/lm32_sys.c create mode 100644 hw/misc/milkymist-hpdmc.c create mode 100644 hw/misc/milkymist-pfpu.c create mode 100644 hw/misc/mst_fpga.c create mode 100644 hw/misc/omap_clk.c create mode 100644 hw/misc/omap_gpmc.c create mode 100644 hw/misc/omap_l4.c create mode 100644 hw/misc/omap_sdrc.c create mode 100644 hw/misc/omap_tap.c create mode 100644 hw/misc/pc-testdev.c create mode 100644 hw/misc/pxa2xx_pcmcia.c create mode 100644 hw/misc/sga.c create mode 100644 hw/misc/slavio_misc.c create mode 100644 hw/misc/vmport.c create mode 100644 hw/misc/zynq_slcr.c delete mode 100644 hw/mst_fpga.c delete mode 100644 hw/omap_clk.c delete mode 100644 hw/omap_gpmc.c delete mode 100644 hw/omap_l4.c delete mode 100644 hw/omap_sdrc.c delete mode 100644 hw/omap_tap.c delete mode 100644 hw/pc-testdev.c delete mode 100644 hw/pxa2xx_pcmcia.c delete mode 100644 hw/sga.c delete mode 100644 hw/slavio_misc.c delete mode 100644 hw/vmport.c delete mode 100644 hw/zynq_slcr.c diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak index 93c7d95d4a..e03840ec56 100644 --- a/default-configs/arm-softmmu.mak +++ b/default-configs/arm-softmmu.mak @@ -58,6 +58,7 @@ CONFIG_BITBANG_I2C=y CONFIG_FRAMEBUFFER=y CONFIG_XILINX_SPIPS=y +CONFIG_A9SCU=y CONFIG_MARVELL_88W8618=y CONFIG_OMAP=y CONFIG_TSC210X=y @@ -65,8 +66,11 @@ CONFIG_BLIZZARD=y CONFIG_ONENAND=y CONFIG_TUSB6010=y CONFIG_IMX=y +CONFIG_MAINSTONE=y +CONFIG_NSERIES=y CONFIG_REALVIEW=y CONFIG_ZAURUS=y +CONFIG_ZYNQ=y CONFIG_VERSATILE_PCI=y CONFIG_VERSATILE_I2C=y diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak index 79851bd52c..4ac0694470 100644 --- a/default-configs/i386-softmmu.mak +++ b/default-configs/i386-softmmu.mak @@ -38,6 +38,9 @@ CONFIG_WDT_IB700=y CONFIG_PC_SYSFW=y CONFIG_XEN_I386=$(CONFIG_XEN) CONFIG_ISA_DEBUG=y +CONFIG_ISA_TESTDEV=y +CONFIG_VMPORT=y +CONFIG_SGA=y CONFIG_LPC_ICH9=y CONFIG_Q35=y CONFIG_APIC=y diff --git a/default-configs/sparc-softmmu.mak b/default-configs/sparc-softmmu.mak index 8c4d0a6886..8fc93dd643 100644 --- a/default-configs/sparc-softmmu.mak +++ b/default-configs/sparc-softmmu.mak @@ -14,4 +14,5 @@ CONFIG_SLAVIO=y CONFIG_CS4231=y CONFIG_GRLIB=y CONFIG_STP2000=y +CONFIG_ECCMEMCTL=y CONFIG_SUN4M=y diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak index 176f493ec4..bf4091c4dd 100644 --- a/default-configs/x86_64-softmmu.mak +++ b/default-configs/x86_64-softmmu.mak @@ -38,6 +38,9 @@ CONFIG_WDT_IB700=y CONFIG_PC_SYSFW=y CONFIG_XEN_I386=$(CONFIG_XEN) CONFIG_ISA_DEBUG=y +CONFIG_ISA_TESTDEV=y +CONFIG_VMPORT=y +CONFIG_SGA=y CONFIG_LPC_ICH9=y CONFIG_Q35=y CONFIG_APIC=y diff --git a/hw/a9scu.c b/hw/a9scu.c deleted file mode 100644 index 05897c2fa2..0000000000 --- a/hw/a9scu.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Cortex-A9MPCore Snoop Control Unit (SCU) emulation. - * - * Copyright (c) 2009 CodeSourcery. - * Copyright (c) 2011 Linaro Limited. - * Written by Paul Brook, Peter Maydell. - * - * This code is licensed under the GPL. - */ - -#include "hw/sysbus.h" - -/* A9MP private memory region. */ - -typedef struct A9SCUState { - SysBusDevice busdev; - MemoryRegion iomem; - uint32_t control; - uint32_t status; - uint32_t num_cpu; -} A9SCUState; - -#define TYPE_A9_SCU "a9-scu" -#define A9_SCU(obj) OBJECT_CHECK(A9SCUState, (obj), TYPE_A9_SCU) - -static uint64_t a9_scu_read(void *opaque, hwaddr offset, - unsigned size) -{ - A9SCUState *s = (A9SCUState *)opaque; - switch (offset) { - case 0x00: /* Control */ - return s->control; - case 0x04: /* Configuration */ - return (((1 << s->num_cpu) - 1) << 4) | (s->num_cpu - 1); - case 0x08: /* CPU Power Status */ - return s->status; - case 0x09: /* CPU status. */ - return s->status >> 8; - case 0x0a: /* CPU status. */ - return s->status >> 16; - case 0x0b: /* CPU status. */ - return s->status >> 24; - case 0x0c: /* Invalidate All Registers In Secure State */ - return 0; - case 0x40: /* Filtering Start Address Register */ - case 0x44: /* Filtering End Address Register */ - /* RAZ/WI, like an implementation with only one AXI master */ - return 0; - case 0x50: /* SCU Access Control Register */ - case 0x54: /* SCU Non-secure Access Control Register */ - /* unimplemented, fall through */ - default: - return 0; - } -} - -static void a9_scu_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - A9SCUState *s = (A9SCUState *)opaque; - uint32_t mask; - uint32_t shift; - switch (size) { - case 1: - mask = 0xff; - break; - case 2: - mask = 0xffff; - break; - case 4: - mask = 0xffffffff; - break; - default: - fprintf(stderr, "Invalid size %u in write to a9 scu register %x\n", - size, (unsigned)offset); - return; - } - - switch (offset) { - case 0x00: /* Control */ - s->control = value & 1; - break; - case 0x4: /* Configuration: RO */ - break; - case 0x08: case 0x09: case 0x0A: case 0x0B: /* Power Control */ - shift = (offset - 0x8) * 8; - s->status &= ~(mask << shift); - s->status |= ((value & mask) << shift); - break; - case 0x0c: /* Invalidate All Registers In Secure State */ - /* no-op as we do not implement caches */ - break; - case 0x40: /* Filtering Start Address Register */ - case 0x44: /* Filtering End Address Register */ - /* RAZ/WI, like an implementation with only one AXI master */ - break; - case 0x50: /* SCU Access Control Register */ - case 0x54: /* SCU Non-secure Access Control Register */ - /* unimplemented, fall through */ - default: - break; - } -} - -static const MemoryRegionOps a9_scu_ops = { - .read = a9_scu_read, - .write = a9_scu_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void a9_scu_reset(DeviceState *dev) -{ - A9SCUState *s = A9_SCU(dev); - s->control = 0; -} - -static void a9_scu_realize(DeviceState *dev, Error ** errp) -{ - A9SCUState *s = A9_SCU(dev); - SysBusDevice *sbd = SYS_BUS_DEVICE(dev); - - memory_region_init_io(&s->iomem, &a9_scu_ops, s, "a9-scu", 0x100); - sysbus_init_mmio(sbd, &s->iomem); -} - -static const VMStateDescription vmstate_a9_scu = { - .name = "a9-scu", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(control, A9SCUState), - VMSTATE_UINT32(status, A9SCUState), - VMSTATE_END_OF_LIST() - } -}; - -static Property a9_scu_properties[] = { - DEFINE_PROP_UINT32("num-cpu", A9SCUState, num_cpu, 1), - DEFINE_PROP_END_OF_LIST(), -}; - -static void a9_scu_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = a9_scu_realize; - dc->props = a9_scu_properties; - dc->vmsd = &vmstate_a9_scu; - dc->reset = a9_scu_reset; -} - -static const TypeInfo a9_scu_info = { - .name = TYPE_A9_SCU, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(A9SCUState), - .class_init = a9_scu_class_init, -}; - -static void a9mp_register_types(void) -{ - type_register_static(&a9_scu_info); -} - -type_init(a9mp_register_types) diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs index ec4d0cb7d5..cb94927e4c 100644 --- a/hw/arm/Makefile.objs +++ b/hw/arm/Makefile.objs @@ -1,15 +1,6 @@ -obj-y += zynq_slcr.o -obj-y += a9scu.o -obj-y += arm_sysctl.o arm11mpcore.o a9mpcore.o -obj-y += exynos4210_pmu.o +obj-y += arm11mpcore.o a9mpcore.o obj-y += a15mpcore.o -obj-y += pxa2xx_pcmcia.o -obj-y += omap_clk.o -obj-y += omap_gpmc.o omap_sdrc.o omap_tap.o omap_l4.o -obj-y += cbus.o -obj-y += mst_fpga.o obj-y += strongarm.o -obj-y += imx_ccm.o obj-y := $(addprefix ../,$(obj-y)) diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c deleted file mode 100644 index c8b55a8349..0000000000 --- a/hw/arm_sysctl.c +++ /dev/null @@ -1,649 +0,0 @@ -/* - * Status and system control registers for ARM RealView/Versatile boards. - * - * Copyright (c) 2006-2007 CodeSourcery. - * Written by Paul Brook - * - * This code is licensed under the GPL. - */ - -#include "hw/hw.h" -#include "qemu/timer.h" -#include "qemu/bitops.h" -#include "hw/sysbus.h" -#include "hw/arm/primecell.h" -#include "sysemu/sysemu.h" - -#define LOCK_VALUE 0xa05f - -typedef struct { - SysBusDevice busdev; - MemoryRegion iomem; - qemu_irq pl110_mux_ctrl; - - uint32_t sys_id; - uint32_t leds; - uint16_t lockval; - uint32_t cfgdata1; - uint32_t cfgdata2; - uint32_t flags; - uint32_t nvflags; - uint32_t resetlevel; - uint32_t proc_id; - uint32_t sys_mci; - uint32_t sys_cfgdata; - uint32_t sys_cfgctrl; - uint32_t sys_cfgstat; - uint32_t sys_clcd; - uint32_t mb_clock[6]; - uint32_t *db_clock; - uint32_t db_num_vsensors; - uint32_t *db_voltage; - uint32_t db_num_clocks; - uint32_t *db_clock_reset; -} arm_sysctl_state; - -static const VMStateDescription vmstate_arm_sysctl = { - .name = "realview_sysctl", - .version_id = 4, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(leds, arm_sysctl_state), - VMSTATE_UINT16(lockval, arm_sysctl_state), - VMSTATE_UINT32(cfgdata1, arm_sysctl_state), - VMSTATE_UINT32(cfgdata2, arm_sysctl_state), - VMSTATE_UINT32(flags, arm_sysctl_state), - VMSTATE_UINT32(nvflags, arm_sysctl_state), - VMSTATE_UINT32(resetlevel, arm_sysctl_state), - VMSTATE_UINT32_V(sys_mci, arm_sysctl_state, 2), - VMSTATE_UINT32_V(sys_cfgdata, arm_sysctl_state, 2), - VMSTATE_UINT32_V(sys_cfgctrl, arm_sysctl_state, 2), - VMSTATE_UINT32_V(sys_cfgstat, arm_sysctl_state, 2), - VMSTATE_UINT32_V(sys_clcd, arm_sysctl_state, 3), - VMSTATE_UINT32_ARRAY_V(mb_clock, arm_sysctl_state, 6, 4), - VMSTATE_VARRAY_UINT32(db_clock, arm_sysctl_state, db_num_clocks, - 4, vmstate_info_uint32, uint32_t), - VMSTATE_END_OF_LIST() - } -}; - -/* The PB926 actually uses a different format for - * its SYS_ID register. Fortunately the bits which are - * board type on later boards are distinct. - */ -#define BOARD_ID_PB926 0x100 -#define BOARD_ID_EB 0x140 -#define BOARD_ID_PBA8 0x178 -#define BOARD_ID_PBX 0x182 -#define BOARD_ID_VEXPRESS 0x190 - -static int board_id(arm_sysctl_state *s) -{ - /* Extract the board ID field from the SYS_ID register value */ - return (s->sys_id >> 16) & 0xfff; -} - -static void arm_sysctl_reset(DeviceState *d) -{ - arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, SYS_BUS_DEVICE(d)); - int i; - - s->leds = 0; - s->lockval = 0; - s->cfgdata1 = 0; - s->cfgdata2 = 0; - s->flags = 0; - s->resetlevel = 0; - /* Motherboard oscillators (in Hz) */ - s->mb_clock[0] = 50000000; /* Static memory clock: 50MHz */ - s->mb_clock[1] = 23750000; /* motherboard CLCD clock: 23.75MHz */ - s->mb_clock[2] = 24000000; /* IO FPGA peripheral clock: 24MHz */ - s->mb_clock[3] = 24000000; /* IO FPGA reserved clock: 24MHz */ - s->mb_clock[4] = 24000000; /* System bus global clock: 24MHz */ - s->mb_clock[5] = 24000000; /* IO FPGA reserved clock: 24MHz */ - /* Daughterboard oscillators: reset from property values */ - for (i = 0; i < s->db_num_clocks; i++) { - s->db_clock[i] = s->db_clock_reset[i]; - } - if (board_id(s) == BOARD_ID_VEXPRESS) { - /* On VExpress this register will RAZ/WI */ - s->sys_clcd = 0; - } else { - /* All others: CLCDID 0x1f, indicating VGA */ - s->sys_clcd = 0x1f00; - } -} - -static uint64_t arm_sysctl_read(void *opaque, hwaddr offset, - unsigned size) -{ - arm_sysctl_state *s = (arm_sysctl_state *)opaque; - - switch (offset) { - case 0x00: /* ID */ - return s->sys_id; - case 0x04: /* SW */ - /* General purpose hardware switches. - We don't have a useful way of exposing these to the user. */ - return 0; - case 0x08: /* LED */ - return s->leds; - case 0x20: /* LOCK */ - return s->lockval; - case 0x0c: /* OSC0 */ - case 0x10: /* OSC1 */ - case 0x14: /* OSC2 */ - case 0x18: /* OSC3 */ - case 0x1c: /* OSC4 */ - case 0x24: /* 100HZ */ - /* ??? Implement these. */ - return 0; - case 0x28: /* CFGDATA1 */ - return s->cfgdata1; - case 0x2c: /* CFGDATA2 */ - return s->cfgdata2; - case 0x30: /* FLAGS */ - return s->flags; - case 0x38: /* NVFLAGS */ - return s->nvflags; - case 0x40: /* RESETCTL */ - if (board_id(s) == BOARD_ID_VEXPRESS) { - /* reserved: RAZ/WI */ - return 0; - } - return s->resetlevel; - case 0x44: /* PCICTL */ - return 1; - case 0x48: /* MCI */ - return s->sys_mci; - case 0x4c: /* FLASH */ - return 0; - case 0x50: /* CLCD */ - return s->sys_clcd; - case 0x54: /* CLCDSER */ - return 0; - case 0x58: /* BOOTCS */ - return 0; - case 0x5c: /* 24MHz */ - return muldiv64(qemu_get_clock_ns(vm_clock), 24000000, get_ticks_per_sec()); - case 0x60: /* MISC */ - return 0; - case 0x84: /* PROCID0 */ - return s->proc_id; - case 0x88: /* PROCID1 */ - return 0xff000000; - case 0x64: /* DMAPSR0 */ - case 0x68: /* DMAPSR1 */ - case 0x6c: /* DMAPSR2 */ - case 0x70: /* IOSEL */ - case 0x74: /* PLDCTL */ - case 0x80: /* BUSID */ - case 0x8c: /* OSCRESET0 */ - case 0x90: /* OSCRESET1 */ - case 0x94: /* OSCRESET2 */ - case 0x98: /* OSCRESET3 */ - case 0x9c: /* OSCRESET4 */ - case 0xc0: /* SYS_TEST_OSC0 */ - case 0xc4: /* SYS_TEST_OSC1 */ - case 0xc8: /* SYS_TEST_OSC2 */ - case 0xcc: /* SYS_TEST_OSC3 */ - case 0xd0: /* SYS_TEST_OSC4 */ - return 0; - case 0xa0: /* SYS_CFGDATA */ - if (board_id(s) != BOARD_ID_VEXPRESS) { - goto bad_reg; - } - return s->sys_cfgdata; - case 0xa4: /* SYS_CFGCTRL */ - if (board_id(s) != BOARD_ID_VEXPRESS) { - goto bad_reg; - } - return s->sys_cfgctrl; - case 0xa8: /* SYS_CFGSTAT */ - if (board_id(s) != BOARD_ID_VEXPRESS) { - goto bad_reg; - } - return s->sys_cfgstat; - default: - bad_reg: - qemu_log_mask(LOG_GUEST_ERROR, - "arm_sysctl_read: Bad register offset 0x%x\n", - (int)offset); - return 0; - } -} - -/* SYS_CFGCTRL functions */ -#define SYS_CFG_OSC 1 -#define SYS_CFG_VOLT 2 -#define SYS_CFG_AMP 3 -#define SYS_CFG_TEMP 4 -#define SYS_CFG_RESET 5 -#define SYS_CFG_SCC 6 -#define SYS_CFG_MUXFPGA 7 -#define SYS_CFG_SHUTDOWN 8 -#define SYS_CFG_REBOOT 9 -#define SYS_CFG_DVIMODE 11 -#define SYS_CFG_POWER 12 -#define SYS_CFG_ENERGY 13 - -/* SYS_CFGCTRL site field values */ -#define SYS_CFG_SITE_MB 0 -#define SYS_CFG_SITE_DB1 1 -#define SYS_CFG_SITE_DB2 2 - -/** - * vexpress_cfgctrl_read: - * @s: arm_sysctl_state pointer - * @dcc, @function, @site, @position, @device: split out values from - * SYS_CFGCTRL register - * @val: pointer to where to put the read data on success - * - * Handle a VExpress SYS_CFGCTRL register read. On success, return true and - * write the read value to *val. On failure, return false (and val may - * or may not be written to). - */ -static bool vexpress_cfgctrl_read(arm_sysctl_state *s, unsigned int dcc, - unsigned int function, unsigned int site, - unsigned int position, unsigned int device, - uint32_t *val) -{ - /* We don't support anything other than DCC 0, board stack position 0 - * or sites other than motherboard/daughterboard: - */ - if (dcc != 0 || position != 0 || - (site != SYS_CFG_SITE_MB && site != SYS_CFG_SITE_DB1)) { - goto cfgctrl_unimp; - } - - switch (function) { - case SYS_CFG_VOLT: - if (site == SYS_CFG_SITE_DB1 && device < s->db_num_vsensors) { - *val = s->db_voltage[device]; - return true; - } - if (site == SYS_CFG_SITE_MB && device == 0) { - /* There is only one motherboard voltage sensor: - * VIO : 3.3V : bus voltage between mother and daughterboard - */ - *val = 3300000; - return true; - } - break; - case SYS_CFG_OSC: - if (site == SYS_CFG_SITE_MB && device < sizeof(s->mb_clock)) { - /* motherboard clock */ - *val = s->mb_clock[device]; - return true; - } - if (site == SYS_CFG_SITE_DB1 && device < s->db_num_clocks) { - /* daughterboard clock */ - *val = s->db_clock[device]; - return true; - } - break; - default: - break; - } - -cfgctrl_unimp: - qemu_log_mask(LOG_UNIMP, - "arm_sysctl: Unimplemented SYS_CFGCTRL read of function " - "0x%x DCC 0x%x site 0x%x position 0x%x device 0x%x\n", - function, dcc, site, position, device); - return false; -} - -/** - * vexpress_cfgctrl_write: - * @s: arm_sysctl_state pointer - * @dcc, @function, @site, @position, @device: split out values from - * SYS_CFGCTRL register - * @val: data to write - * - * Handle a VExpress SYS_CFGCTRL register write. On success, return true. - * On failure, return false. - */ -static bool vexpress_cfgctrl_write(arm_sysctl_state *s, unsigned int dcc, - unsigned int function, unsigned int site, - unsigned int position, unsigned int device, - uint32_t val) -{ - /* We don't support anything other than DCC 0, board stack position 0 - * or sites other than motherboard/daughterboard: - */ - if (dcc != 0 || position != 0 || - (site != SYS_CFG_SITE_MB && site != SYS_CFG_SITE_DB1)) { - goto cfgctrl_unimp; - } - - switch (function) { - case SYS_CFG_OSC: - if (site == SYS_CFG_SITE_MB && device < sizeof(s->mb_clock)) { - /* motherboard clock */ - s->mb_clock[device] = val; - return true; - } - if (site == SYS_CFG_SITE_DB1 && device < s->db_num_clocks) { - /* daughterboard clock */ - s->db_clock[device] = val; - return true; - } - break; - case SYS_CFG_MUXFPGA: - if (site == SYS_CFG_SITE_MB && device == 0) { - /* Select whether video output comes from motherboard - * or daughterboard: log and ignore as QEMU doesn't - * support this. - */ - qemu_log_mask(LOG_UNIMP, "arm_sysctl: selection of video output " - "not supported, ignoring\n"); - return true; - } - break; - case SYS_CFG_SHUTDOWN: - if (site == SYS_CFG_SITE_MB && device == 0) { - qemu_system_shutdown_request(); - return true; - } - break; - case SYS_CFG_REBOOT: - if (site == SYS_CFG_SITE_MB && device == 0) { - qemu_system_reset_request(); - return true; - } - break; - case SYS_CFG_DVIMODE: - if (site == SYS_CFG_SITE_MB && device == 0) { - /* Selecting DVI mode is meaningless for QEMU: we will - * always display the output correctly according to the - * pixel height/width programmed into the CLCD controller. - */ - return true; - } - default: - break; - } - -cfgctrl_unimp: - qemu_log_mask(LOG_UNIMP, - "arm_sysctl: Unimplemented SYS_CFGCTRL write of function " - "0x%x DCC 0x%x site 0x%x position 0x%x device 0x%x\n", - function, dcc, site, position, device); - return false; -} - -static void arm_sysctl_write(void *opaque, hwaddr offset, - uint64_t val, unsigned size) -{ - arm_sysctl_state *s = (arm_sysctl_state *)opaque; - - switch (offset) { - case 0x08: /* LED */ - s->leds = val; - break; - case 0x0c: /* OSC0 */ - case 0x10: /* OSC1 */ - case 0x14: /* OSC2 */ - case 0x18: /* OSC3 */ - case 0x1c: /* OSC4 */ - /* ??? */ - break; - case 0x20: /* LOCK */ - if (val == LOCK_VALUE) - s->lockval = val; - else - s->lockval = val & 0x7fff; - break; - case 0x28: /* CFGDATA1 */ - /* ??? Need to implement this. */ - s->cfgdata1 = val; - break; - case 0x2c: /* CFGDATA2 */ - /* ??? Need to implement this. */ - s->cfgdata2 = val; - break; - case 0x30: /* FLAGSSET */ - s->flags |= val; - break; - case 0x34: /* FLAGSCLR */ - s->flags &= ~val; - break; - case 0x38: /* NVFLAGSSET */ - s->nvflags |= val; - break; - case 0x3c: /* NVFLAGSCLR */ - s->nvflags &= ~val; - break; - case 0x40: /* RESETCTL */ - switch (board_id(s)) { - case BOARD_ID_PB926: - if (s->lockval == LOCK_VALUE) { - s->resetlevel = val; - if (val & 0x100) { - qemu_system_reset_request(); - } - } - break; - case BOARD_ID_PBX: - case BOARD_ID_PBA8: - if (s->lockval == LOCK_VALUE) { - s->resetlevel = val; - if (val & 0x04) { - qemu_system_reset_request(); - } - } - break; - case BOARD_ID_VEXPRESS: - case BOARD_ID_EB: - default: - /* reserved: RAZ/WI */ - break; - } - break; - case 0x44: /* PCICTL */ - /* nothing to do. */ - break; - case 0x4c: /* FLASH */ - break; - case 0x50: /* CLCD */ - switch (board_id(s)) { - case BOARD_ID_PB926: - /* On 926 bits 13:8 are R/O, bits 1:0 control - * the mux that defines how to interpret the PL110 - * graphics format, and other bits are r/w but we - * don't implement them to do anything. - */ - s->sys_clcd &= 0x3f00; - s->sys_clcd |= val & ~0x3f00; - qemu_set_irq(s->pl110_mux_ctrl, val & 3); - break; - case BOARD_ID_EB: - /* The EB is the same except that there is no mux since - * the EB has a PL111. - */ - s->sys_clcd &= 0x3f00; - s->sys_clcd |= val & ~0x3f00; - break; - case BOARD_ID_PBA8: - case BOARD_ID_PBX: - /* On PBA8 and PBX bit 7 is r/w and all other bits - * are either r/o or RAZ/WI. - */ - s->sys_clcd &= (1 << 7); - s->sys_clcd |= val & ~(1 << 7); - break; - case BOARD_ID_VEXPRESS: - default: - /* On VExpress this register is unimplemented and will RAZ/WI */ - break; - } - break; - case 0x54: /* CLCDSER */ - case 0x64: /* DMAPSR0 */ - case 0x68: /* DMAPSR1 */ - case 0x6c: /* DMAPSR2 */ - case 0x70: /* IOSEL */ - case 0x74: /* PLDCTL */ - case 0x80: /* BUSID */ - case 0x84: /* PROCID0 */ - case 0x88: /* PROCID1 */ - case 0x8c: /* OSCRESET0 */ - case 0x90: /* OSCRESET1 */ - case 0x94: /* OSCRESET2 */ - case 0x98: /* OSCRESET3 */ - case 0x9c: /* OSCRESET4 */ - break; - case 0xa0: /* SYS_CFGDATA */ - if (board_id(s) != BOARD_ID_VEXPRESS) { - goto bad_reg; - } - s->sys_cfgdata = val; - return; - case 0xa4: /* SYS_CFGCTRL */ - if (board_id(s) != BOARD_ID_VEXPRESS) { - goto bad_reg; - } - /* Undefined bits [19:18] are RAZ/WI, and writing to - * the start bit just triggers the action; it always reads - * as zero. - */ - s->sys_cfgctrl = val & ~((3 << 18) | (1 << 31)); - if (val & (1 << 31)) { - /* Start bit set -- actually do something */ - unsigned int dcc = extract32(s->sys_cfgctrl, 26, 4); - unsigned int function = extract32(s->sys_cfgctrl, 20, 6); - unsigned int site = extract32(s->sys_cfgctrl, 16, 2); - unsigned int position = extract32(s->sys_cfgctrl, 12, 4); - unsigned int device = extract32(s->sys_cfgctrl, 0, 12); - s->sys_cfgstat = 1; /* complete */ - if (s->sys_cfgctrl & (1 << 30)) { - if (!vexpress_cfgctrl_write(s, dcc, function, site, position, - device, s->sys_cfgdata)) { - s->sys_cfgstat |= 2; /* error */ - } - } else { - uint32_t val; - if (!vexpress_cfgctrl_read(s, dcc, function, site, position, - device, &val)) { - s->sys_cfgstat |= 2; /* error */ - } else { - s->sys_cfgdata = val; - } - } - } - s->sys_cfgctrl &= ~(1 << 31); - return; - case 0xa8: /* SYS_CFGSTAT */ - if (board_id(s) != BOARD_ID_VEXPRESS) { - goto bad_reg; - } - s->sys_cfgstat = val & 3; - return; - default: - bad_reg: - qemu_log_mask(LOG_GUEST_ERROR, - "arm_sysctl_write: Bad register offset 0x%x\n", - (int)offset); - return; - } -} - -static const MemoryRegionOps arm_sysctl_ops = { - .read = arm_sysctl_read, - .write = arm_sysctl_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void arm_sysctl_gpio_set(void *opaque, int line, int level) -{ - arm_sysctl_state *s = (arm_sysctl_state *)opaque; - switch (line) { - case ARM_SYSCTL_GPIO_MMC_WPROT: - { - /* For PB926 and EB write-protect is bit 2 of SYS_MCI; - * for all later boards it is bit 1. - */ - int bit = 2; - if ((board_id(s) == BOARD_ID_PB926) || (board_id(s) == BOARD_ID_EB)) { - bit = 4; - } - s->sys_mci &= ~bit; - if (level) { - s->sys_mci |= bit; - } - break; - } - case ARM_SYSCTL_GPIO_MMC_CARDIN: - s->sys_mci &= ~1; - if (level) { - s->sys_mci |= 1; - } - break; - } -} - -static void arm_sysctl_init(Object *obj) -{ - DeviceState *dev = DEVICE(obj); - SysBusDevice *sd = SYS_BUS_DEVICE(obj); - arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, sd); - - memory_region_init_io(&s->iomem, &arm_sysctl_ops, s, "arm-sysctl", 0x1000); - sysbus_init_mmio(sd, &s->iomem); - qdev_init_gpio_in(dev, arm_sysctl_gpio_set, 2); - qdev_init_gpio_out(dev, &s->pl110_mux_ctrl, 1); -} - -static void arm_sysctl_realize(DeviceState *d, Error **errp) -{ - arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, SYS_BUS_DEVICE(d)); - s->db_clock = g_new0(uint32_t, s->db_num_clocks); -} - -static void arm_sysctl_finalize(Object *obj) -{ - SysBusDevice *dev = SYS_BUS_DEVICE(obj); - arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, dev); - g_free(s->db_voltage); - g_free(s->db_clock); - g_free(s->db_clock_reset); -} - -static Property arm_sysctl_properties[] = { - DEFINE_PROP_UINT32("sys_id", arm_sysctl_state, sys_id, 0), - DEFINE_PROP_UINT32("proc_id", arm_sysctl_state, proc_id, 0), - /* Daughterboard power supply voltages (as reported via SYS_CFG) */ - DEFINE_PROP_ARRAY("db-voltage", arm_sysctl_state, db_num_vsensors, - db_voltage, qdev_prop_uint32, uint32_t), - /* Daughterboard clock reset values (as reported via SYS_CFG) */ - DEFINE_PROP_ARRAY("db-clock", arm_sysctl_state, db_num_clocks, - db_clock_reset, qdev_prop_uint32, uint32_t), - DEFINE_PROP_END_OF_LIST(), -}; - -static void arm_sysctl_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = arm_sysctl_realize; - dc->reset = arm_sysctl_reset; - dc->vmsd = &vmstate_arm_sysctl; - dc->props = arm_sysctl_properties; -} - -static const TypeInfo arm_sysctl_info = { - .name = "realview_sysctl", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(arm_sysctl_state), - .instance_init = arm_sysctl_init, - .instance_finalize = arm_sysctl_finalize, - .class_init = arm_sysctl_class_init, -}; - -static void arm_sysctl_register_types(void) -{ - type_register_static(&arm_sysctl_info); -} - -type_init(arm_sysctl_register_types) diff --git a/hw/cbus.c b/hw/cbus.c deleted file mode 100644 index 3d9027f692..0000000000 --- a/hw/cbus.c +++ /dev/null @@ -1,618 +0,0 @@ -/* - * CBUS three-pin bus and the Retu / Betty / Tahvo / Vilma / Avilma / - * Hinku / Vinku / Ahne / Pihi chips used in various Nokia platforms. - * Based on reverse-engineering of a linux driver. - * - * Copyright (C) 2008 Nokia Corporation - * Written by Andrzej Zaborowski - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 or - * (at your option) version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . - */ - -#include "qemu-common.h" -#include "hw/irq.h" -#include "hw/arm/devices.h" -#include "sysemu/sysemu.h" - -//#define DEBUG - -typedef struct { - void *opaque; - void (*io)(void *opaque, int rw, int reg, uint16_t *val); - int addr; -} CBusSlave; - -typedef struct { - CBus cbus; - - int sel; - int dat; - int clk; - int bit; - int dir; - uint16_t val; - qemu_irq dat_out; - - int addr; - int reg; - int rw; - enum { - cbus_address, - cbus_value, - } cycle; - - CBusSlave *slave[8]; -} CBusPriv; - -static void cbus_io(CBusPriv *s) -{ - if (s->slave[s->addr]) - s->slave[s->addr]->io(s->slave[s->addr]->opaque, - s->rw, s->reg, &s->val); - else - hw_error("%s: bad slave address %i\n", __FUNCTION__, s->addr); -} - -static void cbus_cycle(CBusPriv *s) -{ - switch (s->cycle) { - case cbus_address: - s->addr = (s->val >> 6) & 7; - s->rw = (s->val >> 5) & 1; - s->reg = (s->val >> 0) & 0x1f; - - s->cycle = cbus_value; - s->bit = 15; - s->dir = !s->rw; - s->val = 0; - - if (s->rw) - cbus_io(s); - break; - - case cbus_value: - if (!s->rw) - cbus_io(s); - - s->cycle = cbus_address; - s->bit = 8; - s->dir = 1; - s->val = 0; - break; - } -} - -static void cbus_clk(void *opaque, int line, int level) -{ - CBusPriv *s = (CBusPriv *) opaque; - - if (!s->sel && level && !s->clk) { - if (s->dir) - s->val |= s->dat << (s->bit --); - else - qemu_set_irq(s->dat_out, (s->val >> (s->bit --)) & 1); - - if (s->bit < 0) - cbus_cycle(s); - } - - s->clk = level; -} - -static void cbus_dat(void *opaque, int line, int level) -{ - CBusPriv *s = (CBusPriv *) opaque; - - s->dat = level; -} - -static void cbus_sel(void *opaque, int line, int level) -{ - CBusPriv *s = (CBusPriv *) opaque; - - if (!level) { - s->dir = 1; - s->bit = 8; - s->val = 0; - } - - s->sel = level; -} - -CBus *cbus_init(qemu_irq dat) -{ - CBusPriv *s = (CBusPriv *) g_malloc0(sizeof(*s)); - - s->dat_out = dat; - s->cbus.clk = qemu_allocate_irqs(cbus_clk, s, 1)[0]; - s->cbus.dat = qemu_allocate_irqs(cbus_dat, s, 1)[0]; - s->cbus.sel = qemu_allocate_irqs(cbus_sel, s, 1)[0]; - - s->sel = 1; - s->clk = 0; - s->dat = 0; - - return &s->cbus; -} - -void cbus_attach(CBus *bus, void *slave_opaque) -{ - CBusSlave *slave = (CBusSlave *) slave_opaque; - CBusPriv *s = (CBusPriv *) bus; - - s->slave[slave->addr] = slave; -} - -/* Retu/Vilma */ -typedef struct { - uint16_t irqst; - uint16_t irqen; - uint16_t cc[2]; - int channel; - uint16_t result[16]; - uint16_t sample; - uint16_t status; - - struct { - uint16_t cal; - } rtc; - - int is_vilma; - qemu_irq irq; - CBusSlave cbus; -} CBusRetu; - -static void retu_interrupt_update(CBusRetu *s) -{ - qemu_set_irq(s->irq, s->irqst & ~s->irqen); -} - -#define RETU_REG_ASICR 0x00 /* (RO) ASIC ID & revision */ -#define RETU_REG_IDR 0x01 /* (T) Interrupt ID */ -#define RETU_REG_IMR 0x02 /* (RW) Interrupt mask */ -#define RETU_REG_RTCDSR 0x03 /* (RW) RTC seconds register */ -#define RETU_REG_RTCHMR 0x04 /* (RO) RTC hours and minutes reg */ -#define RETU_REG_RTCHMAR 0x05 /* (RW) RTC hours and minutes set reg */ -#define RETU_REG_RTCCALR 0x06 /* (RW) RTC calibration register */ -#define RETU_REG_ADCR 0x08 /* (RW) ADC result register */ -#define RETU_REG_ADCSCR 0x09 /* (RW) ADC sample control register */ -#define RETU_REG_AFCR 0x0a /* (RW) AFC register */ -#define RETU_REG_ANTIFR 0x0b /* (RW) AntiF register */ -#define RETU_REG_CALIBR 0x0c /* (RW) CalibR register*/ -#define RETU_REG_CCR1 0x0d /* (RW) Common control register 1 */ -#define RETU_REG_CCR2 0x0e /* (RW) Common control register 2 */ -#define RETU_REG_RCTRL_CLR 0x0f /* (T) Regulator clear register */ -#define RETU_REG_RCTRL_SET 0x10 /* (T) Regulator set register */ -#define RETU_REG_TXCR 0x11 /* (RW) TxC register */ -#define RETU_REG_STATUS 0x16 /* (RO) Status register */ -#define RETU_REG_WATCHDOG 0x17 /* (RW) Watchdog register */ -#define RETU_REG_AUDTXR 0x18 /* (RW) Audio Codec Tx register */ -#define RETU_REG_AUDPAR 0x19 /* (RW) AudioPA register */ -#define RETU_REG_AUDRXR1 0x1a /* (RW) Audio receive register 1 */ -#define RETU_REG_AUDRXR2 0x1b /* (RW) Audio receive register 2 */ -#define RETU_REG_SGR1 0x1c /* (RW) */ -#define RETU_REG_SCR1 0x1d /* (RW) */ -#define RETU_REG_SGR2 0x1e /* (RW) */ -#define RETU_REG_SCR2 0x1f /* (RW) */ - -/* Retu Interrupt sources */ -enum { - retu_int_pwr = 0, /* Power button */ - retu_int_char = 1, /* Charger */ - retu_int_rtcs = 2, /* Seconds */ - retu_int_rtcm = 3, /* Minutes */ - retu_int_rtcd = 4, /* Days */ - retu_int_rtca = 5, /* Alarm */ - retu_int_hook = 6, /* Hook */ - retu_int_head = 7, /* Headset */ - retu_int_adcs = 8, /* ADC sample */ -}; - -/* Retu ADC channel wiring */ -enum { - retu_adc_bsi = 1, /* BSI */ - retu_adc_batt_temp = 2, /* Battery temperature */ - retu_adc_chg_volt = 3, /* Charger voltage */ - retu_adc_head_det = 4, /* Headset detection */ - retu_adc_hook_det = 5, /* Hook detection */ - retu_adc_rf_gp = 6, /* RF GP */ - retu_adc_tx_det = 7, /* Wideband Tx detection */ - retu_adc_batt_volt = 8, /* Battery voltage */ - retu_adc_sens = 10, /* Light sensor */ - retu_adc_sens_temp = 11, /* Light sensor temperature */ - retu_adc_bbatt_volt = 12, /* Backup battery voltage */ - retu_adc_self_temp = 13, /* RETU temperature */ -}; - -static inline uint16_t retu_read(CBusRetu *s, int reg) -{ -#ifdef DEBUG - printf("RETU read at %02x\n", reg); -#endif - - switch (reg) { - case RETU_REG_ASICR: - return 0x0215 | (s->is_vilma << 7); - - case RETU_REG_IDR: /* TODO: Or is this ffs(s->irqst)? */ - return s->irqst; - - case RETU_REG_IMR: - return s->irqen; - - case RETU_REG_RTCDSR: - case RETU_REG_RTCHMR: - case RETU_REG_RTCHMAR: - /* TODO */ - return 0x0000; - - case RETU_REG_RTCCALR: - return s->rtc.cal; - - case RETU_REG_ADCR: - return (s->channel << 10) | s->result[s->channel]; - case RETU_REG_ADCSCR: - return s->sample; - - case RETU_REG_AFCR: - case RETU_REG_ANTIFR: - case RETU_REG_CALIBR: - /* TODO */ - return 0x0000; - - case RETU_REG_CCR1: - return s->cc[0]; - case RETU_REG_CCR2: - return s->cc[1]; - - case RETU_REG_RCTRL_CLR: - case RETU_REG_RCTRL_SET: - case RETU_REG_TXCR: - /* TODO */ - return 0x0000; - - case RETU_REG_STATUS: - return s->status; - - case RETU_REG_WATCHDOG: - case RETU_REG_AUDTXR: - case RETU_REG_AUDPAR: - case RETU_REG_AUDRXR1: - case RETU_REG_AUDRXR2: - case RETU_REG_SGR1: - case RETU_REG_SCR1: - case RETU_REG_SGR2: - case RETU_REG_SCR2: - /* TODO */ - return 0x0000; - - default: - hw_error("%s: bad register %02x\n", __FUNCTION__, reg); - } -} - -static inline void retu_write(CBusRetu *s, int reg, uint16_t val) -{ -#ifdef DEBUG - printf("RETU write of %04x at %02x\n", val, reg); -#endif - - switch (reg) { - case RETU_REG_IDR: - s->irqst ^= val; - retu_interrupt_update(s); - break; - - case RETU_REG_IMR: - s->irqen = val; - retu_interrupt_update(s); - break; - - case RETU_REG_RTCDSR: - case RETU_REG_RTCHMAR: - /* TODO */ - break; - - case RETU_REG_RTCCALR: - s->rtc.cal = val; - break; - - case RETU_REG_ADCR: - s->channel = (val >> 10) & 0xf; - s->irqst |= 1 << retu_int_adcs; - retu_interrupt_update(s); - break; - case RETU_REG_ADCSCR: - s->sample &= ~val; - break; - - case RETU_REG_AFCR: - case RETU_REG_ANTIFR: - case RETU_REG_CALIBR: - - case RETU_REG_CCR1: - s->cc[0] = val; - break; - case RETU_REG_CCR2: - s->cc[1] = val; - break; - - case RETU_REG_RCTRL_CLR: - case RETU_REG_RCTRL_SET: - /* TODO */ - break; - - case RETU_REG_WATCHDOG: - if (val == 0 && (s->cc[0] & 2)) - qemu_system_shutdown_request(); - break; - - case RETU_REG_TXCR: - case RETU_REG_AUDTXR: - case RETU_REG_AUDPAR: - case RETU_REG_AUDRXR1: - case RETU_REG_AUDRXR2: - case RETU_REG_SGR1: - case RETU_REG_SCR1: - case RETU_REG_SGR2: - case RETU_REG_SCR2: - /* TODO */ - break; - - default: - hw_error("%s: bad register %02x\n", __FUNCTION__, reg); - } -} - -static void retu_io(void *opaque, int rw, int reg, uint16_t *val) -{ - CBusRetu *s = (CBusRetu *) opaque; - - if (rw) - *val = retu_read(s, reg); - else - retu_write(s, reg, *val); -} - -void *retu_init(qemu_irq irq, int vilma) -{ - CBusRetu *s = (CBusRetu *) g_malloc0(sizeof(*s)); - - s->irq = irq; - s->irqen = 0xffff; - s->irqst = 0x0000; - s->status = 0x0020; - s->is_vilma = !!vilma; - s->rtc.cal = 0x01; - s->result[retu_adc_bsi] = 0x3c2; - s->result[retu_adc_batt_temp] = 0x0fc; - s->result[retu_adc_chg_volt] = 0x165; - s->result[retu_adc_head_det] = 123; - s->result[retu_adc_hook_det] = 1023; - s->result[retu_adc_rf_gp] = 0x11; - s->result[retu_adc_tx_det] = 0x11; - s->result[retu_adc_batt_volt] = 0x250; - s->result[retu_adc_sens] = 2; - s->result[retu_adc_sens_temp] = 0x11; - s->result[retu_adc_bbatt_volt] = 0x3d0; - s->result[retu_adc_self_temp] = 0x330; - - s->cbus.opaque = s; - s->cbus.io = retu_io; - s->cbus.addr = 1; - - return &s->cbus; -} - -void retu_key_event(void *retu, int state) -{ - CBusSlave *slave = (CBusSlave *) retu; - CBusRetu *s = (CBusRetu *) slave->opaque; - - s->irqst |= 1 << retu_int_pwr; - retu_interrupt_update(s); - - if (state) - s->status &= ~(1 << 5); - else - s->status |= 1 << 5; -} - -#if 0 -static void retu_head_event(void *retu, int state) -{ - CBusSlave *slave = (CBusSlave *) retu; - CBusRetu *s = (CBusRetu *) slave->opaque; - - if ((s->cc[0] & 0x500) == 0x500) { /* TODO: Which bits? */ - /* TODO: reissue the interrupt every 100ms or so. */ - s->irqst |= 1 << retu_int_head; - retu_interrupt_update(s); - } - - if (state) - s->result[retu_adc_head_det] = 50; - else - s->result[retu_adc_head_det] = 123; -} - -static void retu_hook_event(void *retu, int state) -{ - CBusSlave *slave = (CBusSlave *) retu; - CBusRetu *s = (CBusRetu *) slave->opaque; - - if ((s->cc[0] & 0x500) == 0x500) { - /* TODO: reissue the interrupt every 100ms or so. */ - s->irqst |= 1 << retu_int_hook; - retu_interrupt_update(s); - } - - if (state) - s->result[retu_adc_hook_det] = 50; - else - s->result[retu_adc_hook_det] = 123; -} -#endif - -/* Tahvo/Betty */ -typedef struct { - uint16_t irqst; - uint16_t irqen; - uint8_t charger; - uint8_t backlight; - uint16_t usbr; - uint16_t power; - - int is_betty; - qemu_irq irq; - CBusSlave cbus; -} CBusTahvo; - -static void tahvo_interrupt_update(CBusTahvo *s) -{ - qemu_set_irq(s->irq, s->irqst & ~s->irqen); -} - -#define TAHVO_REG_ASICR 0x00 /* (RO) ASIC ID & revision */ -#define TAHVO_REG_IDR 0x01 /* (T) Interrupt ID */ -#define TAHVO_REG_IDSR 0x02 /* (RO) Interrupt status */ -#define TAHVO_REG_IMR 0x03 /* (RW) Interrupt mask */ -#define TAHVO_REG_CHAPWMR 0x04 /* (RW) Charger PWM */ -#define TAHVO_REG_LEDPWMR 0x05 /* (RW) LED PWM */ -#define TAHVO_REG_USBR 0x06 /* (RW) USB control */ -#define TAHVO_REG_RCR 0x07 /* (RW) Some kind of power management */ -#define TAHVO_REG_CCR1 0x08 /* (RW) Common control register 1 */ -#define TAHVO_REG_CCR2 0x09 /* (RW) Common control register 2 */ -#define TAHVO_REG_TESTR1 0x0a /* (RW) Test register 1 */ -#define TAHVO_REG_TESTR2 0x0b /* (RW) Test register 2 */ -#define TAHVO_REG_NOPR 0x0c /* (RW) Number of periods */ -#define TAHVO_REG_FRR 0x0d /* (RO) FR */ - -static inline uint16_t tahvo_read(CBusTahvo *s, int reg) -{ -#ifdef DEBUG - printf("TAHVO read at %02x\n", reg); -#endif - - switch (reg) { - case TAHVO_REG_ASICR: - return 0x0021 | (s->is_betty ? 0x0b00 : 0x0300); /* 22 in N810 */ - - case TAHVO_REG_IDR: - case TAHVO_REG_IDSR: /* XXX: what does this do? */ - return s->irqst; - - case TAHVO_REG_IMR: - return s->irqen; - - case TAHVO_REG_CHAPWMR: - return s->charger; - - case TAHVO_REG_LEDPWMR: - return s->backlight; - - case TAHVO_REG_USBR: - return s->usbr; - - case TAHVO_REG_RCR: - return s->power; - - case TAHVO_REG_CCR1: - case TAHVO_REG_CCR2: - case TAHVO_REG_TESTR1: - case TAHVO_REG_TESTR2: - case TAHVO_REG_NOPR: - case TAHVO_REG_FRR: - return 0x0000; - - default: - hw_error("%s: bad register %02x\n", __FUNCTION__, reg); - } -} - -static inline void tahvo_write(CBusTahvo *s, int reg, uint16_t val) -{ -#ifdef DEBUG - printf("TAHVO write of %04x at %02x\n", val, reg); -#endif - - switch (reg) { - case TAHVO_REG_IDR: - s->irqst ^= val; - tahvo_interrupt_update(s); - break; - - case TAHVO_REG_IMR: - s->irqen = val; - tahvo_interrupt_update(s); - break; - - case TAHVO_REG_CHAPWMR: - s->charger = val; - break; - - case TAHVO_REG_LEDPWMR: - if (s->backlight != (val & 0x7f)) { - s->backlight = val & 0x7f; - printf("%s: LCD backlight now at %i / 127\n", - __FUNCTION__, s->backlight); - } - break; - - case TAHVO_REG_USBR: - s->usbr = val; - break; - - case TAHVO_REG_RCR: - s->power = val; - break; - - case TAHVO_REG_CCR1: - case TAHVO_REG_CCR2: - case TAHVO_REG_TESTR1: - case TAHVO_REG_TESTR2: - case TAHVO_REG_NOPR: - case TAHVO_REG_FRR: - break; - - default: - hw_error("%s: bad register %02x\n", __FUNCTION__, reg); - } -} - -static void tahvo_io(void *opaque, int rw, int reg, uint16_t *val) -{ - CBusTahvo *s = (CBusTahvo *) opaque; - - if (rw) - *val = tahvo_read(s, reg); - else - tahvo_write(s, reg, *val); -} - -void *tahvo_init(qemu_irq irq, int betty) -{ - CBusTahvo *s = (CBusTahvo *) g_malloc0(sizeof(*s)); - - s->irq = irq; - s->irqen = 0xffff; - s->irqst = 0x0000; - s->is_betty = !!betty; - - s->cbus.opaque = s; - s->cbus.io = tahvo_io; - s->cbus.addr = 2; - - return &s->cbus; -} diff --git a/hw/debugexit.c b/hw/debugexit.c deleted file mode 100644 index 59bed5bff5..0000000000 --- a/hw/debugexit.c +++ /dev/null @@ -1,75 +0,0 @@ -/* - * debug exit port emulation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 or - * (at your option) any later version. - */ - -#include "hw/hw.h" -#include "hw/isa/isa.h" - -#define TYPE_ISA_DEBUG_EXIT_DEVICE "isa-debug-exit" -#define ISA_DEBUG_EXIT_DEVICE(obj) \ - OBJECT_CHECK(ISADebugExitState, (obj), TYPE_ISA_DEBUG_EXIT_DEVICE) - -typedef struct ISADebugExitState { - ISADevice parent_obj; - - uint32_t iobase; - uint32_t iosize; - MemoryRegion io; -} ISADebugExitState; - -static void debug_exit_write(void *opaque, hwaddr addr, uint64_t val, - unsigned width) -{ - exit((val << 1) | 1); -} - -static const MemoryRegionOps debug_exit_ops = { - .write = debug_exit_write, - .valid.min_access_size = 1, - .valid.max_access_size = 4, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - -static int debug_exit_initfn(ISADevice *dev) -{ - ISADebugExitState *isa = ISA_DEBUG_EXIT_DEVICE(dev); - - memory_region_init_io(&isa->io, &debug_exit_ops, isa, - TYPE_ISA_DEBUG_EXIT_DEVICE, isa->iosize); - memory_region_add_subregion(isa_address_space_io(dev), - isa->iobase, &isa->io); - return 0; -} - -static Property debug_exit_properties[] = { - DEFINE_PROP_HEX32("iobase", ISADebugExitState, iobase, 0x501), - DEFINE_PROP_HEX32("iosize", ISADebugExitState, iosize, 0x02), - DEFINE_PROP_END_OF_LIST(), -}; - -static void debug_exit_class_initfn(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - ISADeviceClass *ic = ISA_DEVICE_CLASS(klass); - ic->init = debug_exit_initfn; - dc->props = debug_exit_properties; -} - -static const TypeInfo debug_exit_info = { - .name = TYPE_ISA_DEBUG_EXIT_DEVICE, - .parent = TYPE_ISA_DEVICE, - .instance_size = sizeof(ISADebugExitState), - .class_init = debug_exit_class_initfn, -}; - -static void debug_exit_register_types(void) -{ - type_register_static(&debug_exit_info); -} - -type_init(debug_exit_register_types) diff --git a/hw/eccmemctl.c b/hw/eccmemctl.c deleted file mode 100644 index 6f4a407cbf..0000000000 --- a/hw/eccmemctl.c +++ /dev/null @@ -1,340 +0,0 @@ -/* - * QEMU Sparc Sun4m ECC memory controller emulation - * - * Copyright (c) 2007 Robert Reif - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "hw/sysbus.h" -#include "trace.h" - -/* There are 3 versions of this chip used in SMP sun4m systems: - * MCC (version 0, implementation 0) SS-600MP - * EMC (version 0, implementation 1) SS-10 - * SMC (version 0, implementation 2) SS-10SX and SS-20 - * - * Chipset docs: - * "Sun-4M System Architecture (revision 2.0) by Chuck Narad", 950-1373-01, - * http://mediacast.sun.com/users/Barton808/media/Sun4M_SystemArchitecture_edited2.pdf - */ - -#define ECC_MCC 0x00000000 -#define ECC_EMC 0x10000000 -#define ECC_SMC 0x20000000 - -/* Register indexes */ -#define ECC_MER 0 /* Memory Enable Register */ -#define ECC_MDR 1 /* Memory Delay Register */ -#define ECC_MFSR 2 /* Memory Fault Status Register */ -#define ECC_VCR 3 /* Video Configuration Register */ -#define ECC_MFAR0 4 /* Memory Fault Address Register 0 */ -#define ECC_MFAR1 5 /* Memory Fault Address Register 1 */ -#define ECC_DR 6 /* Diagnostic Register */ -#define ECC_ECR0 7 /* Event Count Register 0 */ -#define ECC_ECR1 8 /* Event Count Register 1 */ - -/* ECC fault control register */ -#define ECC_MER_EE 0x00000001 /* Enable ECC checking */ -#define ECC_MER_EI 0x00000002 /* Enable Interrupts on - correctable errors */ -#define ECC_MER_MRR0 0x00000004 /* SIMM 0 */ -#define ECC_MER_MRR1 0x00000008 /* SIMM 1 */ -#define ECC_MER_MRR2 0x00000010 /* SIMM 2 */ -#define ECC_MER_MRR3 0x00000020 /* SIMM 3 */ -#define ECC_MER_MRR4 0x00000040 /* SIMM 4 */ -#define ECC_MER_MRR5 0x00000080 /* SIMM 5 */ -#define ECC_MER_MRR6 0x00000100 /* SIMM 6 */ -#define ECC_MER_MRR7 0x00000200 /* SIMM 7 */ -#define ECC_MER_REU 0x00000100 /* Memory Refresh Enable (600MP) */ -#define ECC_MER_MRR 0x000003fc /* MRR mask */ -#define ECC_MER_A 0x00000400 /* Memory controller addr map select */ -#define ECC_MER_DCI 0x00000800 /* Disables Coherent Invalidate ACK */ -#define ECC_MER_VER 0x0f000000 /* Version */ -#define ECC_MER_IMPL 0xf0000000 /* Implementation */ -#define ECC_MER_MASK_0 0x00000103 /* Version 0 (MCC) mask */ -#define ECC_MER_MASK_1 0x00000bff /* Version 1 (EMC) mask */ -#define ECC_MER_MASK_2 0x00000bff /* Version 2 (SMC) mask */ - -/* ECC memory delay register */ -#define ECC_MDR_RRI 0x000003ff /* Refresh Request Interval */ -#define ECC_MDR_MI 0x00001c00 /* MIH Delay */ -#define ECC_MDR_CI 0x0000e000 /* Coherent Invalidate Delay */ -#define ECC_MDR_MDL 0x001f0000 /* MBus Master arbitration delay */ -#define ECC_MDR_MDH 0x03e00000 /* MBus Master arbitration delay */ -#define ECC_MDR_GAD 0x7c000000 /* Graphics Arbitration Delay */ -#define ECC_MDR_RSC 0x80000000 /* Refresh load control */ -#define ECC_MDR_MASK 0x7fffffff - -/* ECC fault status register */ -#define ECC_MFSR_CE 0x00000001 /* Correctable error */ -#define ECC_MFSR_BS 0x00000002 /* C2 graphics bad slot access */ -#define ECC_MFSR_TO 0x00000004 /* Timeout on write */ -#define ECC_MFSR_UE 0x00000008 /* Uncorrectable error */ -#define ECC_MFSR_DW 0x000000f0 /* Index of double word in block */ -#define ECC_MFSR_SYND 0x0000ff00 /* Syndrome for correctable error */ -#define ECC_MFSR_ME 0x00010000 /* Multiple errors */ -#define ECC_MFSR_C2ERR 0x00020000 /* C2 graphics error */ - -/* ECC fault address register 0 */ -#define ECC_MFAR0_PADDR 0x0000000f /* PA[32-35] */ -#define ECC_MFAR0_TYPE 0x000000f0 /* Transaction type */ -#define ECC_MFAR0_SIZE 0x00000700 /* Transaction size */ -#define ECC_MFAR0_CACHE 0x00000800 /* Mapped cacheable */ -#define ECC_MFAR0_LOCK 0x00001000 /* Error occurred in atomic cycle */ -#define ECC_MFAR0_BMODE 0x00002000 /* Boot mode */ -#define ECC_MFAR0_VADDR 0x003fc000 /* VA[12-19] (superset bits) */ -#define ECC_MFAR0_S 0x08000000 /* Supervisor mode */ -#define ECC_MFARO_MID 0xf0000000 /* Module ID */ - -/* ECC diagnostic register */ -#define ECC_DR_CBX 0x00000001 -#define ECC_DR_CB0 0x00000002 -#define ECC_DR_CB1 0x00000004 -#define ECC_DR_CB2 0x00000008 -#define ECC_DR_CB4 0x00000010 -#define ECC_DR_CB8 0x00000020 -#define ECC_DR_CB16 0x00000040 -#define ECC_DR_CB32 0x00000080 -#define ECC_DR_DMODE 0x00000c00 - -#define ECC_NREGS 9 -#define ECC_SIZE (ECC_NREGS * sizeof(uint32_t)) - -#define ECC_DIAG_SIZE 4 -#define ECC_DIAG_MASK (ECC_DIAG_SIZE - 1) - -typedef struct ECCState { - SysBusDevice busdev; - MemoryRegion iomem, iomem_diag; - qemu_irq irq; - uint32_t regs[ECC_NREGS]; - uint8_t diag[ECC_DIAG_SIZE]; - uint32_t version; -} ECCState; - -static void ecc_mem_write(void *opaque, hwaddr addr, uint64_t val, - unsigned size) -{ - ECCState *s = opaque; - - switch (addr >> 2) { - case ECC_MER: - if (s->version == ECC_MCC) - s->regs[ECC_MER] = (val & ECC_MER_MASK_0); - else if (s->version == ECC_EMC) - s->regs[ECC_MER] = s->version | (val & ECC_MER_MASK_1); - else if (s->version == ECC_SMC) - s->regs[ECC_MER] = s->version | (val & ECC_MER_MASK_2); - trace_ecc_mem_writel_mer(val); - break; - case ECC_MDR: - s->regs[ECC_MDR] = val & ECC_MDR_MASK; - trace_ecc_mem_writel_mdr(val); - break; - case ECC_MFSR: - s->regs[ECC_MFSR] = val; - qemu_irq_lower(s->irq); - trace_ecc_mem_writel_mfsr(val); - break; - case ECC_VCR: - s->regs[ECC_VCR] = val; - trace_ecc_mem_writel_vcr(val); - break; - case ECC_DR: - s->regs[ECC_DR] = val; - trace_ecc_mem_writel_dr(val); - break; - case ECC_ECR0: - s->regs[ECC_ECR0] = val; - trace_ecc_mem_writel_ecr0(val); - break; - case ECC_ECR1: - s->regs[ECC_ECR0] = val; - trace_ecc_mem_writel_ecr1(val); - break; - } -} - -static uint64_t ecc_mem_read(void *opaque, hwaddr addr, - unsigned size) -{ - ECCState *s = opaque; - uint32_t ret = 0; - - switch (addr >> 2) { - case ECC_MER: - ret = s->regs[ECC_MER]; - trace_ecc_mem_readl_mer(ret); - break; - case ECC_MDR: - ret = s->regs[ECC_MDR]; - trace_ecc_mem_readl_mdr(ret); - break; - case ECC_MFSR: - ret = s->regs[ECC_MFSR]; - trace_ecc_mem_readl_mfsr(ret); - break; - case ECC_VCR: - ret = s->regs[ECC_VCR]; - trace_ecc_mem_readl_vcr(ret); - break; - case ECC_MFAR0: - ret = s->regs[ECC_MFAR0]; - trace_ecc_mem_readl_mfar0(ret); - break; - case ECC_MFAR1: - ret = s->regs[ECC_MFAR1]; - trace_ecc_mem_readl_mfar1(ret); - break; - case ECC_DR: - ret = s->regs[ECC_DR]; - trace_ecc_mem_readl_dr(ret); - break; - case ECC_ECR0: - ret = s->regs[ECC_ECR0]; - trace_ecc_mem_readl_ecr0(ret); - break; - case ECC_ECR1: - ret = s->regs[ECC_ECR0]; - trace_ecc_mem_readl_ecr1(ret); - break; - } - return ret; -} - -static const MemoryRegionOps ecc_mem_ops = { - .read = ecc_mem_read, - .write = ecc_mem_write, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, -}; - -static void ecc_diag_mem_write(void *opaque, hwaddr addr, - uint64_t val, unsigned size) -{ - ECCState *s = opaque; - - trace_ecc_diag_mem_writeb(addr, val); - s->diag[addr & ECC_DIAG_MASK] = val; -} - -static uint64_t ecc_diag_mem_read(void *opaque, hwaddr addr, - unsigned size) -{ - ECCState *s = opaque; - uint32_t ret = s->diag[(int)addr]; - - trace_ecc_diag_mem_readb(addr, ret); - return ret; -} - -static const MemoryRegionOps ecc_diag_mem_ops = { - .read = ecc_diag_mem_read, - .write = ecc_diag_mem_write, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 1, - .max_access_size = 1, - }, -}; - -static const VMStateDescription vmstate_ecc = { - .name ="ECC", - .version_id = 3, - .minimum_version_id = 3, - .minimum_version_id_old = 3, - .fields = (VMStateField []) { - VMSTATE_UINT32_ARRAY(regs, ECCState, ECC_NREGS), - VMSTATE_BUFFER(diag, ECCState), - VMSTATE_UINT32(version, ECCState), - VMSTATE_END_OF_LIST() - } -}; - -static void ecc_reset(DeviceState *d) -{ - ECCState *s = container_of(d, ECCState, busdev.qdev); - - if (s->version == ECC_MCC) - s->regs[ECC_MER] &= ECC_MER_REU; - else - s->regs[ECC_MER] &= (ECC_MER_VER | ECC_MER_IMPL | ECC_MER_MRR | - ECC_MER_DCI); - s->regs[ECC_MDR] = 0x20; - s->regs[ECC_MFSR] = 0; - s->regs[ECC_VCR] = 0; - s->regs[ECC_MFAR0] = 0x07c00000; - s->regs[ECC_MFAR1] = 0; - s->regs[ECC_DR] = 0; - s->regs[ECC_ECR0] = 0; - s->regs[ECC_ECR1] = 0; -} - -static int ecc_init1(SysBusDevice *dev) -{ - ECCState *s = FROM_SYSBUS(ECCState, dev); - - sysbus_init_irq(dev, &s->irq); - s->regs[0] = s->version; - memory_region_init_io(&s->iomem, &ecc_mem_ops, s, "ecc", ECC_SIZE); - sysbus_init_mmio(dev, &s->iomem); - - if (s->version == ECC_MCC) { // SS-600MP only - memory_region_init_io(&s->iomem_diag, &ecc_diag_mem_ops, s, - "ecc.diag", ECC_DIAG_SIZE); - sysbus_init_mmio(dev, &s->iomem_diag); - } - - return 0; -} - -static Property ecc_properties[] = { - DEFINE_PROP_HEX32("version", ECCState, version, -1), - DEFINE_PROP_END_OF_LIST(), -}; - -static void ecc_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = ecc_init1; - dc->reset = ecc_reset; - dc->vmsd = &vmstate_ecc; - dc->props = ecc_properties; -} - -static const TypeInfo ecc_info = { - .name = "eccmemctl", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(ECCState), - .class_init = ecc_class_init, -}; - - -static void ecc_register_types(void) -{ - type_register_static(&ecc_info); -} - -type_init(ecc_register_types) diff --git a/hw/exynos4210_pmu.c b/hw/exynos4210_pmu.c deleted file mode 100644 index ba5aa8d0e4..0000000000 --- a/hw/exynos4210_pmu.c +++ /dev/null @@ -1,499 +0,0 @@ -/* - * Exynos4210 Power Management Unit (PMU) Emulation - * - * Copyright (C) 2011 Samsung Electronics Co Ltd. - * Maksim Kozlov - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . - */ - -/* - * This model implements PMU registers just as a bulk of memory. Currently, - * the only reason this device exists is that secondary CPU boot loader - * uses PMU INFORM5 register as a holding pen. - */ - -#include "hw/sysbus.h" - -#ifndef DEBUG_PMU -#define DEBUG_PMU 0 -#endif - -#ifndef DEBUG_PMU_EXTEND -#define DEBUG_PMU_EXTEND 0 -#endif - -#if DEBUG_PMU -#define PRINT_DEBUG(fmt, args...) \ - do { \ - fprintf(stderr, " [%s:%d] "fmt, __func__, __LINE__, ##args); \ - } while (0) - -#if DEBUG_PMU_EXTEND -#define PRINT_DEBUG_EXTEND(fmt, args...) \ - do { \ - fprintf(stderr, " [%s:%d] "fmt, __func__, __LINE__, ##args); \ - } while (0) -#else -#define PRINT_DEBUG_EXTEND(fmt, args...) do {} while (0) -#endif /* EXTEND */ - -#else -#define PRINT_DEBUG(fmt, args...) do {} while (0) -#define PRINT_DEBUG_EXTEND(fmt, args...) do {} while (0) -#endif - -/* - * Offsets for PMU registers - */ -#define OM_STAT 0x0000 /* OM status register */ -#define RTC_CLKO_SEL 0x000C /* Controls RTCCLKOUT */ -#define GNSS_RTC_OUT_CTRL 0x0010 /* Controls GNSS_RTC_OUT */ -/* Decides whether system-level low-power mode is used. */ -#define SYSTEM_POWER_DOWN_CTRL 0x0200 -/* Sets control options for CENTRAL_SEQ */ -#define SYSTEM_POWER_DOWN_OPTION 0x0208 -#define SWRESET 0x0400 /* Generate software reset */ -#define RST_STAT 0x0404 /* Reset status register */ -#define WAKEUP_STAT 0x0600 /* Wakeup status register */ -#define EINT_WAKEUP_MASK 0x0604 /* Configure External INTerrupt mask */ -#define WAKEUP_MASK 0x0608 /* Configure wakeup source mask */ -#define HDMI_PHY_CONTROL 0x0700 /* HDMI PHY control register */ -#define USBDEVICE_PHY_CONTROL 0x0704 /* USB Device PHY control register */ -#define USBHOST_PHY_CONTROL 0x0708 /* USB HOST PHY control register */ -#define DAC_PHY_CONTROL 0x070C /* DAC control register */ -#define MIPI_PHY0_CONTROL 0x0710 /* MIPI PHY control register */ -#define MIPI_PHY1_CONTROL 0x0714 /* MIPI PHY control register */ -#define ADC_PHY_CONTROL 0x0718 /* TS-ADC control register */ -#define PCIe_PHY_CONTROL 0x071C /* TS-PCIe control register */ -#define SATA_PHY_CONTROL 0x0720 /* TS-SATA control register */ -#define INFORM0 0x0800 /* Information register 0 */ -#define INFORM1 0x0804 /* Information register 1 */ -#define INFORM2 0x0808 /* Information register 2 */ -#define INFORM3 0x080C /* Information register 3 */ -#define INFORM4 0x0810 /* Information register 4 */ -#define INFORM5 0x0814 /* Information register 5 */ -#define INFORM6 0x0818 /* Information register 6 */ -#define INFORM7 0x081C /* Information register 7 */ -#define PMU_DEBUG 0x0A00 /* PMU debug register */ -/* Registers to set system-level low-power option */ -#define ARM_CORE0_SYS_PWR_REG 0x1000 -#define ARM_CORE1_SYS_PWR_REG 0x1010 -#define ARM_COMMON_SYS_PWR_REG 0x1080 -#define ARM_CPU_L2_0_SYS_PWR_REG 0x10C0 -#define ARM_CPU_L2_1_SYS_PWR_REG 0x10C4 -#define CMU_ACLKSTOP_SYS_PWR_REG 0x1100 -#define CMU_SCLKSTOP_SYS_PWR_REG 0x1104 -#define CMU_RESET_SYS_PWR_REG 0x110C -#define APLL_SYSCLK_SYS_PWR_REG 0x1120 -#define MPLL_SYSCLK_SYS_PWR_REG 0x1124 -#define VPLL_SYSCLK_SYS_PWR_REG 0x1128 -#define EPLL_SYSCLK_SYS_PWR_REG 0x112C -#define CMU_CLKSTOP_GPS_ALIVE_SYS_PWR_REG 0x1138 -#define CMU_RESET_GPS_ALIVE_SYS_PWR_REG 0x113C -#define CMU_CLKSTOP_CAM_SYS_PWR_REG 0x1140 -#define CMU_CLKSTOP_TV_SYS_PWR_REG 0x1144 -#define CMU_CLKSTOP_MFC_SYS_PWR_REG 0x1148 -#define CMU_CLKSTOP_G3D_SYS_PWR_REG 0x114C -#define CMU_CLKSTOP_LCD0_SYS_PWR_REG 0x1150 -#define CMU_CLKSTOP_LCD1_SYS_PWR_REG 0x1154 -#define CMU_CLKSTOP_MAUDIO_SYS_PWR_REG 0x1158 -#define CMU_CLKSTOP_GPS_SYS_PWR_REG 0x115C -#define CMU_RESET_CAM_SYS_PWR_REG 0x1160 -#define CMU_RESET_TV_SYS_PWR_REG 0x1164 -#define CMU_RESET_MFC_SYS_PWR_REG 0x1168 -#define CMU_RESET_G3D_SYS_PWR_REG 0x116C -#define CMU_RESET_LCD0_SYS_PWR_REG 0x1170 -#define CMU_RESET_LCD1_SYS_PWR_REG 0x1174 -#define CMU_RESET_MAUDIO_SYS_PWR_REG 0x1178 -#define CMU_RESET_GPS_SYS_PWR_REG 0x117C -#define TOP_BUS_SYS_PWR_REG 0x1180 -#define TOP_RETENTION_SYS_PWR_REG 0x1184 -#define TOP_PWR_SYS_PWR_REG 0x1188 -#define LOGIC_RESET_SYS_PWR_REG 0x11A0 -#define OneNANDXL_MEM_SYS_PWR_REG 0x11C0 -#define MODEMIF_MEM_SYS_PWR_REG 0x11C4 -#define USBDEVICE_MEM_SYS_PWR_REG 0x11CC -#define SDMMC_MEM_SYS_PWR_REG 0x11D0 -#define CSSYS_MEM_SYS_PWR_REG 0x11D4 -#define SECSS_MEM_SYS_PWR_REG 0x11D8 -#define PCIe_MEM_SYS_PWR_REG 0x11E0 -#define SATA_MEM_SYS_PWR_REG 0x11E4 -#define PAD_RETENTION_DRAM_SYS_PWR_REG 0x1200 -#define PAD_RETENTION_MAUDIO_SYS_PWR_REG 0x1204 -#define PAD_RETENTION_GPIO_SYS_PWR_REG 0x1220 -#define PAD_RETENTION_UART_SYS_PWR_REG 0x1224 -#define PAD_RETENTION_MMCA_SYS_PWR_REG 0x1228 -#define PAD_RETENTION_MMCB_SYS_PWR_REG 0x122C -#define PAD_RETENTION_EBIA_SYS_PWR_REG 0x1230 -#define PAD_RETENTION_EBIB_SYS_PWR_REG 0x1234 -#define PAD_ISOLATION_SYS_PWR_REG 0x1240 -#define PAD_ALV_SEL_SYS_PWR_REG 0x1260 -#define XUSBXTI_SYS_PWR_REG 0x1280 -#define XXTI_SYS_PWR_REG 0x1284 -#define EXT_REGULATOR_SYS_PWR_REG 0x12C0 -#define GPIO_MODE_SYS_PWR_REG 0x1300 -#define GPIO_MODE_MAUDIO_SYS_PWR_REG 0x1340 -#define CAM_SYS_PWR_REG 0x1380 -#define TV_SYS_PWR_REG 0x1384 -#define MFC_SYS_PWR_REG 0x1388 -#define G3D_SYS_PWR_REG 0x138C -#define LCD0_SYS_PWR_REG 0x1390 -#define LCD1_SYS_PWR_REG 0x1394 -#define MAUDIO_SYS_PWR_REG 0x1398 -#define GPS_SYS_PWR_REG 0x139C -#define GPS_ALIVE_SYS_PWR_REG 0x13A0 -#define ARM_CORE0_CONFIGURATION 0x2000 /* Configure power mode of ARM_CORE0 */ -#define ARM_CORE0_STATUS 0x2004 /* Check power mode of ARM_CORE0 */ -#define ARM_CORE0_OPTION 0x2008 /* Sets control options for ARM_CORE0 */ -#define ARM_CORE1_CONFIGURATION 0x2080 /* Configure power mode of ARM_CORE1 */ -#define ARM_CORE1_STATUS 0x2084 /* Check power mode of ARM_CORE1 */ -#define ARM_CORE1_OPTION 0x2088 /* Sets control options for ARM_CORE0 */ -#define ARM_COMMON_OPTION 0x2408 /* Sets control options for ARM_COMMON */ -/* Configure power mode of ARM_CPU_L2_0 */ -#define ARM_CPU_L2_0_CONFIGURATION 0x2600 -#define ARM_CPU_L2_0_STATUS 0x2604 /* Check power mode of ARM_CPU_L2_0 */ -/* Configure power mode of ARM_CPU_L2_1 */ -#define ARM_CPU_L2_1_CONFIGURATION 0x2620 -#define ARM_CPU_L2_1_STATUS 0x2624 /* Check power mode of ARM_CPU_L2_1 */ -/* Sets control options for PAD_RETENTION_MAUDIO */ -#define PAD_RETENTION_MAUDIO_OPTION 0x3028 -/* Sets control options for PAD_RETENTION_GPIO */ -#define PAD_RETENTION_GPIO_OPTION 0x3108 -/* Sets control options for PAD_RETENTION_UART */ -#define PAD_RETENTION_UART_OPTION 0x3128 -/* Sets control options for PAD_RETENTION_MMCA */ -#define PAD_RETENTION_MMCA_OPTION 0x3148 -/* Sets control options for PAD_RETENTION_MMCB */ -#define PAD_RETENTION_MMCB_OPTION 0x3168 -/* Sets control options for PAD_RETENTION_EBIA */ -#define PAD_RETENTION_EBIA_OPTION 0x3188 -/* Sets control options for PAD_RETENTION_EBIB */ -#define PAD_RETENTION_EBIB_OPTION 0x31A8 -#define PS_HOLD_CONTROL 0x330C /* PS_HOLD control register */ -#define XUSBXTI_CONFIGURATION 0x3400 /* Configure the pad of XUSBXTI */ -#define XUSBXTI_STATUS 0x3404 /* Check the pad of XUSBXTI */ -/* Sets time required for XUSBXTI to be stabilized */ -#define XUSBXTI_DURATION 0x341C -#define XXTI_CONFIGURATION 0x3420 /* Configure the pad of XXTI */ -#define XXTI_STATUS 0x3424 /* Check the pad of XXTI */ -/* Sets time required for XXTI to be stabilized */ -#define XXTI_DURATION 0x343C -/* Sets time required for EXT_REGULATOR to be stabilized */ -#define EXT_REGULATOR_DURATION 0x361C -#define CAM_CONFIGURATION 0x3C00 /* Configure power mode of CAM */ -#define CAM_STATUS 0x3C04 /* Check power mode of CAM */ -#define CAM_OPTION 0x3C08 /* Sets control options for CAM */ -#define TV_CONFIGURATION 0x3C20 /* Configure power mode of TV */ -#define TV_STATUS 0x3C24 /* Check power mode of TV */ -#define TV_OPTION 0x3C28 /* Sets control options for TV */ -#define MFC_CONFIGURATION 0x3C40 /* Configure power mode of MFC */ -#define MFC_STATUS 0x3C44 /* Check power mode of MFC */ -#define MFC_OPTION 0x3C48 /* Sets control options for MFC */ -#define G3D_CONFIGURATION 0x3C60 /* Configure power mode of G3D */ -#define G3D_STATUS 0x3C64 /* Check power mode of G3D */ -#define G3D_OPTION 0x3C68 /* Sets control options for G3D */ -#define LCD0_CONFIGURATION 0x3C80 /* Configure power mode of LCD0 */ -#define LCD0_STATUS 0x3C84 /* Check power mode of LCD0 */ -#define LCD0_OPTION 0x3C88 /* Sets control options for LCD0 */ -#define LCD1_CONFIGURATION 0x3CA0 /* Configure power mode of LCD1 */ -#define LCD1_STATUS 0x3CA4 /* Check power mode of LCD1 */ -#define LCD1_OPTION 0x3CA8 /* Sets control options for LCD1 */ -#define GPS_CONFIGURATION 0x3CE0 /* Configure power mode of GPS */ -#define GPS_STATUS 0x3CE4 /* Check power mode of GPS */ -#define GPS_OPTION 0x3CE8 /* Sets control options for GPS */ -#define GPS_ALIVE_CONFIGURATION 0x3D00 /* Configure power mode of GPS */ -#define GPS_ALIVE_STATUS 0x3D04 /* Check power mode of GPS */ -#define GPS_ALIVE_OPTION 0x3D08 /* Sets control options for GPS */ - -#define EXYNOS4210_PMU_REGS_MEM_SIZE 0x3d0c - -typedef struct Exynos4210PmuReg { - const char *name; /* for debug only */ - uint32_t offset; - uint32_t reset_value; -} Exynos4210PmuReg; - -static const Exynos4210PmuReg exynos4210_pmu_regs[] = { - {"OM_STAT", OM_STAT, 0x00000000}, - {"RTC_CLKO_SEL", RTC_CLKO_SEL, 0x00000000}, - {"GNSS_RTC_OUT_CTRL", GNSS_RTC_OUT_CTRL, 0x00000001}, - {"SYSTEM_POWER_DOWN_CTRL", SYSTEM_POWER_DOWN_CTRL, 0x00010000}, - {"SYSTEM_POWER_DOWN_OPTION", SYSTEM_POWER_DOWN_OPTION, 0x03030000}, - {"SWRESET", SWRESET, 0x00000000}, - {"RST_STAT", RST_STAT, 0x00000000}, - {"WAKEUP_STAT", WAKEUP_STAT, 0x00000000}, - {"EINT_WAKEUP_MASK", EINT_WAKEUP_MASK, 0x00000000}, - {"WAKEUP_MASK", WAKEUP_MASK, 0x00000000}, - {"HDMI_PHY_CONTROL", HDMI_PHY_CONTROL, 0x00960000}, - {"USBDEVICE_PHY_CONTROL", USBDEVICE_PHY_CONTROL, 0x00000000}, - {"USBHOST_PHY_CONTROL", USBHOST_PHY_CONTROL, 0x00000000}, - {"DAC_PHY_CONTROL", DAC_PHY_CONTROL, 0x00000000}, - {"MIPI_PHY0_CONTROL", MIPI_PHY0_CONTROL, 0x00000000}, - {"MIPI_PHY1_CONTROL", MIPI_PHY1_CONTROL, 0x00000000}, - {"ADC_PHY_CONTROL", ADC_PHY_CONTROL, 0x00000001}, - {"PCIe_PHY_CONTROL", PCIe_PHY_CONTROL, 0x00000000}, - {"SATA_PHY_CONTROL", SATA_PHY_CONTROL, 0x00000000}, - {"INFORM0", INFORM0, 0x00000000}, - {"INFORM1", INFORM1, 0x00000000}, - {"INFORM2", INFORM2, 0x00000000}, - {"INFORM3", INFORM3, 0x00000000}, - {"INFORM4", INFORM4, 0x00000000}, - {"INFORM5", INFORM5, 0x00000000}, - {"INFORM6", INFORM6, 0x00000000}, - {"INFORM7", INFORM7, 0x00000000}, - {"PMU_DEBUG", PMU_DEBUG, 0x00000000}, - {"ARM_CORE0_SYS_PWR_REG", ARM_CORE0_SYS_PWR_REG, 0xFFFFFFFF}, - {"ARM_CORE1_SYS_PWR_REG", ARM_CORE1_SYS_PWR_REG, 0xFFFFFFFF}, - {"ARM_COMMON_SYS_PWR_REG", ARM_COMMON_SYS_PWR_REG, 0xFFFFFFFF}, - {"ARM_CPU_L2_0_SYS_PWR_REG", ARM_CPU_L2_0_SYS_PWR_REG, 0xFFFFFFFF}, - {"ARM_CPU_L2_1_SYS_PWR_REG", ARM_CPU_L2_1_SYS_PWR_REG, 0xFFFFFFFF}, - {"CMU_ACLKSTOP_SYS_PWR_REG", CMU_ACLKSTOP_SYS_PWR_REG, 0xFFFFFFFF}, - {"CMU_SCLKSTOP_SYS_PWR_REG", CMU_SCLKSTOP_SYS_PWR_REG, 0xFFFFFFFF}, - {"CMU_RESET_SYS_PWR_REG", CMU_RESET_SYS_PWR_REG, 0xFFFFFFFF}, - {"APLL_SYSCLK_SYS_PWR_REG", APLL_SYSCLK_SYS_PWR_REG, 0xFFFFFFFF}, - {"MPLL_SYSCLK_SYS_PWR_REG", MPLL_SYSCLK_SYS_PWR_REG, 0xFFFFFFFF}, - {"VPLL_SYSCLK_SYS_PWR_REG", VPLL_SYSCLK_SYS_PWR_REG, 0xFFFFFFFF}, - {"EPLL_SYSCLK_SYS_PWR_REG", EPLL_SYSCLK_SYS_PWR_REG, 0xFFFFFFFF}, - {"CMU_CLKSTOP_GPS_ALIVE_SYS_PWR_REG", CMU_CLKSTOP_GPS_ALIVE_SYS_PWR_REG, - 0xFFFFFFFF}, - {"CMU_RESET_GPS_ALIVE_SYS_PWR_REG", CMU_RESET_GPS_ALIVE_SYS_PWR_REG, - 0xFFFFFFFF}, - {"CMU_CLKSTOP_CAM_SYS_PWR_REG", CMU_CLKSTOP_CAM_SYS_PWR_REG, 0xFFFFFFFF}, - {"CMU_CLKSTOP_TV_SYS_PWR_REG", CMU_CLKSTOP_TV_SYS_PWR_REG, 0xFFFFFFFF}, - {"CMU_CLKSTOP_MFC_SYS_PWR_REG", CMU_CLKSTOP_MFC_SYS_PWR_REG, 0xFFFFFFFF}, - {"CMU_CLKSTOP_G3D_SYS_PWR_REG", CMU_CLKSTOP_G3D_SYS_PWR_REG, 0xFFFFFFFF}, - {"CMU_CLKSTOP_LCD0_SYS_PWR_REG", CMU_CLKSTOP_LCD0_SYS_PWR_REG, 0xFFFFFFFF}, - {"CMU_CLKSTOP_LCD1_SYS_PWR_REG", CMU_CLKSTOP_LCD1_SYS_PWR_REG, 0xFFFFFFFF}, - {"CMU_CLKSTOP_MAUDIO_SYS_PWR_REG", CMU_CLKSTOP_MAUDIO_SYS_PWR_REG, - 0xFFFFFFFF}, - {"CMU_CLKSTOP_GPS_SYS_PWR_REG", CMU_CLKSTOP_GPS_SYS_PWR_REG, 0xFFFFFFFF}, - {"CMU_RESET_CAM_SYS_PWR_REG", CMU_RESET_CAM_SYS_PWR_REG, 0xFFFFFFFF}, - {"CMU_RESET_TV_SYS_PWR_REG", CMU_RESET_TV_SYS_PWR_REG, 0xFFFFFFFF}, - {"CMU_RESET_MFC_SYS_PWR_REG", CMU_RESET_MFC_SYS_PWR_REG, 0xFFFFFFFF}, - {"CMU_RESET_G3D_SYS_PWR_REG", CMU_RESET_G3D_SYS_PWR_REG, 0xFFFFFFFF}, - {"CMU_RESET_LCD0_SYS_PWR_REG", CMU_RESET_LCD0_SYS_PWR_REG, 0xFFFFFFFF}, - {"CMU_RESET_LCD1_SYS_PWR_REG", CMU_RESET_LCD1_SYS_PWR_REG, 0xFFFFFFFF}, - {"CMU_RESET_MAUDIO_SYS_PWR_REG", CMU_RESET_MAUDIO_SYS_PWR_REG, 0xFFFFFFFF}, - {"CMU_RESET_GPS_SYS_PWR_REG", CMU_RESET_GPS_SYS_PWR_REG, 0xFFFFFFFF}, - {"TOP_BUS_SYS_PWR_REG", TOP_BUS_SYS_PWR_REG, 0xFFFFFFFF}, - {"TOP_RETENTION_SYS_PWR_REG", TOP_RETENTION_SYS_PWR_REG, 0xFFFFFFFF}, - {"TOP_PWR_SYS_PWR_REG", TOP_PWR_SYS_PWR_REG, 0xFFFFFFFF}, - {"LOGIC_RESET_SYS_PWR_REG", LOGIC_RESET_SYS_PWR_REG, 0xFFFFFFFF}, - {"OneNANDXL_MEM_SYS_PWR_REG", OneNANDXL_MEM_SYS_PWR_REG, 0xFFFFFFFF}, - {"MODEMIF_MEM_SYS_PWR_REG", MODEMIF_MEM_SYS_PWR_REG, 0xFFFFFFFF}, - {"USBDEVICE_MEM_SYS_PWR_REG", USBDEVICE_MEM_SYS_PWR_REG, 0xFFFFFFFF}, - {"SDMMC_MEM_SYS_PWR_REG", SDMMC_MEM_SYS_PWR_REG, 0xFFFFFFFF}, - {"CSSYS_MEM_SYS_PWR_REG", CSSYS_MEM_SYS_PWR_REG, 0xFFFFFFFF}, - {"SECSS_MEM_SYS_PWR_REG", SECSS_MEM_SYS_PWR_REG, 0xFFFFFFFF}, - {"PCIe_MEM_SYS_PWR_REG", PCIe_MEM_SYS_PWR_REG, 0xFFFFFFFF}, - {"SATA_MEM_SYS_PWR_REG", SATA_MEM_SYS_PWR_REG, 0xFFFFFFFF}, - {"PAD_RETENTION_DRAM_SYS_PWR_REG", PAD_RETENTION_DRAM_SYS_PWR_REG, - 0xFFFFFFFF}, - {"PAD_RETENTION_MAUDIO_SYS_PWR_REG", PAD_RETENTION_MAUDIO_SYS_PWR_REG, - 0xFFFFFFFF}, - {"PAD_RETENTION_GPIO_SYS_PWR_REG", PAD_RETENTION_GPIO_SYS_PWR_REG, - 0xFFFFFFFF}, - {"PAD_RETENTION_UART_SYS_PWR_REG", PAD_RETENTION_UART_SYS_PWR_REG, - 0xFFFFFFFF}, - {"PAD_RETENTION_MMCA_SYS_PWR_REG", PAD_RETENTION_MMCA_SYS_PWR_REG, - 0xFFFFFFFF}, - {"PAD_RETENTION_MMCB_SYS_PWR_REG", PAD_RETENTION_MMCB_SYS_PWR_REG, - 0xFFFFFFFF}, - {"PAD_RETENTION_EBIA_SYS_PWR_REG", PAD_RETENTION_EBIA_SYS_PWR_REG, - 0xFFFFFFFF}, - {"PAD_RETENTION_EBIB_SYS_PWR_REG", PAD_RETENTION_EBIB_SYS_PWR_REG, - 0xFFFFFFFF}, - {"PAD_ISOLATION_SYS_PWR_REG", PAD_ISOLATION_SYS_PWR_REG, 0xFFFFFFFF}, - {"PAD_ALV_SEL_SYS_PWR_REG", PAD_ALV_SEL_SYS_PWR_REG, 0xFFFFFFFF}, - {"XUSBXTI_SYS_PWR_REG", XUSBXTI_SYS_PWR_REG, 0xFFFFFFFF}, - {"XXTI_SYS_PWR_REG", XXTI_SYS_PWR_REG, 0xFFFFFFFF}, - {"EXT_REGULATOR_SYS_PWR_REG", EXT_REGULATOR_SYS_PWR_REG, 0xFFFFFFFF}, - {"GPIO_MODE_SYS_PWR_REG", GPIO_MODE_SYS_PWR_REG, 0xFFFFFFFF}, - {"GPIO_MODE_MAUDIO_SYS_PWR_REG", GPIO_MODE_MAUDIO_SYS_PWR_REG, 0xFFFFFFFF}, - {"CAM_SYS_PWR_REG", CAM_SYS_PWR_REG, 0xFFFFFFFF}, - {"TV_SYS_PWR_REG", TV_SYS_PWR_REG, 0xFFFFFFFF}, - {"MFC_SYS_PWR_REG", MFC_SYS_PWR_REG, 0xFFFFFFFF}, - {"G3D_SYS_PWR_REG", G3D_SYS_PWR_REG, 0xFFFFFFFF}, - {"LCD0_SYS_PWR_REG", LCD0_SYS_PWR_REG, 0xFFFFFFFF}, - {"LCD1_SYS_PWR_REG", LCD1_SYS_PWR_REG, 0xFFFFFFFF}, - {"MAUDIO_SYS_PWR_REG", MAUDIO_SYS_PWR_REG, 0xFFFFFFFF}, - {"GPS_SYS_PWR_REG", GPS_SYS_PWR_REG, 0xFFFFFFFF}, - {"GPS_ALIVE_SYS_PWR_REG", GPS_ALIVE_SYS_PWR_REG, 0xFFFFFFFF}, - {"ARM_CORE0_CONFIGURATION", ARM_CORE0_CONFIGURATION, 0x00000003}, - {"ARM_CORE0_STATUS", ARM_CORE0_STATUS, 0x00030003}, - {"ARM_CORE0_OPTION", ARM_CORE0_OPTION, 0x01010001}, - {"ARM_CORE1_CONFIGURATION", ARM_CORE1_CONFIGURATION, 0x00000003}, - {"ARM_CORE1_STATUS", ARM_CORE1_STATUS, 0x00030003}, - {"ARM_CORE1_OPTION", ARM_CORE1_OPTION, 0x01010001}, - {"ARM_COMMON_OPTION", ARM_COMMON_OPTION, 0x00000001}, - {"ARM_CPU_L2_0_CONFIGURATION", ARM_CPU_L2_0_CONFIGURATION, 0x00000003}, - {"ARM_CPU_L2_0_STATUS", ARM_CPU_L2_0_STATUS, 0x00000003}, - {"ARM_CPU_L2_1_CONFIGURATION", ARM_CPU_L2_1_CONFIGURATION, 0x00000003}, - {"ARM_CPU_L2_1_STATUS", ARM_CPU_L2_1_STATUS, 0x00000003}, - {"PAD_RETENTION_MAUDIO_OPTION", PAD_RETENTION_MAUDIO_OPTION, 0x00000000}, - {"PAD_RETENTION_GPIO_OPTION", PAD_RETENTION_GPIO_OPTION, 0x00000000}, - {"PAD_RETENTION_UART_OPTION", PAD_RETENTION_UART_OPTION, 0x00000000}, - {"PAD_RETENTION_MMCA_OPTION", PAD_RETENTION_MMCA_OPTION, 0x00000000}, - {"PAD_RETENTION_MMCB_OPTION", PAD_RETENTION_MMCB_OPTION, 0x00000000}, - {"PAD_RETENTION_EBIA_OPTION", PAD_RETENTION_EBIA_OPTION, 0x00000000}, - {"PAD_RETENTION_EBIB_OPTION", PAD_RETENTION_EBIB_OPTION, 0x00000000}, - {"PS_HOLD_CONTROL", PS_HOLD_CONTROL, 0x00005200}, - {"XUSBXTI_CONFIGURATION", XUSBXTI_CONFIGURATION, 0x00000001}, - {"XUSBXTI_STATUS", XUSBXTI_STATUS, 0x00000001}, - {"XUSBXTI_DURATION", XUSBXTI_DURATION, 0xFFF00000}, - {"XXTI_CONFIGURATION", XXTI_CONFIGURATION, 0x00000001}, - {"XXTI_STATUS", XXTI_STATUS, 0x00000001}, - {"XXTI_DURATION", XXTI_DURATION, 0xFFF00000}, - {"EXT_REGULATOR_DURATION", EXT_REGULATOR_DURATION, 0xFFF03FFF}, - {"CAM_CONFIGURATION", CAM_CONFIGURATION, 0x00000007}, - {"CAM_STATUS", CAM_STATUS, 0x00060007}, - {"CAM_OPTION", CAM_OPTION, 0x00000001}, - {"TV_CONFIGURATION", TV_CONFIGURATION, 0x00000007}, - {"TV_STATUS", TV_STATUS, 0x00060007}, - {"TV_OPTION", TV_OPTION, 0x00000001}, - {"MFC_CONFIGURATION", MFC_CONFIGURATION, 0x00000007}, - {"MFC_STATUS", MFC_STATUS, 0x00060007}, - {"MFC_OPTION", MFC_OPTION, 0x00000001}, - {"G3D_CONFIGURATION", G3D_CONFIGURATION, 0x00000007}, - {"G3D_STATUS", G3D_STATUS, 0x00060007}, - {"G3D_OPTION", G3D_OPTION, 0x00000001}, - {"LCD0_CONFIGURATION", LCD0_CONFIGURATION, 0x00000007}, - {"LCD0_STATUS", LCD0_STATUS, 0x00060007}, - {"LCD0_OPTION", LCD0_OPTION, 0x00000001}, - {"LCD1_CONFIGURATION", LCD1_CONFIGURATION, 0x00000007}, - {"LCD1_STATUS", LCD1_STATUS, 0x00060007}, - {"LCD1_OPTION", LCD1_OPTION, 0x00000001}, - {"GPS_CONFIGURATION", GPS_CONFIGURATION, 0x00000007}, - {"GPS_STATUS", GPS_STATUS, 0x00060007}, - {"GPS_OPTION", GPS_OPTION, 0x00000001}, - {"GPS_ALIVE_CONFIGURATION", GPS_ALIVE_CONFIGURATION, 0x00000007}, - {"GPS_ALIVE_STATUS", GPS_ALIVE_STATUS, 0x00060007}, - {"GPS_ALIVE_OPTION", GPS_ALIVE_OPTION, 0x00000001}, -}; - -#define PMU_NUM_OF_REGISTERS \ - (sizeof(exynos4210_pmu_regs) / sizeof(Exynos4210PmuReg)) - -typedef struct Exynos4210PmuState { - SysBusDevice busdev; - MemoryRegion iomem; - uint32_t reg[PMU_NUM_OF_REGISTERS]; -} Exynos4210PmuState; - -static uint64_t exynos4210_pmu_read(void *opaque, hwaddr offset, - unsigned size) -{ - Exynos4210PmuState *s = (Exynos4210PmuState *)opaque; - unsigned i; - const Exynos4210PmuReg *reg_p = exynos4210_pmu_regs; - - for (i = 0; i < PMU_NUM_OF_REGISTERS; i++) { - if (reg_p->offset == offset) { - PRINT_DEBUG_EXTEND("%s [0x%04x] -> 0x%04x\n", reg_p->name, - (uint32_t)offset, s->reg[i]); - return s->reg[i]; - } - reg_p++; - } - PRINT_DEBUG("QEMU PMU ERROR: bad read offset 0x%04x\n", (uint32_t)offset); - return 0; -} - -static void exynos4210_pmu_write(void *opaque, hwaddr offset, - uint64_t val, unsigned size) -{ - Exynos4210PmuState *s = (Exynos4210PmuState *)opaque; - unsigned i; - const Exynos4210PmuReg *reg_p = exynos4210_pmu_regs; - - for (i = 0; i < PMU_NUM_OF_REGISTERS; i++) { - if (reg_p->offset == offset) { - PRINT_DEBUG_EXTEND("%s <0x%04x> <- 0x%04x\n", reg_p->name, - (uint32_t)offset, (uint32_t)val); - s->reg[i] = val; - return; - } - reg_p++; - } - PRINT_DEBUG("QEMU PMU ERROR: bad write offset 0x%04x\n", (uint32_t)offset); -} - -static const MemoryRegionOps exynos4210_pmu_ops = { - .read = exynos4210_pmu_read, - .write = exynos4210_pmu_write, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - .unaligned = false - } -}; - -static void exynos4210_pmu_reset(DeviceState *dev) -{ - Exynos4210PmuState *s = - container_of(dev, Exynos4210PmuState, busdev.qdev); - unsigned i; - - /* Set default values for registers */ - for (i = 0; i < PMU_NUM_OF_REGISTERS; i++) { - s->reg[i] = exynos4210_pmu_regs[i].reset_value; - } -} - -static int exynos4210_pmu_init(SysBusDevice *dev) -{ - Exynos4210PmuState *s = FROM_SYSBUS(Exynos4210PmuState, dev); - - /* memory mapping */ - memory_region_init_io(&s->iomem, &exynos4210_pmu_ops, s, "exynos4210.pmu", - EXYNOS4210_PMU_REGS_MEM_SIZE); - sysbus_init_mmio(dev, &s->iomem); - return 0; -} - -static const VMStateDescription exynos4210_pmu_vmstate = { - .name = "exynos4210.pmu", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(reg, Exynos4210PmuState, PMU_NUM_OF_REGISTERS), - VMSTATE_END_OF_LIST() - } -}; - -static void exynos4210_pmu_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = exynos4210_pmu_init; - dc->reset = exynos4210_pmu_reset; - dc->vmsd = &exynos4210_pmu_vmstate; -} - -static const TypeInfo exynos4210_pmu_info = { - .name = "exynos4210.pmu", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(Exynos4210PmuState), - .class_init = exynos4210_pmu_class_init, -}; - -static void exynos4210_pmu_register(void) -{ - type_register_static(&exynos4210_pmu_info); -} - -type_init(exynos4210_pmu_register) diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs index 533d337c17..c1d73a88a6 100644 --- a/hw/i386/Makefile.objs +++ b/hw/i386/Makefile.objs @@ -1,8 +1,4 @@ -obj-y += sga.o -obj-y += vmport.o -obj-y += debugexit.o obj-y += kvm/ -obj-y += pc-testdev.o obj-y := $(addprefix ../,$(obj-y)) diff --git a/hw/imx_ccm.c b/hw/imx_ccm.c deleted file mode 100644 index c153a24310..0000000000 --- a/hw/imx_ccm.c +++ /dev/null @@ -1,321 +0,0 @@ -/* - * IMX31 Clock Control Module - * - * Copyright (C) 2012 NICTA - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - * - * To get the timer frequencies right, we need to emulate at least part of - * the CCM. - */ - -#include "hw/hw.h" -#include "hw/sysbus.h" -#include "sysemu/sysemu.h" -#include "hw/arm/imx.h" - -#define CKIH_FREQ 26000000 /* 26MHz crystal input */ -#define CKIL_FREQ 32768 /* nominal 32khz clock */ - - -//#define DEBUG_CCM 1 -#ifdef DEBUG_CCM -#define DPRINTF(fmt, args...) \ -do { printf("imx_ccm: " fmt , ##args); } while (0) -#else -#define DPRINTF(fmt, args...) do {} while (0) -#endif - -static int imx_ccm_post_load(void *opaque, int version_id); - -typedef struct { - SysBusDevice busdev; - MemoryRegion iomem; - - uint32_t ccmr; - uint32_t pdr0; - uint32_t pdr1; - uint32_t mpctl; - uint32_t spctl; - uint32_t cgr[3]; - uint32_t pmcr0; - uint32_t pmcr1; - - /* Frequencies precalculated on register changes */ - uint32_t pll_refclk_freq; - uint32_t mcu_clk_freq; - uint32_t hsp_clk_freq; - uint32_t ipg_clk_freq; -} IMXCCMState; - -static const VMStateDescription vmstate_imx_ccm = { - .name = "imx-ccm", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(ccmr, IMXCCMState), - VMSTATE_UINT32(pdr0, IMXCCMState), - VMSTATE_UINT32(pdr1, IMXCCMState), - VMSTATE_UINT32(mpctl, IMXCCMState), - VMSTATE_UINT32(spctl, IMXCCMState), - VMSTATE_UINT32_ARRAY(cgr, IMXCCMState, 3), - VMSTATE_UINT32(pmcr0, IMXCCMState), - VMSTATE_UINT32(pmcr1, IMXCCMState), - VMSTATE_UINT32(pll_refclk_freq, IMXCCMState), - }, - .post_load = imx_ccm_post_load, -}; - -/* CCMR */ -#define CCMR_FPME (1<<0) -#define CCMR_MPE (1<<3) -#define CCMR_MDS (1<<7) -#define CCMR_FPMF (1<<26) -#define CCMR_PRCS (3<<1) - -/* PDR0 */ -#define PDR0_MCU_PODF_SHIFT (0) -#define PDR0_MCU_PODF_MASK (0x7) -#define PDR0_MAX_PODF_SHIFT (3) -#define PDR0_MAX_PODF_MASK (0x7) -#define PDR0_IPG_PODF_SHIFT (6) -#define PDR0_IPG_PODF_MASK (0x3) -#define PDR0_NFC_PODF_SHIFT (8) -#define PDR0_NFC_PODF_MASK (0x7) -#define PDR0_HSP_PODF_SHIFT (11) -#define PDR0_HSP_PODF_MASK (0x7) -#define PDR0_PER_PODF_SHIFT (16) -#define PDR0_PER_PODF_MASK (0x1f) -#define PDR0_CSI_PODF_SHIFT (23) -#define PDR0_CSI_PODF_MASK (0x1ff) - -#define EXTRACT(value, name) (((value) >> PDR0_##name##_PODF_SHIFT) \ - & PDR0_##name##_PODF_MASK) -#define INSERT(value, name) (((value) & PDR0_##name##_PODF_MASK) << \ - PDR0_##name##_PODF_SHIFT) -/* PLL control registers */ -#define PD(v) (((v) >> 26) & 0xf) -#define MFD(v) (((v) >> 16) & 0x3ff) -#define MFI(v) (((v) >> 10) & 0xf); -#define MFN(v) ((v) & 0x3ff) - -#define PLL_PD(x) (((x) & 0xf) << 26) -#define PLL_MFD(x) (((x) & 0x3ff) << 16) -#define PLL_MFI(x) (((x) & 0xf) << 10) -#define PLL_MFN(x) (((x) & 0x3ff) << 0) - -uint32_t imx_clock_frequency(DeviceState *dev, IMXClk clock) -{ - IMXCCMState *s = container_of(dev, IMXCCMState, busdev.qdev); - - switch (clock) { - case NOCLK: - return 0; - case MCU: - return s->mcu_clk_freq; - case HSP: - return s->hsp_clk_freq; - case IPG: - return s->ipg_clk_freq; - case CLK_32k: - return CKIL_FREQ; - } - return 0; -} - -/* - * Calculate PLL output frequency - */ -static uint32_t calc_pll(uint32_t pllreg, uint32_t base_freq) -{ - int32_t mfn = MFN(pllreg); /* Numerator */ - uint32_t mfi = MFI(pllreg); /* Integer part */ - uint32_t mfd = 1 + MFD(pllreg); /* Denominator */ - uint32_t pd = 1 + PD(pllreg); /* Pre-divider */ - - if (mfi < 5) { - mfi = 5; - } - /* mfn is 10-bit signed twos-complement */ - mfn <<= 32 - 10; - mfn >>= 32 - 10; - - return ((2 * (base_freq >> 10) * (mfi * mfd + mfn)) / - (mfd * pd)) << 10; -} - -static void update_clocks(IMXCCMState *s) -{ - /* - * If we ever emulate more clocks, this should switch to a data-driven - * approach - */ - - if ((s->ccmr & CCMR_PRCS) == 1) { - s->pll_refclk_freq = CKIL_FREQ * 1024; - } else { - s->pll_refclk_freq = CKIH_FREQ; - } - - /* ipg_clk_arm aka MCU clock */ - if ((s->ccmr & CCMR_MDS) || !(s->ccmr & CCMR_MPE)) { - s->mcu_clk_freq = s->pll_refclk_freq; - } else { - s->mcu_clk_freq = calc_pll(s->mpctl, s->pll_refclk_freq); - } - - /* High-speed clock */ - s->hsp_clk_freq = s->mcu_clk_freq / (1 + EXTRACT(s->pdr0, HSP)); - s->ipg_clk_freq = s->hsp_clk_freq / (1 + EXTRACT(s->pdr0, IPG)); - - DPRINTF("Clocks: mcu %uMHz, HSP %uMHz, IPG %uHz\n", - s->mcu_clk_freq / 1000000, - s->hsp_clk_freq / 1000000, - s->ipg_clk_freq); -} - -static void imx_ccm_reset(DeviceState *dev) -{ - IMXCCMState *s = container_of(dev, IMXCCMState, busdev.qdev); - - s->ccmr = 0x074b0b7b; - s->pdr0 = 0xff870b48; - s->pdr1 = 0x49fcfe7f; - s->mpctl = PLL_PD(1) | PLL_MFD(0) | PLL_MFI(6) | PLL_MFN(0); - s->cgr[0] = s->cgr[1] = s->cgr[2] = 0xffffffff; - s->spctl = PLL_PD(1) | PLL_MFD(4) | PLL_MFI(0xc) | PLL_MFN(1); - s->pmcr0 = 0x80209828; - - update_clocks(s); -} - -static uint64_t imx_ccm_read(void *opaque, hwaddr offset, - unsigned size) -{ - IMXCCMState *s = (IMXCCMState *)opaque; - - DPRINTF("read(offset=%x)", offset >> 2); - switch (offset >> 2) { - case 0: /* CCMR */ - DPRINTF(" ccmr = 0x%x\n", s->ccmr); - return s->ccmr; - case 1: - DPRINTF(" pdr0 = 0x%x\n", s->pdr0); - return s->pdr0; - case 2: - DPRINTF(" pdr1 = 0x%x\n", s->pdr1); - return s->pdr1; - case 4: - DPRINTF(" mpctl = 0x%x\n", s->mpctl); - return s->mpctl; - case 6: - DPRINTF(" spctl = 0x%x\n", s->spctl); - return s->spctl; - case 8: - DPRINTF(" cgr0 = 0x%x\n", s->cgr[0]); - return s->cgr[0]; - case 9: - DPRINTF(" cgr1 = 0x%x\n", s->cgr[1]); - return s->cgr[1]; - case 10: - DPRINTF(" cgr2 = 0x%x\n", s->cgr[2]); - return s->cgr[2]; - case 18: /* LTR1 */ - return 0x00004040; - case 23: - DPRINTF(" pcmr0 = 0x%x\n", s->pmcr0); - return s->pmcr0; - } - DPRINTF(" return 0\n"); - return 0; -} - -static void imx_ccm_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - IMXCCMState *s = (IMXCCMState *)opaque; - - DPRINTF("write(offset=%x, value = %x)\n", - offset >> 2, (unsigned int)value); - switch (offset >> 2) { - case 0: - s->ccmr = CCMR_FPMF | (value & 0x3b6fdfff); - break; - case 1: - s->pdr0 = value & 0xff9f3fff; - break; - case 2: - s->pdr1 = value; - break; - case 4: - s->mpctl = value & 0xbfff3fff; - break; - case 6: - s->spctl = value & 0xbfff3fff; - break; - case 8: - s->cgr[0] = value; - return; - case 9: - s->cgr[1] = value; - return; - case 10: - s->cgr[2] = value; - return; - - default: - return; - } - update_clocks(s); -} - -static const struct MemoryRegionOps imx_ccm_ops = { - .read = imx_ccm_read, - .write = imx_ccm_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static int imx_ccm_init(SysBusDevice *dev) -{ - IMXCCMState *s = FROM_SYSBUS(typeof(*s), dev); - - memory_region_init_io(&s->iomem, &imx_ccm_ops, s, "imx_ccm", 0x1000); - sysbus_init_mmio(dev, &s->iomem); - - return 0; -} - -static int imx_ccm_post_load(void *opaque, int version_id) -{ - IMXCCMState *s = (IMXCCMState *)opaque; - - update_clocks(s); - return 0; -} - -static void imx_ccm_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass); - - sbc->init = imx_ccm_init; - dc->reset = imx_ccm_reset; - dc->vmsd = &vmstate_imx_ccm; - dc->desc = "i.MX Clock Control Module"; -} - -static const TypeInfo imx_ccm_info = { - .name = "imx_ccm", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(IMXCCMState), - .class_init = imx_ccm_class_init, -}; - -static void imx_ccm_register_types(void) -{ - type_register_static(&imx_ccm_info); -} - -type_init(imx_ccm_register_types) diff --git a/hw/lm32/Makefile.objs b/hw/lm32/Makefile.objs index 1e59ac5c62..ea6418ae59 100644 --- a/hw/lm32/Makefile.objs +++ b/hw/lm32/Makefile.objs @@ -1,10 +1,3 @@ -# LM32 peripherals -obj-y += lm32_sys.o -obj-y += milkymist-hpdmc.o -obj-y += milkymist-pfpu.o - -obj-y := $(addprefix ../,$(obj-y)) - # LM32 boards obj-y += lm32_boards.o obj-y += milkymist.o diff --git a/hw/lm32_sys.c b/hw/lm32_sys.c deleted file mode 100644 index 33a3b80ce7..0000000000 --- a/hw/lm32_sys.c +++ /dev/null @@ -1,172 +0,0 @@ -/* - * QEMU model of the LatticeMico32 system control block. - * - * Copyright (c) 2010 Michael Walle - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - */ - -/* - * This model is mainly intended for testing purposes and doesn't fit to any - * real hardware. On the one hand it provides a control register (R_CTRL) on - * the other hand it supports the lm32 tests. - * - * A write to the control register causes a system shutdown. - * Tests first write the pointer to a test name to the test name register - * (R_TESTNAME) and then write a zero to the pass/fail register (R_PASSFAIL) if - * the test is passed or any non-zero value to it if the test is failed. - */ - -#include "hw/hw.h" -#include "hw/sysbus.h" -#include "trace.h" -#include "qemu/log.h" -#include "qemu/error-report.h" -#include "sysemu/sysemu.h" -#include "qemu/log.h" - -enum { - R_CTRL = 0, - R_PASSFAIL, - R_TESTNAME, - R_MAX -}; - -#define MAX_TESTNAME_LEN 16 - -struct LM32SysState { - SysBusDevice busdev; - MemoryRegion iomem; - uint32_t base; - uint32_t regs[R_MAX]; - uint8_t testname[MAX_TESTNAME_LEN]; -}; -typedef struct LM32SysState LM32SysState; - -static void copy_testname(LM32SysState *s) -{ - cpu_physical_memory_read(s->regs[R_TESTNAME], s->testname, - MAX_TESTNAME_LEN); - s->testname[MAX_TESTNAME_LEN - 1] = '\0'; -} - -static void sys_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - LM32SysState *s = opaque; - char *testname; - - trace_lm32_sys_memory_write(addr, value); - - addr >>= 2; - switch (addr) { - case R_CTRL: - qemu_system_shutdown_request(); - break; - case R_PASSFAIL: - s->regs[addr] = value; - testname = (char *)s->testname; - qemu_log("TC %-16s %s\n", testname, (value) ? "FAILED" : "OK"); - break; - case R_TESTNAME: - s->regs[addr] = value; - copy_testname(s); - break; - - default: - error_report("lm32_sys: write access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } -} - -static bool sys_ops_accepts(void *opaque, hwaddr addr, - unsigned size, bool is_write) -{ - return is_write && size == 4; -} - -static const MemoryRegionOps sys_ops = { - .write = sys_write, - .valid.accepts = sys_ops_accepts, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void sys_reset(DeviceState *d) -{ - LM32SysState *s = container_of(d, LM32SysState, busdev.qdev); - int i; - - for (i = 0; i < R_MAX; i++) { - s->regs[i] = 0; - } - memset(s->testname, 0, MAX_TESTNAME_LEN); -} - -static int lm32_sys_init(SysBusDevice *dev) -{ - LM32SysState *s = FROM_SYSBUS(typeof(*s), dev); - - memory_region_init_io(&s->iomem, &sys_ops , s, "sys", R_MAX * 4); - sysbus_init_mmio(dev, &s->iomem); - - /* Note: This device is not created in the board initialization, - * instead it has to be added with the -device parameter. Therefore, - * the device maps itself. */ - sysbus_mmio_map(dev, 0, s->base); - - return 0; -} - -static const VMStateDescription vmstate_lm32_sys = { - .name = "lm32-sys", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(regs, LM32SysState, R_MAX), - VMSTATE_BUFFER(testname, LM32SysState), - VMSTATE_END_OF_LIST() - } -}; - -static Property lm32_sys_properties[] = { - DEFINE_PROP_UINT32("base", LM32SysState, base, 0xffff0000), - DEFINE_PROP_END_OF_LIST(), -}; - -static void lm32_sys_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = lm32_sys_init; - dc->reset = sys_reset; - dc->vmsd = &vmstate_lm32_sys; - dc->props = lm32_sys_properties; -} - -static const TypeInfo lm32_sys_info = { - .name = "lm32-sys", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(LM32SysState), - .class_init = lm32_sys_class_init, -}; - -static void lm32_sys_register_types(void) -{ - type_register_static(&lm32_sys_info); -} - -type_init(lm32_sys_register_types) diff --git a/hw/milkymist-hpdmc.c b/hw/milkymist-hpdmc.c deleted file mode 100644 index d922f6ffad..0000000000 --- a/hw/milkymist-hpdmc.c +++ /dev/null @@ -1,170 +0,0 @@ -/* - * QEMU model of the Milkymist High Performance Dynamic Memory Controller. - * - * Copyright (c) 2010 Michael Walle - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - * - * - * Specification available at: - * http://www.milkymist.org/socdoc/hpdmc.pdf - */ - -#include "hw/hw.h" -#include "hw/sysbus.h" -#include "trace.h" -#include "qemu/error-report.h" - -enum { - R_SYSTEM = 0, - R_BYPASS, - R_TIMING, - R_IODELAY, - R_MAX -}; - -enum { - IODELAY_DQSDELAY_RDY = (1<<5), - IODELAY_PLL1_LOCKED = (1<<6), - IODELAY_PLL2_LOCKED = (1<<7), -}; - -struct MilkymistHpdmcState { - SysBusDevice busdev; - MemoryRegion regs_region; - - uint32_t regs[R_MAX]; -}; -typedef struct MilkymistHpdmcState MilkymistHpdmcState; - -static uint64_t hpdmc_read(void *opaque, hwaddr addr, - unsigned size) -{ - MilkymistHpdmcState *s = opaque; - uint32_t r = 0; - - addr >>= 2; - switch (addr) { - case R_SYSTEM: - case R_BYPASS: - case R_TIMING: - case R_IODELAY: - r = s->regs[addr]; - break; - - default: - error_report("milkymist_hpdmc: read access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } - - trace_milkymist_hpdmc_memory_read(addr << 2, r); - - return r; -} - -static void hpdmc_write(void *opaque, hwaddr addr, uint64_t value, - unsigned size) -{ - MilkymistHpdmcState *s = opaque; - - trace_milkymist_hpdmc_memory_write(addr, value); - - addr >>= 2; - switch (addr) { - case R_SYSTEM: - case R_BYPASS: - case R_TIMING: - s->regs[addr] = value; - break; - case R_IODELAY: - /* ignore writes */ - break; - - default: - error_report("milkymist_hpdmc: write access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } -} - -static const MemoryRegionOps hpdmc_mmio_ops = { - .read = hpdmc_read, - .write = hpdmc_write, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void milkymist_hpdmc_reset(DeviceState *d) -{ - MilkymistHpdmcState *s = container_of(d, MilkymistHpdmcState, busdev.qdev); - int i; - - for (i = 0; i < R_MAX; i++) { - s->regs[i] = 0; - } - - /* defaults */ - s->regs[R_IODELAY] = IODELAY_DQSDELAY_RDY | IODELAY_PLL1_LOCKED - | IODELAY_PLL2_LOCKED; -} - -static int milkymist_hpdmc_init(SysBusDevice *dev) -{ - MilkymistHpdmcState *s = FROM_SYSBUS(typeof(*s), dev); - - memory_region_init_io(&s->regs_region, &hpdmc_mmio_ops, s, - "milkymist-hpdmc", R_MAX * 4); - sysbus_init_mmio(dev, &s->regs_region); - - return 0; -} - -static const VMStateDescription vmstate_milkymist_hpdmc = { - .name = "milkymist-hpdmc", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(regs, MilkymistHpdmcState, R_MAX), - VMSTATE_END_OF_LIST() - } -}; - -static void milkymist_hpdmc_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = milkymist_hpdmc_init; - dc->reset = milkymist_hpdmc_reset; - dc->vmsd = &vmstate_milkymist_hpdmc; -} - -static const TypeInfo milkymist_hpdmc_info = { - .name = "milkymist-hpdmc", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(MilkymistHpdmcState), - .class_init = milkymist_hpdmc_class_init, -}; - -static void milkymist_hpdmc_register_types(void) -{ - type_register_static(&milkymist_hpdmc_info); -} - -type_init(milkymist_hpdmc_register_types) diff --git a/hw/milkymist-pfpu.c b/hw/milkymist-pfpu.c deleted file mode 100644 index ad44b4db22..0000000000 --- a/hw/milkymist-pfpu.c +++ /dev/null @@ -1,544 +0,0 @@ -/* - * QEMU model of the Milkymist programmable FPU. - * - * Copyright (c) 2010 Michael Walle - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - * - * - * Specification available at: - * http://www.milkymist.org/socdoc/pfpu.pdf - * - */ - -#include "hw/hw.h" -#include "hw/sysbus.h" -#include "trace.h" -#include "qemu/log.h" -#include "qemu/error-report.h" -#include - -/* #define TRACE_EXEC */ - -#ifdef TRACE_EXEC -# define D_EXEC(x) x -#else -# define D_EXEC(x) -#endif - -enum { - R_CTL = 0, - R_MESHBASE, - R_HMESHLAST, - R_VMESHLAST, - R_CODEPAGE, - R_VERTICES, - R_COLLISIONS, - R_STRAYWRITES, - R_LASTDMA, - R_PC, - R_DREGBASE, - R_CODEBASE, - R_MAX -}; - -enum { - CTL_START_BUSY = (1<<0), -}; - -enum { - OP_NOP = 0, - OP_FADD, - OP_FSUB, - OP_FMUL, - OP_FABS, - OP_F2I, - OP_I2F, - OP_VECTOUT, - OP_SIN, - OP_COS, - OP_ABOVE, - OP_EQUAL, - OP_COPY, - OP_IF, - OP_TSIGN, - OP_QUAKE, -}; - -enum { - GPR_X = 0, - GPR_Y = 1, - GPR_FLAGS = 2, -}; - -enum { - LATENCY_FADD = 5, - LATENCY_FSUB = 5, - LATENCY_FMUL = 7, - LATENCY_FABS = 2, - LATENCY_F2I = 2, - LATENCY_I2F = 3, - LATENCY_VECTOUT = 0, - LATENCY_SIN = 4, - LATENCY_COS = 4, - LATENCY_ABOVE = 2, - LATENCY_EQUAL = 2, - LATENCY_COPY = 2, - LATENCY_IF = 2, - LATENCY_TSIGN = 2, - LATENCY_QUAKE = 2, - MAX_LATENCY = 7 -}; - -#define GPR_BEGIN 0x100 -#define GPR_END 0x17f -#define MICROCODE_BEGIN 0x200 -#define MICROCODE_END 0x3ff -#define MICROCODE_WORDS 2048 - -#define REINTERPRET_CAST(type, val) (*((type *)&(val))) - -#ifdef TRACE_EXEC -static const char *opcode_to_str[] = { - "NOP", "FADD", "FSUB", "FMUL", "FABS", "F2I", "I2F", "VECTOUT", - "SIN", "COS", "ABOVE", "EQUAL", "COPY", "IF", "TSIGN", "QUAKE", -}; -#endif - -struct MilkymistPFPUState { - SysBusDevice busdev; - MemoryRegion regs_region; - CharDriverState *chr; - qemu_irq irq; - - uint32_t regs[R_MAX]; - uint32_t gp_regs[128]; - uint32_t microcode[MICROCODE_WORDS]; - - int output_queue_pos; - uint32_t output_queue[MAX_LATENCY]; -}; -typedef struct MilkymistPFPUState MilkymistPFPUState; - -static inline hwaddr -get_dma_address(uint32_t base, uint32_t x, uint32_t y) -{ - return base + 8 * (128 * y + x); -} - -static inline void -output_queue_insert(MilkymistPFPUState *s, uint32_t val, int pos) -{ - s->output_queue[(s->output_queue_pos + pos) % MAX_LATENCY] = val; -} - -static inline uint32_t -output_queue_remove(MilkymistPFPUState *s) -{ - return s->output_queue[s->output_queue_pos]; -} - -static inline void -output_queue_advance(MilkymistPFPUState *s) -{ - s->output_queue[s->output_queue_pos] = 0; - s->output_queue_pos = (s->output_queue_pos + 1) % MAX_LATENCY; -} - -static int pfpu_decode_insn(MilkymistPFPUState *s) -{ - uint32_t pc = s->regs[R_PC]; - uint32_t insn = s->microcode[pc]; - uint32_t reg_a = (insn >> 18) & 0x7f; - uint32_t reg_b = (insn >> 11) & 0x7f; - uint32_t op = (insn >> 7) & 0xf; - uint32_t reg_d = insn & 0x7f; - uint32_t r = 0; - int latency = 0; - - switch (op) { - case OP_NOP: - break; - case OP_FADD: - { - float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]); - float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]); - float t = a + b; - r = REINTERPRET_CAST(uint32_t, t); - latency = LATENCY_FADD; - D_EXEC(qemu_log("ADD a=%f b=%f t=%f, r=%08x\n", a, b, t, r)); - } break; - case OP_FSUB: - { - float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]); - float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]); - float t = a - b; - r = REINTERPRET_CAST(uint32_t, t); - latency = LATENCY_FSUB; - D_EXEC(qemu_log("SUB a=%f b=%f t=%f, r=%08x\n", a, b, t, r)); - } break; - case OP_FMUL: - { - float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]); - float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]); - float t = a * b; - r = REINTERPRET_CAST(uint32_t, t); - latency = LATENCY_FMUL; - D_EXEC(qemu_log("MUL a=%f b=%f t=%f, r=%08x\n", a, b, t, r)); - } break; - case OP_FABS: - { - float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]); - float t = fabsf(a); - r = REINTERPRET_CAST(uint32_t, t); - latency = LATENCY_FABS; - D_EXEC(qemu_log("ABS a=%f t=%f, r=%08x\n", a, t, r)); - } break; - case OP_F2I: - { - float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]); - int32_t t = a; - r = REINTERPRET_CAST(uint32_t, t); - latency = LATENCY_F2I; - D_EXEC(qemu_log("F2I a=%f t=%d, r=%08x\n", a, t, r)); - } break; - case OP_I2F: - { - int32_t a = REINTERPRET_CAST(int32_t, s->gp_regs[reg_a]); - float t = a; - r = REINTERPRET_CAST(uint32_t, t); - latency = LATENCY_I2F; - D_EXEC(qemu_log("I2F a=%08x t=%f, r=%08x\n", a, t, r)); - } break; - case OP_VECTOUT: - { - uint32_t a = cpu_to_be32(s->gp_regs[reg_a]); - uint32_t b = cpu_to_be32(s->gp_regs[reg_b]); - hwaddr dma_ptr = - get_dma_address(s->regs[R_MESHBASE], - s->gp_regs[GPR_X], s->gp_regs[GPR_Y]); - cpu_physical_memory_write(dma_ptr, (uint8_t *)&a, 4); - cpu_physical_memory_write(dma_ptr + 4, (uint8_t *)&b, 4); - s->regs[R_LASTDMA] = dma_ptr + 4; - D_EXEC(qemu_log("VECTOUT a=%08x b=%08x dma=%08x\n", a, b, dma_ptr)); - trace_milkymist_pfpu_vectout(a, b, dma_ptr); - } break; - case OP_SIN: - { - int32_t a = REINTERPRET_CAST(int32_t, s->gp_regs[reg_a]); - float t = sinf(a * (1.0f / (M_PI * 4096.0f))); - r = REINTERPRET_CAST(uint32_t, t); - latency = LATENCY_SIN; - D_EXEC(qemu_log("SIN a=%d t=%f, r=%08x\n", a, t, r)); - } break; - case OP_COS: - { - int32_t a = REINTERPRET_CAST(int32_t, s->gp_regs[reg_a]); - float t = cosf(a * (1.0f / (M_PI * 4096.0f))); - r = REINTERPRET_CAST(uint32_t, t); - latency = LATENCY_COS; - D_EXEC(qemu_log("COS a=%d t=%f, r=%08x\n", a, t, r)); - } break; - case OP_ABOVE: - { - float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]); - float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]); - float t = (a > b) ? 1.0f : 0.0f; - r = REINTERPRET_CAST(uint32_t, t); - latency = LATENCY_ABOVE; - D_EXEC(qemu_log("ABOVE a=%f b=%f t=%f, r=%08x\n", a, b, t, r)); - } break; - case OP_EQUAL: - { - float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]); - float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]); - float t = (a == b) ? 1.0f : 0.0f; - r = REINTERPRET_CAST(uint32_t, t); - latency = LATENCY_EQUAL; - D_EXEC(qemu_log("EQUAL a=%f b=%f t=%f, r=%08x\n", a, b, t, r)); - } break; - case OP_COPY: - { - r = s->gp_regs[reg_a]; - latency = LATENCY_COPY; - D_EXEC(qemu_log("COPY")); - } break; - case OP_IF: - { - float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]); - float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]); - uint32_t f = s->gp_regs[GPR_FLAGS]; - float t = (f != 0) ? a : b; - r = REINTERPRET_CAST(uint32_t, t); - latency = LATENCY_IF; - D_EXEC(qemu_log("IF f=%u a=%f b=%f t=%f, r=%08x\n", f, a, b, t, r)); - } break; - case OP_TSIGN: - { - float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]); - float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]); - float t = (b < 0) ? -a : a; - r = REINTERPRET_CAST(uint32_t, t); - latency = LATENCY_TSIGN; - D_EXEC(qemu_log("TSIGN a=%f b=%f t=%f, r=%08x\n", a, b, t, r)); - } break; - case OP_QUAKE: - { - uint32_t a = s->gp_regs[reg_a]; - r = 0x5f3759df - (a >> 1); - latency = LATENCY_QUAKE; - D_EXEC(qemu_log("QUAKE a=%d r=%08x\n", a, r)); - } break; - - default: - error_report("milkymist_pfpu: unknown opcode %d", op); - break; - } - - if (!reg_d) { - D_EXEC(qemu_log("%04d %8s R%03d, R%03d \n", - s->regs[R_PC], opcode_to_str[op], reg_a, reg_b, latency, - s->regs[R_PC] + latency)); - } else { - D_EXEC(qemu_log("%04d %8s R%03d, R%03d -> R%03d\n", - s->regs[R_PC], opcode_to_str[op], reg_a, reg_b, latency, - s->regs[R_PC] + latency, reg_d)); - } - - if (op == OP_VECTOUT) { - return 0; - } - - /* store output for this cycle */ - if (reg_d) { - uint32_t val = output_queue_remove(s); - D_EXEC(qemu_log("R%03d <- 0x%08x\n", reg_d, val)); - s->gp_regs[reg_d] = val; - } - - output_queue_advance(s); - - /* store op output */ - if (op != OP_NOP) { - output_queue_insert(s, r, latency-1); - } - - /* advance PC */ - s->regs[R_PC]++; - - return 1; -}; - -static void pfpu_start(MilkymistPFPUState *s) -{ - int x, y; - int i; - - for (y = 0; y <= s->regs[R_VMESHLAST]; y++) { - for (x = 0; x <= s->regs[R_HMESHLAST]; x++) { - D_EXEC(qemu_log("\nprocessing x=%d y=%d\n", x, y)); - - /* set current position */ - s->gp_regs[GPR_X] = x; - s->gp_regs[GPR_Y] = y; - - /* run microcode on this position */ - i = 0; - while (pfpu_decode_insn(s)) { - /* decode at most MICROCODE_WORDS instructions */ - if (i++ >= MICROCODE_WORDS) { - error_report("milkymist_pfpu: too many instructions " - "executed in microcode. No VECTOUT?"); - break; - } - } - - /* reset pc for next run */ - s->regs[R_PC] = 0; - } - } - - s->regs[R_VERTICES] = x * y; - - trace_milkymist_pfpu_pulse_irq(); - qemu_irq_pulse(s->irq); -} - -static inline int get_microcode_address(MilkymistPFPUState *s, uint32_t addr) -{ - return (512 * s->regs[R_CODEPAGE]) + addr - MICROCODE_BEGIN; -} - -static uint64_t pfpu_read(void *opaque, hwaddr addr, - unsigned size) -{ - MilkymistPFPUState *s = opaque; - uint32_t r = 0; - - addr >>= 2; - switch (addr) { - case R_CTL: - case R_MESHBASE: - case R_HMESHLAST: - case R_VMESHLAST: - case R_CODEPAGE: - case R_VERTICES: - case R_COLLISIONS: - case R_STRAYWRITES: - case R_LASTDMA: - case R_PC: - case R_DREGBASE: - case R_CODEBASE: - r = s->regs[addr]; - break; - case GPR_BEGIN ... GPR_END: - r = s->gp_regs[addr - GPR_BEGIN]; - break; - case MICROCODE_BEGIN ... MICROCODE_END: - r = s->microcode[get_microcode_address(s, addr)]; - break; - - default: - error_report("milkymist_pfpu: read access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } - - trace_milkymist_pfpu_memory_read(addr << 2, r); - - return r; -} - -static void pfpu_write(void *opaque, hwaddr addr, uint64_t value, - unsigned size) -{ - MilkymistPFPUState *s = opaque; - - trace_milkymist_pfpu_memory_write(addr, value); - - addr >>= 2; - switch (addr) { - case R_CTL: - if (value & CTL_START_BUSY) { - pfpu_start(s); - } - break; - case R_MESHBASE: - case R_HMESHLAST: - case R_VMESHLAST: - case R_CODEPAGE: - case R_VERTICES: - case R_COLLISIONS: - case R_STRAYWRITES: - case R_LASTDMA: - case R_PC: - case R_DREGBASE: - case R_CODEBASE: - s->regs[addr] = value; - break; - case GPR_BEGIN ... GPR_END: - s->gp_regs[addr - GPR_BEGIN] = value; - break; - case MICROCODE_BEGIN ... MICROCODE_END: - s->microcode[get_microcode_address(s, addr)] = value; - break; - - default: - error_report("milkymist_pfpu: write access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } -} - -static const MemoryRegionOps pfpu_mmio_ops = { - .read = pfpu_read, - .write = pfpu_write, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void milkymist_pfpu_reset(DeviceState *d) -{ - MilkymistPFPUState *s = container_of(d, MilkymistPFPUState, busdev.qdev); - int i; - - for (i = 0; i < R_MAX; i++) { - s->regs[i] = 0; - } - for (i = 0; i < 128; i++) { - s->gp_regs[i] = 0; - } - for (i = 0; i < MICROCODE_WORDS; i++) { - s->microcode[i] = 0; - } - s->output_queue_pos = 0; - for (i = 0; i < MAX_LATENCY; i++) { - s->output_queue[i] = 0; - } -} - -static int milkymist_pfpu_init(SysBusDevice *dev) -{ - MilkymistPFPUState *s = FROM_SYSBUS(typeof(*s), dev); - - sysbus_init_irq(dev, &s->irq); - - memory_region_init_io(&s->regs_region, &pfpu_mmio_ops, s, - "milkymist-pfpu", MICROCODE_END * 4); - sysbus_init_mmio(dev, &s->regs_region); - - return 0; -} - -static const VMStateDescription vmstate_milkymist_pfpu = { - .name = "milkymist-pfpu", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(regs, MilkymistPFPUState, R_MAX), - VMSTATE_UINT32_ARRAY(gp_regs, MilkymistPFPUState, 128), - VMSTATE_UINT32_ARRAY(microcode, MilkymistPFPUState, MICROCODE_WORDS), - VMSTATE_INT32(output_queue_pos, MilkymistPFPUState), - VMSTATE_UINT32_ARRAY(output_queue, MilkymistPFPUState, MAX_LATENCY), - VMSTATE_END_OF_LIST() - } -}; - -static void milkymist_pfpu_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = milkymist_pfpu_init; - dc->reset = milkymist_pfpu_reset; - dc->vmsd = &vmstate_milkymist_pfpu; -} - -static const TypeInfo milkymist_pfpu_info = { - .name = "milkymist-pfpu", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(MilkymistPFPUState), - .class_init = milkymist_pfpu_class_init, -}; - -static void milkymist_pfpu_register_types(void) -{ - type_register_static(&milkymist_pfpu_info); -} - -type_init(milkymist_pfpu_register_types) diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index 9b1ab39fbe..03699c3365 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -1,6 +1,11 @@ common-obj-$(CONFIG_APPLESMC) += applesmc.o common-obj-$(CONFIG_MAX111X) += max111x.o common-obj-$(CONFIG_TMP105) += tmp105.o +common-obj-$(CONFIG_ISA_DEBUG) += debugexit.o +common-obj-$(CONFIG_SGA) += sga.o +common-obj-$(CONFIG_ISA_TESTDEV) += pc-testdev.o + +obj-$(CONFIG_VMPORT) += vmport.o # ARM devices common-obj-$(CONFIG_PL310) += arm_l2x0.o @@ -15,3 +20,21 @@ obj-$(CONFIG_KVM) += ivshmem.o obj-$(CONFIG_LINUX) += vfio.o endif +obj-$(CONFIG_REALVIEW) += arm_sysctl.o +obj-$(CONFIG_A9SCU) += a9scu.o +obj-$(CONFIG_NSERIES) += cbus.o +obj-$(CONFIG_ECCMEMCTL) += eccmemctl.o +obj-$(CONFIG_EXYNOS4) += exynos4210_pmu.o +obj-$(CONFIG_IMX) += imx_ccm.o +obj-$(CONFIG_LM32) += lm32_sys.o +obj-$(CONFIG_MILKYMIST) += milkymist-hpdmc.o +obj-$(CONFIG_MILKYMIST) += milkymist-pfpu.o +obj-$(CONFIG_MAINSTONE) += mst_fpga.o +obj-$(CONFIG_OMAP) += omap_clk.o +obj-$(CONFIG_OMAP) += omap_gpmc.o +obj-$(CONFIG_OMAP) += omap_l4.o +obj-$(CONFIG_OMAP) += omap_sdrc.o +obj-$(CONFIG_OMAP) += omap_tap.o +obj-$(CONFIG_PXA2XX) += pxa2xx_pcmcia.o +obj-$(CONFIG_SLAVIO) += slavio_misc.o +obj-$(CONFIG_ZYNQ) += zynq_slcr.o diff --git a/hw/misc/a9scu.c b/hw/misc/a9scu.c new file mode 100644 index 0000000000..05897c2fa2 --- /dev/null +++ b/hw/misc/a9scu.c @@ -0,0 +1,164 @@ +/* + * Cortex-A9MPCore Snoop Control Unit (SCU) emulation. + * + * Copyright (c) 2009 CodeSourcery. + * Copyright (c) 2011 Linaro Limited. + * Written by Paul Brook, Peter Maydell. + * + * This code is licensed under the GPL. + */ + +#include "hw/sysbus.h" + +/* A9MP private memory region. */ + +typedef struct A9SCUState { + SysBusDevice busdev; + MemoryRegion iomem; + uint32_t control; + uint32_t status; + uint32_t num_cpu; +} A9SCUState; + +#define TYPE_A9_SCU "a9-scu" +#define A9_SCU(obj) OBJECT_CHECK(A9SCUState, (obj), TYPE_A9_SCU) + +static uint64_t a9_scu_read(void *opaque, hwaddr offset, + unsigned size) +{ + A9SCUState *s = (A9SCUState *)opaque; + switch (offset) { + case 0x00: /* Control */ + return s->control; + case 0x04: /* Configuration */ + return (((1 << s->num_cpu) - 1) << 4) | (s->num_cpu - 1); + case 0x08: /* CPU Power Status */ + return s->status; + case 0x09: /* CPU status. */ + return s->status >> 8; + case 0x0a: /* CPU status. */ + return s->status >> 16; + case 0x0b: /* CPU status. */ + return s->status >> 24; + case 0x0c: /* Invalidate All Registers In Secure State */ + return 0; + case 0x40: /* Filtering Start Address Register */ + case 0x44: /* Filtering End Address Register */ + /* RAZ/WI, like an implementation with only one AXI master */ + return 0; + case 0x50: /* SCU Access Control Register */ + case 0x54: /* SCU Non-secure Access Control Register */ + /* unimplemented, fall through */ + default: + return 0; + } +} + +static void a9_scu_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + A9SCUState *s = (A9SCUState *)opaque; + uint32_t mask; + uint32_t shift; + switch (size) { + case 1: + mask = 0xff; + break; + case 2: + mask = 0xffff; + break; + case 4: + mask = 0xffffffff; + break; + default: + fprintf(stderr, "Invalid size %u in write to a9 scu register %x\n", + size, (unsigned)offset); + return; + } + + switch (offset) { + case 0x00: /* Control */ + s->control = value & 1; + break; + case 0x4: /* Configuration: RO */ + break; + case 0x08: case 0x09: case 0x0A: case 0x0B: /* Power Control */ + shift = (offset - 0x8) * 8; + s->status &= ~(mask << shift); + s->status |= ((value & mask) << shift); + break; + case 0x0c: /* Invalidate All Registers In Secure State */ + /* no-op as we do not implement caches */ + break; + case 0x40: /* Filtering Start Address Register */ + case 0x44: /* Filtering End Address Register */ + /* RAZ/WI, like an implementation with only one AXI master */ + break; + case 0x50: /* SCU Access Control Register */ + case 0x54: /* SCU Non-secure Access Control Register */ + /* unimplemented, fall through */ + default: + break; + } +} + +static const MemoryRegionOps a9_scu_ops = { + .read = a9_scu_read, + .write = a9_scu_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void a9_scu_reset(DeviceState *dev) +{ + A9SCUState *s = A9_SCU(dev); + s->control = 0; +} + +static void a9_scu_realize(DeviceState *dev, Error ** errp) +{ + A9SCUState *s = A9_SCU(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + + memory_region_init_io(&s->iomem, &a9_scu_ops, s, "a9-scu", 0x100); + sysbus_init_mmio(sbd, &s->iomem); +} + +static const VMStateDescription vmstate_a9_scu = { + .name = "a9-scu", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(control, A9SCUState), + VMSTATE_UINT32(status, A9SCUState), + VMSTATE_END_OF_LIST() + } +}; + +static Property a9_scu_properties[] = { + DEFINE_PROP_UINT32("num-cpu", A9SCUState, num_cpu, 1), + DEFINE_PROP_END_OF_LIST(), +}; + +static void a9_scu_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = a9_scu_realize; + dc->props = a9_scu_properties; + dc->vmsd = &vmstate_a9_scu; + dc->reset = a9_scu_reset; +} + +static const TypeInfo a9_scu_info = { + .name = TYPE_A9_SCU, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(A9SCUState), + .class_init = a9_scu_class_init, +}; + +static void a9mp_register_types(void) +{ + type_register_static(&a9_scu_info); +} + +type_init(a9mp_register_types) diff --git a/hw/misc/arm_sysctl.c b/hw/misc/arm_sysctl.c new file mode 100644 index 0000000000..c8b55a8349 --- /dev/null +++ b/hw/misc/arm_sysctl.c @@ -0,0 +1,649 @@ +/* + * Status and system control registers for ARM RealView/Versatile boards. + * + * Copyright (c) 2006-2007 CodeSourcery. + * Written by Paul Brook + * + * This code is licensed under the GPL. + */ + +#include "hw/hw.h" +#include "qemu/timer.h" +#include "qemu/bitops.h" +#include "hw/sysbus.h" +#include "hw/arm/primecell.h" +#include "sysemu/sysemu.h" + +#define LOCK_VALUE 0xa05f + +typedef struct { + SysBusDevice busdev; + MemoryRegion iomem; + qemu_irq pl110_mux_ctrl; + + uint32_t sys_id; + uint32_t leds; + uint16_t lockval; + uint32_t cfgdata1; + uint32_t cfgdata2; + uint32_t flags; + uint32_t nvflags; + uint32_t resetlevel; + uint32_t proc_id; + uint32_t sys_mci; + uint32_t sys_cfgdata; + uint32_t sys_cfgctrl; + uint32_t sys_cfgstat; + uint32_t sys_clcd; + uint32_t mb_clock[6]; + uint32_t *db_clock; + uint32_t db_num_vsensors; + uint32_t *db_voltage; + uint32_t db_num_clocks; + uint32_t *db_clock_reset; +} arm_sysctl_state; + +static const VMStateDescription vmstate_arm_sysctl = { + .name = "realview_sysctl", + .version_id = 4, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(leds, arm_sysctl_state), + VMSTATE_UINT16(lockval, arm_sysctl_state), + VMSTATE_UINT32(cfgdata1, arm_sysctl_state), + VMSTATE_UINT32(cfgdata2, arm_sysctl_state), + VMSTATE_UINT32(flags, arm_sysctl_state), + VMSTATE_UINT32(nvflags, arm_sysctl_state), + VMSTATE_UINT32(resetlevel, arm_sysctl_state), + VMSTATE_UINT32_V(sys_mci, arm_sysctl_state, 2), + VMSTATE_UINT32_V(sys_cfgdata, arm_sysctl_state, 2), + VMSTATE_UINT32_V(sys_cfgctrl, arm_sysctl_state, 2), + VMSTATE_UINT32_V(sys_cfgstat, arm_sysctl_state, 2), + VMSTATE_UINT32_V(sys_clcd, arm_sysctl_state, 3), + VMSTATE_UINT32_ARRAY_V(mb_clock, arm_sysctl_state, 6, 4), + VMSTATE_VARRAY_UINT32(db_clock, arm_sysctl_state, db_num_clocks, + 4, vmstate_info_uint32, uint32_t), + VMSTATE_END_OF_LIST() + } +}; + +/* The PB926 actually uses a different format for + * its SYS_ID register. Fortunately the bits which are + * board type on later boards are distinct. + */ +#define BOARD_ID_PB926 0x100 +#define BOARD_ID_EB 0x140 +#define BOARD_ID_PBA8 0x178 +#define BOARD_ID_PBX 0x182 +#define BOARD_ID_VEXPRESS 0x190 + +static int board_id(arm_sysctl_state *s) +{ + /* Extract the board ID field from the SYS_ID register value */ + return (s->sys_id >> 16) & 0xfff; +} + +static void arm_sysctl_reset(DeviceState *d) +{ + arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, SYS_BUS_DEVICE(d)); + int i; + + s->leds = 0; + s->lockval = 0; + s->cfgdata1 = 0; + s->cfgdata2 = 0; + s->flags = 0; + s->resetlevel = 0; + /* Motherboard oscillators (in Hz) */ + s->mb_clock[0] = 50000000; /* Static memory clock: 50MHz */ + s->mb_clock[1] = 23750000; /* motherboard CLCD clock: 23.75MHz */ + s->mb_clock[2] = 24000000; /* IO FPGA peripheral clock: 24MHz */ + s->mb_clock[3] = 24000000; /* IO FPGA reserved clock: 24MHz */ + s->mb_clock[4] = 24000000; /* System bus global clock: 24MHz */ + s->mb_clock[5] = 24000000; /* IO FPGA reserved clock: 24MHz */ + /* Daughterboard oscillators: reset from property values */ + for (i = 0; i < s->db_num_clocks; i++) { + s->db_clock[i] = s->db_clock_reset[i]; + } + if (board_id(s) == BOARD_ID_VEXPRESS) { + /* On VExpress this register will RAZ/WI */ + s->sys_clcd = 0; + } else { + /* All others: CLCDID 0x1f, indicating VGA */ + s->sys_clcd = 0x1f00; + } +} + +static uint64_t arm_sysctl_read(void *opaque, hwaddr offset, + unsigned size) +{ + arm_sysctl_state *s = (arm_sysctl_state *)opaque; + + switch (offset) { + case 0x00: /* ID */ + return s->sys_id; + case 0x04: /* SW */ + /* General purpose hardware switches. + We don't have a useful way of exposing these to the user. */ + return 0; + case 0x08: /* LED */ + return s->leds; + case 0x20: /* LOCK */ + return s->lockval; + case 0x0c: /* OSC0 */ + case 0x10: /* OSC1 */ + case 0x14: /* OSC2 */ + case 0x18: /* OSC3 */ + case 0x1c: /* OSC4 */ + case 0x24: /* 100HZ */ + /* ??? Implement these. */ + return 0; + case 0x28: /* CFGDATA1 */ + return s->cfgdata1; + case 0x2c: /* CFGDATA2 */ + return s->cfgdata2; + case 0x30: /* FLAGS */ + return s->flags; + case 0x38: /* NVFLAGS */ + return s->nvflags; + case 0x40: /* RESETCTL */ + if (board_id(s) == BOARD_ID_VEXPRESS) { + /* reserved: RAZ/WI */ + return 0; + } + return s->resetlevel; + case 0x44: /* PCICTL */ + return 1; + case 0x48: /* MCI */ + return s->sys_mci; + case 0x4c: /* FLASH */ + return 0; + case 0x50: /* CLCD */ + return s->sys_clcd; + case 0x54: /* CLCDSER */ + return 0; + case 0x58: /* BOOTCS */ + return 0; + case 0x5c: /* 24MHz */ + return muldiv64(qemu_get_clock_ns(vm_clock), 24000000, get_ticks_per_sec()); + case 0x60: /* MISC */ + return 0; + case 0x84: /* PROCID0 */ + return s->proc_id; + case 0x88: /* PROCID1 */ + return 0xff000000; + case 0x64: /* DMAPSR0 */ + case 0x68: /* DMAPSR1 */ + case 0x6c: /* DMAPSR2 */ + case 0x70: /* IOSEL */ + case 0x74: /* PLDCTL */ + case 0x80: /* BUSID */ + case 0x8c: /* OSCRESET0 */ + case 0x90: /* OSCRESET1 */ + case 0x94: /* OSCRESET2 */ + case 0x98: /* OSCRESET3 */ + case 0x9c: /* OSCRESET4 */ + case 0xc0: /* SYS_TEST_OSC0 */ + case 0xc4: /* SYS_TEST_OSC1 */ + case 0xc8: /* SYS_TEST_OSC2 */ + case 0xcc: /* SYS_TEST_OSC3 */ + case 0xd0: /* SYS_TEST_OSC4 */ + return 0; + case 0xa0: /* SYS_CFGDATA */ + if (board_id(s) != BOARD_ID_VEXPRESS) { + goto bad_reg; + } + return s->sys_cfgdata; + case 0xa4: /* SYS_CFGCTRL */ + if (board_id(s) != BOARD_ID_VEXPRESS) { + goto bad_reg; + } + return s->sys_cfgctrl; + case 0xa8: /* SYS_CFGSTAT */ + if (board_id(s) != BOARD_ID_VEXPRESS) { + goto bad_reg; + } + return s->sys_cfgstat; + default: + bad_reg: + qemu_log_mask(LOG_GUEST_ERROR, + "arm_sysctl_read: Bad register offset 0x%x\n", + (int)offset); + return 0; + } +} + +/* SYS_CFGCTRL functions */ +#define SYS_CFG_OSC 1 +#define SYS_CFG_VOLT 2 +#define SYS_CFG_AMP 3 +#define SYS_CFG_TEMP 4 +#define SYS_CFG_RESET 5 +#define SYS_CFG_SCC 6 +#define SYS_CFG_MUXFPGA 7 +#define SYS_CFG_SHUTDOWN 8 +#define SYS_CFG_REBOOT 9 +#define SYS_CFG_DVIMODE 11 +#define SYS_CFG_POWER 12 +#define SYS_CFG_ENERGY 13 + +/* SYS_CFGCTRL site field values */ +#define SYS_CFG_SITE_MB 0 +#define SYS_CFG_SITE_DB1 1 +#define SYS_CFG_SITE_DB2 2 + +/** + * vexpress_cfgctrl_read: + * @s: arm_sysctl_state pointer + * @dcc, @function, @site, @position, @device: split out values from + * SYS_CFGCTRL register + * @val: pointer to where to put the read data on success + * + * Handle a VExpress SYS_CFGCTRL register read. On success, return true and + * write the read value to *val. On failure, return false (and val may + * or may not be written to). + */ +static bool vexpress_cfgctrl_read(arm_sysctl_state *s, unsigned int dcc, + unsigned int function, unsigned int site, + unsigned int position, unsigned int device, + uint32_t *val) +{ + /* We don't support anything other than DCC 0, board stack position 0 + * or sites other than motherboard/daughterboard: + */ + if (dcc != 0 || position != 0 || + (site != SYS_CFG_SITE_MB && site != SYS_CFG_SITE_DB1)) { + goto cfgctrl_unimp; + } + + switch (function) { + case SYS_CFG_VOLT: + if (site == SYS_CFG_SITE_DB1 && device < s->db_num_vsensors) { + *val = s->db_voltage[device]; + return true; + } + if (site == SYS_CFG_SITE_MB && device == 0) { + /* There is only one motherboard voltage sensor: + * VIO : 3.3V : bus voltage between mother and daughterboard + */ + *val = 3300000; + return true; + } + break; + case SYS_CFG_OSC: + if (site == SYS_CFG_SITE_MB && device < sizeof(s->mb_clock)) { + /* motherboard clock */ + *val = s->mb_clock[device]; + return true; + } + if (site == SYS_CFG_SITE_DB1 && device < s->db_num_clocks) { + /* daughterboard clock */ + *val = s->db_clock[device]; + return true; + } + break; + default: + break; + } + +cfgctrl_unimp: + qemu_log_mask(LOG_UNIMP, + "arm_sysctl: Unimplemented SYS_CFGCTRL read of function " + "0x%x DCC 0x%x site 0x%x position 0x%x device 0x%x\n", + function, dcc, site, position, device); + return false; +} + +/** + * vexpress_cfgctrl_write: + * @s: arm_sysctl_state pointer + * @dcc, @function, @site, @position, @device: split out values from + * SYS_CFGCTRL register + * @val: data to write + * + * Handle a VExpress SYS_CFGCTRL register write. On success, return true. + * On failure, return false. + */ +static bool vexpress_cfgctrl_write(arm_sysctl_state *s, unsigned int dcc, + unsigned int function, unsigned int site, + unsigned int position, unsigned int device, + uint32_t val) +{ + /* We don't support anything other than DCC 0, board stack position 0 + * or sites other than motherboard/daughterboard: + */ + if (dcc != 0 || position != 0 || + (site != SYS_CFG_SITE_MB && site != SYS_CFG_SITE_DB1)) { + goto cfgctrl_unimp; + } + + switch (function) { + case SYS_CFG_OSC: + if (site == SYS_CFG_SITE_MB && device < sizeof(s->mb_clock)) { + /* motherboard clock */ + s->mb_clock[device] = val; + return true; + } + if (site == SYS_CFG_SITE_DB1 && device < s->db_num_clocks) { + /* daughterboard clock */ + s->db_clock[device] = val; + return true; + } + break; + case SYS_CFG_MUXFPGA: + if (site == SYS_CFG_SITE_MB && device == 0) { + /* Select whether video output comes from motherboard + * or daughterboard: log and ignore as QEMU doesn't + * support this. + */ + qemu_log_mask(LOG_UNIMP, "arm_sysctl: selection of video output " + "not supported, ignoring\n"); + return true; + } + break; + case SYS_CFG_SHUTDOWN: + if (site == SYS_CFG_SITE_MB && device == 0) { + qemu_system_shutdown_request(); + return true; + } + break; + case SYS_CFG_REBOOT: + if (site == SYS_CFG_SITE_MB && device == 0) { + qemu_system_reset_request(); + return true; + } + break; + case SYS_CFG_DVIMODE: + if (site == SYS_CFG_SITE_MB && device == 0) { + /* Selecting DVI mode is meaningless for QEMU: we will + * always display the output correctly according to the + * pixel height/width programmed into the CLCD controller. + */ + return true; + } + default: + break; + } + +cfgctrl_unimp: + qemu_log_mask(LOG_UNIMP, + "arm_sysctl: Unimplemented SYS_CFGCTRL write of function " + "0x%x DCC 0x%x site 0x%x position 0x%x device 0x%x\n", + function, dcc, site, position, device); + return false; +} + +static void arm_sysctl_write(void *opaque, hwaddr offset, + uint64_t val, unsigned size) +{ + arm_sysctl_state *s = (arm_sysctl_state *)opaque; + + switch (offset) { + case 0x08: /* LED */ + s->leds = val; + break; + case 0x0c: /* OSC0 */ + case 0x10: /* OSC1 */ + case 0x14: /* OSC2 */ + case 0x18: /* OSC3 */ + case 0x1c: /* OSC4 */ + /* ??? */ + break; + case 0x20: /* LOCK */ + if (val == LOCK_VALUE) + s->lockval = val; + else + s->lockval = val & 0x7fff; + break; + case 0x28: /* CFGDATA1 */ + /* ??? Need to implement this. */ + s->cfgdata1 = val; + break; + case 0x2c: /* CFGDATA2 */ + /* ??? Need to implement this. */ + s->cfgdata2 = val; + break; + case 0x30: /* FLAGSSET */ + s->flags |= val; + break; + case 0x34: /* FLAGSCLR */ + s->flags &= ~val; + break; + case 0x38: /* NVFLAGSSET */ + s->nvflags |= val; + break; + case 0x3c: /* NVFLAGSCLR */ + s->nvflags &= ~val; + break; + case 0x40: /* RESETCTL */ + switch (board_id(s)) { + case BOARD_ID_PB926: + if (s->lockval == LOCK_VALUE) { + s->resetlevel = val; + if (val & 0x100) { + qemu_system_reset_request(); + } + } + break; + case BOARD_ID_PBX: + case BOARD_ID_PBA8: + if (s->lockval == LOCK_VALUE) { + s->resetlevel = val; + if (val & 0x04) { + qemu_system_reset_request(); + } + } + break; + case BOARD_ID_VEXPRESS: + case BOARD_ID_EB: + default: + /* reserved: RAZ/WI */ + break; + } + break; + case 0x44: /* PCICTL */ + /* nothing to do. */ + break; + case 0x4c: /* FLASH */ + break; + case 0x50: /* CLCD */ + switch (board_id(s)) { + case BOARD_ID_PB926: + /* On 926 bits 13:8 are R/O, bits 1:0 control + * the mux that defines how to interpret the PL110 + * graphics format, and other bits are r/w but we + * don't implement them to do anything. + */ + s->sys_clcd &= 0x3f00; + s->sys_clcd |= val & ~0x3f00; + qemu_set_irq(s->pl110_mux_ctrl, val & 3); + break; + case BOARD_ID_EB: + /* The EB is the same except that there is no mux since + * the EB has a PL111. + */ + s->sys_clcd &= 0x3f00; + s->sys_clcd |= val & ~0x3f00; + break; + case BOARD_ID_PBA8: + case BOARD_ID_PBX: + /* On PBA8 and PBX bit 7 is r/w and all other bits + * are either r/o or RAZ/WI. + */ + s->sys_clcd &= (1 << 7); + s->sys_clcd |= val & ~(1 << 7); + break; + case BOARD_ID_VEXPRESS: + default: + /* On VExpress this register is unimplemented and will RAZ/WI */ + break; + } + break; + case 0x54: /* CLCDSER */ + case 0x64: /* DMAPSR0 */ + case 0x68: /* DMAPSR1 */ + case 0x6c: /* DMAPSR2 */ + case 0x70: /* IOSEL */ + case 0x74: /* PLDCTL */ + case 0x80: /* BUSID */ + case 0x84: /* PROCID0 */ + case 0x88: /* PROCID1 */ + case 0x8c: /* OSCRESET0 */ + case 0x90: /* OSCRESET1 */ + case 0x94: /* OSCRESET2 */ + case 0x98: /* OSCRESET3 */ + case 0x9c: /* OSCRESET4 */ + break; + case 0xa0: /* SYS_CFGDATA */ + if (board_id(s) != BOARD_ID_VEXPRESS) { + goto bad_reg; + } + s->sys_cfgdata = val; + return; + case 0xa4: /* SYS_CFGCTRL */ + if (board_id(s) != BOARD_ID_VEXPRESS) { + goto bad_reg; + } + /* Undefined bits [19:18] are RAZ/WI, and writing to + * the start bit just triggers the action; it always reads + * as zero. + */ + s->sys_cfgctrl = val & ~((3 << 18) | (1 << 31)); + if (val & (1 << 31)) { + /* Start bit set -- actually do something */ + unsigned int dcc = extract32(s->sys_cfgctrl, 26, 4); + unsigned int function = extract32(s->sys_cfgctrl, 20, 6); + unsigned int site = extract32(s->sys_cfgctrl, 16, 2); + unsigned int position = extract32(s->sys_cfgctrl, 12, 4); + unsigned int device = extract32(s->sys_cfgctrl, 0, 12); + s->sys_cfgstat = 1; /* complete */ + if (s->sys_cfgctrl & (1 << 30)) { + if (!vexpress_cfgctrl_write(s, dcc, function, site, position, + device, s->sys_cfgdata)) { + s->sys_cfgstat |= 2; /* error */ + } + } else { + uint32_t val; + if (!vexpress_cfgctrl_read(s, dcc, function, site, position, + device, &val)) { + s->sys_cfgstat |= 2; /* error */ + } else { + s->sys_cfgdata = val; + } + } + } + s->sys_cfgctrl &= ~(1 << 31); + return; + case 0xa8: /* SYS_CFGSTAT */ + if (board_id(s) != BOARD_ID_VEXPRESS) { + goto bad_reg; + } + s->sys_cfgstat = val & 3; + return; + default: + bad_reg: + qemu_log_mask(LOG_GUEST_ERROR, + "arm_sysctl_write: Bad register offset 0x%x\n", + (int)offset); + return; + } +} + +static const MemoryRegionOps arm_sysctl_ops = { + .read = arm_sysctl_read, + .write = arm_sysctl_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void arm_sysctl_gpio_set(void *opaque, int line, int level) +{ + arm_sysctl_state *s = (arm_sysctl_state *)opaque; + switch (line) { + case ARM_SYSCTL_GPIO_MMC_WPROT: + { + /* For PB926 and EB write-protect is bit 2 of SYS_MCI; + * for all later boards it is bit 1. + */ + int bit = 2; + if ((board_id(s) == BOARD_ID_PB926) || (board_id(s) == BOARD_ID_EB)) { + bit = 4; + } + s->sys_mci &= ~bit; + if (level) { + s->sys_mci |= bit; + } + break; + } + case ARM_SYSCTL_GPIO_MMC_CARDIN: + s->sys_mci &= ~1; + if (level) { + s->sys_mci |= 1; + } + break; + } +} + +static void arm_sysctl_init(Object *obj) +{ + DeviceState *dev = DEVICE(obj); + SysBusDevice *sd = SYS_BUS_DEVICE(obj); + arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, sd); + + memory_region_init_io(&s->iomem, &arm_sysctl_ops, s, "arm-sysctl", 0x1000); + sysbus_init_mmio(sd, &s->iomem); + qdev_init_gpio_in(dev, arm_sysctl_gpio_set, 2); + qdev_init_gpio_out(dev, &s->pl110_mux_ctrl, 1); +} + +static void arm_sysctl_realize(DeviceState *d, Error **errp) +{ + arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, SYS_BUS_DEVICE(d)); + s->db_clock = g_new0(uint32_t, s->db_num_clocks); +} + +static void arm_sysctl_finalize(Object *obj) +{ + SysBusDevice *dev = SYS_BUS_DEVICE(obj); + arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, dev); + g_free(s->db_voltage); + g_free(s->db_clock); + g_free(s->db_clock_reset); +} + +static Property arm_sysctl_properties[] = { + DEFINE_PROP_UINT32("sys_id", arm_sysctl_state, sys_id, 0), + DEFINE_PROP_UINT32("proc_id", arm_sysctl_state, proc_id, 0), + /* Daughterboard power supply voltages (as reported via SYS_CFG) */ + DEFINE_PROP_ARRAY("db-voltage", arm_sysctl_state, db_num_vsensors, + db_voltage, qdev_prop_uint32, uint32_t), + /* Daughterboard clock reset values (as reported via SYS_CFG) */ + DEFINE_PROP_ARRAY("db-clock", arm_sysctl_state, db_num_clocks, + db_clock_reset, qdev_prop_uint32, uint32_t), + DEFINE_PROP_END_OF_LIST(), +}; + +static void arm_sysctl_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = arm_sysctl_realize; + dc->reset = arm_sysctl_reset; + dc->vmsd = &vmstate_arm_sysctl; + dc->props = arm_sysctl_properties; +} + +static const TypeInfo arm_sysctl_info = { + .name = "realview_sysctl", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(arm_sysctl_state), + .instance_init = arm_sysctl_init, + .instance_finalize = arm_sysctl_finalize, + .class_init = arm_sysctl_class_init, +}; + +static void arm_sysctl_register_types(void) +{ + type_register_static(&arm_sysctl_info); +} + +type_init(arm_sysctl_register_types) diff --git a/hw/misc/cbus.c b/hw/misc/cbus.c new file mode 100644 index 0000000000..3d9027f692 --- /dev/null +++ b/hw/misc/cbus.c @@ -0,0 +1,618 @@ +/* + * CBUS three-pin bus and the Retu / Betty / Tahvo / Vilma / Avilma / + * Hinku / Vinku / Ahne / Pihi chips used in various Nokia platforms. + * Based on reverse-engineering of a linux driver. + * + * Copyright (C) 2008 Nokia Corporation + * Written by Andrzej Zaborowski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#include "qemu-common.h" +#include "hw/irq.h" +#include "hw/arm/devices.h" +#include "sysemu/sysemu.h" + +//#define DEBUG + +typedef struct { + void *opaque; + void (*io)(void *opaque, int rw, int reg, uint16_t *val); + int addr; +} CBusSlave; + +typedef struct { + CBus cbus; + + int sel; + int dat; + int clk; + int bit; + int dir; + uint16_t val; + qemu_irq dat_out; + + int addr; + int reg; + int rw; + enum { + cbus_address, + cbus_value, + } cycle; + + CBusSlave *slave[8]; +} CBusPriv; + +static void cbus_io(CBusPriv *s) +{ + if (s->slave[s->addr]) + s->slave[s->addr]->io(s->slave[s->addr]->opaque, + s->rw, s->reg, &s->val); + else + hw_error("%s: bad slave address %i\n", __FUNCTION__, s->addr); +} + +static void cbus_cycle(CBusPriv *s) +{ + switch (s->cycle) { + case cbus_address: + s->addr = (s->val >> 6) & 7; + s->rw = (s->val >> 5) & 1; + s->reg = (s->val >> 0) & 0x1f; + + s->cycle = cbus_value; + s->bit = 15; + s->dir = !s->rw; + s->val = 0; + + if (s->rw) + cbus_io(s); + break; + + case cbus_value: + if (!s->rw) + cbus_io(s); + + s->cycle = cbus_address; + s->bit = 8; + s->dir = 1; + s->val = 0; + break; + } +} + +static void cbus_clk(void *opaque, int line, int level) +{ + CBusPriv *s = (CBusPriv *) opaque; + + if (!s->sel && level && !s->clk) { + if (s->dir) + s->val |= s->dat << (s->bit --); + else + qemu_set_irq(s->dat_out, (s->val >> (s->bit --)) & 1); + + if (s->bit < 0) + cbus_cycle(s); + } + + s->clk = level; +} + +static void cbus_dat(void *opaque, int line, int level) +{ + CBusPriv *s = (CBusPriv *) opaque; + + s->dat = level; +} + +static void cbus_sel(void *opaque, int line, int level) +{ + CBusPriv *s = (CBusPriv *) opaque; + + if (!level) { + s->dir = 1; + s->bit = 8; + s->val = 0; + } + + s->sel = level; +} + +CBus *cbus_init(qemu_irq dat) +{ + CBusPriv *s = (CBusPriv *) g_malloc0(sizeof(*s)); + + s->dat_out = dat; + s->cbus.clk = qemu_allocate_irqs(cbus_clk, s, 1)[0]; + s->cbus.dat = qemu_allocate_irqs(cbus_dat, s, 1)[0]; + s->cbus.sel = qemu_allocate_irqs(cbus_sel, s, 1)[0]; + + s->sel = 1; + s->clk = 0; + s->dat = 0; + + return &s->cbus; +} + +void cbus_attach(CBus *bus, void *slave_opaque) +{ + CBusSlave *slave = (CBusSlave *) slave_opaque; + CBusPriv *s = (CBusPriv *) bus; + + s->slave[slave->addr] = slave; +} + +/* Retu/Vilma */ +typedef struct { + uint16_t irqst; + uint16_t irqen; + uint16_t cc[2]; + int channel; + uint16_t result[16]; + uint16_t sample; + uint16_t status; + + struct { + uint16_t cal; + } rtc; + + int is_vilma; + qemu_irq irq; + CBusSlave cbus; +} CBusRetu; + +static void retu_interrupt_update(CBusRetu *s) +{ + qemu_set_irq(s->irq, s->irqst & ~s->irqen); +} + +#define RETU_REG_ASICR 0x00 /* (RO) ASIC ID & revision */ +#define RETU_REG_IDR 0x01 /* (T) Interrupt ID */ +#define RETU_REG_IMR 0x02 /* (RW) Interrupt mask */ +#define RETU_REG_RTCDSR 0x03 /* (RW) RTC seconds register */ +#define RETU_REG_RTCHMR 0x04 /* (RO) RTC hours and minutes reg */ +#define RETU_REG_RTCHMAR 0x05 /* (RW) RTC hours and minutes set reg */ +#define RETU_REG_RTCCALR 0x06 /* (RW) RTC calibration register */ +#define RETU_REG_ADCR 0x08 /* (RW) ADC result register */ +#define RETU_REG_ADCSCR 0x09 /* (RW) ADC sample control register */ +#define RETU_REG_AFCR 0x0a /* (RW) AFC register */ +#define RETU_REG_ANTIFR 0x0b /* (RW) AntiF register */ +#define RETU_REG_CALIBR 0x0c /* (RW) CalibR register*/ +#define RETU_REG_CCR1 0x0d /* (RW) Common control register 1 */ +#define RETU_REG_CCR2 0x0e /* (RW) Common control register 2 */ +#define RETU_REG_RCTRL_CLR 0x0f /* (T) Regulator clear register */ +#define RETU_REG_RCTRL_SET 0x10 /* (T) Regulator set register */ +#define RETU_REG_TXCR 0x11 /* (RW) TxC register */ +#define RETU_REG_STATUS 0x16 /* (RO) Status register */ +#define RETU_REG_WATCHDOG 0x17 /* (RW) Watchdog register */ +#define RETU_REG_AUDTXR 0x18 /* (RW) Audio Codec Tx register */ +#define RETU_REG_AUDPAR 0x19 /* (RW) AudioPA register */ +#define RETU_REG_AUDRXR1 0x1a /* (RW) Audio receive register 1 */ +#define RETU_REG_AUDRXR2 0x1b /* (RW) Audio receive register 2 */ +#define RETU_REG_SGR1 0x1c /* (RW) */ +#define RETU_REG_SCR1 0x1d /* (RW) */ +#define RETU_REG_SGR2 0x1e /* (RW) */ +#define RETU_REG_SCR2 0x1f /* (RW) */ + +/* Retu Interrupt sources */ +enum { + retu_int_pwr = 0, /* Power button */ + retu_int_char = 1, /* Charger */ + retu_int_rtcs = 2, /* Seconds */ + retu_int_rtcm = 3, /* Minutes */ + retu_int_rtcd = 4, /* Days */ + retu_int_rtca = 5, /* Alarm */ + retu_int_hook = 6, /* Hook */ + retu_int_head = 7, /* Headset */ + retu_int_adcs = 8, /* ADC sample */ +}; + +/* Retu ADC channel wiring */ +enum { + retu_adc_bsi = 1, /* BSI */ + retu_adc_batt_temp = 2, /* Battery temperature */ + retu_adc_chg_volt = 3, /* Charger voltage */ + retu_adc_head_det = 4, /* Headset detection */ + retu_adc_hook_det = 5, /* Hook detection */ + retu_adc_rf_gp = 6, /* RF GP */ + retu_adc_tx_det = 7, /* Wideband Tx detection */ + retu_adc_batt_volt = 8, /* Battery voltage */ + retu_adc_sens = 10, /* Light sensor */ + retu_adc_sens_temp = 11, /* Light sensor temperature */ + retu_adc_bbatt_volt = 12, /* Backup battery voltage */ + retu_adc_self_temp = 13, /* RETU temperature */ +}; + +static inline uint16_t retu_read(CBusRetu *s, int reg) +{ +#ifdef DEBUG + printf("RETU read at %02x\n", reg); +#endif + + switch (reg) { + case RETU_REG_ASICR: + return 0x0215 | (s->is_vilma << 7); + + case RETU_REG_IDR: /* TODO: Or is this ffs(s->irqst)? */ + return s->irqst; + + case RETU_REG_IMR: + return s->irqen; + + case RETU_REG_RTCDSR: + case RETU_REG_RTCHMR: + case RETU_REG_RTCHMAR: + /* TODO */ + return 0x0000; + + case RETU_REG_RTCCALR: + return s->rtc.cal; + + case RETU_REG_ADCR: + return (s->channel << 10) | s->result[s->channel]; + case RETU_REG_ADCSCR: + return s->sample; + + case RETU_REG_AFCR: + case RETU_REG_ANTIFR: + case RETU_REG_CALIBR: + /* TODO */ + return 0x0000; + + case RETU_REG_CCR1: + return s->cc[0]; + case RETU_REG_CCR2: + return s->cc[1]; + + case RETU_REG_RCTRL_CLR: + case RETU_REG_RCTRL_SET: + case RETU_REG_TXCR: + /* TODO */ + return 0x0000; + + case RETU_REG_STATUS: + return s->status; + + case RETU_REG_WATCHDOG: + case RETU_REG_AUDTXR: + case RETU_REG_AUDPAR: + case RETU_REG_AUDRXR1: + case RETU_REG_AUDRXR2: + case RETU_REG_SGR1: + case RETU_REG_SCR1: + case RETU_REG_SGR2: + case RETU_REG_SCR2: + /* TODO */ + return 0x0000; + + default: + hw_error("%s: bad register %02x\n", __FUNCTION__, reg); + } +} + +static inline void retu_write(CBusRetu *s, int reg, uint16_t val) +{ +#ifdef DEBUG + printf("RETU write of %04x at %02x\n", val, reg); +#endif + + switch (reg) { + case RETU_REG_IDR: + s->irqst ^= val; + retu_interrupt_update(s); + break; + + case RETU_REG_IMR: + s->irqen = val; + retu_interrupt_update(s); + break; + + case RETU_REG_RTCDSR: + case RETU_REG_RTCHMAR: + /* TODO */ + break; + + case RETU_REG_RTCCALR: + s->rtc.cal = val; + break; + + case RETU_REG_ADCR: + s->channel = (val >> 10) & 0xf; + s->irqst |= 1 << retu_int_adcs; + retu_interrupt_update(s); + break; + case RETU_REG_ADCSCR: + s->sample &= ~val; + break; + + case RETU_REG_AFCR: + case RETU_REG_ANTIFR: + case RETU_REG_CALIBR: + + case RETU_REG_CCR1: + s->cc[0] = val; + break; + case RETU_REG_CCR2: + s->cc[1] = val; + break; + + case RETU_REG_RCTRL_CLR: + case RETU_REG_RCTRL_SET: + /* TODO */ + break; + + case RETU_REG_WATCHDOG: + if (val == 0 && (s->cc[0] & 2)) + qemu_system_shutdown_request(); + break; + + case RETU_REG_TXCR: + case RETU_REG_AUDTXR: + case RETU_REG_AUDPAR: + case RETU_REG_AUDRXR1: + case RETU_REG_AUDRXR2: + case RETU_REG_SGR1: + case RETU_REG_SCR1: + case RETU_REG_SGR2: + case RETU_REG_SCR2: + /* TODO */ + break; + + default: + hw_error("%s: bad register %02x\n", __FUNCTION__, reg); + } +} + +static void retu_io(void *opaque, int rw, int reg, uint16_t *val) +{ + CBusRetu *s = (CBusRetu *) opaque; + + if (rw) + *val = retu_read(s, reg); + else + retu_write(s, reg, *val); +} + +void *retu_init(qemu_irq irq, int vilma) +{ + CBusRetu *s = (CBusRetu *) g_malloc0(sizeof(*s)); + + s->irq = irq; + s->irqen = 0xffff; + s->irqst = 0x0000; + s->status = 0x0020; + s->is_vilma = !!vilma; + s->rtc.cal = 0x01; + s->result[retu_adc_bsi] = 0x3c2; + s->result[retu_adc_batt_temp] = 0x0fc; + s->result[retu_adc_chg_volt] = 0x165; + s->result[retu_adc_head_det] = 123; + s->result[retu_adc_hook_det] = 1023; + s->result[retu_adc_rf_gp] = 0x11; + s->result[retu_adc_tx_det] = 0x11; + s->result[retu_adc_batt_volt] = 0x250; + s->result[retu_adc_sens] = 2; + s->result[retu_adc_sens_temp] = 0x11; + s->result[retu_adc_bbatt_volt] = 0x3d0; + s->result[retu_adc_self_temp] = 0x330; + + s->cbus.opaque = s; + s->cbus.io = retu_io; + s->cbus.addr = 1; + + return &s->cbus; +} + +void retu_key_event(void *retu, int state) +{ + CBusSlave *slave = (CBusSlave *) retu; + CBusRetu *s = (CBusRetu *) slave->opaque; + + s->irqst |= 1 << retu_int_pwr; + retu_interrupt_update(s); + + if (state) + s->status &= ~(1 << 5); + else + s->status |= 1 << 5; +} + +#if 0 +static void retu_head_event(void *retu, int state) +{ + CBusSlave *slave = (CBusSlave *) retu; + CBusRetu *s = (CBusRetu *) slave->opaque; + + if ((s->cc[0] & 0x500) == 0x500) { /* TODO: Which bits? */ + /* TODO: reissue the interrupt every 100ms or so. */ + s->irqst |= 1 << retu_int_head; + retu_interrupt_update(s); + } + + if (state) + s->result[retu_adc_head_det] = 50; + else + s->result[retu_adc_head_det] = 123; +} + +static void retu_hook_event(void *retu, int state) +{ + CBusSlave *slave = (CBusSlave *) retu; + CBusRetu *s = (CBusRetu *) slave->opaque; + + if ((s->cc[0] & 0x500) == 0x500) { + /* TODO: reissue the interrupt every 100ms or so. */ + s->irqst |= 1 << retu_int_hook; + retu_interrupt_update(s); + } + + if (state) + s->result[retu_adc_hook_det] = 50; + else + s->result[retu_adc_hook_det] = 123; +} +#endif + +/* Tahvo/Betty */ +typedef struct { + uint16_t irqst; + uint16_t irqen; + uint8_t charger; + uint8_t backlight; + uint16_t usbr; + uint16_t power; + + int is_betty; + qemu_irq irq; + CBusSlave cbus; +} CBusTahvo; + +static void tahvo_interrupt_update(CBusTahvo *s) +{ + qemu_set_irq(s->irq, s->irqst & ~s->irqen); +} + +#define TAHVO_REG_ASICR 0x00 /* (RO) ASIC ID & revision */ +#define TAHVO_REG_IDR 0x01 /* (T) Interrupt ID */ +#define TAHVO_REG_IDSR 0x02 /* (RO) Interrupt status */ +#define TAHVO_REG_IMR 0x03 /* (RW) Interrupt mask */ +#define TAHVO_REG_CHAPWMR 0x04 /* (RW) Charger PWM */ +#define TAHVO_REG_LEDPWMR 0x05 /* (RW) LED PWM */ +#define TAHVO_REG_USBR 0x06 /* (RW) USB control */ +#define TAHVO_REG_RCR 0x07 /* (RW) Some kind of power management */ +#define TAHVO_REG_CCR1 0x08 /* (RW) Common control register 1 */ +#define TAHVO_REG_CCR2 0x09 /* (RW) Common control register 2 */ +#define TAHVO_REG_TESTR1 0x0a /* (RW) Test register 1 */ +#define TAHVO_REG_TESTR2 0x0b /* (RW) Test register 2 */ +#define TAHVO_REG_NOPR 0x0c /* (RW) Number of periods */ +#define TAHVO_REG_FRR 0x0d /* (RO) FR */ + +static inline uint16_t tahvo_read(CBusTahvo *s, int reg) +{ +#ifdef DEBUG + printf("TAHVO read at %02x\n", reg); +#endif + + switch (reg) { + case TAHVO_REG_ASICR: + return 0x0021 | (s->is_betty ? 0x0b00 : 0x0300); /* 22 in N810 */ + + case TAHVO_REG_IDR: + case TAHVO_REG_IDSR: /* XXX: what does this do? */ + return s->irqst; + + case TAHVO_REG_IMR: + return s->irqen; + + case TAHVO_REG_CHAPWMR: + return s->charger; + + case TAHVO_REG_LEDPWMR: + return s->backlight; + + case TAHVO_REG_USBR: + return s->usbr; + + case TAHVO_REG_RCR: + return s->power; + + case TAHVO_REG_CCR1: + case TAHVO_REG_CCR2: + case TAHVO_REG_TESTR1: + case TAHVO_REG_TESTR2: + case TAHVO_REG_NOPR: + case TAHVO_REG_FRR: + return 0x0000; + + default: + hw_error("%s: bad register %02x\n", __FUNCTION__, reg); + } +} + +static inline void tahvo_write(CBusTahvo *s, int reg, uint16_t val) +{ +#ifdef DEBUG + printf("TAHVO write of %04x at %02x\n", val, reg); +#endif + + switch (reg) { + case TAHVO_REG_IDR: + s->irqst ^= val; + tahvo_interrupt_update(s); + break; + + case TAHVO_REG_IMR: + s->irqen = val; + tahvo_interrupt_update(s); + break; + + case TAHVO_REG_CHAPWMR: + s->charger = val; + break; + + case TAHVO_REG_LEDPWMR: + if (s->backlight != (val & 0x7f)) { + s->backlight = val & 0x7f; + printf("%s: LCD backlight now at %i / 127\n", + __FUNCTION__, s->backlight); + } + break; + + case TAHVO_REG_USBR: + s->usbr = val; + break; + + case TAHVO_REG_RCR: + s->power = val; + break; + + case TAHVO_REG_CCR1: + case TAHVO_REG_CCR2: + case TAHVO_REG_TESTR1: + case TAHVO_REG_TESTR2: + case TAHVO_REG_NOPR: + case TAHVO_REG_FRR: + break; + + default: + hw_error("%s: bad register %02x\n", __FUNCTION__, reg); + } +} + +static void tahvo_io(void *opaque, int rw, int reg, uint16_t *val) +{ + CBusTahvo *s = (CBusTahvo *) opaque; + + if (rw) + *val = tahvo_read(s, reg); + else + tahvo_write(s, reg, *val); +} + +void *tahvo_init(qemu_irq irq, int betty) +{ + CBusTahvo *s = (CBusTahvo *) g_malloc0(sizeof(*s)); + + s->irq = irq; + s->irqen = 0xffff; + s->irqst = 0x0000; + s->is_betty = !!betty; + + s->cbus.opaque = s; + s->cbus.io = tahvo_io; + s->cbus.addr = 2; + + return &s->cbus; +} diff --git a/hw/misc/debugexit.c b/hw/misc/debugexit.c new file mode 100644 index 0000000000..59bed5bff5 --- /dev/null +++ b/hw/misc/debugexit.c @@ -0,0 +1,75 @@ +/* + * debug exit port emulation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + */ + +#include "hw/hw.h" +#include "hw/isa/isa.h" + +#define TYPE_ISA_DEBUG_EXIT_DEVICE "isa-debug-exit" +#define ISA_DEBUG_EXIT_DEVICE(obj) \ + OBJECT_CHECK(ISADebugExitState, (obj), TYPE_ISA_DEBUG_EXIT_DEVICE) + +typedef struct ISADebugExitState { + ISADevice parent_obj; + + uint32_t iobase; + uint32_t iosize; + MemoryRegion io; +} ISADebugExitState; + +static void debug_exit_write(void *opaque, hwaddr addr, uint64_t val, + unsigned width) +{ + exit((val << 1) | 1); +} + +static const MemoryRegionOps debug_exit_ops = { + .write = debug_exit_write, + .valid.min_access_size = 1, + .valid.max_access_size = 4, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static int debug_exit_initfn(ISADevice *dev) +{ + ISADebugExitState *isa = ISA_DEBUG_EXIT_DEVICE(dev); + + memory_region_init_io(&isa->io, &debug_exit_ops, isa, + TYPE_ISA_DEBUG_EXIT_DEVICE, isa->iosize); + memory_region_add_subregion(isa_address_space_io(dev), + isa->iobase, &isa->io); + return 0; +} + +static Property debug_exit_properties[] = { + DEFINE_PROP_HEX32("iobase", ISADebugExitState, iobase, 0x501), + DEFINE_PROP_HEX32("iosize", ISADebugExitState, iosize, 0x02), + DEFINE_PROP_END_OF_LIST(), +}; + +static void debug_exit_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ISADeviceClass *ic = ISA_DEVICE_CLASS(klass); + ic->init = debug_exit_initfn; + dc->props = debug_exit_properties; +} + +static const TypeInfo debug_exit_info = { + .name = TYPE_ISA_DEBUG_EXIT_DEVICE, + .parent = TYPE_ISA_DEVICE, + .instance_size = sizeof(ISADebugExitState), + .class_init = debug_exit_class_initfn, +}; + +static void debug_exit_register_types(void) +{ + type_register_static(&debug_exit_info); +} + +type_init(debug_exit_register_types) diff --git a/hw/misc/eccmemctl.c b/hw/misc/eccmemctl.c new file mode 100644 index 0000000000..6f4a407cbf --- /dev/null +++ b/hw/misc/eccmemctl.c @@ -0,0 +1,340 @@ +/* + * QEMU Sparc Sun4m ECC memory controller emulation + * + * Copyright (c) 2007 Robert Reif + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "hw/sysbus.h" +#include "trace.h" + +/* There are 3 versions of this chip used in SMP sun4m systems: + * MCC (version 0, implementation 0) SS-600MP + * EMC (version 0, implementation 1) SS-10 + * SMC (version 0, implementation 2) SS-10SX and SS-20 + * + * Chipset docs: + * "Sun-4M System Architecture (revision 2.0) by Chuck Narad", 950-1373-01, + * http://mediacast.sun.com/users/Barton808/media/Sun4M_SystemArchitecture_edited2.pdf + */ + +#define ECC_MCC 0x00000000 +#define ECC_EMC 0x10000000 +#define ECC_SMC 0x20000000 + +/* Register indexes */ +#define ECC_MER 0 /* Memory Enable Register */ +#define ECC_MDR 1 /* Memory Delay Register */ +#define ECC_MFSR 2 /* Memory Fault Status Register */ +#define ECC_VCR 3 /* Video Configuration Register */ +#define ECC_MFAR0 4 /* Memory Fault Address Register 0 */ +#define ECC_MFAR1 5 /* Memory Fault Address Register 1 */ +#define ECC_DR 6 /* Diagnostic Register */ +#define ECC_ECR0 7 /* Event Count Register 0 */ +#define ECC_ECR1 8 /* Event Count Register 1 */ + +/* ECC fault control register */ +#define ECC_MER_EE 0x00000001 /* Enable ECC checking */ +#define ECC_MER_EI 0x00000002 /* Enable Interrupts on + correctable errors */ +#define ECC_MER_MRR0 0x00000004 /* SIMM 0 */ +#define ECC_MER_MRR1 0x00000008 /* SIMM 1 */ +#define ECC_MER_MRR2 0x00000010 /* SIMM 2 */ +#define ECC_MER_MRR3 0x00000020 /* SIMM 3 */ +#define ECC_MER_MRR4 0x00000040 /* SIMM 4 */ +#define ECC_MER_MRR5 0x00000080 /* SIMM 5 */ +#define ECC_MER_MRR6 0x00000100 /* SIMM 6 */ +#define ECC_MER_MRR7 0x00000200 /* SIMM 7 */ +#define ECC_MER_REU 0x00000100 /* Memory Refresh Enable (600MP) */ +#define ECC_MER_MRR 0x000003fc /* MRR mask */ +#define ECC_MER_A 0x00000400 /* Memory controller addr map select */ +#define ECC_MER_DCI 0x00000800 /* Disables Coherent Invalidate ACK */ +#define ECC_MER_VER 0x0f000000 /* Version */ +#define ECC_MER_IMPL 0xf0000000 /* Implementation */ +#define ECC_MER_MASK_0 0x00000103 /* Version 0 (MCC) mask */ +#define ECC_MER_MASK_1 0x00000bff /* Version 1 (EMC) mask */ +#define ECC_MER_MASK_2 0x00000bff /* Version 2 (SMC) mask */ + +/* ECC memory delay register */ +#define ECC_MDR_RRI 0x000003ff /* Refresh Request Interval */ +#define ECC_MDR_MI 0x00001c00 /* MIH Delay */ +#define ECC_MDR_CI 0x0000e000 /* Coherent Invalidate Delay */ +#define ECC_MDR_MDL 0x001f0000 /* MBus Master arbitration delay */ +#define ECC_MDR_MDH 0x03e00000 /* MBus Master arbitration delay */ +#define ECC_MDR_GAD 0x7c000000 /* Graphics Arbitration Delay */ +#define ECC_MDR_RSC 0x80000000 /* Refresh load control */ +#define ECC_MDR_MASK 0x7fffffff + +/* ECC fault status register */ +#define ECC_MFSR_CE 0x00000001 /* Correctable error */ +#define ECC_MFSR_BS 0x00000002 /* C2 graphics bad slot access */ +#define ECC_MFSR_TO 0x00000004 /* Timeout on write */ +#define ECC_MFSR_UE 0x00000008 /* Uncorrectable error */ +#define ECC_MFSR_DW 0x000000f0 /* Index of double word in block */ +#define ECC_MFSR_SYND 0x0000ff00 /* Syndrome for correctable error */ +#define ECC_MFSR_ME 0x00010000 /* Multiple errors */ +#define ECC_MFSR_C2ERR 0x00020000 /* C2 graphics error */ + +/* ECC fault address register 0 */ +#define ECC_MFAR0_PADDR 0x0000000f /* PA[32-35] */ +#define ECC_MFAR0_TYPE 0x000000f0 /* Transaction type */ +#define ECC_MFAR0_SIZE 0x00000700 /* Transaction size */ +#define ECC_MFAR0_CACHE 0x00000800 /* Mapped cacheable */ +#define ECC_MFAR0_LOCK 0x00001000 /* Error occurred in atomic cycle */ +#define ECC_MFAR0_BMODE 0x00002000 /* Boot mode */ +#define ECC_MFAR0_VADDR 0x003fc000 /* VA[12-19] (superset bits) */ +#define ECC_MFAR0_S 0x08000000 /* Supervisor mode */ +#define ECC_MFARO_MID 0xf0000000 /* Module ID */ + +/* ECC diagnostic register */ +#define ECC_DR_CBX 0x00000001 +#define ECC_DR_CB0 0x00000002 +#define ECC_DR_CB1 0x00000004 +#define ECC_DR_CB2 0x00000008 +#define ECC_DR_CB4 0x00000010 +#define ECC_DR_CB8 0x00000020 +#define ECC_DR_CB16 0x00000040 +#define ECC_DR_CB32 0x00000080 +#define ECC_DR_DMODE 0x00000c00 + +#define ECC_NREGS 9 +#define ECC_SIZE (ECC_NREGS * sizeof(uint32_t)) + +#define ECC_DIAG_SIZE 4 +#define ECC_DIAG_MASK (ECC_DIAG_SIZE - 1) + +typedef struct ECCState { + SysBusDevice busdev; + MemoryRegion iomem, iomem_diag; + qemu_irq irq; + uint32_t regs[ECC_NREGS]; + uint8_t diag[ECC_DIAG_SIZE]; + uint32_t version; +} ECCState; + +static void ecc_mem_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ + ECCState *s = opaque; + + switch (addr >> 2) { + case ECC_MER: + if (s->version == ECC_MCC) + s->regs[ECC_MER] = (val & ECC_MER_MASK_0); + else if (s->version == ECC_EMC) + s->regs[ECC_MER] = s->version | (val & ECC_MER_MASK_1); + else if (s->version == ECC_SMC) + s->regs[ECC_MER] = s->version | (val & ECC_MER_MASK_2); + trace_ecc_mem_writel_mer(val); + break; + case ECC_MDR: + s->regs[ECC_MDR] = val & ECC_MDR_MASK; + trace_ecc_mem_writel_mdr(val); + break; + case ECC_MFSR: + s->regs[ECC_MFSR] = val; + qemu_irq_lower(s->irq); + trace_ecc_mem_writel_mfsr(val); + break; + case ECC_VCR: + s->regs[ECC_VCR] = val; + trace_ecc_mem_writel_vcr(val); + break; + case ECC_DR: + s->regs[ECC_DR] = val; + trace_ecc_mem_writel_dr(val); + break; + case ECC_ECR0: + s->regs[ECC_ECR0] = val; + trace_ecc_mem_writel_ecr0(val); + break; + case ECC_ECR1: + s->regs[ECC_ECR0] = val; + trace_ecc_mem_writel_ecr1(val); + break; + } +} + +static uint64_t ecc_mem_read(void *opaque, hwaddr addr, + unsigned size) +{ + ECCState *s = opaque; + uint32_t ret = 0; + + switch (addr >> 2) { + case ECC_MER: + ret = s->regs[ECC_MER]; + trace_ecc_mem_readl_mer(ret); + break; + case ECC_MDR: + ret = s->regs[ECC_MDR]; + trace_ecc_mem_readl_mdr(ret); + break; + case ECC_MFSR: + ret = s->regs[ECC_MFSR]; + trace_ecc_mem_readl_mfsr(ret); + break; + case ECC_VCR: + ret = s->regs[ECC_VCR]; + trace_ecc_mem_readl_vcr(ret); + break; + case ECC_MFAR0: + ret = s->regs[ECC_MFAR0]; + trace_ecc_mem_readl_mfar0(ret); + break; + case ECC_MFAR1: + ret = s->regs[ECC_MFAR1]; + trace_ecc_mem_readl_mfar1(ret); + break; + case ECC_DR: + ret = s->regs[ECC_DR]; + trace_ecc_mem_readl_dr(ret); + break; + case ECC_ECR0: + ret = s->regs[ECC_ECR0]; + trace_ecc_mem_readl_ecr0(ret); + break; + case ECC_ECR1: + ret = s->regs[ECC_ECR0]; + trace_ecc_mem_readl_ecr1(ret); + break; + } + return ret; +} + +static const MemoryRegionOps ecc_mem_ops = { + .read = ecc_mem_read, + .write = ecc_mem_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; + +static void ecc_diag_mem_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + ECCState *s = opaque; + + trace_ecc_diag_mem_writeb(addr, val); + s->diag[addr & ECC_DIAG_MASK] = val; +} + +static uint64_t ecc_diag_mem_read(void *opaque, hwaddr addr, + unsigned size) +{ + ECCState *s = opaque; + uint32_t ret = s->diag[(int)addr]; + + trace_ecc_diag_mem_readb(addr, ret); + return ret; +} + +static const MemoryRegionOps ecc_diag_mem_ops = { + .read = ecc_diag_mem_read, + .write = ecc_diag_mem_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 1, + }, +}; + +static const VMStateDescription vmstate_ecc = { + .name ="ECC", + .version_id = 3, + .minimum_version_id = 3, + .minimum_version_id_old = 3, + .fields = (VMStateField []) { + VMSTATE_UINT32_ARRAY(regs, ECCState, ECC_NREGS), + VMSTATE_BUFFER(diag, ECCState), + VMSTATE_UINT32(version, ECCState), + VMSTATE_END_OF_LIST() + } +}; + +static void ecc_reset(DeviceState *d) +{ + ECCState *s = container_of(d, ECCState, busdev.qdev); + + if (s->version == ECC_MCC) + s->regs[ECC_MER] &= ECC_MER_REU; + else + s->regs[ECC_MER] &= (ECC_MER_VER | ECC_MER_IMPL | ECC_MER_MRR | + ECC_MER_DCI); + s->regs[ECC_MDR] = 0x20; + s->regs[ECC_MFSR] = 0; + s->regs[ECC_VCR] = 0; + s->regs[ECC_MFAR0] = 0x07c00000; + s->regs[ECC_MFAR1] = 0; + s->regs[ECC_DR] = 0; + s->regs[ECC_ECR0] = 0; + s->regs[ECC_ECR1] = 0; +} + +static int ecc_init1(SysBusDevice *dev) +{ + ECCState *s = FROM_SYSBUS(ECCState, dev); + + sysbus_init_irq(dev, &s->irq); + s->regs[0] = s->version; + memory_region_init_io(&s->iomem, &ecc_mem_ops, s, "ecc", ECC_SIZE); + sysbus_init_mmio(dev, &s->iomem); + + if (s->version == ECC_MCC) { // SS-600MP only + memory_region_init_io(&s->iomem_diag, &ecc_diag_mem_ops, s, + "ecc.diag", ECC_DIAG_SIZE); + sysbus_init_mmio(dev, &s->iomem_diag); + } + + return 0; +} + +static Property ecc_properties[] = { + DEFINE_PROP_HEX32("version", ECCState, version, -1), + DEFINE_PROP_END_OF_LIST(), +}; + +static void ecc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = ecc_init1; + dc->reset = ecc_reset; + dc->vmsd = &vmstate_ecc; + dc->props = ecc_properties; +} + +static const TypeInfo ecc_info = { + .name = "eccmemctl", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(ECCState), + .class_init = ecc_class_init, +}; + + +static void ecc_register_types(void) +{ + type_register_static(&ecc_info); +} + +type_init(ecc_register_types) diff --git a/hw/misc/exynos4210_pmu.c b/hw/misc/exynos4210_pmu.c new file mode 100644 index 0000000000..ba5aa8d0e4 --- /dev/null +++ b/hw/misc/exynos4210_pmu.c @@ -0,0 +1,499 @@ +/* + * Exynos4210 Power Management Unit (PMU) Emulation + * + * Copyright (C) 2011 Samsung Electronics Co Ltd. + * Maksim Kozlov + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +/* + * This model implements PMU registers just as a bulk of memory. Currently, + * the only reason this device exists is that secondary CPU boot loader + * uses PMU INFORM5 register as a holding pen. + */ + +#include "hw/sysbus.h" + +#ifndef DEBUG_PMU +#define DEBUG_PMU 0 +#endif + +#ifndef DEBUG_PMU_EXTEND +#define DEBUG_PMU_EXTEND 0 +#endif + +#if DEBUG_PMU +#define PRINT_DEBUG(fmt, args...) \ + do { \ + fprintf(stderr, " [%s:%d] "fmt, __func__, __LINE__, ##args); \ + } while (0) + +#if DEBUG_PMU_EXTEND +#define PRINT_DEBUG_EXTEND(fmt, args...) \ + do { \ + fprintf(stderr, " [%s:%d] "fmt, __func__, __LINE__, ##args); \ + } while (0) +#else +#define PRINT_DEBUG_EXTEND(fmt, args...) do {} while (0) +#endif /* EXTEND */ + +#else +#define PRINT_DEBUG(fmt, args...) do {} while (0) +#define PRINT_DEBUG_EXTEND(fmt, args...) do {} while (0) +#endif + +/* + * Offsets for PMU registers + */ +#define OM_STAT 0x0000 /* OM status register */ +#define RTC_CLKO_SEL 0x000C /* Controls RTCCLKOUT */ +#define GNSS_RTC_OUT_CTRL 0x0010 /* Controls GNSS_RTC_OUT */ +/* Decides whether system-level low-power mode is used. */ +#define SYSTEM_POWER_DOWN_CTRL 0x0200 +/* Sets control options for CENTRAL_SEQ */ +#define SYSTEM_POWER_DOWN_OPTION 0x0208 +#define SWRESET 0x0400 /* Generate software reset */ +#define RST_STAT 0x0404 /* Reset status register */ +#define WAKEUP_STAT 0x0600 /* Wakeup status register */ +#define EINT_WAKEUP_MASK 0x0604 /* Configure External INTerrupt mask */ +#define WAKEUP_MASK 0x0608 /* Configure wakeup source mask */ +#define HDMI_PHY_CONTROL 0x0700 /* HDMI PHY control register */ +#define USBDEVICE_PHY_CONTROL 0x0704 /* USB Device PHY control register */ +#define USBHOST_PHY_CONTROL 0x0708 /* USB HOST PHY control register */ +#define DAC_PHY_CONTROL 0x070C /* DAC control register */ +#define MIPI_PHY0_CONTROL 0x0710 /* MIPI PHY control register */ +#define MIPI_PHY1_CONTROL 0x0714 /* MIPI PHY control register */ +#define ADC_PHY_CONTROL 0x0718 /* TS-ADC control register */ +#define PCIe_PHY_CONTROL 0x071C /* TS-PCIe control register */ +#define SATA_PHY_CONTROL 0x0720 /* TS-SATA control register */ +#define INFORM0 0x0800 /* Information register 0 */ +#define INFORM1 0x0804 /* Information register 1 */ +#define INFORM2 0x0808 /* Information register 2 */ +#define INFORM3 0x080C /* Information register 3 */ +#define INFORM4 0x0810 /* Information register 4 */ +#define INFORM5 0x0814 /* Information register 5 */ +#define INFORM6 0x0818 /* Information register 6 */ +#define INFORM7 0x081C /* Information register 7 */ +#define PMU_DEBUG 0x0A00 /* PMU debug register */ +/* Registers to set system-level low-power option */ +#define ARM_CORE0_SYS_PWR_REG 0x1000 +#define ARM_CORE1_SYS_PWR_REG 0x1010 +#define ARM_COMMON_SYS_PWR_REG 0x1080 +#define ARM_CPU_L2_0_SYS_PWR_REG 0x10C0 +#define ARM_CPU_L2_1_SYS_PWR_REG 0x10C4 +#define CMU_ACLKSTOP_SYS_PWR_REG 0x1100 +#define CMU_SCLKSTOP_SYS_PWR_REG 0x1104 +#define CMU_RESET_SYS_PWR_REG 0x110C +#define APLL_SYSCLK_SYS_PWR_REG 0x1120 +#define MPLL_SYSCLK_SYS_PWR_REG 0x1124 +#define VPLL_SYSCLK_SYS_PWR_REG 0x1128 +#define EPLL_SYSCLK_SYS_PWR_REG 0x112C +#define CMU_CLKSTOP_GPS_ALIVE_SYS_PWR_REG 0x1138 +#define CMU_RESET_GPS_ALIVE_SYS_PWR_REG 0x113C +#define CMU_CLKSTOP_CAM_SYS_PWR_REG 0x1140 +#define CMU_CLKSTOP_TV_SYS_PWR_REG 0x1144 +#define CMU_CLKSTOP_MFC_SYS_PWR_REG 0x1148 +#define CMU_CLKSTOP_G3D_SYS_PWR_REG 0x114C +#define CMU_CLKSTOP_LCD0_SYS_PWR_REG 0x1150 +#define CMU_CLKSTOP_LCD1_SYS_PWR_REG 0x1154 +#define CMU_CLKSTOP_MAUDIO_SYS_PWR_REG 0x1158 +#define CMU_CLKSTOP_GPS_SYS_PWR_REG 0x115C +#define CMU_RESET_CAM_SYS_PWR_REG 0x1160 +#define CMU_RESET_TV_SYS_PWR_REG 0x1164 +#define CMU_RESET_MFC_SYS_PWR_REG 0x1168 +#define CMU_RESET_G3D_SYS_PWR_REG 0x116C +#define CMU_RESET_LCD0_SYS_PWR_REG 0x1170 +#define CMU_RESET_LCD1_SYS_PWR_REG 0x1174 +#define CMU_RESET_MAUDIO_SYS_PWR_REG 0x1178 +#define CMU_RESET_GPS_SYS_PWR_REG 0x117C +#define TOP_BUS_SYS_PWR_REG 0x1180 +#define TOP_RETENTION_SYS_PWR_REG 0x1184 +#define TOP_PWR_SYS_PWR_REG 0x1188 +#define LOGIC_RESET_SYS_PWR_REG 0x11A0 +#define OneNANDXL_MEM_SYS_PWR_REG 0x11C0 +#define MODEMIF_MEM_SYS_PWR_REG 0x11C4 +#define USBDEVICE_MEM_SYS_PWR_REG 0x11CC +#define SDMMC_MEM_SYS_PWR_REG 0x11D0 +#define CSSYS_MEM_SYS_PWR_REG 0x11D4 +#define SECSS_MEM_SYS_PWR_REG 0x11D8 +#define PCIe_MEM_SYS_PWR_REG 0x11E0 +#define SATA_MEM_SYS_PWR_REG 0x11E4 +#define PAD_RETENTION_DRAM_SYS_PWR_REG 0x1200 +#define PAD_RETENTION_MAUDIO_SYS_PWR_REG 0x1204 +#define PAD_RETENTION_GPIO_SYS_PWR_REG 0x1220 +#define PAD_RETENTION_UART_SYS_PWR_REG 0x1224 +#define PAD_RETENTION_MMCA_SYS_PWR_REG 0x1228 +#define PAD_RETENTION_MMCB_SYS_PWR_REG 0x122C +#define PAD_RETENTION_EBIA_SYS_PWR_REG 0x1230 +#define PAD_RETENTION_EBIB_SYS_PWR_REG 0x1234 +#define PAD_ISOLATION_SYS_PWR_REG 0x1240 +#define PAD_ALV_SEL_SYS_PWR_REG 0x1260 +#define XUSBXTI_SYS_PWR_REG 0x1280 +#define XXTI_SYS_PWR_REG 0x1284 +#define EXT_REGULATOR_SYS_PWR_REG 0x12C0 +#define GPIO_MODE_SYS_PWR_REG 0x1300 +#define GPIO_MODE_MAUDIO_SYS_PWR_REG 0x1340 +#define CAM_SYS_PWR_REG 0x1380 +#define TV_SYS_PWR_REG 0x1384 +#define MFC_SYS_PWR_REG 0x1388 +#define G3D_SYS_PWR_REG 0x138C +#define LCD0_SYS_PWR_REG 0x1390 +#define LCD1_SYS_PWR_REG 0x1394 +#define MAUDIO_SYS_PWR_REG 0x1398 +#define GPS_SYS_PWR_REG 0x139C +#define GPS_ALIVE_SYS_PWR_REG 0x13A0 +#define ARM_CORE0_CONFIGURATION 0x2000 /* Configure power mode of ARM_CORE0 */ +#define ARM_CORE0_STATUS 0x2004 /* Check power mode of ARM_CORE0 */ +#define ARM_CORE0_OPTION 0x2008 /* Sets control options for ARM_CORE0 */ +#define ARM_CORE1_CONFIGURATION 0x2080 /* Configure power mode of ARM_CORE1 */ +#define ARM_CORE1_STATUS 0x2084 /* Check power mode of ARM_CORE1 */ +#define ARM_CORE1_OPTION 0x2088 /* Sets control options for ARM_CORE0 */ +#define ARM_COMMON_OPTION 0x2408 /* Sets control options for ARM_COMMON */ +/* Configure power mode of ARM_CPU_L2_0 */ +#define ARM_CPU_L2_0_CONFIGURATION 0x2600 +#define ARM_CPU_L2_0_STATUS 0x2604 /* Check power mode of ARM_CPU_L2_0 */ +/* Configure power mode of ARM_CPU_L2_1 */ +#define ARM_CPU_L2_1_CONFIGURATION 0x2620 +#define ARM_CPU_L2_1_STATUS 0x2624 /* Check power mode of ARM_CPU_L2_1 */ +/* Sets control options for PAD_RETENTION_MAUDIO */ +#define PAD_RETENTION_MAUDIO_OPTION 0x3028 +/* Sets control options for PAD_RETENTION_GPIO */ +#define PAD_RETENTION_GPIO_OPTION 0x3108 +/* Sets control options for PAD_RETENTION_UART */ +#define PAD_RETENTION_UART_OPTION 0x3128 +/* Sets control options for PAD_RETENTION_MMCA */ +#define PAD_RETENTION_MMCA_OPTION 0x3148 +/* Sets control options for PAD_RETENTION_MMCB */ +#define PAD_RETENTION_MMCB_OPTION 0x3168 +/* Sets control options for PAD_RETENTION_EBIA */ +#define PAD_RETENTION_EBIA_OPTION 0x3188 +/* Sets control options for PAD_RETENTION_EBIB */ +#define PAD_RETENTION_EBIB_OPTION 0x31A8 +#define PS_HOLD_CONTROL 0x330C /* PS_HOLD control register */ +#define XUSBXTI_CONFIGURATION 0x3400 /* Configure the pad of XUSBXTI */ +#define XUSBXTI_STATUS 0x3404 /* Check the pad of XUSBXTI */ +/* Sets time required for XUSBXTI to be stabilized */ +#define XUSBXTI_DURATION 0x341C +#define XXTI_CONFIGURATION 0x3420 /* Configure the pad of XXTI */ +#define XXTI_STATUS 0x3424 /* Check the pad of XXTI */ +/* Sets time required for XXTI to be stabilized */ +#define XXTI_DURATION 0x343C +/* Sets time required for EXT_REGULATOR to be stabilized */ +#define EXT_REGULATOR_DURATION 0x361C +#define CAM_CONFIGURATION 0x3C00 /* Configure power mode of CAM */ +#define CAM_STATUS 0x3C04 /* Check power mode of CAM */ +#define CAM_OPTION 0x3C08 /* Sets control options for CAM */ +#define TV_CONFIGURATION 0x3C20 /* Configure power mode of TV */ +#define TV_STATUS 0x3C24 /* Check power mode of TV */ +#define TV_OPTION 0x3C28 /* Sets control options for TV */ +#define MFC_CONFIGURATION 0x3C40 /* Configure power mode of MFC */ +#define MFC_STATUS 0x3C44 /* Check power mode of MFC */ +#define MFC_OPTION 0x3C48 /* Sets control options for MFC */ +#define G3D_CONFIGURATION 0x3C60 /* Configure power mode of G3D */ +#define G3D_STATUS 0x3C64 /* Check power mode of G3D */ +#define G3D_OPTION 0x3C68 /* Sets control options for G3D */ +#define LCD0_CONFIGURATION 0x3C80 /* Configure power mode of LCD0 */ +#define LCD0_STATUS 0x3C84 /* Check power mode of LCD0 */ +#define LCD0_OPTION 0x3C88 /* Sets control options for LCD0 */ +#define LCD1_CONFIGURATION 0x3CA0 /* Configure power mode of LCD1 */ +#define LCD1_STATUS 0x3CA4 /* Check power mode of LCD1 */ +#define LCD1_OPTION 0x3CA8 /* Sets control options for LCD1 */ +#define GPS_CONFIGURATION 0x3CE0 /* Configure power mode of GPS */ +#define GPS_STATUS 0x3CE4 /* Check power mode of GPS */ +#define GPS_OPTION 0x3CE8 /* Sets control options for GPS */ +#define GPS_ALIVE_CONFIGURATION 0x3D00 /* Configure power mode of GPS */ +#define GPS_ALIVE_STATUS 0x3D04 /* Check power mode of GPS */ +#define GPS_ALIVE_OPTION 0x3D08 /* Sets control options for GPS */ + +#define EXYNOS4210_PMU_REGS_MEM_SIZE 0x3d0c + +typedef struct Exynos4210PmuReg { + const char *name; /* for debug only */ + uint32_t offset; + uint32_t reset_value; +} Exynos4210PmuReg; + +static const Exynos4210PmuReg exynos4210_pmu_regs[] = { + {"OM_STAT", OM_STAT, 0x00000000}, + {"RTC_CLKO_SEL", RTC_CLKO_SEL, 0x00000000}, + {"GNSS_RTC_OUT_CTRL", GNSS_RTC_OUT_CTRL, 0x00000001}, + {"SYSTEM_POWER_DOWN_CTRL", SYSTEM_POWER_DOWN_CTRL, 0x00010000}, + {"SYSTEM_POWER_DOWN_OPTION", SYSTEM_POWER_DOWN_OPTION, 0x03030000}, + {"SWRESET", SWRESET, 0x00000000}, + {"RST_STAT", RST_STAT, 0x00000000}, + {"WAKEUP_STAT", WAKEUP_STAT, 0x00000000}, + {"EINT_WAKEUP_MASK", EINT_WAKEUP_MASK, 0x00000000}, + {"WAKEUP_MASK", WAKEUP_MASK, 0x00000000}, + {"HDMI_PHY_CONTROL", HDMI_PHY_CONTROL, 0x00960000}, + {"USBDEVICE_PHY_CONTROL", USBDEVICE_PHY_CONTROL, 0x00000000}, + {"USBHOST_PHY_CONTROL", USBHOST_PHY_CONTROL, 0x00000000}, + {"DAC_PHY_CONTROL", DAC_PHY_CONTROL, 0x00000000}, + {"MIPI_PHY0_CONTROL", MIPI_PHY0_CONTROL, 0x00000000}, + {"MIPI_PHY1_CONTROL", MIPI_PHY1_CONTROL, 0x00000000}, + {"ADC_PHY_CONTROL", ADC_PHY_CONTROL, 0x00000001}, + {"PCIe_PHY_CONTROL", PCIe_PHY_CONTROL, 0x00000000}, + {"SATA_PHY_CONTROL", SATA_PHY_CONTROL, 0x00000000}, + {"INFORM0", INFORM0, 0x00000000}, + {"INFORM1", INFORM1, 0x00000000}, + {"INFORM2", INFORM2, 0x00000000}, + {"INFORM3", INFORM3, 0x00000000}, + {"INFORM4", INFORM4, 0x00000000}, + {"INFORM5", INFORM5, 0x00000000}, + {"INFORM6", INFORM6, 0x00000000}, + {"INFORM7", INFORM7, 0x00000000}, + {"PMU_DEBUG", PMU_DEBUG, 0x00000000}, + {"ARM_CORE0_SYS_PWR_REG", ARM_CORE0_SYS_PWR_REG, 0xFFFFFFFF}, + {"ARM_CORE1_SYS_PWR_REG", ARM_CORE1_SYS_PWR_REG, 0xFFFFFFFF}, + {"ARM_COMMON_SYS_PWR_REG", ARM_COMMON_SYS_PWR_REG, 0xFFFFFFFF}, + {"ARM_CPU_L2_0_SYS_PWR_REG", ARM_CPU_L2_0_SYS_PWR_REG, 0xFFFFFFFF}, + {"ARM_CPU_L2_1_SYS_PWR_REG", ARM_CPU_L2_1_SYS_PWR_REG, 0xFFFFFFFF}, + {"CMU_ACLKSTOP_SYS_PWR_REG", CMU_ACLKSTOP_SYS_PWR_REG, 0xFFFFFFFF}, + {"CMU_SCLKSTOP_SYS_PWR_REG", CMU_SCLKSTOP_SYS_PWR_REG, 0xFFFFFFFF}, + {"CMU_RESET_SYS_PWR_REG", CMU_RESET_SYS_PWR_REG, 0xFFFFFFFF}, + {"APLL_SYSCLK_SYS_PWR_REG", APLL_SYSCLK_SYS_PWR_REG, 0xFFFFFFFF}, + {"MPLL_SYSCLK_SYS_PWR_REG", MPLL_SYSCLK_SYS_PWR_REG, 0xFFFFFFFF}, + {"VPLL_SYSCLK_SYS_PWR_REG", VPLL_SYSCLK_SYS_PWR_REG, 0xFFFFFFFF}, + {"EPLL_SYSCLK_SYS_PWR_REG", EPLL_SYSCLK_SYS_PWR_REG, 0xFFFFFFFF}, + {"CMU_CLKSTOP_GPS_ALIVE_SYS_PWR_REG", CMU_CLKSTOP_GPS_ALIVE_SYS_PWR_REG, + 0xFFFFFFFF}, + {"CMU_RESET_GPS_ALIVE_SYS_PWR_REG", CMU_RESET_GPS_ALIVE_SYS_PWR_REG, + 0xFFFFFFFF}, + {"CMU_CLKSTOP_CAM_SYS_PWR_REG", CMU_CLKSTOP_CAM_SYS_PWR_REG, 0xFFFFFFFF}, + {"CMU_CLKSTOP_TV_SYS_PWR_REG", CMU_CLKSTOP_TV_SYS_PWR_REG, 0xFFFFFFFF}, + {"CMU_CLKSTOP_MFC_SYS_PWR_REG", CMU_CLKSTOP_MFC_SYS_PWR_REG, 0xFFFFFFFF}, + {"CMU_CLKSTOP_G3D_SYS_PWR_REG", CMU_CLKSTOP_G3D_SYS_PWR_REG, 0xFFFFFFFF}, + {"CMU_CLKSTOP_LCD0_SYS_PWR_REG", CMU_CLKSTOP_LCD0_SYS_PWR_REG, 0xFFFFFFFF}, + {"CMU_CLKSTOP_LCD1_SYS_PWR_REG", CMU_CLKSTOP_LCD1_SYS_PWR_REG, 0xFFFFFFFF}, + {"CMU_CLKSTOP_MAUDIO_SYS_PWR_REG", CMU_CLKSTOP_MAUDIO_SYS_PWR_REG, + 0xFFFFFFFF}, + {"CMU_CLKSTOP_GPS_SYS_PWR_REG", CMU_CLKSTOP_GPS_SYS_PWR_REG, 0xFFFFFFFF}, + {"CMU_RESET_CAM_SYS_PWR_REG", CMU_RESET_CAM_SYS_PWR_REG, 0xFFFFFFFF}, + {"CMU_RESET_TV_SYS_PWR_REG", CMU_RESET_TV_SYS_PWR_REG, 0xFFFFFFFF}, + {"CMU_RESET_MFC_SYS_PWR_REG", CMU_RESET_MFC_SYS_PWR_REG, 0xFFFFFFFF}, + {"CMU_RESET_G3D_SYS_PWR_REG", CMU_RESET_G3D_SYS_PWR_REG, 0xFFFFFFFF}, + {"CMU_RESET_LCD0_SYS_PWR_REG", CMU_RESET_LCD0_SYS_PWR_REG, 0xFFFFFFFF}, + {"CMU_RESET_LCD1_SYS_PWR_REG", CMU_RESET_LCD1_SYS_PWR_REG, 0xFFFFFFFF}, + {"CMU_RESET_MAUDIO_SYS_PWR_REG", CMU_RESET_MAUDIO_SYS_PWR_REG, 0xFFFFFFFF}, + {"CMU_RESET_GPS_SYS_PWR_REG", CMU_RESET_GPS_SYS_PWR_REG, 0xFFFFFFFF}, + {"TOP_BUS_SYS_PWR_REG", TOP_BUS_SYS_PWR_REG, 0xFFFFFFFF}, + {"TOP_RETENTION_SYS_PWR_REG", TOP_RETENTION_SYS_PWR_REG, 0xFFFFFFFF}, + {"TOP_PWR_SYS_PWR_REG", TOP_PWR_SYS_PWR_REG, 0xFFFFFFFF}, + {"LOGIC_RESET_SYS_PWR_REG", LOGIC_RESET_SYS_PWR_REG, 0xFFFFFFFF}, + {"OneNANDXL_MEM_SYS_PWR_REG", OneNANDXL_MEM_SYS_PWR_REG, 0xFFFFFFFF}, + {"MODEMIF_MEM_SYS_PWR_REG", MODEMIF_MEM_SYS_PWR_REG, 0xFFFFFFFF}, + {"USBDEVICE_MEM_SYS_PWR_REG", USBDEVICE_MEM_SYS_PWR_REG, 0xFFFFFFFF}, + {"SDMMC_MEM_SYS_PWR_REG", SDMMC_MEM_SYS_PWR_REG, 0xFFFFFFFF}, + {"CSSYS_MEM_SYS_PWR_REG", CSSYS_MEM_SYS_PWR_REG, 0xFFFFFFFF}, + {"SECSS_MEM_SYS_PWR_REG", SECSS_MEM_SYS_PWR_REG, 0xFFFFFFFF}, + {"PCIe_MEM_SYS_PWR_REG", PCIe_MEM_SYS_PWR_REG, 0xFFFFFFFF}, + {"SATA_MEM_SYS_PWR_REG", SATA_MEM_SYS_PWR_REG, 0xFFFFFFFF}, + {"PAD_RETENTION_DRAM_SYS_PWR_REG", PAD_RETENTION_DRAM_SYS_PWR_REG, + 0xFFFFFFFF}, + {"PAD_RETENTION_MAUDIO_SYS_PWR_REG", PAD_RETENTION_MAUDIO_SYS_PWR_REG, + 0xFFFFFFFF}, + {"PAD_RETENTION_GPIO_SYS_PWR_REG", PAD_RETENTION_GPIO_SYS_PWR_REG, + 0xFFFFFFFF}, + {"PAD_RETENTION_UART_SYS_PWR_REG", PAD_RETENTION_UART_SYS_PWR_REG, + 0xFFFFFFFF}, + {"PAD_RETENTION_MMCA_SYS_PWR_REG", PAD_RETENTION_MMCA_SYS_PWR_REG, + 0xFFFFFFFF}, + {"PAD_RETENTION_MMCB_SYS_PWR_REG", PAD_RETENTION_MMCB_SYS_PWR_REG, + 0xFFFFFFFF}, + {"PAD_RETENTION_EBIA_SYS_PWR_REG", PAD_RETENTION_EBIA_SYS_PWR_REG, + 0xFFFFFFFF}, + {"PAD_RETENTION_EBIB_SYS_PWR_REG", PAD_RETENTION_EBIB_SYS_PWR_REG, + 0xFFFFFFFF}, + {"PAD_ISOLATION_SYS_PWR_REG", PAD_ISOLATION_SYS_PWR_REG, 0xFFFFFFFF}, + {"PAD_ALV_SEL_SYS_PWR_REG", PAD_ALV_SEL_SYS_PWR_REG, 0xFFFFFFFF}, + {"XUSBXTI_SYS_PWR_REG", XUSBXTI_SYS_PWR_REG, 0xFFFFFFFF}, + {"XXTI_SYS_PWR_REG", XXTI_SYS_PWR_REG, 0xFFFFFFFF}, + {"EXT_REGULATOR_SYS_PWR_REG", EXT_REGULATOR_SYS_PWR_REG, 0xFFFFFFFF}, + {"GPIO_MODE_SYS_PWR_REG", GPIO_MODE_SYS_PWR_REG, 0xFFFFFFFF}, + {"GPIO_MODE_MAUDIO_SYS_PWR_REG", GPIO_MODE_MAUDIO_SYS_PWR_REG, 0xFFFFFFFF}, + {"CAM_SYS_PWR_REG", CAM_SYS_PWR_REG, 0xFFFFFFFF}, + {"TV_SYS_PWR_REG", TV_SYS_PWR_REG, 0xFFFFFFFF}, + {"MFC_SYS_PWR_REG", MFC_SYS_PWR_REG, 0xFFFFFFFF}, + {"G3D_SYS_PWR_REG", G3D_SYS_PWR_REG, 0xFFFFFFFF}, + {"LCD0_SYS_PWR_REG", LCD0_SYS_PWR_REG, 0xFFFFFFFF}, + {"LCD1_SYS_PWR_REG", LCD1_SYS_PWR_REG, 0xFFFFFFFF}, + {"MAUDIO_SYS_PWR_REG", MAUDIO_SYS_PWR_REG, 0xFFFFFFFF}, + {"GPS_SYS_PWR_REG", GPS_SYS_PWR_REG, 0xFFFFFFFF}, + {"GPS_ALIVE_SYS_PWR_REG", GPS_ALIVE_SYS_PWR_REG, 0xFFFFFFFF}, + {"ARM_CORE0_CONFIGURATION", ARM_CORE0_CONFIGURATION, 0x00000003}, + {"ARM_CORE0_STATUS", ARM_CORE0_STATUS, 0x00030003}, + {"ARM_CORE0_OPTION", ARM_CORE0_OPTION, 0x01010001}, + {"ARM_CORE1_CONFIGURATION", ARM_CORE1_CONFIGURATION, 0x00000003}, + {"ARM_CORE1_STATUS", ARM_CORE1_STATUS, 0x00030003}, + {"ARM_CORE1_OPTION", ARM_CORE1_OPTION, 0x01010001}, + {"ARM_COMMON_OPTION", ARM_COMMON_OPTION, 0x00000001}, + {"ARM_CPU_L2_0_CONFIGURATION", ARM_CPU_L2_0_CONFIGURATION, 0x00000003}, + {"ARM_CPU_L2_0_STATUS", ARM_CPU_L2_0_STATUS, 0x00000003}, + {"ARM_CPU_L2_1_CONFIGURATION", ARM_CPU_L2_1_CONFIGURATION, 0x00000003}, + {"ARM_CPU_L2_1_STATUS", ARM_CPU_L2_1_STATUS, 0x00000003}, + {"PAD_RETENTION_MAUDIO_OPTION", PAD_RETENTION_MAUDIO_OPTION, 0x00000000}, + {"PAD_RETENTION_GPIO_OPTION", PAD_RETENTION_GPIO_OPTION, 0x00000000}, + {"PAD_RETENTION_UART_OPTION", PAD_RETENTION_UART_OPTION, 0x00000000}, + {"PAD_RETENTION_MMCA_OPTION", PAD_RETENTION_MMCA_OPTION, 0x00000000}, + {"PAD_RETENTION_MMCB_OPTION", PAD_RETENTION_MMCB_OPTION, 0x00000000}, + {"PAD_RETENTION_EBIA_OPTION", PAD_RETENTION_EBIA_OPTION, 0x00000000}, + {"PAD_RETENTION_EBIB_OPTION", PAD_RETENTION_EBIB_OPTION, 0x00000000}, + {"PS_HOLD_CONTROL", PS_HOLD_CONTROL, 0x00005200}, + {"XUSBXTI_CONFIGURATION", XUSBXTI_CONFIGURATION, 0x00000001}, + {"XUSBXTI_STATUS", XUSBXTI_STATUS, 0x00000001}, + {"XUSBXTI_DURATION", XUSBXTI_DURATION, 0xFFF00000}, + {"XXTI_CONFIGURATION", XXTI_CONFIGURATION, 0x00000001}, + {"XXTI_STATUS", XXTI_STATUS, 0x00000001}, + {"XXTI_DURATION", XXTI_DURATION, 0xFFF00000}, + {"EXT_REGULATOR_DURATION", EXT_REGULATOR_DURATION, 0xFFF03FFF}, + {"CAM_CONFIGURATION", CAM_CONFIGURATION, 0x00000007}, + {"CAM_STATUS", CAM_STATUS, 0x00060007}, + {"CAM_OPTION", CAM_OPTION, 0x00000001}, + {"TV_CONFIGURATION", TV_CONFIGURATION, 0x00000007}, + {"TV_STATUS", TV_STATUS, 0x00060007}, + {"TV_OPTION", TV_OPTION, 0x00000001}, + {"MFC_CONFIGURATION", MFC_CONFIGURATION, 0x00000007}, + {"MFC_STATUS", MFC_STATUS, 0x00060007}, + {"MFC_OPTION", MFC_OPTION, 0x00000001}, + {"G3D_CONFIGURATION", G3D_CONFIGURATION, 0x00000007}, + {"G3D_STATUS", G3D_STATUS, 0x00060007}, + {"G3D_OPTION", G3D_OPTION, 0x00000001}, + {"LCD0_CONFIGURATION", LCD0_CONFIGURATION, 0x00000007}, + {"LCD0_STATUS", LCD0_STATUS, 0x00060007}, + {"LCD0_OPTION", LCD0_OPTION, 0x00000001}, + {"LCD1_CONFIGURATION", LCD1_CONFIGURATION, 0x00000007}, + {"LCD1_STATUS", LCD1_STATUS, 0x00060007}, + {"LCD1_OPTION", LCD1_OPTION, 0x00000001}, + {"GPS_CONFIGURATION", GPS_CONFIGURATION, 0x00000007}, + {"GPS_STATUS", GPS_STATUS, 0x00060007}, + {"GPS_OPTION", GPS_OPTION, 0x00000001}, + {"GPS_ALIVE_CONFIGURATION", GPS_ALIVE_CONFIGURATION, 0x00000007}, + {"GPS_ALIVE_STATUS", GPS_ALIVE_STATUS, 0x00060007}, + {"GPS_ALIVE_OPTION", GPS_ALIVE_OPTION, 0x00000001}, +}; + +#define PMU_NUM_OF_REGISTERS \ + (sizeof(exynos4210_pmu_regs) / sizeof(Exynos4210PmuReg)) + +typedef struct Exynos4210PmuState { + SysBusDevice busdev; + MemoryRegion iomem; + uint32_t reg[PMU_NUM_OF_REGISTERS]; +} Exynos4210PmuState; + +static uint64_t exynos4210_pmu_read(void *opaque, hwaddr offset, + unsigned size) +{ + Exynos4210PmuState *s = (Exynos4210PmuState *)opaque; + unsigned i; + const Exynos4210PmuReg *reg_p = exynos4210_pmu_regs; + + for (i = 0; i < PMU_NUM_OF_REGISTERS; i++) { + if (reg_p->offset == offset) { + PRINT_DEBUG_EXTEND("%s [0x%04x] -> 0x%04x\n", reg_p->name, + (uint32_t)offset, s->reg[i]); + return s->reg[i]; + } + reg_p++; + } + PRINT_DEBUG("QEMU PMU ERROR: bad read offset 0x%04x\n", (uint32_t)offset); + return 0; +} + +static void exynos4210_pmu_write(void *opaque, hwaddr offset, + uint64_t val, unsigned size) +{ + Exynos4210PmuState *s = (Exynos4210PmuState *)opaque; + unsigned i; + const Exynos4210PmuReg *reg_p = exynos4210_pmu_regs; + + for (i = 0; i < PMU_NUM_OF_REGISTERS; i++) { + if (reg_p->offset == offset) { + PRINT_DEBUG_EXTEND("%s <0x%04x> <- 0x%04x\n", reg_p->name, + (uint32_t)offset, (uint32_t)val); + s->reg[i] = val; + return; + } + reg_p++; + } + PRINT_DEBUG("QEMU PMU ERROR: bad write offset 0x%04x\n", (uint32_t)offset); +} + +static const MemoryRegionOps exynos4210_pmu_ops = { + .read = exynos4210_pmu_read, + .write = exynos4210_pmu_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + .unaligned = false + } +}; + +static void exynos4210_pmu_reset(DeviceState *dev) +{ + Exynos4210PmuState *s = + container_of(dev, Exynos4210PmuState, busdev.qdev); + unsigned i; + + /* Set default values for registers */ + for (i = 0; i < PMU_NUM_OF_REGISTERS; i++) { + s->reg[i] = exynos4210_pmu_regs[i].reset_value; + } +} + +static int exynos4210_pmu_init(SysBusDevice *dev) +{ + Exynos4210PmuState *s = FROM_SYSBUS(Exynos4210PmuState, dev); + + /* memory mapping */ + memory_region_init_io(&s->iomem, &exynos4210_pmu_ops, s, "exynos4210.pmu", + EXYNOS4210_PMU_REGS_MEM_SIZE); + sysbus_init_mmio(dev, &s->iomem); + return 0; +} + +static const VMStateDescription exynos4210_pmu_vmstate = { + .name = "exynos4210.pmu", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(reg, Exynos4210PmuState, PMU_NUM_OF_REGISTERS), + VMSTATE_END_OF_LIST() + } +}; + +static void exynos4210_pmu_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = exynos4210_pmu_init; + dc->reset = exynos4210_pmu_reset; + dc->vmsd = &exynos4210_pmu_vmstate; +} + +static const TypeInfo exynos4210_pmu_info = { + .name = "exynos4210.pmu", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(Exynos4210PmuState), + .class_init = exynos4210_pmu_class_init, +}; + +static void exynos4210_pmu_register(void) +{ + type_register_static(&exynos4210_pmu_info); +} + +type_init(exynos4210_pmu_register) diff --git a/hw/misc/imx_ccm.c b/hw/misc/imx_ccm.c new file mode 100644 index 0000000000..c153a24310 --- /dev/null +++ b/hw/misc/imx_ccm.c @@ -0,0 +1,321 @@ +/* + * IMX31 Clock Control Module + * + * Copyright (C) 2012 NICTA + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + * To get the timer frequencies right, we need to emulate at least part of + * the CCM. + */ + +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "sysemu/sysemu.h" +#include "hw/arm/imx.h" + +#define CKIH_FREQ 26000000 /* 26MHz crystal input */ +#define CKIL_FREQ 32768 /* nominal 32khz clock */ + + +//#define DEBUG_CCM 1 +#ifdef DEBUG_CCM +#define DPRINTF(fmt, args...) \ +do { printf("imx_ccm: " fmt , ##args); } while (0) +#else +#define DPRINTF(fmt, args...) do {} while (0) +#endif + +static int imx_ccm_post_load(void *opaque, int version_id); + +typedef struct { + SysBusDevice busdev; + MemoryRegion iomem; + + uint32_t ccmr; + uint32_t pdr0; + uint32_t pdr1; + uint32_t mpctl; + uint32_t spctl; + uint32_t cgr[3]; + uint32_t pmcr0; + uint32_t pmcr1; + + /* Frequencies precalculated on register changes */ + uint32_t pll_refclk_freq; + uint32_t mcu_clk_freq; + uint32_t hsp_clk_freq; + uint32_t ipg_clk_freq; +} IMXCCMState; + +static const VMStateDescription vmstate_imx_ccm = { + .name = "imx-ccm", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(ccmr, IMXCCMState), + VMSTATE_UINT32(pdr0, IMXCCMState), + VMSTATE_UINT32(pdr1, IMXCCMState), + VMSTATE_UINT32(mpctl, IMXCCMState), + VMSTATE_UINT32(spctl, IMXCCMState), + VMSTATE_UINT32_ARRAY(cgr, IMXCCMState, 3), + VMSTATE_UINT32(pmcr0, IMXCCMState), + VMSTATE_UINT32(pmcr1, IMXCCMState), + VMSTATE_UINT32(pll_refclk_freq, IMXCCMState), + }, + .post_load = imx_ccm_post_load, +}; + +/* CCMR */ +#define CCMR_FPME (1<<0) +#define CCMR_MPE (1<<3) +#define CCMR_MDS (1<<7) +#define CCMR_FPMF (1<<26) +#define CCMR_PRCS (3<<1) + +/* PDR0 */ +#define PDR0_MCU_PODF_SHIFT (0) +#define PDR0_MCU_PODF_MASK (0x7) +#define PDR0_MAX_PODF_SHIFT (3) +#define PDR0_MAX_PODF_MASK (0x7) +#define PDR0_IPG_PODF_SHIFT (6) +#define PDR0_IPG_PODF_MASK (0x3) +#define PDR0_NFC_PODF_SHIFT (8) +#define PDR0_NFC_PODF_MASK (0x7) +#define PDR0_HSP_PODF_SHIFT (11) +#define PDR0_HSP_PODF_MASK (0x7) +#define PDR0_PER_PODF_SHIFT (16) +#define PDR0_PER_PODF_MASK (0x1f) +#define PDR0_CSI_PODF_SHIFT (23) +#define PDR0_CSI_PODF_MASK (0x1ff) + +#define EXTRACT(value, name) (((value) >> PDR0_##name##_PODF_SHIFT) \ + & PDR0_##name##_PODF_MASK) +#define INSERT(value, name) (((value) & PDR0_##name##_PODF_MASK) << \ + PDR0_##name##_PODF_SHIFT) +/* PLL control registers */ +#define PD(v) (((v) >> 26) & 0xf) +#define MFD(v) (((v) >> 16) & 0x3ff) +#define MFI(v) (((v) >> 10) & 0xf); +#define MFN(v) ((v) & 0x3ff) + +#define PLL_PD(x) (((x) & 0xf) << 26) +#define PLL_MFD(x) (((x) & 0x3ff) << 16) +#define PLL_MFI(x) (((x) & 0xf) << 10) +#define PLL_MFN(x) (((x) & 0x3ff) << 0) + +uint32_t imx_clock_frequency(DeviceState *dev, IMXClk clock) +{ + IMXCCMState *s = container_of(dev, IMXCCMState, busdev.qdev); + + switch (clock) { + case NOCLK: + return 0; + case MCU: + return s->mcu_clk_freq; + case HSP: + return s->hsp_clk_freq; + case IPG: + return s->ipg_clk_freq; + case CLK_32k: + return CKIL_FREQ; + } + return 0; +} + +/* + * Calculate PLL output frequency + */ +static uint32_t calc_pll(uint32_t pllreg, uint32_t base_freq) +{ + int32_t mfn = MFN(pllreg); /* Numerator */ + uint32_t mfi = MFI(pllreg); /* Integer part */ + uint32_t mfd = 1 + MFD(pllreg); /* Denominator */ + uint32_t pd = 1 + PD(pllreg); /* Pre-divider */ + + if (mfi < 5) { + mfi = 5; + } + /* mfn is 10-bit signed twos-complement */ + mfn <<= 32 - 10; + mfn >>= 32 - 10; + + return ((2 * (base_freq >> 10) * (mfi * mfd + mfn)) / + (mfd * pd)) << 10; +} + +static void update_clocks(IMXCCMState *s) +{ + /* + * If we ever emulate more clocks, this should switch to a data-driven + * approach + */ + + if ((s->ccmr & CCMR_PRCS) == 1) { + s->pll_refclk_freq = CKIL_FREQ * 1024; + } else { + s->pll_refclk_freq = CKIH_FREQ; + } + + /* ipg_clk_arm aka MCU clock */ + if ((s->ccmr & CCMR_MDS) || !(s->ccmr & CCMR_MPE)) { + s->mcu_clk_freq = s->pll_refclk_freq; + } else { + s->mcu_clk_freq = calc_pll(s->mpctl, s->pll_refclk_freq); + } + + /* High-speed clock */ + s->hsp_clk_freq = s->mcu_clk_freq / (1 + EXTRACT(s->pdr0, HSP)); + s->ipg_clk_freq = s->hsp_clk_freq / (1 + EXTRACT(s->pdr0, IPG)); + + DPRINTF("Clocks: mcu %uMHz, HSP %uMHz, IPG %uHz\n", + s->mcu_clk_freq / 1000000, + s->hsp_clk_freq / 1000000, + s->ipg_clk_freq); +} + +static void imx_ccm_reset(DeviceState *dev) +{ + IMXCCMState *s = container_of(dev, IMXCCMState, busdev.qdev); + + s->ccmr = 0x074b0b7b; + s->pdr0 = 0xff870b48; + s->pdr1 = 0x49fcfe7f; + s->mpctl = PLL_PD(1) | PLL_MFD(0) | PLL_MFI(6) | PLL_MFN(0); + s->cgr[0] = s->cgr[1] = s->cgr[2] = 0xffffffff; + s->spctl = PLL_PD(1) | PLL_MFD(4) | PLL_MFI(0xc) | PLL_MFN(1); + s->pmcr0 = 0x80209828; + + update_clocks(s); +} + +static uint64_t imx_ccm_read(void *opaque, hwaddr offset, + unsigned size) +{ + IMXCCMState *s = (IMXCCMState *)opaque; + + DPRINTF("read(offset=%x)", offset >> 2); + switch (offset >> 2) { + case 0: /* CCMR */ + DPRINTF(" ccmr = 0x%x\n", s->ccmr); + return s->ccmr; + case 1: + DPRINTF(" pdr0 = 0x%x\n", s->pdr0); + return s->pdr0; + case 2: + DPRINTF(" pdr1 = 0x%x\n", s->pdr1); + return s->pdr1; + case 4: + DPRINTF(" mpctl = 0x%x\n", s->mpctl); + return s->mpctl; + case 6: + DPRINTF(" spctl = 0x%x\n", s->spctl); + return s->spctl; + case 8: + DPRINTF(" cgr0 = 0x%x\n", s->cgr[0]); + return s->cgr[0]; + case 9: + DPRINTF(" cgr1 = 0x%x\n", s->cgr[1]); + return s->cgr[1]; + case 10: + DPRINTF(" cgr2 = 0x%x\n", s->cgr[2]); + return s->cgr[2]; + case 18: /* LTR1 */ + return 0x00004040; + case 23: + DPRINTF(" pcmr0 = 0x%x\n", s->pmcr0); + return s->pmcr0; + } + DPRINTF(" return 0\n"); + return 0; +} + +static void imx_ccm_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + IMXCCMState *s = (IMXCCMState *)opaque; + + DPRINTF("write(offset=%x, value = %x)\n", + offset >> 2, (unsigned int)value); + switch (offset >> 2) { + case 0: + s->ccmr = CCMR_FPMF | (value & 0x3b6fdfff); + break; + case 1: + s->pdr0 = value & 0xff9f3fff; + break; + case 2: + s->pdr1 = value; + break; + case 4: + s->mpctl = value & 0xbfff3fff; + break; + case 6: + s->spctl = value & 0xbfff3fff; + break; + case 8: + s->cgr[0] = value; + return; + case 9: + s->cgr[1] = value; + return; + case 10: + s->cgr[2] = value; + return; + + default: + return; + } + update_clocks(s); +} + +static const struct MemoryRegionOps imx_ccm_ops = { + .read = imx_ccm_read, + .write = imx_ccm_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static int imx_ccm_init(SysBusDevice *dev) +{ + IMXCCMState *s = FROM_SYSBUS(typeof(*s), dev); + + memory_region_init_io(&s->iomem, &imx_ccm_ops, s, "imx_ccm", 0x1000); + sysbus_init_mmio(dev, &s->iomem); + + return 0; +} + +static int imx_ccm_post_load(void *opaque, int version_id) +{ + IMXCCMState *s = (IMXCCMState *)opaque; + + update_clocks(s); + return 0; +} + +static void imx_ccm_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass); + + sbc->init = imx_ccm_init; + dc->reset = imx_ccm_reset; + dc->vmsd = &vmstate_imx_ccm; + dc->desc = "i.MX Clock Control Module"; +} + +static const TypeInfo imx_ccm_info = { + .name = "imx_ccm", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IMXCCMState), + .class_init = imx_ccm_class_init, +}; + +static void imx_ccm_register_types(void) +{ + type_register_static(&imx_ccm_info); +} + +type_init(imx_ccm_register_types) diff --git a/hw/misc/lm32_sys.c b/hw/misc/lm32_sys.c new file mode 100644 index 0000000000..33a3b80ce7 --- /dev/null +++ b/hw/misc/lm32_sys.c @@ -0,0 +1,172 @@ +/* + * QEMU model of the LatticeMico32 system control block. + * + * Copyright (c) 2010 Michael Walle + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +/* + * This model is mainly intended for testing purposes and doesn't fit to any + * real hardware. On the one hand it provides a control register (R_CTRL) on + * the other hand it supports the lm32 tests. + * + * A write to the control register causes a system shutdown. + * Tests first write the pointer to a test name to the test name register + * (R_TESTNAME) and then write a zero to the pass/fail register (R_PASSFAIL) if + * the test is passed or any non-zero value to it if the test is failed. + */ + +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "trace.h" +#include "qemu/log.h" +#include "qemu/error-report.h" +#include "sysemu/sysemu.h" +#include "qemu/log.h" + +enum { + R_CTRL = 0, + R_PASSFAIL, + R_TESTNAME, + R_MAX +}; + +#define MAX_TESTNAME_LEN 16 + +struct LM32SysState { + SysBusDevice busdev; + MemoryRegion iomem; + uint32_t base; + uint32_t regs[R_MAX]; + uint8_t testname[MAX_TESTNAME_LEN]; +}; +typedef struct LM32SysState LM32SysState; + +static void copy_testname(LM32SysState *s) +{ + cpu_physical_memory_read(s->regs[R_TESTNAME], s->testname, + MAX_TESTNAME_LEN); + s->testname[MAX_TESTNAME_LEN - 1] = '\0'; +} + +static void sys_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + LM32SysState *s = opaque; + char *testname; + + trace_lm32_sys_memory_write(addr, value); + + addr >>= 2; + switch (addr) { + case R_CTRL: + qemu_system_shutdown_request(); + break; + case R_PASSFAIL: + s->regs[addr] = value; + testname = (char *)s->testname; + qemu_log("TC %-16s %s\n", testname, (value) ? "FAILED" : "OK"); + break; + case R_TESTNAME: + s->regs[addr] = value; + copy_testname(s); + break; + + default: + error_report("lm32_sys: write access to unknown register 0x" + TARGET_FMT_plx, addr << 2); + break; + } +} + +static bool sys_ops_accepts(void *opaque, hwaddr addr, + unsigned size, bool is_write) +{ + return is_write && size == 4; +} + +static const MemoryRegionOps sys_ops = { + .write = sys_write, + .valid.accepts = sys_ops_accepts, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void sys_reset(DeviceState *d) +{ + LM32SysState *s = container_of(d, LM32SysState, busdev.qdev); + int i; + + for (i = 0; i < R_MAX; i++) { + s->regs[i] = 0; + } + memset(s->testname, 0, MAX_TESTNAME_LEN); +} + +static int lm32_sys_init(SysBusDevice *dev) +{ + LM32SysState *s = FROM_SYSBUS(typeof(*s), dev); + + memory_region_init_io(&s->iomem, &sys_ops , s, "sys", R_MAX * 4); + sysbus_init_mmio(dev, &s->iomem); + + /* Note: This device is not created in the board initialization, + * instead it has to be added with the -device parameter. Therefore, + * the device maps itself. */ + sysbus_mmio_map(dev, 0, s->base); + + return 0; +} + +static const VMStateDescription vmstate_lm32_sys = { + .name = "lm32-sys", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, LM32SysState, R_MAX), + VMSTATE_BUFFER(testname, LM32SysState), + VMSTATE_END_OF_LIST() + } +}; + +static Property lm32_sys_properties[] = { + DEFINE_PROP_UINT32("base", LM32SysState, base, 0xffff0000), + DEFINE_PROP_END_OF_LIST(), +}; + +static void lm32_sys_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = lm32_sys_init; + dc->reset = sys_reset; + dc->vmsd = &vmstate_lm32_sys; + dc->props = lm32_sys_properties; +} + +static const TypeInfo lm32_sys_info = { + .name = "lm32-sys", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(LM32SysState), + .class_init = lm32_sys_class_init, +}; + +static void lm32_sys_register_types(void) +{ + type_register_static(&lm32_sys_info); +} + +type_init(lm32_sys_register_types) diff --git a/hw/misc/milkymist-hpdmc.c b/hw/misc/milkymist-hpdmc.c new file mode 100644 index 0000000000..d922f6ffad --- /dev/null +++ b/hw/misc/milkymist-hpdmc.c @@ -0,0 +1,170 @@ +/* + * QEMU model of the Milkymist High Performance Dynamic Memory Controller. + * + * Copyright (c) 2010 Michael Walle + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + * + * Specification available at: + * http://www.milkymist.org/socdoc/hpdmc.pdf + */ + +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "trace.h" +#include "qemu/error-report.h" + +enum { + R_SYSTEM = 0, + R_BYPASS, + R_TIMING, + R_IODELAY, + R_MAX +}; + +enum { + IODELAY_DQSDELAY_RDY = (1<<5), + IODELAY_PLL1_LOCKED = (1<<6), + IODELAY_PLL2_LOCKED = (1<<7), +}; + +struct MilkymistHpdmcState { + SysBusDevice busdev; + MemoryRegion regs_region; + + uint32_t regs[R_MAX]; +}; +typedef struct MilkymistHpdmcState MilkymistHpdmcState; + +static uint64_t hpdmc_read(void *opaque, hwaddr addr, + unsigned size) +{ + MilkymistHpdmcState *s = opaque; + uint32_t r = 0; + + addr >>= 2; + switch (addr) { + case R_SYSTEM: + case R_BYPASS: + case R_TIMING: + case R_IODELAY: + r = s->regs[addr]; + break; + + default: + error_report("milkymist_hpdmc: read access to unknown register 0x" + TARGET_FMT_plx, addr << 2); + break; + } + + trace_milkymist_hpdmc_memory_read(addr << 2, r); + + return r; +} + +static void hpdmc_write(void *opaque, hwaddr addr, uint64_t value, + unsigned size) +{ + MilkymistHpdmcState *s = opaque; + + trace_milkymist_hpdmc_memory_write(addr, value); + + addr >>= 2; + switch (addr) { + case R_SYSTEM: + case R_BYPASS: + case R_TIMING: + s->regs[addr] = value; + break; + case R_IODELAY: + /* ignore writes */ + break; + + default: + error_report("milkymist_hpdmc: write access to unknown register 0x" + TARGET_FMT_plx, addr << 2); + break; + } +} + +static const MemoryRegionOps hpdmc_mmio_ops = { + .read = hpdmc_read, + .write = hpdmc_write, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void milkymist_hpdmc_reset(DeviceState *d) +{ + MilkymistHpdmcState *s = container_of(d, MilkymistHpdmcState, busdev.qdev); + int i; + + for (i = 0; i < R_MAX; i++) { + s->regs[i] = 0; + } + + /* defaults */ + s->regs[R_IODELAY] = IODELAY_DQSDELAY_RDY | IODELAY_PLL1_LOCKED + | IODELAY_PLL2_LOCKED; +} + +static int milkymist_hpdmc_init(SysBusDevice *dev) +{ + MilkymistHpdmcState *s = FROM_SYSBUS(typeof(*s), dev); + + memory_region_init_io(&s->regs_region, &hpdmc_mmio_ops, s, + "milkymist-hpdmc", R_MAX * 4); + sysbus_init_mmio(dev, &s->regs_region); + + return 0; +} + +static const VMStateDescription vmstate_milkymist_hpdmc = { + .name = "milkymist-hpdmc", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, MilkymistHpdmcState, R_MAX), + VMSTATE_END_OF_LIST() + } +}; + +static void milkymist_hpdmc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = milkymist_hpdmc_init; + dc->reset = milkymist_hpdmc_reset; + dc->vmsd = &vmstate_milkymist_hpdmc; +} + +static const TypeInfo milkymist_hpdmc_info = { + .name = "milkymist-hpdmc", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(MilkymistHpdmcState), + .class_init = milkymist_hpdmc_class_init, +}; + +static void milkymist_hpdmc_register_types(void) +{ + type_register_static(&milkymist_hpdmc_info); +} + +type_init(milkymist_hpdmc_register_types) diff --git a/hw/misc/milkymist-pfpu.c b/hw/misc/milkymist-pfpu.c new file mode 100644 index 0000000000..ad44b4db22 --- /dev/null +++ b/hw/misc/milkymist-pfpu.c @@ -0,0 +1,544 @@ +/* + * QEMU model of the Milkymist programmable FPU. + * + * Copyright (c) 2010 Michael Walle + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + * + * Specification available at: + * http://www.milkymist.org/socdoc/pfpu.pdf + * + */ + +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "trace.h" +#include "qemu/log.h" +#include "qemu/error-report.h" +#include + +/* #define TRACE_EXEC */ + +#ifdef TRACE_EXEC +# define D_EXEC(x) x +#else +# define D_EXEC(x) +#endif + +enum { + R_CTL = 0, + R_MESHBASE, + R_HMESHLAST, + R_VMESHLAST, + R_CODEPAGE, + R_VERTICES, + R_COLLISIONS, + R_STRAYWRITES, + R_LASTDMA, + R_PC, + R_DREGBASE, + R_CODEBASE, + R_MAX +}; + +enum { + CTL_START_BUSY = (1<<0), +}; + +enum { + OP_NOP = 0, + OP_FADD, + OP_FSUB, + OP_FMUL, + OP_FABS, + OP_F2I, + OP_I2F, + OP_VECTOUT, + OP_SIN, + OP_COS, + OP_ABOVE, + OP_EQUAL, + OP_COPY, + OP_IF, + OP_TSIGN, + OP_QUAKE, +}; + +enum { + GPR_X = 0, + GPR_Y = 1, + GPR_FLAGS = 2, +}; + +enum { + LATENCY_FADD = 5, + LATENCY_FSUB = 5, + LATENCY_FMUL = 7, + LATENCY_FABS = 2, + LATENCY_F2I = 2, + LATENCY_I2F = 3, + LATENCY_VECTOUT = 0, + LATENCY_SIN = 4, + LATENCY_COS = 4, + LATENCY_ABOVE = 2, + LATENCY_EQUAL = 2, + LATENCY_COPY = 2, + LATENCY_IF = 2, + LATENCY_TSIGN = 2, + LATENCY_QUAKE = 2, + MAX_LATENCY = 7 +}; + +#define GPR_BEGIN 0x100 +#define GPR_END 0x17f +#define MICROCODE_BEGIN 0x200 +#define MICROCODE_END 0x3ff +#define MICROCODE_WORDS 2048 + +#define REINTERPRET_CAST(type, val) (*((type *)&(val))) + +#ifdef TRACE_EXEC +static const char *opcode_to_str[] = { + "NOP", "FADD", "FSUB", "FMUL", "FABS", "F2I", "I2F", "VECTOUT", + "SIN", "COS", "ABOVE", "EQUAL", "COPY", "IF", "TSIGN", "QUAKE", +}; +#endif + +struct MilkymistPFPUState { + SysBusDevice busdev; + MemoryRegion regs_region; + CharDriverState *chr; + qemu_irq irq; + + uint32_t regs[R_MAX]; + uint32_t gp_regs[128]; + uint32_t microcode[MICROCODE_WORDS]; + + int output_queue_pos; + uint32_t output_queue[MAX_LATENCY]; +}; +typedef struct MilkymistPFPUState MilkymistPFPUState; + +static inline hwaddr +get_dma_address(uint32_t base, uint32_t x, uint32_t y) +{ + return base + 8 * (128 * y + x); +} + +static inline void +output_queue_insert(MilkymistPFPUState *s, uint32_t val, int pos) +{ + s->output_queue[(s->output_queue_pos + pos) % MAX_LATENCY] = val; +} + +static inline uint32_t +output_queue_remove(MilkymistPFPUState *s) +{ + return s->output_queue[s->output_queue_pos]; +} + +static inline void +output_queue_advance(MilkymistPFPUState *s) +{ + s->output_queue[s->output_queue_pos] = 0; + s->output_queue_pos = (s->output_queue_pos + 1) % MAX_LATENCY; +} + +static int pfpu_decode_insn(MilkymistPFPUState *s) +{ + uint32_t pc = s->regs[R_PC]; + uint32_t insn = s->microcode[pc]; + uint32_t reg_a = (insn >> 18) & 0x7f; + uint32_t reg_b = (insn >> 11) & 0x7f; + uint32_t op = (insn >> 7) & 0xf; + uint32_t reg_d = insn & 0x7f; + uint32_t r = 0; + int latency = 0; + + switch (op) { + case OP_NOP: + break; + case OP_FADD: + { + float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]); + float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]); + float t = a + b; + r = REINTERPRET_CAST(uint32_t, t); + latency = LATENCY_FADD; + D_EXEC(qemu_log("ADD a=%f b=%f t=%f, r=%08x\n", a, b, t, r)); + } break; + case OP_FSUB: + { + float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]); + float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]); + float t = a - b; + r = REINTERPRET_CAST(uint32_t, t); + latency = LATENCY_FSUB; + D_EXEC(qemu_log("SUB a=%f b=%f t=%f, r=%08x\n", a, b, t, r)); + } break; + case OP_FMUL: + { + float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]); + float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]); + float t = a * b; + r = REINTERPRET_CAST(uint32_t, t); + latency = LATENCY_FMUL; + D_EXEC(qemu_log("MUL a=%f b=%f t=%f, r=%08x\n", a, b, t, r)); + } break; + case OP_FABS: + { + float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]); + float t = fabsf(a); + r = REINTERPRET_CAST(uint32_t, t); + latency = LATENCY_FABS; + D_EXEC(qemu_log("ABS a=%f t=%f, r=%08x\n", a, t, r)); + } break; + case OP_F2I: + { + float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]); + int32_t t = a; + r = REINTERPRET_CAST(uint32_t, t); + latency = LATENCY_F2I; + D_EXEC(qemu_log("F2I a=%f t=%d, r=%08x\n", a, t, r)); + } break; + case OP_I2F: + { + int32_t a = REINTERPRET_CAST(int32_t, s->gp_regs[reg_a]); + float t = a; + r = REINTERPRET_CAST(uint32_t, t); + latency = LATENCY_I2F; + D_EXEC(qemu_log("I2F a=%08x t=%f, r=%08x\n", a, t, r)); + } break; + case OP_VECTOUT: + { + uint32_t a = cpu_to_be32(s->gp_regs[reg_a]); + uint32_t b = cpu_to_be32(s->gp_regs[reg_b]); + hwaddr dma_ptr = + get_dma_address(s->regs[R_MESHBASE], + s->gp_regs[GPR_X], s->gp_regs[GPR_Y]); + cpu_physical_memory_write(dma_ptr, (uint8_t *)&a, 4); + cpu_physical_memory_write(dma_ptr + 4, (uint8_t *)&b, 4); + s->regs[R_LASTDMA] = dma_ptr + 4; + D_EXEC(qemu_log("VECTOUT a=%08x b=%08x dma=%08x\n", a, b, dma_ptr)); + trace_milkymist_pfpu_vectout(a, b, dma_ptr); + } break; + case OP_SIN: + { + int32_t a = REINTERPRET_CAST(int32_t, s->gp_regs[reg_a]); + float t = sinf(a * (1.0f / (M_PI * 4096.0f))); + r = REINTERPRET_CAST(uint32_t, t); + latency = LATENCY_SIN; + D_EXEC(qemu_log("SIN a=%d t=%f, r=%08x\n", a, t, r)); + } break; + case OP_COS: + { + int32_t a = REINTERPRET_CAST(int32_t, s->gp_regs[reg_a]); + float t = cosf(a * (1.0f / (M_PI * 4096.0f))); + r = REINTERPRET_CAST(uint32_t, t); + latency = LATENCY_COS; + D_EXEC(qemu_log("COS a=%d t=%f, r=%08x\n", a, t, r)); + } break; + case OP_ABOVE: + { + float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]); + float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]); + float t = (a > b) ? 1.0f : 0.0f; + r = REINTERPRET_CAST(uint32_t, t); + latency = LATENCY_ABOVE; + D_EXEC(qemu_log("ABOVE a=%f b=%f t=%f, r=%08x\n", a, b, t, r)); + } break; + case OP_EQUAL: + { + float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]); + float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]); + float t = (a == b) ? 1.0f : 0.0f; + r = REINTERPRET_CAST(uint32_t, t); + latency = LATENCY_EQUAL; + D_EXEC(qemu_log("EQUAL a=%f b=%f t=%f, r=%08x\n", a, b, t, r)); + } break; + case OP_COPY: + { + r = s->gp_regs[reg_a]; + latency = LATENCY_COPY; + D_EXEC(qemu_log("COPY")); + } break; + case OP_IF: + { + float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]); + float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]); + uint32_t f = s->gp_regs[GPR_FLAGS]; + float t = (f != 0) ? a : b; + r = REINTERPRET_CAST(uint32_t, t); + latency = LATENCY_IF; + D_EXEC(qemu_log("IF f=%u a=%f b=%f t=%f, r=%08x\n", f, a, b, t, r)); + } break; + case OP_TSIGN: + { + float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]); + float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]); + float t = (b < 0) ? -a : a; + r = REINTERPRET_CAST(uint32_t, t); + latency = LATENCY_TSIGN; + D_EXEC(qemu_log("TSIGN a=%f b=%f t=%f, r=%08x\n", a, b, t, r)); + } break; + case OP_QUAKE: + { + uint32_t a = s->gp_regs[reg_a]; + r = 0x5f3759df - (a >> 1); + latency = LATENCY_QUAKE; + D_EXEC(qemu_log("QUAKE a=%d r=%08x\n", a, r)); + } break; + + default: + error_report("milkymist_pfpu: unknown opcode %d", op); + break; + } + + if (!reg_d) { + D_EXEC(qemu_log("%04d %8s R%03d, R%03d \n", + s->regs[R_PC], opcode_to_str[op], reg_a, reg_b, latency, + s->regs[R_PC] + latency)); + } else { + D_EXEC(qemu_log("%04d %8s R%03d, R%03d -> R%03d\n", + s->regs[R_PC], opcode_to_str[op], reg_a, reg_b, latency, + s->regs[R_PC] + latency, reg_d)); + } + + if (op == OP_VECTOUT) { + return 0; + } + + /* store output for this cycle */ + if (reg_d) { + uint32_t val = output_queue_remove(s); + D_EXEC(qemu_log("R%03d <- 0x%08x\n", reg_d, val)); + s->gp_regs[reg_d] = val; + } + + output_queue_advance(s); + + /* store op output */ + if (op != OP_NOP) { + output_queue_insert(s, r, latency-1); + } + + /* advance PC */ + s->regs[R_PC]++; + + return 1; +}; + +static void pfpu_start(MilkymistPFPUState *s) +{ + int x, y; + int i; + + for (y = 0; y <= s->regs[R_VMESHLAST]; y++) { + for (x = 0; x <= s->regs[R_HMESHLAST]; x++) { + D_EXEC(qemu_log("\nprocessing x=%d y=%d\n", x, y)); + + /* set current position */ + s->gp_regs[GPR_X] = x; + s->gp_regs[GPR_Y] = y; + + /* run microcode on this position */ + i = 0; + while (pfpu_decode_insn(s)) { + /* decode at most MICROCODE_WORDS instructions */ + if (i++ >= MICROCODE_WORDS) { + error_report("milkymist_pfpu: too many instructions " + "executed in microcode. No VECTOUT?"); + break; + } + } + + /* reset pc for next run */ + s->regs[R_PC] = 0; + } + } + + s->regs[R_VERTICES] = x * y; + + trace_milkymist_pfpu_pulse_irq(); + qemu_irq_pulse(s->irq); +} + +static inline int get_microcode_address(MilkymistPFPUState *s, uint32_t addr) +{ + return (512 * s->regs[R_CODEPAGE]) + addr - MICROCODE_BEGIN; +} + +static uint64_t pfpu_read(void *opaque, hwaddr addr, + unsigned size) +{ + MilkymistPFPUState *s = opaque; + uint32_t r = 0; + + addr >>= 2; + switch (addr) { + case R_CTL: + case R_MESHBASE: + case R_HMESHLAST: + case R_VMESHLAST: + case R_CODEPAGE: + case R_VERTICES: + case R_COLLISIONS: + case R_STRAYWRITES: + case R_LASTDMA: + case R_PC: + case R_DREGBASE: + case R_CODEBASE: + r = s->regs[addr]; + break; + case GPR_BEGIN ... GPR_END: + r = s->gp_regs[addr - GPR_BEGIN]; + break; + case MICROCODE_BEGIN ... MICROCODE_END: + r = s->microcode[get_microcode_address(s, addr)]; + break; + + default: + error_report("milkymist_pfpu: read access to unknown register 0x" + TARGET_FMT_plx, addr << 2); + break; + } + + trace_milkymist_pfpu_memory_read(addr << 2, r); + + return r; +} + +static void pfpu_write(void *opaque, hwaddr addr, uint64_t value, + unsigned size) +{ + MilkymistPFPUState *s = opaque; + + trace_milkymist_pfpu_memory_write(addr, value); + + addr >>= 2; + switch (addr) { + case R_CTL: + if (value & CTL_START_BUSY) { + pfpu_start(s); + } + break; + case R_MESHBASE: + case R_HMESHLAST: + case R_VMESHLAST: + case R_CODEPAGE: + case R_VERTICES: + case R_COLLISIONS: + case R_STRAYWRITES: + case R_LASTDMA: + case R_PC: + case R_DREGBASE: + case R_CODEBASE: + s->regs[addr] = value; + break; + case GPR_BEGIN ... GPR_END: + s->gp_regs[addr - GPR_BEGIN] = value; + break; + case MICROCODE_BEGIN ... MICROCODE_END: + s->microcode[get_microcode_address(s, addr)] = value; + break; + + default: + error_report("milkymist_pfpu: write access to unknown register 0x" + TARGET_FMT_plx, addr << 2); + break; + } +} + +static const MemoryRegionOps pfpu_mmio_ops = { + .read = pfpu_read, + .write = pfpu_write, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void milkymist_pfpu_reset(DeviceState *d) +{ + MilkymistPFPUState *s = container_of(d, MilkymistPFPUState, busdev.qdev); + int i; + + for (i = 0; i < R_MAX; i++) { + s->regs[i] = 0; + } + for (i = 0; i < 128; i++) { + s->gp_regs[i] = 0; + } + for (i = 0; i < MICROCODE_WORDS; i++) { + s->microcode[i] = 0; + } + s->output_queue_pos = 0; + for (i = 0; i < MAX_LATENCY; i++) { + s->output_queue[i] = 0; + } +} + +static int milkymist_pfpu_init(SysBusDevice *dev) +{ + MilkymistPFPUState *s = FROM_SYSBUS(typeof(*s), dev); + + sysbus_init_irq(dev, &s->irq); + + memory_region_init_io(&s->regs_region, &pfpu_mmio_ops, s, + "milkymist-pfpu", MICROCODE_END * 4); + sysbus_init_mmio(dev, &s->regs_region); + + return 0; +} + +static const VMStateDescription vmstate_milkymist_pfpu = { + .name = "milkymist-pfpu", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, MilkymistPFPUState, R_MAX), + VMSTATE_UINT32_ARRAY(gp_regs, MilkymistPFPUState, 128), + VMSTATE_UINT32_ARRAY(microcode, MilkymistPFPUState, MICROCODE_WORDS), + VMSTATE_INT32(output_queue_pos, MilkymistPFPUState), + VMSTATE_UINT32_ARRAY(output_queue, MilkymistPFPUState, MAX_LATENCY), + VMSTATE_END_OF_LIST() + } +}; + +static void milkymist_pfpu_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = milkymist_pfpu_init; + dc->reset = milkymist_pfpu_reset; + dc->vmsd = &vmstate_milkymist_pfpu; +} + +static const TypeInfo milkymist_pfpu_info = { + .name = "milkymist-pfpu", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(MilkymistPFPUState), + .class_init = milkymist_pfpu_class_init, +}; + +static void milkymist_pfpu_register_types(void) +{ + type_register_static(&milkymist_pfpu_info); +} + +type_init(milkymist_pfpu_register_types) diff --git a/hw/misc/mst_fpga.c b/hw/misc/mst_fpga.c new file mode 100644 index 0000000000..1dd15054d0 --- /dev/null +++ b/hw/misc/mst_fpga.c @@ -0,0 +1,263 @@ +/* + * PXA270-based Intel Mainstone platforms. + * FPGA driver + * + * Copyright (c) 2007 by Armin Kuster or + * + * + * This code is licensed under the GNU GPL v2. + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ +#include "hw/hw.h" +#include "hw/sysbus.h" + +/* Mainstone FPGA for extern irqs */ +#define FPGA_GPIO_PIN 0 +#define MST_NUM_IRQS 16 +#define MST_LEDDAT1 0x10 +#define MST_LEDDAT2 0x14 +#define MST_LEDCTRL 0x40 +#define MST_GPSWR 0x60 +#define MST_MSCWR1 0x80 +#define MST_MSCWR2 0x84 +#define MST_MSCWR3 0x88 +#define MST_MSCRD 0x90 +#define MST_INTMSKENA 0xc0 +#define MST_INTSETCLR 0xd0 +#define MST_PCMCIA0 0xe0 +#define MST_PCMCIA1 0xe4 + +#define MST_PCMCIAx_READY (1 << 10) +#define MST_PCMCIAx_nCD (1 << 5) + +#define MST_PCMCIA_CD0_IRQ 9 +#define MST_PCMCIA_CD1_IRQ 13 + +typedef struct mst_irq_state{ + SysBusDevice busdev; + MemoryRegion iomem; + + qemu_irq parent; + + uint32_t prev_level; + uint32_t leddat1; + uint32_t leddat2; + uint32_t ledctrl; + uint32_t gpswr; + uint32_t mscwr1; + uint32_t mscwr2; + uint32_t mscwr3; + uint32_t mscrd; + uint32_t intmskena; + uint32_t intsetclr; + uint32_t pcmcia0; + uint32_t pcmcia1; +}mst_irq_state; + +static void +mst_fpga_set_irq(void *opaque, int irq, int level) +{ + mst_irq_state *s = (mst_irq_state *)opaque; + uint32_t oldint = s->intsetclr & s->intmskena; + + if (level) + s->prev_level |= 1u << irq; + else + s->prev_level &= ~(1u << irq); + + switch(irq) { + case MST_PCMCIA_CD0_IRQ: + if (level) + s->pcmcia0 &= ~MST_PCMCIAx_nCD; + else + s->pcmcia0 |= MST_PCMCIAx_nCD; + break; + case MST_PCMCIA_CD1_IRQ: + if (level) + s->pcmcia1 &= ~MST_PCMCIAx_nCD; + else + s->pcmcia1 |= MST_PCMCIAx_nCD; + break; + } + + if ((s->intmskena & (1u << irq)) && level) + s->intsetclr |= 1u << irq; + + if (oldint != (s->intsetclr & s->intmskena)) + qemu_set_irq(s->parent, s->intsetclr & s->intmskena); +} + + +static uint64_t +mst_fpga_readb(void *opaque, hwaddr addr, unsigned size) +{ + mst_irq_state *s = (mst_irq_state *) opaque; + + switch (addr) { + case MST_LEDDAT1: + return s->leddat1; + case MST_LEDDAT2: + return s->leddat2; + case MST_LEDCTRL: + return s->ledctrl; + case MST_GPSWR: + return s->gpswr; + case MST_MSCWR1: + return s->mscwr1; + case MST_MSCWR2: + return s->mscwr2; + case MST_MSCWR3: + return s->mscwr3; + case MST_MSCRD: + return s->mscrd; + case MST_INTMSKENA: + return s->intmskena; + case MST_INTSETCLR: + return s->intsetclr; + case MST_PCMCIA0: + return s->pcmcia0; + case MST_PCMCIA1: + return s->pcmcia1; + default: + printf("Mainstone - mst_fpga_readb: Bad register offset " + "0x" TARGET_FMT_plx "\n", addr); + } + return 0; +} + +static void +mst_fpga_writeb(void *opaque, hwaddr addr, uint64_t value, + unsigned size) +{ + mst_irq_state *s = (mst_irq_state *) opaque; + value &= 0xffffffff; + + switch (addr) { + case MST_LEDDAT1: + s->leddat1 = value; + break; + case MST_LEDDAT2: + s->leddat2 = value; + break; + case MST_LEDCTRL: + s->ledctrl = value; + break; + case MST_GPSWR: + s->gpswr = value; + break; + case MST_MSCWR1: + s->mscwr1 = value; + break; + case MST_MSCWR2: + s->mscwr2 = value; + break; + case MST_MSCWR3: + s->mscwr3 = value; + break; + case MST_MSCRD: + s->mscrd = value; + break; + case MST_INTMSKENA: /* Mask interrupt */ + s->intmskena = (value & 0xFEEFF); + qemu_set_irq(s->parent, s->intsetclr & s->intmskena); + break; + case MST_INTSETCLR: /* clear or set interrupt */ + s->intsetclr = (value & 0xFEEFF); + qemu_set_irq(s->parent, s->intsetclr & s->intmskena); + break; + /* For PCMCIAx allow the to change only power and reset */ + case MST_PCMCIA0: + s->pcmcia0 = (value & 0x1f) | (s->pcmcia0 & ~0x1f); + break; + case MST_PCMCIA1: + s->pcmcia1 = (value & 0x1f) | (s->pcmcia1 & ~0x1f); + break; + default: + printf("Mainstone - mst_fpga_writeb: Bad register offset " + "0x" TARGET_FMT_plx "\n", addr); + } +} + +static const MemoryRegionOps mst_fpga_ops = { + .read = mst_fpga_readb, + .write = mst_fpga_writeb, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static int mst_fpga_post_load(void *opaque, int version_id) +{ + mst_irq_state *s = (mst_irq_state *) opaque; + + qemu_set_irq(s->parent, s->intsetclr & s->intmskena); + return 0; +} + +static int mst_fpga_init(SysBusDevice *dev) +{ + mst_irq_state *s; + + s = FROM_SYSBUS(mst_irq_state, dev); + + s->pcmcia0 = MST_PCMCIAx_READY | MST_PCMCIAx_nCD; + s->pcmcia1 = MST_PCMCIAx_READY | MST_PCMCIAx_nCD; + + sysbus_init_irq(dev, &s->parent); + + /* alloc the external 16 irqs */ + qdev_init_gpio_in(&dev->qdev, mst_fpga_set_irq, MST_NUM_IRQS); + + memory_region_init_io(&s->iomem, &mst_fpga_ops, s, + "fpga", 0x00100000); + sysbus_init_mmio(dev, &s->iomem); + return 0; +} + +static VMStateDescription vmstate_mst_fpga_regs = { + .name = "mainstone_fpga", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .post_load = mst_fpga_post_load, + .fields = (VMStateField []) { + VMSTATE_UINT32(prev_level, mst_irq_state), + VMSTATE_UINT32(leddat1, mst_irq_state), + VMSTATE_UINT32(leddat2, mst_irq_state), + VMSTATE_UINT32(ledctrl, mst_irq_state), + VMSTATE_UINT32(gpswr, mst_irq_state), + VMSTATE_UINT32(mscwr1, mst_irq_state), + VMSTATE_UINT32(mscwr2, mst_irq_state), + VMSTATE_UINT32(mscwr3, mst_irq_state), + VMSTATE_UINT32(mscrd, mst_irq_state), + VMSTATE_UINT32(intmskena, mst_irq_state), + VMSTATE_UINT32(intsetclr, mst_irq_state), + VMSTATE_UINT32(pcmcia0, mst_irq_state), + VMSTATE_UINT32(pcmcia1, mst_irq_state), + VMSTATE_END_OF_LIST(), + }, +}; + +static void mst_fpga_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = mst_fpga_init; + dc->desc = "Mainstone II FPGA"; + dc->vmsd = &vmstate_mst_fpga_regs; +} + +static const TypeInfo mst_fpga_info = { + .name = "mainstone-fpga", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(mst_irq_state), + .class_init = mst_fpga_class_init, +}; + +static void mst_fpga_register_types(void) +{ + type_register_static(&mst_fpga_info); +} + +type_init(mst_fpga_register_types) diff --git a/hw/misc/omap_clk.c b/hw/misc/omap_clk.c new file mode 100644 index 0000000000..80a3c50e1e --- /dev/null +++ b/hw/misc/omap_clk.c @@ -0,0 +1,1264 @@ +/* + * OMAP clocks. + * + * Copyright (C) 2006-2008 Andrzej Zaborowski + * + * Clocks data comes in part from arch/arm/mach-omap1/clock.h in Linux. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ +#include "hw/hw.h" +#include "hw/arm/omap.h" + +struct clk { + const char *name; + const char *alias; + struct clk *parent; + struct clk *child1; + struct clk *sibling; +#define ALWAYS_ENABLED (1 << 0) +#define CLOCK_IN_OMAP310 (1 << 10) +#define CLOCK_IN_OMAP730 (1 << 11) +#define CLOCK_IN_OMAP1510 (1 << 12) +#define CLOCK_IN_OMAP16XX (1 << 13) +#define CLOCK_IN_OMAP242X (1 << 14) +#define CLOCK_IN_OMAP243X (1 << 15) +#define CLOCK_IN_OMAP343X (1 << 16) + uint32_t flags; + int id; + + int running; /* Is currently ticking */ + int enabled; /* Is enabled, regardless of its input clk */ + unsigned long rate; /* Current rate (if .running) */ + unsigned int divisor; /* Rate relative to input (if .enabled) */ + unsigned int multiplier; /* Rate relative to input (if .enabled) */ + qemu_irq users[16]; /* Who to notify on change */ + int usecount; /* Automatically idle when unused */ +}; + +static struct clk xtal_osc12m = { + .name = "xtal_osc_12m", + .rate = 12000000, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, +}; + +static struct clk xtal_osc32k = { + .name = "xtal_osc_32k", + .rate = 32768, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | + CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, +}; + +static struct clk ck_ref = { + .name = "ck_ref", + .alias = "clkin", + .parent = &xtal_osc12m, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | + ALWAYS_ENABLED, +}; + +/* If a dpll is disabled it becomes a bypass, child clocks don't stop */ +static struct clk dpll1 = { + .name = "dpll1", + .parent = &ck_ref, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | + ALWAYS_ENABLED, +}; + +static struct clk dpll2 = { + .name = "dpll2", + .parent = &ck_ref, + .flags = CLOCK_IN_OMAP310 | ALWAYS_ENABLED, +}; + +static struct clk dpll3 = { + .name = "dpll3", + .parent = &ck_ref, + .flags = CLOCK_IN_OMAP310 | ALWAYS_ENABLED, +}; + +static struct clk dpll4 = { + .name = "dpll4", + .parent = &ck_ref, + .multiplier = 4, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, +}; + +static struct clk apll = { + .name = "apll", + .parent = &ck_ref, + .multiplier = 48, + .divisor = 12, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, +}; + +static struct clk ck_48m = { + .name = "ck_48m", + .parent = &dpll4, /* either dpll4 or apll */ + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, +}; + +static struct clk ck_dpll1out = { + .name = "ck_dpll1out", + .parent = &dpll1, + .flags = CLOCK_IN_OMAP16XX, +}; + +static struct clk sossi_ck = { + .name = "ck_sossi", + .parent = &ck_dpll1out, + .flags = CLOCK_IN_OMAP16XX, +}; + +static struct clk clkm1 = { + .name = "clkm1", + .alias = "ck_gen1", + .parent = &dpll1, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | + ALWAYS_ENABLED, +}; + +static struct clk clkm2 = { + .name = "clkm2", + .alias = "ck_gen2", + .parent = &dpll1, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | + ALWAYS_ENABLED, +}; + +static struct clk clkm3 = { + .name = "clkm3", + .alias = "ck_gen3", + .parent = &dpll1, /* either dpll1 or ck_ref */ + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | + ALWAYS_ENABLED, +}; + +static struct clk arm_ck = { + .name = "arm_ck", + .alias = "mpu_ck", + .parent = &clkm1, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | + ALWAYS_ENABLED, +}; + +static struct clk armper_ck = { + .name = "armper_ck", + .alias = "mpuper_ck", + .parent = &clkm1, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, +}; + +static struct clk arm_gpio_ck = { + .name = "arm_gpio_ck", + .alias = "mpu_gpio_ck", + .parent = &clkm1, + .divisor = 1, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, +}; + +static struct clk armxor_ck = { + .name = "armxor_ck", + .alias = "mpuxor_ck", + .parent = &ck_ref, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, +}; + +static struct clk armtim_ck = { + .name = "armtim_ck", + .alias = "mputim_ck", + .parent = &ck_ref, /* either CLKIN or DPLL1 */ + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, +}; + +static struct clk armwdt_ck = { + .name = "armwdt_ck", + .alias = "mpuwd_ck", + .parent = &clkm1, + .divisor = 14, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | + ALWAYS_ENABLED, +}; + +static struct clk arminth_ck16xx = { + .name = "arminth_ck", + .parent = &arm_ck, + .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, + /* Note: On 16xx the frequency can be divided by 2 by programming + * ARM_CKCTL:ARM_INTHCK_SEL(14) to 1 + * + * 1510 version is in TC clocks. + */ +}; + +static struct clk dsp_ck = { + .name = "dsp_ck", + .parent = &clkm2, + .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, +}; + +static struct clk dspmmu_ck = { + .name = "dspmmu_ck", + .parent = &clkm2, + .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | + ALWAYS_ENABLED, +}; + +static struct clk dspper_ck = { + .name = "dspper_ck", + .parent = &clkm2, + .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, +}; + +static struct clk dspxor_ck = { + .name = "dspxor_ck", + .parent = &ck_ref, + .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, +}; + +static struct clk dsptim_ck = { + .name = "dsptim_ck", + .parent = &ck_ref, + .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, +}; + +static struct clk tc_ck = { + .name = "tc_ck", + .parent = &clkm3, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | + CLOCK_IN_OMAP730 | CLOCK_IN_OMAP310 | + ALWAYS_ENABLED, +}; + +static struct clk arminth_ck15xx = { + .name = "arminth_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED, + /* Note: On 1510 the frequency follows TC_CK + * + * 16xx version is in MPU clocks. + */ +}; + +static struct clk tipb_ck = { + /* No-idle controlled by "tc_ck" */ + .name = "tipb_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED, +}; + +static struct clk l3_ocpi_ck = { + /* No-idle controlled by "tc_ck" */ + .name = "l3_ocpi_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP16XX, +}; + +static struct clk tc1_ck = { + .name = "tc1_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP16XX, +}; + +static struct clk tc2_ck = { + .name = "tc2_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP16XX, +}; + +static struct clk dma_ck = { + /* No-idle controlled by "tc_ck" */ + .name = "dma_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | + ALWAYS_ENABLED, +}; + +static struct clk dma_lcdfree_ck = { + .name = "dma_lcdfree_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, +}; + +static struct clk api_ck = { + .name = "api_ck", + .alias = "mpui_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, +}; + +static struct clk lb_ck = { + .name = "lb_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, +}; + +static struct clk lbfree_ck = { + .name = "lbfree_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, +}; + +static struct clk hsab_ck = { + .name = "hsab_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, +}; + +static struct clk rhea1_ck = { + .name = "rhea1_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, +}; + +static struct clk rhea2_ck = { + .name = "rhea2_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, +}; + +static struct clk lcd_ck_16xx = { + .name = "lcd_ck", + .parent = &clkm3, + .flags = CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP730, +}; + +static struct clk lcd_ck_1510 = { + .name = "lcd_ck", + .parent = &clkm3, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, +}; + +static struct clk uart1_1510 = { + .name = "uart1_ck", + /* Direct from ULPD, no real parent */ + .parent = &armper_ck, /* either armper_ck or dpll4 */ + .rate = 12000000, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED, +}; + +static struct clk uart1_16xx = { + .name = "uart1_ck", + /* Direct from ULPD, no real parent */ + .parent = &armper_ck, + .rate = 48000000, + .flags = CLOCK_IN_OMAP16XX, +}; + +static struct clk uart2_ck = { + .name = "uart2_ck", + /* Direct from ULPD, no real parent */ + .parent = &armper_ck, /* either armper_ck or dpll4 */ + .rate = 12000000, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | + ALWAYS_ENABLED, +}; + +static struct clk uart3_1510 = { + .name = "uart3_ck", + /* Direct from ULPD, no real parent */ + .parent = &armper_ck, /* either armper_ck or dpll4 */ + .rate = 12000000, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED, +}; + +static struct clk uart3_16xx = { + .name = "uart3_ck", + /* Direct from ULPD, no real parent */ + .parent = &armper_ck, + .rate = 48000000, + .flags = CLOCK_IN_OMAP16XX, +}; + +static struct clk usb_clk0 = { /* 6 MHz output on W4_USB_CLK0 */ + .name = "usb_clk0", + .alias = "usb.clko", + /* Direct from ULPD, no parent */ + .rate = 6000000, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, +}; + +static struct clk usb_hhc_ck1510 = { + .name = "usb_hhc_ck", + /* Direct from ULPD, no parent */ + .rate = 48000000, /* Actually 2 clocks, 12MHz and 48MHz */ + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, +}; + +static struct clk usb_hhc_ck16xx = { + .name = "usb_hhc_ck", + /* Direct from ULPD, no parent */ + .rate = 48000000, + /* OTG_SYSCON_2.OTG_PADEN == 0 (not 1510-compatible) */ + .flags = CLOCK_IN_OMAP16XX, +}; + +static struct clk usb_w2fc_mclk = { + .name = "usb_w2fc_mclk", + .alias = "usb_w2fc_ck", + .parent = &ck_48m, + .rate = 48000000, + .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, +}; + +static struct clk mclk_1510 = { + .name = "mclk", + /* Direct from ULPD, no parent. May be enabled by ext hardware. */ + .rate = 12000000, + .flags = CLOCK_IN_OMAP1510, +}; + +static struct clk bclk_310 = { + .name = "bt_mclk_out", /* Alias midi_mclk_out? */ + .parent = &armper_ck, + .flags = CLOCK_IN_OMAP310, +}; + +static struct clk mclk_310 = { + .name = "com_mclk_out", + .parent = &armper_ck, + .flags = CLOCK_IN_OMAP310, +}; + +static struct clk mclk_16xx = { + .name = "mclk", + /* Direct from ULPD, no parent. May be enabled by ext hardware. */ + .flags = CLOCK_IN_OMAP16XX, +}; + +static struct clk bclk_1510 = { + .name = "bclk", + /* Direct from ULPD, no parent. May be enabled by ext hardware. */ + .rate = 12000000, + .flags = CLOCK_IN_OMAP1510, +}; + +static struct clk bclk_16xx = { + .name = "bclk", + /* Direct from ULPD, no parent. May be enabled by ext hardware. */ + .flags = CLOCK_IN_OMAP16XX, +}; + +static struct clk mmc1_ck = { + .name = "mmc_ck", + .id = 1, + /* Functional clock is direct from ULPD, interface clock is ARMPER */ + .parent = &armper_ck, /* either armper_ck or dpll4 */ + .rate = 48000000, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, +}; + +static struct clk mmc2_ck = { + .name = "mmc_ck", + .id = 2, + /* Functional clock is direct from ULPD, interface clock is ARMPER */ + .parent = &armper_ck, + .rate = 48000000, + .flags = CLOCK_IN_OMAP16XX, +}; + +static struct clk cam_mclk = { + .name = "cam.mclk", + .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, + .rate = 12000000, +}; + +static struct clk cam_exclk = { + .name = "cam.exclk", + .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, + /* Either 12M from cam.mclk or 48M from dpll4 */ + .parent = &cam_mclk, +}; + +static struct clk cam_lclk = { + .name = "cam.lclk", + .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, +}; + +static struct clk i2c_fck = { + .name = "i2c_fck", + .id = 1, + .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | + ALWAYS_ENABLED, + .parent = &armxor_ck, +}; + +static struct clk i2c_ick = { + .name = "i2c_ick", + .id = 1, + .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, + .parent = &armper_ck, +}; + +static struct clk clk32k = { + .name = "clk32-kHz", + .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | + CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED, + .parent = &xtal_osc32k, +}; + +static struct clk ref_clk = { + .name = "ref_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED, + .rate = 12000000, /* 12 MHz or 13 MHz or 19.2 MHz */ + /*.parent = sys.xtalin */ +}; + +static struct clk apll_96m = { + .name = "apll_96m", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED, + .rate = 96000000, + /*.parent = ref_clk */ +}; + +static struct clk apll_54m = { + .name = "apll_54m", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED, + .rate = 54000000, + /*.parent = ref_clk */ +}; + +static struct clk sys_clk = { + .name = "sys_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED, + .rate = 32768, + /*.parent = sys.xtalin */ +}; + +static struct clk sleep_clk = { + .name = "sleep_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED, + .rate = 32768, + /*.parent = sys.xtalin */ +}; + +static struct clk dpll_ck = { + .name = "dpll", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED, + .parent = &ref_clk, +}; + +static struct clk dpll_x2_ck = { + .name = "dpll_x2", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED, + .parent = &ref_clk, +}; + +static struct clk wdt1_sys_clk = { + .name = "wdt1_sys_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED, + .rate = 32768, + /*.parent = sys.xtalin */ +}; + +static struct clk func_96m_clk = { + .name = "func_96m_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .divisor = 1, + .parent = &apll_96m, +}; + +static struct clk func_48m_clk = { + .name = "func_48m_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .divisor = 2, + .parent = &apll_96m, +}; + +static struct clk func_12m_clk = { + .name = "func_12m_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .divisor = 8, + .parent = &apll_96m, +}; + +static struct clk func_54m_clk = { + .name = "func_54m_clk", + .flags = CLOCK_IN_OMAP242X, + .divisor = 1, + .parent = &apll_54m, +}; + +static struct clk sys_clkout = { + .name = "clkout", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &sys_clk, +}; + +static struct clk sys_clkout2 = { + .name = "clkout2", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &sys_clk, +}; + +static struct clk core_clk = { + .name = "core_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &dpll_x2_ck, /* Switchable between dpll_ck and clk32k */ +}; + +static struct clk l3_clk = { + .name = "l3_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &core_clk, +}; + +static struct clk core_l4_iclk = { + .name = "core_l4_iclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &l3_clk, +}; + +static struct clk wu_l4_iclk = { + .name = "wu_l4_iclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &l3_clk, +}; + +static struct clk core_l3_iclk = { + .name = "core_l3_iclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &core_clk, +}; + +static struct clk core_l4_usb_clk = { + .name = "core_l4_usb_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &l3_clk, +}; + +static struct clk wu_gpt1_clk = { + .name = "wu_gpt1_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &sys_clk, +}; + +static struct clk wu_32k_clk = { + .name = "wu_32k_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &sys_clk, +}; + +static struct clk uart1_fclk = { + .name = "uart1_fclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &func_48m_clk, +}; + +static struct clk uart1_iclk = { + .name = "uart1_iclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &core_l4_iclk, +}; + +static struct clk uart2_fclk = { + .name = "uart2_fclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &func_48m_clk, +}; + +static struct clk uart2_iclk = { + .name = "uart2_iclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &core_l4_iclk, +}; + +static struct clk uart3_fclk = { + .name = "uart3_fclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &func_48m_clk, +}; + +static struct clk uart3_iclk = { + .name = "uart3_iclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &core_l4_iclk, +}; + +static struct clk mpu_fclk = { + .name = "mpu_fclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &core_clk, +}; + +static struct clk mpu_iclk = { + .name = "mpu_iclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &core_clk, +}; + +static struct clk int_m_fclk = { + .name = "int_m_fclk", + .alias = "mpu_intc_fclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &core_clk, +}; + +static struct clk int_m_iclk = { + .name = "int_m_iclk", + .alias = "mpu_intc_iclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &core_clk, +}; + +static struct clk core_gpt2_clk = { + .name = "core_gpt2_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &sys_clk, +}; + +static struct clk core_gpt3_clk = { + .name = "core_gpt3_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &sys_clk, +}; + +static struct clk core_gpt4_clk = { + .name = "core_gpt4_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &sys_clk, +}; + +static struct clk core_gpt5_clk = { + .name = "core_gpt5_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &sys_clk, +}; + +static struct clk core_gpt6_clk = { + .name = "core_gpt6_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &sys_clk, +}; + +static struct clk core_gpt7_clk = { + .name = "core_gpt7_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &sys_clk, +}; + +static struct clk core_gpt8_clk = { + .name = "core_gpt8_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &sys_clk, +}; + +static struct clk core_gpt9_clk = { + .name = "core_gpt9_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &sys_clk, +}; + +static struct clk core_gpt10_clk = { + .name = "core_gpt10_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &sys_clk, +}; + +static struct clk core_gpt11_clk = { + .name = "core_gpt11_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &sys_clk, +}; + +static struct clk core_gpt12_clk = { + .name = "core_gpt12_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &sys_clk, +}; + +static struct clk mcbsp1_clk = { + .name = "mcbsp1_cg", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .divisor = 2, + .parent = &func_96m_clk, +}; + +static struct clk mcbsp2_clk = { + .name = "mcbsp2_cg", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .divisor = 2, + .parent = &func_96m_clk, +}; + +static struct clk emul_clk = { + .name = "emul_ck", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &func_54m_clk, +}; + +static struct clk sdma_fclk = { + .name = "sdma_fclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &l3_clk, +}; + +static struct clk sdma_iclk = { + .name = "sdma_iclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &core_l3_iclk, /* core_l4_iclk for the configuration port */ +}; + +static struct clk i2c1_fclk = { + .name = "i2c1.fclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &func_12m_clk, + .divisor = 1, +}; + +static struct clk i2c1_iclk = { + .name = "i2c1.iclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &core_l4_iclk, +}; + +static struct clk i2c2_fclk = { + .name = "i2c2.fclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &func_12m_clk, + .divisor = 1, +}; + +static struct clk i2c2_iclk = { + .name = "i2c2.iclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &core_l4_iclk, +}; + +static struct clk gpio_dbclk[5] = { + { + .name = "gpio1_dbclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &wu_32k_clk, + }, { + .name = "gpio2_dbclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &wu_32k_clk, + }, { + .name = "gpio3_dbclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &wu_32k_clk, + }, { + .name = "gpio4_dbclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &wu_32k_clk, + }, { + .name = "gpio5_dbclk", + .flags = CLOCK_IN_OMAP243X, + .parent = &wu_32k_clk, + }, +}; + +static struct clk gpio_iclk = { + .name = "gpio_iclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &wu_l4_iclk, +}; + +static struct clk mmc_fck = { + .name = "mmc_fclk", + .flags = CLOCK_IN_OMAP242X, + .parent = &func_96m_clk, +}; + +static struct clk mmc_ick = { + .name = "mmc_iclk", + .flags = CLOCK_IN_OMAP242X, + .parent = &core_l4_iclk, +}; + +static struct clk spi_fclk[3] = { + { + .name = "spi1_fclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &func_48m_clk, + }, { + .name = "spi2_fclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &func_48m_clk, + }, { + .name = "spi3_fclk", + .flags = CLOCK_IN_OMAP243X, + .parent = &func_48m_clk, + }, +}; + +static struct clk dss_clk[2] = { + { + .name = "dss_clk1", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &core_clk, + }, { + .name = "dss_clk2", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &sys_clk, + }, +}; + +static struct clk dss_54m_clk = { + .name = "dss_54m_clk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &func_54m_clk, +}; + +static struct clk dss_l3_iclk = { + .name = "dss_l3_iclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &core_l3_iclk, +}; + +static struct clk dss_l4_iclk = { + .name = "dss_l4_iclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &core_l4_iclk, +}; + +static struct clk spi_iclk[3] = { + { + .name = "spi1_iclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &core_l4_iclk, + }, { + .name = "spi2_iclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + .parent = &core_l4_iclk, + }, { + .name = "spi3_iclk", + .flags = CLOCK_IN_OMAP243X, + .parent = &core_l4_iclk, + }, +}; + +static struct clk omapctrl_clk = { + .name = "omapctrl_iclk", + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + /* XXX Should be in WKUP domain */ + .parent = &core_l4_iclk, +}; + +static struct clk *onchip_clks[] = { + /* OMAP 1 */ + + /* non-ULPD clocks */ + &xtal_osc12m, + &xtal_osc32k, + &ck_ref, + &dpll1, + &dpll2, + &dpll3, + &dpll4, + &apll, + &ck_48m, + /* CK_GEN1 clocks */ + &clkm1, + &ck_dpll1out, + &sossi_ck, + &arm_ck, + &armper_ck, + &arm_gpio_ck, + &armxor_ck, + &armtim_ck, + &armwdt_ck, + &arminth_ck15xx, &arminth_ck16xx, + /* CK_GEN2 clocks */ + &clkm2, + &dsp_ck, + &dspmmu_ck, + &dspper_ck, + &dspxor_ck, + &dsptim_ck, + /* CK_GEN3 clocks */ + &clkm3, + &tc_ck, + &tipb_ck, + &l3_ocpi_ck, + &tc1_ck, + &tc2_ck, + &dma_ck, + &dma_lcdfree_ck, + &api_ck, + &lb_ck, + &lbfree_ck, + &hsab_ck, + &rhea1_ck, + &rhea2_ck, + &lcd_ck_16xx, + &lcd_ck_1510, + /* ULPD clocks */ + &uart1_1510, + &uart1_16xx, + &uart2_ck, + &uart3_1510, + &uart3_16xx, + &usb_clk0, + &usb_hhc_ck1510, &usb_hhc_ck16xx, + &mclk_1510, &mclk_16xx, &mclk_310, + &bclk_1510, &bclk_16xx, &bclk_310, + &mmc1_ck, + &mmc2_ck, + &cam_mclk, + &cam_exclk, + &cam_lclk, + &clk32k, + &usb_w2fc_mclk, + /* Virtual clocks */ + &i2c_fck, + &i2c_ick, + + /* OMAP 2 */ + + &ref_clk, + &apll_96m, + &apll_54m, + &sys_clk, + &sleep_clk, + &dpll_ck, + &dpll_x2_ck, + &wdt1_sys_clk, + &func_96m_clk, + &func_48m_clk, + &func_12m_clk, + &func_54m_clk, + &sys_clkout, + &sys_clkout2, + &core_clk, + &l3_clk, + &core_l4_iclk, + &wu_l4_iclk, + &core_l3_iclk, + &core_l4_usb_clk, + &wu_gpt1_clk, + &wu_32k_clk, + &uart1_fclk, + &uart1_iclk, + &uart2_fclk, + &uart2_iclk, + &uart3_fclk, + &uart3_iclk, + &mpu_fclk, + &mpu_iclk, + &int_m_fclk, + &int_m_iclk, + &core_gpt2_clk, + &core_gpt3_clk, + &core_gpt4_clk, + &core_gpt5_clk, + &core_gpt6_clk, + &core_gpt7_clk, + &core_gpt8_clk, + &core_gpt9_clk, + &core_gpt10_clk, + &core_gpt11_clk, + &core_gpt12_clk, + &mcbsp1_clk, + &mcbsp2_clk, + &emul_clk, + &sdma_fclk, + &sdma_iclk, + &i2c1_fclk, + &i2c1_iclk, + &i2c2_fclk, + &i2c2_iclk, + &gpio_dbclk[0], + &gpio_dbclk[1], + &gpio_dbclk[2], + &gpio_dbclk[3], + &gpio_iclk, + &mmc_fck, + &mmc_ick, + &spi_fclk[0], + &spi_iclk[0], + &spi_fclk[1], + &spi_iclk[1], + &spi_fclk[2], + &spi_iclk[2], + &dss_clk[0], + &dss_clk[1], + &dss_54m_clk, + &dss_l3_iclk, + &dss_l4_iclk, + &omapctrl_clk, + + NULL +}; + +void omap_clk_adduser(struct clk *clk, qemu_irq user) +{ + qemu_irq *i; + + for (i = clk->users; *i; i ++); + *i = user; +} + +struct clk *omap_findclk(struct omap_mpu_state_s *mpu, const char *name) +{ + struct clk *i; + + for (i = mpu->clks; i->name; i ++) + if (!strcmp(i->name, name) || (i->alias && !strcmp(i->alias, name))) + return i; + hw_error("%s: %s not found\n", __FUNCTION__, name); +} + +void omap_clk_get(struct clk *clk) +{ + clk->usecount ++; +} + +void omap_clk_put(struct clk *clk) +{ + if (!(clk->usecount --)) + hw_error("%s: %s is not in use\n", __FUNCTION__, clk->name); +} + +static void omap_clk_update(struct clk *clk) +{ + int parent, running; + qemu_irq *user; + struct clk *i; + + if (clk->parent) + parent = clk->parent->running; + else + parent = 1; + + running = parent && (clk->enabled || + ((clk->flags & ALWAYS_ENABLED) && clk->usecount)); + if (clk->running != running) { + clk->running = running; + for (user = clk->users; *user; user ++) + qemu_set_irq(*user, running); + for (i = clk->child1; i; i = i->sibling) + omap_clk_update(i); + } +} + +static void omap_clk_rate_update_full(struct clk *clk, unsigned long int rate, + unsigned long int div, unsigned long int mult) +{ + struct clk *i; + qemu_irq *user; + + clk->rate = muldiv64(rate, mult, div); + if (clk->running) + for (user = clk->users; *user; user ++) + qemu_irq_raise(*user); + for (i = clk->child1; i; i = i->sibling) + omap_clk_rate_update_full(i, rate, + div * i->divisor, mult * i->multiplier); +} + +static void omap_clk_rate_update(struct clk *clk) +{ + struct clk *i; + unsigned long int div, mult = div = 1; + + for (i = clk; i->parent; i = i->parent) { + div *= i->divisor; + mult *= i->multiplier; + } + + omap_clk_rate_update_full(clk, i->rate, div, mult); +} + +void omap_clk_reparent(struct clk *clk, struct clk *parent) +{ + struct clk **p; + + if (clk->parent) { + for (p = &clk->parent->child1; *p != clk; p = &(*p)->sibling); + *p = clk->sibling; + } + + clk->parent = parent; + if (parent) { + clk->sibling = parent->child1; + parent->child1 = clk; + omap_clk_update(clk); + omap_clk_rate_update(clk); + } else + clk->sibling = NULL; +} + +void omap_clk_onoff(struct clk *clk, int on) +{ + clk->enabled = on; + omap_clk_update(clk); +} + +void omap_clk_canidle(struct clk *clk, int can) +{ + if (can) + omap_clk_put(clk); + else + omap_clk_get(clk); +} + +void omap_clk_setrate(struct clk *clk, int divide, int multiply) +{ + clk->divisor = divide; + clk->multiplier = multiply; + omap_clk_rate_update(clk); +} + +int64_t omap_clk_getrate(omap_clk clk) +{ + return clk->rate; +} + +void omap_clk_init(struct omap_mpu_state_s *mpu) +{ + struct clk **i, *j, *k; + int count; + int flag; + + if (cpu_is_omap310(mpu)) + flag = CLOCK_IN_OMAP310; + else if (cpu_is_omap1510(mpu)) + flag = CLOCK_IN_OMAP1510; + else if (cpu_is_omap2410(mpu) || cpu_is_omap2420(mpu)) + flag = CLOCK_IN_OMAP242X; + else if (cpu_is_omap2430(mpu)) + flag = CLOCK_IN_OMAP243X; + else if (cpu_is_omap3430(mpu)) + flag = CLOCK_IN_OMAP243X; + else + return; + + for (i = onchip_clks, count = 0; *i; i ++) + if ((*i)->flags & flag) + count ++; + mpu->clks = (struct clk *) g_malloc0(sizeof(struct clk) * (count + 1)); + for (i = onchip_clks, j = mpu->clks; *i; i ++) + if ((*i)->flags & flag) { + memcpy(j, *i, sizeof(struct clk)); + for (k = mpu->clks; k < j; k ++) + if (j->parent && !strcmp(j->parent->name, k->name)) { + j->parent = k; + j->sibling = k->child1; + k->child1 = j; + } else if (k->parent && !strcmp(k->parent->name, j->name)) { + k->parent = j; + k->sibling = j->child1; + j->child1 = k; + } + j->divisor = j->divisor ?: 1; + j->multiplier = j->multiplier ?: 1; + j ++; + } + for (j = mpu->clks; count --; j ++) { + omap_clk_update(j); + omap_clk_rate_update(j); + } +} diff --git a/hw/misc/omap_gpmc.c b/hw/misc/omap_gpmc.c new file mode 100644 index 0000000000..91adb66c2b --- /dev/null +++ b/hw/misc/omap_gpmc.c @@ -0,0 +1,894 @@ +/* + * TI OMAP general purpose memory controller emulation. + * + * Copyright (C) 2007-2009 Nokia Corporation + * Original code written by Andrzej Zaborowski + * Enhancements for OMAP3 and NAND support written by Juha Riihimäki + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ +#include "hw/hw.h" +#include "hw/block/flash.h" +#include "hw/arm/omap.h" +#include "exec/memory.h" +#include "exec/address-spaces.h" + +/* General-Purpose Memory Controller */ +struct omap_gpmc_s { + qemu_irq irq; + qemu_irq drq; + MemoryRegion iomem; + int accept_256; + + uint8_t revision; + uint8_t sysconfig; + uint16_t irqst; + uint16_t irqen; + uint16_t lastirq; + uint16_t timeout; + uint16_t config; + struct omap_gpmc_cs_file_s { + uint32_t config[7]; + MemoryRegion *iomem; + MemoryRegion container; + MemoryRegion nandiomem; + DeviceState *dev; + } cs_file[8]; + int ecc_cs; + int ecc_ptr; + uint32_t ecc_cfg; + ECCState ecc[9]; + struct prefetch { + uint32_t config1; /* GPMC_PREFETCH_CONFIG1 */ + uint32_t transfercount; /* GPMC_PREFETCH_CONFIG2:TRANSFERCOUNT */ + int startengine; /* GPMC_PREFETCH_CONTROL:STARTENGINE */ + int fifopointer; /* GPMC_PREFETCH_STATUS:FIFOPOINTER */ + int count; /* GPMC_PREFETCH_STATUS:COUNTVALUE */ + MemoryRegion iomem; + uint8_t fifo[64]; + } prefetch; +}; + +#define OMAP_GPMC_8BIT 0 +#define OMAP_GPMC_16BIT 1 +#define OMAP_GPMC_NOR 0 +#define OMAP_GPMC_NAND 2 + +static int omap_gpmc_devtype(struct omap_gpmc_cs_file_s *f) +{ + return (f->config[0] >> 10) & 3; +} + +static int omap_gpmc_devsize(struct omap_gpmc_cs_file_s *f) +{ + /* devsize field is really 2 bits but we ignore the high + * bit to ensure consistent behaviour if the guest sets + * it (values 2 and 3 are reserved in the TRM) + */ + return (f->config[0] >> 12) & 1; +} + +/* Extract the chip-select value from the prefetch config1 register */ +static int prefetch_cs(uint32_t config1) +{ + return (config1 >> 24) & 7; +} + +static int prefetch_threshold(uint32_t config1) +{ + return (config1 >> 8) & 0x7f; +} + +static void omap_gpmc_int_update(struct omap_gpmc_s *s) +{ + /* The TRM is a bit unclear, but it seems to say that + * the TERMINALCOUNTSTATUS bit is set only on the + * transition when the prefetch engine goes from + * active to inactive, whereas the FIFOEVENTSTATUS + * bit is held high as long as the fifo has at + * least THRESHOLD bytes available. + * So we do the latter here, but TERMINALCOUNTSTATUS + * is set elsewhere. + */ + if (s->prefetch.fifopointer >= prefetch_threshold(s->prefetch.config1)) { + s->irqst |= 1; + } + if ((s->irqen & s->irqst) != s->lastirq) { + s->lastirq = s->irqen & s->irqst; + qemu_set_irq(s->irq, s->lastirq); + } +} + +static void omap_gpmc_dma_update(struct omap_gpmc_s *s, int value) +{ + if (s->prefetch.config1 & 4) { + qemu_set_irq(s->drq, value); + } +} + +/* Access functions for when a NAND-like device is mapped into memory: + * all addresses in the region behave like accesses to the relevant + * GPMC_NAND_DATA_i register (which is actually implemented to call these) + */ +static uint64_t omap_nand_read(void *opaque, hwaddr addr, + unsigned size) +{ + struct omap_gpmc_cs_file_s *f = (struct omap_gpmc_cs_file_s *)opaque; + uint64_t v; + nand_setpins(f->dev, 0, 0, 0, 1, 0); + switch (omap_gpmc_devsize(f)) { + case OMAP_GPMC_8BIT: + v = nand_getio(f->dev); + if (size == 1) { + return v; + } + v |= (nand_getio(f->dev) << 8); + if (size == 2) { + return v; + } + v |= (nand_getio(f->dev) << 16); + v |= (nand_getio(f->dev) << 24); + return v; + case OMAP_GPMC_16BIT: + v = nand_getio(f->dev); + if (size == 1) { + /* 8 bit read from 16 bit device : probably a guest bug */ + return v & 0xff; + } + if (size == 2) { + return v; + } + v |= (nand_getio(f->dev) << 16); + return v; + default: + abort(); + } +} + +static void omap_nand_setio(DeviceState *dev, uint64_t value, + int nandsize, int size) +{ + /* Write the specified value to the NAND device, respecting + * both size of the NAND device and size of the write access. + */ + switch (nandsize) { + case OMAP_GPMC_8BIT: + switch (size) { + case 1: + nand_setio(dev, value & 0xff); + break; + case 2: + nand_setio(dev, value & 0xff); + nand_setio(dev, (value >> 8) & 0xff); + break; + case 4: + default: + nand_setio(dev, value & 0xff); + nand_setio(dev, (value >> 8) & 0xff); + nand_setio(dev, (value >> 16) & 0xff); + nand_setio(dev, (value >> 24) & 0xff); + break; + } + break; + case OMAP_GPMC_16BIT: + switch (size) { + case 1: + /* writing to a 16bit device with 8bit access is probably a guest + * bug; pass the value through anyway. + */ + case 2: + nand_setio(dev, value & 0xffff); + break; + case 4: + default: + nand_setio(dev, value & 0xffff); + nand_setio(dev, (value >> 16) & 0xffff); + break; + } + break; + } +} + +static void omap_nand_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + struct omap_gpmc_cs_file_s *f = (struct omap_gpmc_cs_file_s *)opaque; + nand_setpins(f->dev, 0, 0, 0, 1, 0); + omap_nand_setio(f->dev, value, omap_gpmc_devsize(f), size); +} + +static const MemoryRegionOps omap_nand_ops = { + .read = omap_nand_read, + .write = omap_nand_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void fill_prefetch_fifo(struct omap_gpmc_s *s) +{ + /* Fill the prefetch FIFO by reading data from NAND. + * We do this synchronously, unlike the hardware which + * will do this asynchronously. We refill when the + * FIFO has THRESHOLD bytes free, and we always refill + * as much data as possible starting at the top end + * of the FIFO. + * (We have to refill at THRESHOLD rather than waiting + * for the FIFO to empty to allow for the case where + * the FIFO size isn't an exact multiple of THRESHOLD + * and we're doing DMA transfers.) + * This means we never need to handle wrap-around in + * the fifo-reading code, and the next byte of data + * to read is always fifo[63 - fifopointer]. + */ + int fptr; + int cs = prefetch_cs(s->prefetch.config1); + int is16bit = (((s->cs_file[cs].config[0] >> 12) & 3) != 0); + int bytes; + /* Don't believe the bit of the OMAP TRM that says that COUNTVALUE + * and TRANSFERCOUNT are in units of 16 bit words for 16 bit NAND. + * Instead believe the bit that says it is always a byte count. + */ + bytes = 64 - s->prefetch.fifopointer; + if (bytes > s->prefetch.count) { + bytes = s->prefetch.count; + } + s->prefetch.count -= bytes; + s->prefetch.fifopointer += bytes; + fptr = 64 - s->prefetch.fifopointer; + /* Move the existing data in the FIFO so it sits just + * before what we're about to read in + */ + while (fptr < (64 - bytes)) { + s->prefetch.fifo[fptr] = s->prefetch.fifo[fptr + bytes]; + fptr++; + } + while (fptr < 64) { + if (is16bit) { + uint32_t v = omap_nand_read(&s->cs_file[cs], 0, 2); + s->prefetch.fifo[fptr++] = v & 0xff; + s->prefetch.fifo[fptr++] = (v >> 8) & 0xff; + } else { + s->prefetch.fifo[fptr++] = omap_nand_read(&s->cs_file[cs], 0, 1); + } + } + if (s->prefetch.startengine && (s->prefetch.count == 0)) { + /* This was the final transfer: raise TERMINALCOUNTSTATUS */ + s->irqst |= 2; + s->prefetch.startengine = 0; + } + /* If there are any bytes in the FIFO at this point then + * we must raise a DMA request (either this is a final part + * transfer, or we filled the FIFO in which case we certainly + * have THRESHOLD bytes available) + */ + if (s->prefetch.fifopointer != 0) { + omap_gpmc_dma_update(s, 1); + } + omap_gpmc_int_update(s); +} + +/* Access functions for a NAND-like device when the prefetch/postwrite + * engine is enabled -- all addresses in the region behave alike: + * data is read or written to the FIFO. + */ +static uint64_t omap_gpmc_prefetch_read(void *opaque, hwaddr addr, + unsigned size) +{ + struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque; + uint32_t data; + if (s->prefetch.config1 & 1) { + /* The TRM doesn't define the behaviour if you read from the + * FIFO when the prefetch engine is in write mode. We choose + * to always return zero. + */ + return 0; + } + /* Note that trying to read an empty fifo repeats the last byte */ + if (s->prefetch.fifopointer) { + s->prefetch.fifopointer--; + } + data = s->prefetch.fifo[63 - s->prefetch.fifopointer]; + if (s->prefetch.fifopointer == + (64 - prefetch_threshold(s->prefetch.config1))) { + /* We've drained THRESHOLD bytes now. So deassert the + * DMA request, then refill the FIFO (which will probably + * assert it again.) + */ + omap_gpmc_dma_update(s, 0); + fill_prefetch_fifo(s); + } + omap_gpmc_int_update(s); + return data; +} + +static void omap_gpmc_prefetch_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque; + int cs = prefetch_cs(s->prefetch.config1); + if ((s->prefetch.config1 & 1) == 0) { + /* The TRM doesn't define the behaviour of writing to the + * FIFO when the prefetch engine is in read mode. We + * choose to ignore the write. + */ + return; + } + if (s->prefetch.count == 0) { + /* The TRM doesn't define the behaviour of writing to the + * FIFO if the transfer is complete. We choose to ignore. + */ + return; + } + /* The only reason we do any data buffering in postwrite + * mode is if we are talking to a 16 bit NAND device, in + * which case we need to buffer the first byte of the + * 16 bit word until the other byte arrives. + */ + int is16bit = (((s->cs_file[cs].config[0] >> 12) & 3) != 0); + if (is16bit) { + /* fifopointer alternates between 64 (waiting for first + * byte of word) and 63 (waiting for second byte) + */ + if (s->prefetch.fifopointer == 64) { + s->prefetch.fifo[0] = value; + s->prefetch.fifopointer--; + } else { + value = (value << 8) | s->prefetch.fifo[0]; + omap_nand_write(&s->cs_file[cs], 0, value, 2); + s->prefetch.count--; + s->prefetch.fifopointer = 64; + } + } else { + /* Just write the byte : fifopointer remains 64 at all times */ + omap_nand_write(&s->cs_file[cs], 0, value, 1); + s->prefetch.count--; + } + if (s->prefetch.count == 0) { + /* Final transfer: raise TERMINALCOUNTSTATUS */ + s->irqst |= 2; + s->prefetch.startengine = 0; + } + omap_gpmc_int_update(s); +} + +static const MemoryRegionOps omap_prefetch_ops = { + .read = omap_gpmc_prefetch_read, + .write = omap_gpmc_prefetch_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl.min_access_size = 1, + .impl.max_access_size = 1, +}; + +static MemoryRegion *omap_gpmc_cs_memregion(struct omap_gpmc_s *s, int cs) +{ + /* Return the MemoryRegion* to map/unmap for this chipselect */ + struct omap_gpmc_cs_file_s *f = &s->cs_file[cs]; + if (omap_gpmc_devtype(f) == OMAP_GPMC_NOR) { + return f->iomem; + } + if ((s->prefetch.config1 & 0x80) && + (prefetch_cs(s->prefetch.config1) == cs)) { + /* The prefetch engine is enabled for this CS: map the FIFO */ + return &s->prefetch.iomem; + } + return &f->nandiomem; +} + +static void omap_gpmc_cs_map(struct omap_gpmc_s *s, int cs) +{ + struct omap_gpmc_cs_file_s *f = &s->cs_file[cs]; + uint32_t mask = (f->config[6] >> 8) & 0xf; + uint32_t base = f->config[6] & 0x3f; + uint32_t size; + + if (!f->iomem && !f->dev) { + return; + } + + if (!(f->config[6] & (1 << 6))) { + /* Do nothing unless CSVALID */ + return; + } + + /* TODO: check for overlapping regions and report access errors */ + if (mask != 0x8 && mask != 0xc && mask != 0xe && mask != 0xf + && !(s->accept_256 && !mask)) { + fprintf(stderr, "%s: invalid chip-select mask address (0x%x)\n", + __func__, mask); + } + + base <<= 24; + size = (0x0fffffff & ~(mask << 24)) + 1; + /* TODO: rather than setting the size of the mapping (which should be + * constant), the mask should cause wrapping of the address space, so + * that the same memory becomes accessible at every size bytes + * starting from base. */ + memory_region_init(&f->container, "omap-gpmc-file", size); + memory_region_add_subregion(&f->container, 0, + omap_gpmc_cs_memregion(s, cs)); + memory_region_add_subregion(get_system_memory(), base, + &f->container); +} + +static void omap_gpmc_cs_unmap(struct omap_gpmc_s *s, int cs) +{ + struct omap_gpmc_cs_file_s *f = &s->cs_file[cs]; + if (!(f->config[6] & (1 << 6))) { + /* Do nothing unless CSVALID */ + return; + } + if (!f->iomem && !f->dev) { + return; + } + memory_region_del_subregion(get_system_memory(), &f->container); + memory_region_del_subregion(&f->container, omap_gpmc_cs_memregion(s, cs)); + memory_region_destroy(&f->container); +} + +void omap_gpmc_reset(struct omap_gpmc_s *s) +{ + int i; + + s->sysconfig = 0; + s->irqst = 0; + s->irqen = 0; + omap_gpmc_int_update(s); + for (i = 0; i < 8; i++) { + /* This has to happen before we change any of the config + * used to determine which memory regions are mapped or unmapped. + */ + omap_gpmc_cs_unmap(s, i); + } + s->timeout = 0; + s->config = 0xa00; + s->prefetch.config1 = 0x00004000; + s->prefetch.transfercount = 0x00000000; + s->prefetch.startengine = 0; + s->prefetch.fifopointer = 0; + s->prefetch.count = 0; + for (i = 0; i < 8; i ++) { + s->cs_file[i].config[1] = 0x101001; + s->cs_file[i].config[2] = 0x020201; + s->cs_file[i].config[3] = 0x10031003; + s->cs_file[i].config[4] = 0x10f1111; + s->cs_file[i].config[5] = 0; + s->cs_file[i].config[6] = 0xf00 | (i ? 0 : 1 << 6); + + s->cs_file[i].config[6] = 0xf00; + /* In theory we could probe attached devices for some CFG1 + * bits here, but we just retain them across resets as they + * were set initially by omap_gpmc_attach(). + */ + if (i == 0) { + s->cs_file[i].config[0] &= 0x00433e00; + s->cs_file[i].config[6] |= 1 << 6; /* CSVALID */ + omap_gpmc_cs_map(s, i); + } else { + s->cs_file[i].config[0] &= 0x00403c00; + } + } + s->ecc_cs = 0; + s->ecc_ptr = 0; + s->ecc_cfg = 0x3fcff000; + for (i = 0; i < 9; i ++) + ecc_reset(&s->ecc[i]); +} + +static int gpmc_wordaccess_only(hwaddr addr) +{ + /* Return true if the register offset is to a register that + * only permits word width accesses. + * Non-word accesses are only OK for GPMC_NAND_DATA/ADDRESS/COMMAND + * for any chipselect. + */ + if (addr >= 0x60 && addr <= 0x1d4) { + int cs = (addr - 0x60) / 0x30; + addr -= cs * 0x30; + if (addr >= 0x7c && addr < 0x88) { + /* GPMC_NAND_COMMAND, GPMC_NAND_ADDRESS, GPMC_NAND_DATA */ + return 0; + } + } + return 1; +} + +static uint64_t omap_gpmc_read(void *opaque, hwaddr addr, + unsigned size) +{ + struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque; + int cs; + struct omap_gpmc_cs_file_s *f; + + if (size != 4 && gpmc_wordaccess_only(addr)) { + return omap_badwidth_read32(opaque, addr); + } + + switch (addr) { + case 0x000: /* GPMC_REVISION */ + return s->revision; + + case 0x010: /* GPMC_SYSCONFIG */ + return s->sysconfig; + + case 0x014: /* GPMC_SYSSTATUS */ + return 1; /* RESETDONE */ + + case 0x018: /* GPMC_IRQSTATUS */ + return s->irqst; + + case 0x01c: /* GPMC_IRQENABLE */ + return s->irqen; + + case 0x040: /* GPMC_TIMEOUT_CONTROL */ + return s->timeout; + + case 0x044: /* GPMC_ERR_ADDRESS */ + case 0x048: /* GPMC_ERR_TYPE */ + return 0; + + case 0x050: /* GPMC_CONFIG */ + return s->config; + + case 0x054: /* GPMC_STATUS */ + return 0x001; + + case 0x060 ... 0x1d4: + cs = (addr - 0x060) / 0x30; + addr -= cs * 0x30; + f = s->cs_file + cs; + switch (addr) { + case 0x60: /* GPMC_CONFIG1 */ + return f->config[0]; + case 0x64: /* GPMC_CONFIG2 */ + return f->config[1]; + case 0x68: /* GPMC_CONFIG3 */ + return f->config[2]; + case 0x6c: /* GPMC_CONFIG4 */ + return f->config[3]; + case 0x70: /* GPMC_CONFIG5 */ + return f->config[4]; + case 0x74: /* GPMC_CONFIG6 */ + return f->config[5]; + case 0x78: /* GPMC_CONFIG7 */ + return f->config[6]; + case 0x84 ... 0x87: /* GPMC_NAND_DATA */ + if (omap_gpmc_devtype(f) == OMAP_GPMC_NAND) { + return omap_nand_read(f, 0, size); + } + return 0; + } + break; + + case 0x1e0: /* GPMC_PREFETCH_CONFIG1 */ + return s->prefetch.config1; + case 0x1e4: /* GPMC_PREFETCH_CONFIG2 */ + return s->prefetch.transfercount; + case 0x1ec: /* GPMC_PREFETCH_CONTROL */ + return s->prefetch.startengine; + case 0x1f0: /* GPMC_PREFETCH_STATUS */ + /* NB: The OMAP3 TRM is inconsistent about whether the GPMC + * FIFOTHRESHOLDSTATUS bit should be set when + * FIFOPOINTER > FIFOTHRESHOLD or when it is >= FIFOTHRESHOLD. + * Apparently the underlying functional spec from which the TRM was + * created states that the behaviour is ">=", and this also + * makes more conceptual sense. + */ + return (s->prefetch.fifopointer << 24) | + ((s->prefetch.fifopointer >= + ((s->prefetch.config1 >> 8) & 0x7f) ? 1 : 0) << 16) | + s->prefetch.count; + + case 0x1f4: /* GPMC_ECC_CONFIG */ + return s->ecc_cs; + case 0x1f8: /* GPMC_ECC_CONTROL */ + return s->ecc_ptr; + case 0x1fc: /* GPMC_ECC_SIZE_CONFIG */ + return s->ecc_cfg; + case 0x200 ... 0x220: /* GPMC_ECC_RESULT */ + cs = (addr & 0x1f) >> 2; + /* TODO: check correctness */ + return + ((s->ecc[cs].cp & 0x07) << 0) | + ((s->ecc[cs].cp & 0x38) << 13) | + ((s->ecc[cs].lp[0] & 0x1ff) << 3) | + ((s->ecc[cs].lp[1] & 0x1ff) << 19); + + case 0x230: /* GPMC_TESTMODE_CTRL */ + return 0; + case 0x234: /* GPMC_PSA_LSB */ + case 0x238: /* GPMC_PSA_MSB */ + return 0x00000000; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_gpmc_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque; + int cs; + struct omap_gpmc_cs_file_s *f; + + if (size != 4 && gpmc_wordaccess_only(addr)) { + return omap_badwidth_write32(opaque, addr, value); + } + + switch (addr) { + case 0x000: /* GPMC_REVISION */ + case 0x014: /* GPMC_SYSSTATUS */ + case 0x054: /* GPMC_STATUS */ + case 0x1f0: /* GPMC_PREFETCH_STATUS */ + case 0x200 ... 0x220: /* GPMC_ECC_RESULT */ + case 0x234: /* GPMC_PSA_LSB */ + case 0x238: /* GPMC_PSA_MSB */ + OMAP_RO_REG(addr); + break; + + case 0x010: /* GPMC_SYSCONFIG */ + if ((value >> 3) == 0x3) + fprintf(stderr, "%s: bad SDRAM idle mode %"PRIi64"\n", + __FUNCTION__, value >> 3); + if (value & 2) + omap_gpmc_reset(s); + s->sysconfig = value & 0x19; + break; + + case 0x018: /* GPMC_IRQSTATUS */ + s->irqst &= ~value; + omap_gpmc_int_update(s); + break; + + case 0x01c: /* GPMC_IRQENABLE */ + s->irqen = value & 0xf03; + omap_gpmc_int_update(s); + break; + + case 0x040: /* GPMC_TIMEOUT_CONTROL */ + s->timeout = value & 0x1ff1; + break; + + case 0x044: /* GPMC_ERR_ADDRESS */ + case 0x048: /* GPMC_ERR_TYPE */ + break; + + case 0x050: /* GPMC_CONFIG */ + s->config = value & 0xf13; + break; + + case 0x060 ... 0x1d4: + cs = (addr - 0x060) / 0x30; + addr -= cs * 0x30; + f = s->cs_file + cs; + switch (addr) { + case 0x60: /* GPMC_CONFIG1 */ + f->config[0] = value & 0xffef3e13; + break; + case 0x64: /* GPMC_CONFIG2 */ + f->config[1] = value & 0x001f1f8f; + break; + case 0x68: /* GPMC_CONFIG3 */ + f->config[2] = value & 0x001f1f8f; + break; + case 0x6c: /* GPMC_CONFIG4 */ + f->config[3] = value & 0x1f8f1f8f; + break; + case 0x70: /* GPMC_CONFIG5 */ + f->config[4] = value & 0x0f1f1f1f; + break; + case 0x74: /* GPMC_CONFIG6 */ + f->config[5] = value & 0x00000fcf; + break; + case 0x78: /* GPMC_CONFIG7 */ + if ((f->config[6] ^ value) & 0xf7f) { + omap_gpmc_cs_unmap(s, cs); + f->config[6] = value & 0x00000f7f; + omap_gpmc_cs_map(s, cs); + } + break; + case 0x7c ... 0x7f: /* GPMC_NAND_COMMAND */ + if (omap_gpmc_devtype(f) == OMAP_GPMC_NAND) { + nand_setpins(f->dev, 1, 0, 0, 1, 0); /* CLE */ + omap_nand_setio(f->dev, value, omap_gpmc_devsize(f), size); + } + break; + case 0x80 ... 0x83: /* GPMC_NAND_ADDRESS */ + if (omap_gpmc_devtype(f) == OMAP_GPMC_NAND) { + nand_setpins(f->dev, 0, 1, 0, 1, 0); /* ALE */ + omap_nand_setio(f->dev, value, omap_gpmc_devsize(f), size); + } + break; + case 0x84 ... 0x87: /* GPMC_NAND_DATA */ + if (omap_gpmc_devtype(f) == OMAP_GPMC_NAND) { + omap_nand_write(f, 0, value, size); + } + break; + default: + goto bad_reg; + } + break; + + case 0x1e0: /* GPMC_PREFETCH_CONFIG1 */ + if (!s->prefetch.startengine) { + uint32_t newconfig1 = value & 0x7f8f7fbf; + uint32_t changed; + changed = newconfig1 ^ s->prefetch.config1; + if (changed & (0x80 | 0x7000000)) { + /* Turning the engine on or off, or mapping it somewhere else. + * cs_map() and cs_unmap() check the prefetch config and + * overall CSVALID bits, so it is sufficient to unmap-and-map + * both the old cs and the new one. Note that we adhere to + * the "unmap/change config/map" order (and not unmap twice + * if newcs == oldcs), otherwise we'll try to delete the wrong + * memory region. + */ + int oldcs = prefetch_cs(s->prefetch.config1); + int newcs = prefetch_cs(newconfig1); + omap_gpmc_cs_unmap(s, oldcs); + if (oldcs != newcs) { + omap_gpmc_cs_unmap(s, newcs); + } + s->prefetch.config1 = newconfig1; + omap_gpmc_cs_map(s, oldcs); + if (oldcs != newcs) { + omap_gpmc_cs_map(s, newcs); + } + } else { + s->prefetch.config1 = newconfig1; + } + } + break; + + case 0x1e4: /* GPMC_PREFETCH_CONFIG2 */ + if (!s->prefetch.startengine) { + s->prefetch.transfercount = value & 0x3fff; + } + break; + + case 0x1ec: /* GPMC_PREFETCH_CONTROL */ + if (s->prefetch.startengine != (value & 1)) { + s->prefetch.startengine = value & 1; + if (s->prefetch.startengine) { + /* Prefetch engine start */ + s->prefetch.count = s->prefetch.transfercount; + if (s->prefetch.config1 & 1) { + /* Write */ + s->prefetch.fifopointer = 64; + } else { + /* Read */ + s->prefetch.fifopointer = 0; + fill_prefetch_fifo(s); + } + } else { + /* Prefetch engine forcibly stopped. The TRM + * doesn't define the behaviour if you do this. + * We clear the prefetch count, which means that + * we permit no more writes, and don't read any + * more data from NAND. The CPU can still drain + * the FIFO of unread data. + */ + s->prefetch.count = 0; + } + omap_gpmc_int_update(s); + } + break; + + case 0x1f4: /* GPMC_ECC_CONFIG */ + s->ecc_cs = 0x8f; + break; + case 0x1f8: /* GPMC_ECC_CONTROL */ + if (value & (1 << 8)) + for (cs = 0; cs < 9; cs ++) + ecc_reset(&s->ecc[cs]); + s->ecc_ptr = value & 0xf; + if (s->ecc_ptr == 0 || s->ecc_ptr > 9) { + s->ecc_ptr = 0; + s->ecc_cs &= ~1; + } + break; + case 0x1fc: /* GPMC_ECC_SIZE_CONFIG */ + s->ecc_cfg = value & 0x3fcff1ff; + break; + case 0x230: /* GPMC_TESTMODE_CTRL */ + if (value & 7) + fprintf(stderr, "%s: test mode enable attempt\n", __FUNCTION__); + break; + + default: + bad_reg: + OMAP_BAD_REG(addr); + return; + } +} + +static const MemoryRegionOps omap_gpmc_ops = { + .read = omap_gpmc_read, + .write = omap_gpmc_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +struct omap_gpmc_s *omap_gpmc_init(struct omap_mpu_state_s *mpu, + hwaddr base, + qemu_irq irq, qemu_irq drq) +{ + int cs; + struct omap_gpmc_s *s = (struct omap_gpmc_s *) + g_malloc0(sizeof(struct omap_gpmc_s)); + + memory_region_init_io(&s->iomem, &omap_gpmc_ops, s, "omap-gpmc", 0x1000); + memory_region_add_subregion(get_system_memory(), base, &s->iomem); + + s->irq = irq; + s->drq = drq; + s->accept_256 = cpu_is_omap3630(mpu); + s->revision = cpu_class_omap3(mpu) ? 0x50 : 0x20; + s->lastirq = 0; + omap_gpmc_reset(s); + + /* We have to register a different IO memory handler for each + * chip select region in case a NAND device is mapped there. We + * make the region the worst-case size of 256MB and rely on the + * container memory region in cs_map to chop it down to the actual + * guest-requested size. + */ + for (cs = 0; cs < 8; cs++) { + memory_region_init_io(&s->cs_file[cs].nandiomem, + &omap_nand_ops, + &s->cs_file[cs], + "omap-nand", + 256 * 1024 * 1024); + } + + memory_region_init_io(&s->prefetch.iomem, &omap_prefetch_ops, s, + "omap-gpmc-prefetch", 256 * 1024 * 1024); + return s; +} + +void omap_gpmc_attach(struct omap_gpmc_s *s, int cs, MemoryRegion *iomem) +{ + struct omap_gpmc_cs_file_s *f; + assert(iomem); + + if (cs < 0 || cs >= 8) { + fprintf(stderr, "%s: bad chip-select %i\n", __FUNCTION__, cs); + exit(-1); + } + f = &s->cs_file[cs]; + + omap_gpmc_cs_unmap(s, cs); + f->config[0] &= ~(0xf << 10); + f->iomem = iomem; + omap_gpmc_cs_map(s, cs); +} + +void omap_gpmc_attach_nand(struct omap_gpmc_s *s, int cs, DeviceState *nand) +{ + struct omap_gpmc_cs_file_s *f; + assert(nand); + + if (cs < 0 || cs >= 8) { + fprintf(stderr, "%s: bad chip-select %i\n", __func__, cs); + exit(-1); + } + f = &s->cs_file[cs]; + + omap_gpmc_cs_unmap(s, cs); + f->config[0] &= ~(0xf << 10); + f->config[0] |= (OMAP_GPMC_NAND << 10); + f->dev = nand; + if (nand_getbuswidth(f->dev) == 16) { + f->config[0] |= OMAP_GPMC_16BIT << 12; + } + omap_gpmc_cs_map(s, cs); +} diff --git a/hw/misc/omap_l4.c b/hw/misc/omap_l4.c new file mode 100644 index 0000000000..ac8251f736 --- /dev/null +++ b/hw/misc/omap_l4.c @@ -0,0 +1,162 @@ +/* + * TI OMAP L4 interconnect emulation. + * + * Copyright (C) 2007-2009 Nokia Corporation + * Written by Andrzej Zaborowski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ +#include "hw/hw.h" +#include "hw/arm/omap.h" + +struct omap_l4_s { + MemoryRegion *address_space; + hwaddr base; + int ta_num; + struct omap_target_agent_s ta[0]; +}; + +struct omap_l4_s *omap_l4_init(MemoryRegion *address_space, + hwaddr base, int ta_num) +{ + struct omap_l4_s *bus = g_malloc0( + sizeof(*bus) + ta_num * sizeof(*bus->ta)); + + bus->address_space = address_space; + bus->ta_num = ta_num; + bus->base = base; + + return bus; +} + +hwaddr omap_l4_region_base(struct omap_target_agent_s *ta, + int region) +{ + return ta->bus->base + ta->start[region].offset; +} + +hwaddr omap_l4_region_size(struct omap_target_agent_s *ta, + int region) +{ + return ta->start[region].size; +} + +static uint64_t omap_l4ta_read(void *opaque, hwaddr addr, + unsigned size) +{ + struct omap_target_agent_s *s = (struct omap_target_agent_s *) opaque; + + if (size != 2) { + return omap_badwidth_read16(opaque, addr); + } + + switch (addr) { + case 0x00: /* COMPONENT */ + return s->component; + + case 0x20: /* AGENT_CONTROL */ + return s->control; + + case 0x28: /* AGENT_STATUS */ + return s->status; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_l4ta_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + struct omap_target_agent_s *s = (struct omap_target_agent_s *) opaque; + + if (size != 4) { + return omap_badwidth_write32(opaque, addr, value); + } + + switch (addr) { + case 0x00: /* COMPONENT */ + case 0x28: /* AGENT_STATUS */ + OMAP_RO_REG(addr); + break; + + case 0x20: /* AGENT_CONTROL */ + s->control = value & 0x01000700; + if (value & 1) /* OCP_RESET */ + s->status &= ~1; /* REQ_TIMEOUT */ + break; + + default: + OMAP_BAD_REG(addr); + } +} + +static const MemoryRegionOps omap_l4ta_ops = { + .read = omap_l4ta_read, + .write = omap_l4ta_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +struct omap_target_agent_s *omap_l4ta_get(struct omap_l4_s *bus, + const struct omap_l4_region_s *regions, + const struct omap_l4_agent_info_s *agents, + int cs) +{ + int i; + struct omap_target_agent_s *ta = NULL; + const struct omap_l4_agent_info_s *info = NULL; + + for (i = 0; i < bus->ta_num; i ++) + if (agents[i].ta == cs) { + ta = &bus->ta[i]; + info = &agents[i]; + break; + } + if (!ta) { + fprintf(stderr, "%s: bad target agent (%i)\n", __FUNCTION__, cs); + exit(-1); + } + + ta->bus = bus; + ta->start = ®ions[info->region]; + ta->regions = info->regions; + + ta->component = ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0); + ta->status = 0x00000000; + ta->control = 0x00000200; /* XXX 01000200 for L4TAO */ + + memory_region_init_io(&ta->iomem, &omap_l4ta_ops, ta, "omap.l4ta", + omap_l4_region_size(ta, info->ta_region)); + omap_l4_attach(ta, info->ta_region, &ta->iomem); + + return ta; +} + +hwaddr omap_l4_attach(struct omap_target_agent_s *ta, + int region, MemoryRegion *mr) +{ + hwaddr base; + + if (region < 0 || region >= ta->regions) { + fprintf(stderr, "%s: bad io region (%i)\n", __FUNCTION__, region); + exit(-1); + } + + base = ta->bus->base + ta->start[region].offset; + if (mr) { + memory_region_add_subregion(ta->bus->address_space, base, mr); + } + + return base; +} diff --git a/hw/misc/omap_sdrc.c b/hw/misc/omap_sdrc.c new file mode 100644 index 0000000000..e38b571054 --- /dev/null +++ b/hw/misc/omap_sdrc.c @@ -0,0 +1,168 @@ +/* + * TI OMAP SDRAM controller emulation. + * + * Copyright (C) 2007-2008 Nokia Corporation + * Written by Andrzej Zaborowski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ +#include "hw/hw.h" +#include "hw/arm/omap.h" + +/* SDRAM Controller Subsystem */ +struct omap_sdrc_s { + MemoryRegion iomem; + uint8_t config; +}; + +void omap_sdrc_reset(struct omap_sdrc_s *s) +{ + s->config = 0x10; +} + +static uint64_t omap_sdrc_read(void *opaque, hwaddr addr, + unsigned size) +{ + struct omap_sdrc_s *s = (struct omap_sdrc_s *) opaque; + + if (size != 4) { + return omap_badwidth_read32(opaque, addr); + } + + switch (addr) { + case 0x00: /* SDRC_REVISION */ + return 0x20; + + case 0x10: /* SDRC_SYSCONFIG */ + return s->config; + + case 0x14: /* SDRC_SYSSTATUS */ + return 1; /* RESETDONE */ + + case 0x40: /* SDRC_CS_CFG */ + case 0x44: /* SDRC_SHARING */ + case 0x48: /* SDRC_ERR_ADDR */ + case 0x4c: /* SDRC_ERR_TYPE */ + case 0x60: /* SDRC_DLLA_SCTRL */ + case 0x64: /* SDRC_DLLA_STATUS */ + case 0x68: /* SDRC_DLLB_CTRL */ + case 0x6c: /* SDRC_DLLB_STATUS */ + case 0x70: /* SDRC_POWER */ + case 0x80: /* SDRC_MCFG_0 */ + case 0x84: /* SDRC_MR_0 */ + case 0x88: /* SDRC_EMR1_0 */ + case 0x8c: /* SDRC_EMR2_0 */ + case 0x90: /* SDRC_EMR3_0 */ + case 0x94: /* SDRC_DCDL1_CTRL */ + case 0x98: /* SDRC_DCDL2_CTRL */ + case 0x9c: /* SDRC_ACTIM_CTRLA_0 */ + case 0xa0: /* SDRC_ACTIM_CTRLB_0 */ + case 0xa4: /* SDRC_RFR_CTRL_0 */ + case 0xa8: /* SDRC_MANUAL_0 */ + case 0xb0: /* SDRC_MCFG_1 */ + case 0xb4: /* SDRC_MR_1 */ + case 0xb8: /* SDRC_EMR1_1 */ + case 0xbc: /* SDRC_EMR2_1 */ + case 0xc0: /* SDRC_EMR3_1 */ + case 0xc4: /* SDRC_ACTIM_CTRLA_1 */ + case 0xc8: /* SDRC_ACTIM_CTRLB_1 */ + case 0xd4: /* SDRC_RFR_CTRL_1 */ + case 0xd8: /* SDRC_MANUAL_1 */ + return 0x00; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_sdrc_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + struct omap_sdrc_s *s = (struct omap_sdrc_s *) opaque; + + if (size != 4) { + return omap_badwidth_write32(opaque, addr, value); + } + + switch (addr) { + case 0x00: /* SDRC_REVISION */ + case 0x14: /* SDRC_SYSSTATUS */ + case 0x48: /* SDRC_ERR_ADDR */ + case 0x64: /* SDRC_DLLA_STATUS */ + case 0x6c: /* SDRC_DLLB_STATUS */ + OMAP_RO_REG(addr); + return; + + case 0x10: /* SDRC_SYSCONFIG */ + if ((value >> 3) != 0x2) + fprintf(stderr, "%s: bad SDRAM idle mode %i\n", + __FUNCTION__, (unsigned)value >> 3); + if (value & 2) + omap_sdrc_reset(s); + s->config = value & 0x18; + break; + + case 0x40: /* SDRC_CS_CFG */ + case 0x44: /* SDRC_SHARING */ + case 0x4c: /* SDRC_ERR_TYPE */ + case 0x60: /* SDRC_DLLA_SCTRL */ + case 0x68: /* SDRC_DLLB_CTRL */ + case 0x70: /* SDRC_POWER */ + case 0x80: /* SDRC_MCFG_0 */ + case 0x84: /* SDRC_MR_0 */ + case 0x88: /* SDRC_EMR1_0 */ + case 0x8c: /* SDRC_EMR2_0 */ + case 0x90: /* SDRC_EMR3_0 */ + case 0x94: /* SDRC_DCDL1_CTRL */ + case 0x98: /* SDRC_DCDL2_CTRL */ + case 0x9c: /* SDRC_ACTIM_CTRLA_0 */ + case 0xa0: /* SDRC_ACTIM_CTRLB_0 */ + case 0xa4: /* SDRC_RFR_CTRL_0 */ + case 0xa8: /* SDRC_MANUAL_0 */ + case 0xb0: /* SDRC_MCFG_1 */ + case 0xb4: /* SDRC_MR_1 */ + case 0xb8: /* SDRC_EMR1_1 */ + case 0xbc: /* SDRC_EMR2_1 */ + case 0xc0: /* SDRC_EMR3_1 */ + case 0xc4: /* SDRC_ACTIM_CTRLA_1 */ + case 0xc8: /* SDRC_ACTIM_CTRLB_1 */ + case 0xd4: /* SDRC_RFR_CTRL_1 */ + case 0xd8: /* SDRC_MANUAL_1 */ + break; + + default: + OMAP_BAD_REG(addr); + return; + } +} + +static const MemoryRegionOps omap_sdrc_ops = { + .read = omap_sdrc_read, + .write = omap_sdrc_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +struct omap_sdrc_s *omap_sdrc_init(MemoryRegion *sysmem, + hwaddr base) +{ + struct omap_sdrc_s *s = (struct omap_sdrc_s *) + g_malloc0(sizeof(struct omap_sdrc_s)); + + omap_sdrc_reset(s); + + memory_region_init_io(&s->iomem, &omap_sdrc_ops, s, "omap.sdrc", 0x1000); + memory_region_add_subregion(sysmem, base, &s->iomem); + + return s; +} diff --git a/hw/misc/omap_tap.c b/hw/misc/omap_tap.c new file mode 100644 index 0000000000..99b70d5a75 --- /dev/null +++ b/hw/misc/omap_tap.c @@ -0,0 +1,116 @@ +/* + * TI OMAP TEST-Chip-level TAP emulation. + * + * Copyright (C) 2007-2008 Nokia Corporation + * Written by Andrzej Zaborowski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#include "hw/hw.h" +#include "hw/arm/omap.h" + +/* TEST-Chip-level TAP */ +static uint64_t omap_tap_read(void *opaque, hwaddr addr, + unsigned size) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + + if (size != 4) { + return omap_badwidth_read32(opaque, addr); + } + + switch (addr) { + case 0x204: /* IDCODE_reg */ + switch (s->mpu_model) { + case omap2420: + case omap2422: + case omap2423: + return 0x5b5d902f; /* ES 2.2 */ + case omap2430: + return 0x5b68a02f; /* ES 2.2 */ + case omap3430: + return 0x1b7ae02f; /* ES 2 */ + default: + hw_error("%s: Bad mpu model\n", __FUNCTION__); + } + + case 0x208: /* PRODUCTION_ID_reg for OMAP2 */ + case 0x210: /* PRODUCTION_ID_reg for OMAP3 */ + switch (s->mpu_model) { + case omap2420: + return 0x000254f0; /* POP ESHS2.1.1 in N91/93/95, ES2 in N800 */ + case omap2422: + return 0x000400f0; + case omap2423: + return 0x000800f0; + case omap2430: + return 0x000000f0; + case omap3430: + return 0x000000f0; + default: + hw_error("%s: Bad mpu model\n", __FUNCTION__); + } + + case 0x20c: + switch (s->mpu_model) { + case omap2420: + case omap2422: + case omap2423: + return 0xcafeb5d9; /* ES 2.2 */ + case omap2430: + return 0xcafeb68a; /* ES 2.2 */ + case omap3430: + return 0xcafeb7ae; /* ES 2 */ + default: + hw_error("%s: Bad mpu model\n", __FUNCTION__); + } + + case 0x218: /* DIE_ID_reg */ + return ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0); + case 0x21c: /* DIE_ID_reg */ + return 0x54 << 24; + case 0x220: /* DIE_ID_reg */ + return ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0); + case 0x224: /* DIE_ID_reg */ + return ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0); + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_tap_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + if (size != 4) { + return omap_badwidth_write32(opaque, addr, value); + } + + OMAP_BAD_REG(addr); +} + +static const MemoryRegionOps omap_tap_ops = { + .read = omap_tap_read, + .write = omap_tap_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +void omap_tap_init(struct omap_target_agent_s *ta, + struct omap_mpu_state_s *mpu) +{ + memory_region_init_io(&mpu->tap_iomem, &omap_tap_ops, mpu, "omap.tap", + omap_l4_region_size(ta, 0)); + omap_l4_attach(ta, 0, &mpu->tap_iomem); +} diff --git a/hw/misc/pc-testdev.c b/hw/misc/pc-testdev.c new file mode 100644 index 0000000000..32df175c10 --- /dev/null +++ b/hw/misc/pc-testdev.c @@ -0,0 +1,187 @@ +/* + * QEMU x86 ISA testdev + * + * Copyright (c) 2012 Avi Kivity, Gerd Hoffmann, Marcelo Tosatti + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/* + * This device is used to test KVM features specific to the x86 port, such + * as emulation, power management, interrupt routing, among others. It's meant + * to be used like: + * + * qemu-system-x86_64 -device pc-testdev -serial stdio \ + * -device isa-debug-exit,iobase=0xf4,iosize=0x4 \ + * -kernel /home/lmr/Code/virt-test.git/kvm/unittests/msr.flat + * + * Where msr.flat is one of the KVM unittests, present on a separate repo, + * git://git.kernel.org/pub/scm/virt/kvm/kvm-unit-tests.git +*/ + +#include "config-host.h" +#if defined(CONFIG_POSIX) +#include +#endif +#include "hw/hw.h" +#include "hw/qdev.h" +#include "hw/isa/isa.h" + +#define IOMEM_LEN 0x10000 + +typedef struct PCTestdev { + ISADevice parent_obj; + + MemoryRegion ioport; + MemoryRegion flush; + MemoryRegion irq; + MemoryRegion iomem; + uint32_t ioport_data; + char iomem_buf[IOMEM_LEN]; +} PCTestdev; + +#define TYPE_TESTDEV "pc-testdev" +#define TESTDEV(obj) \ + OBJECT_CHECK(PCTestdev, (obj), TYPE_TESTDEV) + +static void test_irq_line(void *opaque, hwaddr addr, uint64_t data, + unsigned len) +{ + PCTestdev *dev = opaque; + ISADevice *isa = ISA_DEVICE(dev); + + qemu_set_irq(isa_get_irq(isa, addr), !!data); +} + +static const MemoryRegionOps test_irq_ops = { + .write = test_irq_line, + .valid.min_access_size = 1, + .valid.max_access_size = 1, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void test_ioport_write(void *opaque, hwaddr addr, uint64_t data, + unsigned len) +{ + PCTestdev *dev = opaque; + dev->ioport_data = data; +} + +static uint64_t test_ioport_read(void *opaque, hwaddr addr, unsigned len) +{ + PCTestdev *dev = opaque; + return dev->ioport_data; +} + +static const MemoryRegionOps test_ioport_ops = { + .read = test_ioport_read, + .write = test_ioport_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void test_flush_page(void *opaque, hwaddr addr, uint64_t data, + unsigned len) +{ + hwaddr page = 4096; + void *a = cpu_physical_memory_map(data & ~0xffful, &page, 0); + + /* We might not be able to get the full page, only mprotect what we actually + have mapped */ +#if defined(CONFIG_POSIX) + mprotect(a, page, PROT_NONE); + mprotect(a, page, PROT_READ|PROT_WRITE); +#endif + cpu_physical_memory_unmap(a, page, 0, 0); +} + +static const MemoryRegionOps test_flush_ops = { + .write = test_flush_page, + .valid.min_access_size = 4, + .valid.max_access_size = 4, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static uint64_t test_iomem_read(void *opaque, hwaddr addr, unsigned len) +{ + PCTestdev *dev = opaque; + uint64_t ret = 0; + memcpy(&ret, &dev->iomem_buf[addr], len); + ret = le64_to_cpu(ret); + + return ret; +} + +static void test_iomem_write(void *opaque, hwaddr addr, uint64_t val, + unsigned len) +{ + PCTestdev *dev = opaque; + val = cpu_to_le64(val); + memcpy(&dev->iomem_buf[addr], &val, len); + dev->iomem_buf[addr] = val; +} + +static const MemoryRegionOps test_iomem_ops = { + .read = test_iomem_read, + .write = test_iomem_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static int init_test_device(ISADevice *isa) +{ + PCTestdev *dev = TESTDEV(isa); + MemoryRegion *mem = isa_address_space(isa); + MemoryRegion *io = isa_address_space_io(isa); + + memory_region_init_io(&dev->ioport, &test_ioport_ops, dev, + "pc-testdev-ioport", 4); + memory_region_init_io(&dev->flush, &test_flush_ops, dev, + "pc-testdev-flush-page", 4); + memory_region_init_io(&dev->irq, &test_irq_ops, dev, + "pc-testdev-irq-line", 24); + memory_region_init_io(&dev->iomem, &test_iomem_ops, dev, + "pc-testdev-iomem", IOMEM_LEN); + + memory_region_add_subregion(io, 0xe0, &dev->ioport); + memory_region_add_subregion(io, 0xe4, &dev->flush); + memory_region_add_subregion(io, 0x2000, &dev->irq); + memory_region_add_subregion(mem, 0xff000000, &dev->iomem); + + return 0; +} + +static void testdev_class_init(ObjectClass *klass, void *data) +{ + ISADeviceClass *k = ISA_DEVICE_CLASS(klass); + + k->init = init_test_device; +} + +static const TypeInfo testdev_info = { + .name = TYPE_TESTDEV, + .parent = TYPE_ISA_DEVICE, + .instance_size = sizeof(PCTestdev), + .class_init = testdev_class_init, +}; + +static void testdev_register_types(void) +{ + type_register_static(&testdev_info); +} + +type_init(testdev_register_types) diff --git a/hw/misc/pxa2xx_pcmcia.c b/hw/misc/pxa2xx_pcmcia.c new file mode 100644 index 0000000000..323d458491 --- /dev/null +++ b/hw/misc/pxa2xx_pcmcia.c @@ -0,0 +1,207 @@ +/* + * Intel XScale PXA255/270 PC Card and CompactFlash Interface. + * + * Copyright (c) 2006 Openedhand Ltd. + * Written by Andrzej Zaborowski + * + * This code is licensed under the GPLv2. + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#include "hw/hw.h" +#include "hw/pcmcia.h" +#include "hw/arm/pxa.h" + + +struct PXA2xxPCMCIAState { + PCMCIASocket slot; + PCMCIACardState *card; + MemoryRegion common_iomem; + MemoryRegion attr_iomem; + MemoryRegion iomem; + + qemu_irq irq; + qemu_irq cd_irq; +}; + +static uint64_t pxa2xx_pcmcia_common_read(void *opaque, + hwaddr offset, unsigned size) +{ + PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque; + + if (s->slot.attached) { + return s->card->common_read(s->card->state, offset); + } + + return 0; +} + +static void pxa2xx_pcmcia_common_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque; + + if (s->slot.attached) { + s->card->common_write(s->card->state, offset, value); + } +} + +static uint64_t pxa2xx_pcmcia_attr_read(void *opaque, + hwaddr offset, unsigned size) +{ + PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque; + + if (s->slot.attached) { + return s->card->attr_read(s->card->state, offset); + } + + return 0; +} + +static void pxa2xx_pcmcia_attr_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque; + + if (s->slot.attached) { + s->card->attr_write(s->card->state, offset, value); + } +} + +static uint64_t pxa2xx_pcmcia_io_read(void *opaque, + hwaddr offset, unsigned size) +{ + PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque; + + if (s->slot.attached) { + return s->card->io_read(s->card->state, offset); + } + + return 0; +} + +static void pxa2xx_pcmcia_io_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque; + + if (s->slot.attached) { + s->card->io_write(s->card->state, offset, value); + } +} + +static const MemoryRegionOps pxa2xx_pcmcia_common_ops = { + .read = pxa2xx_pcmcia_common_read, + .write = pxa2xx_pcmcia_common_write, + .endianness = DEVICE_NATIVE_ENDIAN +}; + +static const MemoryRegionOps pxa2xx_pcmcia_attr_ops = { + .read = pxa2xx_pcmcia_attr_read, + .write = pxa2xx_pcmcia_attr_write, + .endianness = DEVICE_NATIVE_ENDIAN +}; + +static const MemoryRegionOps pxa2xx_pcmcia_io_ops = { + .read = pxa2xx_pcmcia_io_read, + .write = pxa2xx_pcmcia_io_write, + .endianness = DEVICE_NATIVE_ENDIAN +}; + +static void pxa2xx_pcmcia_set_irq(void *opaque, int line, int level) +{ + PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque; + if (!s->irq) + return; + + qemu_set_irq(s->irq, level); +} + +PXA2xxPCMCIAState *pxa2xx_pcmcia_init(MemoryRegion *sysmem, + hwaddr base) +{ + PXA2xxPCMCIAState *s; + + s = (PXA2xxPCMCIAState *) + g_malloc0(sizeof(PXA2xxPCMCIAState)); + + /* Socket I/O Memory Space */ + memory_region_init_io(&s->iomem, &pxa2xx_pcmcia_io_ops, s, + "pxa2xx-pcmcia-io", 0x04000000); + memory_region_add_subregion(sysmem, base | 0x00000000, + &s->iomem); + + /* Then next 64 MB is reserved */ + + /* Socket Attribute Memory Space */ + memory_region_init_io(&s->attr_iomem, &pxa2xx_pcmcia_attr_ops, s, + "pxa2xx-pcmcia-attribute", 0x04000000); + memory_region_add_subregion(sysmem, base | 0x08000000, + &s->attr_iomem); + + /* Socket Common Memory Space */ + memory_region_init_io(&s->common_iomem, &pxa2xx_pcmcia_common_ops, s, + "pxa2xx-pcmcia-common", 0x04000000); + memory_region_add_subregion(sysmem, base | 0x0c000000, + &s->common_iomem); + + if (base == 0x30000000) + s->slot.slot_string = "PXA PC Card Socket 1"; + else + s->slot.slot_string = "PXA PC Card Socket 0"; + s->slot.irq = qemu_allocate_irqs(pxa2xx_pcmcia_set_irq, s, 1)[0]; + pcmcia_socket_register(&s->slot); + + return s; +} + +/* Insert a new card into a slot */ +int pxa2xx_pcmcia_attach(void *opaque, PCMCIACardState *card) +{ + PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque; + if (s->slot.attached) + return -EEXIST; + + if (s->cd_irq) { + qemu_irq_raise(s->cd_irq); + } + + s->card = card; + + s->slot.attached = 1; + s->card->slot = &s->slot; + s->card->attach(s->card->state); + + return 0; +} + +/* Eject card from the slot */ +int pxa2xx_pcmcia_dettach(void *opaque) +{ + PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque; + if (!s->slot.attached) + return -ENOENT; + + s->card->detach(s->card->state); + s->card->slot = NULL; + s->card = NULL; + + s->slot.attached = 0; + + if (s->irq) + qemu_irq_lower(s->irq); + if (s->cd_irq) + qemu_irq_lower(s->cd_irq); + + return 0; +} + +/* Who to notify on card events */ +void pxa2xx_pcmcia_set_irq_cb(void *opaque, qemu_irq irq, qemu_irq cd_irq) +{ + PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque; + s->irq = irq; + s->cd_irq = cd_irq; +} diff --git a/hw/misc/sga.c b/hw/misc/sga.c new file mode 100644 index 0000000000..5cf4b86c4f --- /dev/null +++ b/hw/misc/sga.c @@ -0,0 +1,63 @@ +/* + * QEMU dummy ISA device for loading sgabios option rom. + * + * Copyright (c) 2011 Glauber Costa, Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * sgabios code originally available at code.google.com/p/sgabios + * + */ +#include "hw/pci/pci.h" +#include "hw/i386/pc.h" +#include "hw/loader.h" +#include "sysemu/sysemu.h" + +#define SGABIOS_FILENAME "sgabios.bin" + +typedef struct ISAGAState { + ISADevice dev; +} ISASGAState; + +static int sga_initfn(ISADevice *dev) +{ + rom_add_vga(SGABIOS_FILENAME); + return 0; +} +static void sga_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ISADeviceClass *ic = ISA_DEVICE_CLASS(klass); + ic->init = sga_initfn; + dc->desc = "Serial Graphics Adapter"; +} + +static const TypeInfo sga_info = { + .name = "sga", + .parent = TYPE_ISA_DEVICE, + .instance_size = sizeof(ISASGAState), + .class_init = sga_class_initfn, +}; + +static void sga_register_types(void) +{ + type_register_static(&sga_info); +} + +type_init(sga_register_types) diff --git a/hw/misc/slavio_misc.c b/hw/misc/slavio_misc.c new file mode 100644 index 0000000000..a7a9368864 --- /dev/null +++ b/hw/misc/slavio_misc.c @@ -0,0 +1,508 @@ +/* + * QEMU Sparc SLAVIO aux io port emulation + * + * Copyright (c) 2005 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "sysemu/sysemu.h" +#include "hw/sysbus.h" +#include "trace.h" + +/* + * This is the auxio port, chip control and system control part of + * chip STP2001 (Slave I/O), also produced as NCR89C105. See + * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt + * + * This also includes the PMC CPU idle controller. + */ + +typedef struct MiscState { + SysBusDevice busdev; + MemoryRegion cfg_iomem; + MemoryRegion diag_iomem; + MemoryRegion mdm_iomem; + MemoryRegion led_iomem; + MemoryRegion sysctrl_iomem; + MemoryRegion aux1_iomem; + MemoryRegion aux2_iomem; + qemu_irq irq; + qemu_irq fdc_tc; + uint32_t dummy; + uint8_t config; + uint8_t aux1, aux2; + uint8_t diag, mctrl; + uint8_t sysctrl; + uint16_t leds; +} MiscState; + +typedef struct APCState { + SysBusDevice busdev; + MemoryRegion iomem; + qemu_irq cpu_halt; +} APCState; + +#define MISC_SIZE 1 +#define SYSCTRL_SIZE 4 + +#define AUX1_TC 0x02 + +#define AUX2_PWROFF 0x01 +#define AUX2_PWRINTCLR 0x02 +#define AUX2_PWRFAIL 0x20 + +#define CFG_PWRINTEN 0x08 + +#define SYS_RESET 0x01 +#define SYS_RESETSTAT 0x02 + +static void slavio_misc_update_irq(void *opaque) +{ + MiscState *s = opaque; + + if ((s->aux2 & AUX2_PWRFAIL) && (s->config & CFG_PWRINTEN)) { + trace_slavio_misc_update_irq_raise(); + qemu_irq_raise(s->irq); + } else { + trace_slavio_misc_update_irq_lower(); + qemu_irq_lower(s->irq); + } +} + +static void slavio_misc_reset(DeviceState *d) +{ + MiscState *s = container_of(d, MiscState, busdev.qdev); + + // Diagnostic and system control registers not cleared in reset + s->config = s->aux1 = s->aux2 = s->mctrl = 0; +} + +static void slavio_set_power_fail(void *opaque, int irq, int power_failing) +{ + MiscState *s = opaque; + + trace_slavio_set_power_fail(power_failing, s->config); + if (power_failing && (s->config & CFG_PWRINTEN)) { + s->aux2 |= AUX2_PWRFAIL; + } else { + s->aux2 &= ~AUX2_PWRFAIL; + } + slavio_misc_update_irq(s); +} + +static void slavio_cfg_mem_writeb(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + MiscState *s = opaque; + + trace_slavio_cfg_mem_writeb(val & 0xff); + s->config = val & 0xff; + slavio_misc_update_irq(s); +} + +static uint64_t slavio_cfg_mem_readb(void *opaque, hwaddr addr, + unsigned size) +{ + MiscState *s = opaque; + uint32_t ret = 0; + + ret = s->config; + trace_slavio_cfg_mem_readb(ret); + return ret; +} + +static const MemoryRegionOps slavio_cfg_mem_ops = { + .read = slavio_cfg_mem_readb, + .write = slavio_cfg_mem_writeb, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 1, + }, +}; + +static void slavio_diag_mem_writeb(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + MiscState *s = opaque; + + trace_slavio_diag_mem_writeb(val & 0xff); + s->diag = val & 0xff; +} + +static uint64_t slavio_diag_mem_readb(void *opaque, hwaddr addr, + unsigned size) +{ + MiscState *s = opaque; + uint32_t ret = 0; + + ret = s->diag; + trace_slavio_diag_mem_readb(ret); + return ret; +} + +static const MemoryRegionOps slavio_diag_mem_ops = { + .read = slavio_diag_mem_readb, + .write = slavio_diag_mem_writeb, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 1, + }, +}; + +static void slavio_mdm_mem_writeb(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + MiscState *s = opaque; + + trace_slavio_mdm_mem_writeb(val & 0xff); + s->mctrl = val & 0xff; +} + +static uint64_t slavio_mdm_mem_readb(void *opaque, hwaddr addr, + unsigned size) +{ + MiscState *s = opaque; + uint32_t ret = 0; + + ret = s->mctrl; + trace_slavio_mdm_mem_readb(ret); + return ret; +} + +static const MemoryRegionOps slavio_mdm_mem_ops = { + .read = slavio_mdm_mem_readb, + .write = slavio_mdm_mem_writeb, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 1, + }, +}; + +static void slavio_aux1_mem_writeb(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + MiscState *s = opaque; + + trace_slavio_aux1_mem_writeb(val & 0xff); + if (val & AUX1_TC) { + // Send a pulse to floppy terminal count line + if (s->fdc_tc) { + qemu_irq_raise(s->fdc_tc); + qemu_irq_lower(s->fdc_tc); + } + val &= ~AUX1_TC; + } + s->aux1 = val & 0xff; +} + +static uint64_t slavio_aux1_mem_readb(void *opaque, hwaddr addr, + unsigned size) +{ + MiscState *s = opaque; + uint32_t ret = 0; + + ret = s->aux1; + trace_slavio_aux1_mem_readb(ret); + return ret; +} + +static const MemoryRegionOps slavio_aux1_mem_ops = { + .read = slavio_aux1_mem_readb, + .write = slavio_aux1_mem_writeb, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 1, + }, +}; + +static void slavio_aux2_mem_writeb(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + MiscState *s = opaque; + + val &= AUX2_PWRINTCLR | AUX2_PWROFF; + trace_slavio_aux2_mem_writeb(val & 0xff); + val |= s->aux2 & AUX2_PWRFAIL; + if (val & AUX2_PWRINTCLR) // Clear Power Fail int + val &= AUX2_PWROFF; + s->aux2 = val; + if (val & AUX2_PWROFF) + qemu_system_shutdown_request(); + slavio_misc_update_irq(s); +} + +static uint64_t slavio_aux2_mem_readb(void *opaque, hwaddr addr, + unsigned size) +{ + MiscState *s = opaque; + uint32_t ret = 0; + + ret = s->aux2; + trace_slavio_aux2_mem_readb(ret); + return ret; +} + +static const MemoryRegionOps slavio_aux2_mem_ops = { + .read = slavio_aux2_mem_readb, + .write = slavio_aux2_mem_writeb, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 1, + }, +}; + +static void apc_mem_writeb(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + APCState *s = opaque; + + trace_apc_mem_writeb(val & 0xff); + qemu_irq_raise(s->cpu_halt); +} + +static uint64_t apc_mem_readb(void *opaque, hwaddr addr, + unsigned size) +{ + uint32_t ret = 0; + + trace_apc_mem_readb(ret); + return ret; +} + +static const MemoryRegionOps apc_mem_ops = { + .read = apc_mem_readb, + .write = apc_mem_writeb, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 1, + } +}; + +static uint64_t slavio_sysctrl_mem_readl(void *opaque, hwaddr addr, + unsigned size) +{ + MiscState *s = opaque; + uint32_t ret = 0; + + switch (addr) { + case 0: + ret = s->sysctrl; + break; + default: + break; + } + trace_slavio_sysctrl_mem_readl(ret); + return ret; +} + +static void slavio_sysctrl_mem_writel(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + MiscState *s = opaque; + + trace_slavio_sysctrl_mem_writel(val); + switch (addr) { + case 0: + if (val & SYS_RESET) { + s->sysctrl = SYS_RESETSTAT; + qemu_system_reset_request(); + } + break; + default: + break; + } +} + +static const MemoryRegionOps slavio_sysctrl_mem_ops = { + .read = slavio_sysctrl_mem_readl, + .write = slavio_sysctrl_mem_writel, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; + +static uint64_t slavio_led_mem_readw(void *opaque, hwaddr addr, + unsigned size) +{ + MiscState *s = opaque; + uint32_t ret = 0; + + switch (addr) { + case 0: + ret = s->leds; + break; + default: + break; + } + trace_slavio_led_mem_readw(ret); + return ret; +} + +static void slavio_led_mem_writew(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + MiscState *s = opaque; + + trace_slavio_led_mem_readw(val & 0xffff); + switch (addr) { + case 0: + s->leds = val; + break; + default: + break; + } +} + +static const MemoryRegionOps slavio_led_mem_ops = { + .read = slavio_led_mem_readw, + .write = slavio_led_mem_writew, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 2, + .max_access_size = 2, + }, +}; + +static const VMStateDescription vmstate_misc = { + .name ="slavio_misc", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_UINT32(dummy, MiscState), + VMSTATE_UINT8(config, MiscState), + VMSTATE_UINT8(aux1, MiscState), + VMSTATE_UINT8(aux2, MiscState), + VMSTATE_UINT8(diag, MiscState), + VMSTATE_UINT8(mctrl, MiscState), + VMSTATE_UINT8(sysctrl, MiscState), + VMSTATE_END_OF_LIST() + } +}; + +static int apc_init1(SysBusDevice *dev) +{ + APCState *s = FROM_SYSBUS(APCState, dev); + + sysbus_init_irq(dev, &s->cpu_halt); + + /* Power management (APC) XXX: not a Slavio device */ + memory_region_init_io(&s->iomem, &apc_mem_ops, s, + "apc", MISC_SIZE); + sysbus_init_mmio(dev, &s->iomem); + return 0; +} + +static int slavio_misc_init1(SysBusDevice *dev) +{ + MiscState *s = FROM_SYSBUS(MiscState, dev); + + sysbus_init_irq(dev, &s->irq); + sysbus_init_irq(dev, &s->fdc_tc); + + /* 8 bit registers */ + /* Slavio control */ + memory_region_init_io(&s->cfg_iomem, &slavio_cfg_mem_ops, s, + "configuration", MISC_SIZE); + sysbus_init_mmio(dev, &s->cfg_iomem); + + /* Diagnostics */ + memory_region_init_io(&s->diag_iomem, &slavio_diag_mem_ops, s, + "diagnostic", MISC_SIZE); + sysbus_init_mmio(dev, &s->diag_iomem); + + /* Modem control */ + memory_region_init_io(&s->mdm_iomem, &slavio_mdm_mem_ops, s, + "modem", MISC_SIZE); + sysbus_init_mmio(dev, &s->mdm_iomem); + + /* 16 bit registers */ + /* ss600mp diag LEDs */ + memory_region_init_io(&s->led_iomem, &slavio_led_mem_ops, s, + "leds", MISC_SIZE); + sysbus_init_mmio(dev, &s->led_iomem); + + /* 32 bit registers */ + /* System control */ + memory_region_init_io(&s->sysctrl_iomem, &slavio_sysctrl_mem_ops, s, + "system-control", MISC_SIZE); + sysbus_init_mmio(dev, &s->sysctrl_iomem); + + /* AUX 1 (Misc System Functions) */ + memory_region_init_io(&s->aux1_iomem, &slavio_aux1_mem_ops, s, + "misc-system-functions", MISC_SIZE); + sysbus_init_mmio(dev, &s->aux1_iomem); + + /* AUX 2 (Software Powerdown Control) */ + memory_region_init_io(&s->aux2_iomem, &slavio_aux2_mem_ops, s, + "software-powerdown-control", MISC_SIZE); + sysbus_init_mmio(dev, &s->aux2_iomem); + + qdev_init_gpio_in(&dev->qdev, slavio_set_power_fail, 1); + + return 0; +} + +static void slavio_misc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = slavio_misc_init1; + dc->reset = slavio_misc_reset; + dc->vmsd = &vmstate_misc; +} + +static const TypeInfo slavio_misc_info = { + .name = "slavio_misc", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(MiscState), + .class_init = slavio_misc_class_init, +}; + +static void apc_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = apc_init1; +} + +static const TypeInfo apc_info = { + .name = "apc", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(MiscState), + .class_init = apc_class_init, +}; + +static void slavio_misc_register_types(void) +{ + type_register_static(&slavio_misc_info); + type_register_static(&apc_info); +} + +type_init(slavio_misc_register_types) diff --git a/hw/misc/vmport.c b/hw/misc/vmport.c new file mode 100644 index 0000000000..0d07ea1fc5 --- /dev/null +++ b/hw/misc/vmport.c @@ -0,0 +1,170 @@ +/* + * QEMU VMPort emulation + * + * Copyright (C) 2007 HervĂ© Poussineau + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "hw/hw.h" +#include "hw/isa/isa.h" +#include "hw/i386/pc.h" +#include "sysemu/kvm.h" +#include "hw/qdev.h" + +//#define VMPORT_DEBUG + +#define VMPORT_CMD_GETVERSION 0x0a +#define VMPORT_CMD_GETRAMSIZE 0x14 + +#define VMPORT_ENTRIES 0x2c +#define VMPORT_MAGIC 0x564D5868 + +typedef struct _VMPortState +{ + ISADevice dev; + MemoryRegion io; + IOPortReadFunc *func[VMPORT_ENTRIES]; + void *opaque[VMPORT_ENTRIES]; +} VMPortState; + +static VMPortState *port_state; + +void vmport_register(unsigned char command, IOPortReadFunc *func, void *opaque) +{ + if (command >= VMPORT_ENTRIES) + return; + + port_state->func[command] = func; + port_state->opaque[command] = opaque; +} + +static uint64_t vmport_ioport_read(void *opaque, hwaddr addr, + unsigned size) +{ + VMPortState *s = opaque; + CPUX86State *env = cpu_single_env; + unsigned char command; + uint32_t eax; + + cpu_synchronize_state(env); + + eax = env->regs[R_EAX]; + if (eax != VMPORT_MAGIC) + return eax; + + command = env->regs[R_ECX]; + if (command >= VMPORT_ENTRIES) + return eax; + if (!s->func[command]) + { +#ifdef VMPORT_DEBUG + fprintf(stderr, "vmport: unknown command %x\n", command); +#endif + return eax; + } + + return s->func[command](s->opaque[command], addr); +} + +static void vmport_ioport_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + CPUX86State *env = cpu_single_env; + + env->regs[R_EAX] = vmport_ioport_read(opaque, addr, 4); +} + +static uint32_t vmport_cmd_get_version(void *opaque, uint32_t addr) +{ + CPUX86State *env = cpu_single_env; + env->regs[R_EBX] = VMPORT_MAGIC; + return 6; +} + +static uint32_t vmport_cmd_ram_size(void *opaque, uint32_t addr) +{ + CPUX86State *env = cpu_single_env; + env->regs[R_EBX] = 0x1177; + return ram_size; +} + +/* vmmouse helpers */ +void vmmouse_get_data(uint32_t *data) +{ + CPUX86State *env = cpu_single_env; + + data[0] = env->regs[R_EAX]; data[1] = env->regs[R_EBX]; + data[2] = env->regs[R_ECX]; data[3] = env->regs[R_EDX]; + data[4] = env->regs[R_ESI]; data[5] = env->regs[R_EDI]; +} + +void vmmouse_set_data(const uint32_t *data) +{ + CPUX86State *env = cpu_single_env; + + env->regs[R_EAX] = data[0]; env->regs[R_EBX] = data[1]; + env->regs[R_ECX] = data[2]; env->regs[R_EDX] = data[3]; + env->regs[R_ESI] = data[4]; env->regs[R_EDI] = data[5]; +} + +static const MemoryRegionOps vmport_ops = { + .read = vmport_ioport_read, + .write = vmport_ioport_write, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static int vmport_initfn(ISADevice *dev) +{ + VMPortState *s = DO_UPCAST(VMPortState, dev, dev); + + memory_region_init_io(&s->io, &vmport_ops, s, "vmport", 1); + isa_register_ioport(dev, &s->io, 0x5658); + + port_state = s; + /* Register some generic port commands */ + vmport_register(VMPORT_CMD_GETVERSION, vmport_cmd_get_version, NULL); + vmport_register(VMPORT_CMD_GETRAMSIZE, vmport_cmd_ram_size, NULL); + return 0; +} + +static void vmport_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ISADeviceClass *ic = ISA_DEVICE_CLASS(klass); + ic->init = vmport_initfn; + dc->no_user = 1; +} + +static const TypeInfo vmport_info = { + .name = "vmport", + .parent = TYPE_ISA_DEVICE, + .instance_size = sizeof(VMPortState), + .class_init = vmport_class_initfn, +}; + +static void vmport_register_types(void) +{ + type_register_static(&vmport_info); +} + +type_init(vmport_register_types) diff --git a/hw/misc/zynq_slcr.c b/hw/misc/zynq_slcr.c new file mode 100644 index 0000000000..8418327261 --- /dev/null +++ b/hw/misc/zynq_slcr.c @@ -0,0 +1,536 @@ +/* + * Status and system control registers for Xilinx Zynq Platform + * + * Copyright (c) 2011 Michal Simek + * Copyright (c) 2012 PetaLogix Pty Ltd. + * Based on hw/arm_sysctl.c, written by Paul Brook + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#include "hw/hw.h" +#include "qemu/timer.h" +#include "hw/sysbus.h" +#include "sysemu/sysemu.h" + +#ifdef ZYNQ_ARM_SLCR_ERR_DEBUG +#define DB_PRINT(...) do { \ + fprintf(stderr, ": %s: ", __func__); \ + fprintf(stderr, ## __VA_ARGS__); \ + } while (0); +#else + #define DB_PRINT(...) +#endif + +#define XILINX_LOCK_KEY 0x767b +#define XILINX_UNLOCK_KEY 0xdf0d + +typedef enum { + ARM_PLL_CTRL, + DDR_PLL_CTRL, + IO_PLL_CTRL, + PLL_STATUS, + ARM_PPL_CFG, + DDR_PLL_CFG, + IO_PLL_CFG, + PLL_BG_CTRL, + PLL_MAX +} PLLValues; + +typedef enum { + ARM_CLK_CTRL, + DDR_CLK_CTRL, + DCI_CLK_CTRL, + APER_CLK_CTRL, + USB0_CLK_CTRL, + USB1_CLK_CTRL, + GEM0_RCLK_CTRL, + GEM1_RCLK_CTRL, + GEM0_CLK_CTRL, + GEM1_CLK_CTRL, + SMC_CLK_CTRL, + LQSPI_CLK_CTRL, + SDIO_CLK_CTRL, + UART_CLK_CTRL, + SPI_CLK_CTRL, + CAN_CLK_CTRL, + CAN_MIOCLK_CTRL, + DBG_CLK_CTRL, + PCAP_CLK_CTRL, + TOPSW_CLK_CTRL, + CLK_MAX +} ClkValues; + +typedef enum { + CLK_CTRL, + THR_CTRL, + THR_CNT, + THR_STA, + FPGA_MAX +} FPGAValues; + +typedef enum { + SYNC_CTRL, + SYNC_STATUS, + BANDGAP_TRIP, + CC_TEST, + PLL_PREDIVISOR, + CLK_621_TRUE, + PICTURE_DBG, + PICTURE_DBG_UCNT, + PICTURE_DBG_LCNT, + MISC_MAX +} MiscValues; + +typedef enum { + PSS, + DDDR, + DMAC = 3, + USB, + GEM, + SDIO, + SPI, + CAN, + I2C, + UART, + GPIO, + LQSPI, + SMC, + OCM, + DEVCI, + FPGA, + A9_CPU, + RS_AWDT, + RST_REASON, + RST_REASON_CLR, + REBOOT_STATUS, + BOOT_MODE, + RESET_MAX +} ResetValues; + +typedef struct { + SysBusDevice busdev; + MemoryRegion iomem; + + union { + struct { + uint16_t scl; + uint16_t lockval; + uint32_t pll[PLL_MAX]; /* 0x100 - 0x11C */ + uint32_t clk[CLK_MAX]; /* 0x120 - 0x16C */ + uint32_t fpga[4][FPGA_MAX]; /* 0x170 - 0x1AC */ + uint32_t misc[MISC_MAX]; /* 0x1B0 - 0x1D8 */ + uint32_t reset[RESET_MAX]; /* 0x200 - 0x25C */ + uint32_t apu_ctrl; /* 0x300 */ + uint32_t wdt_clk_sel; /* 0x304 */ + uint32_t tz_ocm[3]; /* 0x400 - 0x408 */ + uint32_t tz_ddr; /* 0x430 */ + uint32_t tz_dma[3]; /* 0x440 - 0x448 */ + uint32_t tz_misc[3]; /* 0x450 - 0x458 */ + uint32_t tz_fpga[2]; /* 0x484 - 0x488 */ + uint32_t dbg_ctrl; /* 0x500 */ + uint32_t pss_idcode; /* 0x530 */ + uint32_t ddr[8]; /* 0x600 - 0x620 - 0x604-missing */ + uint32_t mio[54]; /* 0x700 - 0x7D4 */ + uint32_t mio_func[4]; /* 0x800 - 0x810 */ + uint32_t sd[2]; /* 0x830 - 0x834 */ + uint32_t lvl_shftr_en; /* 0x900 */ + uint32_t ocm_cfg; /* 0x910 */ + uint32_t cpu_ram[8]; /* 0xA00 - 0xA1C */ + uint32_t iou[7]; /* 0xA30 - 0xA48 */ + uint32_t dmac_ram; /* 0xA50 */ + uint32_t afi[4][3]; /* 0xA60 - 0xA8C */ + uint32_t ocm[3]; /* 0xA90 - 0xA98 */ + uint32_t devci_ram; /* 0xAA0 */ + uint32_t csg_ram; /* 0xAB0 */ + uint32_t gpiob[12]; /* 0xB00 - 0xB2C */ + uint32_t ddriob[14]; /* 0xB40 - 0xB74 */ + }; + uint8_t data[0x1000]; + }; +} ZynqSLCRState; + +static void zynq_slcr_reset(DeviceState *d) +{ + int i; + ZynqSLCRState *s = + FROM_SYSBUS(ZynqSLCRState, SYS_BUS_DEVICE(d)); + + DB_PRINT("RESET\n"); + + s->lockval = 1; + /* 0x100 - 0x11C */ + s->pll[ARM_PLL_CTRL] = 0x0001A008; + s->pll[DDR_PLL_CTRL] = 0x0001A008; + s->pll[IO_PLL_CTRL] = 0x0001A008; + s->pll[PLL_STATUS] = 0x0000003F; + s->pll[ARM_PPL_CFG] = 0x00014000; + s->pll[DDR_PLL_CFG] = 0x00014000; + s->pll[IO_PLL_CFG] = 0x00014000; + + /* 0x120 - 0x16C */ + s->clk[ARM_CLK_CTRL] = 0x1F000400; + s->clk[DDR_CLK_CTRL] = 0x18400003; + s->clk[DCI_CLK_CTRL] = 0x01E03201; + s->clk[APER_CLK_CTRL] = 0x01FFCCCD; + s->clk[USB0_CLK_CTRL] = s->clk[USB1_CLK_CTRL] = 0x00101941; + s->clk[GEM0_RCLK_CTRL] = s->clk[GEM1_RCLK_CTRL] = 0x00000001; + s->clk[GEM0_CLK_CTRL] = s->clk[GEM1_CLK_CTRL] = 0x00003C01; + s->clk[SMC_CLK_CTRL] = 0x00003C01; + s->clk[LQSPI_CLK_CTRL] = 0x00002821; + s->clk[SDIO_CLK_CTRL] = 0x00001E03; + s->clk[UART_CLK_CTRL] = 0x00003F03; + s->clk[SPI_CLK_CTRL] = 0x00003F03; + s->clk[CAN_CLK_CTRL] = 0x00501903; + s->clk[DBG_CLK_CTRL] = 0x00000F03; + s->clk[PCAP_CLK_CTRL] = 0x00000F01; + + /* 0x170 - 0x1AC */ + s->fpga[0][CLK_CTRL] = s->fpga[1][CLK_CTRL] = s->fpga[2][CLK_CTRL] = + s->fpga[3][CLK_CTRL] = 0x00101800; + s->fpga[0][THR_STA] = s->fpga[1][THR_STA] = s->fpga[2][THR_STA] = + s->fpga[3][THR_STA] = 0x00010000; + + /* 0x1B0 - 0x1D8 */ + s->misc[BANDGAP_TRIP] = 0x0000001F; + s->misc[PLL_PREDIVISOR] = 0x00000001; + s->misc[CLK_621_TRUE] = 0x00000001; + + /* 0x200 - 0x25C */ + s->reset[FPGA] = 0x01F33F0F; + s->reset[RST_REASON] = 0x00000040; + + /* 0x700 - 0x7D4 */ + for (i = 0; i < 54; i++) { + s->mio[i] = 0x00001601; + } + for (i = 2; i <= 8; i++) { + s->mio[i] = 0x00000601; + } + + /* MIO_MST_TRI0, MIO_MST_TRI1 */ + s->mio_func[2] = s->mio_func[3] = 0xFFFFFFFF; + + s->cpu_ram[0] = s->cpu_ram[1] = s->cpu_ram[3] = + s->cpu_ram[4] = s->cpu_ram[7] = 0x00010101; + s->cpu_ram[2] = s->cpu_ram[5] = 0x01010101; + s->cpu_ram[6] = 0x00000001; + + s->iou[0] = s->iou[1] = s->iou[2] = s->iou[3] = 0x09090909; + s->iou[4] = s->iou[5] = 0x00090909; + s->iou[6] = 0x00000909; + + s->dmac_ram = 0x00000009; + + s->afi[0][0] = s->afi[0][1] = 0x09090909; + s->afi[1][0] = s->afi[1][1] = 0x09090909; + s->afi[2][0] = s->afi[2][1] = 0x09090909; + s->afi[3][0] = s->afi[3][1] = 0x09090909; + s->afi[0][2] = s->afi[1][2] = s->afi[2][2] = s->afi[3][2] = 0x00000909; + + s->ocm[0] = 0x01010101; + s->ocm[1] = s->ocm[2] = 0x09090909; + + s->devci_ram = 0x00000909; + s->csg_ram = 0x00000001; + + s->ddriob[0] = s->ddriob[1] = s->ddriob[2] = s->ddriob[3] = 0x00000e00; + s->ddriob[4] = s->ddriob[5] = s->ddriob[6] = 0x00000e00; + s->ddriob[12] = 0x00000021; +} + +static inline uint32_t zynq_slcr_read_imp(void *opaque, + hwaddr offset) +{ + ZynqSLCRState *s = (ZynqSLCRState *)opaque; + + switch (offset) { + case 0x0: /* SCL */ + return s->scl; + case 0x4: /* LOCK */ + case 0x8: /* UNLOCK */ + DB_PRINT("Reading SCLR_LOCK/UNLOCK is not enabled\n"); + return 0; + case 0x0C: /* LOCKSTA */ + return s->lockval; + case 0x100 ... 0x11C: + return s->pll[(offset - 0x100) / 4]; + case 0x120 ... 0x16C: + return s->clk[(offset - 0x120) / 4]; + case 0x170 ... 0x1AC: + return s->fpga[0][(offset - 0x170) / 4]; + case 0x1B0 ... 0x1D8: + return s->misc[(offset - 0x1B0) / 4]; + case 0x200 ... 0x258: + return s->reset[(offset - 0x200) / 4]; + case 0x25c: + return 1; + case 0x300: + return s->apu_ctrl; + case 0x304: + return s->wdt_clk_sel; + case 0x400 ... 0x408: + return s->tz_ocm[(offset - 0x400) / 4]; + case 0x430: + return s->tz_ddr; + case 0x440 ... 0x448: + return s->tz_dma[(offset - 0x440) / 4]; + case 0x450 ... 0x458: + return s->tz_misc[(offset - 0x450) / 4]; + case 0x484 ... 0x488: + return s->tz_fpga[(offset - 0x484) / 4]; + case 0x500: + return s->dbg_ctrl; + case 0x530: + return s->pss_idcode; + case 0x600 ... 0x620: + if (offset == 0x604) { + goto bad_reg; + } + return s->ddr[(offset - 0x600) / 4]; + case 0x700 ... 0x7D4: + return s->mio[(offset - 0x700) / 4]; + case 0x800 ... 0x810: + return s->mio_func[(offset - 0x800) / 4]; + case 0x830 ... 0x834: + return s->sd[(offset - 0x830) / 4]; + case 0x900: + return s->lvl_shftr_en; + case 0x910: + return s->ocm_cfg; + case 0xA00 ... 0xA1C: + return s->cpu_ram[(offset - 0xA00) / 4]; + case 0xA30 ... 0xA48: + return s->iou[(offset - 0xA30) / 4]; + case 0xA50: + return s->dmac_ram; + case 0xA60 ... 0xA8C: + return s->afi[0][(offset - 0xA60) / 4]; + case 0xA90 ... 0xA98: + return s->ocm[(offset - 0xA90) / 4]; + case 0xAA0: + return s->devci_ram; + case 0xAB0: + return s->csg_ram; + case 0xB00 ... 0xB2C: + return s->gpiob[(offset - 0xB00) / 4]; + case 0xB40 ... 0xB74: + return s->ddriob[(offset - 0xB40) / 4]; + default: + bad_reg: + DB_PRINT("Bad register offset 0x%x\n", (int)offset); + return 0; + } +} + +static uint64_t zynq_slcr_read(void *opaque, hwaddr offset, + unsigned size) +{ + uint32_t ret = zynq_slcr_read_imp(opaque, offset); + + DB_PRINT("addr: %08x data: %08x\n", (unsigned)offset, (unsigned)ret); + return ret; +} + +static void zynq_slcr_write(void *opaque, hwaddr offset, + uint64_t val, unsigned size) +{ + ZynqSLCRState *s = (ZynqSLCRState *)opaque; + + DB_PRINT("offset: %08x data: %08x\n", (unsigned)offset, (unsigned)val); + + switch (offset) { + case 0x00: /* SCL */ + s->scl = val & 0x1; + return; + case 0x4: /* SLCR_LOCK */ + if ((val & 0xFFFF) == XILINX_LOCK_KEY) { + DB_PRINT("XILINX LOCK 0xF8000000 + 0x%x <= 0x%x\n", (int)offset, + (unsigned)val & 0xFFFF); + s->lockval = 1; + } else { + DB_PRINT("WRONG XILINX LOCK KEY 0xF8000000 + 0x%x <= 0x%x\n", + (int)offset, (unsigned)val & 0xFFFF); + } + return; + case 0x8: /* SLCR_UNLOCK */ + if ((val & 0xFFFF) == XILINX_UNLOCK_KEY) { + DB_PRINT("XILINX UNLOCK 0xF8000000 + 0x%x <= 0x%x\n", (int)offset, + (unsigned)val & 0xFFFF); + s->lockval = 0; + } else { + DB_PRINT("WRONG XILINX UNLOCK KEY 0xF8000000 + 0x%x <= 0x%x\n", + (int)offset, (unsigned)val & 0xFFFF); + } + return; + case 0xc: /* LOCKSTA */ + DB_PRINT("Writing SCLR_LOCKSTA is not enabled\n"); + return; + } + + if (!s->lockval) { + switch (offset) { + case 0x100 ... 0x11C: + if (offset == 0x10C) { + goto bad_reg; + } + s->pll[(offset - 0x100) / 4] = val; + break; + case 0x120 ... 0x16C: + s->clk[(offset - 0x120) / 4] = val; + break; + case 0x170 ... 0x1AC: + s->fpga[0][(offset - 0x170) / 4] = val; + break; + case 0x1B0 ... 0x1D8: + s->misc[(offset - 0x1B0) / 4] = val; + break; + case 0x200 ... 0x25C: + if (offset == 0x250) { + goto bad_reg; + } + s->reset[(offset - 0x200) / 4] = val; + break; + case 0x300: + s->apu_ctrl = val; + break; + case 0x304: + s->wdt_clk_sel = val; + break; + case 0x400 ... 0x408: + s->tz_ocm[(offset - 0x400) / 4] = val; + break; + case 0x430: + s->tz_ddr = val; + break; + case 0x440 ... 0x448: + s->tz_dma[(offset - 0x440) / 4] = val; + break; + case 0x450 ... 0x458: + s->tz_misc[(offset - 0x450) / 4] = val; + break; + case 0x484 ... 0x488: + s->tz_fpga[(offset - 0x484) / 4] = val; + break; + case 0x500: + s->dbg_ctrl = val; + break; + case 0x530: + s->pss_idcode = val; + break; + case 0x600 ... 0x620: + if (offset == 0x604) { + goto bad_reg; + } + s->ddr[(offset - 0x600) / 4] = val; + break; + case 0x700 ... 0x7D4: + s->mio[(offset - 0x700) / 4] = val; + break; + case 0x800 ... 0x810: + s->mio_func[(offset - 0x800) / 4] = val; + break; + case 0x830 ... 0x834: + s->sd[(offset - 0x830) / 4] = val; + break; + case 0x900: + s->lvl_shftr_en = val; + break; + case 0x910: + break; + case 0xA00 ... 0xA1C: + s->cpu_ram[(offset - 0xA00) / 4] = val; + break; + case 0xA30 ... 0xA48: + s->iou[(offset - 0xA30) / 4] = val; + break; + case 0xA50: + s->dmac_ram = val; + break; + case 0xA60 ... 0xA8C: + s->afi[0][(offset - 0xA60) / 4] = val; + break; + case 0xA90: + s->ocm[0] = val; + break; + case 0xAA0: + s->devci_ram = val; + break; + case 0xAB0: + s->csg_ram = val; + break; + case 0xB00 ... 0xB2C: + if (offset == 0xB20 || offset == 0xB2C) { + goto bad_reg; + } + s->gpiob[(offset - 0xB00) / 4] = val; + break; + case 0xB40 ... 0xB74: + s->ddriob[(offset - 0xB40) / 4] = val; + break; + default: + bad_reg: + DB_PRINT("Bad register write %x <= %08x\n", (int)offset, + (unsigned)val); + } + } else { + DB_PRINT("SCLR registers are locked. Unlock them first\n"); + } +} + +static const MemoryRegionOps slcr_ops = { + .read = zynq_slcr_read, + .write = zynq_slcr_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static int zynq_slcr_init(SysBusDevice *dev) +{ + ZynqSLCRState *s = FROM_SYSBUS(ZynqSLCRState, dev); + + memory_region_init_io(&s->iomem, &slcr_ops, s, "slcr", 0x1000); + sysbus_init_mmio(dev, &s->iomem); + + return 0; +} + +static const VMStateDescription vmstate_zynq_slcr = { + .name = "zynq_slcr", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT8_ARRAY(data, ZynqSLCRState, 0x1000), + VMSTATE_END_OF_LIST() + } +}; + +static void zynq_slcr_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); + + sdc->init = zynq_slcr_init; + dc->vmsd = &vmstate_zynq_slcr; + dc->reset = zynq_slcr_reset; +} + +static const TypeInfo zynq_slcr_info = { + .class_init = zynq_slcr_class_init, + .name = "xilinx,zynq_slcr", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(ZynqSLCRState), +}; + +static void zynq_slcr_register_types(void) +{ + type_register_static(&zynq_slcr_info); +} + +type_init(zynq_slcr_register_types) diff --git a/hw/mst_fpga.c b/hw/mst_fpga.c deleted file mode 100644 index 1dd15054d0..0000000000 --- a/hw/mst_fpga.c +++ /dev/null @@ -1,263 +0,0 @@ -/* - * PXA270-based Intel Mainstone platforms. - * FPGA driver - * - * Copyright (c) 2007 by Armin Kuster or - * - * - * This code is licensed under the GNU GPL v2. - * - * Contributions after 2012-01-13 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. - */ -#include "hw/hw.h" -#include "hw/sysbus.h" - -/* Mainstone FPGA for extern irqs */ -#define FPGA_GPIO_PIN 0 -#define MST_NUM_IRQS 16 -#define MST_LEDDAT1 0x10 -#define MST_LEDDAT2 0x14 -#define MST_LEDCTRL 0x40 -#define MST_GPSWR 0x60 -#define MST_MSCWR1 0x80 -#define MST_MSCWR2 0x84 -#define MST_MSCWR3 0x88 -#define MST_MSCRD 0x90 -#define MST_INTMSKENA 0xc0 -#define MST_INTSETCLR 0xd0 -#define MST_PCMCIA0 0xe0 -#define MST_PCMCIA1 0xe4 - -#define MST_PCMCIAx_READY (1 << 10) -#define MST_PCMCIAx_nCD (1 << 5) - -#define MST_PCMCIA_CD0_IRQ 9 -#define MST_PCMCIA_CD1_IRQ 13 - -typedef struct mst_irq_state{ - SysBusDevice busdev; - MemoryRegion iomem; - - qemu_irq parent; - - uint32_t prev_level; - uint32_t leddat1; - uint32_t leddat2; - uint32_t ledctrl; - uint32_t gpswr; - uint32_t mscwr1; - uint32_t mscwr2; - uint32_t mscwr3; - uint32_t mscrd; - uint32_t intmskena; - uint32_t intsetclr; - uint32_t pcmcia0; - uint32_t pcmcia1; -}mst_irq_state; - -static void -mst_fpga_set_irq(void *opaque, int irq, int level) -{ - mst_irq_state *s = (mst_irq_state *)opaque; - uint32_t oldint = s->intsetclr & s->intmskena; - - if (level) - s->prev_level |= 1u << irq; - else - s->prev_level &= ~(1u << irq); - - switch(irq) { - case MST_PCMCIA_CD0_IRQ: - if (level) - s->pcmcia0 &= ~MST_PCMCIAx_nCD; - else - s->pcmcia0 |= MST_PCMCIAx_nCD; - break; - case MST_PCMCIA_CD1_IRQ: - if (level) - s->pcmcia1 &= ~MST_PCMCIAx_nCD; - else - s->pcmcia1 |= MST_PCMCIAx_nCD; - break; - } - - if ((s->intmskena & (1u << irq)) && level) - s->intsetclr |= 1u << irq; - - if (oldint != (s->intsetclr & s->intmskena)) - qemu_set_irq(s->parent, s->intsetclr & s->intmskena); -} - - -static uint64_t -mst_fpga_readb(void *opaque, hwaddr addr, unsigned size) -{ - mst_irq_state *s = (mst_irq_state *) opaque; - - switch (addr) { - case MST_LEDDAT1: - return s->leddat1; - case MST_LEDDAT2: - return s->leddat2; - case MST_LEDCTRL: - return s->ledctrl; - case MST_GPSWR: - return s->gpswr; - case MST_MSCWR1: - return s->mscwr1; - case MST_MSCWR2: - return s->mscwr2; - case MST_MSCWR3: - return s->mscwr3; - case MST_MSCRD: - return s->mscrd; - case MST_INTMSKENA: - return s->intmskena; - case MST_INTSETCLR: - return s->intsetclr; - case MST_PCMCIA0: - return s->pcmcia0; - case MST_PCMCIA1: - return s->pcmcia1; - default: - printf("Mainstone - mst_fpga_readb: Bad register offset " - "0x" TARGET_FMT_plx "\n", addr); - } - return 0; -} - -static void -mst_fpga_writeb(void *opaque, hwaddr addr, uint64_t value, - unsigned size) -{ - mst_irq_state *s = (mst_irq_state *) opaque; - value &= 0xffffffff; - - switch (addr) { - case MST_LEDDAT1: - s->leddat1 = value; - break; - case MST_LEDDAT2: - s->leddat2 = value; - break; - case MST_LEDCTRL: - s->ledctrl = value; - break; - case MST_GPSWR: - s->gpswr = value; - break; - case MST_MSCWR1: - s->mscwr1 = value; - break; - case MST_MSCWR2: - s->mscwr2 = value; - break; - case MST_MSCWR3: - s->mscwr3 = value; - break; - case MST_MSCRD: - s->mscrd = value; - break; - case MST_INTMSKENA: /* Mask interrupt */ - s->intmskena = (value & 0xFEEFF); - qemu_set_irq(s->parent, s->intsetclr & s->intmskena); - break; - case MST_INTSETCLR: /* clear or set interrupt */ - s->intsetclr = (value & 0xFEEFF); - qemu_set_irq(s->parent, s->intsetclr & s->intmskena); - break; - /* For PCMCIAx allow the to change only power and reset */ - case MST_PCMCIA0: - s->pcmcia0 = (value & 0x1f) | (s->pcmcia0 & ~0x1f); - break; - case MST_PCMCIA1: - s->pcmcia1 = (value & 0x1f) | (s->pcmcia1 & ~0x1f); - break; - default: - printf("Mainstone - mst_fpga_writeb: Bad register offset " - "0x" TARGET_FMT_plx "\n", addr); - } -} - -static const MemoryRegionOps mst_fpga_ops = { - .read = mst_fpga_readb, - .write = mst_fpga_writeb, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static int mst_fpga_post_load(void *opaque, int version_id) -{ - mst_irq_state *s = (mst_irq_state *) opaque; - - qemu_set_irq(s->parent, s->intsetclr & s->intmskena); - return 0; -} - -static int mst_fpga_init(SysBusDevice *dev) -{ - mst_irq_state *s; - - s = FROM_SYSBUS(mst_irq_state, dev); - - s->pcmcia0 = MST_PCMCIAx_READY | MST_PCMCIAx_nCD; - s->pcmcia1 = MST_PCMCIAx_READY | MST_PCMCIAx_nCD; - - sysbus_init_irq(dev, &s->parent); - - /* alloc the external 16 irqs */ - qdev_init_gpio_in(&dev->qdev, mst_fpga_set_irq, MST_NUM_IRQS); - - memory_region_init_io(&s->iomem, &mst_fpga_ops, s, - "fpga", 0x00100000); - sysbus_init_mmio(dev, &s->iomem); - return 0; -} - -static VMStateDescription vmstate_mst_fpga_regs = { - .name = "mainstone_fpga", - .version_id = 0, - .minimum_version_id = 0, - .minimum_version_id_old = 0, - .post_load = mst_fpga_post_load, - .fields = (VMStateField []) { - VMSTATE_UINT32(prev_level, mst_irq_state), - VMSTATE_UINT32(leddat1, mst_irq_state), - VMSTATE_UINT32(leddat2, mst_irq_state), - VMSTATE_UINT32(ledctrl, mst_irq_state), - VMSTATE_UINT32(gpswr, mst_irq_state), - VMSTATE_UINT32(mscwr1, mst_irq_state), - VMSTATE_UINT32(mscwr2, mst_irq_state), - VMSTATE_UINT32(mscwr3, mst_irq_state), - VMSTATE_UINT32(mscrd, mst_irq_state), - VMSTATE_UINT32(intmskena, mst_irq_state), - VMSTATE_UINT32(intsetclr, mst_irq_state), - VMSTATE_UINT32(pcmcia0, mst_irq_state), - VMSTATE_UINT32(pcmcia1, mst_irq_state), - VMSTATE_END_OF_LIST(), - }, -}; - -static void mst_fpga_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = mst_fpga_init; - dc->desc = "Mainstone II FPGA"; - dc->vmsd = &vmstate_mst_fpga_regs; -} - -static const TypeInfo mst_fpga_info = { - .name = "mainstone-fpga", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(mst_irq_state), - .class_init = mst_fpga_class_init, -}; - -static void mst_fpga_register_types(void) -{ - type_register_static(&mst_fpga_info); -} - -type_init(mst_fpga_register_types) diff --git a/hw/omap_clk.c b/hw/omap_clk.c deleted file mode 100644 index 80a3c50e1e..0000000000 --- a/hw/omap_clk.c +++ /dev/null @@ -1,1264 +0,0 @@ -/* - * OMAP clocks. - * - * Copyright (C) 2006-2008 Andrzej Zaborowski - * - * Clocks data comes in part from arch/arm/mach-omap1/clock.h in Linux. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . - */ -#include "hw/hw.h" -#include "hw/arm/omap.h" - -struct clk { - const char *name; - const char *alias; - struct clk *parent; - struct clk *child1; - struct clk *sibling; -#define ALWAYS_ENABLED (1 << 0) -#define CLOCK_IN_OMAP310 (1 << 10) -#define CLOCK_IN_OMAP730 (1 << 11) -#define CLOCK_IN_OMAP1510 (1 << 12) -#define CLOCK_IN_OMAP16XX (1 << 13) -#define CLOCK_IN_OMAP242X (1 << 14) -#define CLOCK_IN_OMAP243X (1 << 15) -#define CLOCK_IN_OMAP343X (1 << 16) - uint32_t flags; - int id; - - int running; /* Is currently ticking */ - int enabled; /* Is enabled, regardless of its input clk */ - unsigned long rate; /* Current rate (if .running) */ - unsigned int divisor; /* Rate relative to input (if .enabled) */ - unsigned int multiplier; /* Rate relative to input (if .enabled) */ - qemu_irq users[16]; /* Who to notify on change */ - int usecount; /* Automatically idle when unused */ -}; - -static struct clk xtal_osc12m = { - .name = "xtal_osc_12m", - .rate = 12000000, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, -}; - -static struct clk xtal_osc32k = { - .name = "xtal_osc_32k", - .rate = 32768, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | - CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, -}; - -static struct clk ck_ref = { - .name = "ck_ref", - .alias = "clkin", - .parent = &xtal_osc12m, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | - ALWAYS_ENABLED, -}; - -/* If a dpll is disabled it becomes a bypass, child clocks don't stop */ -static struct clk dpll1 = { - .name = "dpll1", - .parent = &ck_ref, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | - ALWAYS_ENABLED, -}; - -static struct clk dpll2 = { - .name = "dpll2", - .parent = &ck_ref, - .flags = CLOCK_IN_OMAP310 | ALWAYS_ENABLED, -}; - -static struct clk dpll3 = { - .name = "dpll3", - .parent = &ck_ref, - .flags = CLOCK_IN_OMAP310 | ALWAYS_ENABLED, -}; - -static struct clk dpll4 = { - .name = "dpll4", - .parent = &ck_ref, - .multiplier = 4, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, -}; - -static struct clk apll = { - .name = "apll", - .parent = &ck_ref, - .multiplier = 48, - .divisor = 12, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, -}; - -static struct clk ck_48m = { - .name = "ck_48m", - .parent = &dpll4, /* either dpll4 or apll */ - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, -}; - -static struct clk ck_dpll1out = { - .name = "ck_dpll1out", - .parent = &dpll1, - .flags = CLOCK_IN_OMAP16XX, -}; - -static struct clk sossi_ck = { - .name = "ck_sossi", - .parent = &ck_dpll1out, - .flags = CLOCK_IN_OMAP16XX, -}; - -static struct clk clkm1 = { - .name = "clkm1", - .alias = "ck_gen1", - .parent = &dpll1, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | - ALWAYS_ENABLED, -}; - -static struct clk clkm2 = { - .name = "clkm2", - .alias = "ck_gen2", - .parent = &dpll1, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | - ALWAYS_ENABLED, -}; - -static struct clk clkm3 = { - .name = "clkm3", - .alias = "ck_gen3", - .parent = &dpll1, /* either dpll1 or ck_ref */ - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | - ALWAYS_ENABLED, -}; - -static struct clk arm_ck = { - .name = "arm_ck", - .alias = "mpu_ck", - .parent = &clkm1, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | - ALWAYS_ENABLED, -}; - -static struct clk armper_ck = { - .name = "armper_ck", - .alias = "mpuper_ck", - .parent = &clkm1, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, -}; - -static struct clk arm_gpio_ck = { - .name = "arm_gpio_ck", - .alias = "mpu_gpio_ck", - .parent = &clkm1, - .divisor = 1, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, -}; - -static struct clk armxor_ck = { - .name = "armxor_ck", - .alias = "mpuxor_ck", - .parent = &ck_ref, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, -}; - -static struct clk armtim_ck = { - .name = "armtim_ck", - .alias = "mputim_ck", - .parent = &ck_ref, /* either CLKIN or DPLL1 */ - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, -}; - -static struct clk armwdt_ck = { - .name = "armwdt_ck", - .alias = "mpuwd_ck", - .parent = &clkm1, - .divisor = 14, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | - ALWAYS_ENABLED, -}; - -static struct clk arminth_ck16xx = { - .name = "arminth_ck", - .parent = &arm_ck, - .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, - /* Note: On 16xx the frequency can be divided by 2 by programming - * ARM_CKCTL:ARM_INTHCK_SEL(14) to 1 - * - * 1510 version is in TC clocks. - */ -}; - -static struct clk dsp_ck = { - .name = "dsp_ck", - .parent = &clkm2, - .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, -}; - -static struct clk dspmmu_ck = { - .name = "dspmmu_ck", - .parent = &clkm2, - .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | - ALWAYS_ENABLED, -}; - -static struct clk dspper_ck = { - .name = "dspper_ck", - .parent = &clkm2, - .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, -}; - -static struct clk dspxor_ck = { - .name = "dspxor_ck", - .parent = &ck_ref, - .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, -}; - -static struct clk dsptim_ck = { - .name = "dsptim_ck", - .parent = &ck_ref, - .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, -}; - -static struct clk tc_ck = { - .name = "tc_ck", - .parent = &clkm3, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | - CLOCK_IN_OMAP730 | CLOCK_IN_OMAP310 | - ALWAYS_ENABLED, -}; - -static struct clk arminth_ck15xx = { - .name = "arminth_ck", - .parent = &tc_ck, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED, - /* Note: On 1510 the frequency follows TC_CK - * - * 16xx version is in MPU clocks. - */ -}; - -static struct clk tipb_ck = { - /* No-idle controlled by "tc_ck" */ - .name = "tipb_ck", - .parent = &tc_ck, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED, -}; - -static struct clk l3_ocpi_ck = { - /* No-idle controlled by "tc_ck" */ - .name = "l3_ocpi_ck", - .parent = &tc_ck, - .flags = CLOCK_IN_OMAP16XX, -}; - -static struct clk tc1_ck = { - .name = "tc1_ck", - .parent = &tc_ck, - .flags = CLOCK_IN_OMAP16XX, -}; - -static struct clk tc2_ck = { - .name = "tc2_ck", - .parent = &tc_ck, - .flags = CLOCK_IN_OMAP16XX, -}; - -static struct clk dma_ck = { - /* No-idle controlled by "tc_ck" */ - .name = "dma_ck", - .parent = &tc_ck, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | - ALWAYS_ENABLED, -}; - -static struct clk dma_lcdfree_ck = { - .name = "dma_lcdfree_ck", - .parent = &tc_ck, - .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, -}; - -static struct clk api_ck = { - .name = "api_ck", - .alias = "mpui_ck", - .parent = &tc_ck, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, -}; - -static struct clk lb_ck = { - .name = "lb_ck", - .parent = &tc_ck, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, -}; - -static struct clk lbfree_ck = { - .name = "lbfree_ck", - .parent = &tc_ck, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, -}; - -static struct clk hsab_ck = { - .name = "hsab_ck", - .parent = &tc_ck, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, -}; - -static struct clk rhea1_ck = { - .name = "rhea1_ck", - .parent = &tc_ck, - .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, -}; - -static struct clk rhea2_ck = { - .name = "rhea2_ck", - .parent = &tc_ck, - .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, -}; - -static struct clk lcd_ck_16xx = { - .name = "lcd_ck", - .parent = &clkm3, - .flags = CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP730, -}; - -static struct clk lcd_ck_1510 = { - .name = "lcd_ck", - .parent = &clkm3, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, -}; - -static struct clk uart1_1510 = { - .name = "uart1_ck", - /* Direct from ULPD, no real parent */ - .parent = &armper_ck, /* either armper_ck or dpll4 */ - .rate = 12000000, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED, -}; - -static struct clk uart1_16xx = { - .name = "uart1_ck", - /* Direct from ULPD, no real parent */ - .parent = &armper_ck, - .rate = 48000000, - .flags = CLOCK_IN_OMAP16XX, -}; - -static struct clk uart2_ck = { - .name = "uart2_ck", - /* Direct from ULPD, no real parent */ - .parent = &armper_ck, /* either armper_ck or dpll4 */ - .rate = 12000000, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | - ALWAYS_ENABLED, -}; - -static struct clk uart3_1510 = { - .name = "uart3_ck", - /* Direct from ULPD, no real parent */ - .parent = &armper_ck, /* either armper_ck or dpll4 */ - .rate = 12000000, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED, -}; - -static struct clk uart3_16xx = { - .name = "uart3_ck", - /* Direct from ULPD, no real parent */ - .parent = &armper_ck, - .rate = 48000000, - .flags = CLOCK_IN_OMAP16XX, -}; - -static struct clk usb_clk0 = { /* 6 MHz output on W4_USB_CLK0 */ - .name = "usb_clk0", - .alias = "usb.clko", - /* Direct from ULPD, no parent */ - .rate = 6000000, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, -}; - -static struct clk usb_hhc_ck1510 = { - .name = "usb_hhc_ck", - /* Direct from ULPD, no parent */ - .rate = 48000000, /* Actually 2 clocks, 12MHz and 48MHz */ - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, -}; - -static struct clk usb_hhc_ck16xx = { - .name = "usb_hhc_ck", - /* Direct from ULPD, no parent */ - .rate = 48000000, - /* OTG_SYSCON_2.OTG_PADEN == 0 (not 1510-compatible) */ - .flags = CLOCK_IN_OMAP16XX, -}; - -static struct clk usb_w2fc_mclk = { - .name = "usb_w2fc_mclk", - .alias = "usb_w2fc_ck", - .parent = &ck_48m, - .rate = 48000000, - .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, -}; - -static struct clk mclk_1510 = { - .name = "mclk", - /* Direct from ULPD, no parent. May be enabled by ext hardware. */ - .rate = 12000000, - .flags = CLOCK_IN_OMAP1510, -}; - -static struct clk bclk_310 = { - .name = "bt_mclk_out", /* Alias midi_mclk_out? */ - .parent = &armper_ck, - .flags = CLOCK_IN_OMAP310, -}; - -static struct clk mclk_310 = { - .name = "com_mclk_out", - .parent = &armper_ck, - .flags = CLOCK_IN_OMAP310, -}; - -static struct clk mclk_16xx = { - .name = "mclk", - /* Direct from ULPD, no parent. May be enabled by ext hardware. */ - .flags = CLOCK_IN_OMAP16XX, -}; - -static struct clk bclk_1510 = { - .name = "bclk", - /* Direct from ULPD, no parent. May be enabled by ext hardware. */ - .rate = 12000000, - .flags = CLOCK_IN_OMAP1510, -}; - -static struct clk bclk_16xx = { - .name = "bclk", - /* Direct from ULPD, no parent. May be enabled by ext hardware. */ - .flags = CLOCK_IN_OMAP16XX, -}; - -static struct clk mmc1_ck = { - .name = "mmc_ck", - .id = 1, - /* Functional clock is direct from ULPD, interface clock is ARMPER */ - .parent = &armper_ck, /* either armper_ck or dpll4 */ - .rate = 48000000, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, -}; - -static struct clk mmc2_ck = { - .name = "mmc_ck", - .id = 2, - /* Functional clock is direct from ULPD, interface clock is ARMPER */ - .parent = &armper_ck, - .rate = 48000000, - .flags = CLOCK_IN_OMAP16XX, -}; - -static struct clk cam_mclk = { - .name = "cam.mclk", - .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, - .rate = 12000000, -}; - -static struct clk cam_exclk = { - .name = "cam.exclk", - .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, - /* Either 12M from cam.mclk or 48M from dpll4 */ - .parent = &cam_mclk, -}; - -static struct clk cam_lclk = { - .name = "cam.lclk", - .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, -}; - -static struct clk i2c_fck = { - .name = "i2c_fck", - .id = 1, - .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | - ALWAYS_ENABLED, - .parent = &armxor_ck, -}; - -static struct clk i2c_ick = { - .name = "i2c_ick", - .id = 1, - .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, - .parent = &armper_ck, -}; - -static struct clk clk32k = { - .name = "clk32-kHz", - .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | - CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED, - .parent = &xtal_osc32k, -}; - -static struct clk ref_clk = { - .name = "ref_clk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED, - .rate = 12000000, /* 12 MHz or 13 MHz or 19.2 MHz */ - /*.parent = sys.xtalin */ -}; - -static struct clk apll_96m = { - .name = "apll_96m", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED, - .rate = 96000000, - /*.parent = ref_clk */ -}; - -static struct clk apll_54m = { - .name = "apll_54m", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED, - .rate = 54000000, - /*.parent = ref_clk */ -}; - -static struct clk sys_clk = { - .name = "sys_clk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED, - .rate = 32768, - /*.parent = sys.xtalin */ -}; - -static struct clk sleep_clk = { - .name = "sleep_clk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED, - .rate = 32768, - /*.parent = sys.xtalin */ -}; - -static struct clk dpll_ck = { - .name = "dpll", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED, - .parent = &ref_clk, -}; - -static struct clk dpll_x2_ck = { - .name = "dpll_x2", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED, - .parent = &ref_clk, -}; - -static struct clk wdt1_sys_clk = { - .name = "wdt1_sys_clk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED, - .rate = 32768, - /*.parent = sys.xtalin */ -}; - -static struct clk func_96m_clk = { - .name = "func_96m_clk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .divisor = 1, - .parent = &apll_96m, -}; - -static struct clk func_48m_clk = { - .name = "func_48m_clk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .divisor = 2, - .parent = &apll_96m, -}; - -static struct clk func_12m_clk = { - .name = "func_12m_clk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .divisor = 8, - .parent = &apll_96m, -}; - -static struct clk func_54m_clk = { - .name = "func_54m_clk", - .flags = CLOCK_IN_OMAP242X, - .divisor = 1, - .parent = &apll_54m, -}; - -static struct clk sys_clkout = { - .name = "clkout", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &sys_clk, -}; - -static struct clk sys_clkout2 = { - .name = "clkout2", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &sys_clk, -}; - -static struct clk core_clk = { - .name = "core_clk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &dpll_x2_ck, /* Switchable between dpll_ck and clk32k */ -}; - -static struct clk l3_clk = { - .name = "l3_clk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &core_clk, -}; - -static struct clk core_l4_iclk = { - .name = "core_l4_iclk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &l3_clk, -}; - -static struct clk wu_l4_iclk = { - .name = "wu_l4_iclk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &l3_clk, -}; - -static struct clk core_l3_iclk = { - .name = "core_l3_iclk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &core_clk, -}; - -static struct clk core_l4_usb_clk = { - .name = "core_l4_usb_clk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &l3_clk, -}; - -static struct clk wu_gpt1_clk = { - .name = "wu_gpt1_clk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &sys_clk, -}; - -static struct clk wu_32k_clk = { - .name = "wu_32k_clk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &sys_clk, -}; - -static struct clk uart1_fclk = { - .name = "uart1_fclk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &func_48m_clk, -}; - -static struct clk uart1_iclk = { - .name = "uart1_iclk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &core_l4_iclk, -}; - -static struct clk uart2_fclk = { - .name = "uart2_fclk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &func_48m_clk, -}; - -static struct clk uart2_iclk = { - .name = "uart2_iclk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &core_l4_iclk, -}; - -static struct clk uart3_fclk = { - .name = "uart3_fclk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &func_48m_clk, -}; - -static struct clk uart3_iclk = { - .name = "uart3_iclk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &core_l4_iclk, -}; - -static struct clk mpu_fclk = { - .name = "mpu_fclk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &core_clk, -}; - -static struct clk mpu_iclk = { - .name = "mpu_iclk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &core_clk, -}; - -static struct clk int_m_fclk = { - .name = "int_m_fclk", - .alias = "mpu_intc_fclk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &core_clk, -}; - -static struct clk int_m_iclk = { - .name = "int_m_iclk", - .alias = "mpu_intc_iclk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &core_clk, -}; - -static struct clk core_gpt2_clk = { - .name = "core_gpt2_clk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &sys_clk, -}; - -static struct clk core_gpt3_clk = { - .name = "core_gpt3_clk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &sys_clk, -}; - -static struct clk core_gpt4_clk = { - .name = "core_gpt4_clk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &sys_clk, -}; - -static struct clk core_gpt5_clk = { - .name = "core_gpt5_clk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &sys_clk, -}; - -static struct clk core_gpt6_clk = { - .name = "core_gpt6_clk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &sys_clk, -}; - -static struct clk core_gpt7_clk = { - .name = "core_gpt7_clk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &sys_clk, -}; - -static struct clk core_gpt8_clk = { - .name = "core_gpt8_clk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &sys_clk, -}; - -static struct clk core_gpt9_clk = { - .name = "core_gpt9_clk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &sys_clk, -}; - -static struct clk core_gpt10_clk = { - .name = "core_gpt10_clk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &sys_clk, -}; - -static struct clk core_gpt11_clk = { - .name = "core_gpt11_clk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &sys_clk, -}; - -static struct clk core_gpt12_clk = { - .name = "core_gpt12_clk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &sys_clk, -}; - -static struct clk mcbsp1_clk = { - .name = "mcbsp1_cg", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .divisor = 2, - .parent = &func_96m_clk, -}; - -static struct clk mcbsp2_clk = { - .name = "mcbsp2_cg", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .divisor = 2, - .parent = &func_96m_clk, -}; - -static struct clk emul_clk = { - .name = "emul_ck", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &func_54m_clk, -}; - -static struct clk sdma_fclk = { - .name = "sdma_fclk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &l3_clk, -}; - -static struct clk sdma_iclk = { - .name = "sdma_iclk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &core_l3_iclk, /* core_l4_iclk for the configuration port */ -}; - -static struct clk i2c1_fclk = { - .name = "i2c1.fclk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &func_12m_clk, - .divisor = 1, -}; - -static struct clk i2c1_iclk = { - .name = "i2c1.iclk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &core_l4_iclk, -}; - -static struct clk i2c2_fclk = { - .name = "i2c2.fclk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &func_12m_clk, - .divisor = 1, -}; - -static struct clk i2c2_iclk = { - .name = "i2c2.iclk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &core_l4_iclk, -}; - -static struct clk gpio_dbclk[5] = { - { - .name = "gpio1_dbclk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &wu_32k_clk, - }, { - .name = "gpio2_dbclk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &wu_32k_clk, - }, { - .name = "gpio3_dbclk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &wu_32k_clk, - }, { - .name = "gpio4_dbclk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &wu_32k_clk, - }, { - .name = "gpio5_dbclk", - .flags = CLOCK_IN_OMAP243X, - .parent = &wu_32k_clk, - }, -}; - -static struct clk gpio_iclk = { - .name = "gpio_iclk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &wu_l4_iclk, -}; - -static struct clk mmc_fck = { - .name = "mmc_fclk", - .flags = CLOCK_IN_OMAP242X, - .parent = &func_96m_clk, -}; - -static struct clk mmc_ick = { - .name = "mmc_iclk", - .flags = CLOCK_IN_OMAP242X, - .parent = &core_l4_iclk, -}; - -static struct clk spi_fclk[3] = { - { - .name = "spi1_fclk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &func_48m_clk, - }, { - .name = "spi2_fclk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &func_48m_clk, - }, { - .name = "spi3_fclk", - .flags = CLOCK_IN_OMAP243X, - .parent = &func_48m_clk, - }, -}; - -static struct clk dss_clk[2] = { - { - .name = "dss_clk1", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &core_clk, - }, { - .name = "dss_clk2", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &sys_clk, - }, -}; - -static struct clk dss_54m_clk = { - .name = "dss_54m_clk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &func_54m_clk, -}; - -static struct clk dss_l3_iclk = { - .name = "dss_l3_iclk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &core_l3_iclk, -}; - -static struct clk dss_l4_iclk = { - .name = "dss_l4_iclk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &core_l4_iclk, -}; - -static struct clk spi_iclk[3] = { - { - .name = "spi1_iclk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &core_l4_iclk, - }, { - .name = "spi2_iclk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - .parent = &core_l4_iclk, - }, { - .name = "spi3_iclk", - .flags = CLOCK_IN_OMAP243X, - .parent = &core_l4_iclk, - }, -}; - -static struct clk omapctrl_clk = { - .name = "omapctrl_iclk", - .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, - /* XXX Should be in WKUP domain */ - .parent = &core_l4_iclk, -}; - -static struct clk *onchip_clks[] = { - /* OMAP 1 */ - - /* non-ULPD clocks */ - &xtal_osc12m, - &xtal_osc32k, - &ck_ref, - &dpll1, - &dpll2, - &dpll3, - &dpll4, - &apll, - &ck_48m, - /* CK_GEN1 clocks */ - &clkm1, - &ck_dpll1out, - &sossi_ck, - &arm_ck, - &armper_ck, - &arm_gpio_ck, - &armxor_ck, - &armtim_ck, - &armwdt_ck, - &arminth_ck15xx, &arminth_ck16xx, - /* CK_GEN2 clocks */ - &clkm2, - &dsp_ck, - &dspmmu_ck, - &dspper_ck, - &dspxor_ck, - &dsptim_ck, - /* CK_GEN3 clocks */ - &clkm3, - &tc_ck, - &tipb_ck, - &l3_ocpi_ck, - &tc1_ck, - &tc2_ck, - &dma_ck, - &dma_lcdfree_ck, - &api_ck, - &lb_ck, - &lbfree_ck, - &hsab_ck, - &rhea1_ck, - &rhea2_ck, - &lcd_ck_16xx, - &lcd_ck_1510, - /* ULPD clocks */ - &uart1_1510, - &uart1_16xx, - &uart2_ck, - &uart3_1510, - &uart3_16xx, - &usb_clk0, - &usb_hhc_ck1510, &usb_hhc_ck16xx, - &mclk_1510, &mclk_16xx, &mclk_310, - &bclk_1510, &bclk_16xx, &bclk_310, - &mmc1_ck, - &mmc2_ck, - &cam_mclk, - &cam_exclk, - &cam_lclk, - &clk32k, - &usb_w2fc_mclk, - /* Virtual clocks */ - &i2c_fck, - &i2c_ick, - - /* OMAP 2 */ - - &ref_clk, - &apll_96m, - &apll_54m, - &sys_clk, - &sleep_clk, - &dpll_ck, - &dpll_x2_ck, - &wdt1_sys_clk, - &func_96m_clk, - &func_48m_clk, - &func_12m_clk, - &func_54m_clk, - &sys_clkout, - &sys_clkout2, - &core_clk, - &l3_clk, - &core_l4_iclk, - &wu_l4_iclk, - &core_l3_iclk, - &core_l4_usb_clk, - &wu_gpt1_clk, - &wu_32k_clk, - &uart1_fclk, - &uart1_iclk, - &uart2_fclk, - &uart2_iclk, - &uart3_fclk, - &uart3_iclk, - &mpu_fclk, - &mpu_iclk, - &int_m_fclk, - &int_m_iclk, - &core_gpt2_clk, - &core_gpt3_clk, - &core_gpt4_clk, - &core_gpt5_clk, - &core_gpt6_clk, - &core_gpt7_clk, - &core_gpt8_clk, - &core_gpt9_clk, - &core_gpt10_clk, - &core_gpt11_clk, - &core_gpt12_clk, - &mcbsp1_clk, - &mcbsp2_clk, - &emul_clk, - &sdma_fclk, - &sdma_iclk, - &i2c1_fclk, - &i2c1_iclk, - &i2c2_fclk, - &i2c2_iclk, - &gpio_dbclk[0], - &gpio_dbclk[1], - &gpio_dbclk[2], - &gpio_dbclk[3], - &gpio_iclk, - &mmc_fck, - &mmc_ick, - &spi_fclk[0], - &spi_iclk[0], - &spi_fclk[1], - &spi_iclk[1], - &spi_fclk[2], - &spi_iclk[2], - &dss_clk[0], - &dss_clk[1], - &dss_54m_clk, - &dss_l3_iclk, - &dss_l4_iclk, - &omapctrl_clk, - - NULL -}; - -void omap_clk_adduser(struct clk *clk, qemu_irq user) -{ - qemu_irq *i; - - for (i = clk->users; *i; i ++); - *i = user; -} - -struct clk *omap_findclk(struct omap_mpu_state_s *mpu, const char *name) -{ - struct clk *i; - - for (i = mpu->clks; i->name; i ++) - if (!strcmp(i->name, name) || (i->alias && !strcmp(i->alias, name))) - return i; - hw_error("%s: %s not found\n", __FUNCTION__, name); -} - -void omap_clk_get(struct clk *clk) -{ - clk->usecount ++; -} - -void omap_clk_put(struct clk *clk) -{ - if (!(clk->usecount --)) - hw_error("%s: %s is not in use\n", __FUNCTION__, clk->name); -} - -static void omap_clk_update(struct clk *clk) -{ - int parent, running; - qemu_irq *user; - struct clk *i; - - if (clk->parent) - parent = clk->parent->running; - else - parent = 1; - - running = parent && (clk->enabled || - ((clk->flags & ALWAYS_ENABLED) && clk->usecount)); - if (clk->running != running) { - clk->running = running; - for (user = clk->users; *user; user ++) - qemu_set_irq(*user, running); - for (i = clk->child1; i; i = i->sibling) - omap_clk_update(i); - } -} - -static void omap_clk_rate_update_full(struct clk *clk, unsigned long int rate, - unsigned long int div, unsigned long int mult) -{ - struct clk *i; - qemu_irq *user; - - clk->rate = muldiv64(rate, mult, div); - if (clk->running) - for (user = clk->users; *user; user ++) - qemu_irq_raise(*user); - for (i = clk->child1; i; i = i->sibling) - omap_clk_rate_update_full(i, rate, - div * i->divisor, mult * i->multiplier); -} - -static void omap_clk_rate_update(struct clk *clk) -{ - struct clk *i; - unsigned long int div, mult = div = 1; - - for (i = clk; i->parent; i = i->parent) { - div *= i->divisor; - mult *= i->multiplier; - } - - omap_clk_rate_update_full(clk, i->rate, div, mult); -} - -void omap_clk_reparent(struct clk *clk, struct clk *parent) -{ - struct clk **p; - - if (clk->parent) { - for (p = &clk->parent->child1; *p != clk; p = &(*p)->sibling); - *p = clk->sibling; - } - - clk->parent = parent; - if (parent) { - clk->sibling = parent->child1; - parent->child1 = clk; - omap_clk_update(clk); - omap_clk_rate_update(clk); - } else - clk->sibling = NULL; -} - -void omap_clk_onoff(struct clk *clk, int on) -{ - clk->enabled = on; - omap_clk_update(clk); -} - -void omap_clk_canidle(struct clk *clk, int can) -{ - if (can) - omap_clk_put(clk); - else - omap_clk_get(clk); -} - -void omap_clk_setrate(struct clk *clk, int divide, int multiply) -{ - clk->divisor = divide; - clk->multiplier = multiply; - omap_clk_rate_update(clk); -} - -int64_t omap_clk_getrate(omap_clk clk) -{ - return clk->rate; -} - -void omap_clk_init(struct omap_mpu_state_s *mpu) -{ - struct clk **i, *j, *k; - int count; - int flag; - - if (cpu_is_omap310(mpu)) - flag = CLOCK_IN_OMAP310; - else if (cpu_is_omap1510(mpu)) - flag = CLOCK_IN_OMAP1510; - else if (cpu_is_omap2410(mpu) || cpu_is_omap2420(mpu)) - flag = CLOCK_IN_OMAP242X; - else if (cpu_is_omap2430(mpu)) - flag = CLOCK_IN_OMAP243X; - else if (cpu_is_omap3430(mpu)) - flag = CLOCK_IN_OMAP243X; - else - return; - - for (i = onchip_clks, count = 0; *i; i ++) - if ((*i)->flags & flag) - count ++; - mpu->clks = (struct clk *) g_malloc0(sizeof(struct clk) * (count + 1)); - for (i = onchip_clks, j = mpu->clks; *i; i ++) - if ((*i)->flags & flag) { - memcpy(j, *i, sizeof(struct clk)); - for (k = mpu->clks; k < j; k ++) - if (j->parent && !strcmp(j->parent->name, k->name)) { - j->parent = k; - j->sibling = k->child1; - k->child1 = j; - } else if (k->parent && !strcmp(k->parent->name, j->name)) { - k->parent = j; - k->sibling = j->child1; - j->child1 = k; - } - j->divisor = j->divisor ?: 1; - j->multiplier = j->multiplier ?: 1; - j ++; - } - for (j = mpu->clks; count --; j ++) { - omap_clk_update(j); - omap_clk_rate_update(j); - } -} diff --git a/hw/omap_gpmc.c b/hw/omap_gpmc.c deleted file mode 100644 index 91adb66c2b..0000000000 --- a/hw/omap_gpmc.c +++ /dev/null @@ -1,894 +0,0 @@ -/* - * TI OMAP general purpose memory controller emulation. - * - * Copyright (C) 2007-2009 Nokia Corporation - * Original code written by Andrzej Zaborowski - * Enhancements for OMAP3 and NAND support written by Juha Riihimäki - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 or - * (at your option) any later version of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . - */ -#include "hw/hw.h" -#include "hw/block/flash.h" -#include "hw/arm/omap.h" -#include "exec/memory.h" -#include "exec/address-spaces.h" - -/* General-Purpose Memory Controller */ -struct omap_gpmc_s { - qemu_irq irq; - qemu_irq drq; - MemoryRegion iomem; - int accept_256; - - uint8_t revision; - uint8_t sysconfig; - uint16_t irqst; - uint16_t irqen; - uint16_t lastirq; - uint16_t timeout; - uint16_t config; - struct omap_gpmc_cs_file_s { - uint32_t config[7]; - MemoryRegion *iomem; - MemoryRegion container; - MemoryRegion nandiomem; - DeviceState *dev; - } cs_file[8]; - int ecc_cs; - int ecc_ptr; - uint32_t ecc_cfg; - ECCState ecc[9]; - struct prefetch { - uint32_t config1; /* GPMC_PREFETCH_CONFIG1 */ - uint32_t transfercount; /* GPMC_PREFETCH_CONFIG2:TRANSFERCOUNT */ - int startengine; /* GPMC_PREFETCH_CONTROL:STARTENGINE */ - int fifopointer; /* GPMC_PREFETCH_STATUS:FIFOPOINTER */ - int count; /* GPMC_PREFETCH_STATUS:COUNTVALUE */ - MemoryRegion iomem; - uint8_t fifo[64]; - } prefetch; -}; - -#define OMAP_GPMC_8BIT 0 -#define OMAP_GPMC_16BIT 1 -#define OMAP_GPMC_NOR 0 -#define OMAP_GPMC_NAND 2 - -static int omap_gpmc_devtype(struct omap_gpmc_cs_file_s *f) -{ - return (f->config[0] >> 10) & 3; -} - -static int omap_gpmc_devsize(struct omap_gpmc_cs_file_s *f) -{ - /* devsize field is really 2 bits but we ignore the high - * bit to ensure consistent behaviour if the guest sets - * it (values 2 and 3 are reserved in the TRM) - */ - return (f->config[0] >> 12) & 1; -} - -/* Extract the chip-select value from the prefetch config1 register */ -static int prefetch_cs(uint32_t config1) -{ - return (config1 >> 24) & 7; -} - -static int prefetch_threshold(uint32_t config1) -{ - return (config1 >> 8) & 0x7f; -} - -static void omap_gpmc_int_update(struct omap_gpmc_s *s) -{ - /* The TRM is a bit unclear, but it seems to say that - * the TERMINALCOUNTSTATUS bit is set only on the - * transition when the prefetch engine goes from - * active to inactive, whereas the FIFOEVENTSTATUS - * bit is held high as long as the fifo has at - * least THRESHOLD bytes available. - * So we do the latter here, but TERMINALCOUNTSTATUS - * is set elsewhere. - */ - if (s->prefetch.fifopointer >= prefetch_threshold(s->prefetch.config1)) { - s->irqst |= 1; - } - if ((s->irqen & s->irqst) != s->lastirq) { - s->lastirq = s->irqen & s->irqst; - qemu_set_irq(s->irq, s->lastirq); - } -} - -static void omap_gpmc_dma_update(struct omap_gpmc_s *s, int value) -{ - if (s->prefetch.config1 & 4) { - qemu_set_irq(s->drq, value); - } -} - -/* Access functions for when a NAND-like device is mapped into memory: - * all addresses in the region behave like accesses to the relevant - * GPMC_NAND_DATA_i register (which is actually implemented to call these) - */ -static uint64_t omap_nand_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct omap_gpmc_cs_file_s *f = (struct omap_gpmc_cs_file_s *)opaque; - uint64_t v; - nand_setpins(f->dev, 0, 0, 0, 1, 0); - switch (omap_gpmc_devsize(f)) { - case OMAP_GPMC_8BIT: - v = nand_getio(f->dev); - if (size == 1) { - return v; - } - v |= (nand_getio(f->dev) << 8); - if (size == 2) { - return v; - } - v |= (nand_getio(f->dev) << 16); - v |= (nand_getio(f->dev) << 24); - return v; - case OMAP_GPMC_16BIT: - v = nand_getio(f->dev); - if (size == 1) { - /* 8 bit read from 16 bit device : probably a guest bug */ - return v & 0xff; - } - if (size == 2) { - return v; - } - v |= (nand_getio(f->dev) << 16); - return v; - default: - abort(); - } -} - -static void omap_nand_setio(DeviceState *dev, uint64_t value, - int nandsize, int size) -{ - /* Write the specified value to the NAND device, respecting - * both size of the NAND device and size of the write access. - */ - switch (nandsize) { - case OMAP_GPMC_8BIT: - switch (size) { - case 1: - nand_setio(dev, value & 0xff); - break; - case 2: - nand_setio(dev, value & 0xff); - nand_setio(dev, (value >> 8) & 0xff); - break; - case 4: - default: - nand_setio(dev, value & 0xff); - nand_setio(dev, (value >> 8) & 0xff); - nand_setio(dev, (value >> 16) & 0xff); - nand_setio(dev, (value >> 24) & 0xff); - break; - } - break; - case OMAP_GPMC_16BIT: - switch (size) { - case 1: - /* writing to a 16bit device with 8bit access is probably a guest - * bug; pass the value through anyway. - */ - case 2: - nand_setio(dev, value & 0xffff); - break; - case 4: - default: - nand_setio(dev, value & 0xffff); - nand_setio(dev, (value >> 16) & 0xffff); - break; - } - break; - } -} - -static void omap_nand_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct omap_gpmc_cs_file_s *f = (struct omap_gpmc_cs_file_s *)opaque; - nand_setpins(f->dev, 0, 0, 0, 1, 0); - omap_nand_setio(f->dev, value, omap_gpmc_devsize(f), size); -} - -static const MemoryRegionOps omap_nand_ops = { - .read = omap_nand_read, - .write = omap_nand_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void fill_prefetch_fifo(struct omap_gpmc_s *s) -{ - /* Fill the prefetch FIFO by reading data from NAND. - * We do this synchronously, unlike the hardware which - * will do this asynchronously. We refill when the - * FIFO has THRESHOLD bytes free, and we always refill - * as much data as possible starting at the top end - * of the FIFO. - * (We have to refill at THRESHOLD rather than waiting - * for the FIFO to empty to allow for the case where - * the FIFO size isn't an exact multiple of THRESHOLD - * and we're doing DMA transfers.) - * This means we never need to handle wrap-around in - * the fifo-reading code, and the next byte of data - * to read is always fifo[63 - fifopointer]. - */ - int fptr; - int cs = prefetch_cs(s->prefetch.config1); - int is16bit = (((s->cs_file[cs].config[0] >> 12) & 3) != 0); - int bytes; - /* Don't believe the bit of the OMAP TRM that says that COUNTVALUE - * and TRANSFERCOUNT are in units of 16 bit words for 16 bit NAND. - * Instead believe the bit that says it is always a byte count. - */ - bytes = 64 - s->prefetch.fifopointer; - if (bytes > s->prefetch.count) { - bytes = s->prefetch.count; - } - s->prefetch.count -= bytes; - s->prefetch.fifopointer += bytes; - fptr = 64 - s->prefetch.fifopointer; - /* Move the existing data in the FIFO so it sits just - * before what we're about to read in - */ - while (fptr < (64 - bytes)) { - s->prefetch.fifo[fptr] = s->prefetch.fifo[fptr + bytes]; - fptr++; - } - while (fptr < 64) { - if (is16bit) { - uint32_t v = omap_nand_read(&s->cs_file[cs], 0, 2); - s->prefetch.fifo[fptr++] = v & 0xff; - s->prefetch.fifo[fptr++] = (v >> 8) & 0xff; - } else { - s->prefetch.fifo[fptr++] = omap_nand_read(&s->cs_file[cs], 0, 1); - } - } - if (s->prefetch.startengine && (s->prefetch.count == 0)) { - /* This was the final transfer: raise TERMINALCOUNTSTATUS */ - s->irqst |= 2; - s->prefetch.startengine = 0; - } - /* If there are any bytes in the FIFO at this point then - * we must raise a DMA request (either this is a final part - * transfer, or we filled the FIFO in which case we certainly - * have THRESHOLD bytes available) - */ - if (s->prefetch.fifopointer != 0) { - omap_gpmc_dma_update(s, 1); - } - omap_gpmc_int_update(s); -} - -/* Access functions for a NAND-like device when the prefetch/postwrite - * engine is enabled -- all addresses in the region behave alike: - * data is read or written to the FIFO. - */ -static uint64_t omap_gpmc_prefetch_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque; - uint32_t data; - if (s->prefetch.config1 & 1) { - /* The TRM doesn't define the behaviour if you read from the - * FIFO when the prefetch engine is in write mode. We choose - * to always return zero. - */ - return 0; - } - /* Note that trying to read an empty fifo repeats the last byte */ - if (s->prefetch.fifopointer) { - s->prefetch.fifopointer--; - } - data = s->prefetch.fifo[63 - s->prefetch.fifopointer]; - if (s->prefetch.fifopointer == - (64 - prefetch_threshold(s->prefetch.config1))) { - /* We've drained THRESHOLD bytes now. So deassert the - * DMA request, then refill the FIFO (which will probably - * assert it again.) - */ - omap_gpmc_dma_update(s, 0); - fill_prefetch_fifo(s); - } - omap_gpmc_int_update(s); - return data; -} - -static void omap_gpmc_prefetch_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque; - int cs = prefetch_cs(s->prefetch.config1); - if ((s->prefetch.config1 & 1) == 0) { - /* The TRM doesn't define the behaviour of writing to the - * FIFO when the prefetch engine is in read mode. We - * choose to ignore the write. - */ - return; - } - if (s->prefetch.count == 0) { - /* The TRM doesn't define the behaviour of writing to the - * FIFO if the transfer is complete. We choose to ignore. - */ - return; - } - /* The only reason we do any data buffering in postwrite - * mode is if we are talking to a 16 bit NAND device, in - * which case we need to buffer the first byte of the - * 16 bit word until the other byte arrives. - */ - int is16bit = (((s->cs_file[cs].config[0] >> 12) & 3) != 0); - if (is16bit) { - /* fifopointer alternates between 64 (waiting for first - * byte of word) and 63 (waiting for second byte) - */ - if (s->prefetch.fifopointer == 64) { - s->prefetch.fifo[0] = value; - s->prefetch.fifopointer--; - } else { - value = (value << 8) | s->prefetch.fifo[0]; - omap_nand_write(&s->cs_file[cs], 0, value, 2); - s->prefetch.count--; - s->prefetch.fifopointer = 64; - } - } else { - /* Just write the byte : fifopointer remains 64 at all times */ - omap_nand_write(&s->cs_file[cs], 0, value, 1); - s->prefetch.count--; - } - if (s->prefetch.count == 0) { - /* Final transfer: raise TERMINALCOUNTSTATUS */ - s->irqst |= 2; - s->prefetch.startengine = 0; - } - omap_gpmc_int_update(s); -} - -static const MemoryRegionOps omap_prefetch_ops = { - .read = omap_gpmc_prefetch_read, - .write = omap_gpmc_prefetch_write, - .endianness = DEVICE_NATIVE_ENDIAN, - .impl.min_access_size = 1, - .impl.max_access_size = 1, -}; - -static MemoryRegion *omap_gpmc_cs_memregion(struct omap_gpmc_s *s, int cs) -{ - /* Return the MemoryRegion* to map/unmap for this chipselect */ - struct omap_gpmc_cs_file_s *f = &s->cs_file[cs]; - if (omap_gpmc_devtype(f) == OMAP_GPMC_NOR) { - return f->iomem; - } - if ((s->prefetch.config1 & 0x80) && - (prefetch_cs(s->prefetch.config1) == cs)) { - /* The prefetch engine is enabled for this CS: map the FIFO */ - return &s->prefetch.iomem; - } - return &f->nandiomem; -} - -static void omap_gpmc_cs_map(struct omap_gpmc_s *s, int cs) -{ - struct omap_gpmc_cs_file_s *f = &s->cs_file[cs]; - uint32_t mask = (f->config[6] >> 8) & 0xf; - uint32_t base = f->config[6] & 0x3f; - uint32_t size; - - if (!f->iomem && !f->dev) { - return; - } - - if (!(f->config[6] & (1 << 6))) { - /* Do nothing unless CSVALID */ - return; - } - - /* TODO: check for overlapping regions and report access errors */ - if (mask != 0x8 && mask != 0xc && mask != 0xe && mask != 0xf - && !(s->accept_256 && !mask)) { - fprintf(stderr, "%s: invalid chip-select mask address (0x%x)\n", - __func__, mask); - } - - base <<= 24; - size = (0x0fffffff & ~(mask << 24)) + 1; - /* TODO: rather than setting the size of the mapping (which should be - * constant), the mask should cause wrapping of the address space, so - * that the same memory becomes accessible at every size bytes - * starting from base. */ - memory_region_init(&f->container, "omap-gpmc-file", size); - memory_region_add_subregion(&f->container, 0, - omap_gpmc_cs_memregion(s, cs)); - memory_region_add_subregion(get_system_memory(), base, - &f->container); -} - -static void omap_gpmc_cs_unmap(struct omap_gpmc_s *s, int cs) -{ - struct omap_gpmc_cs_file_s *f = &s->cs_file[cs]; - if (!(f->config[6] & (1 << 6))) { - /* Do nothing unless CSVALID */ - return; - } - if (!f->iomem && !f->dev) { - return; - } - memory_region_del_subregion(get_system_memory(), &f->container); - memory_region_del_subregion(&f->container, omap_gpmc_cs_memregion(s, cs)); - memory_region_destroy(&f->container); -} - -void omap_gpmc_reset(struct omap_gpmc_s *s) -{ - int i; - - s->sysconfig = 0; - s->irqst = 0; - s->irqen = 0; - omap_gpmc_int_update(s); - for (i = 0; i < 8; i++) { - /* This has to happen before we change any of the config - * used to determine which memory regions are mapped or unmapped. - */ - omap_gpmc_cs_unmap(s, i); - } - s->timeout = 0; - s->config = 0xa00; - s->prefetch.config1 = 0x00004000; - s->prefetch.transfercount = 0x00000000; - s->prefetch.startengine = 0; - s->prefetch.fifopointer = 0; - s->prefetch.count = 0; - for (i = 0; i < 8; i ++) { - s->cs_file[i].config[1] = 0x101001; - s->cs_file[i].config[2] = 0x020201; - s->cs_file[i].config[3] = 0x10031003; - s->cs_file[i].config[4] = 0x10f1111; - s->cs_file[i].config[5] = 0; - s->cs_file[i].config[6] = 0xf00 | (i ? 0 : 1 << 6); - - s->cs_file[i].config[6] = 0xf00; - /* In theory we could probe attached devices for some CFG1 - * bits here, but we just retain them across resets as they - * were set initially by omap_gpmc_attach(). - */ - if (i == 0) { - s->cs_file[i].config[0] &= 0x00433e00; - s->cs_file[i].config[6] |= 1 << 6; /* CSVALID */ - omap_gpmc_cs_map(s, i); - } else { - s->cs_file[i].config[0] &= 0x00403c00; - } - } - s->ecc_cs = 0; - s->ecc_ptr = 0; - s->ecc_cfg = 0x3fcff000; - for (i = 0; i < 9; i ++) - ecc_reset(&s->ecc[i]); -} - -static int gpmc_wordaccess_only(hwaddr addr) -{ - /* Return true if the register offset is to a register that - * only permits word width accesses. - * Non-word accesses are only OK for GPMC_NAND_DATA/ADDRESS/COMMAND - * for any chipselect. - */ - if (addr >= 0x60 && addr <= 0x1d4) { - int cs = (addr - 0x60) / 0x30; - addr -= cs * 0x30; - if (addr >= 0x7c && addr < 0x88) { - /* GPMC_NAND_COMMAND, GPMC_NAND_ADDRESS, GPMC_NAND_DATA */ - return 0; - } - } - return 1; -} - -static uint64_t omap_gpmc_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque; - int cs; - struct omap_gpmc_cs_file_s *f; - - if (size != 4 && gpmc_wordaccess_only(addr)) { - return omap_badwidth_read32(opaque, addr); - } - - switch (addr) { - case 0x000: /* GPMC_REVISION */ - return s->revision; - - case 0x010: /* GPMC_SYSCONFIG */ - return s->sysconfig; - - case 0x014: /* GPMC_SYSSTATUS */ - return 1; /* RESETDONE */ - - case 0x018: /* GPMC_IRQSTATUS */ - return s->irqst; - - case 0x01c: /* GPMC_IRQENABLE */ - return s->irqen; - - case 0x040: /* GPMC_TIMEOUT_CONTROL */ - return s->timeout; - - case 0x044: /* GPMC_ERR_ADDRESS */ - case 0x048: /* GPMC_ERR_TYPE */ - return 0; - - case 0x050: /* GPMC_CONFIG */ - return s->config; - - case 0x054: /* GPMC_STATUS */ - return 0x001; - - case 0x060 ... 0x1d4: - cs = (addr - 0x060) / 0x30; - addr -= cs * 0x30; - f = s->cs_file + cs; - switch (addr) { - case 0x60: /* GPMC_CONFIG1 */ - return f->config[0]; - case 0x64: /* GPMC_CONFIG2 */ - return f->config[1]; - case 0x68: /* GPMC_CONFIG3 */ - return f->config[2]; - case 0x6c: /* GPMC_CONFIG4 */ - return f->config[3]; - case 0x70: /* GPMC_CONFIG5 */ - return f->config[4]; - case 0x74: /* GPMC_CONFIG6 */ - return f->config[5]; - case 0x78: /* GPMC_CONFIG7 */ - return f->config[6]; - case 0x84 ... 0x87: /* GPMC_NAND_DATA */ - if (omap_gpmc_devtype(f) == OMAP_GPMC_NAND) { - return omap_nand_read(f, 0, size); - } - return 0; - } - break; - - case 0x1e0: /* GPMC_PREFETCH_CONFIG1 */ - return s->prefetch.config1; - case 0x1e4: /* GPMC_PREFETCH_CONFIG2 */ - return s->prefetch.transfercount; - case 0x1ec: /* GPMC_PREFETCH_CONTROL */ - return s->prefetch.startengine; - case 0x1f0: /* GPMC_PREFETCH_STATUS */ - /* NB: The OMAP3 TRM is inconsistent about whether the GPMC - * FIFOTHRESHOLDSTATUS bit should be set when - * FIFOPOINTER > FIFOTHRESHOLD or when it is >= FIFOTHRESHOLD. - * Apparently the underlying functional spec from which the TRM was - * created states that the behaviour is ">=", and this also - * makes more conceptual sense. - */ - return (s->prefetch.fifopointer << 24) | - ((s->prefetch.fifopointer >= - ((s->prefetch.config1 >> 8) & 0x7f) ? 1 : 0) << 16) | - s->prefetch.count; - - case 0x1f4: /* GPMC_ECC_CONFIG */ - return s->ecc_cs; - case 0x1f8: /* GPMC_ECC_CONTROL */ - return s->ecc_ptr; - case 0x1fc: /* GPMC_ECC_SIZE_CONFIG */ - return s->ecc_cfg; - case 0x200 ... 0x220: /* GPMC_ECC_RESULT */ - cs = (addr & 0x1f) >> 2; - /* TODO: check correctness */ - return - ((s->ecc[cs].cp & 0x07) << 0) | - ((s->ecc[cs].cp & 0x38) << 13) | - ((s->ecc[cs].lp[0] & 0x1ff) << 3) | - ((s->ecc[cs].lp[1] & 0x1ff) << 19); - - case 0x230: /* GPMC_TESTMODE_CTRL */ - return 0; - case 0x234: /* GPMC_PSA_LSB */ - case 0x238: /* GPMC_PSA_MSB */ - return 0x00000000; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_gpmc_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque; - int cs; - struct omap_gpmc_cs_file_s *f; - - if (size != 4 && gpmc_wordaccess_only(addr)) { - return omap_badwidth_write32(opaque, addr, value); - } - - switch (addr) { - case 0x000: /* GPMC_REVISION */ - case 0x014: /* GPMC_SYSSTATUS */ - case 0x054: /* GPMC_STATUS */ - case 0x1f0: /* GPMC_PREFETCH_STATUS */ - case 0x200 ... 0x220: /* GPMC_ECC_RESULT */ - case 0x234: /* GPMC_PSA_LSB */ - case 0x238: /* GPMC_PSA_MSB */ - OMAP_RO_REG(addr); - break; - - case 0x010: /* GPMC_SYSCONFIG */ - if ((value >> 3) == 0x3) - fprintf(stderr, "%s: bad SDRAM idle mode %"PRIi64"\n", - __FUNCTION__, value >> 3); - if (value & 2) - omap_gpmc_reset(s); - s->sysconfig = value & 0x19; - break; - - case 0x018: /* GPMC_IRQSTATUS */ - s->irqst &= ~value; - omap_gpmc_int_update(s); - break; - - case 0x01c: /* GPMC_IRQENABLE */ - s->irqen = value & 0xf03; - omap_gpmc_int_update(s); - break; - - case 0x040: /* GPMC_TIMEOUT_CONTROL */ - s->timeout = value & 0x1ff1; - break; - - case 0x044: /* GPMC_ERR_ADDRESS */ - case 0x048: /* GPMC_ERR_TYPE */ - break; - - case 0x050: /* GPMC_CONFIG */ - s->config = value & 0xf13; - break; - - case 0x060 ... 0x1d4: - cs = (addr - 0x060) / 0x30; - addr -= cs * 0x30; - f = s->cs_file + cs; - switch (addr) { - case 0x60: /* GPMC_CONFIG1 */ - f->config[0] = value & 0xffef3e13; - break; - case 0x64: /* GPMC_CONFIG2 */ - f->config[1] = value & 0x001f1f8f; - break; - case 0x68: /* GPMC_CONFIG3 */ - f->config[2] = value & 0x001f1f8f; - break; - case 0x6c: /* GPMC_CONFIG4 */ - f->config[3] = value & 0x1f8f1f8f; - break; - case 0x70: /* GPMC_CONFIG5 */ - f->config[4] = value & 0x0f1f1f1f; - break; - case 0x74: /* GPMC_CONFIG6 */ - f->config[5] = value & 0x00000fcf; - break; - case 0x78: /* GPMC_CONFIG7 */ - if ((f->config[6] ^ value) & 0xf7f) { - omap_gpmc_cs_unmap(s, cs); - f->config[6] = value & 0x00000f7f; - omap_gpmc_cs_map(s, cs); - } - break; - case 0x7c ... 0x7f: /* GPMC_NAND_COMMAND */ - if (omap_gpmc_devtype(f) == OMAP_GPMC_NAND) { - nand_setpins(f->dev, 1, 0, 0, 1, 0); /* CLE */ - omap_nand_setio(f->dev, value, omap_gpmc_devsize(f), size); - } - break; - case 0x80 ... 0x83: /* GPMC_NAND_ADDRESS */ - if (omap_gpmc_devtype(f) == OMAP_GPMC_NAND) { - nand_setpins(f->dev, 0, 1, 0, 1, 0); /* ALE */ - omap_nand_setio(f->dev, value, omap_gpmc_devsize(f), size); - } - break; - case 0x84 ... 0x87: /* GPMC_NAND_DATA */ - if (omap_gpmc_devtype(f) == OMAP_GPMC_NAND) { - omap_nand_write(f, 0, value, size); - } - break; - default: - goto bad_reg; - } - break; - - case 0x1e0: /* GPMC_PREFETCH_CONFIG1 */ - if (!s->prefetch.startengine) { - uint32_t newconfig1 = value & 0x7f8f7fbf; - uint32_t changed; - changed = newconfig1 ^ s->prefetch.config1; - if (changed & (0x80 | 0x7000000)) { - /* Turning the engine on or off, or mapping it somewhere else. - * cs_map() and cs_unmap() check the prefetch config and - * overall CSVALID bits, so it is sufficient to unmap-and-map - * both the old cs and the new one. Note that we adhere to - * the "unmap/change config/map" order (and not unmap twice - * if newcs == oldcs), otherwise we'll try to delete the wrong - * memory region. - */ - int oldcs = prefetch_cs(s->prefetch.config1); - int newcs = prefetch_cs(newconfig1); - omap_gpmc_cs_unmap(s, oldcs); - if (oldcs != newcs) { - omap_gpmc_cs_unmap(s, newcs); - } - s->prefetch.config1 = newconfig1; - omap_gpmc_cs_map(s, oldcs); - if (oldcs != newcs) { - omap_gpmc_cs_map(s, newcs); - } - } else { - s->prefetch.config1 = newconfig1; - } - } - break; - - case 0x1e4: /* GPMC_PREFETCH_CONFIG2 */ - if (!s->prefetch.startengine) { - s->prefetch.transfercount = value & 0x3fff; - } - break; - - case 0x1ec: /* GPMC_PREFETCH_CONTROL */ - if (s->prefetch.startengine != (value & 1)) { - s->prefetch.startengine = value & 1; - if (s->prefetch.startengine) { - /* Prefetch engine start */ - s->prefetch.count = s->prefetch.transfercount; - if (s->prefetch.config1 & 1) { - /* Write */ - s->prefetch.fifopointer = 64; - } else { - /* Read */ - s->prefetch.fifopointer = 0; - fill_prefetch_fifo(s); - } - } else { - /* Prefetch engine forcibly stopped. The TRM - * doesn't define the behaviour if you do this. - * We clear the prefetch count, which means that - * we permit no more writes, and don't read any - * more data from NAND. The CPU can still drain - * the FIFO of unread data. - */ - s->prefetch.count = 0; - } - omap_gpmc_int_update(s); - } - break; - - case 0x1f4: /* GPMC_ECC_CONFIG */ - s->ecc_cs = 0x8f; - break; - case 0x1f8: /* GPMC_ECC_CONTROL */ - if (value & (1 << 8)) - for (cs = 0; cs < 9; cs ++) - ecc_reset(&s->ecc[cs]); - s->ecc_ptr = value & 0xf; - if (s->ecc_ptr == 0 || s->ecc_ptr > 9) { - s->ecc_ptr = 0; - s->ecc_cs &= ~1; - } - break; - case 0x1fc: /* GPMC_ECC_SIZE_CONFIG */ - s->ecc_cfg = value & 0x3fcff1ff; - break; - case 0x230: /* GPMC_TESTMODE_CTRL */ - if (value & 7) - fprintf(stderr, "%s: test mode enable attempt\n", __FUNCTION__); - break; - - default: - bad_reg: - OMAP_BAD_REG(addr); - return; - } -} - -static const MemoryRegionOps omap_gpmc_ops = { - .read = omap_gpmc_read, - .write = omap_gpmc_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -struct omap_gpmc_s *omap_gpmc_init(struct omap_mpu_state_s *mpu, - hwaddr base, - qemu_irq irq, qemu_irq drq) -{ - int cs; - struct omap_gpmc_s *s = (struct omap_gpmc_s *) - g_malloc0(sizeof(struct omap_gpmc_s)); - - memory_region_init_io(&s->iomem, &omap_gpmc_ops, s, "omap-gpmc", 0x1000); - memory_region_add_subregion(get_system_memory(), base, &s->iomem); - - s->irq = irq; - s->drq = drq; - s->accept_256 = cpu_is_omap3630(mpu); - s->revision = cpu_class_omap3(mpu) ? 0x50 : 0x20; - s->lastirq = 0; - omap_gpmc_reset(s); - - /* We have to register a different IO memory handler for each - * chip select region in case a NAND device is mapped there. We - * make the region the worst-case size of 256MB and rely on the - * container memory region in cs_map to chop it down to the actual - * guest-requested size. - */ - for (cs = 0; cs < 8; cs++) { - memory_region_init_io(&s->cs_file[cs].nandiomem, - &omap_nand_ops, - &s->cs_file[cs], - "omap-nand", - 256 * 1024 * 1024); - } - - memory_region_init_io(&s->prefetch.iomem, &omap_prefetch_ops, s, - "omap-gpmc-prefetch", 256 * 1024 * 1024); - return s; -} - -void omap_gpmc_attach(struct omap_gpmc_s *s, int cs, MemoryRegion *iomem) -{ - struct omap_gpmc_cs_file_s *f; - assert(iomem); - - if (cs < 0 || cs >= 8) { - fprintf(stderr, "%s: bad chip-select %i\n", __FUNCTION__, cs); - exit(-1); - } - f = &s->cs_file[cs]; - - omap_gpmc_cs_unmap(s, cs); - f->config[0] &= ~(0xf << 10); - f->iomem = iomem; - omap_gpmc_cs_map(s, cs); -} - -void omap_gpmc_attach_nand(struct omap_gpmc_s *s, int cs, DeviceState *nand) -{ - struct omap_gpmc_cs_file_s *f; - assert(nand); - - if (cs < 0 || cs >= 8) { - fprintf(stderr, "%s: bad chip-select %i\n", __func__, cs); - exit(-1); - } - f = &s->cs_file[cs]; - - omap_gpmc_cs_unmap(s, cs); - f->config[0] &= ~(0xf << 10); - f->config[0] |= (OMAP_GPMC_NAND << 10); - f->dev = nand; - if (nand_getbuswidth(f->dev) == 16) { - f->config[0] |= OMAP_GPMC_16BIT << 12; - } - omap_gpmc_cs_map(s, cs); -} diff --git a/hw/omap_l4.c b/hw/omap_l4.c deleted file mode 100644 index ac8251f736..0000000000 --- a/hw/omap_l4.c +++ /dev/null @@ -1,162 +0,0 @@ -/* - * TI OMAP L4 interconnect emulation. - * - * Copyright (C) 2007-2009 Nokia Corporation - * Written by Andrzej Zaborowski - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 or - * (at your option) any later version of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . - */ -#include "hw/hw.h" -#include "hw/arm/omap.h" - -struct omap_l4_s { - MemoryRegion *address_space; - hwaddr base; - int ta_num; - struct omap_target_agent_s ta[0]; -}; - -struct omap_l4_s *omap_l4_init(MemoryRegion *address_space, - hwaddr base, int ta_num) -{ - struct omap_l4_s *bus = g_malloc0( - sizeof(*bus) + ta_num * sizeof(*bus->ta)); - - bus->address_space = address_space; - bus->ta_num = ta_num; - bus->base = base; - - return bus; -} - -hwaddr omap_l4_region_base(struct omap_target_agent_s *ta, - int region) -{ - return ta->bus->base + ta->start[region].offset; -} - -hwaddr omap_l4_region_size(struct omap_target_agent_s *ta, - int region) -{ - return ta->start[region].size; -} - -static uint64_t omap_l4ta_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct omap_target_agent_s *s = (struct omap_target_agent_s *) opaque; - - if (size != 2) { - return omap_badwidth_read16(opaque, addr); - } - - switch (addr) { - case 0x00: /* COMPONENT */ - return s->component; - - case 0x20: /* AGENT_CONTROL */ - return s->control; - - case 0x28: /* AGENT_STATUS */ - return s->status; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_l4ta_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct omap_target_agent_s *s = (struct omap_target_agent_s *) opaque; - - if (size != 4) { - return omap_badwidth_write32(opaque, addr, value); - } - - switch (addr) { - case 0x00: /* COMPONENT */ - case 0x28: /* AGENT_STATUS */ - OMAP_RO_REG(addr); - break; - - case 0x20: /* AGENT_CONTROL */ - s->control = value & 0x01000700; - if (value & 1) /* OCP_RESET */ - s->status &= ~1; /* REQ_TIMEOUT */ - break; - - default: - OMAP_BAD_REG(addr); - } -} - -static const MemoryRegionOps omap_l4ta_ops = { - .read = omap_l4ta_read, - .write = omap_l4ta_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -struct omap_target_agent_s *omap_l4ta_get(struct omap_l4_s *bus, - const struct omap_l4_region_s *regions, - const struct omap_l4_agent_info_s *agents, - int cs) -{ - int i; - struct omap_target_agent_s *ta = NULL; - const struct omap_l4_agent_info_s *info = NULL; - - for (i = 0; i < bus->ta_num; i ++) - if (agents[i].ta == cs) { - ta = &bus->ta[i]; - info = &agents[i]; - break; - } - if (!ta) { - fprintf(stderr, "%s: bad target agent (%i)\n", __FUNCTION__, cs); - exit(-1); - } - - ta->bus = bus; - ta->start = ®ions[info->region]; - ta->regions = info->regions; - - ta->component = ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0); - ta->status = 0x00000000; - ta->control = 0x00000200; /* XXX 01000200 for L4TAO */ - - memory_region_init_io(&ta->iomem, &omap_l4ta_ops, ta, "omap.l4ta", - omap_l4_region_size(ta, info->ta_region)); - omap_l4_attach(ta, info->ta_region, &ta->iomem); - - return ta; -} - -hwaddr omap_l4_attach(struct omap_target_agent_s *ta, - int region, MemoryRegion *mr) -{ - hwaddr base; - - if (region < 0 || region >= ta->regions) { - fprintf(stderr, "%s: bad io region (%i)\n", __FUNCTION__, region); - exit(-1); - } - - base = ta->bus->base + ta->start[region].offset; - if (mr) { - memory_region_add_subregion(ta->bus->address_space, base, mr); - } - - return base; -} diff --git a/hw/omap_sdrc.c b/hw/omap_sdrc.c deleted file mode 100644 index e38b571054..0000000000 --- a/hw/omap_sdrc.c +++ /dev/null @@ -1,168 +0,0 @@ -/* - * TI OMAP SDRAM controller emulation. - * - * Copyright (C) 2007-2008 Nokia Corporation - * Written by Andrzej Zaborowski - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 or - * (at your option) any later version of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . - */ -#include "hw/hw.h" -#include "hw/arm/omap.h" - -/* SDRAM Controller Subsystem */ -struct omap_sdrc_s { - MemoryRegion iomem; - uint8_t config; -}; - -void omap_sdrc_reset(struct omap_sdrc_s *s) -{ - s->config = 0x10; -} - -static uint64_t omap_sdrc_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct omap_sdrc_s *s = (struct omap_sdrc_s *) opaque; - - if (size != 4) { - return omap_badwidth_read32(opaque, addr); - } - - switch (addr) { - case 0x00: /* SDRC_REVISION */ - return 0x20; - - case 0x10: /* SDRC_SYSCONFIG */ - return s->config; - - case 0x14: /* SDRC_SYSSTATUS */ - return 1; /* RESETDONE */ - - case 0x40: /* SDRC_CS_CFG */ - case 0x44: /* SDRC_SHARING */ - case 0x48: /* SDRC_ERR_ADDR */ - case 0x4c: /* SDRC_ERR_TYPE */ - case 0x60: /* SDRC_DLLA_SCTRL */ - case 0x64: /* SDRC_DLLA_STATUS */ - case 0x68: /* SDRC_DLLB_CTRL */ - case 0x6c: /* SDRC_DLLB_STATUS */ - case 0x70: /* SDRC_POWER */ - case 0x80: /* SDRC_MCFG_0 */ - case 0x84: /* SDRC_MR_0 */ - case 0x88: /* SDRC_EMR1_0 */ - case 0x8c: /* SDRC_EMR2_0 */ - case 0x90: /* SDRC_EMR3_0 */ - case 0x94: /* SDRC_DCDL1_CTRL */ - case 0x98: /* SDRC_DCDL2_CTRL */ - case 0x9c: /* SDRC_ACTIM_CTRLA_0 */ - case 0xa0: /* SDRC_ACTIM_CTRLB_0 */ - case 0xa4: /* SDRC_RFR_CTRL_0 */ - case 0xa8: /* SDRC_MANUAL_0 */ - case 0xb0: /* SDRC_MCFG_1 */ - case 0xb4: /* SDRC_MR_1 */ - case 0xb8: /* SDRC_EMR1_1 */ - case 0xbc: /* SDRC_EMR2_1 */ - case 0xc0: /* SDRC_EMR3_1 */ - case 0xc4: /* SDRC_ACTIM_CTRLA_1 */ - case 0xc8: /* SDRC_ACTIM_CTRLB_1 */ - case 0xd4: /* SDRC_RFR_CTRL_1 */ - case 0xd8: /* SDRC_MANUAL_1 */ - return 0x00; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_sdrc_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct omap_sdrc_s *s = (struct omap_sdrc_s *) opaque; - - if (size != 4) { - return omap_badwidth_write32(opaque, addr, value); - } - - switch (addr) { - case 0x00: /* SDRC_REVISION */ - case 0x14: /* SDRC_SYSSTATUS */ - case 0x48: /* SDRC_ERR_ADDR */ - case 0x64: /* SDRC_DLLA_STATUS */ - case 0x6c: /* SDRC_DLLB_STATUS */ - OMAP_RO_REG(addr); - return; - - case 0x10: /* SDRC_SYSCONFIG */ - if ((value >> 3) != 0x2) - fprintf(stderr, "%s: bad SDRAM idle mode %i\n", - __FUNCTION__, (unsigned)value >> 3); - if (value & 2) - omap_sdrc_reset(s); - s->config = value & 0x18; - break; - - case 0x40: /* SDRC_CS_CFG */ - case 0x44: /* SDRC_SHARING */ - case 0x4c: /* SDRC_ERR_TYPE */ - case 0x60: /* SDRC_DLLA_SCTRL */ - case 0x68: /* SDRC_DLLB_CTRL */ - case 0x70: /* SDRC_POWER */ - case 0x80: /* SDRC_MCFG_0 */ - case 0x84: /* SDRC_MR_0 */ - case 0x88: /* SDRC_EMR1_0 */ - case 0x8c: /* SDRC_EMR2_0 */ - case 0x90: /* SDRC_EMR3_0 */ - case 0x94: /* SDRC_DCDL1_CTRL */ - case 0x98: /* SDRC_DCDL2_CTRL */ - case 0x9c: /* SDRC_ACTIM_CTRLA_0 */ - case 0xa0: /* SDRC_ACTIM_CTRLB_0 */ - case 0xa4: /* SDRC_RFR_CTRL_0 */ - case 0xa8: /* SDRC_MANUAL_0 */ - case 0xb0: /* SDRC_MCFG_1 */ - case 0xb4: /* SDRC_MR_1 */ - case 0xb8: /* SDRC_EMR1_1 */ - case 0xbc: /* SDRC_EMR2_1 */ - case 0xc0: /* SDRC_EMR3_1 */ - case 0xc4: /* SDRC_ACTIM_CTRLA_1 */ - case 0xc8: /* SDRC_ACTIM_CTRLB_1 */ - case 0xd4: /* SDRC_RFR_CTRL_1 */ - case 0xd8: /* SDRC_MANUAL_1 */ - break; - - default: - OMAP_BAD_REG(addr); - return; - } -} - -static const MemoryRegionOps omap_sdrc_ops = { - .read = omap_sdrc_read, - .write = omap_sdrc_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -struct omap_sdrc_s *omap_sdrc_init(MemoryRegion *sysmem, - hwaddr base) -{ - struct omap_sdrc_s *s = (struct omap_sdrc_s *) - g_malloc0(sizeof(struct omap_sdrc_s)); - - omap_sdrc_reset(s); - - memory_region_init_io(&s->iomem, &omap_sdrc_ops, s, "omap.sdrc", 0x1000); - memory_region_add_subregion(sysmem, base, &s->iomem); - - return s; -} diff --git a/hw/omap_tap.c b/hw/omap_tap.c deleted file mode 100644 index 99b70d5a75..0000000000 --- a/hw/omap_tap.c +++ /dev/null @@ -1,116 +0,0 @@ -/* - * TI OMAP TEST-Chip-level TAP emulation. - * - * Copyright (C) 2007-2008 Nokia Corporation - * Written by Andrzej Zaborowski - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 or - * (at your option) any later version of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . - */ - -#include "hw/hw.h" -#include "hw/arm/omap.h" - -/* TEST-Chip-level TAP */ -static uint64_t omap_tap_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; - - if (size != 4) { - return omap_badwidth_read32(opaque, addr); - } - - switch (addr) { - case 0x204: /* IDCODE_reg */ - switch (s->mpu_model) { - case omap2420: - case omap2422: - case omap2423: - return 0x5b5d902f; /* ES 2.2 */ - case omap2430: - return 0x5b68a02f; /* ES 2.2 */ - case omap3430: - return 0x1b7ae02f; /* ES 2 */ - default: - hw_error("%s: Bad mpu model\n", __FUNCTION__); - } - - case 0x208: /* PRODUCTION_ID_reg for OMAP2 */ - case 0x210: /* PRODUCTION_ID_reg for OMAP3 */ - switch (s->mpu_model) { - case omap2420: - return 0x000254f0; /* POP ESHS2.1.1 in N91/93/95, ES2 in N800 */ - case omap2422: - return 0x000400f0; - case omap2423: - return 0x000800f0; - case omap2430: - return 0x000000f0; - case omap3430: - return 0x000000f0; - default: - hw_error("%s: Bad mpu model\n", __FUNCTION__); - } - - case 0x20c: - switch (s->mpu_model) { - case omap2420: - case omap2422: - case omap2423: - return 0xcafeb5d9; /* ES 2.2 */ - case omap2430: - return 0xcafeb68a; /* ES 2.2 */ - case omap3430: - return 0xcafeb7ae; /* ES 2 */ - default: - hw_error("%s: Bad mpu model\n", __FUNCTION__); - } - - case 0x218: /* DIE_ID_reg */ - return ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0); - case 0x21c: /* DIE_ID_reg */ - return 0x54 << 24; - case 0x220: /* DIE_ID_reg */ - return ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0); - case 0x224: /* DIE_ID_reg */ - return ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0); - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_tap_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - if (size != 4) { - return omap_badwidth_write32(opaque, addr, value); - } - - OMAP_BAD_REG(addr); -} - -static const MemoryRegionOps omap_tap_ops = { - .read = omap_tap_read, - .write = omap_tap_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -void omap_tap_init(struct omap_target_agent_s *ta, - struct omap_mpu_state_s *mpu) -{ - memory_region_init_io(&mpu->tap_iomem, &omap_tap_ops, mpu, "omap.tap", - omap_l4_region_size(ta, 0)); - omap_l4_attach(ta, 0, &mpu->tap_iomem); -} diff --git a/hw/pc-testdev.c b/hw/pc-testdev.c deleted file mode 100644 index 32df175c10..0000000000 --- a/hw/pc-testdev.c +++ /dev/null @@ -1,187 +0,0 @@ -/* - * QEMU x86 ISA testdev - * - * Copyright (c) 2012 Avi Kivity, Gerd Hoffmann, Marcelo Tosatti - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -/* - * This device is used to test KVM features specific to the x86 port, such - * as emulation, power management, interrupt routing, among others. It's meant - * to be used like: - * - * qemu-system-x86_64 -device pc-testdev -serial stdio \ - * -device isa-debug-exit,iobase=0xf4,iosize=0x4 \ - * -kernel /home/lmr/Code/virt-test.git/kvm/unittests/msr.flat - * - * Where msr.flat is one of the KVM unittests, present on a separate repo, - * git://git.kernel.org/pub/scm/virt/kvm/kvm-unit-tests.git -*/ - -#include "config-host.h" -#if defined(CONFIG_POSIX) -#include -#endif -#include "hw/hw.h" -#include "hw/qdev.h" -#include "hw/isa/isa.h" - -#define IOMEM_LEN 0x10000 - -typedef struct PCTestdev { - ISADevice parent_obj; - - MemoryRegion ioport; - MemoryRegion flush; - MemoryRegion irq; - MemoryRegion iomem; - uint32_t ioport_data; - char iomem_buf[IOMEM_LEN]; -} PCTestdev; - -#define TYPE_TESTDEV "pc-testdev" -#define TESTDEV(obj) \ - OBJECT_CHECK(PCTestdev, (obj), TYPE_TESTDEV) - -static void test_irq_line(void *opaque, hwaddr addr, uint64_t data, - unsigned len) -{ - PCTestdev *dev = opaque; - ISADevice *isa = ISA_DEVICE(dev); - - qemu_set_irq(isa_get_irq(isa, addr), !!data); -} - -static const MemoryRegionOps test_irq_ops = { - .write = test_irq_line, - .valid.min_access_size = 1, - .valid.max_access_size = 1, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - -static void test_ioport_write(void *opaque, hwaddr addr, uint64_t data, - unsigned len) -{ - PCTestdev *dev = opaque; - dev->ioport_data = data; -} - -static uint64_t test_ioport_read(void *opaque, hwaddr addr, unsigned len) -{ - PCTestdev *dev = opaque; - return dev->ioport_data; -} - -static const MemoryRegionOps test_ioport_ops = { - .read = test_ioport_read, - .write = test_ioport_write, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - -static void test_flush_page(void *opaque, hwaddr addr, uint64_t data, - unsigned len) -{ - hwaddr page = 4096; - void *a = cpu_physical_memory_map(data & ~0xffful, &page, 0); - - /* We might not be able to get the full page, only mprotect what we actually - have mapped */ -#if defined(CONFIG_POSIX) - mprotect(a, page, PROT_NONE); - mprotect(a, page, PROT_READ|PROT_WRITE); -#endif - cpu_physical_memory_unmap(a, page, 0, 0); -} - -static const MemoryRegionOps test_flush_ops = { - .write = test_flush_page, - .valid.min_access_size = 4, - .valid.max_access_size = 4, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - -static uint64_t test_iomem_read(void *opaque, hwaddr addr, unsigned len) -{ - PCTestdev *dev = opaque; - uint64_t ret = 0; - memcpy(&ret, &dev->iomem_buf[addr], len); - ret = le64_to_cpu(ret); - - return ret; -} - -static void test_iomem_write(void *opaque, hwaddr addr, uint64_t val, - unsigned len) -{ - PCTestdev *dev = opaque; - val = cpu_to_le64(val); - memcpy(&dev->iomem_buf[addr], &val, len); - dev->iomem_buf[addr] = val; -} - -static const MemoryRegionOps test_iomem_ops = { - .read = test_iomem_read, - .write = test_iomem_write, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - -static int init_test_device(ISADevice *isa) -{ - PCTestdev *dev = TESTDEV(isa); - MemoryRegion *mem = isa_address_space(isa); - MemoryRegion *io = isa_address_space_io(isa); - - memory_region_init_io(&dev->ioport, &test_ioport_ops, dev, - "pc-testdev-ioport", 4); - memory_region_init_io(&dev->flush, &test_flush_ops, dev, - "pc-testdev-flush-page", 4); - memory_region_init_io(&dev->irq, &test_irq_ops, dev, - "pc-testdev-irq-line", 24); - memory_region_init_io(&dev->iomem, &test_iomem_ops, dev, - "pc-testdev-iomem", IOMEM_LEN); - - memory_region_add_subregion(io, 0xe0, &dev->ioport); - memory_region_add_subregion(io, 0xe4, &dev->flush); - memory_region_add_subregion(io, 0x2000, &dev->irq); - memory_region_add_subregion(mem, 0xff000000, &dev->iomem); - - return 0; -} - -static void testdev_class_init(ObjectClass *klass, void *data) -{ - ISADeviceClass *k = ISA_DEVICE_CLASS(klass); - - k->init = init_test_device; -} - -static const TypeInfo testdev_info = { - .name = TYPE_TESTDEV, - .parent = TYPE_ISA_DEVICE, - .instance_size = sizeof(PCTestdev), - .class_init = testdev_class_init, -}; - -static void testdev_register_types(void) -{ - type_register_static(&testdev_info); -} - -type_init(testdev_register_types) diff --git a/hw/pxa2xx_pcmcia.c b/hw/pxa2xx_pcmcia.c deleted file mode 100644 index 323d458491..0000000000 --- a/hw/pxa2xx_pcmcia.c +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Intel XScale PXA255/270 PC Card and CompactFlash Interface. - * - * Copyright (c) 2006 Openedhand Ltd. - * Written by Andrzej Zaborowski - * - * This code is licensed under the GPLv2. - * - * Contributions after 2012-01-13 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. - */ - -#include "hw/hw.h" -#include "hw/pcmcia.h" -#include "hw/arm/pxa.h" - - -struct PXA2xxPCMCIAState { - PCMCIASocket slot; - PCMCIACardState *card; - MemoryRegion common_iomem; - MemoryRegion attr_iomem; - MemoryRegion iomem; - - qemu_irq irq; - qemu_irq cd_irq; -}; - -static uint64_t pxa2xx_pcmcia_common_read(void *opaque, - hwaddr offset, unsigned size) -{ - PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque; - - if (s->slot.attached) { - return s->card->common_read(s->card->state, offset); - } - - return 0; -} - -static void pxa2xx_pcmcia_common_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque; - - if (s->slot.attached) { - s->card->common_write(s->card->state, offset, value); - } -} - -static uint64_t pxa2xx_pcmcia_attr_read(void *opaque, - hwaddr offset, unsigned size) -{ - PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque; - - if (s->slot.attached) { - return s->card->attr_read(s->card->state, offset); - } - - return 0; -} - -static void pxa2xx_pcmcia_attr_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque; - - if (s->slot.attached) { - s->card->attr_write(s->card->state, offset, value); - } -} - -static uint64_t pxa2xx_pcmcia_io_read(void *opaque, - hwaddr offset, unsigned size) -{ - PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque; - - if (s->slot.attached) { - return s->card->io_read(s->card->state, offset); - } - - return 0; -} - -static void pxa2xx_pcmcia_io_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque; - - if (s->slot.attached) { - s->card->io_write(s->card->state, offset, value); - } -} - -static const MemoryRegionOps pxa2xx_pcmcia_common_ops = { - .read = pxa2xx_pcmcia_common_read, - .write = pxa2xx_pcmcia_common_write, - .endianness = DEVICE_NATIVE_ENDIAN -}; - -static const MemoryRegionOps pxa2xx_pcmcia_attr_ops = { - .read = pxa2xx_pcmcia_attr_read, - .write = pxa2xx_pcmcia_attr_write, - .endianness = DEVICE_NATIVE_ENDIAN -}; - -static const MemoryRegionOps pxa2xx_pcmcia_io_ops = { - .read = pxa2xx_pcmcia_io_read, - .write = pxa2xx_pcmcia_io_write, - .endianness = DEVICE_NATIVE_ENDIAN -}; - -static void pxa2xx_pcmcia_set_irq(void *opaque, int line, int level) -{ - PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque; - if (!s->irq) - return; - - qemu_set_irq(s->irq, level); -} - -PXA2xxPCMCIAState *pxa2xx_pcmcia_init(MemoryRegion *sysmem, - hwaddr base) -{ - PXA2xxPCMCIAState *s; - - s = (PXA2xxPCMCIAState *) - g_malloc0(sizeof(PXA2xxPCMCIAState)); - - /* Socket I/O Memory Space */ - memory_region_init_io(&s->iomem, &pxa2xx_pcmcia_io_ops, s, - "pxa2xx-pcmcia-io", 0x04000000); - memory_region_add_subregion(sysmem, base | 0x00000000, - &s->iomem); - - /* Then next 64 MB is reserved */ - - /* Socket Attribute Memory Space */ - memory_region_init_io(&s->attr_iomem, &pxa2xx_pcmcia_attr_ops, s, - "pxa2xx-pcmcia-attribute", 0x04000000); - memory_region_add_subregion(sysmem, base | 0x08000000, - &s->attr_iomem); - - /* Socket Common Memory Space */ - memory_region_init_io(&s->common_iomem, &pxa2xx_pcmcia_common_ops, s, - "pxa2xx-pcmcia-common", 0x04000000); - memory_region_add_subregion(sysmem, base | 0x0c000000, - &s->common_iomem); - - if (base == 0x30000000) - s->slot.slot_string = "PXA PC Card Socket 1"; - else - s->slot.slot_string = "PXA PC Card Socket 0"; - s->slot.irq = qemu_allocate_irqs(pxa2xx_pcmcia_set_irq, s, 1)[0]; - pcmcia_socket_register(&s->slot); - - return s; -} - -/* Insert a new card into a slot */ -int pxa2xx_pcmcia_attach(void *opaque, PCMCIACardState *card) -{ - PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque; - if (s->slot.attached) - return -EEXIST; - - if (s->cd_irq) { - qemu_irq_raise(s->cd_irq); - } - - s->card = card; - - s->slot.attached = 1; - s->card->slot = &s->slot; - s->card->attach(s->card->state); - - return 0; -} - -/* Eject card from the slot */ -int pxa2xx_pcmcia_dettach(void *opaque) -{ - PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque; - if (!s->slot.attached) - return -ENOENT; - - s->card->detach(s->card->state); - s->card->slot = NULL; - s->card = NULL; - - s->slot.attached = 0; - - if (s->irq) - qemu_irq_lower(s->irq); - if (s->cd_irq) - qemu_irq_lower(s->cd_irq); - - return 0; -} - -/* Who to notify on card events */ -void pxa2xx_pcmcia_set_irq_cb(void *opaque, qemu_irq irq, qemu_irq cd_irq) -{ - PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque; - s->irq = irq; - s->cd_irq = cd_irq; -} diff --git a/hw/sga.c b/hw/sga.c deleted file mode 100644 index 5cf4b86c4f..0000000000 --- a/hw/sga.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - * QEMU dummy ISA device for loading sgabios option rom. - * - * Copyright (c) 2011 Glauber Costa, Red Hat Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * sgabios code originally available at code.google.com/p/sgabios - * - */ -#include "hw/pci/pci.h" -#include "hw/i386/pc.h" -#include "hw/loader.h" -#include "sysemu/sysemu.h" - -#define SGABIOS_FILENAME "sgabios.bin" - -typedef struct ISAGAState { - ISADevice dev; -} ISASGAState; - -static int sga_initfn(ISADevice *dev) -{ - rom_add_vga(SGABIOS_FILENAME); - return 0; -} -static void sga_class_initfn(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - ISADeviceClass *ic = ISA_DEVICE_CLASS(klass); - ic->init = sga_initfn; - dc->desc = "Serial Graphics Adapter"; -} - -static const TypeInfo sga_info = { - .name = "sga", - .parent = TYPE_ISA_DEVICE, - .instance_size = sizeof(ISASGAState), - .class_init = sga_class_initfn, -}; - -static void sga_register_types(void) -{ - type_register_static(&sga_info); -} - -type_init(sga_register_types) diff --git a/hw/slavio_misc.c b/hw/slavio_misc.c deleted file mode 100644 index a7a9368864..0000000000 --- a/hw/slavio_misc.c +++ /dev/null @@ -1,508 +0,0 @@ -/* - * QEMU Sparc SLAVIO aux io port emulation - * - * Copyright (c) 2005 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "sysemu/sysemu.h" -#include "hw/sysbus.h" -#include "trace.h" - -/* - * This is the auxio port, chip control and system control part of - * chip STP2001 (Slave I/O), also produced as NCR89C105. See - * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt - * - * This also includes the PMC CPU idle controller. - */ - -typedef struct MiscState { - SysBusDevice busdev; - MemoryRegion cfg_iomem; - MemoryRegion diag_iomem; - MemoryRegion mdm_iomem; - MemoryRegion led_iomem; - MemoryRegion sysctrl_iomem; - MemoryRegion aux1_iomem; - MemoryRegion aux2_iomem; - qemu_irq irq; - qemu_irq fdc_tc; - uint32_t dummy; - uint8_t config; - uint8_t aux1, aux2; - uint8_t diag, mctrl; - uint8_t sysctrl; - uint16_t leds; -} MiscState; - -typedef struct APCState { - SysBusDevice busdev; - MemoryRegion iomem; - qemu_irq cpu_halt; -} APCState; - -#define MISC_SIZE 1 -#define SYSCTRL_SIZE 4 - -#define AUX1_TC 0x02 - -#define AUX2_PWROFF 0x01 -#define AUX2_PWRINTCLR 0x02 -#define AUX2_PWRFAIL 0x20 - -#define CFG_PWRINTEN 0x08 - -#define SYS_RESET 0x01 -#define SYS_RESETSTAT 0x02 - -static void slavio_misc_update_irq(void *opaque) -{ - MiscState *s = opaque; - - if ((s->aux2 & AUX2_PWRFAIL) && (s->config & CFG_PWRINTEN)) { - trace_slavio_misc_update_irq_raise(); - qemu_irq_raise(s->irq); - } else { - trace_slavio_misc_update_irq_lower(); - qemu_irq_lower(s->irq); - } -} - -static void slavio_misc_reset(DeviceState *d) -{ - MiscState *s = container_of(d, MiscState, busdev.qdev); - - // Diagnostic and system control registers not cleared in reset - s->config = s->aux1 = s->aux2 = s->mctrl = 0; -} - -static void slavio_set_power_fail(void *opaque, int irq, int power_failing) -{ - MiscState *s = opaque; - - trace_slavio_set_power_fail(power_failing, s->config); - if (power_failing && (s->config & CFG_PWRINTEN)) { - s->aux2 |= AUX2_PWRFAIL; - } else { - s->aux2 &= ~AUX2_PWRFAIL; - } - slavio_misc_update_irq(s); -} - -static void slavio_cfg_mem_writeb(void *opaque, hwaddr addr, - uint64_t val, unsigned size) -{ - MiscState *s = opaque; - - trace_slavio_cfg_mem_writeb(val & 0xff); - s->config = val & 0xff; - slavio_misc_update_irq(s); -} - -static uint64_t slavio_cfg_mem_readb(void *opaque, hwaddr addr, - unsigned size) -{ - MiscState *s = opaque; - uint32_t ret = 0; - - ret = s->config; - trace_slavio_cfg_mem_readb(ret); - return ret; -} - -static const MemoryRegionOps slavio_cfg_mem_ops = { - .read = slavio_cfg_mem_readb, - .write = slavio_cfg_mem_writeb, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 1, - .max_access_size = 1, - }, -}; - -static void slavio_diag_mem_writeb(void *opaque, hwaddr addr, - uint64_t val, unsigned size) -{ - MiscState *s = opaque; - - trace_slavio_diag_mem_writeb(val & 0xff); - s->diag = val & 0xff; -} - -static uint64_t slavio_diag_mem_readb(void *opaque, hwaddr addr, - unsigned size) -{ - MiscState *s = opaque; - uint32_t ret = 0; - - ret = s->diag; - trace_slavio_diag_mem_readb(ret); - return ret; -} - -static const MemoryRegionOps slavio_diag_mem_ops = { - .read = slavio_diag_mem_readb, - .write = slavio_diag_mem_writeb, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 1, - .max_access_size = 1, - }, -}; - -static void slavio_mdm_mem_writeb(void *opaque, hwaddr addr, - uint64_t val, unsigned size) -{ - MiscState *s = opaque; - - trace_slavio_mdm_mem_writeb(val & 0xff); - s->mctrl = val & 0xff; -} - -static uint64_t slavio_mdm_mem_readb(void *opaque, hwaddr addr, - unsigned size) -{ - MiscState *s = opaque; - uint32_t ret = 0; - - ret = s->mctrl; - trace_slavio_mdm_mem_readb(ret); - return ret; -} - -static const MemoryRegionOps slavio_mdm_mem_ops = { - .read = slavio_mdm_mem_readb, - .write = slavio_mdm_mem_writeb, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 1, - .max_access_size = 1, - }, -}; - -static void slavio_aux1_mem_writeb(void *opaque, hwaddr addr, - uint64_t val, unsigned size) -{ - MiscState *s = opaque; - - trace_slavio_aux1_mem_writeb(val & 0xff); - if (val & AUX1_TC) { - // Send a pulse to floppy terminal count line - if (s->fdc_tc) { - qemu_irq_raise(s->fdc_tc); - qemu_irq_lower(s->fdc_tc); - } - val &= ~AUX1_TC; - } - s->aux1 = val & 0xff; -} - -static uint64_t slavio_aux1_mem_readb(void *opaque, hwaddr addr, - unsigned size) -{ - MiscState *s = opaque; - uint32_t ret = 0; - - ret = s->aux1; - trace_slavio_aux1_mem_readb(ret); - return ret; -} - -static const MemoryRegionOps slavio_aux1_mem_ops = { - .read = slavio_aux1_mem_readb, - .write = slavio_aux1_mem_writeb, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 1, - .max_access_size = 1, - }, -}; - -static void slavio_aux2_mem_writeb(void *opaque, hwaddr addr, - uint64_t val, unsigned size) -{ - MiscState *s = opaque; - - val &= AUX2_PWRINTCLR | AUX2_PWROFF; - trace_slavio_aux2_mem_writeb(val & 0xff); - val |= s->aux2 & AUX2_PWRFAIL; - if (val & AUX2_PWRINTCLR) // Clear Power Fail int - val &= AUX2_PWROFF; - s->aux2 = val; - if (val & AUX2_PWROFF) - qemu_system_shutdown_request(); - slavio_misc_update_irq(s); -} - -static uint64_t slavio_aux2_mem_readb(void *opaque, hwaddr addr, - unsigned size) -{ - MiscState *s = opaque; - uint32_t ret = 0; - - ret = s->aux2; - trace_slavio_aux2_mem_readb(ret); - return ret; -} - -static const MemoryRegionOps slavio_aux2_mem_ops = { - .read = slavio_aux2_mem_readb, - .write = slavio_aux2_mem_writeb, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 1, - .max_access_size = 1, - }, -}; - -static void apc_mem_writeb(void *opaque, hwaddr addr, - uint64_t val, unsigned size) -{ - APCState *s = opaque; - - trace_apc_mem_writeb(val & 0xff); - qemu_irq_raise(s->cpu_halt); -} - -static uint64_t apc_mem_readb(void *opaque, hwaddr addr, - unsigned size) -{ - uint32_t ret = 0; - - trace_apc_mem_readb(ret); - return ret; -} - -static const MemoryRegionOps apc_mem_ops = { - .read = apc_mem_readb, - .write = apc_mem_writeb, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 1, - .max_access_size = 1, - } -}; - -static uint64_t slavio_sysctrl_mem_readl(void *opaque, hwaddr addr, - unsigned size) -{ - MiscState *s = opaque; - uint32_t ret = 0; - - switch (addr) { - case 0: - ret = s->sysctrl; - break; - default: - break; - } - trace_slavio_sysctrl_mem_readl(ret); - return ret; -} - -static void slavio_sysctrl_mem_writel(void *opaque, hwaddr addr, - uint64_t val, unsigned size) -{ - MiscState *s = opaque; - - trace_slavio_sysctrl_mem_writel(val); - switch (addr) { - case 0: - if (val & SYS_RESET) { - s->sysctrl = SYS_RESETSTAT; - qemu_system_reset_request(); - } - break; - default: - break; - } -} - -static const MemoryRegionOps slavio_sysctrl_mem_ops = { - .read = slavio_sysctrl_mem_readl, - .write = slavio_sysctrl_mem_writel, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, -}; - -static uint64_t slavio_led_mem_readw(void *opaque, hwaddr addr, - unsigned size) -{ - MiscState *s = opaque; - uint32_t ret = 0; - - switch (addr) { - case 0: - ret = s->leds; - break; - default: - break; - } - trace_slavio_led_mem_readw(ret); - return ret; -} - -static void slavio_led_mem_writew(void *opaque, hwaddr addr, - uint64_t val, unsigned size) -{ - MiscState *s = opaque; - - trace_slavio_led_mem_readw(val & 0xffff); - switch (addr) { - case 0: - s->leds = val; - break; - default: - break; - } -} - -static const MemoryRegionOps slavio_led_mem_ops = { - .read = slavio_led_mem_readw, - .write = slavio_led_mem_writew, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 2, - .max_access_size = 2, - }, -}; - -static const VMStateDescription vmstate_misc = { - .name ="slavio_misc", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField []) { - VMSTATE_UINT32(dummy, MiscState), - VMSTATE_UINT8(config, MiscState), - VMSTATE_UINT8(aux1, MiscState), - VMSTATE_UINT8(aux2, MiscState), - VMSTATE_UINT8(diag, MiscState), - VMSTATE_UINT8(mctrl, MiscState), - VMSTATE_UINT8(sysctrl, MiscState), - VMSTATE_END_OF_LIST() - } -}; - -static int apc_init1(SysBusDevice *dev) -{ - APCState *s = FROM_SYSBUS(APCState, dev); - - sysbus_init_irq(dev, &s->cpu_halt); - - /* Power management (APC) XXX: not a Slavio device */ - memory_region_init_io(&s->iomem, &apc_mem_ops, s, - "apc", MISC_SIZE); - sysbus_init_mmio(dev, &s->iomem); - return 0; -} - -static int slavio_misc_init1(SysBusDevice *dev) -{ - MiscState *s = FROM_SYSBUS(MiscState, dev); - - sysbus_init_irq(dev, &s->irq); - sysbus_init_irq(dev, &s->fdc_tc); - - /* 8 bit registers */ - /* Slavio control */ - memory_region_init_io(&s->cfg_iomem, &slavio_cfg_mem_ops, s, - "configuration", MISC_SIZE); - sysbus_init_mmio(dev, &s->cfg_iomem); - - /* Diagnostics */ - memory_region_init_io(&s->diag_iomem, &slavio_diag_mem_ops, s, - "diagnostic", MISC_SIZE); - sysbus_init_mmio(dev, &s->diag_iomem); - - /* Modem control */ - memory_region_init_io(&s->mdm_iomem, &slavio_mdm_mem_ops, s, - "modem", MISC_SIZE); - sysbus_init_mmio(dev, &s->mdm_iomem); - - /* 16 bit registers */ - /* ss600mp diag LEDs */ - memory_region_init_io(&s->led_iomem, &slavio_led_mem_ops, s, - "leds", MISC_SIZE); - sysbus_init_mmio(dev, &s->led_iomem); - - /* 32 bit registers */ - /* System control */ - memory_region_init_io(&s->sysctrl_iomem, &slavio_sysctrl_mem_ops, s, - "system-control", MISC_SIZE); - sysbus_init_mmio(dev, &s->sysctrl_iomem); - - /* AUX 1 (Misc System Functions) */ - memory_region_init_io(&s->aux1_iomem, &slavio_aux1_mem_ops, s, - "misc-system-functions", MISC_SIZE); - sysbus_init_mmio(dev, &s->aux1_iomem); - - /* AUX 2 (Software Powerdown Control) */ - memory_region_init_io(&s->aux2_iomem, &slavio_aux2_mem_ops, s, - "software-powerdown-control", MISC_SIZE); - sysbus_init_mmio(dev, &s->aux2_iomem); - - qdev_init_gpio_in(&dev->qdev, slavio_set_power_fail, 1); - - return 0; -} - -static void slavio_misc_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = slavio_misc_init1; - dc->reset = slavio_misc_reset; - dc->vmsd = &vmstate_misc; -} - -static const TypeInfo slavio_misc_info = { - .name = "slavio_misc", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(MiscState), - .class_init = slavio_misc_class_init, -}; - -static void apc_class_init(ObjectClass *klass, void *data) -{ - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = apc_init1; -} - -static const TypeInfo apc_info = { - .name = "apc", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(MiscState), - .class_init = apc_class_init, -}; - -static void slavio_misc_register_types(void) -{ - type_register_static(&slavio_misc_info); - type_register_static(&apc_info); -} - -type_init(slavio_misc_register_types) diff --git a/hw/sparc/Makefile.objs b/hw/sparc/Makefile.objs index 3246bb15e5..c987b5b5df 100644 --- a/hw/sparc/Makefile.objs +++ b/hw/sparc/Makefile.objs @@ -1,6 +1 @@ -obj-y += slavio_misc.o -obj-y += eccmemctl.o - -obj-y := $(addprefix ../,$(obj-y)) - obj-y += sun4m.o leon3.o diff --git a/hw/vmport.c b/hw/vmport.c deleted file mode 100644 index 0d07ea1fc5..0000000000 --- a/hw/vmport.c +++ /dev/null @@ -1,170 +0,0 @@ -/* - * QEMU VMPort emulation - * - * Copyright (C) 2007 HervĂ© Poussineau - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "hw/hw.h" -#include "hw/isa/isa.h" -#include "hw/i386/pc.h" -#include "sysemu/kvm.h" -#include "hw/qdev.h" - -//#define VMPORT_DEBUG - -#define VMPORT_CMD_GETVERSION 0x0a -#define VMPORT_CMD_GETRAMSIZE 0x14 - -#define VMPORT_ENTRIES 0x2c -#define VMPORT_MAGIC 0x564D5868 - -typedef struct _VMPortState -{ - ISADevice dev; - MemoryRegion io; - IOPortReadFunc *func[VMPORT_ENTRIES]; - void *opaque[VMPORT_ENTRIES]; -} VMPortState; - -static VMPortState *port_state; - -void vmport_register(unsigned char command, IOPortReadFunc *func, void *opaque) -{ - if (command >= VMPORT_ENTRIES) - return; - - port_state->func[command] = func; - port_state->opaque[command] = opaque; -} - -static uint64_t vmport_ioport_read(void *opaque, hwaddr addr, - unsigned size) -{ - VMPortState *s = opaque; - CPUX86State *env = cpu_single_env; - unsigned char command; - uint32_t eax; - - cpu_synchronize_state(env); - - eax = env->regs[R_EAX]; - if (eax != VMPORT_MAGIC) - return eax; - - command = env->regs[R_ECX]; - if (command >= VMPORT_ENTRIES) - return eax; - if (!s->func[command]) - { -#ifdef VMPORT_DEBUG - fprintf(stderr, "vmport: unknown command %x\n", command); -#endif - return eax; - } - - return s->func[command](s->opaque[command], addr); -} - -static void vmport_ioport_write(void *opaque, hwaddr addr, - uint64_t val, unsigned size) -{ - CPUX86State *env = cpu_single_env; - - env->regs[R_EAX] = vmport_ioport_read(opaque, addr, 4); -} - -static uint32_t vmport_cmd_get_version(void *opaque, uint32_t addr) -{ - CPUX86State *env = cpu_single_env; - env->regs[R_EBX] = VMPORT_MAGIC; - return 6; -} - -static uint32_t vmport_cmd_ram_size(void *opaque, uint32_t addr) -{ - CPUX86State *env = cpu_single_env; - env->regs[R_EBX] = 0x1177; - return ram_size; -} - -/* vmmouse helpers */ -void vmmouse_get_data(uint32_t *data) -{ - CPUX86State *env = cpu_single_env; - - data[0] = env->regs[R_EAX]; data[1] = env->regs[R_EBX]; - data[2] = env->regs[R_ECX]; data[3] = env->regs[R_EDX]; - data[4] = env->regs[R_ESI]; data[5] = env->regs[R_EDI]; -} - -void vmmouse_set_data(const uint32_t *data) -{ - CPUX86State *env = cpu_single_env; - - env->regs[R_EAX] = data[0]; env->regs[R_EBX] = data[1]; - env->regs[R_ECX] = data[2]; env->regs[R_EDX] = data[3]; - env->regs[R_ESI] = data[4]; env->regs[R_EDI] = data[5]; -} - -static const MemoryRegionOps vmport_ops = { - .read = vmport_ioport_read, - .write = vmport_ioport_write, - .impl = { - .min_access_size = 4, - .max_access_size = 4, - }, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - -static int vmport_initfn(ISADevice *dev) -{ - VMPortState *s = DO_UPCAST(VMPortState, dev, dev); - - memory_region_init_io(&s->io, &vmport_ops, s, "vmport", 1); - isa_register_ioport(dev, &s->io, 0x5658); - - port_state = s; - /* Register some generic port commands */ - vmport_register(VMPORT_CMD_GETVERSION, vmport_cmd_get_version, NULL); - vmport_register(VMPORT_CMD_GETRAMSIZE, vmport_cmd_ram_size, NULL); - return 0; -} - -static void vmport_class_initfn(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - ISADeviceClass *ic = ISA_DEVICE_CLASS(klass); - ic->init = vmport_initfn; - dc->no_user = 1; -} - -static const TypeInfo vmport_info = { - .name = "vmport", - .parent = TYPE_ISA_DEVICE, - .instance_size = sizeof(VMPortState), - .class_init = vmport_class_initfn, -}; - -static void vmport_register_types(void) -{ - type_register_static(&vmport_info); -} - -type_init(vmport_register_types) diff --git a/hw/zynq_slcr.c b/hw/zynq_slcr.c deleted file mode 100644 index 8418327261..0000000000 --- a/hw/zynq_slcr.c +++ /dev/null @@ -1,536 +0,0 @@ -/* - * Status and system control registers for Xilinx Zynq Platform - * - * Copyright (c) 2011 Michal Simek - * Copyright (c) 2012 PetaLogix Pty Ltd. - * Based on hw/arm_sysctl.c, written by Paul Brook - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . - */ - -#include "hw/hw.h" -#include "qemu/timer.h" -#include "hw/sysbus.h" -#include "sysemu/sysemu.h" - -#ifdef ZYNQ_ARM_SLCR_ERR_DEBUG -#define DB_PRINT(...) do { \ - fprintf(stderr, ": %s: ", __func__); \ - fprintf(stderr, ## __VA_ARGS__); \ - } while (0); -#else - #define DB_PRINT(...) -#endif - -#define XILINX_LOCK_KEY 0x767b -#define XILINX_UNLOCK_KEY 0xdf0d - -typedef enum { - ARM_PLL_CTRL, - DDR_PLL_CTRL, - IO_PLL_CTRL, - PLL_STATUS, - ARM_PPL_CFG, - DDR_PLL_CFG, - IO_PLL_CFG, - PLL_BG_CTRL, - PLL_MAX -} PLLValues; - -typedef enum { - ARM_CLK_CTRL, - DDR_CLK_CTRL, - DCI_CLK_CTRL, - APER_CLK_CTRL, - USB0_CLK_CTRL, - USB1_CLK_CTRL, - GEM0_RCLK_CTRL, - GEM1_RCLK_CTRL, - GEM0_CLK_CTRL, - GEM1_CLK_CTRL, - SMC_CLK_CTRL, - LQSPI_CLK_CTRL, - SDIO_CLK_CTRL, - UART_CLK_CTRL, - SPI_CLK_CTRL, - CAN_CLK_CTRL, - CAN_MIOCLK_CTRL, - DBG_CLK_CTRL, - PCAP_CLK_CTRL, - TOPSW_CLK_CTRL, - CLK_MAX -} ClkValues; - -typedef enum { - CLK_CTRL, - THR_CTRL, - THR_CNT, - THR_STA, - FPGA_MAX -} FPGAValues; - -typedef enum { - SYNC_CTRL, - SYNC_STATUS, - BANDGAP_TRIP, - CC_TEST, - PLL_PREDIVISOR, - CLK_621_TRUE, - PICTURE_DBG, - PICTURE_DBG_UCNT, - PICTURE_DBG_LCNT, - MISC_MAX -} MiscValues; - -typedef enum { - PSS, - DDDR, - DMAC = 3, - USB, - GEM, - SDIO, - SPI, - CAN, - I2C, - UART, - GPIO, - LQSPI, - SMC, - OCM, - DEVCI, - FPGA, - A9_CPU, - RS_AWDT, - RST_REASON, - RST_REASON_CLR, - REBOOT_STATUS, - BOOT_MODE, - RESET_MAX -} ResetValues; - -typedef struct { - SysBusDevice busdev; - MemoryRegion iomem; - - union { - struct { - uint16_t scl; - uint16_t lockval; - uint32_t pll[PLL_MAX]; /* 0x100 - 0x11C */ - uint32_t clk[CLK_MAX]; /* 0x120 - 0x16C */ - uint32_t fpga[4][FPGA_MAX]; /* 0x170 - 0x1AC */ - uint32_t misc[MISC_MAX]; /* 0x1B0 - 0x1D8 */ - uint32_t reset[RESET_MAX]; /* 0x200 - 0x25C */ - uint32_t apu_ctrl; /* 0x300 */ - uint32_t wdt_clk_sel; /* 0x304 */ - uint32_t tz_ocm[3]; /* 0x400 - 0x408 */ - uint32_t tz_ddr; /* 0x430 */ - uint32_t tz_dma[3]; /* 0x440 - 0x448 */ - uint32_t tz_misc[3]; /* 0x450 - 0x458 */ - uint32_t tz_fpga[2]; /* 0x484 - 0x488 */ - uint32_t dbg_ctrl; /* 0x500 */ - uint32_t pss_idcode; /* 0x530 */ - uint32_t ddr[8]; /* 0x600 - 0x620 - 0x604-missing */ - uint32_t mio[54]; /* 0x700 - 0x7D4 */ - uint32_t mio_func[4]; /* 0x800 - 0x810 */ - uint32_t sd[2]; /* 0x830 - 0x834 */ - uint32_t lvl_shftr_en; /* 0x900 */ - uint32_t ocm_cfg; /* 0x910 */ - uint32_t cpu_ram[8]; /* 0xA00 - 0xA1C */ - uint32_t iou[7]; /* 0xA30 - 0xA48 */ - uint32_t dmac_ram; /* 0xA50 */ - uint32_t afi[4][3]; /* 0xA60 - 0xA8C */ - uint32_t ocm[3]; /* 0xA90 - 0xA98 */ - uint32_t devci_ram; /* 0xAA0 */ - uint32_t csg_ram; /* 0xAB0 */ - uint32_t gpiob[12]; /* 0xB00 - 0xB2C */ - uint32_t ddriob[14]; /* 0xB40 - 0xB74 */ - }; - uint8_t data[0x1000]; - }; -} ZynqSLCRState; - -static void zynq_slcr_reset(DeviceState *d) -{ - int i; - ZynqSLCRState *s = - FROM_SYSBUS(ZynqSLCRState, SYS_BUS_DEVICE(d)); - - DB_PRINT("RESET\n"); - - s->lockval = 1; - /* 0x100 - 0x11C */ - s->pll[ARM_PLL_CTRL] = 0x0001A008; - s->pll[DDR_PLL_CTRL] = 0x0001A008; - s->pll[IO_PLL_CTRL] = 0x0001A008; - s->pll[PLL_STATUS] = 0x0000003F; - s->pll[ARM_PPL_CFG] = 0x00014000; - s->pll[DDR_PLL_CFG] = 0x00014000; - s->pll[IO_PLL_CFG] = 0x00014000; - - /* 0x120 - 0x16C */ - s->clk[ARM_CLK_CTRL] = 0x1F000400; - s->clk[DDR_CLK_CTRL] = 0x18400003; - s->clk[DCI_CLK_CTRL] = 0x01E03201; - s->clk[APER_CLK_CTRL] = 0x01FFCCCD; - s->clk[USB0_CLK_CTRL] = s->clk[USB1_CLK_CTRL] = 0x00101941; - s->clk[GEM0_RCLK_CTRL] = s->clk[GEM1_RCLK_CTRL] = 0x00000001; - s->clk[GEM0_CLK_CTRL] = s->clk[GEM1_CLK_CTRL] = 0x00003C01; - s->clk[SMC_CLK_CTRL] = 0x00003C01; - s->clk[LQSPI_CLK_CTRL] = 0x00002821; - s->clk[SDIO_CLK_CTRL] = 0x00001E03; - s->clk[UART_CLK_CTRL] = 0x00003F03; - s->clk[SPI_CLK_CTRL] = 0x00003F03; - s->clk[CAN_CLK_CTRL] = 0x00501903; - s->clk[DBG_CLK_CTRL] = 0x00000F03; - s->clk[PCAP_CLK_CTRL] = 0x00000F01; - - /* 0x170 - 0x1AC */ - s->fpga[0][CLK_CTRL] = s->fpga[1][CLK_CTRL] = s->fpga[2][CLK_CTRL] = - s->fpga[3][CLK_CTRL] = 0x00101800; - s->fpga[0][THR_STA] = s->fpga[1][THR_STA] = s->fpga[2][THR_STA] = - s->fpga[3][THR_STA] = 0x00010000; - - /* 0x1B0 - 0x1D8 */ - s->misc[BANDGAP_TRIP] = 0x0000001F; - s->misc[PLL_PREDIVISOR] = 0x00000001; - s->misc[CLK_621_TRUE] = 0x00000001; - - /* 0x200 - 0x25C */ - s->reset[FPGA] = 0x01F33F0F; - s->reset[RST_REASON] = 0x00000040; - - /* 0x700 - 0x7D4 */ - for (i = 0; i < 54; i++) { - s->mio[i] = 0x00001601; - } - for (i = 2; i <= 8; i++) { - s->mio[i] = 0x00000601; - } - - /* MIO_MST_TRI0, MIO_MST_TRI1 */ - s->mio_func[2] = s->mio_func[3] = 0xFFFFFFFF; - - s->cpu_ram[0] = s->cpu_ram[1] = s->cpu_ram[3] = - s->cpu_ram[4] = s->cpu_ram[7] = 0x00010101; - s->cpu_ram[2] = s->cpu_ram[5] = 0x01010101; - s->cpu_ram[6] = 0x00000001; - - s->iou[0] = s->iou[1] = s->iou[2] = s->iou[3] = 0x09090909; - s->iou[4] = s->iou[5] = 0x00090909; - s->iou[6] = 0x00000909; - - s->dmac_ram = 0x00000009; - - s->afi[0][0] = s->afi[0][1] = 0x09090909; - s->afi[1][0] = s->afi[1][1] = 0x09090909; - s->afi[2][0] = s->afi[2][1] = 0x09090909; - s->afi[3][0] = s->afi[3][1] = 0x09090909; - s->afi[0][2] = s->afi[1][2] = s->afi[2][2] = s->afi[3][2] = 0x00000909; - - s->ocm[0] = 0x01010101; - s->ocm[1] = s->ocm[2] = 0x09090909; - - s->devci_ram = 0x00000909; - s->csg_ram = 0x00000001; - - s->ddriob[0] = s->ddriob[1] = s->ddriob[2] = s->ddriob[3] = 0x00000e00; - s->ddriob[4] = s->ddriob[5] = s->ddriob[6] = 0x00000e00; - s->ddriob[12] = 0x00000021; -} - -static inline uint32_t zynq_slcr_read_imp(void *opaque, - hwaddr offset) -{ - ZynqSLCRState *s = (ZynqSLCRState *)opaque; - - switch (offset) { - case 0x0: /* SCL */ - return s->scl; - case 0x4: /* LOCK */ - case 0x8: /* UNLOCK */ - DB_PRINT("Reading SCLR_LOCK/UNLOCK is not enabled\n"); - return 0; - case 0x0C: /* LOCKSTA */ - return s->lockval; - case 0x100 ... 0x11C: - return s->pll[(offset - 0x100) / 4]; - case 0x120 ... 0x16C: - return s->clk[(offset - 0x120) / 4]; - case 0x170 ... 0x1AC: - return s->fpga[0][(offset - 0x170) / 4]; - case 0x1B0 ... 0x1D8: - return s->misc[(offset - 0x1B0) / 4]; - case 0x200 ... 0x258: - return s->reset[(offset - 0x200) / 4]; - case 0x25c: - return 1; - case 0x300: - return s->apu_ctrl; - case 0x304: - return s->wdt_clk_sel; - case 0x400 ... 0x408: - return s->tz_ocm[(offset - 0x400) / 4]; - case 0x430: - return s->tz_ddr; - case 0x440 ... 0x448: - return s->tz_dma[(offset - 0x440) / 4]; - case 0x450 ... 0x458: - return s->tz_misc[(offset - 0x450) / 4]; - case 0x484 ... 0x488: - return s->tz_fpga[(offset - 0x484) / 4]; - case 0x500: - return s->dbg_ctrl; - case 0x530: - return s->pss_idcode; - case 0x600 ... 0x620: - if (offset == 0x604) { - goto bad_reg; - } - return s->ddr[(offset - 0x600) / 4]; - case 0x700 ... 0x7D4: - return s->mio[(offset - 0x700) / 4]; - case 0x800 ... 0x810: - return s->mio_func[(offset - 0x800) / 4]; - case 0x830 ... 0x834: - return s->sd[(offset - 0x830) / 4]; - case 0x900: - return s->lvl_shftr_en; - case 0x910: - return s->ocm_cfg; - case 0xA00 ... 0xA1C: - return s->cpu_ram[(offset - 0xA00) / 4]; - case 0xA30 ... 0xA48: - return s->iou[(offset - 0xA30) / 4]; - case 0xA50: - return s->dmac_ram; - case 0xA60 ... 0xA8C: - return s->afi[0][(offset - 0xA60) / 4]; - case 0xA90 ... 0xA98: - return s->ocm[(offset - 0xA90) / 4]; - case 0xAA0: - return s->devci_ram; - case 0xAB0: - return s->csg_ram; - case 0xB00 ... 0xB2C: - return s->gpiob[(offset - 0xB00) / 4]; - case 0xB40 ... 0xB74: - return s->ddriob[(offset - 0xB40) / 4]; - default: - bad_reg: - DB_PRINT("Bad register offset 0x%x\n", (int)offset); - return 0; - } -} - -static uint64_t zynq_slcr_read(void *opaque, hwaddr offset, - unsigned size) -{ - uint32_t ret = zynq_slcr_read_imp(opaque, offset); - - DB_PRINT("addr: %08x data: %08x\n", (unsigned)offset, (unsigned)ret); - return ret; -} - -static void zynq_slcr_write(void *opaque, hwaddr offset, - uint64_t val, unsigned size) -{ - ZynqSLCRState *s = (ZynqSLCRState *)opaque; - - DB_PRINT("offset: %08x data: %08x\n", (unsigned)offset, (unsigned)val); - - switch (offset) { - case 0x00: /* SCL */ - s->scl = val & 0x1; - return; - case 0x4: /* SLCR_LOCK */ - if ((val & 0xFFFF) == XILINX_LOCK_KEY) { - DB_PRINT("XILINX LOCK 0xF8000000 + 0x%x <= 0x%x\n", (int)offset, - (unsigned)val & 0xFFFF); - s->lockval = 1; - } else { - DB_PRINT("WRONG XILINX LOCK KEY 0xF8000000 + 0x%x <= 0x%x\n", - (int)offset, (unsigned)val & 0xFFFF); - } - return; - case 0x8: /* SLCR_UNLOCK */ - if ((val & 0xFFFF) == XILINX_UNLOCK_KEY) { - DB_PRINT("XILINX UNLOCK 0xF8000000 + 0x%x <= 0x%x\n", (int)offset, - (unsigned)val & 0xFFFF); - s->lockval = 0; - } else { - DB_PRINT("WRONG XILINX UNLOCK KEY 0xF8000000 + 0x%x <= 0x%x\n", - (int)offset, (unsigned)val & 0xFFFF); - } - return; - case 0xc: /* LOCKSTA */ - DB_PRINT("Writing SCLR_LOCKSTA is not enabled\n"); - return; - } - - if (!s->lockval) { - switch (offset) { - case 0x100 ... 0x11C: - if (offset == 0x10C) { - goto bad_reg; - } - s->pll[(offset - 0x100) / 4] = val; - break; - case 0x120 ... 0x16C: - s->clk[(offset - 0x120) / 4] = val; - break; - case 0x170 ... 0x1AC: - s->fpga[0][(offset - 0x170) / 4] = val; - break; - case 0x1B0 ... 0x1D8: - s->misc[(offset - 0x1B0) / 4] = val; - break; - case 0x200 ... 0x25C: - if (offset == 0x250) { - goto bad_reg; - } - s->reset[(offset - 0x200) / 4] = val; - break; - case 0x300: - s->apu_ctrl = val; - break; - case 0x304: - s->wdt_clk_sel = val; - break; - case 0x400 ... 0x408: - s->tz_ocm[(offset - 0x400) / 4] = val; - break; - case 0x430: - s->tz_ddr = val; - break; - case 0x440 ... 0x448: - s->tz_dma[(offset - 0x440) / 4] = val; - break; - case 0x450 ... 0x458: - s->tz_misc[(offset - 0x450) / 4] = val; - break; - case 0x484 ... 0x488: - s->tz_fpga[(offset - 0x484) / 4] = val; - break; - case 0x500: - s->dbg_ctrl = val; - break; - case 0x530: - s->pss_idcode = val; - break; - case 0x600 ... 0x620: - if (offset == 0x604) { - goto bad_reg; - } - s->ddr[(offset - 0x600) / 4] = val; - break; - case 0x700 ... 0x7D4: - s->mio[(offset - 0x700) / 4] = val; - break; - case 0x800 ... 0x810: - s->mio_func[(offset - 0x800) / 4] = val; - break; - case 0x830 ... 0x834: - s->sd[(offset - 0x830) / 4] = val; - break; - case 0x900: - s->lvl_shftr_en = val; - break; - case 0x910: - break; - case 0xA00 ... 0xA1C: - s->cpu_ram[(offset - 0xA00) / 4] = val; - break; - case 0xA30 ... 0xA48: - s->iou[(offset - 0xA30) / 4] = val; - break; - case 0xA50: - s->dmac_ram = val; - break; - case 0xA60 ... 0xA8C: - s->afi[0][(offset - 0xA60) / 4] = val; - break; - case 0xA90: - s->ocm[0] = val; - break; - case 0xAA0: - s->devci_ram = val; - break; - case 0xAB0: - s->csg_ram = val; - break; - case 0xB00 ... 0xB2C: - if (offset == 0xB20 || offset == 0xB2C) { - goto bad_reg; - } - s->gpiob[(offset - 0xB00) / 4] = val; - break; - case 0xB40 ... 0xB74: - s->ddriob[(offset - 0xB40) / 4] = val; - break; - default: - bad_reg: - DB_PRINT("Bad register write %x <= %08x\n", (int)offset, - (unsigned)val); - } - } else { - DB_PRINT("SCLR registers are locked. Unlock them first\n"); - } -} - -static const MemoryRegionOps slcr_ops = { - .read = zynq_slcr_read, - .write = zynq_slcr_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static int zynq_slcr_init(SysBusDevice *dev) -{ - ZynqSLCRState *s = FROM_SYSBUS(ZynqSLCRState, dev); - - memory_region_init_io(&s->iomem, &slcr_ops, s, "slcr", 0x1000); - sysbus_init_mmio(dev, &s->iomem); - - return 0; -} - -static const VMStateDescription vmstate_zynq_slcr = { - .name = "zynq_slcr", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT8_ARRAY(data, ZynqSLCRState, 0x1000), - VMSTATE_END_OF_LIST() - } -}; - -static void zynq_slcr_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); - - sdc->init = zynq_slcr_init; - dc->vmsd = &vmstate_zynq_slcr; - dc->reset = zynq_slcr_reset; -} - -static const TypeInfo zynq_slcr_info = { - .class_init = zynq_slcr_class_init, - .name = "xilinx,zynq_slcr", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(ZynqSLCRState), -}; - -static void zynq_slcr_register_types(void) -{ - type_register_static(&zynq_slcr_info); -} - -type_init(zynq_slcr_register_types) -- cgit v1.2.1