diff options
Diffstat (limited to 'qemu/hw/arm')
49 files changed, 0 insertions, 29810 deletions
diff --git a/qemu/hw/arm/Makefile.objs b/qemu/hw/arm/Makefile.objs deleted file mode 100644 index 954c9fe15..000000000 --- a/qemu/hw/arm/Makefile.objs +++ /dev/null @@ -1,19 +0,0 @@ -obj-y += boot.o collie.o exynos4_boards.o gumstix.o highbank.o -obj-$(CONFIG_DIGIC) += digic_boards.o -obj-y += integratorcp.o mainstone.o musicpal.o nseries.o -obj-y += omap_sx1.o palm.o realview.o spitz.o stellaris.o -obj-y += tosa.o versatilepb.o vexpress.o virt.o xilinx_zynq.o z2.o -obj-$(CONFIG_ACPI) += virt-acpi-build.o -obj-y += netduino2.o -obj-y += sysbus-fdt.o - -obj-y += armv7m.o exynos4210.o pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o -obj-$(CONFIG_DIGIC) += digic.o -obj-y += omap1.o omap2.o strongarm.o -obj-$(CONFIG_ALLWINNER_A10) += allwinner-a10.o cubieboard.o -obj-$(CONFIG_RASPI) += bcm2835_peripherals.o bcm2836.o raspi.o -obj-$(CONFIG_STM32F205_SOC) += stm32f205_soc.o -obj-$(CONFIG_XLNX_ZYNQMP) += xlnx-zynqmp.o xlnx-ep108.o -obj-$(CONFIG_FSL_IMX25) += fsl-imx25.o imx25_pdk.o -obj-$(CONFIG_FSL_IMX31) += fsl-imx31.o kzm.o -obj-$(CONFIG_ASPEED_SOC) += ast2400.o palmetto-bmc.o diff --git a/qemu/hw/arm/allwinner-a10.c b/qemu/hw/arm/allwinner-a10.c deleted file mode 100644 index ca15d1c8c..000000000 --- a/qemu/hw/arm/allwinner-a10.c +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Allwinner A10 SoC emulation - * - * Copyright (C) 2013 Li Guang - * Written by Li Guang <lig.fnst@cn.fujitsu.com> - * - * 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. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "qemu-common.h" -#include "cpu.h" -#include "hw/sysbus.h" -#include "hw/devices.h" -#include "hw/arm/allwinner-a10.h" - -static void aw_a10_init(Object *obj) -{ - AwA10State *s = AW_A10(obj); - - object_initialize(&s->cpu, sizeof(s->cpu), "cortex-a8-" TYPE_ARM_CPU); - object_property_add_child(obj, "cpu", OBJECT(&s->cpu), NULL); - - object_initialize(&s->intc, sizeof(s->intc), TYPE_AW_A10_PIC); - qdev_set_parent_bus(DEVICE(&s->intc), sysbus_get_default()); - - object_initialize(&s->timer, sizeof(s->timer), TYPE_AW_A10_PIT); - qdev_set_parent_bus(DEVICE(&s->timer), sysbus_get_default()); - - object_initialize(&s->emac, sizeof(s->emac), TYPE_AW_EMAC); - qdev_set_parent_bus(DEVICE(&s->emac), sysbus_get_default()); - /* FIXME use qdev NIC properties instead of nd_table[] */ - if (nd_table[0].used) { - qemu_check_nic_model(&nd_table[0], TYPE_AW_EMAC); - qdev_set_nic_properties(DEVICE(&s->emac), &nd_table[0]); - } - - object_initialize(&s->sata, sizeof(s->sata), TYPE_ALLWINNER_AHCI); - qdev_set_parent_bus(DEVICE(&s->sata), sysbus_get_default()); -} - -static void aw_a10_realize(DeviceState *dev, Error **errp) -{ - AwA10State *s = AW_A10(dev); - SysBusDevice *sysbusdev; - uint8_t i; - qemu_irq fiq, irq; - Error *err = NULL; - - object_property_set_bool(OBJECT(&s->cpu), true, "realized", &err); - if (err != NULL) { - error_propagate(errp, err); - return; - } - irq = qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_IRQ); - fiq = qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_FIQ); - - object_property_set_bool(OBJECT(&s->intc), true, "realized", &err); - if (err != NULL) { - error_propagate(errp, err); - return; - } - sysbusdev = SYS_BUS_DEVICE(&s->intc); - sysbus_mmio_map(sysbusdev, 0, AW_A10_PIC_REG_BASE); - sysbus_connect_irq(sysbusdev, 0, irq); - sysbus_connect_irq(sysbusdev, 1, fiq); - for (i = 0; i < AW_A10_PIC_INT_NR; i++) { - s->irq[i] = qdev_get_gpio_in(DEVICE(&s->intc), i); - } - - object_property_set_bool(OBJECT(&s->timer), true, "realized", &err); - if (err != NULL) { - error_propagate(errp, err); - return; - } - sysbusdev = SYS_BUS_DEVICE(&s->timer); - sysbus_mmio_map(sysbusdev, 0, AW_A10_PIT_REG_BASE); - sysbus_connect_irq(sysbusdev, 0, s->irq[22]); - sysbus_connect_irq(sysbusdev, 1, s->irq[23]); - sysbus_connect_irq(sysbusdev, 2, s->irq[24]); - sysbus_connect_irq(sysbusdev, 3, s->irq[25]); - sysbus_connect_irq(sysbusdev, 4, s->irq[67]); - sysbus_connect_irq(sysbusdev, 5, s->irq[68]); - - object_property_set_bool(OBJECT(&s->emac), true, "realized", &err); - if (err != NULL) { - error_propagate(errp, err); - return; - } - sysbusdev = SYS_BUS_DEVICE(&s->emac); - sysbus_mmio_map(sysbusdev, 0, AW_A10_EMAC_BASE); - sysbus_connect_irq(sysbusdev, 0, s->irq[55]); - - object_property_set_bool(OBJECT(&s->sata), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->sata), 0, AW_A10_SATA_BASE); - sysbus_connect_irq(SYS_BUS_DEVICE(&s->sata), 0, s->irq[56]); - - /* FIXME use a qdev chardev prop instead of serial_hds[] */ - serial_mm_init(get_system_memory(), AW_A10_UART0_REG_BASE, 2, s->irq[1], - 115200, serial_hds[0], DEVICE_NATIVE_ENDIAN); -} - -static void aw_a10_class_init(ObjectClass *oc, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(oc); - - dc->realize = aw_a10_realize; - - /* - * Reason: creates an ARM CPU, thus use after free(), see - * arm_cpu_class_init() - */ - dc->cannot_destroy_with_object_finalize_yet = true; -} - -static const TypeInfo aw_a10_type_info = { - .name = TYPE_AW_A10, - .parent = TYPE_DEVICE, - .instance_size = sizeof(AwA10State), - .instance_init = aw_a10_init, - .class_init = aw_a10_class_init, -}; - -static void aw_a10_register_types(void) -{ - type_register_static(&aw_a10_type_info); -} - -type_init(aw_a10_register_types) diff --git a/qemu/hw/arm/armv7m.c b/qemu/hw/arm/armv7m.c deleted file mode 100644 index bb2a22d96..000000000 --- a/qemu/hw/arm/armv7m.c +++ /dev/null @@ -1,265 +0,0 @@ -/* - * ARMV7M System emulation. - * - * Copyright (c) 2006-2007 CodeSourcery. - * Written by Paul Brook - * - * This code is licensed under the GPL. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "qemu-common.h" -#include "cpu.h" -#include "hw/sysbus.h" -#include "hw/arm/arm.h" -#include "hw/loader.h" -#include "elf.h" -#include "sysemu/qtest.h" -#include "qemu/error-report.h" - -/* Bitbanded IO. Each word corresponds to a single bit. */ - -/* Get the byte address of the real memory for a bitband access. */ -static inline uint32_t bitband_addr(void * opaque, uint32_t addr) -{ - uint32_t res; - - res = *(uint32_t *)opaque; - res |= (addr & 0x1ffffff) >> 5; - return res; - -} - -static uint32_t bitband_readb(void *opaque, hwaddr offset) -{ - uint8_t v; - cpu_physical_memory_read(bitband_addr(opaque, offset), &v, 1); - return (v & (1 << ((offset >> 2) & 7))) != 0; -} - -static void bitband_writeb(void *opaque, hwaddr offset, - uint32_t value) -{ - uint32_t addr; - uint8_t mask; - uint8_t v; - addr = bitband_addr(opaque, offset); - mask = (1 << ((offset >> 2) & 7)); - cpu_physical_memory_read(addr, &v, 1); - if (value & 1) - v |= mask; - else - v &= ~mask; - cpu_physical_memory_write(addr, &v, 1); -} - -static uint32_t bitband_readw(void *opaque, hwaddr offset) -{ - uint32_t addr; - uint16_t mask; - uint16_t v; - addr = bitband_addr(opaque, offset) & ~1; - mask = (1 << ((offset >> 2) & 15)); - mask = tswap16(mask); - cpu_physical_memory_read(addr, &v, 2); - return (v & mask) != 0; -} - -static void bitband_writew(void *opaque, hwaddr offset, - uint32_t value) -{ - uint32_t addr; - uint16_t mask; - uint16_t v; - addr = bitband_addr(opaque, offset) & ~1; - mask = (1 << ((offset >> 2) & 15)); - mask = tswap16(mask); - cpu_physical_memory_read(addr, &v, 2); - if (value & 1) - v |= mask; - else - v &= ~mask; - cpu_physical_memory_write(addr, &v, 2); -} - -static uint32_t bitband_readl(void *opaque, hwaddr offset) -{ - uint32_t addr; - uint32_t mask; - uint32_t v; - addr = bitband_addr(opaque, offset) & ~3; - mask = (1 << ((offset >> 2) & 31)); - mask = tswap32(mask); - cpu_physical_memory_read(addr, &v, 4); - return (v & mask) != 0; -} - -static void bitband_writel(void *opaque, hwaddr offset, - uint32_t value) -{ - uint32_t addr; - uint32_t mask; - uint32_t v; - addr = bitband_addr(opaque, offset) & ~3; - mask = (1 << ((offset >> 2) & 31)); - mask = tswap32(mask); - cpu_physical_memory_read(addr, &v, 4); - if (value & 1) - v |= mask; - else - v &= ~mask; - cpu_physical_memory_write(addr, &v, 4); -} - -static const MemoryRegionOps bitband_ops = { - .old_mmio = { - .read = { bitband_readb, bitband_readw, bitband_readl, }, - .write = { bitband_writeb, bitband_writew, bitband_writel, }, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -#define TYPE_BITBAND "ARM,bitband-memory" -#define BITBAND(obj) OBJECT_CHECK(BitBandState, (obj), TYPE_BITBAND) - -typedef struct { - /*< private >*/ - SysBusDevice parent_obj; - /*< public >*/ - - MemoryRegion iomem; - uint32_t base; -} BitBandState; - -static int bitband_init(SysBusDevice *dev) -{ - BitBandState *s = BITBAND(dev); - - memory_region_init_io(&s->iomem, OBJECT(s), &bitband_ops, &s->base, - "bitband", 0x02000000); - sysbus_init_mmio(dev, &s->iomem); - return 0; -} - -static void armv7m_bitband_init(void) -{ - DeviceState *dev; - - dev = qdev_create(NULL, TYPE_BITBAND); - qdev_prop_set_uint32(dev, "base", 0x20000000); - qdev_init_nofail(dev); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x22000000); - - dev = qdev_create(NULL, TYPE_BITBAND); - qdev_prop_set_uint32(dev, "base", 0x40000000); - qdev_init_nofail(dev); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x42000000); -} - -/* Board init. */ - -static void armv7m_reset(void *opaque) -{ - ARMCPU *cpu = opaque; - - cpu_reset(CPU(cpu)); -} - -/* Init CPU and memory for a v7-M based board. - mem_size is in bytes. - Returns the NVIC array. */ - -DeviceState *armv7m_init(MemoryRegion *system_memory, int mem_size, int num_irq, - const char *kernel_filename, const char *cpu_model) -{ - ARMCPU *cpu; - CPUARMState *env; - DeviceState *nvic; - int image_size; - uint64_t entry; - uint64_t lowaddr; - int big_endian; - MemoryRegion *hack = g_new(MemoryRegion, 1); - - if (cpu_model == NULL) { - cpu_model = "cortex-m3"; - } - cpu = cpu_arm_init(cpu_model); - if (cpu == NULL) { - fprintf(stderr, "Unable to find CPU definition\n"); - exit(1); - } - env = &cpu->env; - - armv7m_bitband_init(); - - nvic = qdev_create(NULL, "armv7m_nvic"); - qdev_prop_set_uint32(nvic, "num-irq", num_irq); - env->nvic = nvic; - qdev_init_nofail(nvic); - sysbus_connect_irq(SYS_BUS_DEVICE(nvic), 0, - qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ)); - -#ifdef TARGET_WORDS_BIGENDIAN - big_endian = 1; -#else - big_endian = 0; -#endif - - if (!kernel_filename && !qtest_enabled()) { - fprintf(stderr, "Guest image must be specified (using -kernel)\n"); - exit(1); - } - - if (kernel_filename) { - image_size = load_elf(kernel_filename, NULL, NULL, &entry, &lowaddr, - NULL, big_endian, EM_ARM, 1, 0); - if (image_size < 0) { - image_size = load_image_targphys(kernel_filename, 0, mem_size); - lowaddr = 0; - } - if (image_size < 0) { - error_report("Could not load kernel '%s'", kernel_filename); - exit(1); - } - } - - /* Hack to map an additional page of ram at the top of the address - space. This stops qemu complaining about executing code outside RAM - when returning from an exception. */ - memory_region_init_ram(hack, NULL, "armv7m.hack", 0x1000, &error_fatal); - vmstate_register_ram_global(hack); - memory_region_add_subregion(system_memory, 0xfffff000, hack); - - qemu_register_reset(armv7m_reset, cpu); - return nvic; -} - -static Property bitband_properties[] = { - DEFINE_PROP_UINT32("base", BitBandState, base, 0), - DEFINE_PROP_END_OF_LIST(), -}; - -static void bitband_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = bitband_init; - dc->props = bitband_properties; -} - -static const TypeInfo bitband_info = { - .name = TYPE_BITBAND, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(BitBandState), - .class_init = bitband_class_init, -}; - -static void armv7m_register_types(void) -{ - type_register_static(&bitband_info); -} - -type_init(armv7m_register_types) diff --git a/qemu/hw/arm/ast2400.c b/qemu/hw/arm/ast2400.c deleted file mode 100644 index 03f993863..000000000 --- a/qemu/hw/arm/ast2400.c +++ /dev/null @@ -1,140 +0,0 @@ -/* - * AST2400 SoC - * - * Andrew Jeffery <andrew@aj.id.au> - * Jeremy Kerr <jk@ozlabs.org> - * - * Copyright 2016 IBM Corp. - * - * This code is licensed under the GPL version 2 or later. See - * the COPYING file in the top-level directory. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "qemu-common.h" -#include "cpu.h" -#include "exec/address-spaces.h" -#include "hw/arm/ast2400.h" -#include "hw/char/serial.h" - -#define AST2400_UART_5_BASE 0x00184000 -#define AST2400_IOMEM_SIZE 0x00200000 -#define AST2400_IOMEM_BASE 0x1E600000 -#define AST2400_VIC_BASE 0x1E6C0000 -#define AST2400_TIMER_BASE 0x1E782000 - -static const int uart_irqs[] = { 9, 32, 33, 34, 10 }; -static const int timer_irqs[] = { 16, 17, 18, 35, 36, 37, 38, 39, }; - -/* - * IO handlers: simply catch any reads/writes to IO addresses that aren't - * handled by a device mapping. - */ - -static uint64_t ast2400_io_read(void *p, hwaddr offset, unsigned size) -{ - qemu_log_mask(LOG_UNIMP, "%s: 0x%" HWADDR_PRIx " [%u]\n", - __func__, offset, size); - return 0; -} - -static void ast2400_io_write(void *opaque, hwaddr offset, uint64_t value, - unsigned size) -{ - qemu_log_mask(LOG_UNIMP, "%s: 0x%" HWADDR_PRIx " <- 0x%" PRIx64 " [%u]\n", - __func__, offset, value, size); -} - -static const MemoryRegionOps ast2400_io_ops = { - .read = ast2400_io_read, - .write = ast2400_io_write, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - -static void ast2400_init(Object *obj) -{ - AST2400State *s = AST2400(obj); - - s->cpu = cpu_arm_init("arm926"); - - object_initialize(&s->vic, sizeof(s->vic), TYPE_ASPEED_VIC); - object_property_add_child(obj, "vic", OBJECT(&s->vic), NULL); - qdev_set_parent_bus(DEVICE(&s->vic), sysbus_get_default()); - - object_initialize(&s->timerctrl, sizeof(s->timerctrl), TYPE_ASPEED_TIMER); - object_property_add_child(obj, "timerctrl", OBJECT(&s->timerctrl), NULL); - qdev_set_parent_bus(DEVICE(&s->timerctrl), sysbus_get_default()); -} - -static void ast2400_realize(DeviceState *dev, Error **errp) -{ - int i; - AST2400State *s = AST2400(dev); - Error *err = NULL; - - /* IO space */ - memory_region_init_io(&s->iomem, NULL, &ast2400_io_ops, NULL, - "ast2400.io", AST2400_IOMEM_SIZE); - memory_region_add_subregion_overlap(get_system_memory(), AST2400_IOMEM_BASE, - &s->iomem, -1); - - /* VIC */ - object_property_set_bool(OBJECT(&s->vic), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->vic), 0, AST2400_VIC_BASE); - sysbus_connect_irq(SYS_BUS_DEVICE(&s->vic), 0, - qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_IRQ)); - sysbus_connect_irq(SYS_BUS_DEVICE(&s->vic), 1, - qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_FIQ)); - - /* Timer */ - object_property_set_bool(OBJECT(&s->timerctrl), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->timerctrl), 0, AST2400_TIMER_BASE); - for (i = 0; i < ARRAY_SIZE(timer_irqs); i++) { - qemu_irq irq = qdev_get_gpio_in(DEVICE(&s->vic), timer_irqs[i]); - sysbus_connect_irq(SYS_BUS_DEVICE(&s->timerctrl), i, irq); - } - - /* UART - attach an 8250 to the IO space as our UART5 */ - if (serial_hds[0]) { - qemu_irq uart5 = qdev_get_gpio_in(DEVICE(&s->vic), uart_irqs[4]); - serial_mm_init(&s->iomem, AST2400_UART_5_BASE, 2, - uart5, 38400, serial_hds[0], DEVICE_LITTLE_ENDIAN); - } -} - -static void ast2400_class_init(ObjectClass *oc, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(oc); - - dc->realize = ast2400_realize; - - /* - * Reason: creates an ARM CPU, thus use after free(), see - * arm_cpu_class_init() - */ - dc->cannot_destroy_with_object_finalize_yet = true; -} - -static const TypeInfo ast2400_type_info = { - .name = TYPE_AST2400, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(AST2400State), - .instance_init = ast2400_init, - .class_init = ast2400_class_init, -}; - -static void ast2400_register_types(void) -{ - type_register_static(&ast2400_type_info); -} - -type_init(ast2400_register_types) diff --git a/qemu/hw/arm/bcm2835_peripherals.c b/qemu/hw/arm/bcm2835_peripherals.c deleted file mode 100644 index 234d51843..000000000 --- a/qemu/hw/arm/bcm2835_peripherals.c +++ /dev/null @@ -1,312 +0,0 @@ -/* - * Raspberry Pi emulation (c) 2012 Gregory Estrade - * Upstreaming code cleanup [including bcm2835_*] (c) 2013 Jan Petrous - * - * Rasperry Pi 2 emulation and refactoring Copyright (c) 2015, Microsoft - * Written by Andrew Baumann - * - * This code is licensed under the GNU GPLv2 and later. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "hw/arm/bcm2835_peripherals.h" -#include "hw/misc/bcm2835_mbox_defs.h" -#include "hw/arm/raspi_platform.h" -#include "sysemu/char.h" - -/* Peripheral base address on the VC (GPU) system bus */ -#define BCM2835_VC_PERI_BASE 0x7e000000 - -/* Capabilities for SD controller: no DMA, high-speed, default clocks etc. */ -#define BCM2835_SDHC_CAPAREG 0x52034b4 - -static void bcm2835_peripherals_init(Object *obj) -{ - BCM2835PeripheralState *s = BCM2835_PERIPHERALS(obj); - - /* Memory region for peripheral devices, which we export to our parent */ - memory_region_init(&s->peri_mr, obj,"bcm2835-peripherals", 0x1000000); - object_property_add_child(obj, "peripheral-io", OBJECT(&s->peri_mr), NULL); - sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->peri_mr); - - /* Internal memory region for peripheral bus addresses (not exported) */ - memory_region_init(&s->gpu_bus_mr, obj, "bcm2835-gpu", (uint64_t)1 << 32); - object_property_add_child(obj, "gpu-bus", OBJECT(&s->gpu_bus_mr), NULL); - - /* Internal memory region for request/response communication with - * mailbox-addressable peripherals (not exported) - */ - memory_region_init(&s->mbox_mr, obj, "bcm2835-mbox", - MBOX_CHAN_COUNT << MBOX_AS_CHAN_SHIFT); - - /* Interrupt Controller */ - object_initialize(&s->ic, sizeof(s->ic), TYPE_BCM2835_IC); - object_property_add_child(obj, "ic", OBJECT(&s->ic), NULL); - qdev_set_parent_bus(DEVICE(&s->ic), sysbus_get_default()); - - /* UART0 */ - s->uart0 = SYS_BUS_DEVICE(object_new("pl011")); - object_property_add_child(obj, "uart0", OBJECT(s->uart0), NULL); - qdev_set_parent_bus(DEVICE(s->uart0), sysbus_get_default()); - - /* AUX / UART1 */ - object_initialize(&s->aux, sizeof(s->aux), TYPE_BCM2835_AUX); - object_property_add_child(obj, "aux", OBJECT(&s->aux), NULL); - qdev_set_parent_bus(DEVICE(&s->aux), sysbus_get_default()); - - /* Mailboxes */ - object_initialize(&s->mboxes, sizeof(s->mboxes), TYPE_BCM2835_MBOX); - object_property_add_child(obj, "mbox", OBJECT(&s->mboxes), NULL); - qdev_set_parent_bus(DEVICE(&s->mboxes), sysbus_get_default()); - - object_property_add_const_link(OBJECT(&s->mboxes), "mbox-mr", - OBJECT(&s->mbox_mr), &error_abort); - - /* Framebuffer */ - object_initialize(&s->fb, sizeof(s->fb), TYPE_BCM2835_FB); - object_property_add_child(obj, "fb", OBJECT(&s->fb), NULL); - object_property_add_alias(obj, "vcram-size", OBJECT(&s->fb), "vcram-size", - &error_abort); - qdev_set_parent_bus(DEVICE(&s->fb), sysbus_get_default()); - - object_property_add_const_link(OBJECT(&s->fb), "dma-mr", - OBJECT(&s->gpu_bus_mr), &error_abort); - - /* Property channel */ - object_initialize(&s->property, sizeof(s->property), TYPE_BCM2835_PROPERTY); - object_property_add_child(obj, "property", OBJECT(&s->property), NULL); - object_property_add_alias(obj, "board-rev", OBJECT(&s->property), - "board-rev", &error_abort); - qdev_set_parent_bus(DEVICE(&s->property), sysbus_get_default()); - - object_property_add_const_link(OBJECT(&s->property), "fb", - OBJECT(&s->fb), &error_abort); - object_property_add_const_link(OBJECT(&s->property), "dma-mr", - OBJECT(&s->gpu_bus_mr), &error_abort); - - /* Extended Mass Media Controller */ - object_initialize(&s->sdhci, sizeof(s->sdhci), TYPE_SYSBUS_SDHCI); - object_property_add_child(obj, "sdhci", OBJECT(&s->sdhci), NULL); - qdev_set_parent_bus(DEVICE(&s->sdhci), sysbus_get_default()); - - /* DMA Channels */ - object_initialize(&s->dma, sizeof(s->dma), TYPE_BCM2835_DMA); - object_property_add_child(obj, "dma", OBJECT(&s->dma), NULL); - qdev_set_parent_bus(DEVICE(&s->dma), sysbus_get_default()); - - object_property_add_const_link(OBJECT(&s->dma), "dma-mr", - OBJECT(&s->gpu_bus_mr), &error_abort); -} - -static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) -{ - BCM2835PeripheralState *s = BCM2835_PERIPHERALS(dev); - Object *obj; - MemoryRegion *ram; - Error *err = NULL; - uint32_t ram_size, vcram_size; - CharDriverState *chr; - int n; - - obj = object_property_get_link(OBJECT(dev), "ram", &err); - if (obj == NULL) { - error_setg(errp, "%s: required ram link not found: %s", - __func__, error_get_pretty(err)); - return; - } - - ram = MEMORY_REGION(obj); - ram_size = memory_region_size(ram); - - /* Map peripherals and RAM into the GPU address space. */ - memory_region_init_alias(&s->peri_mr_alias, OBJECT(s), - "bcm2835-peripherals", &s->peri_mr, 0, - memory_region_size(&s->peri_mr)); - - memory_region_add_subregion_overlap(&s->gpu_bus_mr, BCM2835_VC_PERI_BASE, - &s->peri_mr_alias, 1); - - /* RAM is aliased four times (different cache configurations) on the GPU */ - for (n = 0; n < 4; n++) { - memory_region_init_alias(&s->ram_alias[n], OBJECT(s), - "bcm2835-gpu-ram-alias[*]", ram, 0, ram_size); - memory_region_add_subregion_overlap(&s->gpu_bus_mr, (hwaddr)n << 30, - &s->ram_alias[n], 0); - } - - /* Interrupt Controller */ - object_property_set_bool(OBJECT(&s->ic), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - - memory_region_add_subregion(&s->peri_mr, ARMCTRL_IC_OFFSET, - sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->ic), 0)); - sysbus_pass_irq(SYS_BUS_DEVICE(s), SYS_BUS_DEVICE(&s->ic)); - - /* UART0 */ - object_property_set_bool(OBJECT(s->uart0), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - - memory_region_add_subregion(&s->peri_mr, UART0_OFFSET, - sysbus_mmio_get_region(s->uart0, 0)); - sysbus_connect_irq(s->uart0, 0, - qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ, - INTERRUPT_UART)); - - /* AUX / UART1 */ - /* TODO: don't call qemu_char_get_next_serial() here, instead set - * chardev properties for each uart at the board level, once pl011 - * (uart0) has been updated to avoid qemu_char_get_next_serial() - */ - chr = qemu_char_get_next_serial(); - if (chr == NULL) { - chr = qemu_chr_new("bcm2835.uart1", "null", NULL); - } - qdev_prop_set_chr(DEVICE(&s->aux), "chardev", chr); - - object_property_set_bool(OBJECT(&s->aux), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - - memory_region_add_subregion(&s->peri_mr, UART1_OFFSET, - sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->aux), 0)); - sysbus_connect_irq(SYS_BUS_DEVICE(&s->aux), 0, - qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ, - INTERRUPT_AUX)); - - /* Mailboxes */ - object_property_set_bool(OBJECT(&s->mboxes), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - - memory_region_add_subregion(&s->peri_mr, ARMCTRL_0_SBM_OFFSET, - sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->mboxes), 0)); - sysbus_connect_irq(SYS_BUS_DEVICE(&s->mboxes), 0, - qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_ARM_IRQ, - INTERRUPT_ARM_MAILBOX)); - - /* Framebuffer */ - vcram_size = (uint32_t)object_property_get_int(OBJECT(s), "vcram-size", - &err); - if (err) { - error_propagate(errp, err); - return; - } - - object_property_set_int(OBJECT(&s->fb), ram_size - vcram_size, - "vcram-base", &err); - if (err) { - error_propagate(errp, err); - return; - } - - object_property_set_bool(OBJECT(&s->fb), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - - memory_region_add_subregion(&s->mbox_mr, MBOX_CHAN_FB << MBOX_AS_CHAN_SHIFT, - sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->fb), 0)); - sysbus_connect_irq(SYS_BUS_DEVICE(&s->fb), 0, - qdev_get_gpio_in(DEVICE(&s->mboxes), MBOX_CHAN_FB)); - - /* Property channel */ - object_property_set_bool(OBJECT(&s->property), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - - memory_region_add_subregion(&s->mbox_mr, - MBOX_CHAN_PROPERTY << MBOX_AS_CHAN_SHIFT, - sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->property), 0)); - sysbus_connect_irq(SYS_BUS_DEVICE(&s->property), 0, - qdev_get_gpio_in(DEVICE(&s->mboxes), MBOX_CHAN_PROPERTY)); - - /* Extended Mass Media Controller */ - object_property_set_int(OBJECT(&s->sdhci), BCM2835_SDHC_CAPAREG, "capareg", - &err); - if (err) { - error_propagate(errp, err); - return; - } - - object_property_set_bool(OBJECT(&s->sdhci), true, "pending-insert-quirk", - &err); - if (err) { - error_propagate(errp, err); - return; - } - - object_property_set_bool(OBJECT(&s->sdhci), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - - memory_region_add_subregion(&s->peri_mr, EMMC_OFFSET, - sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->sdhci), 0)); - sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdhci), 0, - qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ, - INTERRUPT_ARASANSDIO)); - object_property_add_alias(OBJECT(s), "sd-bus", OBJECT(&s->sdhci), "sd-bus", - &err); - if (err) { - error_propagate(errp, err); - return; - } - - /* DMA Channels */ - object_property_set_bool(OBJECT(&s->dma), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - - memory_region_add_subregion(&s->peri_mr, DMA_OFFSET, - sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->dma), 0)); - memory_region_add_subregion(&s->peri_mr, DMA15_OFFSET, - sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->dma), 1)); - - for (n = 0; n <= 12; n++) { - sysbus_connect_irq(SYS_BUS_DEVICE(&s->dma), n, - qdev_get_gpio_in_named(DEVICE(&s->ic), - BCM2835_IC_GPU_IRQ, - INTERRUPT_DMA0 + n)); - } -} - -static void bcm2835_peripherals_class_init(ObjectClass *oc, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(oc); - - dc->realize = bcm2835_peripherals_realize; - /* Reason: realize() method uses qemu_char_get_next_serial() */ - dc->cannot_instantiate_with_device_add_yet = true; -} - -static const TypeInfo bcm2835_peripherals_type_info = { - .name = TYPE_BCM2835_PERIPHERALS, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(BCM2835PeripheralState), - .instance_init = bcm2835_peripherals_init, - .class_init = bcm2835_peripherals_class_init, -}; - -static void bcm2835_peripherals_register_types(void) -{ - type_register_static(&bcm2835_peripherals_type_info); -} - -type_init(bcm2835_peripherals_register_types) diff --git a/qemu/hw/arm/bcm2836.c b/qemu/hw/arm/bcm2836.c deleted file mode 100644 index 8451190a1..000000000 --- a/qemu/hw/arm/bcm2836.c +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Raspberry Pi emulation (c) 2012 Gregory Estrade - * Upstreaming code cleanup [including bcm2835_*] (c) 2013 Jan Petrous - * - * Rasperry Pi 2 emulation and refactoring Copyright (c) 2015, Microsoft - * Written by Andrew Baumann - * - * This code is licensed under the GNU GPLv2 and later. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "qemu-common.h" -#include "cpu.h" -#include "hw/arm/bcm2836.h" -#include "hw/arm/raspi_platform.h" -#include "hw/sysbus.h" -#include "exec/address-spaces.h" - -/* Peripheral base address seen by the CPU */ -#define BCM2836_PERI_BASE 0x3F000000 - -/* "QA7" (Pi2) interrupt controller and mailboxes etc. */ -#define BCM2836_CONTROL_BASE 0x40000000 - -static void bcm2836_init(Object *obj) -{ - BCM2836State *s = BCM2836(obj); - int n; - - for (n = 0; n < BCM2836_NCPUS; n++) { - object_initialize(&s->cpus[n], sizeof(s->cpus[n]), - "cortex-a15-" TYPE_ARM_CPU); - object_property_add_child(obj, "cpu[*]", OBJECT(&s->cpus[n]), - &error_abort); - } - - object_initialize(&s->control, sizeof(s->control), TYPE_BCM2836_CONTROL); - object_property_add_child(obj, "control", OBJECT(&s->control), NULL); - qdev_set_parent_bus(DEVICE(&s->control), sysbus_get_default()); - - object_initialize(&s->peripherals, sizeof(s->peripherals), - TYPE_BCM2835_PERIPHERALS); - object_property_add_child(obj, "peripherals", OBJECT(&s->peripherals), - &error_abort); - object_property_add_alias(obj, "board-rev", OBJECT(&s->peripherals), - "board-rev", &error_abort); - object_property_add_alias(obj, "vcram-size", OBJECT(&s->peripherals), - "vcram-size", &error_abort); - qdev_set_parent_bus(DEVICE(&s->peripherals), sysbus_get_default()); -} - -static void bcm2836_realize(DeviceState *dev, Error **errp) -{ - BCM2836State *s = BCM2836(dev); - Object *obj; - Error *err = NULL; - int n; - - /* common peripherals from bcm2835 */ - - obj = object_property_get_link(OBJECT(dev), "ram", &err); - if (obj == NULL) { - error_setg(errp, "%s: required ram link not found: %s", - __func__, error_get_pretty(err)); - return; - } - - object_property_add_const_link(OBJECT(&s->peripherals), "ram", obj, &err); - if (err) { - error_propagate(errp, err); - return; - } - - object_property_set_bool(OBJECT(&s->peripherals), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - - object_property_add_alias(OBJECT(s), "sd-bus", OBJECT(&s->peripherals), - "sd-bus", &err); - if (err) { - error_propagate(errp, err); - return; - } - - sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->peripherals), 0, - BCM2836_PERI_BASE, 1); - - /* bcm2836 interrupt controller (and mailboxes, etc.) */ - object_property_set_bool(OBJECT(&s->control), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - - sysbus_mmio_map(SYS_BUS_DEVICE(&s->control), 0, BCM2836_CONTROL_BASE); - - sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 0, - qdev_get_gpio_in_named(DEVICE(&s->control), "gpu-irq", 0)); - sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 1, - qdev_get_gpio_in_named(DEVICE(&s->control), "gpu-fiq", 0)); - - for (n = 0; n < BCM2836_NCPUS; n++) { - /* Mirror bcm2836, which has clusterid set to 0xf - * TODO: this should be converted to a property of ARM_CPU - */ - s->cpus[n].mp_affinity = 0xF00 | n; - - /* set periphbase/CBAR value for CPU-local registers */ - object_property_set_int(OBJECT(&s->cpus[n]), - BCM2836_PERI_BASE + MCORE_OFFSET, - "reset-cbar", &err); - if (err) { - error_propagate(errp, err); - return; - } - - /* start powered off if not enabled */ - object_property_set_bool(OBJECT(&s->cpus[n]), n >= s->enabled_cpus, - "start-powered-off", &err); - if (err) { - error_propagate(errp, err); - return; - } - - object_property_set_bool(OBJECT(&s->cpus[n]), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - - /* Connect irq/fiq outputs from the interrupt controller. */ - qdev_connect_gpio_out_named(DEVICE(&s->control), "irq", n, - qdev_get_gpio_in(DEVICE(&s->cpus[n]), ARM_CPU_IRQ)); - qdev_connect_gpio_out_named(DEVICE(&s->control), "fiq", n, - qdev_get_gpio_in(DEVICE(&s->cpus[n]), ARM_CPU_FIQ)); - - /* Connect timers from the CPU to the interrupt controller */ - qdev_connect_gpio_out(DEVICE(&s->cpus[n]), GTIMER_PHYS, - qdev_get_gpio_in_named(DEVICE(&s->control), "cntpnsirq", n)); - qdev_connect_gpio_out(DEVICE(&s->cpus[n]), GTIMER_VIRT, - qdev_get_gpio_in_named(DEVICE(&s->control), "cntvirq", n)); - qdev_connect_gpio_out(DEVICE(&s->cpus[n]), GTIMER_HYP, - qdev_get_gpio_in_named(DEVICE(&s->control), "cnthpirq", n)); - qdev_connect_gpio_out(DEVICE(&s->cpus[n]), GTIMER_SEC, - qdev_get_gpio_in_named(DEVICE(&s->control), "cntpsirq", n)); - } -} - -static Property bcm2836_props[] = { - DEFINE_PROP_UINT32("enabled-cpus", BCM2836State, enabled_cpus, BCM2836_NCPUS), - DEFINE_PROP_END_OF_LIST() -}; - -static void bcm2836_class_init(ObjectClass *oc, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(oc); - - dc->props = bcm2836_props; - dc->realize = bcm2836_realize; - - /* - * Reason: creates an ARM CPU, thus use after free(), see - * arm_cpu_class_init() - */ - dc->cannot_destroy_with_object_finalize_yet = true; -} - -static const TypeInfo bcm2836_type_info = { - .name = TYPE_BCM2836, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(BCM2836State), - .instance_init = bcm2836_init, - .class_init = bcm2836_class_init, -}; - -static void bcm2836_register_types(void) -{ - type_register_static(&bcm2836_type_info); -} - -type_init(bcm2836_register_types) diff --git a/qemu/hw/arm/boot.c b/qemu/hw/arm/boot.c deleted file mode 100644 index 587694557..000000000 --- a/qemu/hw/arm/boot.c +++ /dev/null @@ -1,994 +0,0 @@ -/* - * ARM kernel loader. - * - * Copyright (c) 2006-2007 CodeSourcery. - * Written by Paul Brook - * - * This code is licensed under the GPL. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "hw/hw.h" -#include "hw/arm/arm.h" -#include "hw/arm/linux-boot-if.h" -#include "sysemu/kvm.h" -#include "sysemu/sysemu.h" -#include "hw/boards.h" -#include "hw/loader.h" -#include "elf.h" -#include "sysemu/device_tree.h" -#include "qemu/config-file.h" -#include "exec/address-spaces.h" - -/* Kernel boot protocol is specified in the kernel docs - * Documentation/arm/Booting and Documentation/arm64/booting.txt - * They have different preferred image load offsets from system RAM base. - */ -#define KERNEL_ARGS_ADDR 0x100 -#define KERNEL_LOAD_ADDR 0x00010000 -#define KERNEL64_LOAD_ADDR 0x00080000 - -typedef enum { - FIXUP_NONE = 0, /* do nothing */ - FIXUP_TERMINATOR, /* end of insns */ - FIXUP_BOARDID, /* overwrite with board ID number */ - FIXUP_BOARD_SETUP, /* overwrite with board specific setup code address */ - FIXUP_ARGPTR, /* overwrite with pointer to kernel args */ - FIXUP_ENTRYPOINT, /* overwrite with kernel entry point */ - FIXUP_GIC_CPU_IF, /* overwrite with GIC CPU interface address */ - FIXUP_BOOTREG, /* overwrite with boot register address */ - FIXUP_DSB, /* overwrite with correct DSB insn for cpu */ - FIXUP_MAX, -} FixupType; - -typedef struct ARMInsnFixup { - uint32_t insn; - FixupType fixup; -} ARMInsnFixup; - -static const ARMInsnFixup bootloader_aarch64[] = { - { 0x580000c0 }, /* ldr x0, arg ; Load the lower 32-bits of DTB */ - { 0xaa1f03e1 }, /* mov x1, xzr */ - { 0xaa1f03e2 }, /* mov x2, xzr */ - { 0xaa1f03e3 }, /* mov x3, xzr */ - { 0x58000084 }, /* ldr x4, entry ; Load the lower 32-bits of kernel entry */ - { 0xd61f0080 }, /* br x4 ; Jump to the kernel entry point */ - { 0, FIXUP_ARGPTR }, /* arg: .word @DTB Lower 32-bits */ - { 0 }, /* .word @DTB Higher 32-bits */ - { 0, FIXUP_ENTRYPOINT }, /* entry: .word @Kernel Entry Lower 32-bits */ - { 0 }, /* .word @Kernel Entry Higher 32-bits */ - { 0, FIXUP_TERMINATOR } -}; - -/* A very small bootloader: call the board-setup code (if needed), - * set r0-r2, then jump to the kernel. - * If we're not calling boot setup code then we don't copy across - * the first BOOTLOADER_NO_BOARD_SETUP_OFFSET insns in this array. - */ - -static const ARMInsnFixup bootloader[] = { - { 0xe28fe004 }, /* add lr, pc, #4 */ - { 0xe51ff004 }, /* ldr pc, [pc, #-4] */ - { 0, FIXUP_BOARD_SETUP }, -#define BOOTLOADER_NO_BOARD_SETUP_OFFSET 3 - { 0xe3a00000 }, /* mov r0, #0 */ - { 0xe59f1004 }, /* ldr r1, [pc, #4] */ - { 0xe59f2004 }, /* ldr r2, [pc, #4] */ - { 0xe59ff004 }, /* ldr pc, [pc, #4] */ - { 0, FIXUP_BOARDID }, - { 0, FIXUP_ARGPTR }, - { 0, FIXUP_ENTRYPOINT }, - { 0, FIXUP_TERMINATOR } -}; - -/* Handling for secondary CPU boot in a multicore system. - * Unlike the uniprocessor/primary CPU boot, this is platform - * dependent. The default code here is based on the secondary - * CPU boot protocol used on realview/vexpress boards, with - * some parameterisation to increase its flexibility. - * QEMU platform models for which this code is not appropriate - * should override write_secondary_boot and secondary_cpu_reset_hook - * instead. - * - * This code enables the interrupt controllers for the secondary - * CPUs and then puts all the secondary CPUs into a loop waiting - * for an interprocessor interrupt and polling a configurable - * location for the kernel secondary CPU entry point. - */ -#define DSB_INSN 0xf57ff04f -#define CP15_DSB_INSN 0xee070f9a /* mcr cp15, 0, r0, c7, c10, 4 */ - -static const ARMInsnFixup smpboot[] = { - { 0xe59f2028 }, /* ldr r2, gic_cpu_if */ - { 0xe59f0028 }, /* ldr r0, bootreg_addr */ - { 0xe3a01001 }, /* mov r1, #1 */ - { 0xe5821000 }, /* str r1, [r2] - set GICC_CTLR.Enable */ - { 0xe3a010ff }, /* mov r1, #0xff */ - { 0xe5821004 }, /* str r1, [r2, 4] - set GIC_PMR.Priority to 0xff */ - { 0, FIXUP_DSB }, /* dsb */ - { 0xe320f003 }, /* wfi */ - { 0xe5901000 }, /* ldr r1, [r0] */ - { 0xe1110001 }, /* tst r1, r1 */ - { 0x0afffffb }, /* beq <wfi> */ - { 0xe12fff11 }, /* bx r1 */ - { 0, FIXUP_GIC_CPU_IF }, /* gic_cpu_if: .word 0x.... */ - { 0, FIXUP_BOOTREG }, /* bootreg_addr: .word 0x.... */ - { 0, FIXUP_TERMINATOR } -}; - -static void write_bootloader(const char *name, hwaddr addr, - const ARMInsnFixup *insns, uint32_t *fixupcontext) -{ - /* Fix up the specified bootloader fragment and write it into - * guest memory using rom_add_blob_fixed(). fixupcontext is - * an array giving the values to write in for the fixup types - * which write a value into the code array. - */ - int i, len; - uint32_t *code; - - len = 0; - while (insns[len].fixup != FIXUP_TERMINATOR) { - len++; - } - - code = g_new0(uint32_t, len); - - for (i = 0; i < len; i++) { - uint32_t insn = insns[i].insn; - FixupType fixup = insns[i].fixup; - - switch (fixup) { - case FIXUP_NONE: - break; - case FIXUP_BOARDID: - case FIXUP_BOARD_SETUP: - case FIXUP_ARGPTR: - case FIXUP_ENTRYPOINT: - case FIXUP_GIC_CPU_IF: - case FIXUP_BOOTREG: - case FIXUP_DSB: - insn = fixupcontext[fixup]; - break; - default: - abort(); - } - code[i] = tswap32(insn); - } - - rom_add_blob_fixed(name, code, len * sizeof(uint32_t), addr); - - g_free(code); -} - -static void default_write_secondary(ARMCPU *cpu, - const struct arm_boot_info *info) -{ - uint32_t fixupcontext[FIXUP_MAX]; - - fixupcontext[FIXUP_GIC_CPU_IF] = info->gic_cpu_if_addr; - fixupcontext[FIXUP_BOOTREG] = info->smp_bootreg_addr; - if (arm_feature(&cpu->env, ARM_FEATURE_V7)) { - fixupcontext[FIXUP_DSB] = DSB_INSN; - } else { - fixupcontext[FIXUP_DSB] = CP15_DSB_INSN; - } - - write_bootloader("smpboot", info->smp_loader_start, - smpboot, fixupcontext); -} - -void arm_write_secure_board_setup_dummy_smc(ARMCPU *cpu, - const struct arm_boot_info *info, - hwaddr mvbar_addr) -{ - int n; - uint32_t mvbar_blob[] = { - /* mvbar_addr: secure monitor vectors - * Default unimplemented and unused vectors to spin. Makes it - * easier to debug (as opposed to the CPU running away). - */ - 0xeafffffe, /* (spin) */ - 0xeafffffe, /* (spin) */ - 0xe1b0f00e, /* movs pc, lr ;SMC exception return */ - 0xeafffffe, /* (spin) */ - 0xeafffffe, /* (spin) */ - 0xeafffffe, /* (spin) */ - 0xeafffffe, /* (spin) */ - 0xeafffffe, /* (spin) */ - }; - uint32_t board_setup_blob[] = { - /* board setup addr */ - 0xe3a00e00 + (mvbar_addr >> 4), /* mov r0, #mvbar_addr */ - 0xee0c0f30, /* mcr p15, 0, r0, c12, c0, 1 ;set MVBAR */ - 0xee110f11, /* mrc p15, 0, r0, c1 , c1, 0 ;read SCR */ - 0xe3800031, /* orr r0, #0x31 ;enable AW, FW, NS */ - 0xee010f11, /* mcr p15, 0, r0, c1, c1, 0 ;write SCR */ - 0xe1a0100e, /* mov r1, lr ;save LR across SMC */ - 0xe1600070, /* smc #0 ;call monitor to flush SCR */ - 0xe1a0f001, /* mov pc, r1 ;return */ - }; - - /* check that mvbar_addr is correctly aligned and relocatable (using MOV) */ - assert((mvbar_addr & 0x1f) == 0 && (mvbar_addr >> 4) < 0x100); - - /* check that these blobs don't overlap */ - assert((mvbar_addr + sizeof(mvbar_blob) <= info->board_setup_addr) - || (info->board_setup_addr + sizeof(board_setup_blob) <= mvbar_addr)); - - for (n = 0; n < ARRAY_SIZE(mvbar_blob); n++) { - mvbar_blob[n] = tswap32(mvbar_blob[n]); - } - rom_add_blob_fixed("board-setup-mvbar", mvbar_blob, sizeof(mvbar_blob), - mvbar_addr); - - for (n = 0; n < ARRAY_SIZE(board_setup_blob); n++) { - board_setup_blob[n] = tswap32(board_setup_blob[n]); - } - rom_add_blob_fixed("board-setup", board_setup_blob, - sizeof(board_setup_blob), info->board_setup_addr); -} - -static void default_reset_secondary(ARMCPU *cpu, - const struct arm_boot_info *info) -{ - CPUState *cs = CPU(cpu); - - address_space_stl_notdirty(&address_space_memory, info->smp_bootreg_addr, - 0, MEMTXATTRS_UNSPECIFIED, NULL); - cpu_set_pc(cs, info->smp_loader_start); -} - -static inline bool have_dtb(const struct arm_boot_info *info) -{ - return info->dtb_filename || info->get_dtb; -} - -#define WRITE_WORD(p, value) do { \ - address_space_stl_notdirty(&address_space_memory, p, value, \ - MEMTXATTRS_UNSPECIFIED, NULL); \ - p += 4; \ -} while (0) - -static void set_kernel_args(const struct arm_boot_info *info) -{ - int initrd_size = info->initrd_size; - hwaddr base = info->loader_start; - hwaddr p; - - p = base + KERNEL_ARGS_ADDR; - /* ATAG_CORE */ - WRITE_WORD(p, 5); - WRITE_WORD(p, 0x54410001); - WRITE_WORD(p, 1); - WRITE_WORD(p, 0x1000); - WRITE_WORD(p, 0); - /* ATAG_MEM */ - /* TODO: handle multiple chips on one ATAG list */ - WRITE_WORD(p, 4); - WRITE_WORD(p, 0x54410002); - WRITE_WORD(p, info->ram_size); - WRITE_WORD(p, info->loader_start); - if (initrd_size) { - /* ATAG_INITRD2 */ - WRITE_WORD(p, 4); - WRITE_WORD(p, 0x54420005); - WRITE_WORD(p, info->initrd_start); - WRITE_WORD(p, initrd_size); - } - if (info->kernel_cmdline && *info->kernel_cmdline) { - /* ATAG_CMDLINE */ - int cmdline_size; - - cmdline_size = strlen(info->kernel_cmdline); - cpu_physical_memory_write(p + 8, info->kernel_cmdline, - cmdline_size + 1); - cmdline_size = (cmdline_size >> 2) + 1; - WRITE_WORD(p, cmdline_size + 2); - WRITE_WORD(p, 0x54410009); - p += cmdline_size * 4; - } - if (info->atag_board) { - /* ATAG_BOARD */ - int atag_board_len; - uint8_t atag_board_buf[0x1000]; - - atag_board_len = (info->atag_board(info, atag_board_buf) + 3) & ~3; - WRITE_WORD(p, (atag_board_len + 8) >> 2); - WRITE_WORD(p, 0x414f4d50); - cpu_physical_memory_write(p, atag_board_buf, atag_board_len); - p += atag_board_len; - } - /* ATAG_END */ - WRITE_WORD(p, 0); - WRITE_WORD(p, 0); -} - -static void set_kernel_args_old(const struct arm_boot_info *info) -{ - hwaddr p; - const char *s; - int initrd_size = info->initrd_size; - hwaddr base = info->loader_start; - - /* see linux/include/asm-arm/setup.h */ - p = base + KERNEL_ARGS_ADDR; - /* page_size */ - WRITE_WORD(p, 4096); - /* nr_pages */ - WRITE_WORD(p, info->ram_size / 4096); - /* ramdisk_size */ - WRITE_WORD(p, 0); -#define FLAG_READONLY 1 -#define FLAG_RDLOAD 4 -#define FLAG_RDPROMPT 8 - /* flags */ - WRITE_WORD(p, FLAG_READONLY | FLAG_RDLOAD | FLAG_RDPROMPT); - /* rootdev */ - WRITE_WORD(p, (31 << 8) | 0); /* /dev/mtdblock0 */ - /* video_num_cols */ - WRITE_WORD(p, 0); - /* video_num_rows */ - WRITE_WORD(p, 0); - /* video_x */ - WRITE_WORD(p, 0); - /* video_y */ - WRITE_WORD(p, 0); - /* memc_control_reg */ - WRITE_WORD(p, 0); - /* unsigned char sounddefault */ - /* unsigned char adfsdrives */ - /* unsigned char bytes_per_char_h */ - /* unsigned char bytes_per_char_v */ - WRITE_WORD(p, 0); - /* pages_in_bank[4] */ - WRITE_WORD(p, 0); - WRITE_WORD(p, 0); - WRITE_WORD(p, 0); - WRITE_WORD(p, 0); - /* pages_in_vram */ - WRITE_WORD(p, 0); - /* initrd_start */ - if (initrd_size) { - WRITE_WORD(p, info->initrd_start); - } else { - WRITE_WORD(p, 0); - } - /* initrd_size */ - WRITE_WORD(p, initrd_size); - /* rd_start */ - WRITE_WORD(p, 0); - /* system_rev */ - WRITE_WORD(p, 0); - /* system_serial_low */ - WRITE_WORD(p, 0); - /* system_serial_high */ - WRITE_WORD(p, 0); - /* mem_fclk_21285 */ - WRITE_WORD(p, 0); - /* zero unused fields */ - while (p < base + KERNEL_ARGS_ADDR + 256 + 1024) { - WRITE_WORD(p, 0); - } - s = info->kernel_cmdline; - if (s) { - cpu_physical_memory_write(p, s, strlen(s) + 1); - } else { - WRITE_WORD(p, 0); - } -} - -/** - * load_dtb() - load a device tree binary image into memory - * @addr: the address to load the image at - * @binfo: struct describing the boot environment - * @addr_limit: upper limit of the available memory area at @addr - * - * Load a device tree supplied by the machine or by the user with the - * '-dtb' command line option, and put it at offset @addr in target - * memory. - * - * If @addr_limit contains a meaningful value (i.e., it is strictly greater - * than @addr), the device tree is only loaded if its size does not exceed - * the limit. - * - * Returns: the size of the device tree image on success, - * 0 if the image size exceeds the limit, - * -1 on errors. - * - * Note: Must not be called unless have_dtb(binfo) is true. - */ -static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo, - hwaddr addr_limit) -{ - void *fdt = NULL; - int size, rc; - uint32_t acells, scells; - - if (binfo->dtb_filename) { - char *filename; - filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, binfo->dtb_filename); - if (!filename) { - fprintf(stderr, "Couldn't open dtb file %s\n", binfo->dtb_filename); - goto fail; - } - - fdt = load_device_tree(filename, &size); - if (!fdt) { - fprintf(stderr, "Couldn't open dtb file %s\n", filename); - g_free(filename); - goto fail; - } - g_free(filename); - } else { - fdt = binfo->get_dtb(binfo, &size); - if (!fdt) { - fprintf(stderr, "Board was unable to create a dtb blob\n"); - goto fail; - } - } - - if (addr_limit > addr && size > (addr_limit - addr)) { - /* Installing the device tree blob at addr would exceed addr_limit. - * Whether this constitutes failure is up to the caller to decide, - * so just return 0 as size, i.e., no error. - */ - g_free(fdt); - return 0; - } - - acells = qemu_fdt_getprop_cell(fdt, "/", "#address-cells", - NULL, &error_fatal); - scells = qemu_fdt_getprop_cell(fdt, "/", "#size-cells", - NULL, &error_fatal); - if (acells == 0 || scells == 0) { - fprintf(stderr, "dtb file invalid (#address-cells or #size-cells 0)\n"); - goto fail; - } - - if (scells < 2 && binfo->ram_size >= (1ULL << 32)) { - /* This is user error so deserves a friendlier error message - * than the failure of setprop_sized_cells would provide - */ - fprintf(stderr, "qemu: dtb file not compatible with " - "RAM size > 4GB\n"); - goto fail; - } - - rc = qemu_fdt_setprop_sized_cells(fdt, "/memory", "reg", - acells, binfo->loader_start, - scells, binfo->ram_size); - if (rc < 0) { - fprintf(stderr, "couldn't set /memory/reg\n"); - goto fail; - } - - if (binfo->kernel_cmdline && *binfo->kernel_cmdline) { - rc = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", - binfo->kernel_cmdline); - if (rc < 0) { - fprintf(stderr, "couldn't set /chosen/bootargs\n"); - goto fail; - } - } - - if (binfo->initrd_size) { - rc = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start", - binfo->initrd_start); - if (rc < 0) { - fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n"); - goto fail; - } - - rc = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end", - binfo->initrd_start + binfo->initrd_size); - if (rc < 0) { - fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n"); - goto fail; - } - } - - if (binfo->modify_dtb) { - binfo->modify_dtb(binfo, fdt); - } - - qemu_fdt_dumpdtb(fdt, size); - - /* Put the DTB into the memory map as a ROM image: this will ensure - * the DTB is copied again upon reset, even if addr points into RAM. - */ - rom_add_blob_fixed("dtb", fdt, size, addr); - - g_free(fdt); - - return size; - -fail: - g_free(fdt); - return -1; -} - -static void do_cpu_reset(void *opaque) -{ - ARMCPU *cpu = opaque; - CPUState *cs = CPU(cpu); - CPUARMState *env = &cpu->env; - const struct arm_boot_info *info = env->boot_info; - - cpu_reset(cs); - if (info) { - if (!info->is_linux) { - int i; - /* Jump to the entry point. */ - uint64_t entry = info->entry; - - switch (info->endianness) { - case ARM_ENDIANNESS_LE: - env->cp15.sctlr_el[1] &= ~SCTLR_E0E; - for (i = 1; i < 4; ++i) { - env->cp15.sctlr_el[i] &= ~SCTLR_EE; - } - env->uncached_cpsr &= ~CPSR_E; - break; - case ARM_ENDIANNESS_BE8: - env->cp15.sctlr_el[1] |= SCTLR_E0E; - for (i = 1; i < 4; ++i) { - env->cp15.sctlr_el[i] |= SCTLR_EE; - } - env->uncached_cpsr |= CPSR_E; - break; - case ARM_ENDIANNESS_BE32: - env->cp15.sctlr_el[1] |= SCTLR_B; - break; - case ARM_ENDIANNESS_UNKNOWN: - break; /* Board's decision */ - default: - g_assert_not_reached(); - } - - if (!env->aarch64) { - env->thumb = info->entry & 1; - entry &= 0xfffffffe; - } - cpu_set_pc(cs, entry); - } else { - /* If we are booting Linux then we need to check whether we are - * booting into secure or non-secure state and adjust the state - * accordingly. Out of reset, ARM is defined to be in secure state - * (SCR.NS = 0), we change that here if non-secure boot has been - * requested. - */ - if (arm_feature(env, ARM_FEATURE_EL3)) { - /* AArch64 is defined to come out of reset into EL3 if enabled. - * If we are booting Linux then we need to adjust our EL as - * Linux expects us to be in EL2 or EL1. AArch32 resets into - * SVC, which Linux expects, so no privilege/exception level to - * adjust. - */ - if (env->aarch64) { - env->cp15.scr_el3 |= SCR_RW; - if (arm_feature(env, ARM_FEATURE_EL2)) { - env->cp15.hcr_el2 |= HCR_RW; - env->pstate = PSTATE_MODE_EL2h; - } else { - env->pstate = PSTATE_MODE_EL1h; - } - } - - /* Set to non-secure if not a secure boot */ - if (!info->secure_boot && - (cs != first_cpu || !info->secure_board_setup)) { - /* Linux expects non-secure state */ - env->cp15.scr_el3 |= SCR_NS; - } - } - - if (cs == first_cpu) { - cpu_set_pc(cs, info->loader_start); - - if (!have_dtb(info)) { - if (old_param) { - set_kernel_args_old(info); - } else { - set_kernel_args(info); - } - } - } else { - info->secondary_cpu_reset_hook(cpu, info); - } - } - } -} - -/** - * load_image_to_fw_cfg() - Load an image file into an fw_cfg entry identified - * by key. - * @fw_cfg: The firmware config instance to store the data in. - * @size_key: The firmware config key to store the size of the loaded - * data under, with fw_cfg_add_i32(). - * @data_key: The firmware config key to store the loaded data under, - * with fw_cfg_add_bytes(). - * @image_name: The name of the image file to load. If it is NULL, the - * function returns without doing anything. - * @try_decompress: Whether the image should be decompressed (gunzipped) before - * adding it to fw_cfg. If decompression fails, the image is - * loaded as-is. - * - * In case of failure, the function prints an error message to stderr and the - * process exits with status 1. - */ -static void load_image_to_fw_cfg(FWCfgState *fw_cfg, uint16_t size_key, - uint16_t data_key, const char *image_name, - bool try_decompress) -{ - size_t size = -1; - uint8_t *data; - - if (image_name == NULL) { - return; - } - - if (try_decompress) { - size = load_image_gzipped_buffer(image_name, - LOAD_IMAGE_MAX_GUNZIP_BYTES, &data); - } - - if (size == (size_t)-1) { - gchar *contents; - gsize length; - - if (!g_file_get_contents(image_name, &contents, &length, NULL)) { - fprintf(stderr, "failed to load \"%s\"\n", image_name); - exit(1); - } - size = length; - data = (uint8_t *)contents; - } - - fw_cfg_add_i32(fw_cfg, size_key, size); - fw_cfg_add_bytes(fw_cfg, data_key, data, size); -} - -static int do_arm_linux_init(Object *obj, void *opaque) -{ - if (object_dynamic_cast(obj, TYPE_ARM_LINUX_BOOT_IF)) { - ARMLinuxBootIf *albif = ARM_LINUX_BOOT_IF(obj); - ARMLinuxBootIfClass *albifc = ARM_LINUX_BOOT_IF_GET_CLASS(obj); - struct arm_boot_info *info = opaque; - - if (albifc->arm_linux_init) { - albifc->arm_linux_init(albif, info->secure_boot); - } - } - return 0; -} - -static uint64_t arm_load_elf(struct arm_boot_info *info, uint64_t *pentry, - uint64_t *lowaddr, uint64_t *highaddr, - int elf_machine) -{ - bool elf_is64; - union { - Elf32_Ehdr h32; - Elf64_Ehdr h64; - } elf_header; - int data_swab = 0; - bool big_endian; - uint64_t ret = -1; - Error *err = NULL; - - - load_elf_hdr(info->kernel_filename, &elf_header, &elf_is64, &err); - if (err) { - return ret; - } - - if (elf_is64) { - big_endian = elf_header.h64.e_ident[EI_DATA] == ELFDATA2MSB; - info->endianness = big_endian ? ARM_ENDIANNESS_BE8 - : ARM_ENDIANNESS_LE; - } else { - big_endian = elf_header.h32.e_ident[EI_DATA] == ELFDATA2MSB; - if (big_endian) { - if (bswap32(elf_header.h32.e_flags) & EF_ARM_BE8) { - info->endianness = ARM_ENDIANNESS_BE8; - } else { - info->endianness = ARM_ENDIANNESS_BE32; - /* In BE32, the CPU has a different view of the per-byte - * address map than the rest of the system. BE32 ELF files - * are organised such that they can be programmed through - * the CPU's per-word byte-reversed view of the world. QEMU - * however loads ELF files independently of the CPU. So - * tell the ELF loader to byte reverse the data for us. - */ - data_swab = 2; - } - } else { - info->endianness = ARM_ENDIANNESS_LE; - } - } - - ret = load_elf(info->kernel_filename, NULL, NULL, - pentry, lowaddr, highaddr, big_endian, elf_machine, - 1, data_swab); - if (ret <= 0) { - /* The header loaded but the image didn't */ - exit(1); - } - - return ret; -} - -static void arm_load_kernel_notify(Notifier *notifier, void *data) -{ - CPUState *cs; - int kernel_size; - int initrd_size; - int is_linux = 0; - uint64_t elf_entry, elf_low_addr, elf_high_addr; - int elf_machine; - hwaddr entry, kernel_load_offset; - static const ARMInsnFixup *primary_loader; - ArmLoadKernelNotifier *n = DO_UPCAST(ArmLoadKernelNotifier, - notifier, notifier); - ARMCPU *cpu = n->cpu; - struct arm_boot_info *info = - container_of(n, struct arm_boot_info, load_kernel_notifier); - - /* The board code is not supposed to set secure_board_setup unless - * running its code in secure mode is actually possible, and KVM - * doesn't support secure. - */ - assert(!(info->secure_board_setup && kvm_enabled())); - - /* Load the kernel. */ - if (!info->kernel_filename || info->firmware_loaded) { - - if (have_dtb(info)) { - /* If we have a device tree blob, but no kernel to supply it to (or - * the kernel is supposed to be loaded by the bootloader), copy the - * DTB to the base of RAM for the bootloader to pick up. - */ - if (load_dtb(info->loader_start, info, 0) < 0) { - exit(1); - } - } - - if (info->kernel_filename) { - FWCfgState *fw_cfg; - bool try_decompressing_kernel; - - fw_cfg = fw_cfg_find(); - try_decompressing_kernel = arm_feature(&cpu->env, - ARM_FEATURE_AARCH64); - - /* Expose the kernel, the command line, and the initrd in fw_cfg. - * We don't process them here at all, it's all left to the - * firmware. - */ - load_image_to_fw_cfg(fw_cfg, - FW_CFG_KERNEL_SIZE, FW_CFG_KERNEL_DATA, - info->kernel_filename, - try_decompressing_kernel); - load_image_to_fw_cfg(fw_cfg, - FW_CFG_INITRD_SIZE, FW_CFG_INITRD_DATA, - info->initrd_filename, false); - - if (info->kernel_cmdline) { - fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, - strlen(info->kernel_cmdline) + 1); - fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, - info->kernel_cmdline); - } - } - - /* We will start from address 0 (typically a boot ROM image) in the - * same way as hardware. - */ - return; - } - - if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { - primary_loader = bootloader_aarch64; - kernel_load_offset = KERNEL64_LOAD_ADDR; - elf_machine = EM_AARCH64; - } else { - primary_loader = bootloader; - if (!info->write_board_setup) { - primary_loader += BOOTLOADER_NO_BOARD_SETUP_OFFSET; - } - kernel_load_offset = KERNEL_LOAD_ADDR; - elf_machine = EM_ARM; - } - - info->dtb_filename = qemu_opt_get(qemu_get_machine_opts(), "dtb"); - - if (!info->secondary_cpu_reset_hook) { - info->secondary_cpu_reset_hook = default_reset_secondary; - } - if (!info->write_secondary_boot) { - info->write_secondary_boot = default_write_secondary; - } - - if (info->nb_cpus == 0) - info->nb_cpus = 1; - - /* We want to put the initrd far enough into RAM that when the - * kernel is uncompressed it will not clobber the initrd. However - * on boards without much RAM we must ensure that we still leave - * enough room for a decent sized initrd, and on boards with large - * amounts of RAM we must avoid the initrd being so far up in RAM - * that it is outside lowmem and inaccessible to the kernel. - * So for boards with less than 256MB of RAM we put the initrd - * halfway into RAM, and for boards with 256MB of RAM or more we put - * the initrd at 128MB. - */ - info->initrd_start = info->loader_start + - MIN(info->ram_size / 2, 128 * 1024 * 1024); - - /* Assume that raw images are linux kernels, and ELF images are not. */ - kernel_size = arm_load_elf(info, &elf_entry, &elf_low_addr, - &elf_high_addr, elf_machine); - if (kernel_size > 0 && have_dtb(info)) { - /* If there is still some room left at the base of RAM, try and put - * the DTB there like we do for images loaded with -bios or -pflash. - */ - if (elf_low_addr > info->loader_start - || elf_high_addr < info->loader_start) { - /* Pass elf_low_addr as address limit to load_dtb if it may be - * pointing into RAM, otherwise pass '0' (no limit) - */ - if (elf_low_addr < info->loader_start) { - elf_low_addr = 0; - } - if (load_dtb(info->loader_start, info, elf_low_addr) < 0) { - exit(1); - } - } - } - entry = elf_entry; - if (kernel_size < 0) { - kernel_size = load_uimage(info->kernel_filename, &entry, NULL, - &is_linux, NULL, NULL); - } - /* On aarch64, it's the bootloader's job to uncompress the kernel. */ - if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64) && kernel_size < 0) { - entry = info->loader_start + kernel_load_offset; - kernel_size = load_image_gzipped(info->kernel_filename, entry, - info->ram_size - kernel_load_offset); - is_linux = 1; - } - if (kernel_size < 0) { - entry = info->loader_start + kernel_load_offset; - kernel_size = load_image_targphys(info->kernel_filename, entry, - info->ram_size - kernel_load_offset); - is_linux = 1; - } - if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - info->kernel_filename); - exit(1); - } - info->entry = entry; - if (is_linux) { - uint32_t fixupcontext[FIXUP_MAX]; - - if (info->initrd_filename) { - initrd_size = load_ramdisk(info->initrd_filename, - info->initrd_start, - info->ram_size - - info->initrd_start); - if (initrd_size < 0) { - initrd_size = load_image_targphys(info->initrd_filename, - info->initrd_start, - info->ram_size - - info->initrd_start); - } - if (initrd_size < 0) { - fprintf(stderr, "qemu: could not load initrd '%s'\n", - info->initrd_filename); - exit(1); - } - } else { - initrd_size = 0; - } - info->initrd_size = initrd_size; - - fixupcontext[FIXUP_BOARDID] = info->board_id; - fixupcontext[FIXUP_BOARD_SETUP] = info->board_setup_addr; - - /* for device tree boot, we pass the DTB directly in r2. Otherwise - * we point to the kernel args. - */ - if (have_dtb(info)) { - hwaddr align; - hwaddr dtb_start; - - if (elf_machine == EM_AARCH64) { - /* - * Some AArch64 kernels on early bootup map the fdt region as - * - * [ ALIGN_DOWN(fdt, 2MB) ... ALIGN_DOWN(fdt, 2MB) + 2MB ] - * - * Let's play safe and prealign it to 2MB to give us some space. - */ - align = 2 * 1024 * 1024; - } else { - /* - * Some 32bit kernels will trash anything in the 4K page the - * initrd ends in, so make sure the DTB isn't caught up in that. - */ - align = 4096; - } - - /* Place the DTB after the initrd in memory with alignment. */ - dtb_start = QEMU_ALIGN_UP(info->initrd_start + initrd_size, align); - if (load_dtb(dtb_start, info, 0) < 0) { - exit(1); - } - fixupcontext[FIXUP_ARGPTR] = dtb_start; - } else { - fixupcontext[FIXUP_ARGPTR] = info->loader_start + KERNEL_ARGS_ADDR; - if (info->ram_size >= (1ULL << 32)) { - fprintf(stderr, "qemu: RAM size must be less than 4GB to boot" - " Linux kernel using ATAGS (try passing a device tree" - " using -dtb)\n"); - exit(1); - } - } - fixupcontext[FIXUP_ENTRYPOINT] = entry; - - write_bootloader("bootloader", info->loader_start, - primary_loader, fixupcontext); - - if (info->nb_cpus > 1) { - info->write_secondary_boot(cpu, info); - } - if (info->write_board_setup) { - info->write_board_setup(cpu, info); - } - - /* Notify devices which need to fake up firmware initialization - * that we're doing a direct kernel boot. - */ - object_child_foreach_recursive(object_get_root(), - do_arm_linux_init, info); - } - info->is_linux = is_linux; - - for (cs = CPU(cpu); cs; cs = CPU_NEXT(cs)) { - ARM_CPU(cs)->env.boot_info = info; - } -} - -void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info) -{ - CPUState *cs; - - info->load_kernel_notifier.cpu = cpu; - info->load_kernel_notifier.notifier.notify = arm_load_kernel_notify; - qemu_add_machine_init_done_notifier(&info->load_kernel_notifier.notifier); - - /* CPU objects (unlike devices) are not automatically reset on system - * reset, so we must always register a handler to do so. If we're - * actually loading a kernel, the handler is also responsible for - * arranging that we start it correctly. - */ - for (cs = CPU(cpu); cs; cs = CPU_NEXT(cs)) { - qemu_register_reset(do_cpu_reset, ARM_CPU(cs)); - } -} - -static const TypeInfo arm_linux_boot_if_info = { - .name = TYPE_ARM_LINUX_BOOT_IF, - .parent = TYPE_INTERFACE, - .class_size = sizeof(ARMLinuxBootIfClass), -}; - -static void arm_linux_boot_register_types(void) -{ - type_register_static(&arm_linux_boot_if_info); -} - -type_init(arm_linux_boot_register_types) diff --git a/qemu/hw/arm/collie.c b/qemu/hw/arm/collie.c deleted file mode 100644 index 8bb308a42..000000000 --- a/qemu/hw/arm/collie.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * SA-1110-based Sharp Zaurus SL-5500 platform. - * - * Copyright (C) 2011 Dmitry Eremin-Solenikov - * - * This code is licensed under 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 "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/sysbus.h" -#include "hw/boards.h" -#include "hw/devices.h" -#include "strongarm.h" -#include "hw/arm/arm.h" -#include "hw/block/flash.h" -#include "sysemu/block-backend.h" -#include "exec/address-spaces.h" - -static struct arm_boot_info collie_binfo = { - .loader_start = SA_SDCS0, - .ram_size = 0x20000000, -}; - -static void collie_init(MachineState *machine) -{ - const char *cpu_model = machine->cpu_model; - const char *kernel_filename = machine->kernel_filename; - const char *kernel_cmdline = machine->kernel_cmdline; - const char *initrd_filename = machine->initrd_filename; - StrongARMState *s; - DriveInfo *dinfo; - MemoryRegion *sysmem = get_system_memory(); - - if (!cpu_model) { - cpu_model = "sa1110"; - } - - s = sa1110_init(sysmem, collie_binfo.ram_size, cpu_model); - - dinfo = drive_get(IF_PFLASH, 0, 0); - pflash_cfi01_register(SA_CS0, NULL, "collie.fl1", 0x02000000, - dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, - (64 * 1024), 512, 4, 0x00, 0x00, 0x00, 0x00, 0); - - dinfo = drive_get(IF_PFLASH, 0, 1); - pflash_cfi01_register(SA_CS1, NULL, "collie.fl2", 0x02000000, - dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, - (64 * 1024), 512, 4, 0x00, 0x00, 0x00, 0x00, 0); - - sysbus_create_simple("scoop", 0x40800000, NULL); - - collie_binfo.kernel_filename = kernel_filename; - collie_binfo.kernel_cmdline = kernel_cmdline; - collie_binfo.initrd_filename = initrd_filename; - collie_binfo.board_id = 0x208; - arm_load_kernel(s->cpu, &collie_binfo); -} - -static void collie_machine_init(MachineClass *mc) -{ - mc->desc = "Sharp SL-5500 (Collie) PDA (SA-1110)"; - mc->init = collie_init; -} - -DEFINE_MACHINE("collie", collie_machine_init) diff --git a/qemu/hw/arm/cubieboard.c b/qemu/hw/arm/cubieboard.c deleted file mode 100644 index fbd78ed01..000000000 --- a/qemu/hw/arm/cubieboard.c +++ /dev/null @@ -1,86 +0,0 @@ -/* - * cubieboard emulation - * - * Copyright (C) 2013 Li Guang - * Written by Li Guang <lig.fnst@cn.fujitsu.com> - * - * 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. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "qemu-common.h" -#include "cpu.h" -#include "hw/sysbus.h" -#include "hw/devices.h" -#include "hw/boards.h" -#include "hw/arm/allwinner-a10.h" - -static struct arm_boot_info cubieboard_binfo = { - .loader_start = AW_A10_SDRAM_BASE, - .board_id = 0x1008, -}; - -typedef struct CubieBoardState { - AwA10State *a10; - MemoryRegion sdram; -} CubieBoardState; - -static void cubieboard_init(MachineState *machine) -{ - CubieBoardState *s = g_new(CubieBoardState, 1); - Error *err = NULL; - - s->a10 = AW_A10(object_new(TYPE_AW_A10)); - - object_property_set_int(OBJECT(&s->a10->emac), 1, "phy-addr", &err); - if (err != NULL) { - error_reportf_err(err, "Couldn't set phy address: "); - exit(1); - } - - object_property_set_int(OBJECT(&s->a10->timer), 32768, "clk0-freq", &err); - if (err != NULL) { - error_reportf_err(err, "Couldn't set clk0 frequency: "); - exit(1); - } - - object_property_set_int(OBJECT(&s->a10->timer), 24000000, "clk1-freq", - &err); - if (err != NULL) { - error_reportf_err(err, "Couldn't set clk1 frequency: "); - exit(1); - } - - object_property_set_bool(OBJECT(s->a10), true, "realized", &err); - if (err != NULL) { - error_reportf_err(err, "Couldn't realize Allwinner A10: "); - exit(1); - } - - memory_region_allocate_system_memory(&s->sdram, NULL, "cubieboard.ram", - machine->ram_size); - memory_region_add_subregion(get_system_memory(), AW_A10_SDRAM_BASE, - &s->sdram); - - cubieboard_binfo.ram_size = machine->ram_size; - cubieboard_binfo.kernel_filename = machine->kernel_filename; - cubieboard_binfo.kernel_cmdline = machine->kernel_cmdline; - arm_load_kernel(&s->a10->cpu, &cubieboard_binfo); -} - -static void cubieboard_machine_init(MachineClass *mc) -{ - mc->desc = "cubietech cubieboard"; - mc->init = cubieboard_init; -} - -DEFINE_MACHINE("cubieboard", cubieboard_machine_init) diff --git a/qemu/hw/arm/digic.c b/qemu/hw/arm/digic.c deleted file mode 100644 index e0f973032..000000000 --- a/qemu/hw/arm/digic.c +++ /dev/null @@ -1,123 +0,0 @@ -/* - * QEMU model of the Canon DIGIC SoC. - * - * Copyright (C) 2013 Antony Pavlov <antonynpavlov@gmail.com> - * - * This model is based on reverse engineering efforts - * made by CHDK (http://chdk.wikia.com) and - * Magic Lantern (http://www.magiclantern.fm) projects - * contributors. - * - * 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. - * - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "hw/arm/digic.h" - -#define DIGIC4_TIMER_BASE(n) (0xc0210000 + (n) * 0x100) - -#define DIGIC_UART_BASE 0xc0800000 - -static void digic_init(Object *obj) -{ - DigicState *s = DIGIC(obj); - DeviceState *dev; - int i; - - object_initialize(&s->cpu, sizeof(s->cpu), "arm946-" TYPE_ARM_CPU); - object_property_add_child(obj, "cpu", OBJECT(&s->cpu), NULL); - - for (i = 0; i < DIGIC4_NB_TIMERS; i++) { -#define DIGIC_TIMER_NAME_MLEN 11 - char name[DIGIC_TIMER_NAME_MLEN]; - - object_initialize(&s->timer[i], sizeof(s->timer[i]), TYPE_DIGIC_TIMER); - dev = DEVICE(&s->timer[i]); - qdev_set_parent_bus(dev, sysbus_get_default()); - snprintf(name, DIGIC_TIMER_NAME_MLEN, "timer[%d]", i); - object_property_add_child(obj, name, OBJECT(&s->timer[i]), NULL); - } - - object_initialize(&s->uart, sizeof(s->uart), TYPE_DIGIC_UART); - dev = DEVICE(&s->uart); - qdev_set_parent_bus(dev, sysbus_get_default()); - object_property_add_child(obj, "uart", OBJECT(&s->uart), NULL); -} - -static void digic_realize(DeviceState *dev, Error **errp) -{ - DigicState *s = DIGIC(dev); - Error *err = NULL; - SysBusDevice *sbd; - int i; - - object_property_set_bool(OBJECT(&s->cpu), true, "reset-hivecs", &err); - if (err != NULL) { - error_propagate(errp, err); - return; - } - - object_property_set_bool(OBJECT(&s->cpu), true, "realized", &err); - if (err != NULL) { - error_propagate(errp, err); - return; - } - - for (i = 0; i < DIGIC4_NB_TIMERS; i++) { - object_property_set_bool(OBJECT(&s->timer[i]), true, "realized", &err); - if (err != NULL) { - error_propagate(errp, err); - return; - } - - sbd = SYS_BUS_DEVICE(&s->timer[i]); - sysbus_mmio_map(sbd, 0, DIGIC4_TIMER_BASE(i)); - } - - object_property_set_bool(OBJECT(&s->uart), true, "realized", &err); - if (err != NULL) { - error_propagate(errp, err); - return; - } - - sbd = SYS_BUS_DEVICE(&s->uart); - sysbus_mmio_map(sbd, 0, DIGIC_UART_BASE); -} - -static void digic_class_init(ObjectClass *oc, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(oc); - - dc->realize = digic_realize; - - /* - * Reason: creates an ARM CPU, thus use after free(), see - * arm_cpu_class_init() - */ - dc->cannot_destroy_with_object_finalize_yet = true; -} - -static const TypeInfo digic_type_info = { - .name = TYPE_DIGIC, - .parent = TYPE_DEVICE, - .instance_size = sizeof(DigicState), - .instance_init = digic_init, - .class_init = digic_class_init, -}; - -static void digic_register_types(void) -{ - type_register_static(&digic_type_info); -} - -type_init(digic_register_types) diff --git a/qemu/hw/arm/digic_boards.c b/qemu/hw/arm/digic_boards.c deleted file mode 100644 index 520c8e9ff..000000000 --- a/qemu/hw/arm/digic_boards.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * QEMU model of the Canon DIGIC boards (cameras indeed :). - * - * Copyright (C) 2013 Antony Pavlov <antonynpavlov@gmail.com> - * - * This model is based on reverse engineering efforts - * made by CHDK (http://chdk.wikia.com) and - * Magic Lantern (http://www.magiclantern.fm) projects - * contributors. - * - * See docs here: - * http://magiclantern.wikia.com/wiki/Register_Map - * - * 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. - * - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "qemu-common.h" -#include "cpu.h" -#include "hw/boards.h" -#include "exec/address-spaces.h" -#include "qemu/error-report.h" -#include "hw/arm/digic.h" -#include "hw/block/flash.h" -#include "hw/loader.h" -#include "sysemu/sysemu.h" -#include "sysemu/qtest.h" - -#define DIGIC4_ROM0_BASE 0xf0000000 -#define DIGIC4_ROM1_BASE 0xf8000000 -#define DIGIC4_ROM_MAX_SIZE 0x08000000 - -typedef struct DigicBoardState { - DigicState *digic; - MemoryRegion ram; -} DigicBoardState; - -typedef struct DigicBoard { - hwaddr ram_size; - void (*add_rom0)(DigicBoardState *, hwaddr, const char *); - const char *rom0_def_filename; - void (*add_rom1)(DigicBoardState *, hwaddr, const char *); - const char *rom1_def_filename; -} DigicBoard; - -static void digic4_board_setup_ram(DigicBoardState *s, hwaddr ram_size) -{ - memory_region_allocate_system_memory(&s->ram, NULL, "ram", ram_size); - memory_region_add_subregion(get_system_memory(), 0, &s->ram); -} - -static void digic4_board_init(DigicBoard *board) -{ - Error *err = NULL; - - DigicBoardState *s = g_new(DigicBoardState, 1); - - s->digic = DIGIC(object_new(TYPE_DIGIC)); - object_property_set_bool(OBJECT(s->digic), true, "realized", &err); - if (err != NULL) { - error_reportf_err(err, "Couldn't realize DIGIC SoC: "); - exit(1); - } - - digic4_board_setup_ram(s, board->ram_size); - - if (board->add_rom0) { - board->add_rom0(s, DIGIC4_ROM0_BASE, board->rom0_def_filename); - } - - if (board->add_rom1) { - board->add_rom1(s, DIGIC4_ROM1_BASE, board->rom1_def_filename); - } -} - -static void digic_load_rom(DigicBoardState *s, hwaddr addr, - hwaddr max_size, const char *def_filename) -{ - target_long rom_size; - const char *filename; - - if (qtest_enabled()) { - /* qtest runs no code so don't attempt a ROM load which - * could fail and result in a spurious test failure. - */ - return; - } - - if (bios_name) { - filename = bios_name; - } else { - filename = def_filename; - } - - if (filename) { - char *fn = qemu_find_file(QEMU_FILE_TYPE_BIOS, filename); - - if (!fn) { - error_report("Couldn't find rom image '%s'.", filename); - exit(1); - } - - rom_size = load_image_targphys(fn, addr, max_size); - if (rom_size < 0 || rom_size > max_size) { - error_report("Couldn't load rom image '%s'.", filename); - exit(1); - } - g_free(fn); - } -} - -/* - * Samsung K8P3215UQB - * 64M Bit (4Mx16) Page Mode / Multi-Bank NOR Flash Memory - */ -static void digic4_add_k8p3215uqb_rom(DigicBoardState *s, hwaddr addr, - const char *def_filename) -{ -#define FLASH_K8P3215UQB_SIZE (4 * 1024 * 1024) -#define FLASH_K8P3215UQB_SECTOR_SIZE (64 * 1024) - - pflash_cfi02_register(addr, NULL, "pflash", FLASH_K8P3215UQB_SIZE, - NULL, FLASH_K8P3215UQB_SECTOR_SIZE, - FLASH_K8P3215UQB_SIZE / FLASH_K8P3215UQB_SECTOR_SIZE, - DIGIC4_ROM_MAX_SIZE / FLASH_K8P3215UQB_SIZE, - 4, - 0x00EC, 0x007E, 0x0003, 0x0001, - 0x0555, 0x2aa, 0); - - digic_load_rom(s, addr, FLASH_K8P3215UQB_SIZE, def_filename); -} - -static DigicBoard digic4_board_canon_a1100 = { - .ram_size = 64 * 1024 * 1024, - .add_rom1 = digic4_add_k8p3215uqb_rom, - .rom1_def_filename = "canon-a1100-rom1.bin", -}; - -static void canon_a1100_init(MachineState *machine) -{ - digic4_board_init(&digic4_board_canon_a1100); -} - -static void canon_a1100_machine_init(MachineClass *mc) -{ - mc->desc = "Canon PowerShot A1100 IS"; - mc->init = &canon_a1100_init; -} - -DEFINE_MACHINE("canon-a1100", canon_a1100_machine_init) diff --git a/qemu/hw/arm/exynos4210.c b/qemu/hw/arm/exynos4210.c deleted file mode 100644 index be3c96d21..000000000 --- a/qemu/hw/arm/exynos4210.c +++ /dev/null @@ -1,378 +0,0 @@ -/* - * Samsung exynos4210 SoC emulation - * - * Copyright (c) 2011 Samsung Electronics Co., Ltd. All rights reserved. - * Maksim Kozlov <m.kozlov@samsung.com> - * Evgeny Voevodin <e.voevodin@samsung.com> - * Igor Mitsyanko <i.mitsyanko@samsung.com> - * - * 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 <http://www.gnu.org/licenses/>. - * - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "qemu-common.h" -#include "cpu.h" -#include "hw/boards.h" -#include "sysemu/sysemu.h" -#include "hw/sysbus.h" -#include "hw/arm/arm.h" -#include "hw/loader.h" -#include "hw/arm/exynos4210.h" -#include "hw/usb/hcd-ehci.h" - -#define EXYNOS4210_CHIPID_ADDR 0x10000000 - -/* PWM */ -#define EXYNOS4210_PWM_BASE_ADDR 0x139D0000 - -/* RTC */ -#define EXYNOS4210_RTC_BASE_ADDR 0x10070000 - -/* MCT */ -#define EXYNOS4210_MCT_BASE_ADDR 0x10050000 - -/* I2C */ -#define EXYNOS4210_I2C_SHIFT 0x00010000 -#define EXYNOS4210_I2C_BASE_ADDR 0x13860000 -/* Interrupt Group of External Interrupt Combiner for I2C */ -#define EXYNOS4210_I2C_INTG 27 -#define EXYNOS4210_HDMI_INTG 16 - -/* UART's definitions */ -#define EXYNOS4210_UART0_BASE_ADDR 0x13800000 -#define EXYNOS4210_UART1_BASE_ADDR 0x13810000 -#define EXYNOS4210_UART2_BASE_ADDR 0x13820000 -#define EXYNOS4210_UART3_BASE_ADDR 0x13830000 -#define EXYNOS4210_UART0_FIFO_SIZE 256 -#define EXYNOS4210_UART1_FIFO_SIZE 64 -#define EXYNOS4210_UART2_FIFO_SIZE 16 -#define EXYNOS4210_UART3_FIFO_SIZE 16 -/* Interrupt Group of External Interrupt Combiner for UART */ -#define EXYNOS4210_UART_INT_GRP 26 - -/* External GIC */ -#define EXYNOS4210_EXT_GIC_CPU_BASE_ADDR 0x10480000 -#define EXYNOS4210_EXT_GIC_DIST_BASE_ADDR 0x10490000 - -/* Combiner */ -#define EXYNOS4210_EXT_COMBINER_BASE_ADDR 0x10440000 -#define EXYNOS4210_INT_COMBINER_BASE_ADDR 0x10448000 - -/* PMU SFR base address */ -#define EXYNOS4210_PMU_BASE_ADDR 0x10020000 - -/* Display controllers (FIMD) */ -#define EXYNOS4210_FIMD0_BASE_ADDR 0x11C00000 - -/* EHCI */ -#define EXYNOS4210_EHCI_BASE_ADDR 0x12580000 - -static uint8_t chipid_and_omr[] = { 0x11, 0x02, 0x21, 0x43, - 0x09, 0x00, 0x00, 0x00 }; - -static uint64_t exynos4210_chipid_and_omr_read(void *opaque, hwaddr offset, - unsigned size) -{ - assert(offset < sizeof(chipid_and_omr)); - return chipid_and_omr[offset]; -} - -static void exynos4210_chipid_and_omr_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - return; -} - -static const MemoryRegionOps exynos4210_chipid_and_omr_ops = { - .read = exynos4210_chipid_and_omr_read, - .write = exynos4210_chipid_and_omr_write, - .endianness = DEVICE_NATIVE_ENDIAN, - .impl = { - .max_access_size = 1, - } -}; - -void exynos4210_write_secondary(ARMCPU *cpu, - const struct arm_boot_info *info) -{ - int n; - uint32_t smpboot[] = { - 0xe59f3034, /* ldr r3, External gic_cpu_if */ - 0xe59f2034, /* ldr r2, Internal gic_cpu_if */ - 0xe59f0034, /* ldr r0, startaddr */ - 0xe3a01001, /* mov r1, #1 */ - 0xe5821000, /* str r1, [r2] */ - 0xe5831000, /* str r1, [r3] */ - 0xe3a010ff, /* mov r1, #0xff */ - 0xe5821004, /* str r1, [r2, #4] */ - 0xe5831004, /* str r1, [r3, #4] */ - 0xf57ff04f, /* dsb */ - 0xe320f003, /* wfi */ - 0xe5901000, /* ldr r1, [r0] */ - 0xe1110001, /* tst r1, r1 */ - 0x0afffffb, /* beq <wfi> */ - 0xe12fff11, /* bx r1 */ - EXYNOS4210_EXT_GIC_CPU_BASE_ADDR, - 0, /* gic_cpu_if: base address of Internal GIC CPU interface */ - 0 /* bootreg: Boot register address is held here */ - }; - smpboot[ARRAY_SIZE(smpboot) - 1] = info->smp_bootreg_addr; - smpboot[ARRAY_SIZE(smpboot) - 2] = info->gic_cpu_if_addr; - for (n = 0; n < ARRAY_SIZE(smpboot); n++) { - smpboot[n] = tswap32(smpboot[n]); - } - rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot), - info->smp_loader_start); -} - -Exynos4210State *exynos4210_init(MemoryRegion *system_mem, - unsigned long ram_size) -{ - int i, n; - Exynos4210State *s = g_new(Exynos4210State, 1); - qemu_irq gate_irq[EXYNOS4210_NCPUS][EXYNOS4210_IRQ_GATE_NINPUTS]; - unsigned long mem_size; - DeviceState *dev; - SysBusDevice *busdev; - ObjectClass *cpu_oc; - - cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, "cortex-a9"); - assert(cpu_oc); - - for (n = 0; n < EXYNOS4210_NCPUS; n++) { - Object *cpuobj = object_new(object_class_get_name(cpu_oc)); - - /* By default A9 CPUs have EL3 enabled. This board does not currently - * support EL3 so the CPU EL3 property is disabled before realization. - */ - if (object_property_find(cpuobj, "has_el3", NULL)) { - object_property_set_bool(cpuobj, false, "has_el3", &error_fatal); - } - - s->cpu[n] = ARM_CPU(cpuobj); - object_property_set_int(cpuobj, EXYNOS4210_SMP_PRIVATE_BASE_ADDR, - "reset-cbar", &error_abort); - object_property_set_bool(cpuobj, true, "realized", &error_fatal); - } - - /*** IRQs ***/ - - s->irq_table = exynos4210_init_irq(&s->irqs); - - /* IRQ Gate */ - for (i = 0; i < EXYNOS4210_NCPUS; i++) { - dev = qdev_create(NULL, "exynos4210.irq_gate"); - qdev_prop_set_uint32(dev, "n_in", EXYNOS4210_IRQ_GATE_NINPUTS); - qdev_init_nofail(dev); - /* Get IRQ Gate input in gate_irq */ - for (n = 0; n < EXYNOS4210_IRQ_GATE_NINPUTS; n++) { - gate_irq[i][n] = qdev_get_gpio_in(dev, n); - } - busdev = SYS_BUS_DEVICE(dev); - - /* Connect IRQ Gate output to CPU's IRQ line */ - sysbus_connect_irq(busdev, 0, - qdev_get_gpio_in(DEVICE(s->cpu[i]), ARM_CPU_IRQ)); - } - - /* Private memory region and Internal GIC */ - dev = qdev_create(NULL, "a9mpcore_priv"); - qdev_prop_set_uint32(dev, "num-cpu", EXYNOS4210_NCPUS); - qdev_init_nofail(dev); - busdev = SYS_BUS_DEVICE(dev); - sysbus_mmio_map(busdev, 0, EXYNOS4210_SMP_PRIVATE_BASE_ADDR); - for (n = 0; n < EXYNOS4210_NCPUS; n++) { - sysbus_connect_irq(busdev, n, gate_irq[n][0]); - } - for (n = 0; n < EXYNOS4210_INT_GIC_NIRQ; n++) { - s->irqs.int_gic_irq[n] = qdev_get_gpio_in(dev, n); - } - - /* Cache controller */ - sysbus_create_simple("l2x0", EXYNOS4210_L2X0_BASE_ADDR, NULL); - - /* External GIC */ - dev = qdev_create(NULL, "exynos4210.gic"); - qdev_prop_set_uint32(dev, "num-cpu", EXYNOS4210_NCPUS); - qdev_init_nofail(dev); - busdev = SYS_BUS_DEVICE(dev); - /* Map CPU interface */ - sysbus_mmio_map(busdev, 0, EXYNOS4210_EXT_GIC_CPU_BASE_ADDR); - /* Map Distributer interface */ - sysbus_mmio_map(busdev, 1, EXYNOS4210_EXT_GIC_DIST_BASE_ADDR); - for (n = 0; n < EXYNOS4210_NCPUS; n++) { - sysbus_connect_irq(busdev, n, gate_irq[n][1]); - } - for (n = 0; n < EXYNOS4210_EXT_GIC_NIRQ; n++) { - s->irqs.ext_gic_irq[n] = qdev_get_gpio_in(dev, n); - } - - /* Internal Interrupt Combiner */ - dev = qdev_create(NULL, "exynos4210.combiner"); - qdev_init_nofail(dev); - busdev = SYS_BUS_DEVICE(dev); - for (n = 0; n < EXYNOS4210_MAX_INT_COMBINER_OUT_IRQ; n++) { - sysbus_connect_irq(busdev, n, s->irqs.int_gic_irq[n]); - } - exynos4210_combiner_get_gpioin(&s->irqs, dev, 0); - sysbus_mmio_map(busdev, 0, EXYNOS4210_INT_COMBINER_BASE_ADDR); - - /* External Interrupt Combiner */ - dev = qdev_create(NULL, "exynos4210.combiner"); - qdev_prop_set_uint32(dev, "external", 1); - qdev_init_nofail(dev); - busdev = SYS_BUS_DEVICE(dev); - for (n = 0; n < EXYNOS4210_MAX_INT_COMBINER_OUT_IRQ; n++) { - sysbus_connect_irq(busdev, n, s->irqs.ext_gic_irq[n]); - } - exynos4210_combiner_get_gpioin(&s->irqs, dev, 1); - sysbus_mmio_map(busdev, 0, EXYNOS4210_EXT_COMBINER_BASE_ADDR); - - /* Initialize board IRQs. */ - exynos4210_init_board_irqs(&s->irqs); - - /*** Memory ***/ - - /* Chip-ID and OMR */ - memory_region_init_io(&s->chipid_mem, NULL, &exynos4210_chipid_and_omr_ops, - NULL, "exynos4210.chipid", sizeof(chipid_and_omr)); - memory_region_add_subregion(system_mem, EXYNOS4210_CHIPID_ADDR, - &s->chipid_mem); - - /* Internal ROM */ - memory_region_init_ram(&s->irom_mem, NULL, "exynos4210.irom", - EXYNOS4210_IROM_SIZE, &error_fatal); - vmstate_register_ram_global(&s->irom_mem); - memory_region_set_readonly(&s->irom_mem, true); - memory_region_add_subregion(system_mem, EXYNOS4210_IROM_BASE_ADDR, - &s->irom_mem); - /* mirror of iROM */ - memory_region_init_alias(&s->irom_alias_mem, NULL, "exynos4210.irom_alias", - &s->irom_mem, - 0, - EXYNOS4210_IROM_SIZE); - memory_region_set_readonly(&s->irom_alias_mem, true); - memory_region_add_subregion(system_mem, EXYNOS4210_IROM_MIRROR_BASE_ADDR, - &s->irom_alias_mem); - - /* Internal RAM */ - memory_region_init_ram(&s->iram_mem, NULL, "exynos4210.iram", - EXYNOS4210_IRAM_SIZE, &error_fatal); - vmstate_register_ram_global(&s->iram_mem); - memory_region_add_subregion(system_mem, EXYNOS4210_IRAM_BASE_ADDR, - &s->iram_mem); - - /* DRAM */ - mem_size = ram_size; - if (mem_size > EXYNOS4210_DRAM_MAX_SIZE) { - memory_region_init_ram(&s->dram1_mem, NULL, "exynos4210.dram1", - mem_size - EXYNOS4210_DRAM_MAX_SIZE, &error_fatal); - vmstate_register_ram_global(&s->dram1_mem); - memory_region_add_subregion(system_mem, EXYNOS4210_DRAM1_BASE_ADDR, - &s->dram1_mem); - mem_size = EXYNOS4210_DRAM_MAX_SIZE; - } - memory_region_init_ram(&s->dram0_mem, NULL, "exynos4210.dram0", mem_size, - &error_fatal); - vmstate_register_ram_global(&s->dram0_mem); - memory_region_add_subregion(system_mem, EXYNOS4210_DRAM0_BASE_ADDR, - &s->dram0_mem); - - /* PMU. - * The only reason of existence at the moment is that secondary CPU boot - * loader uses PMU INFORM5 register as a holding pen. - */ - sysbus_create_simple("exynos4210.pmu", EXYNOS4210_PMU_BASE_ADDR, NULL); - - /* PWM */ - sysbus_create_varargs("exynos4210.pwm", EXYNOS4210_PWM_BASE_ADDR, - s->irq_table[exynos4210_get_irq(22, 0)], - s->irq_table[exynos4210_get_irq(22, 1)], - s->irq_table[exynos4210_get_irq(22, 2)], - s->irq_table[exynos4210_get_irq(22, 3)], - s->irq_table[exynos4210_get_irq(22, 4)], - NULL); - /* RTC */ - sysbus_create_varargs("exynos4210.rtc", EXYNOS4210_RTC_BASE_ADDR, - s->irq_table[exynos4210_get_irq(23, 0)], - s->irq_table[exynos4210_get_irq(23, 1)], - NULL); - - /* Multi Core Timer */ - dev = qdev_create(NULL, "exynos4210.mct"); - qdev_init_nofail(dev); - busdev = SYS_BUS_DEVICE(dev); - for (n = 0; n < 4; n++) { - /* Connect global timer interrupts to Combiner gpio_in */ - sysbus_connect_irq(busdev, n, - s->irq_table[exynos4210_get_irq(1, 4 + n)]); - } - /* Connect local timer interrupts to Combiner gpio_in */ - sysbus_connect_irq(busdev, 4, - s->irq_table[exynos4210_get_irq(51, 0)]); - sysbus_connect_irq(busdev, 5, - s->irq_table[exynos4210_get_irq(35, 3)]); - sysbus_mmio_map(busdev, 0, EXYNOS4210_MCT_BASE_ADDR); - - /*** I2C ***/ - for (n = 0; n < EXYNOS4210_I2C_NUMBER; n++) { - uint32_t addr = EXYNOS4210_I2C_BASE_ADDR + EXYNOS4210_I2C_SHIFT * n; - qemu_irq i2c_irq; - - if (n < 8) { - i2c_irq = s->irq_table[exynos4210_get_irq(EXYNOS4210_I2C_INTG, n)]; - } else { - i2c_irq = s->irq_table[exynos4210_get_irq(EXYNOS4210_HDMI_INTG, 1)]; - } - - dev = qdev_create(NULL, "exynos4210.i2c"); - qdev_init_nofail(dev); - busdev = SYS_BUS_DEVICE(dev); - sysbus_connect_irq(busdev, 0, i2c_irq); - sysbus_mmio_map(busdev, 0, addr); - s->i2c_if[n] = (I2CBus *)qdev_get_child_bus(dev, "i2c"); - } - - - /*** UARTs ***/ - exynos4210_uart_create(EXYNOS4210_UART0_BASE_ADDR, - EXYNOS4210_UART0_FIFO_SIZE, 0, NULL, - s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 0)]); - - exynos4210_uart_create(EXYNOS4210_UART1_BASE_ADDR, - EXYNOS4210_UART1_FIFO_SIZE, 1, NULL, - s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 1)]); - - exynos4210_uart_create(EXYNOS4210_UART2_BASE_ADDR, - EXYNOS4210_UART2_FIFO_SIZE, 2, NULL, - s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 2)]); - - exynos4210_uart_create(EXYNOS4210_UART3_BASE_ADDR, - EXYNOS4210_UART3_FIFO_SIZE, 3, NULL, - s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 3)]); - - /*** Display controller (FIMD) ***/ - sysbus_create_varargs("exynos4210.fimd", EXYNOS4210_FIMD0_BASE_ADDR, - s->irq_table[exynos4210_get_irq(11, 0)], - s->irq_table[exynos4210_get_irq(11, 1)], - s->irq_table[exynos4210_get_irq(11, 2)], - NULL); - - sysbus_create_simple(TYPE_EXYNOS4210_EHCI, EXYNOS4210_EHCI_BASE_ADDR, - s->irq_table[exynos4210_get_irq(28, 3)]); - - return s; -} diff --git a/qemu/hw/arm/exynos4_boards.c b/qemu/hw/arm/exynos4_boards.c deleted file mode 100644 index 0efa19405..000000000 --- a/qemu/hw/arm/exynos4_boards.c +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Samsung exynos4 SoC based boards emulation - * - * Copyright (c) 2011 Samsung Electronics Co., Ltd. All rights reserved. - * Maksim Kozlov <m.kozlov@samsung.com> - * Evgeny Voevodin <e.voevodin@samsung.com> - * Igor Mitsyanko <i.mitsyanko@samsung.com> - * - * 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 <http://www.gnu.org/licenses/>. - * - */ - -#include "qemu/osdep.h" -#include "qemu-common.h" -#include "cpu.h" -#include "sysemu/sysemu.h" -#include "sysemu/qtest.h" -#include "hw/sysbus.h" -#include "net/net.h" -#include "hw/arm/arm.h" -#include "exec/address-spaces.h" -#include "hw/arm/exynos4210.h" -#include "hw/boards.h" - -#undef DEBUG - -//#define DEBUG - -#ifdef DEBUG - #undef PRINT_DEBUG - #define PRINT_DEBUG(fmt, args...) \ - do { \ - fprintf(stderr, " [%s:%d] "fmt, __func__, __LINE__, ##args); \ - } while (0) -#else - #define PRINT_DEBUG(fmt, args...) do {} while (0) -#endif - -#define SMDK_LAN9118_BASE_ADDR 0x05000000 - -typedef enum Exynos4BoardType { - EXYNOS4_BOARD_NURI, - EXYNOS4_BOARD_SMDKC210, - EXYNOS4_NUM_OF_BOARDS -} Exynos4BoardType; - -static int exynos4_board_id[EXYNOS4_NUM_OF_BOARDS] = { - [EXYNOS4_BOARD_NURI] = 0xD33, - [EXYNOS4_BOARD_SMDKC210] = 0xB16, -}; - -static int exynos4_board_smp_bootreg_addr[EXYNOS4_NUM_OF_BOARDS] = { - [EXYNOS4_BOARD_NURI] = EXYNOS4210_SECOND_CPU_BOOTREG, - [EXYNOS4_BOARD_SMDKC210] = EXYNOS4210_SECOND_CPU_BOOTREG, -}; - -static unsigned long exynos4_board_ram_size[EXYNOS4_NUM_OF_BOARDS] = { - [EXYNOS4_BOARD_NURI] = 0x40000000, - [EXYNOS4_BOARD_SMDKC210] = 0x40000000, -}; - -static struct arm_boot_info exynos4_board_binfo = { - .loader_start = EXYNOS4210_BASE_BOOT_ADDR, - .smp_loader_start = EXYNOS4210_SMP_BOOT_ADDR, - .nb_cpus = EXYNOS4210_NCPUS, - .write_secondary_boot = exynos4210_write_secondary, -}; - -static void lan9215_init(uint32_t base, qemu_irq irq) -{ - DeviceState *dev; - SysBusDevice *s; - - /* This should be a 9215 but the 9118 is close enough */ - if (nd_table[0].used) { - qemu_check_nic_model(&nd_table[0], "lan9118"); - dev = qdev_create(NULL, "lan9118"); - qdev_set_nic_properties(dev, &nd_table[0]); - qdev_prop_set_uint32(dev, "mode_16bit", 1); - qdev_init_nofail(dev); - s = SYS_BUS_DEVICE(dev); - sysbus_mmio_map(s, 0, base); - sysbus_connect_irq(s, 0, irq); - } -} - -static Exynos4210State *exynos4_boards_init_common(MachineState *machine, - Exynos4BoardType board_type) -{ - MachineClass *mc = MACHINE_GET_CLASS(machine); - - if (smp_cpus != EXYNOS4210_NCPUS && !qtest_enabled()) { - fprintf(stderr, "%s board supports only %d CPU cores. Ignoring smp_cpus" - " value.\n", - mc->name, EXYNOS4210_NCPUS); - } - - exynos4_board_binfo.ram_size = exynos4_board_ram_size[board_type]; - exynos4_board_binfo.board_id = exynos4_board_id[board_type]; - exynos4_board_binfo.smp_bootreg_addr = - exynos4_board_smp_bootreg_addr[board_type]; - exynos4_board_binfo.kernel_filename = machine->kernel_filename; - exynos4_board_binfo.initrd_filename = machine->initrd_filename; - exynos4_board_binfo.kernel_cmdline = machine->kernel_cmdline; - exynos4_board_binfo.gic_cpu_if_addr = - EXYNOS4210_SMP_PRIVATE_BASE_ADDR + 0x100; - - PRINT_DEBUG("\n ram_size: %luMiB [0x%08lx]\n" - " kernel_filename: %s\n" - " kernel_cmdline: %s\n" - " initrd_filename: %s\n", - exynos4_board_ram_size[board_type] / 1048576, - exynos4_board_ram_size[board_type], - machine->kernel_filename, - machine->kernel_cmdline, - machine->initrd_filename); - - return exynos4210_init(get_system_memory(), - exynos4_board_ram_size[board_type]); -} - -static void nuri_init(MachineState *machine) -{ - exynos4_boards_init_common(machine, EXYNOS4_BOARD_NURI); - - arm_load_kernel(ARM_CPU(first_cpu), &exynos4_board_binfo); -} - -static void smdkc210_init(MachineState *machine) -{ - Exynos4210State *s = exynos4_boards_init_common(machine, - EXYNOS4_BOARD_SMDKC210); - - lan9215_init(SMDK_LAN9118_BASE_ADDR, - qemu_irq_invert(s->irq_table[exynos4210_get_irq(37, 1)])); - arm_load_kernel(ARM_CPU(first_cpu), &exynos4_board_binfo); -} - -static void nuri_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "Samsung NURI board (Exynos4210)"; - mc->init = nuri_init; - mc->max_cpus = EXYNOS4210_NCPUS; -} - -static const TypeInfo nuri_type = { - .name = MACHINE_TYPE_NAME("nuri"), - .parent = TYPE_MACHINE, - .class_init = nuri_class_init, -}; - -static void smdkc210_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "Samsung SMDKC210 board (Exynos4210)"; - mc->init = smdkc210_init; - mc->max_cpus = EXYNOS4210_NCPUS; -} - -static const TypeInfo smdkc210_type = { - .name = MACHINE_TYPE_NAME("smdkc210"), - .parent = TYPE_MACHINE, - .class_init = smdkc210_class_init, -}; - -static void exynos4_machines_init(void) -{ - type_register_static(&nuri_type); - type_register_static(&smdkc210_type); -} - -type_init(exynos4_machines_init) diff --git a/qemu/hw/arm/fsl-imx25.c b/qemu/hw/arm/fsl-imx25.c deleted file mode 100644 index 2f878b935..000000000 --- a/qemu/hw/arm/fsl-imx25.c +++ /dev/null @@ -1,313 +0,0 @@ -/* - * Copyright (c) 2013 Jean-Christophe Dubois <jcd@tribudubois.net> - * - * i.MX25 SOC emulation. - * - * Based on hw/arm/xlnx-zynqmp.c - * - * Copyright (C) 2015 Xilinx Inc - * Written by Peter Crosthwaite <peter.crosthwaite@xilinx.com> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "qemu-common.h" -#include "cpu.h" -#include "hw/arm/fsl-imx25.h" -#include "sysemu/sysemu.h" -#include "exec/address-spaces.h" -#include "hw/boards.h" -#include "sysemu/char.h" - -static void fsl_imx25_init(Object *obj) -{ - FslIMX25State *s = FSL_IMX25(obj); - int i; - - object_initialize(&s->cpu, sizeof(s->cpu), "arm926-" TYPE_ARM_CPU); - - object_initialize(&s->avic, sizeof(s->avic), TYPE_IMX_AVIC); - qdev_set_parent_bus(DEVICE(&s->avic), sysbus_get_default()); - - object_initialize(&s->ccm, sizeof(s->ccm), TYPE_IMX25_CCM); - qdev_set_parent_bus(DEVICE(&s->ccm), sysbus_get_default()); - - for (i = 0; i < FSL_IMX25_NUM_UARTS; i++) { - object_initialize(&s->uart[i], sizeof(s->uart[i]), TYPE_IMX_SERIAL); - qdev_set_parent_bus(DEVICE(&s->uart[i]), sysbus_get_default()); - } - - for (i = 0; i < FSL_IMX25_NUM_GPTS; i++) { - object_initialize(&s->gpt[i], sizeof(s->gpt[i]), TYPE_IMX_GPT); - qdev_set_parent_bus(DEVICE(&s->gpt[i]), sysbus_get_default()); - } - - for (i = 0; i < FSL_IMX25_NUM_EPITS; i++) { - object_initialize(&s->epit[i], sizeof(s->epit[i]), TYPE_IMX_EPIT); - qdev_set_parent_bus(DEVICE(&s->epit[i]), sysbus_get_default()); - } - - object_initialize(&s->fec, sizeof(s->fec), TYPE_IMX_FEC); - qdev_set_parent_bus(DEVICE(&s->fec), sysbus_get_default()); - - for (i = 0; i < FSL_IMX25_NUM_I2CS; i++) { - object_initialize(&s->i2c[i], sizeof(s->i2c[i]), TYPE_IMX_I2C); - qdev_set_parent_bus(DEVICE(&s->i2c[i]), sysbus_get_default()); - } - - for (i = 0; i < FSL_IMX25_NUM_GPIOS; i++) { - object_initialize(&s->gpio[i], sizeof(s->gpio[i]), TYPE_IMX_GPIO); - qdev_set_parent_bus(DEVICE(&s->gpio[i]), sysbus_get_default()); - } -} - -static void fsl_imx25_realize(DeviceState *dev, Error **errp) -{ - FslIMX25State *s = FSL_IMX25(dev); - uint8_t i; - Error *err = NULL; - - object_property_set_bool(OBJECT(&s->cpu), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - - object_property_set_bool(OBJECT(&s->avic), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->avic), 0, FSL_IMX25_AVIC_ADDR); - sysbus_connect_irq(SYS_BUS_DEVICE(&s->avic), 0, - qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_IRQ)); - sysbus_connect_irq(SYS_BUS_DEVICE(&s->avic), 1, - qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_FIQ)); - - object_property_set_bool(OBJECT(&s->ccm), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->ccm), 0, FSL_IMX25_CCM_ADDR); - - /* Initialize all UARTs */ - for (i = 0; i < FSL_IMX25_NUM_UARTS; i++) { - static const struct { - hwaddr addr; - unsigned int irq; - } serial_table[FSL_IMX25_NUM_UARTS] = { - { FSL_IMX25_UART1_ADDR, FSL_IMX25_UART1_IRQ }, - { FSL_IMX25_UART2_ADDR, FSL_IMX25_UART2_IRQ }, - { FSL_IMX25_UART3_ADDR, FSL_IMX25_UART3_IRQ }, - { FSL_IMX25_UART4_ADDR, FSL_IMX25_UART4_IRQ }, - { FSL_IMX25_UART5_ADDR, FSL_IMX25_UART5_IRQ } - }; - - if (i < MAX_SERIAL_PORTS) { - CharDriverState *chr; - - chr = serial_hds[i]; - - if (!chr) { - char label[20]; - snprintf(label, sizeof(label), "imx31.uart%d", i); - chr = qemu_chr_new(label, "null", NULL); - } - - qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", chr); - } - - object_property_set_bool(OBJECT(&s->uart[i]), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->uart[i]), 0, serial_table[i].addr); - sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart[i]), 0, - qdev_get_gpio_in(DEVICE(&s->avic), - serial_table[i].irq)); - } - - /* Initialize all GPT timers */ - for (i = 0; i < FSL_IMX25_NUM_GPTS; i++) { - static const struct { - hwaddr addr; - unsigned int irq; - } gpt_table[FSL_IMX25_NUM_GPTS] = { - { FSL_IMX25_GPT1_ADDR, FSL_IMX25_GPT1_IRQ }, - { FSL_IMX25_GPT2_ADDR, FSL_IMX25_GPT2_IRQ }, - { FSL_IMX25_GPT3_ADDR, FSL_IMX25_GPT3_IRQ }, - { FSL_IMX25_GPT4_ADDR, FSL_IMX25_GPT4_IRQ } - }; - - s->gpt[i].ccm = IMX_CCM(&s->ccm); - - object_property_set_bool(OBJECT(&s->gpt[i]), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpt[i]), 0, gpt_table[i].addr); - sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpt[i]), 0, - qdev_get_gpio_in(DEVICE(&s->avic), - gpt_table[i].irq)); - } - - /* Initialize all EPIT timers */ - for (i = 0; i < FSL_IMX25_NUM_EPITS; i++) { - static const struct { - hwaddr addr; - unsigned int irq; - } epit_table[FSL_IMX25_NUM_EPITS] = { - { FSL_IMX25_EPIT1_ADDR, FSL_IMX25_EPIT1_IRQ }, - { FSL_IMX25_EPIT2_ADDR, FSL_IMX25_EPIT2_IRQ } - }; - - s->epit[i].ccm = IMX_CCM(&s->ccm); - - object_property_set_bool(OBJECT(&s->epit[i]), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->epit[i]), 0, epit_table[i].addr); - sysbus_connect_irq(SYS_BUS_DEVICE(&s->epit[i]), 0, - qdev_get_gpio_in(DEVICE(&s->avic), - epit_table[i].irq)); - } - - qdev_set_nic_properties(DEVICE(&s->fec), &nd_table[0]); - object_property_set_bool(OBJECT(&s->fec), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->fec), 0, FSL_IMX25_FEC_ADDR); - sysbus_connect_irq(SYS_BUS_DEVICE(&s->fec), 0, - qdev_get_gpio_in(DEVICE(&s->avic), FSL_IMX25_FEC_IRQ)); - - - /* Initialize all I2C */ - for (i = 0; i < FSL_IMX25_NUM_I2CS; i++) { - static const struct { - hwaddr addr; - unsigned int irq; - } i2c_table[FSL_IMX25_NUM_I2CS] = { - { FSL_IMX25_I2C1_ADDR, FSL_IMX25_I2C1_IRQ }, - { FSL_IMX25_I2C2_ADDR, FSL_IMX25_I2C2_IRQ }, - { FSL_IMX25_I2C3_ADDR, FSL_IMX25_I2C3_IRQ } - }; - - object_property_set_bool(OBJECT(&s->i2c[i]), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c[i]), 0, i2c_table[i].addr); - sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c[i]), 0, - qdev_get_gpio_in(DEVICE(&s->avic), - i2c_table[i].irq)); - } - - /* Initialize all GPIOs */ - for (i = 0; i < FSL_IMX25_NUM_GPIOS; i++) { - static const struct { - hwaddr addr; - unsigned int irq; - } gpio_table[FSL_IMX25_NUM_GPIOS] = { - { FSL_IMX25_GPIO1_ADDR, FSL_IMX25_GPIO1_IRQ }, - { FSL_IMX25_GPIO2_ADDR, FSL_IMX25_GPIO2_IRQ }, - { FSL_IMX25_GPIO3_ADDR, FSL_IMX25_GPIO3_IRQ }, - { FSL_IMX25_GPIO4_ADDR, FSL_IMX25_GPIO4_IRQ } - }; - - object_property_set_bool(OBJECT(&s->gpio[i]), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio[i]), 0, gpio_table[i].addr); - /* Connect GPIO IRQ to PIC */ - sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 0, - qdev_get_gpio_in(DEVICE(&s->avic), - gpio_table[i].irq)); - } - - /* initialize 2 x 16 KB ROM */ - memory_region_init_rom_device(&s->rom[0], NULL, NULL, NULL, - "imx25.rom0", FSL_IMX25_ROM0_SIZE, &err); - if (err) { - error_propagate(errp, err); - return; - } - memory_region_add_subregion(get_system_memory(), FSL_IMX25_ROM0_ADDR, - &s->rom[0]); - memory_region_init_rom_device(&s->rom[1], NULL, NULL, NULL, - "imx25.rom1", FSL_IMX25_ROM1_SIZE, &err); - if (err) { - error_propagate(errp, err); - return; - } - memory_region_add_subregion(get_system_memory(), FSL_IMX25_ROM1_ADDR, - &s->rom[1]); - - /* initialize internal RAM (128 KB) */ - memory_region_init_ram(&s->iram, NULL, "imx25.iram", FSL_IMX25_IRAM_SIZE, - &err); - if (err) { - error_propagate(errp, err); - return; - } - memory_region_add_subregion(get_system_memory(), FSL_IMX25_IRAM_ADDR, - &s->iram); - vmstate_register_ram_global(&s->iram); - - /* internal RAM (128 KB) is aliased over 128 MB - 128 KB */ - memory_region_init_alias(&s->iram_alias, NULL, "imx25.iram_alias", - &s->iram, 0, FSL_IMX25_IRAM_ALIAS_SIZE); - memory_region_add_subregion(get_system_memory(), FSL_IMX25_IRAM_ALIAS_ADDR, - &s->iram_alias); -} - -static void fsl_imx25_class_init(ObjectClass *oc, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(oc); - - dc->realize = fsl_imx25_realize; - - /* - * Reason: creates an ARM CPU, thus use after free(), see - * arm_cpu_class_init() - */ - dc->cannot_destroy_with_object_finalize_yet = true; - dc->desc = "i.MX25 SOC"; -} - -static const TypeInfo fsl_imx25_type_info = { - .name = TYPE_FSL_IMX25, - .parent = TYPE_DEVICE, - .instance_size = sizeof(FslIMX25State), - .instance_init = fsl_imx25_init, - .class_init = fsl_imx25_class_init, -}; - -static void fsl_imx25_register_types(void) -{ - type_register_static(&fsl_imx25_type_info); -} - -type_init(fsl_imx25_register_types) diff --git a/qemu/hw/arm/fsl-imx31.c b/qemu/hw/arm/fsl-imx31.c deleted file mode 100644 index 31a3a8791..000000000 --- a/qemu/hw/arm/fsl-imx31.c +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Copyright (c) 2013 Jean-Christophe Dubois <jcd@tribudubois.net> - * - * i.MX31 SOC emulation. - * - * Based on hw/arm/fsl-imx31.c - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "qemu-common.h" -#include "cpu.h" -#include "hw/arm/fsl-imx31.h" -#include "sysemu/sysemu.h" -#include "exec/address-spaces.h" -#include "hw/boards.h" -#include "sysemu/char.h" - -static void fsl_imx31_init(Object *obj) -{ - FslIMX31State *s = FSL_IMX31(obj); - int i; - - object_initialize(&s->cpu, sizeof(s->cpu), "arm1136-" TYPE_ARM_CPU); - - object_initialize(&s->avic, sizeof(s->avic), TYPE_IMX_AVIC); - qdev_set_parent_bus(DEVICE(&s->avic), sysbus_get_default()); - - object_initialize(&s->ccm, sizeof(s->ccm), TYPE_IMX31_CCM); - qdev_set_parent_bus(DEVICE(&s->ccm), sysbus_get_default()); - - for (i = 0; i < FSL_IMX31_NUM_UARTS; i++) { - object_initialize(&s->uart[i], sizeof(s->uart[i]), TYPE_IMX_SERIAL); - qdev_set_parent_bus(DEVICE(&s->uart[i]), sysbus_get_default()); - } - - object_initialize(&s->gpt, sizeof(s->gpt), TYPE_IMX_GPT); - qdev_set_parent_bus(DEVICE(&s->gpt), sysbus_get_default()); - - for (i = 0; i < FSL_IMX31_NUM_EPITS; i++) { - object_initialize(&s->epit[i], sizeof(s->epit[i]), TYPE_IMX_EPIT); - qdev_set_parent_bus(DEVICE(&s->epit[i]), sysbus_get_default()); - } - - for (i = 0; i < FSL_IMX31_NUM_I2CS; i++) { - object_initialize(&s->i2c[i], sizeof(s->i2c[i]), TYPE_IMX_I2C); - qdev_set_parent_bus(DEVICE(&s->i2c[i]), sysbus_get_default()); - } - - for (i = 0; i < FSL_IMX31_NUM_GPIOS; i++) { - object_initialize(&s->gpio[i], sizeof(s->gpio[i]), TYPE_IMX_GPIO); - qdev_set_parent_bus(DEVICE(&s->gpio[i]), sysbus_get_default()); - } -} - -static void fsl_imx31_realize(DeviceState *dev, Error **errp) -{ - FslIMX31State *s = FSL_IMX31(dev); - uint16_t i; - Error *err = NULL; - - object_property_set_bool(OBJECT(&s->cpu), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - - object_property_set_bool(OBJECT(&s->avic), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->avic), 0, FSL_IMX31_AVIC_ADDR); - sysbus_connect_irq(SYS_BUS_DEVICE(&s->avic), 0, - qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_IRQ)); - sysbus_connect_irq(SYS_BUS_DEVICE(&s->avic), 1, - qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_FIQ)); - - object_property_set_bool(OBJECT(&s->ccm), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->ccm), 0, FSL_IMX31_CCM_ADDR); - - /* Initialize all UARTS */ - for (i = 0; i < FSL_IMX31_NUM_UARTS; i++) { - static const struct { - hwaddr addr; - unsigned int irq; - } serial_table[FSL_IMX31_NUM_UARTS] = { - { FSL_IMX31_UART1_ADDR, FSL_IMX31_UART1_IRQ }, - { FSL_IMX31_UART2_ADDR, FSL_IMX31_UART2_IRQ }, - }; - - if (i < MAX_SERIAL_PORTS) { - CharDriverState *chr; - - chr = serial_hds[i]; - - if (!chr) { - char label[20]; - snprintf(label, sizeof(label), "imx31.uart%d", i); - chr = qemu_chr_new(label, "null", NULL); - } - - qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", chr); - } - - object_property_set_bool(OBJECT(&s->uart[i]), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - - sysbus_mmio_map(SYS_BUS_DEVICE(&s->uart[i]), 0, serial_table[i].addr); - sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart[i]), 0, - qdev_get_gpio_in(DEVICE(&s->avic), - serial_table[i].irq)); - } - - s->gpt.ccm = IMX_CCM(&s->ccm); - - object_property_set_bool(OBJECT(&s->gpt), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - - sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpt), 0, FSL_IMX31_GPT_ADDR); - sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpt), 0, - qdev_get_gpio_in(DEVICE(&s->avic), FSL_IMX31_GPT_IRQ)); - - /* Initialize all EPIT timers */ - for (i = 0; i < FSL_IMX31_NUM_EPITS; i++) { - static const struct { - hwaddr addr; - unsigned int irq; - } epit_table[FSL_IMX31_NUM_EPITS] = { - { FSL_IMX31_EPIT1_ADDR, FSL_IMX31_EPIT1_IRQ }, - { FSL_IMX31_EPIT2_ADDR, FSL_IMX31_EPIT2_IRQ }, - }; - - s->epit[i].ccm = IMX_CCM(&s->ccm); - - object_property_set_bool(OBJECT(&s->epit[i]), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - - sysbus_mmio_map(SYS_BUS_DEVICE(&s->epit[i]), 0, epit_table[i].addr); - sysbus_connect_irq(SYS_BUS_DEVICE(&s->epit[i]), 0, - qdev_get_gpio_in(DEVICE(&s->avic), - epit_table[i].irq)); - } - - /* Initialize all I2C */ - for (i = 0; i < FSL_IMX31_NUM_I2CS; i++) { - static const struct { - hwaddr addr; - unsigned int irq; - } i2c_table[FSL_IMX31_NUM_I2CS] = { - { FSL_IMX31_I2C1_ADDR, FSL_IMX31_I2C1_IRQ }, - { FSL_IMX31_I2C2_ADDR, FSL_IMX31_I2C2_IRQ }, - { FSL_IMX31_I2C3_ADDR, FSL_IMX31_I2C3_IRQ } - }; - - /* Initialize the I2C */ - object_property_set_bool(OBJECT(&s->i2c[i]), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - /* Map I2C memory */ - sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c[i]), 0, i2c_table[i].addr); - /* Connect I2C IRQ to PIC */ - sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c[i]), 0, - qdev_get_gpio_in(DEVICE(&s->avic), - i2c_table[i].irq)); - } - - /* Initialize all GPIOs */ - for (i = 0; i < FSL_IMX31_NUM_GPIOS; i++) { - static const struct { - hwaddr addr; - unsigned int irq; - } gpio_table[FSL_IMX31_NUM_GPIOS] = { - { FSL_IMX31_GPIO1_ADDR, FSL_IMX31_GPIO1_IRQ }, - { FSL_IMX31_GPIO2_ADDR, FSL_IMX31_GPIO2_IRQ }, - { FSL_IMX31_GPIO3_ADDR, FSL_IMX31_GPIO3_IRQ } - }; - - object_property_set_bool(OBJECT(&s->gpio[i]), false, "has-edge-sel", - &error_abort); - object_property_set_bool(OBJECT(&s->gpio[i]), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio[i]), 0, gpio_table[i].addr); - /* Connect GPIO IRQ to PIC */ - sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 0, - qdev_get_gpio_in(DEVICE(&s->avic), - gpio_table[i].irq)); - } - - /* On a real system, the first 16k is a `secure boot rom' */ - memory_region_init_rom_device(&s->secure_rom, NULL, NULL, NULL, - "imx31.secure_rom", - FSL_IMX31_SECURE_ROM_SIZE, &err); - if (err) { - error_propagate(errp, err); - return; - } - memory_region_add_subregion(get_system_memory(), FSL_IMX31_SECURE_ROM_ADDR, - &s->secure_rom); - - /* There is also a 16k ROM */ - memory_region_init_rom_device(&s->rom, NULL, NULL, NULL, "imx31.rom", - FSL_IMX31_ROM_SIZE, &err); - if (err) { - error_propagate(errp, err); - return; - } - memory_region_add_subregion(get_system_memory(), FSL_IMX31_ROM_ADDR, - &s->rom); - - /* initialize internal RAM (16 KB) */ - memory_region_init_ram(&s->iram, NULL, "imx31.iram", FSL_IMX31_IRAM_SIZE, - &err); - if (err) { - error_propagate(errp, err); - return; - } - memory_region_add_subregion(get_system_memory(), FSL_IMX31_IRAM_ADDR, - &s->iram); - vmstate_register_ram_global(&s->iram); - - /* internal RAM (16 KB) is aliased over 256 MB - 16 KB */ - memory_region_init_alias(&s->iram_alias, NULL, "imx31.iram_alias", - &s->iram, 0, FSL_IMX31_IRAM_ALIAS_SIZE); - memory_region_add_subregion(get_system_memory(), FSL_IMX31_IRAM_ALIAS_ADDR, - &s->iram_alias); -} - -static void fsl_imx31_class_init(ObjectClass *oc, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(oc); - - dc->realize = fsl_imx31_realize; - - /* - * Reason: creates an ARM CPU, thus use after free(), see - * arm_cpu_class_init() - */ - dc->cannot_destroy_with_object_finalize_yet = true; - dc->desc = "i.MX31 SOC"; -} - -static const TypeInfo fsl_imx31_type_info = { - .name = TYPE_FSL_IMX31, - .parent = TYPE_DEVICE, - .instance_size = sizeof(FslIMX31State), - .instance_init = fsl_imx31_init, - .class_init = fsl_imx31_class_init, -}; - -static void fsl_imx31_register_types(void) -{ - type_register_static(&fsl_imx31_type_info); -} - -type_init(fsl_imx31_register_types) diff --git a/qemu/hw/arm/gumstix.c b/qemu/hw/arm/gumstix.c deleted file mode 100644 index d59d9ba4e..000000000 --- a/qemu/hw/arm/gumstix.c +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Gumstix Platforms - * - * Copyright (c) 2007 by Thorsten Zitterell <info@bitmux.org> - * - * Code based on spitz platform by Andrzej Zaborowski <balrog@zabor.org> - * - * 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. - */ - -/* - * Example usage: - * - * connex: - * ======= - * create image: - * # dd of=flash bs=1k count=16k if=/dev/zero - * # dd of=flash bs=1k conv=notrunc if=u-boot.bin - * # dd of=flash bs=1k conv=notrunc seek=256 if=rootfs.arm_nofpu.jffs2 - * start it: - * # qemu-system-arm -M connex -pflash flash -monitor null -nographic - * - * verdex: - * ======= - * create image: - * # dd of=flash bs=1k count=32k if=/dev/zero - * # dd of=flash bs=1k conv=notrunc if=u-boot.bin - * # dd of=flash bs=1k conv=notrunc seek=256 if=rootfs.arm_nofpu.jffs2 - * # dd of=flash bs=1k conv=notrunc seek=31744 if=uImage - * start it: - * # qemu-system-arm -M verdex -pflash flash -monitor null -nographic -m 289 - */ - -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/arm/pxa.h" -#include "net/net.h" -#include "hw/block/flash.h" -#include "hw/devices.h" -#include "hw/boards.h" -#include "sysemu/block-backend.h" -#include "exec/address-spaces.h" -#include "sysemu/qtest.h" - -static const int sector_len = 128 * 1024; - -static void connex_init(MachineState *machine) -{ - PXA2xxState *cpu; - DriveInfo *dinfo; - int be; - MemoryRegion *address_space_mem = get_system_memory(); - - uint32_t connex_rom = 0x01000000; - uint32_t connex_ram = 0x04000000; - - cpu = pxa255_init(address_space_mem, connex_ram); - - dinfo = drive_get(IF_PFLASH, 0, 0); - if (!dinfo && !qtest_enabled()) { - fprintf(stderr, "A flash image must be given with the " - "'pflash' parameter\n"); - exit(1); - } - -#ifdef TARGET_WORDS_BIGENDIAN - be = 1; -#else - be = 0; -#endif - if (!pflash_cfi01_register(0x00000000, NULL, "connext.rom", connex_rom, - dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, - sector_len, connex_rom / sector_len, - 2, 0, 0, 0, 0, be)) { - fprintf(stderr, "qemu: Error registering flash memory.\n"); - exit(1); - } - - /* Interrupt line of NIC is connected to GPIO line 36 */ - smc91c111_init(&nd_table[0], 0x04000300, - qdev_get_gpio_in(cpu->gpio, 36)); -} - -static void verdex_init(MachineState *machine) -{ - const char *cpu_model = machine->cpu_model; - PXA2xxState *cpu; - DriveInfo *dinfo; - int be; - MemoryRegion *address_space_mem = get_system_memory(); - - uint32_t verdex_rom = 0x02000000; - uint32_t verdex_ram = 0x10000000; - - cpu = pxa270_init(address_space_mem, verdex_ram, cpu_model ?: "pxa270-c0"); - - dinfo = drive_get(IF_PFLASH, 0, 0); - if (!dinfo && !qtest_enabled()) { - fprintf(stderr, "A flash image must be given with the " - "'pflash' parameter\n"); - exit(1); - } - -#ifdef TARGET_WORDS_BIGENDIAN - be = 1; -#else - be = 0; -#endif - if (!pflash_cfi01_register(0x00000000, NULL, "verdex.rom", verdex_rom, - dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, - sector_len, verdex_rom / sector_len, - 2, 0, 0, 0, 0, be)) { - fprintf(stderr, "qemu: Error registering flash memory.\n"); - exit(1); - } - - /* Interrupt line of NIC is connected to GPIO line 99 */ - smc91c111_init(&nd_table[0], 0x04000300, - qdev_get_gpio_in(cpu->gpio, 99)); -} - -static void connex_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "Gumstix Connex (PXA255)"; - mc->init = connex_init; -} - -static const TypeInfo connex_type = { - .name = MACHINE_TYPE_NAME("connex"), - .parent = TYPE_MACHINE, - .class_init = connex_class_init, -}; - -static void verdex_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "Gumstix Verdex (PXA270)"; - mc->init = verdex_init; -} - -static const TypeInfo verdex_type = { - .name = MACHINE_TYPE_NAME("verdex"), - .parent = TYPE_MACHINE, - .class_init = verdex_class_init, -}; - -static void gumstix_machine_init(void) -{ - type_register_static(&connex_type); - type_register_static(&verdex_type); -} - -type_init(gumstix_machine_init) diff --git a/qemu/hw/arm/highbank.c b/qemu/hw/arm/highbank.c deleted file mode 100644 index d9930c0d3..000000000 --- a/qemu/hw/arm/highbank.c +++ /dev/null @@ -1,441 +0,0 @@ -/* - * Calxeda Highbank SoC emulation - * - * Copyright (c) 2010-2012 Calxeda - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2 or later, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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 <http://www.gnu.org/licenses/>. - * - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "hw/sysbus.h" -#include "hw/arm/arm.h" -#include "hw/devices.h" -#include "hw/loader.h" -#include "net/net.h" -#include "sysemu/kvm.h" -#include "sysemu/sysemu.h" -#include "hw/boards.h" -#include "sysemu/block-backend.h" -#include "exec/address-spaces.h" -#include "qemu/error-report.h" - -#define SMP_BOOT_ADDR 0x100 -#define SMP_BOOT_REG 0x40 -#define MPCORE_PERIPHBASE 0xfff10000 - -#define MVBAR_ADDR 0x200 -#define BOARD_SETUP_ADDR (MVBAR_ADDR + 8 * sizeof(uint32_t)) - -#define NIRQ_GIC 160 - -/* Board init. */ - -static void hb_write_board_setup(ARMCPU *cpu, - const struct arm_boot_info *info) -{ - arm_write_secure_board_setup_dummy_smc(cpu, info, MVBAR_ADDR); -} - -static void hb_write_secondary(ARMCPU *cpu, const struct arm_boot_info *info) -{ - int n; - uint32_t smpboot[] = { - 0xee100fb0, /* mrc p15, 0, r0, c0, c0, 5 - read current core id */ - 0xe210000f, /* ands r0, r0, #0x0f */ - 0xe3a03040, /* mov r3, #0x40 - jump address is 0x40 + 0x10 * core id */ - 0xe0830200, /* add r0, r3, r0, lsl #4 */ - 0xe59f2024, /* ldr r2, privbase */ - 0xe3a01001, /* mov r1, #1 */ - 0xe5821100, /* str r1, [r2, #256] - set GICC_CTLR.Enable */ - 0xe3a010ff, /* mov r1, #0xff */ - 0xe5821104, /* str r1, [r2, #260] - set GICC_PMR.Priority to 0xff */ - 0xf57ff04f, /* dsb */ - 0xe320f003, /* wfi */ - 0xe5901000, /* ldr r1, [r0] */ - 0xe1110001, /* tst r1, r1 */ - 0x0afffffb, /* beq <wfi> */ - 0xe12fff11, /* bx r1 */ - MPCORE_PERIPHBASE /* privbase: MPCore peripheral base address. */ - }; - for (n = 0; n < ARRAY_SIZE(smpboot); n++) { - smpboot[n] = tswap32(smpboot[n]); - } - rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot), SMP_BOOT_ADDR); -} - -static void hb_reset_secondary(ARMCPU *cpu, const struct arm_boot_info *info) -{ - CPUARMState *env = &cpu->env; - - switch (info->nb_cpus) { - case 4: - address_space_stl_notdirty(&address_space_memory, - SMP_BOOT_REG + 0x30, 0, - MEMTXATTRS_UNSPECIFIED, NULL); - case 3: - address_space_stl_notdirty(&address_space_memory, - SMP_BOOT_REG + 0x20, 0, - MEMTXATTRS_UNSPECIFIED, NULL); - case 2: - address_space_stl_notdirty(&address_space_memory, - SMP_BOOT_REG + 0x10, 0, - MEMTXATTRS_UNSPECIFIED, NULL); - env->regs[15] = SMP_BOOT_ADDR; - break; - default: - break; - } -} - -#define NUM_REGS 0x200 -static void hb_regs_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - uint32_t *regs = opaque; - - if (offset == 0xf00) { - if (value == 1 || value == 2) { - qemu_system_reset_request(); - } else if (value == 3) { - qemu_system_shutdown_request(); - } - } - - regs[offset/4] = value; -} - -static uint64_t hb_regs_read(void *opaque, hwaddr offset, - unsigned size) -{ - uint32_t *regs = opaque; - uint32_t value = regs[offset/4]; - - if ((offset == 0x100) || (offset == 0x108) || (offset == 0x10C)) { - value |= 0x30000000; - } - - return value; -} - -static const MemoryRegionOps hb_mem_ops = { - .read = hb_regs_read, - .write = hb_regs_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -#define TYPE_HIGHBANK_REGISTERS "highbank-regs" -#define HIGHBANK_REGISTERS(obj) \ - OBJECT_CHECK(HighbankRegsState, (obj), TYPE_HIGHBANK_REGISTERS) - -typedef struct { - /*< private >*/ - SysBusDevice parent_obj; - /*< public >*/ - - MemoryRegion iomem; - uint32_t regs[NUM_REGS]; -} HighbankRegsState; - -static VMStateDescription vmstate_highbank_regs = { - .name = "highbank-regs", - .version_id = 0, - .minimum_version_id = 0, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(regs, HighbankRegsState, NUM_REGS), - VMSTATE_END_OF_LIST(), - }, -}; - -static void highbank_regs_reset(DeviceState *dev) -{ - HighbankRegsState *s = HIGHBANK_REGISTERS(dev); - - s->regs[0x40] = 0x05F20121; - s->regs[0x41] = 0x2; - s->regs[0x42] = 0x05F30121; - s->regs[0x43] = 0x05F40121; -} - -static int highbank_regs_init(SysBusDevice *dev) -{ - HighbankRegsState *s = HIGHBANK_REGISTERS(dev); - - memory_region_init_io(&s->iomem, OBJECT(s), &hb_mem_ops, s->regs, - "highbank_regs", 0x1000); - sysbus_init_mmio(dev, &s->iomem); - - return 0; -} - -static void highbank_regs_class_init(ObjectClass *klass, void *data) -{ - SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass); - DeviceClass *dc = DEVICE_CLASS(klass); - - sbc->init = highbank_regs_init; - dc->desc = "Calxeda Highbank registers"; - dc->vmsd = &vmstate_highbank_regs; - dc->reset = highbank_regs_reset; -} - -static const TypeInfo highbank_regs_info = { - .name = TYPE_HIGHBANK_REGISTERS, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(HighbankRegsState), - .class_init = highbank_regs_class_init, -}; - -static void highbank_regs_register_types(void) -{ - type_register_static(&highbank_regs_info); -} - -type_init(highbank_regs_register_types) - -static struct arm_boot_info highbank_binfo; - -enum cxmachines { - CALXEDA_HIGHBANK, - CALXEDA_MIDWAY, -}; - -/* ram_size must be set to match the upper bound of memory in the - * device tree (linux/arch/arm/boot/dts/highbank.dts), which is - * normally 0xff900000 or -m 4089. When running this board on a - * 32-bit host, set the reg value of memory to 0xf7ff00000 in the - * device tree and pass -m 2047 to QEMU. - */ -static void calxeda_init(MachineState *machine, enum cxmachines machine_id) -{ - ram_addr_t ram_size = machine->ram_size; - const char *cpu_model = machine->cpu_model; - const char *kernel_filename = machine->kernel_filename; - const char *kernel_cmdline = machine->kernel_cmdline; - const char *initrd_filename = machine->initrd_filename; - DeviceState *dev = NULL; - SysBusDevice *busdev; - qemu_irq pic[128]; - int n; - qemu_irq cpu_irq[4]; - qemu_irq cpu_fiq[4]; - MemoryRegion *sysram; - MemoryRegion *dram; - MemoryRegion *sysmem; - char *sysboot_filename; - - switch (machine_id) { - case CALXEDA_HIGHBANK: - cpu_model = "cortex-a9"; - break; - case CALXEDA_MIDWAY: - cpu_model = "cortex-a15"; - break; - } - - for (n = 0; n < smp_cpus; n++) { - ObjectClass *oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model); - Object *cpuobj; - ARMCPU *cpu; - - cpuobj = object_new(object_class_get_name(oc)); - cpu = ARM_CPU(cpuobj); - - object_property_set_int(cpuobj, QEMU_PSCI_CONDUIT_SMC, - "psci-conduit", &error_abort); - - if (n) { - /* Secondary CPUs start in PSCI powered-down state */ - object_property_set_bool(cpuobj, true, - "start-powered-off", &error_abort); - } - - if (object_property_find(cpuobj, "reset-cbar", NULL)) { - object_property_set_int(cpuobj, MPCORE_PERIPHBASE, - "reset-cbar", &error_abort); - } - object_property_set_bool(cpuobj, true, "realized", &error_fatal); - cpu_irq[n] = qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ); - cpu_fiq[n] = qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_FIQ); - } - - sysmem = get_system_memory(); - dram = g_new(MemoryRegion, 1); - memory_region_allocate_system_memory(dram, NULL, "highbank.dram", ram_size); - /* SDRAM at address zero. */ - memory_region_add_subregion(sysmem, 0, dram); - - sysram = g_new(MemoryRegion, 1); - memory_region_init_ram(sysram, NULL, "highbank.sysram", 0x8000, - &error_fatal); - memory_region_add_subregion(sysmem, 0xfff88000, sysram); - if (bios_name != NULL) { - sysboot_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); - if (sysboot_filename != NULL) { - if (load_image_targphys(sysboot_filename, 0xfff88000, 0x8000) < 0) { - error_report("Unable to load %s", bios_name); - exit(1); - } - g_free(sysboot_filename); - } else { - error_report("Unable to find %s", bios_name); - exit(1); - } - } - - switch (machine_id) { - case CALXEDA_HIGHBANK: - dev = qdev_create(NULL, "l2x0"); - qdev_init_nofail(dev); - busdev = SYS_BUS_DEVICE(dev); - sysbus_mmio_map(busdev, 0, 0xfff12000); - - dev = qdev_create(NULL, "a9mpcore_priv"); - break; - case CALXEDA_MIDWAY: - dev = qdev_create(NULL, "a15mpcore_priv"); - break; - } - qdev_prop_set_uint32(dev, "num-cpu", smp_cpus); - qdev_prop_set_uint32(dev, "num-irq", NIRQ_GIC); - qdev_init_nofail(dev); - busdev = SYS_BUS_DEVICE(dev); - sysbus_mmio_map(busdev, 0, MPCORE_PERIPHBASE); - for (n = 0; n < smp_cpus; n++) { - sysbus_connect_irq(busdev, n, cpu_irq[n]); - sysbus_connect_irq(busdev, n + smp_cpus, cpu_fiq[n]); - } - - for (n = 0; n < 128; n++) { - pic[n] = qdev_get_gpio_in(dev, n); - } - - dev = qdev_create(NULL, "sp804"); - qdev_prop_set_uint32(dev, "freq0", 150000000); - qdev_prop_set_uint32(dev, "freq1", 150000000); - qdev_init_nofail(dev); - busdev = SYS_BUS_DEVICE(dev); - sysbus_mmio_map(busdev, 0, 0xfff34000); - sysbus_connect_irq(busdev, 0, pic[18]); - sysbus_create_simple("pl011", 0xfff36000, pic[20]); - - dev = qdev_create(NULL, "highbank-regs"); - qdev_init_nofail(dev); - busdev = SYS_BUS_DEVICE(dev); - sysbus_mmio_map(busdev, 0, 0xfff3c000); - - sysbus_create_simple("pl061", 0xfff30000, pic[14]); - sysbus_create_simple("pl061", 0xfff31000, pic[15]); - sysbus_create_simple("pl061", 0xfff32000, pic[16]); - sysbus_create_simple("pl061", 0xfff33000, pic[17]); - sysbus_create_simple("pl031", 0xfff35000, pic[19]); - sysbus_create_simple("pl022", 0xfff39000, pic[23]); - - sysbus_create_simple("sysbus-ahci", 0xffe08000, pic[83]); - - if (nd_table[0].used) { - qemu_check_nic_model(&nd_table[0], "xgmac"); - dev = qdev_create(NULL, "xgmac"); - qdev_set_nic_properties(dev, &nd_table[0]); - qdev_init_nofail(dev); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xfff50000); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[77]); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, pic[78]); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, pic[79]); - - qemu_check_nic_model(&nd_table[1], "xgmac"); - dev = qdev_create(NULL, "xgmac"); - qdev_set_nic_properties(dev, &nd_table[1]); - qdev_init_nofail(dev); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xfff51000); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[80]); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, pic[81]); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, pic[82]); - } - - highbank_binfo.ram_size = ram_size; - highbank_binfo.kernel_filename = kernel_filename; - highbank_binfo.kernel_cmdline = kernel_cmdline; - highbank_binfo.initrd_filename = initrd_filename; - /* highbank requires a dtb in order to boot, and the dtb will override - * the board ID. The following value is ignored, so set it to -1 to be - * clear that the value is meaningless. - */ - highbank_binfo.board_id = -1; - highbank_binfo.nb_cpus = smp_cpus; - highbank_binfo.loader_start = 0; - highbank_binfo.write_secondary_boot = hb_write_secondary; - highbank_binfo.secondary_cpu_reset_hook = hb_reset_secondary; - if (!kvm_enabled()) { - highbank_binfo.board_setup_addr = BOARD_SETUP_ADDR; - highbank_binfo.write_board_setup = hb_write_board_setup; - highbank_binfo.secure_board_setup = true; - } else { - error_report("WARNING: cannot load built-in Monitor support " - "if KVM is enabled. Some guests (such as Linux) " - "may not boot."); - } - - arm_load_kernel(ARM_CPU(first_cpu), &highbank_binfo); -} - -static void highbank_init(MachineState *machine) -{ - calxeda_init(machine, CALXEDA_HIGHBANK); -} - -static void midway_init(MachineState *machine) -{ - calxeda_init(machine, CALXEDA_MIDWAY); -} - -static void highbank_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "Calxeda Highbank (ECX-1000)"; - mc->init = highbank_init; - mc->block_default_type = IF_SCSI; - mc->max_cpus = 4; -} - -static const TypeInfo highbank_type = { - .name = MACHINE_TYPE_NAME("highbank"), - .parent = TYPE_MACHINE, - .class_init = highbank_class_init, -}; - -static void midway_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "Calxeda Midway (ECX-2000)"; - mc->init = midway_init; - mc->block_default_type = IF_SCSI; - mc->max_cpus = 4; -} - -static const TypeInfo midway_type = { - .name = MACHINE_TYPE_NAME("midway"), - .parent = TYPE_MACHINE, - .class_init = midway_class_init, -}; - -static void calxeda_machines_init(void) -{ - type_register_static(&highbank_type); - type_register_static(&midway_type); -} - -type_init(calxeda_machines_init) diff --git a/qemu/hw/arm/imx25_pdk.c b/qemu/hw/arm/imx25_pdk.c deleted file mode 100644 index 025b60843..000000000 --- a/qemu/hw/arm/imx25_pdk.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright (c) 2013 Jean-Christophe Dubois <jcd@tribudubois.net> - * - * PDK Board System emulation. - * - * Based on hw/arm/kzm.c - * - * Copyright (c) 2008 OKL and 2011 NICTA - * Written by Hans at OK-Labs - * Updated by Peter Chubb. - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "qemu-common.h" -#include "cpu.h" -#include "hw/arm/fsl-imx25.h" -#include "hw/boards.h" -#include "qemu/error-report.h" -#include "exec/address-spaces.h" -#include "sysemu/qtest.h" -#include "hw/i2c/i2c.h" - -/* Memory map for PDK Emulation Baseboard: - * 0x00000000-0x7fffffff See i.MX25 SOC fr support - * 0x80000000-0x87ffffff RAM + Alias EMULATED - * 0x90000000-0x9fffffff RAM + Alias EMULATED - * 0xa0000000-0xa7ffffff Flash IGNORED - * 0xa8000000-0xafffffff Flash IGNORED - * 0xb0000000-0xb1ffffff SRAM IGNORED - * 0xb2000000-0xb3ffffff SRAM IGNORED - * 0xb4000000-0xb5ffffff CS4 IGNORED - * 0xb6000000-0xb8000fff Reserved IGNORED - * 0xb8001000-0xb8001fff SDRAM CTRL reg IGNORED - * 0xb8002000-0xb8002fff WEIM CTRL reg IGNORED - * 0xb8003000-0xb8003fff M3IF CTRL reg IGNORED - * 0xb8004000-0xb8004fff EMI CTRL reg IGNORED - * 0xb8005000-0xbaffffff Reserved IGNORED - * 0xbb000000-0xbb000fff NAND flash area buf IGNORED - * 0xbb001000-0xbb0011ff NAND flash reserved IGNORED - * 0xbb001200-0xbb001dff Reserved IGNORED - * 0xbb001e00-0xbb001fff NAN flash CTRL reg IGNORED - * 0xbb012000-0xbfffffff Reserved IGNORED - * 0xc0000000-0xffffffff Reserved IGNORED - */ - -typedef struct IMX25PDK { - FslIMX25State soc; - MemoryRegion ram; - MemoryRegion ram_alias; -} IMX25PDK; - -static struct arm_boot_info imx25_pdk_binfo; - -static void imx25_pdk_init(MachineState *machine) -{ - IMX25PDK *s = g_new0(IMX25PDK, 1); - unsigned int ram_size; - unsigned int alias_offset; - int i; - - object_initialize(&s->soc, sizeof(s->soc), TYPE_FSL_IMX25); - object_property_add_child(OBJECT(machine), "soc", OBJECT(&s->soc), - &error_abort); - - object_property_set_bool(OBJECT(&s->soc), true, "realized", &error_fatal); - - /* We need to initialize our memory */ - if (machine->ram_size > (FSL_IMX25_SDRAM0_SIZE + FSL_IMX25_SDRAM1_SIZE)) { - error_report("WARNING: RAM size " RAM_ADDR_FMT " above max supported, " - "reduced to %x", machine->ram_size, - FSL_IMX25_SDRAM0_SIZE + FSL_IMX25_SDRAM1_SIZE); - machine->ram_size = FSL_IMX25_SDRAM0_SIZE + FSL_IMX25_SDRAM1_SIZE; - } - - memory_region_allocate_system_memory(&s->ram, NULL, "imx25.ram", - machine->ram_size); - memory_region_add_subregion(get_system_memory(), FSL_IMX25_SDRAM0_ADDR, - &s->ram); - - /* initialize the alias memory if any */ - for (i = 0, ram_size = machine->ram_size, alias_offset = 0; - (i < 2) && ram_size; i++) { - unsigned int size; - static const struct { - hwaddr addr; - unsigned int size; - } ram[2] = { - { FSL_IMX25_SDRAM0_ADDR, FSL_IMX25_SDRAM0_SIZE }, - { FSL_IMX25_SDRAM1_ADDR, FSL_IMX25_SDRAM1_SIZE }, - }; - - size = MIN(ram_size, ram[i].size); - - ram_size -= size; - - if (size < ram[i].size) { - memory_region_init_alias(&s->ram_alias, NULL, "ram.alias", - &s->ram, alias_offset, ram[i].size - size); - memory_region_add_subregion(get_system_memory(), - ram[i].addr + size, &s->ram_alias); - } - - alias_offset += ram[i].size; - } - - imx25_pdk_binfo.ram_size = machine->ram_size; - imx25_pdk_binfo.kernel_filename = machine->kernel_filename; - imx25_pdk_binfo.kernel_cmdline = machine->kernel_cmdline; - imx25_pdk_binfo.initrd_filename = machine->initrd_filename; - imx25_pdk_binfo.loader_start = FSL_IMX25_SDRAM0_ADDR; - imx25_pdk_binfo.board_id = 1771, - imx25_pdk_binfo.nb_cpus = 1; - - /* - * We test explicitly for qtest here as it is not done (yet?) in - * arm_load_kernel(). Without this the "make check" command would - * fail. - */ - if (!qtest_enabled()) { - arm_load_kernel(&s->soc.cpu, &imx25_pdk_binfo); - } else { - /* - * This I2C device doesn't exist on the real board. - * We add it here (only on qtest usage) to be able to do a bit - * of simple qtest. See "make check" for details. - */ - i2c_create_slave((I2CBus *)qdev_get_child_bus(DEVICE(&s->soc.i2c[0]), - "i2c"), - "ds1338", 0x68); - } -} - -static void imx25_pdk_machine_init(MachineClass *mc) -{ - mc->desc = "ARM i.MX25 PDK board (ARM926)"; - mc->init = imx25_pdk_init; -} - -DEFINE_MACHINE("imx25-pdk", imx25_pdk_machine_init) diff --git a/qemu/hw/arm/integratorcp.c b/qemu/hw/arm/integratorcp.c deleted file mode 100644 index e31bca6e7..000000000 --- a/qemu/hw/arm/integratorcp.c +++ /dev/null @@ -1,674 +0,0 @@ -/* - * ARM Integrator CP System emulation. - * - * Copyright (c) 2005-2007 CodeSourcery. - * Written by Paul Brook - * - * This code is licensed under the GPL - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "qemu-common.h" -#include "cpu.h" -#include "hw/sysbus.h" -#include "hw/devices.h" -#include "hw/boards.h" -#include "hw/arm/arm.h" -#include "hw/misc/arm_integrator_debug.h" -#include "net/net.h" -#include "exec/address-spaces.h" -#include "sysemu/sysemu.h" -#include "qemu/error-report.h" - -#define TYPE_INTEGRATOR_CM "integrator_core" -#define INTEGRATOR_CM(obj) \ - OBJECT_CHECK(IntegratorCMState, (obj), TYPE_INTEGRATOR_CM) - -typedef struct IntegratorCMState { - /*< private >*/ - SysBusDevice parent_obj; - /*< public >*/ - - MemoryRegion iomem; - uint32_t memsz; - MemoryRegion flash; - uint32_t cm_osc; - uint32_t cm_ctrl; - uint32_t cm_lock; - uint32_t cm_auxosc; - uint32_t cm_sdram; - uint32_t cm_init; - uint32_t cm_flags; - uint32_t cm_nvflags; - uint32_t cm_refcnt_offset; - uint32_t int_level; - uint32_t irq_enabled; - uint32_t fiq_enabled; -} IntegratorCMState; - -static uint8_t integrator_spd[128] = { - 128, 8, 4, 11, 9, 1, 64, 0, 2, 0xa0, 0xa0, 0, 0, 8, 0, 1, - 0xe, 4, 0x1c, 1, 2, 0x20, 0xc0, 0, 0, 0, 0, 0x30, 0x28, 0x30, 0x28, 0x40 -}; - -static uint64_t integratorcm_read(void *opaque, hwaddr offset, - unsigned size) -{ - IntegratorCMState *s = opaque; - if (offset >= 0x100 && offset < 0x200) { - /* CM_SPD */ - if (offset >= 0x180) - return 0; - return integrator_spd[offset >> 2]; - } - switch (offset >> 2) { - case 0: /* CM_ID */ - return 0x411a3001; - case 1: /* CM_PROC */ - return 0; - case 2: /* CM_OSC */ - return s->cm_osc; - case 3: /* CM_CTRL */ - return s->cm_ctrl; - case 4: /* CM_STAT */ - return 0x00100000; - case 5: /* CM_LOCK */ - if (s->cm_lock == 0xa05f) { - return 0x1a05f; - } else { - return s->cm_lock; - } - case 6: /* CM_LMBUSCNT */ - /* ??? High frequency timer. */ - hw_error("integratorcm_read: CM_LMBUSCNT"); - case 7: /* CM_AUXOSC */ - return s->cm_auxosc; - case 8: /* CM_SDRAM */ - return s->cm_sdram; - case 9: /* CM_INIT */ - return s->cm_init; - case 10: /* CM_REFCNT */ - /* This register, CM_REFCNT, provides a 32-bit count value. - * The count increments at the fixed reference clock frequency of 24MHz - * and can be used as a real-time counter. - */ - return (uint32_t)muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24, - 1000) - s->cm_refcnt_offset; - case 12: /* CM_FLAGS */ - return s->cm_flags; - case 14: /* CM_NVFLAGS */ - return s->cm_nvflags; - case 16: /* CM_IRQ_STAT */ - return s->int_level & s->irq_enabled; - case 17: /* CM_IRQ_RSTAT */ - return s->int_level; - case 18: /* CM_IRQ_ENSET */ - return s->irq_enabled; - case 20: /* CM_SOFT_INTSET */ - return s->int_level & 1; - case 24: /* CM_FIQ_STAT */ - return s->int_level & s->fiq_enabled; - case 25: /* CM_FIQ_RSTAT */ - return s->int_level; - case 26: /* CM_FIQ_ENSET */ - return s->fiq_enabled; - case 32: /* CM_VOLTAGE_CTL0 */ - case 33: /* CM_VOLTAGE_CTL1 */ - case 34: /* CM_VOLTAGE_CTL2 */ - case 35: /* CM_VOLTAGE_CTL3 */ - /* ??? Voltage control unimplemented. */ - return 0; - default: - hw_error("integratorcm_read: Unimplemented offset 0x%x\n", - (int)offset); - return 0; - } -} - -static void integratorcm_do_remap(IntegratorCMState *s) -{ - /* Sync memory region state with CM_CTRL REMAP bit: - * bit 0 => flash at address 0; bit 1 => RAM - */ - memory_region_set_enabled(&s->flash, !(s->cm_ctrl & 4)); -} - -static void integratorcm_set_ctrl(IntegratorCMState *s, uint32_t value) -{ - if (value & 8) { - qemu_system_reset_request(); - } - if ((s->cm_ctrl ^ value) & 1) { - /* (value & 1) != 0 means the green "MISC LED" is lit. - * We don't have any nice place to display LEDs. printf is a bad - * idea because Linux uses the LED as a heartbeat and the output - * will swamp anything else on the terminal. - */ - } - /* Note that the RESET bit [3] always reads as zero */ - s->cm_ctrl = (s->cm_ctrl & ~5) | (value & 5); - integratorcm_do_remap(s); -} - -static void integratorcm_update(IntegratorCMState *s) -{ - /* ??? The CPU irq/fiq is raised when either the core module or base PIC - are active. */ - if (s->int_level & (s->irq_enabled | s->fiq_enabled)) - hw_error("Core module interrupt\n"); -} - -static void integratorcm_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - IntegratorCMState *s = opaque; - switch (offset >> 2) { - case 2: /* CM_OSC */ - if (s->cm_lock == 0xa05f) - s->cm_osc = value; - break; - case 3: /* CM_CTRL */ - integratorcm_set_ctrl(s, value); - break; - case 5: /* CM_LOCK */ - s->cm_lock = value & 0xffff; - break; - case 7: /* CM_AUXOSC */ - if (s->cm_lock == 0xa05f) - s->cm_auxosc = value; - break; - case 8: /* CM_SDRAM */ - s->cm_sdram = value; - break; - case 9: /* CM_INIT */ - /* ??? This can change the memory bus frequency. */ - s->cm_init = value; - break; - case 12: /* CM_FLAGSS */ - s->cm_flags |= value; - break; - case 13: /* CM_FLAGSC */ - s->cm_flags &= ~value; - break; - case 14: /* CM_NVFLAGSS */ - s->cm_nvflags |= value; - break; - case 15: /* CM_NVFLAGSS */ - s->cm_nvflags &= ~value; - break; - case 18: /* CM_IRQ_ENSET */ - s->irq_enabled |= value; - integratorcm_update(s); - break; - case 19: /* CM_IRQ_ENCLR */ - s->irq_enabled &= ~value; - integratorcm_update(s); - break; - case 20: /* CM_SOFT_INTSET */ - s->int_level |= (value & 1); - integratorcm_update(s); - break; - case 21: /* CM_SOFT_INTCLR */ - s->int_level &= ~(value & 1); - integratorcm_update(s); - break; - case 26: /* CM_FIQ_ENSET */ - s->fiq_enabled |= value; - integratorcm_update(s); - break; - case 27: /* CM_FIQ_ENCLR */ - s->fiq_enabled &= ~value; - integratorcm_update(s); - break; - case 32: /* CM_VOLTAGE_CTL0 */ - case 33: /* CM_VOLTAGE_CTL1 */ - case 34: /* CM_VOLTAGE_CTL2 */ - case 35: /* CM_VOLTAGE_CTL3 */ - /* ??? Voltage control unimplemented. */ - break; - default: - hw_error("integratorcm_write: Unimplemented offset 0x%x\n", - (int)offset); - break; - } -} - -/* Integrator/CM control registers. */ - -static const MemoryRegionOps integratorcm_ops = { - .read = integratorcm_read, - .write = integratorcm_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static int integratorcm_init(SysBusDevice *dev) -{ - IntegratorCMState *s = INTEGRATOR_CM(dev); - - s->cm_osc = 0x01000048; - /* ??? What should the high bits of this value be? */ - s->cm_auxosc = 0x0007feff; - s->cm_sdram = 0x00011122; - if (s->memsz >= 256) { - integrator_spd[31] = 64; - s->cm_sdram |= 0x10; - } else if (s->memsz >= 128) { - integrator_spd[31] = 32; - s->cm_sdram |= 0x0c; - } else if (s->memsz >= 64) { - integrator_spd[31] = 16; - s->cm_sdram |= 0x08; - } else if (s->memsz >= 32) { - integrator_spd[31] = 4; - s->cm_sdram |= 0x04; - } else { - integrator_spd[31] = 2; - } - memcpy(integrator_spd + 73, "QEMU-MEMORY", 11); - s->cm_init = 0x00000112; - s->cm_refcnt_offset = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24, - 1000); - memory_region_init_ram(&s->flash, OBJECT(s), "integrator.flash", 0x100000, - &error_fatal); - vmstate_register_ram_global(&s->flash); - - memory_region_init_io(&s->iomem, OBJECT(s), &integratorcm_ops, s, - "integratorcm", 0x00800000); - sysbus_init_mmio(dev, &s->iomem); - - integratorcm_do_remap(s); - /* ??? Save/restore. */ - return 0; -} - -/* Integrator/CP hardware emulation. */ -/* Primary interrupt controller. */ - -#define TYPE_INTEGRATOR_PIC "integrator_pic" -#define INTEGRATOR_PIC(obj) \ - OBJECT_CHECK(icp_pic_state, (obj), TYPE_INTEGRATOR_PIC) - -typedef struct icp_pic_state { - /*< private >*/ - SysBusDevice parent_obj; - /*< public >*/ - - MemoryRegion iomem; - uint32_t level; - uint32_t irq_enabled; - uint32_t fiq_enabled; - qemu_irq parent_irq; - qemu_irq parent_fiq; -} icp_pic_state; - -static void icp_pic_update(icp_pic_state *s) -{ - uint32_t flags; - - flags = (s->level & s->irq_enabled); - qemu_set_irq(s->parent_irq, flags != 0); - flags = (s->level & s->fiq_enabled); - qemu_set_irq(s->parent_fiq, flags != 0); -} - -static void icp_pic_set_irq(void *opaque, int irq, int level) -{ - icp_pic_state *s = (icp_pic_state *)opaque; - if (level) - s->level |= 1 << irq; - else - s->level &= ~(1 << irq); - icp_pic_update(s); -} - -static uint64_t icp_pic_read(void *opaque, hwaddr offset, - unsigned size) -{ - icp_pic_state *s = (icp_pic_state *)opaque; - - switch (offset >> 2) { - case 0: /* IRQ_STATUS */ - return s->level & s->irq_enabled; - case 1: /* IRQ_RAWSTAT */ - return s->level; - case 2: /* IRQ_ENABLESET */ - return s->irq_enabled; - case 4: /* INT_SOFTSET */ - return s->level & 1; - case 8: /* FRQ_STATUS */ - return s->level & s->fiq_enabled; - case 9: /* FRQ_RAWSTAT */ - return s->level; - case 10: /* FRQ_ENABLESET */ - return s->fiq_enabled; - case 3: /* IRQ_ENABLECLR */ - case 5: /* INT_SOFTCLR */ - case 11: /* FRQ_ENABLECLR */ - default: - printf ("icp_pic_read: Bad register offset 0x%x\n", (int)offset); - return 0; - } -} - -static void icp_pic_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - icp_pic_state *s = (icp_pic_state *)opaque; - - switch (offset >> 2) { - case 2: /* IRQ_ENABLESET */ - s->irq_enabled |= value; - break; - case 3: /* IRQ_ENABLECLR */ - s->irq_enabled &= ~value; - break; - case 4: /* INT_SOFTSET */ - if (value & 1) - icp_pic_set_irq(s, 0, 1); - break; - case 5: /* INT_SOFTCLR */ - if (value & 1) - icp_pic_set_irq(s, 0, 0); - break; - case 10: /* FRQ_ENABLESET */ - s->fiq_enabled |= value; - break; - case 11: /* FRQ_ENABLECLR */ - s->fiq_enabled &= ~value; - break; - case 0: /* IRQ_STATUS */ - case 1: /* IRQ_RAWSTAT */ - case 8: /* FRQ_STATUS */ - case 9: /* FRQ_RAWSTAT */ - default: - printf ("icp_pic_write: Bad register offset 0x%x\n", (int)offset); - return; - } - icp_pic_update(s); -} - -static const MemoryRegionOps icp_pic_ops = { - .read = icp_pic_read, - .write = icp_pic_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static int icp_pic_init(SysBusDevice *sbd) -{ - DeviceState *dev = DEVICE(sbd); - icp_pic_state *s = INTEGRATOR_PIC(dev); - - qdev_init_gpio_in(dev, icp_pic_set_irq, 32); - sysbus_init_irq(sbd, &s->parent_irq); - sysbus_init_irq(sbd, &s->parent_fiq); - memory_region_init_io(&s->iomem, OBJECT(s), &icp_pic_ops, s, - "icp-pic", 0x00800000); - sysbus_init_mmio(sbd, &s->iomem); - return 0; -} - -/* CP control registers. */ - -#define TYPE_ICP_CONTROL_REGS "icp-ctrl-regs" -#define ICP_CONTROL_REGS(obj) \ - OBJECT_CHECK(ICPCtrlRegsState, (obj), TYPE_ICP_CONTROL_REGS) - -typedef struct ICPCtrlRegsState { - /*< private >*/ - SysBusDevice parent_obj; - /*< public >*/ - - MemoryRegion iomem; - - qemu_irq mmc_irq; - uint32_t intreg_state; -} ICPCtrlRegsState; - -#define ICP_GPIO_MMC_WPROT "mmc-wprot" -#define ICP_GPIO_MMC_CARDIN "mmc-cardin" - -#define ICP_INTREG_WPROT (1 << 0) -#define ICP_INTREG_CARDIN (1 << 3) - -static uint64_t icp_control_read(void *opaque, hwaddr offset, - unsigned size) -{ - ICPCtrlRegsState *s = opaque; - - switch (offset >> 2) { - case 0: /* CP_IDFIELD */ - return 0x41034003; - case 1: /* CP_FLASHPROG */ - return 0; - case 2: /* CP_INTREG */ - return s->intreg_state; - case 3: /* CP_DECODE */ - return 0x11; - default: - hw_error("icp_control_read: Bad offset %x\n", (int)offset); - return 0; - } -} - -static void icp_control_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - ICPCtrlRegsState *s = opaque; - - switch (offset >> 2) { - case 2: /* CP_INTREG */ - s->intreg_state &= ~(value & ICP_INTREG_CARDIN); - qemu_set_irq(s->mmc_irq, !!(s->intreg_state & ICP_INTREG_CARDIN)); - break; - case 1: /* CP_FLASHPROG */ - case 3: /* CP_DECODE */ - /* Nothing interesting implemented yet. */ - break; - default: - hw_error("icp_control_write: Bad offset %x\n", (int)offset); - } -} - -static const MemoryRegionOps icp_control_ops = { - .read = icp_control_read, - .write = icp_control_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void icp_control_mmc_wprot(void *opaque, int line, int level) -{ - ICPCtrlRegsState *s = opaque; - - s->intreg_state &= ~ICP_INTREG_WPROT; - if (level) { - s->intreg_state |= ICP_INTREG_WPROT; - } -} - -static void icp_control_mmc_cardin(void *opaque, int line, int level) -{ - ICPCtrlRegsState *s = opaque; - - /* line is released by writing to CP_INTREG */ - if (level) { - s->intreg_state |= ICP_INTREG_CARDIN; - qemu_set_irq(s->mmc_irq, 1); - } -} - -static void icp_control_init(Object *obj) -{ - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - ICPCtrlRegsState *s = ICP_CONTROL_REGS(obj); - DeviceState *dev = DEVICE(obj); - - memory_region_init_io(&s->iomem, OBJECT(s), &icp_control_ops, s, - "icp_ctrl_regs", 0x00800000); - sysbus_init_mmio(sbd, &s->iomem); - - qdev_init_gpio_in_named(dev, icp_control_mmc_wprot, ICP_GPIO_MMC_WPROT, 1); - qdev_init_gpio_in_named(dev, icp_control_mmc_cardin, - ICP_GPIO_MMC_CARDIN, 1); - sysbus_init_irq(sbd, &s->mmc_irq); -} - - -/* Board init. */ - -static struct arm_boot_info integrator_binfo = { - .loader_start = 0x0, - .board_id = 0x113, -}; - -static void integratorcp_init(MachineState *machine) -{ - ram_addr_t ram_size = machine->ram_size; - const char *cpu_model = machine->cpu_model; - const char *kernel_filename = machine->kernel_filename; - const char *kernel_cmdline = machine->kernel_cmdline; - const char *initrd_filename = machine->initrd_filename; - ObjectClass *cpu_oc; - Object *cpuobj; - ARMCPU *cpu; - MemoryRegion *address_space_mem = get_system_memory(); - MemoryRegion *ram = g_new(MemoryRegion, 1); - MemoryRegion *ram_alias = g_new(MemoryRegion, 1); - qemu_irq pic[32]; - DeviceState *dev, *sic, *icp; - int i; - - if (!cpu_model) { - cpu_model = "arm926"; - } - - cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model); - if (!cpu_oc) { - fprintf(stderr, "Unable to find CPU definition\n"); - exit(1); - } - - cpuobj = object_new(object_class_get_name(cpu_oc)); - - /* By default ARM1176 CPUs have EL3 enabled. This board does not - * currently support EL3 so the CPU EL3 property is disabled before - * realization. - */ - if (object_property_find(cpuobj, "has_el3", NULL)) { - object_property_set_bool(cpuobj, false, "has_el3", &error_fatal); - } - - object_property_set_bool(cpuobj, true, "realized", &error_fatal); - - cpu = ARM_CPU(cpuobj); - - memory_region_allocate_system_memory(ram, NULL, "integrator.ram", - ram_size); - /* ??? On a real system the first 1Mb is mapped as SSRAM or boot flash. */ - /* ??? RAM should repeat to fill physical memory space. */ - /* SDRAM at address zero*/ - memory_region_add_subregion(address_space_mem, 0, ram); - /* And again at address 0x80000000 */ - memory_region_init_alias(ram_alias, NULL, "ram.alias", ram, 0, ram_size); - memory_region_add_subregion(address_space_mem, 0x80000000, ram_alias); - - dev = qdev_create(NULL, TYPE_INTEGRATOR_CM); - qdev_prop_set_uint32(dev, "memsz", ram_size >> 20); - qdev_init_nofail(dev); - sysbus_mmio_map((SysBusDevice *)dev, 0, 0x10000000); - - dev = sysbus_create_varargs(TYPE_INTEGRATOR_PIC, 0x14000000, - qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ), - qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_FIQ), - NULL); - for (i = 0; i < 32; i++) { - pic[i] = qdev_get_gpio_in(dev, i); - } - sic = sysbus_create_simple(TYPE_INTEGRATOR_PIC, 0xca000000, pic[26]); - sysbus_create_varargs("integrator_pit", 0x13000000, - pic[5], pic[6], pic[7], NULL); - sysbus_create_simple("pl031", 0x15000000, pic[8]); - sysbus_create_simple("pl011", 0x16000000, pic[1]); - sysbus_create_simple("pl011", 0x17000000, pic[2]); - icp = sysbus_create_simple(TYPE_ICP_CONTROL_REGS, 0xcb000000, - qdev_get_gpio_in(sic, 3)); - sysbus_create_simple("pl050_keyboard", 0x18000000, pic[3]); - sysbus_create_simple("pl050_mouse", 0x19000000, pic[4]); - sysbus_create_simple(TYPE_INTEGRATOR_DEBUG, 0x1a000000, 0); - - dev = sysbus_create_varargs("pl181", 0x1c000000, pic[23], pic[24], NULL); - qdev_connect_gpio_out(dev, 0, - qdev_get_gpio_in_named(icp, ICP_GPIO_MMC_WPROT, 0)); - qdev_connect_gpio_out(dev, 1, - qdev_get_gpio_in_named(icp, ICP_GPIO_MMC_CARDIN, 0)); - - if (nd_table[0].used) - smc91c111_init(&nd_table[0], 0xc8000000, pic[27]); - - sysbus_create_simple("pl110", 0xc0000000, pic[22]); - - integrator_binfo.ram_size = ram_size; - integrator_binfo.kernel_filename = kernel_filename; - integrator_binfo.kernel_cmdline = kernel_cmdline; - integrator_binfo.initrd_filename = initrd_filename; - arm_load_kernel(cpu, &integrator_binfo); -} - -static void integratorcp_machine_init(MachineClass *mc) -{ - mc->desc = "ARM Integrator/CP (ARM926EJ-S)"; - mc->init = integratorcp_init; -} - -DEFINE_MACHINE("integratorcp", integratorcp_machine_init) - -static Property core_properties[] = { - DEFINE_PROP_UINT32("memsz", IntegratorCMState, memsz, 0), - DEFINE_PROP_END_OF_LIST(), -}; - -static void core_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = integratorcm_init; - dc->props = core_properties; -} - -static const TypeInfo core_info = { - .name = TYPE_INTEGRATOR_CM, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(IntegratorCMState), - .class_init = core_class_init, -}; - -static void icp_pic_class_init(ObjectClass *klass, void *data) -{ - SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); - - sdc->init = icp_pic_init; -} - -static const TypeInfo icp_pic_info = { - .name = TYPE_INTEGRATOR_PIC, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(icp_pic_state), - .class_init = icp_pic_class_init, -}; - -static const TypeInfo icp_ctrl_regs_info = { - .name = TYPE_ICP_CONTROL_REGS, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(ICPCtrlRegsState), - .instance_init = icp_control_init, -}; - -static void integratorcp_register_types(void) -{ - type_register_static(&icp_pic_info); - type_register_static(&core_info); - type_register_static(&icp_ctrl_regs_info); -} - -type_init(integratorcp_register_types) diff --git a/qemu/hw/arm/kzm.c b/qemu/hw/arm/kzm.c deleted file mode 100644 index 2c96ee33b..000000000 --- a/qemu/hw/arm/kzm.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * KZM Board System emulation. - * - * Copyright (c) 2008 OKL and 2011 NICTA - * Written by Hans at OK-Labs - * Updated by Peter Chubb. - * - * This code is licensed under the GPL, version 2 or later. - * See the file `COPYING' in the top level directory. - * - * It (partially) emulates a Kyoto Microcomputer - * KZM-ARM11-01 evaluation board, with a Freescale - * i.MX31 SoC - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "qemu-common.h" -#include "cpu.h" -#include "hw/arm/fsl-imx31.h" -#include "hw/boards.h" -#include "qemu/error-report.h" -#include "exec/address-spaces.h" -#include "net/net.h" -#include "hw/devices.h" -#include "hw/char/serial.h" -#include "sysemu/qtest.h" - -/* Memory map for Kzm Emulation Baseboard: - * 0x00000000-0x7fffffff See i.MX31 SOC for support - * 0x80000000-0x8fffffff RAM EMULATED - * 0x90000000-0x9fffffff RAM EMULATED - * 0xa0000000-0xafffffff Flash IGNORED - * 0xb0000000-0xb3ffffff Unavailable IGNORED - * 0xb4000000-0xb4000fff 8-bit free space IGNORED - * 0xb4001000-0xb400100f Board control IGNORED - * 0xb4001003 DIP switch - * 0xb4001010-0xb400101f 7-segment LED IGNORED - * 0xb4001020-0xb400102f LED IGNORED - * 0xb4001030-0xb400103f LED IGNORED - * 0xb4001040-0xb400104f FPGA, UART EMULATED - * 0xb4001050-0xb400105f FPGA, UART EMULATED - * 0xb4001060-0xb40fffff FPGA IGNORED - * 0xb6000000-0xb61fffff LAN controller EMULATED - * 0xb6200000-0xb62fffff FPGA NAND Controller IGNORED - * 0xb6300000-0xb7ffffff Free IGNORED - * 0xb8000000-0xb8004fff Memory control registers IGNORED - * 0xc0000000-0xc3ffffff PCMCIA/CF IGNORED - * 0xc4000000-0xffffffff Reserved IGNORED - */ - -typedef struct IMX31KZM { - FslIMX31State soc; - MemoryRegion ram; - MemoryRegion ram_alias; -} IMX31KZM; - -#define KZM_RAM_ADDR (FSL_IMX31_SDRAM0_ADDR) -#define KZM_FPGA_ADDR (FSL_IMX31_CS4_ADDR + 0x1040) -#define KZM_LAN9118_ADDR (FSL_IMX31_CS5_ADDR) - -static struct arm_boot_info kzm_binfo = { - .loader_start = KZM_RAM_ADDR, - .board_id = 1722, -}; - -static void kzm_init(MachineState *machine) -{ - IMX31KZM *s = g_new0(IMX31KZM, 1); - unsigned int ram_size; - unsigned int alias_offset; - unsigned int i; - - object_initialize(&s->soc, sizeof(s->soc), TYPE_FSL_IMX31); - object_property_add_child(OBJECT(machine), "soc", OBJECT(&s->soc), - &error_abort); - - object_property_set_bool(OBJECT(&s->soc), true, "realized", &error_fatal); - - /* Check the amount of memory is compatible with the SOC */ - if (machine->ram_size > (FSL_IMX31_SDRAM0_SIZE + FSL_IMX31_SDRAM1_SIZE)) { - error_report("WARNING: RAM size " RAM_ADDR_FMT " above max supported, " - "reduced to %x", machine->ram_size, - FSL_IMX31_SDRAM0_SIZE + FSL_IMX31_SDRAM1_SIZE); - machine->ram_size = FSL_IMX31_SDRAM0_SIZE + FSL_IMX31_SDRAM1_SIZE; - } - - memory_region_allocate_system_memory(&s->ram, NULL, "kzm.ram", - machine->ram_size); - memory_region_add_subregion(get_system_memory(), FSL_IMX31_SDRAM0_ADDR, - &s->ram); - - /* initialize the alias memory if any */ - for (i = 0, ram_size = machine->ram_size, alias_offset = 0; - (i < 2) && ram_size; i++) { - unsigned int size; - static const struct { - hwaddr addr; - unsigned int size; - } ram[2] = { - { FSL_IMX31_SDRAM0_ADDR, FSL_IMX31_SDRAM0_SIZE }, - { FSL_IMX31_SDRAM1_ADDR, FSL_IMX31_SDRAM1_SIZE }, - }; - - size = MIN(ram_size, ram[i].size); - - ram_size -= size; - - if (size < ram[i].size) { - memory_region_init_alias(&s->ram_alias, NULL, "ram.alias", - &s->ram, alias_offset, ram[i].size - size); - memory_region_add_subregion(get_system_memory(), - ram[i].addr + size, &s->ram_alias); - } - - alias_offset += ram[i].size; - } - - if (nd_table[0].used) { - lan9118_init(&nd_table[0], KZM_LAN9118_ADDR, - qdev_get_gpio_in(DEVICE(&s->soc.avic), 52)); - } - - if (serial_hds[2]) { /* touchscreen */ - serial_mm_init(get_system_memory(), KZM_FPGA_ADDR+0x10, 0, - qdev_get_gpio_in(DEVICE(&s->soc.avic), 52), - 14745600, serial_hds[2], DEVICE_NATIVE_ENDIAN); - } - - kzm_binfo.ram_size = machine->ram_size; - kzm_binfo.kernel_filename = machine->kernel_filename; - kzm_binfo.kernel_cmdline = machine->kernel_cmdline; - kzm_binfo.initrd_filename = machine->initrd_filename; - kzm_binfo.nb_cpus = 1; - - if (!qtest_enabled()) { - arm_load_kernel(&s->soc.cpu, &kzm_binfo); - } -} - -static void kzm_machine_init(MachineClass *mc) -{ - mc->desc = "ARM KZM Emulation Baseboard (ARM1136)"; - mc->init = kzm_init; -} - -DEFINE_MACHINE("kzm", kzm_machine_init) diff --git a/qemu/hw/arm/mainstone.c b/qemu/hw/arm/mainstone.c deleted file mode 100644 index 454acc5d2..000000000 --- a/qemu/hw/arm/mainstone.c +++ /dev/null @@ -1,199 +0,0 @@ -/* - * PXA270-based Intel Mainstone platforms. - * - * Copyright (c) 2007 by Armin Kuster <akuster@kama-aina.net> or - * <akuster@mvista.com> - * - * Code based on spitz platform by Andrzej Zaborowski <balrog@zabor.org> - * - * 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 "qemu/osdep.h" -#include "qapi/error.h" -#include "hw/hw.h" -#include "hw/arm/pxa.h" -#include "hw/arm/arm.h" -#include "net/net.h" -#include "hw/devices.h" -#include "hw/boards.h" -#include "hw/block/flash.h" -#include "sysemu/block-backend.h" -#include "hw/sysbus.h" -#include "exec/address-spaces.h" -#include "sysemu/qtest.h" - -/* Device addresses */ -#define MST_FPGA_PHYS 0x08000000 -#define MST_ETH_PHYS 0x10000300 -#define MST_FLASH_0 0x00000000 -#define MST_FLASH_1 0x04000000 - -/* IRQ definitions */ -#define MMC_IRQ 0 -#define USIM_IRQ 1 -#define USBC_IRQ 2 -#define ETHERNET_IRQ 3 -#define AC97_IRQ 4 -#define PEN_IRQ 5 -#define MSINS_IRQ 6 -#define EXBRD_IRQ 7 -#define S0_CD_IRQ 9 -#define S0_STSCHG_IRQ 10 -#define S0_IRQ 11 -#define S1_CD_IRQ 13 -#define S1_STSCHG_IRQ 14 -#define S1_IRQ 15 - -static const struct keymap map[0xE0] = { - [0 ... 0xDF] = { -1, -1 }, - [0x1e] = {0,0}, /* a */ - [0x30] = {0,1}, /* b */ - [0x2e] = {0,2}, /* c */ - [0x20] = {0,3}, /* d */ - [0x12] = {0,4}, /* e */ - [0x21] = {0,5}, /* f */ - [0x22] = {1,0}, /* g */ - [0x23] = {1,1}, /* h */ - [0x17] = {1,2}, /* i */ - [0x24] = {1,3}, /* j */ - [0x25] = {1,4}, /* k */ - [0x26] = {1,5}, /* l */ - [0x32] = {2,0}, /* m */ - [0x31] = {2,1}, /* n */ - [0x18] = {2,2}, /* o */ - [0x19] = {2,3}, /* p */ - [0x10] = {2,4}, /* q */ - [0x13] = {2,5}, /* r */ - [0x1f] = {3,0}, /* s */ - [0x14] = {3,1}, /* t */ - [0x16] = {3,2}, /* u */ - [0x2f] = {3,3}, /* v */ - [0x11] = {3,4}, /* w */ - [0x2d] = {3,5}, /* x */ - [0x15] = {4,2}, /* y */ - [0x2c] = {4,3}, /* z */ - [0xc7] = {5,0}, /* Home */ - [0x2a] = {5,1}, /* shift */ - /* - * There are two matrix positions which map to space, - * but QEMU can only use one of them for the reverse - * mapping, so simply use the second one. - */ - /* [0x39] = {5,2}, space */ - [0x39] = {5,3}, /* space */ - /* - * Matrix position {5,4} and other keys are missing here. - * TODO: Compare with Linux code and test real hardware. - */ - [0x1c] = {5,5}, /* enter (TODO: might be wrong) */ - [0xc8] = {6,0}, /* up */ - [0xd0] = {6,1}, /* down */ - [0xcb] = {6,2}, /* left */ - [0xcd] = {6,3}, /* right */ -}; - -enum mainstone_model_e { mainstone }; - -#define MAINSTONE_RAM 0x04000000 -#define MAINSTONE_ROM 0x00800000 -#define MAINSTONE_FLASH 0x02000000 - -static struct arm_boot_info mainstone_binfo = { - .loader_start = PXA2XX_SDRAM_BASE, - .ram_size = 0x04000000, -}; - -static void mainstone_common_init(MemoryRegion *address_space_mem, - MachineState *machine, - enum mainstone_model_e model, int arm_id) -{ - uint32_t sector_len = 256 * 1024; - hwaddr mainstone_flash_base[] = { MST_FLASH_0, MST_FLASH_1 }; - PXA2xxState *mpu; - DeviceState *mst_irq; - DriveInfo *dinfo; - int i; - int be; - MemoryRegion *rom = g_new(MemoryRegion, 1); - const char *cpu_model = machine->cpu_model; - - if (!cpu_model) - cpu_model = "pxa270-c5"; - - /* Setup CPU & memory */ - mpu = pxa270_init(address_space_mem, mainstone_binfo.ram_size, cpu_model); - memory_region_init_ram(rom, NULL, "mainstone.rom", MAINSTONE_ROM, - &error_fatal); - vmstate_register_ram_global(rom); - memory_region_set_readonly(rom, true); - memory_region_add_subregion(address_space_mem, 0, rom); - -#ifdef TARGET_WORDS_BIGENDIAN - be = 1; -#else - be = 0; -#endif - /* There are two 32MiB flash devices on the board */ - for (i = 0; i < 2; i ++) { - dinfo = drive_get(IF_PFLASH, 0, i); - if (!dinfo) { - if (qtest_enabled()) { - break; - } - fprintf(stderr, "Two flash images must be given with the " - "'pflash' parameter\n"); - exit(1); - } - - if (!pflash_cfi01_register(mainstone_flash_base[i], NULL, - i ? "mainstone.flash1" : "mainstone.flash0", - MAINSTONE_FLASH, - blk_by_legacy_dinfo(dinfo), - sector_len, MAINSTONE_FLASH / sector_len, - 4, 0, 0, 0, 0, be)) { - fprintf(stderr, "qemu: Error registering flash memory.\n"); - exit(1); - } - } - - mst_irq = sysbus_create_simple("mainstone-fpga", MST_FPGA_PHYS, - qdev_get_gpio_in(mpu->gpio, 0)); - - /* setup keypad */ - pxa27x_register_keypad(mpu->kp, map, 0xe0); - - /* MMC/SD host */ - pxa2xx_mmci_handlers(mpu->mmc, NULL, qdev_get_gpio_in(mst_irq, MMC_IRQ)); - - pxa2xx_pcmcia_set_irq_cb(mpu->pcmcia[0], - qdev_get_gpio_in(mst_irq, S0_IRQ), - qdev_get_gpio_in(mst_irq, S0_CD_IRQ)); - pxa2xx_pcmcia_set_irq_cb(mpu->pcmcia[1], - qdev_get_gpio_in(mst_irq, S1_IRQ), - qdev_get_gpio_in(mst_irq, S1_CD_IRQ)); - - smc91c111_init(&nd_table[0], MST_ETH_PHYS, - qdev_get_gpio_in(mst_irq, ETHERNET_IRQ)); - - mainstone_binfo.kernel_filename = machine->kernel_filename; - mainstone_binfo.kernel_cmdline = machine->kernel_cmdline; - mainstone_binfo.initrd_filename = machine->initrd_filename; - mainstone_binfo.board_id = arm_id; - arm_load_kernel(mpu->cpu, &mainstone_binfo); -} - -static void mainstone_init(MachineState *machine) -{ - mainstone_common_init(get_system_memory(), machine, mainstone, 0x196); -} - -static void mainstone2_machine_init(MachineClass *mc) -{ - mc->desc = "Mainstone II (PXA27x)"; - mc->init = mainstone_init; -} - -DEFINE_MACHINE("mainstone", mainstone2_machine_init) diff --git a/qemu/hw/arm/musicpal.c b/qemu/hw/arm/musicpal.c deleted file mode 100644 index 7a4cc07dd..000000000 --- a/qemu/hw/arm/musicpal.c +++ /dev/null @@ -1,1751 +0,0 @@ -/* - * Marvell MV88W8618 / Freecom MusicPal emulation. - * - * Copyright (c) 2008 Jan Kiszka - * - * 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 "qemu/osdep.h" -#include "qapi/error.h" -#include "qemu-common.h" -#include "cpu.h" -#include "hw/sysbus.h" -#include "hw/arm/arm.h" -#include "hw/devices.h" -#include "net/net.h" -#include "sysemu/sysemu.h" -#include "hw/boards.h" -#include "hw/char/serial.h" -#include "qemu/timer.h" -#include "hw/ptimer.h" -#include "hw/block/flash.h" -#include "ui/console.h" -#include "hw/i2c/i2c.h" -#include "sysemu/block-backend.h" -#include "exec/address-spaces.h" -#include "ui/pixel_ops.h" - -#define MP_MISC_BASE 0x80002000 -#define MP_MISC_SIZE 0x00001000 - -#define MP_ETH_BASE 0x80008000 -#define MP_ETH_SIZE 0x00001000 - -#define MP_WLAN_BASE 0x8000C000 -#define MP_WLAN_SIZE 0x00000800 - -#define MP_UART1_BASE 0x8000C840 -#define MP_UART2_BASE 0x8000C940 - -#define MP_GPIO_BASE 0x8000D000 -#define MP_GPIO_SIZE 0x00001000 - -#define MP_FLASHCFG_BASE 0x90006000 -#define MP_FLASHCFG_SIZE 0x00001000 - -#define MP_AUDIO_BASE 0x90007000 - -#define MP_PIC_BASE 0x90008000 -#define MP_PIC_SIZE 0x00001000 - -#define MP_PIT_BASE 0x90009000 -#define MP_PIT_SIZE 0x00001000 - -#define MP_LCD_BASE 0x9000c000 -#define MP_LCD_SIZE 0x00001000 - -#define MP_SRAM_BASE 0xC0000000 -#define MP_SRAM_SIZE 0x00020000 - -#define MP_RAM_DEFAULT_SIZE 32*1024*1024 -#define MP_FLASH_SIZE_MAX 32*1024*1024 - -#define MP_TIMER1_IRQ 4 -#define MP_TIMER2_IRQ 5 -#define MP_TIMER3_IRQ 6 -#define MP_TIMER4_IRQ 7 -#define MP_EHCI_IRQ 8 -#define MP_ETH_IRQ 9 -#define MP_UART1_IRQ 11 -#define MP_UART2_IRQ 11 -#define MP_GPIO_IRQ 12 -#define MP_RTC_IRQ 28 -#define MP_AUDIO_IRQ 30 - -/* Wolfson 8750 I2C address */ -#define MP_WM_ADDR 0x1A - -/* Ethernet register offsets */ -#define MP_ETH_SMIR 0x010 -#define MP_ETH_PCXR 0x408 -#define MP_ETH_SDCMR 0x448 -#define MP_ETH_ICR 0x450 -#define MP_ETH_IMR 0x458 -#define MP_ETH_FRDP0 0x480 -#define MP_ETH_FRDP1 0x484 -#define MP_ETH_FRDP2 0x488 -#define MP_ETH_FRDP3 0x48C -#define MP_ETH_CRDP0 0x4A0 -#define MP_ETH_CRDP1 0x4A4 -#define MP_ETH_CRDP2 0x4A8 -#define MP_ETH_CRDP3 0x4AC -#define MP_ETH_CTDP0 0x4E0 -#define MP_ETH_CTDP1 0x4E4 - -/* MII PHY access */ -#define MP_ETH_SMIR_DATA 0x0000FFFF -#define MP_ETH_SMIR_ADDR 0x03FF0000 -#define MP_ETH_SMIR_OPCODE (1 << 26) /* Read value */ -#define MP_ETH_SMIR_RDVALID (1 << 27) - -/* PHY registers */ -#define MP_ETH_PHY1_BMSR 0x00210000 -#define MP_ETH_PHY1_PHYSID1 0x00410000 -#define MP_ETH_PHY1_PHYSID2 0x00610000 - -#define MP_PHY_BMSR_LINK 0x0004 -#define MP_PHY_BMSR_AUTONEG 0x0008 - -#define MP_PHY_88E3015 0x01410E20 - -/* TX descriptor status */ -#define MP_ETH_TX_OWN (1U << 31) - -/* RX descriptor status */ -#define MP_ETH_RX_OWN (1U << 31) - -/* Interrupt cause/mask bits */ -#define MP_ETH_IRQ_RX_BIT 0 -#define MP_ETH_IRQ_RX (1 << MP_ETH_IRQ_RX_BIT) -#define MP_ETH_IRQ_TXHI_BIT 2 -#define MP_ETH_IRQ_TXLO_BIT 3 - -/* Port config bits */ -#define MP_ETH_PCXR_2BSM_BIT 28 /* 2-byte incoming suffix */ - -/* SDMA command bits */ -#define MP_ETH_CMD_TXHI (1 << 23) -#define MP_ETH_CMD_TXLO (1 << 22) - -typedef struct mv88w8618_tx_desc { - uint32_t cmdstat; - uint16_t res; - uint16_t bytes; - uint32_t buffer; - uint32_t next; -} mv88w8618_tx_desc; - -typedef struct mv88w8618_rx_desc { - uint32_t cmdstat; - uint16_t bytes; - uint16_t buffer_size; - uint32_t buffer; - uint32_t next; -} mv88w8618_rx_desc; - -#define TYPE_MV88W8618_ETH "mv88w8618_eth" -#define MV88W8618_ETH(obj) \ - OBJECT_CHECK(mv88w8618_eth_state, (obj), TYPE_MV88W8618_ETH) - -typedef struct mv88w8618_eth_state { - /*< private >*/ - SysBusDevice parent_obj; - /*< public >*/ - - MemoryRegion iomem; - qemu_irq irq; - uint32_t smir; - uint32_t icr; - uint32_t imr; - int mmio_index; - uint32_t vlan_header; - uint32_t tx_queue[2]; - uint32_t rx_queue[4]; - uint32_t frx_queue[4]; - uint32_t cur_rx[4]; - NICState *nic; - NICConf conf; -} mv88w8618_eth_state; - -static void eth_rx_desc_put(uint32_t addr, mv88w8618_rx_desc *desc) -{ - cpu_to_le32s(&desc->cmdstat); - cpu_to_le16s(&desc->bytes); - cpu_to_le16s(&desc->buffer_size); - cpu_to_le32s(&desc->buffer); - cpu_to_le32s(&desc->next); - cpu_physical_memory_write(addr, desc, sizeof(*desc)); -} - -static void eth_rx_desc_get(uint32_t addr, mv88w8618_rx_desc *desc) -{ - cpu_physical_memory_read(addr, desc, sizeof(*desc)); - le32_to_cpus(&desc->cmdstat); - le16_to_cpus(&desc->bytes); - le16_to_cpus(&desc->buffer_size); - le32_to_cpus(&desc->buffer); - le32_to_cpus(&desc->next); -} - -static ssize_t eth_receive(NetClientState *nc, const uint8_t *buf, size_t size) -{ - mv88w8618_eth_state *s = qemu_get_nic_opaque(nc); - uint32_t desc_addr; - mv88w8618_rx_desc desc; - int i; - - for (i = 0; i < 4; i++) { - desc_addr = s->cur_rx[i]; - if (!desc_addr) { - continue; - } - do { - eth_rx_desc_get(desc_addr, &desc); - if ((desc.cmdstat & MP_ETH_RX_OWN) && desc.buffer_size >= size) { - cpu_physical_memory_write(desc.buffer + s->vlan_header, - buf, size); - desc.bytes = size + s->vlan_header; - desc.cmdstat &= ~MP_ETH_RX_OWN; - s->cur_rx[i] = desc.next; - - s->icr |= MP_ETH_IRQ_RX; - if (s->icr & s->imr) { - qemu_irq_raise(s->irq); - } - eth_rx_desc_put(desc_addr, &desc); - return size; - } - desc_addr = desc.next; - } while (desc_addr != s->rx_queue[i]); - } - return size; -} - -static void eth_tx_desc_put(uint32_t addr, mv88w8618_tx_desc *desc) -{ - cpu_to_le32s(&desc->cmdstat); - cpu_to_le16s(&desc->res); - cpu_to_le16s(&desc->bytes); - cpu_to_le32s(&desc->buffer); - cpu_to_le32s(&desc->next); - cpu_physical_memory_write(addr, desc, sizeof(*desc)); -} - -static void eth_tx_desc_get(uint32_t addr, mv88w8618_tx_desc *desc) -{ - cpu_physical_memory_read(addr, desc, sizeof(*desc)); - le32_to_cpus(&desc->cmdstat); - le16_to_cpus(&desc->res); - le16_to_cpus(&desc->bytes); - le32_to_cpus(&desc->buffer); - le32_to_cpus(&desc->next); -} - -static void eth_send(mv88w8618_eth_state *s, int queue_index) -{ - uint32_t desc_addr = s->tx_queue[queue_index]; - mv88w8618_tx_desc desc; - uint32_t next_desc; - uint8_t buf[2048]; - int len; - - do { - eth_tx_desc_get(desc_addr, &desc); - next_desc = desc.next; - if (desc.cmdstat & MP_ETH_TX_OWN) { - len = desc.bytes; - if (len < 2048) { - cpu_physical_memory_read(desc.buffer, buf, len); - qemu_send_packet(qemu_get_queue(s->nic), buf, len); - } - desc.cmdstat &= ~MP_ETH_TX_OWN; - s->icr |= 1 << (MP_ETH_IRQ_TXLO_BIT - queue_index); - eth_tx_desc_put(desc_addr, &desc); - } - desc_addr = next_desc; - } while (desc_addr != s->tx_queue[queue_index]); -} - -static uint64_t mv88w8618_eth_read(void *opaque, hwaddr offset, - unsigned size) -{ - mv88w8618_eth_state *s = opaque; - - switch (offset) { - case MP_ETH_SMIR: - if (s->smir & MP_ETH_SMIR_OPCODE) { - switch (s->smir & MP_ETH_SMIR_ADDR) { - case MP_ETH_PHY1_BMSR: - return MP_PHY_BMSR_LINK | MP_PHY_BMSR_AUTONEG | - MP_ETH_SMIR_RDVALID; - case MP_ETH_PHY1_PHYSID1: - return (MP_PHY_88E3015 >> 16) | MP_ETH_SMIR_RDVALID; - case MP_ETH_PHY1_PHYSID2: - return (MP_PHY_88E3015 & 0xFFFF) | MP_ETH_SMIR_RDVALID; - default: - return MP_ETH_SMIR_RDVALID; - } - } - return 0; - - case MP_ETH_ICR: - return s->icr; - - case MP_ETH_IMR: - return s->imr; - - case MP_ETH_FRDP0 ... MP_ETH_FRDP3: - return s->frx_queue[(offset - MP_ETH_FRDP0)/4]; - - case MP_ETH_CRDP0 ... MP_ETH_CRDP3: - return s->rx_queue[(offset - MP_ETH_CRDP0)/4]; - - case MP_ETH_CTDP0 ... MP_ETH_CTDP1: - return s->tx_queue[(offset - MP_ETH_CTDP0)/4]; - - default: - return 0; - } -} - -static void mv88w8618_eth_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - mv88w8618_eth_state *s = opaque; - - switch (offset) { - case MP_ETH_SMIR: - s->smir = value; - break; - - case MP_ETH_PCXR: - s->vlan_header = ((value >> MP_ETH_PCXR_2BSM_BIT) & 1) * 2; - break; - - case MP_ETH_SDCMR: - if (value & MP_ETH_CMD_TXHI) { - eth_send(s, 1); - } - if (value & MP_ETH_CMD_TXLO) { - eth_send(s, 0); - } - if (value & (MP_ETH_CMD_TXHI | MP_ETH_CMD_TXLO) && s->icr & s->imr) { - qemu_irq_raise(s->irq); - } - break; - - case MP_ETH_ICR: - s->icr &= value; - break; - - case MP_ETH_IMR: - s->imr = value; - if (s->icr & s->imr) { - qemu_irq_raise(s->irq); - } - break; - - case MP_ETH_FRDP0 ... MP_ETH_FRDP3: - s->frx_queue[(offset - MP_ETH_FRDP0)/4] = value; - break; - - case MP_ETH_CRDP0 ... MP_ETH_CRDP3: - s->rx_queue[(offset - MP_ETH_CRDP0)/4] = - s->cur_rx[(offset - MP_ETH_CRDP0)/4] = value; - break; - - case MP_ETH_CTDP0 ... MP_ETH_CTDP1: - s->tx_queue[(offset - MP_ETH_CTDP0)/4] = value; - break; - } -} - -static const MemoryRegionOps mv88w8618_eth_ops = { - .read = mv88w8618_eth_read, - .write = mv88w8618_eth_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void eth_cleanup(NetClientState *nc) -{ - mv88w8618_eth_state *s = qemu_get_nic_opaque(nc); - - s->nic = NULL; -} - -static NetClientInfo net_mv88w8618_info = { - .type = NET_CLIENT_OPTIONS_KIND_NIC, - .size = sizeof(NICState), - .receive = eth_receive, - .cleanup = eth_cleanup, -}; - -static int mv88w8618_eth_init(SysBusDevice *sbd) -{ - DeviceState *dev = DEVICE(sbd); - mv88w8618_eth_state *s = MV88W8618_ETH(dev); - - sysbus_init_irq(sbd, &s->irq); - s->nic = qemu_new_nic(&net_mv88w8618_info, &s->conf, - object_get_typename(OBJECT(dev)), dev->id, s); - memory_region_init_io(&s->iomem, OBJECT(s), &mv88w8618_eth_ops, s, - "mv88w8618-eth", MP_ETH_SIZE); - sysbus_init_mmio(sbd, &s->iomem); - return 0; -} - -static const VMStateDescription mv88w8618_eth_vmsd = { - .name = "mv88w8618_eth", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(smir, mv88w8618_eth_state), - VMSTATE_UINT32(icr, mv88w8618_eth_state), - VMSTATE_UINT32(imr, mv88w8618_eth_state), - VMSTATE_UINT32(vlan_header, mv88w8618_eth_state), - VMSTATE_UINT32_ARRAY(tx_queue, mv88w8618_eth_state, 2), - VMSTATE_UINT32_ARRAY(rx_queue, mv88w8618_eth_state, 4), - VMSTATE_UINT32_ARRAY(frx_queue, mv88w8618_eth_state, 4), - VMSTATE_UINT32_ARRAY(cur_rx, mv88w8618_eth_state, 4), - VMSTATE_END_OF_LIST() - } -}; - -static Property mv88w8618_eth_properties[] = { - DEFINE_NIC_PROPERTIES(mv88w8618_eth_state, conf), - DEFINE_PROP_END_OF_LIST(), -}; - -static void mv88w8618_eth_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = mv88w8618_eth_init; - dc->vmsd = &mv88w8618_eth_vmsd; - dc->props = mv88w8618_eth_properties; -} - -static const TypeInfo mv88w8618_eth_info = { - .name = TYPE_MV88W8618_ETH, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(mv88w8618_eth_state), - .class_init = mv88w8618_eth_class_init, -}; - -/* LCD register offsets */ -#define MP_LCD_IRQCTRL 0x180 -#define MP_LCD_IRQSTAT 0x184 -#define MP_LCD_SPICTRL 0x1ac -#define MP_LCD_INST 0x1bc -#define MP_LCD_DATA 0x1c0 - -/* Mode magics */ -#define MP_LCD_SPI_DATA 0x00100011 -#define MP_LCD_SPI_CMD 0x00104011 -#define MP_LCD_SPI_INVALID 0x00000000 - -/* Commmands */ -#define MP_LCD_INST_SETPAGE0 0xB0 -/* ... */ -#define MP_LCD_INST_SETPAGE7 0xB7 - -#define MP_LCD_TEXTCOLOR 0xe0e0ff /* RRGGBB */ - -#define TYPE_MUSICPAL_LCD "musicpal_lcd" -#define MUSICPAL_LCD(obj) \ - OBJECT_CHECK(musicpal_lcd_state, (obj), TYPE_MUSICPAL_LCD) - -typedef struct musicpal_lcd_state { - /*< private >*/ - SysBusDevice parent_obj; - /*< public >*/ - - MemoryRegion iomem; - uint32_t brightness; - uint32_t mode; - uint32_t irqctrl; - uint32_t page; - uint32_t page_off; - QemuConsole *con; - uint8_t video_ram[128*64/8]; -} musicpal_lcd_state; - -static uint8_t scale_lcd_color(musicpal_lcd_state *s, uint8_t col) -{ - switch (s->brightness) { - case 7: - return col; - case 0: - return 0; - default: - return (col * s->brightness) / 7; - } -} - -#define SET_LCD_PIXEL(depth, type) \ -static inline void glue(set_lcd_pixel, depth) \ - (musicpal_lcd_state *s, int x, int y, type col) \ -{ \ - int dx, dy; \ - DisplaySurface *surface = qemu_console_surface(s->con); \ - type *pixel = &((type *) surface_data(surface))[(y * 128 * 3 + x) * 3]; \ -\ - for (dy = 0; dy < 3; dy++, pixel += 127 * 3) \ - for (dx = 0; dx < 3; dx++, pixel++) \ - *pixel = col; \ -} -SET_LCD_PIXEL(8, uint8_t) -SET_LCD_PIXEL(16, uint16_t) -SET_LCD_PIXEL(32, uint32_t) - -static void lcd_refresh(void *opaque) -{ - musicpal_lcd_state *s = opaque; - DisplaySurface *surface = qemu_console_surface(s->con); - int x, y, col; - - switch (surface_bits_per_pixel(surface)) { - case 0: - return; -#define LCD_REFRESH(depth, func) \ - case depth: \ - col = func(scale_lcd_color(s, (MP_LCD_TEXTCOLOR >> 16) & 0xff), \ - scale_lcd_color(s, (MP_LCD_TEXTCOLOR >> 8) & 0xff), \ - scale_lcd_color(s, MP_LCD_TEXTCOLOR & 0xff)); \ - for (x = 0; x < 128; x++) { \ - for (y = 0; y < 64; y++) { \ - if (s->video_ram[x + (y/8)*128] & (1 << (y % 8))) { \ - glue(set_lcd_pixel, depth)(s, x, y, col); \ - } else { \ - glue(set_lcd_pixel, depth)(s, x, y, 0); \ - } \ - } \ - } \ - break; - LCD_REFRESH(8, rgb_to_pixel8) - LCD_REFRESH(16, rgb_to_pixel16) - LCD_REFRESH(32, (is_surface_bgr(surface) ? - rgb_to_pixel32bgr : rgb_to_pixel32)) - default: - hw_error("unsupported colour depth %i\n", - surface_bits_per_pixel(surface)); - } - - dpy_gfx_update(s->con, 0, 0, 128*3, 64*3); -} - -static void lcd_invalidate(void *opaque) -{ -} - -static void musicpal_lcd_gpio_brightness_in(void *opaque, int irq, int level) -{ - musicpal_lcd_state *s = opaque; - s->brightness &= ~(1 << irq); - s->brightness |= level << irq; -} - -static uint64_t musicpal_lcd_read(void *opaque, hwaddr offset, - unsigned size) -{ - musicpal_lcd_state *s = opaque; - - switch (offset) { - case MP_LCD_IRQCTRL: - return s->irqctrl; - - default: - return 0; - } -} - -static void musicpal_lcd_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - musicpal_lcd_state *s = opaque; - - switch (offset) { - case MP_LCD_IRQCTRL: - s->irqctrl = value; - break; - - case MP_LCD_SPICTRL: - if (value == MP_LCD_SPI_DATA || value == MP_LCD_SPI_CMD) { - s->mode = value; - } else { - s->mode = MP_LCD_SPI_INVALID; - } - break; - - case MP_LCD_INST: - if (value >= MP_LCD_INST_SETPAGE0 && value <= MP_LCD_INST_SETPAGE7) { - s->page = value - MP_LCD_INST_SETPAGE0; - s->page_off = 0; - } - break; - - case MP_LCD_DATA: - if (s->mode == MP_LCD_SPI_CMD) { - if (value >= MP_LCD_INST_SETPAGE0 && - value <= MP_LCD_INST_SETPAGE7) { - s->page = value - MP_LCD_INST_SETPAGE0; - s->page_off = 0; - } - } else if (s->mode == MP_LCD_SPI_DATA) { - s->video_ram[s->page*128 + s->page_off] = value; - s->page_off = (s->page_off + 1) & 127; - } - break; - } -} - -static const MemoryRegionOps musicpal_lcd_ops = { - .read = musicpal_lcd_read, - .write = musicpal_lcd_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static const GraphicHwOps musicpal_gfx_ops = { - .invalidate = lcd_invalidate, - .gfx_update = lcd_refresh, -}; - -static int musicpal_lcd_init(SysBusDevice *sbd) -{ - DeviceState *dev = DEVICE(sbd); - musicpal_lcd_state *s = MUSICPAL_LCD(dev); - - s->brightness = 7; - - memory_region_init_io(&s->iomem, OBJECT(s), &musicpal_lcd_ops, s, - "musicpal-lcd", MP_LCD_SIZE); - sysbus_init_mmio(sbd, &s->iomem); - - s->con = graphic_console_init(dev, 0, &musicpal_gfx_ops, s); - qemu_console_resize(s->con, 128*3, 64*3); - - qdev_init_gpio_in(dev, musicpal_lcd_gpio_brightness_in, 3); - - return 0; -} - -static const VMStateDescription musicpal_lcd_vmsd = { - .name = "musicpal_lcd", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(brightness, musicpal_lcd_state), - VMSTATE_UINT32(mode, musicpal_lcd_state), - VMSTATE_UINT32(irqctrl, musicpal_lcd_state), - VMSTATE_UINT32(page, musicpal_lcd_state), - VMSTATE_UINT32(page_off, musicpal_lcd_state), - VMSTATE_BUFFER(video_ram, musicpal_lcd_state), - VMSTATE_END_OF_LIST() - } -}; - -static void musicpal_lcd_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = musicpal_lcd_init; - dc->vmsd = &musicpal_lcd_vmsd; -} - -static const TypeInfo musicpal_lcd_info = { - .name = TYPE_MUSICPAL_LCD, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(musicpal_lcd_state), - .class_init = musicpal_lcd_class_init, -}; - -/* PIC register offsets */ -#define MP_PIC_STATUS 0x00 -#define MP_PIC_ENABLE_SET 0x08 -#define MP_PIC_ENABLE_CLR 0x0C - -#define TYPE_MV88W8618_PIC "mv88w8618_pic" -#define MV88W8618_PIC(obj) \ - OBJECT_CHECK(mv88w8618_pic_state, (obj), TYPE_MV88W8618_PIC) - -typedef struct mv88w8618_pic_state { - /*< private >*/ - SysBusDevice parent_obj; - /*< public >*/ - - MemoryRegion iomem; - uint32_t level; - uint32_t enabled; - qemu_irq parent_irq; -} mv88w8618_pic_state; - -static void mv88w8618_pic_update(mv88w8618_pic_state *s) -{ - qemu_set_irq(s->parent_irq, (s->level & s->enabled)); -} - -static void mv88w8618_pic_set_irq(void *opaque, int irq, int level) -{ - mv88w8618_pic_state *s = opaque; - - if (level) { - s->level |= 1 << irq; - } else { - s->level &= ~(1 << irq); - } - mv88w8618_pic_update(s); -} - -static uint64_t mv88w8618_pic_read(void *opaque, hwaddr offset, - unsigned size) -{ - mv88w8618_pic_state *s = opaque; - - switch (offset) { - case MP_PIC_STATUS: - return s->level & s->enabled; - - default: - return 0; - } -} - -static void mv88w8618_pic_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - mv88w8618_pic_state *s = opaque; - - switch (offset) { - case MP_PIC_ENABLE_SET: - s->enabled |= value; - break; - - case MP_PIC_ENABLE_CLR: - s->enabled &= ~value; - s->level &= ~value; - break; - } - mv88w8618_pic_update(s); -} - -static void mv88w8618_pic_reset(DeviceState *d) -{ - mv88w8618_pic_state *s = MV88W8618_PIC(d); - - s->level = 0; - s->enabled = 0; -} - -static const MemoryRegionOps mv88w8618_pic_ops = { - .read = mv88w8618_pic_read, - .write = mv88w8618_pic_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static int mv88w8618_pic_init(SysBusDevice *dev) -{ - mv88w8618_pic_state *s = MV88W8618_PIC(dev); - - qdev_init_gpio_in(DEVICE(dev), mv88w8618_pic_set_irq, 32); - sysbus_init_irq(dev, &s->parent_irq); - memory_region_init_io(&s->iomem, OBJECT(s), &mv88w8618_pic_ops, s, - "musicpal-pic", MP_PIC_SIZE); - sysbus_init_mmio(dev, &s->iomem); - return 0; -} - -static const VMStateDescription mv88w8618_pic_vmsd = { - .name = "mv88w8618_pic", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(level, mv88w8618_pic_state), - VMSTATE_UINT32(enabled, mv88w8618_pic_state), - VMSTATE_END_OF_LIST() - } -}; - -static void mv88w8618_pic_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = mv88w8618_pic_init; - dc->reset = mv88w8618_pic_reset; - dc->vmsd = &mv88w8618_pic_vmsd; -} - -static const TypeInfo mv88w8618_pic_info = { - .name = TYPE_MV88W8618_PIC, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(mv88w8618_pic_state), - .class_init = mv88w8618_pic_class_init, -}; - -/* PIT register offsets */ -#define MP_PIT_TIMER1_LENGTH 0x00 -/* ... */ -#define MP_PIT_TIMER4_LENGTH 0x0C -#define MP_PIT_CONTROL 0x10 -#define MP_PIT_TIMER1_VALUE 0x14 -/* ... */ -#define MP_PIT_TIMER4_VALUE 0x20 -#define MP_BOARD_RESET 0x34 - -/* Magic board reset value (probably some watchdog behind it) */ -#define MP_BOARD_RESET_MAGIC 0x10000 - -typedef struct mv88w8618_timer_state { - ptimer_state *ptimer; - uint32_t limit; - int freq; - qemu_irq irq; -} mv88w8618_timer_state; - -#define TYPE_MV88W8618_PIT "mv88w8618_pit" -#define MV88W8618_PIT(obj) \ - OBJECT_CHECK(mv88w8618_pit_state, (obj), TYPE_MV88W8618_PIT) - -typedef struct mv88w8618_pit_state { - /*< private >*/ - SysBusDevice parent_obj; - /*< public >*/ - - MemoryRegion iomem; - mv88w8618_timer_state timer[4]; -} mv88w8618_pit_state; - -static void mv88w8618_timer_tick(void *opaque) -{ - mv88w8618_timer_state *s = opaque; - - qemu_irq_raise(s->irq); -} - -static void mv88w8618_timer_init(SysBusDevice *dev, mv88w8618_timer_state *s, - uint32_t freq) -{ - QEMUBH *bh; - - sysbus_init_irq(dev, &s->irq); - s->freq = freq; - - bh = qemu_bh_new(mv88w8618_timer_tick, s); - s->ptimer = ptimer_init(bh); -} - -static uint64_t mv88w8618_pit_read(void *opaque, hwaddr offset, - unsigned size) -{ - mv88w8618_pit_state *s = opaque; - mv88w8618_timer_state *t; - - switch (offset) { - case MP_PIT_TIMER1_VALUE ... MP_PIT_TIMER4_VALUE: - t = &s->timer[(offset-MP_PIT_TIMER1_VALUE) >> 2]; - return ptimer_get_count(t->ptimer); - - default: - return 0; - } -} - -static void mv88w8618_pit_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - mv88w8618_pit_state *s = opaque; - mv88w8618_timer_state *t; - int i; - - switch (offset) { - case MP_PIT_TIMER1_LENGTH ... MP_PIT_TIMER4_LENGTH: - t = &s->timer[offset >> 2]; - t->limit = value; - if (t->limit > 0) { - ptimer_set_limit(t->ptimer, t->limit, 1); - } else { - ptimer_stop(t->ptimer); - } - break; - - case MP_PIT_CONTROL: - for (i = 0; i < 4; i++) { - t = &s->timer[i]; - if (value & 0xf && t->limit > 0) { - ptimer_set_limit(t->ptimer, t->limit, 0); - ptimer_set_freq(t->ptimer, t->freq); - ptimer_run(t->ptimer, 0); - } else { - ptimer_stop(t->ptimer); - } - value >>= 4; - } - break; - - case MP_BOARD_RESET: - if (value == MP_BOARD_RESET_MAGIC) { - qemu_system_reset_request(); - } - break; - } -} - -static void mv88w8618_pit_reset(DeviceState *d) -{ - mv88w8618_pit_state *s = MV88W8618_PIT(d); - int i; - - for (i = 0; i < 4; i++) { - ptimer_stop(s->timer[i].ptimer); - s->timer[i].limit = 0; - } -} - -static const MemoryRegionOps mv88w8618_pit_ops = { - .read = mv88w8618_pit_read, - .write = mv88w8618_pit_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static int mv88w8618_pit_init(SysBusDevice *dev) -{ - mv88w8618_pit_state *s = MV88W8618_PIT(dev); - int i; - - /* Letting them all run at 1 MHz is likely just a pragmatic - * simplification. */ - for (i = 0; i < 4; i++) { - mv88w8618_timer_init(dev, &s->timer[i], 1000000); - } - - memory_region_init_io(&s->iomem, OBJECT(s), &mv88w8618_pit_ops, s, - "musicpal-pit", MP_PIT_SIZE); - sysbus_init_mmio(dev, &s->iomem); - return 0; -} - -static const VMStateDescription mv88w8618_timer_vmsd = { - .name = "timer", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_PTIMER(ptimer, mv88w8618_timer_state), - VMSTATE_UINT32(limit, mv88w8618_timer_state), - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription mv88w8618_pit_vmsd = { - .name = "mv88w8618_pit", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_STRUCT_ARRAY(timer, mv88w8618_pit_state, 4, 1, - mv88w8618_timer_vmsd, mv88w8618_timer_state), - VMSTATE_END_OF_LIST() - } -}; - -static void mv88w8618_pit_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = mv88w8618_pit_init; - dc->reset = mv88w8618_pit_reset; - dc->vmsd = &mv88w8618_pit_vmsd; -} - -static const TypeInfo mv88w8618_pit_info = { - .name = TYPE_MV88W8618_PIT, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(mv88w8618_pit_state), - .class_init = mv88w8618_pit_class_init, -}; - -/* Flash config register offsets */ -#define MP_FLASHCFG_CFGR0 0x04 - -#define TYPE_MV88W8618_FLASHCFG "mv88w8618_flashcfg" -#define MV88W8618_FLASHCFG(obj) \ - OBJECT_CHECK(mv88w8618_flashcfg_state, (obj), TYPE_MV88W8618_FLASHCFG) - -typedef struct mv88w8618_flashcfg_state { - /*< private >*/ - SysBusDevice parent_obj; - /*< public >*/ - - MemoryRegion iomem; - uint32_t cfgr0; -} mv88w8618_flashcfg_state; - -static uint64_t mv88w8618_flashcfg_read(void *opaque, - hwaddr offset, - unsigned size) -{ - mv88w8618_flashcfg_state *s = opaque; - - switch (offset) { - case MP_FLASHCFG_CFGR0: - return s->cfgr0; - - default: - return 0; - } -} - -static void mv88w8618_flashcfg_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - mv88w8618_flashcfg_state *s = opaque; - - switch (offset) { - case MP_FLASHCFG_CFGR0: - s->cfgr0 = value; - break; - } -} - -static const MemoryRegionOps mv88w8618_flashcfg_ops = { - .read = mv88w8618_flashcfg_read, - .write = mv88w8618_flashcfg_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static int mv88w8618_flashcfg_init(SysBusDevice *dev) -{ - mv88w8618_flashcfg_state *s = MV88W8618_FLASHCFG(dev); - - s->cfgr0 = 0xfffe4285; /* Default as set by U-Boot for 8 MB flash */ - memory_region_init_io(&s->iomem, OBJECT(s), &mv88w8618_flashcfg_ops, s, - "musicpal-flashcfg", MP_FLASHCFG_SIZE); - sysbus_init_mmio(dev, &s->iomem); - return 0; -} - -static const VMStateDescription mv88w8618_flashcfg_vmsd = { - .name = "mv88w8618_flashcfg", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(cfgr0, mv88w8618_flashcfg_state), - VMSTATE_END_OF_LIST() - } -}; - -static void mv88w8618_flashcfg_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = mv88w8618_flashcfg_init; - dc->vmsd = &mv88w8618_flashcfg_vmsd; -} - -static const TypeInfo mv88w8618_flashcfg_info = { - .name = TYPE_MV88W8618_FLASHCFG, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(mv88w8618_flashcfg_state), - .class_init = mv88w8618_flashcfg_class_init, -}; - -/* Misc register offsets */ -#define MP_MISC_BOARD_REVISION 0x18 - -#define MP_BOARD_REVISION 0x31 - -typedef struct { - SysBusDevice parent_obj; - MemoryRegion iomem; -} MusicPalMiscState; - -#define TYPE_MUSICPAL_MISC "musicpal-misc" -#define MUSICPAL_MISC(obj) \ - OBJECT_CHECK(MusicPalMiscState, (obj), TYPE_MUSICPAL_MISC) - -static uint64_t musicpal_misc_read(void *opaque, hwaddr offset, - unsigned size) -{ - switch (offset) { - case MP_MISC_BOARD_REVISION: - return MP_BOARD_REVISION; - - default: - return 0; - } -} - -static void musicpal_misc_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ -} - -static const MemoryRegionOps musicpal_misc_ops = { - .read = musicpal_misc_read, - .write = musicpal_misc_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void musicpal_misc_init(Object *obj) -{ - SysBusDevice *sd = SYS_BUS_DEVICE(obj); - MusicPalMiscState *s = MUSICPAL_MISC(obj); - - memory_region_init_io(&s->iomem, OBJECT(s), &musicpal_misc_ops, NULL, - "musicpal-misc", MP_MISC_SIZE); - sysbus_init_mmio(sd, &s->iomem); -} - -static const TypeInfo musicpal_misc_info = { - .name = TYPE_MUSICPAL_MISC, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_init = musicpal_misc_init, - .instance_size = sizeof(MusicPalMiscState), -}; - -/* WLAN register offsets */ -#define MP_WLAN_MAGIC1 0x11c -#define MP_WLAN_MAGIC2 0x124 - -static uint64_t mv88w8618_wlan_read(void *opaque, hwaddr offset, - unsigned size) -{ - switch (offset) { - /* Workaround to allow loading the binary-only wlandrv.ko crap - * from the original Freecom firmware. */ - case MP_WLAN_MAGIC1: - return ~3; - case MP_WLAN_MAGIC2: - return -1; - - default: - return 0; - } -} - -static void mv88w8618_wlan_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ -} - -static const MemoryRegionOps mv88w8618_wlan_ops = { - .read = mv88w8618_wlan_read, - .write =mv88w8618_wlan_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static int mv88w8618_wlan_init(SysBusDevice *dev) -{ - MemoryRegion *iomem = g_new(MemoryRegion, 1); - - memory_region_init_io(iomem, OBJECT(dev), &mv88w8618_wlan_ops, NULL, - "musicpal-wlan", MP_WLAN_SIZE); - sysbus_init_mmio(dev, iomem); - return 0; -} - -/* GPIO register offsets */ -#define MP_GPIO_OE_LO 0x008 -#define MP_GPIO_OUT_LO 0x00c -#define MP_GPIO_IN_LO 0x010 -#define MP_GPIO_IER_LO 0x014 -#define MP_GPIO_IMR_LO 0x018 -#define MP_GPIO_ISR_LO 0x020 -#define MP_GPIO_OE_HI 0x508 -#define MP_GPIO_OUT_HI 0x50c -#define MP_GPIO_IN_HI 0x510 -#define MP_GPIO_IER_HI 0x514 -#define MP_GPIO_IMR_HI 0x518 -#define MP_GPIO_ISR_HI 0x520 - -/* GPIO bits & masks */ -#define MP_GPIO_LCD_BRIGHTNESS 0x00070000 -#define MP_GPIO_I2C_DATA_BIT 29 -#define MP_GPIO_I2C_CLOCK_BIT 30 - -/* LCD brightness bits in GPIO_OE_HI */ -#define MP_OE_LCD_BRIGHTNESS 0x0007 - -#define TYPE_MUSICPAL_GPIO "musicpal_gpio" -#define MUSICPAL_GPIO(obj) \ - OBJECT_CHECK(musicpal_gpio_state, (obj), TYPE_MUSICPAL_GPIO) - -typedef struct musicpal_gpio_state { - /*< private >*/ - SysBusDevice parent_obj; - /*< public >*/ - - MemoryRegion iomem; - uint32_t lcd_brightness; - uint32_t out_state; - uint32_t in_state; - uint32_t ier; - uint32_t imr; - uint32_t isr; - qemu_irq irq; - qemu_irq out[5]; /* 3 brightness out + 2 lcd (data and clock ) */ -} musicpal_gpio_state; - -static void musicpal_gpio_brightness_update(musicpal_gpio_state *s) { - int i; - uint32_t brightness; - - /* compute brightness ratio */ - switch (s->lcd_brightness) { - case 0x00000007: - brightness = 0; - break; - - case 0x00020000: - brightness = 1; - break; - - case 0x00020001: - brightness = 2; - break; - - case 0x00040000: - brightness = 3; - break; - - case 0x00010006: - brightness = 4; - break; - - case 0x00020005: - brightness = 5; - break; - - case 0x00040003: - brightness = 6; - break; - - case 0x00030004: - default: - brightness = 7; - } - - /* set lcd brightness GPIOs */ - for (i = 0; i <= 2; i++) { - qemu_set_irq(s->out[i], (brightness >> i) & 1); - } -} - -static void musicpal_gpio_pin_event(void *opaque, int pin, int level) -{ - musicpal_gpio_state *s = opaque; - uint32_t mask = 1 << pin; - uint32_t delta = level << pin; - uint32_t old = s->in_state & mask; - - s->in_state &= ~mask; - s->in_state |= delta; - - if ((old ^ delta) && - ((level && (s->imr & mask)) || (!level && (s->ier & mask)))) { - s->isr = mask; - qemu_irq_raise(s->irq); - } -} - -static uint64_t musicpal_gpio_read(void *opaque, hwaddr offset, - unsigned size) -{ - musicpal_gpio_state *s = opaque; - - switch (offset) { - case MP_GPIO_OE_HI: /* used for LCD brightness control */ - return s->lcd_brightness & MP_OE_LCD_BRIGHTNESS; - - case MP_GPIO_OUT_LO: - return s->out_state & 0xFFFF; - case MP_GPIO_OUT_HI: - return s->out_state >> 16; - - case MP_GPIO_IN_LO: - return s->in_state & 0xFFFF; - case MP_GPIO_IN_HI: - return s->in_state >> 16; - - case MP_GPIO_IER_LO: - return s->ier & 0xFFFF; - case MP_GPIO_IER_HI: - return s->ier >> 16; - - case MP_GPIO_IMR_LO: - return s->imr & 0xFFFF; - case MP_GPIO_IMR_HI: - return s->imr >> 16; - - case MP_GPIO_ISR_LO: - return s->isr & 0xFFFF; - case MP_GPIO_ISR_HI: - return s->isr >> 16; - - default: - return 0; - } -} - -static void musicpal_gpio_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - musicpal_gpio_state *s = opaque; - switch (offset) { - case MP_GPIO_OE_HI: /* used for LCD brightness control */ - s->lcd_brightness = (s->lcd_brightness & MP_GPIO_LCD_BRIGHTNESS) | - (value & MP_OE_LCD_BRIGHTNESS); - musicpal_gpio_brightness_update(s); - break; - - case MP_GPIO_OUT_LO: - s->out_state = (s->out_state & 0xFFFF0000) | (value & 0xFFFF); - break; - case MP_GPIO_OUT_HI: - s->out_state = (s->out_state & 0xFFFF) | (value << 16); - s->lcd_brightness = (s->lcd_brightness & 0xFFFF) | - (s->out_state & MP_GPIO_LCD_BRIGHTNESS); - musicpal_gpio_brightness_update(s); - qemu_set_irq(s->out[3], (s->out_state >> MP_GPIO_I2C_DATA_BIT) & 1); - qemu_set_irq(s->out[4], (s->out_state >> MP_GPIO_I2C_CLOCK_BIT) & 1); - break; - - case MP_GPIO_IER_LO: - s->ier = (s->ier & 0xFFFF0000) | (value & 0xFFFF); - break; - case MP_GPIO_IER_HI: - s->ier = (s->ier & 0xFFFF) | (value << 16); - break; - - case MP_GPIO_IMR_LO: - s->imr = (s->imr & 0xFFFF0000) | (value & 0xFFFF); - break; - case MP_GPIO_IMR_HI: - s->imr = (s->imr & 0xFFFF) | (value << 16); - break; - } -} - -static const MemoryRegionOps musicpal_gpio_ops = { - .read = musicpal_gpio_read, - .write = musicpal_gpio_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void musicpal_gpio_reset(DeviceState *d) -{ - musicpal_gpio_state *s = MUSICPAL_GPIO(d); - - s->lcd_brightness = 0; - s->out_state = 0; - s->in_state = 0xffffffff; - s->ier = 0; - s->imr = 0; - s->isr = 0; -} - -static int musicpal_gpio_init(SysBusDevice *sbd) -{ - DeviceState *dev = DEVICE(sbd); - musicpal_gpio_state *s = MUSICPAL_GPIO(dev); - - sysbus_init_irq(sbd, &s->irq); - - memory_region_init_io(&s->iomem, OBJECT(s), &musicpal_gpio_ops, s, - "musicpal-gpio", MP_GPIO_SIZE); - sysbus_init_mmio(sbd, &s->iomem); - - qdev_init_gpio_out(dev, s->out, ARRAY_SIZE(s->out)); - - qdev_init_gpio_in(dev, musicpal_gpio_pin_event, 32); - - return 0; -} - -static const VMStateDescription musicpal_gpio_vmsd = { - .name = "musicpal_gpio", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(lcd_brightness, musicpal_gpio_state), - VMSTATE_UINT32(out_state, musicpal_gpio_state), - VMSTATE_UINT32(in_state, musicpal_gpio_state), - VMSTATE_UINT32(ier, musicpal_gpio_state), - VMSTATE_UINT32(imr, musicpal_gpio_state), - VMSTATE_UINT32(isr, musicpal_gpio_state), - VMSTATE_END_OF_LIST() - } -}; - -static void musicpal_gpio_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = musicpal_gpio_init; - dc->reset = musicpal_gpio_reset; - dc->vmsd = &musicpal_gpio_vmsd; -} - -static const TypeInfo musicpal_gpio_info = { - .name = TYPE_MUSICPAL_GPIO, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(musicpal_gpio_state), - .class_init = musicpal_gpio_class_init, -}; - -/* Keyboard codes & masks */ -#define KEY_RELEASED 0x80 -#define KEY_CODE 0x7f - -#define KEYCODE_TAB 0x0f -#define KEYCODE_ENTER 0x1c -#define KEYCODE_F 0x21 -#define KEYCODE_M 0x32 - -#define KEYCODE_EXTENDED 0xe0 -#define KEYCODE_UP 0x48 -#define KEYCODE_DOWN 0x50 -#define KEYCODE_LEFT 0x4b -#define KEYCODE_RIGHT 0x4d - -#define MP_KEY_WHEEL_VOL (1 << 0) -#define MP_KEY_WHEEL_VOL_INV (1 << 1) -#define MP_KEY_WHEEL_NAV (1 << 2) -#define MP_KEY_WHEEL_NAV_INV (1 << 3) -#define MP_KEY_BTN_FAVORITS (1 << 4) -#define MP_KEY_BTN_MENU (1 << 5) -#define MP_KEY_BTN_VOLUME (1 << 6) -#define MP_KEY_BTN_NAVIGATION (1 << 7) - -#define TYPE_MUSICPAL_KEY "musicpal_key" -#define MUSICPAL_KEY(obj) \ - OBJECT_CHECK(musicpal_key_state, (obj), TYPE_MUSICPAL_KEY) - -typedef struct musicpal_key_state { - /*< private >*/ - SysBusDevice parent_obj; - /*< public >*/ - - MemoryRegion iomem; - uint32_t kbd_extended; - uint32_t pressed_keys; - qemu_irq out[8]; -} musicpal_key_state; - -static void musicpal_key_event(void *opaque, int keycode) -{ - musicpal_key_state *s = opaque; - uint32_t event = 0; - int i; - - if (keycode == KEYCODE_EXTENDED) { - s->kbd_extended = 1; - return; - } - - if (s->kbd_extended) { - switch (keycode & KEY_CODE) { - case KEYCODE_UP: - event = MP_KEY_WHEEL_NAV | MP_KEY_WHEEL_NAV_INV; - break; - - case KEYCODE_DOWN: - event = MP_KEY_WHEEL_NAV; - break; - - case KEYCODE_LEFT: - event = MP_KEY_WHEEL_VOL | MP_KEY_WHEEL_VOL_INV; - break; - - case KEYCODE_RIGHT: - event = MP_KEY_WHEEL_VOL; - break; - } - } else { - switch (keycode & KEY_CODE) { - case KEYCODE_F: - event = MP_KEY_BTN_FAVORITS; - break; - - case KEYCODE_TAB: - event = MP_KEY_BTN_VOLUME; - break; - - case KEYCODE_ENTER: - event = MP_KEY_BTN_NAVIGATION; - break; - - case KEYCODE_M: - event = MP_KEY_BTN_MENU; - break; - } - /* Do not repeat already pressed buttons */ - if (!(keycode & KEY_RELEASED) && (s->pressed_keys & event)) { - event = 0; - } - } - - if (event) { - /* Raise GPIO pin first if repeating a key */ - if (!(keycode & KEY_RELEASED) && (s->pressed_keys & event)) { - for (i = 0; i <= 7; i++) { - if (event & (1 << i)) { - qemu_set_irq(s->out[i], 1); - } - } - } - for (i = 0; i <= 7; i++) { - if (event & (1 << i)) { - qemu_set_irq(s->out[i], !!(keycode & KEY_RELEASED)); - } - } - if (keycode & KEY_RELEASED) { - s->pressed_keys &= ~event; - } else { - s->pressed_keys |= event; - } - } - - s->kbd_extended = 0; -} - -static int musicpal_key_init(SysBusDevice *sbd) -{ - DeviceState *dev = DEVICE(sbd); - musicpal_key_state *s = MUSICPAL_KEY(dev); - - memory_region_init(&s->iomem, OBJECT(s), "dummy", 0); - sysbus_init_mmio(sbd, &s->iomem); - - s->kbd_extended = 0; - s->pressed_keys = 0; - - qdev_init_gpio_out(dev, s->out, ARRAY_SIZE(s->out)); - - qemu_add_kbd_event_handler(musicpal_key_event, s); - - return 0; -} - -static const VMStateDescription musicpal_key_vmsd = { - .name = "musicpal_key", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(kbd_extended, musicpal_key_state), - VMSTATE_UINT32(pressed_keys, musicpal_key_state), - VMSTATE_END_OF_LIST() - } -}; - -static void musicpal_key_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = musicpal_key_init; - dc->vmsd = &musicpal_key_vmsd; -} - -static const TypeInfo musicpal_key_info = { - .name = TYPE_MUSICPAL_KEY, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(musicpal_key_state), - .class_init = musicpal_key_class_init, -}; - -static struct arm_boot_info musicpal_binfo = { - .loader_start = 0x0, - .board_id = 0x20e, -}; - -static void musicpal_init(MachineState *machine) -{ - const char *cpu_model = machine->cpu_model; - const char *kernel_filename = machine->kernel_filename; - const char *kernel_cmdline = machine->kernel_cmdline; - const char *initrd_filename = machine->initrd_filename; - ARMCPU *cpu; - qemu_irq pic[32]; - DeviceState *dev; - DeviceState *i2c_dev; - DeviceState *lcd_dev; - DeviceState *key_dev; - DeviceState *wm8750_dev; - SysBusDevice *s; - I2CBus *i2c; - int i; - unsigned long flash_size; - DriveInfo *dinfo; - MemoryRegion *address_space_mem = get_system_memory(); - MemoryRegion *ram = g_new(MemoryRegion, 1); - MemoryRegion *sram = g_new(MemoryRegion, 1); - - if (!cpu_model) { - cpu_model = "arm926"; - } - cpu = cpu_arm_init(cpu_model); - if (!cpu) { - fprintf(stderr, "Unable to find CPU definition\n"); - exit(1); - } - - /* For now we use a fixed - the original - RAM size */ - memory_region_allocate_system_memory(ram, NULL, "musicpal.ram", - MP_RAM_DEFAULT_SIZE); - memory_region_add_subregion(address_space_mem, 0, ram); - - memory_region_init_ram(sram, NULL, "musicpal.sram", MP_SRAM_SIZE, - &error_fatal); - vmstate_register_ram_global(sram); - memory_region_add_subregion(address_space_mem, MP_SRAM_BASE, sram); - - dev = sysbus_create_simple(TYPE_MV88W8618_PIC, MP_PIC_BASE, - qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ)); - for (i = 0; i < 32; i++) { - pic[i] = qdev_get_gpio_in(dev, i); - } - sysbus_create_varargs(TYPE_MV88W8618_PIT, MP_PIT_BASE, pic[MP_TIMER1_IRQ], - pic[MP_TIMER2_IRQ], pic[MP_TIMER3_IRQ], - pic[MP_TIMER4_IRQ], NULL); - - if (serial_hds[0]) { - serial_mm_init(address_space_mem, MP_UART1_BASE, 2, pic[MP_UART1_IRQ], - 1825000, serial_hds[0], DEVICE_NATIVE_ENDIAN); - } - if (serial_hds[1]) { - serial_mm_init(address_space_mem, MP_UART2_BASE, 2, pic[MP_UART2_IRQ], - 1825000, serial_hds[1], DEVICE_NATIVE_ENDIAN); - } - - /* Register flash */ - dinfo = drive_get(IF_PFLASH, 0, 0); - if (dinfo) { - BlockBackend *blk = blk_by_legacy_dinfo(dinfo); - - flash_size = blk_getlength(blk); - if (flash_size != 8*1024*1024 && flash_size != 16*1024*1024 && - flash_size != 32*1024*1024) { - fprintf(stderr, "Invalid flash image size\n"); - exit(1); - } - - /* - * The original U-Boot accesses the flash at 0xFE000000 instead of - * 0xFF800000 (if there is 8 MB flash). So remap flash access if the - * image is smaller than 32 MB. - */ -#ifdef TARGET_WORDS_BIGENDIAN - pflash_cfi02_register(0x100000000ULL-MP_FLASH_SIZE_MAX, NULL, - "musicpal.flash", flash_size, - blk, 0x10000, (flash_size + 0xffff) >> 16, - MP_FLASH_SIZE_MAX / flash_size, - 2, 0x00BF, 0x236D, 0x0000, 0x0000, - 0x5555, 0x2AAA, 1); -#else - pflash_cfi02_register(0x100000000ULL-MP_FLASH_SIZE_MAX, NULL, - "musicpal.flash", flash_size, - blk, 0x10000, (flash_size + 0xffff) >> 16, - MP_FLASH_SIZE_MAX / flash_size, - 2, 0x00BF, 0x236D, 0x0000, 0x0000, - 0x5555, 0x2AAA, 0); -#endif - - } - sysbus_create_simple(TYPE_MV88W8618_FLASHCFG, MP_FLASHCFG_BASE, NULL); - - qemu_check_nic_model(&nd_table[0], "mv88w8618"); - dev = qdev_create(NULL, TYPE_MV88W8618_ETH); - qdev_set_nic_properties(dev, &nd_table[0]); - qdev_init_nofail(dev); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, MP_ETH_BASE); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[MP_ETH_IRQ]); - - sysbus_create_simple("mv88w8618_wlan", MP_WLAN_BASE, NULL); - - sysbus_create_simple(TYPE_MUSICPAL_MISC, MP_MISC_BASE, NULL); - - dev = sysbus_create_simple(TYPE_MUSICPAL_GPIO, MP_GPIO_BASE, - pic[MP_GPIO_IRQ]); - i2c_dev = sysbus_create_simple("gpio_i2c", -1, NULL); - i2c = (I2CBus *)qdev_get_child_bus(i2c_dev, "i2c"); - - lcd_dev = sysbus_create_simple(TYPE_MUSICPAL_LCD, MP_LCD_BASE, NULL); - key_dev = sysbus_create_simple(TYPE_MUSICPAL_KEY, -1, NULL); - - /* I2C read data */ - qdev_connect_gpio_out(i2c_dev, 0, - qdev_get_gpio_in(dev, MP_GPIO_I2C_DATA_BIT)); - /* I2C data */ - qdev_connect_gpio_out(dev, 3, qdev_get_gpio_in(i2c_dev, 0)); - /* I2C clock */ - qdev_connect_gpio_out(dev, 4, qdev_get_gpio_in(i2c_dev, 1)); - - for (i = 0; i < 3; i++) { - qdev_connect_gpio_out(dev, i, qdev_get_gpio_in(lcd_dev, i)); - } - for (i = 0; i < 4; i++) { - qdev_connect_gpio_out(key_dev, i, qdev_get_gpio_in(dev, i + 8)); - } - for (i = 4; i < 8; i++) { - qdev_connect_gpio_out(key_dev, i, qdev_get_gpio_in(dev, i + 15)); - } - - wm8750_dev = i2c_create_slave(i2c, "wm8750", MP_WM_ADDR); - dev = qdev_create(NULL, "mv88w8618_audio"); - s = SYS_BUS_DEVICE(dev); - qdev_prop_set_ptr(dev, "wm8750", wm8750_dev); - qdev_init_nofail(dev); - sysbus_mmio_map(s, 0, MP_AUDIO_BASE); - sysbus_connect_irq(s, 0, pic[MP_AUDIO_IRQ]); - - musicpal_binfo.ram_size = MP_RAM_DEFAULT_SIZE; - musicpal_binfo.kernel_filename = kernel_filename; - musicpal_binfo.kernel_cmdline = kernel_cmdline; - musicpal_binfo.initrd_filename = initrd_filename; - arm_load_kernel(cpu, &musicpal_binfo); -} - -static void musicpal_machine_init(MachineClass *mc) -{ - mc->desc = "Marvell 88w8618 / MusicPal (ARM926EJ-S)"; - mc->init = musicpal_init; -} - -DEFINE_MACHINE("musicpal", musicpal_machine_init) - -static void mv88w8618_wlan_class_init(ObjectClass *klass, void *data) -{ - SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); - - sdc->init = mv88w8618_wlan_init; -} - -static const TypeInfo mv88w8618_wlan_info = { - .name = "mv88w8618_wlan", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(SysBusDevice), - .class_init = mv88w8618_wlan_class_init, -}; - -static void musicpal_register_types(void) -{ - type_register_static(&mv88w8618_pic_info); - type_register_static(&mv88w8618_pit_info); - type_register_static(&mv88w8618_flashcfg_info); - type_register_static(&mv88w8618_eth_info); - type_register_static(&mv88w8618_wlan_info); - type_register_static(&musicpal_lcd_info); - type_register_static(&musicpal_gpio_info); - type_register_static(&musicpal_key_info); - type_register_static(&musicpal_misc_info); -} - -type_init(musicpal_register_types) diff --git a/qemu/hw/arm/netduino2.c b/qemu/hw/arm/netduino2.c deleted file mode 100644 index 23d792837..000000000 --- a/qemu/hw/arm/netduino2.c +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Netduino 2 Machine Model - * - * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me> - * - * 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 "qemu/osdep.h" -#include "qapi/error.h" -#include "hw/boards.h" -#include "qemu/error-report.h" -#include "hw/arm/stm32f205_soc.h" - -static void netduino2_init(MachineState *machine) -{ - DeviceState *dev; - - dev = qdev_create(NULL, TYPE_STM32F205_SOC); - if (machine->kernel_filename) { - qdev_prop_set_string(dev, "kernel-filename", machine->kernel_filename); - } - qdev_prop_set_string(dev, "cpu-model", "cortex-m3"); - object_property_set_bool(OBJECT(dev), true, "realized", &error_fatal); -} - -static void netduino2_machine_init(MachineClass *mc) -{ - mc->desc = "Netduino 2 Machine"; - mc->init = netduino2_init; -} - -DEFINE_MACHINE("netduino2", netduino2_machine_init) diff --git a/qemu/hw/arm/nseries.c b/qemu/hw/arm/nseries.c deleted file mode 100644 index 538250555..000000000 --- a/qemu/hw/arm/nseries.c +++ /dev/null @@ -1,1454 +0,0 @@ -/* - * Nokia N-series internet tablets. - * - * Copyright (C) 2007 Nokia Corporation - * Written by Andrzej Zaborowski <andrew@openedhand.com> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "qemu/cutils.h" -#include "sysemu/sysemu.h" -#include "hw/arm/omap.h" -#include "hw/arm/arm.h" -#include "hw/irq.h" -#include "ui/console.h" -#include "hw/boards.h" -#include "hw/i2c/i2c.h" -#include "hw/devices.h" -#include "hw/block/flash.h" -#include "hw/hw.h" -#include "hw/bt.h" -#include "hw/loader.h" -#include "sysemu/block-backend.h" -#include "hw/sysbus.h" -#include "exec/address-spaces.h" - -/* Nokia N8x0 support */ -struct n800_s { - struct omap_mpu_state_s *mpu; - - struct rfbi_chip_s blizzard; - struct { - void *opaque; - uint32_t (*txrx)(void *opaque, uint32_t value, int len); - uWireSlave *chip; - } ts; - - int keymap[0x80]; - DeviceState *kbd; - - DeviceState *usb; - void *retu; - void *tahvo; - DeviceState *nand; -}; - -/* GPIO pins */ -#define N8X0_TUSB_ENABLE_GPIO 0 -#define N800_MMC2_WP_GPIO 8 -#define N800_UNKNOWN_GPIO0 9 /* out */ -#define N810_MMC2_VIOSD_GPIO 9 -#define N810_HEADSET_AMP_GPIO 10 -#define N800_CAM_TURN_GPIO 12 -#define N810_GPS_RESET_GPIO 12 -#define N800_BLIZZARD_POWERDOWN_GPIO 15 -#define N800_MMC1_WP_GPIO 23 -#define N810_MMC2_VSD_GPIO 23 -#define N8X0_ONENAND_GPIO 26 -#define N810_BLIZZARD_RESET_GPIO 30 -#define N800_UNKNOWN_GPIO2 53 /* out */ -#define N8X0_TUSB_INT_GPIO 58 -#define N8X0_BT_WKUP_GPIO 61 -#define N8X0_STI_GPIO 62 -#define N8X0_CBUS_SEL_GPIO 64 -#define N8X0_CBUS_DAT_GPIO 65 -#define N8X0_CBUS_CLK_GPIO 66 -#define N8X0_WLAN_IRQ_GPIO 87 -#define N8X0_BT_RESET_GPIO 92 -#define N8X0_TEA5761_CS_GPIO 93 -#define N800_UNKNOWN_GPIO 94 -#define N810_TSC_RESET_GPIO 94 -#define N800_CAM_ACT_GPIO 95 -#define N810_GPS_WAKEUP_GPIO 95 -#define N8X0_MMC_CS_GPIO 96 -#define N8X0_WLAN_PWR_GPIO 97 -#define N8X0_BT_HOST_WKUP_GPIO 98 -#define N810_SPEAKER_AMP_GPIO 101 -#define N810_KB_LOCK_GPIO 102 -#define N800_TSC_TS_GPIO 103 -#define N810_TSC_TS_GPIO 106 -#define N8X0_HEADPHONE_GPIO 107 -#define N8X0_RETU_GPIO 108 -#define N800_TSC_KP_IRQ_GPIO 109 -#define N810_KEYBOARD_GPIO 109 -#define N800_BAT_COVER_GPIO 110 -#define N810_SLIDE_GPIO 110 -#define N8X0_TAHVO_GPIO 111 -#define N800_UNKNOWN_GPIO4 112 /* out */ -#define N810_SLEEPX_LED_GPIO 112 -#define N800_TSC_RESET_GPIO 118 /* ? */ -#define N810_AIC33_RESET_GPIO 118 -#define N800_TSC_UNKNOWN_GPIO 119 /* out */ -#define N8X0_TMP105_GPIO 125 - -/* Config */ -#define BT_UART 0 -#define XLDR_LL_UART 1 - -/* Addresses on the I2C bus 0 */ -#define N810_TLV320AIC33_ADDR 0x18 /* Audio CODEC */ -#define N8X0_TCM825x_ADDR 0x29 /* Camera */ -#define N810_LP5521_ADDR 0x32 /* LEDs */ -#define N810_TSL2563_ADDR 0x3d /* Light sensor */ -#define N810_LM8323_ADDR 0x45 /* Keyboard */ -/* Addresses on the I2C bus 1 */ -#define N8X0_TMP105_ADDR 0x48 /* Temperature sensor */ -#define N8X0_MENELAUS_ADDR 0x72 /* Power management */ - -/* Chipselects on GPMC NOR interface */ -#define N8X0_ONENAND_CS 0 -#define N8X0_USB_ASYNC_CS 1 -#define N8X0_USB_SYNC_CS 4 - -#define N8X0_BD_ADDR 0x00, 0x1a, 0x89, 0x9e, 0x3e, 0x81 - -static void n800_mmc_cs_cb(void *opaque, int line, int level) -{ - /* TODO: this seems to actually be connected to the menelaus, to - * which also both MMC slots connect. */ - omap_mmc_enable((struct omap_mmc_s *) opaque, !level); -} - -static void n8x0_gpio_setup(struct n800_s *s) -{ - qdev_connect_gpio_out(s->mpu->gpio, N8X0_MMC_CS_GPIO, - qemu_allocate_irq(n800_mmc_cs_cb, s->mpu->mmc, 0)); - qemu_irq_lower(qdev_get_gpio_in(s->mpu->gpio, N800_BAT_COVER_GPIO)); -} - -#define MAEMO_CAL_HEADER(...) \ - 'C', 'o', 'n', 'F', 0x02, 0x00, 0x04, 0x00, \ - __VA_ARGS__, \ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - -static const uint8_t n8x0_cal_wlan_mac[] = { - MAEMO_CAL_HEADER('w', 'l', 'a', 'n', '-', 'm', 'a', 'c') - 0x1c, 0x00, 0x00, 0x00, 0x47, 0xd6, 0x69, 0xb3, - 0x30, 0x08, 0xa0, 0x83, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, - 0x89, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, - 0x5d, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, -}; - -static const uint8_t n8x0_cal_bt_id[] = { - MAEMO_CAL_HEADER('b', 't', '-', 'i', 'd', 0, 0, 0) - 0x0a, 0x00, 0x00, 0x00, 0xa3, 0x4b, 0xf6, 0x96, - 0xa8, 0xeb, 0xb2, 0x41, 0x00, 0x00, 0x00, 0x00, - N8X0_BD_ADDR, -}; - -static void n8x0_nand_setup(struct n800_s *s) -{ - char *otp_region; - DriveInfo *dinfo; - - s->nand = qdev_create(NULL, "onenand"); - qdev_prop_set_uint16(s->nand, "manufacturer_id", NAND_MFR_SAMSUNG); - /* Either 0x40 or 0x48 are OK for the device ID */ - qdev_prop_set_uint16(s->nand, "device_id", 0x48); - qdev_prop_set_uint16(s->nand, "version_id", 0); - qdev_prop_set_int32(s->nand, "shift", 1); - dinfo = drive_get(IF_MTD, 0, 0); - if (dinfo) { - qdev_prop_set_drive(s->nand, "drive", blk_by_legacy_dinfo(dinfo), - &error_fatal); - } - qdev_init_nofail(s->nand); - sysbus_connect_irq(SYS_BUS_DEVICE(s->nand), 0, - qdev_get_gpio_in(s->mpu->gpio, N8X0_ONENAND_GPIO)); - omap_gpmc_attach(s->mpu->gpmc, N8X0_ONENAND_CS, - sysbus_mmio_get_region(SYS_BUS_DEVICE(s->nand), 0)); - otp_region = onenand_raw_otp(s->nand); - - memcpy(otp_region + 0x000, n8x0_cal_wlan_mac, sizeof(n8x0_cal_wlan_mac)); - memcpy(otp_region + 0x800, n8x0_cal_bt_id, sizeof(n8x0_cal_bt_id)); - /* XXX: in theory should also update the OOB for both pages */ -} - -static qemu_irq n8x0_system_powerdown; - -static void n8x0_powerdown_req(Notifier *n, void *opaque) -{ - qemu_irq_raise(n8x0_system_powerdown); -} - -static Notifier n8x0_system_powerdown_notifier = { - .notify = n8x0_powerdown_req -}; - -static void n8x0_i2c_setup(struct n800_s *s) -{ - DeviceState *dev; - qemu_irq tmp_irq = qdev_get_gpio_in(s->mpu->gpio, N8X0_TMP105_GPIO); - I2CBus *i2c = omap_i2c_bus(s->mpu->i2c[0]); - - /* Attach a menelaus PM chip */ - dev = i2c_create_slave(i2c, "twl92230", N8X0_MENELAUS_ADDR); - qdev_connect_gpio_out(dev, 3, - qdev_get_gpio_in(s->mpu->ih[0], - OMAP_INT_24XX_SYS_NIRQ)); - - n8x0_system_powerdown = qdev_get_gpio_in(dev, 3); - qemu_register_powerdown_notifier(&n8x0_system_powerdown_notifier); - - /* Attach a TMP105 PM chip (A0 wired to ground) */ - dev = i2c_create_slave(i2c, "tmp105", N8X0_TMP105_ADDR); - qdev_connect_gpio_out(dev, 0, tmp_irq); -} - -/* Touchscreen and keypad controller */ -static MouseTransformInfo n800_pointercal = { - .x = 800, - .y = 480, - .a = { 14560, -68, -3455208, -39, -9621, 35152972, 65536 }, -}; - -static MouseTransformInfo n810_pointercal = { - .x = 800, - .y = 480, - .a = { 15041, 148, -4731056, 171, -10238, 35933380, 65536 }, -}; - -#define RETU_KEYCODE 61 /* F3 */ - -static void n800_key_event(void *opaque, int keycode) -{ - struct n800_s *s = (struct n800_s *) opaque; - int code = s->keymap[keycode & 0x7f]; - - if (code == -1) { - if ((keycode & 0x7f) == RETU_KEYCODE) { - retu_key_event(s->retu, !(keycode & 0x80)); - } - return; - } - - tsc210x_key_event(s->ts.chip, code, !(keycode & 0x80)); -} - -static const int n800_keys[16] = { - -1, - 72, /* Up */ - 63, /* Home (F5) */ - -1, - 75, /* Left */ - 28, /* Enter */ - 77, /* Right */ - -1, - 1, /* Cycle (ESC) */ - 80, /* Down */ - 62, /* Menu (F4) */ - -1, - 66, /* Zoom- (F8) */ - 64, /* FullScreen (F6) */ - 65, /* Zoom+ (F7) */ - -1, -}; - -static void n800_tsc_kbd_setup(struct n800_s *s) -{ - int i; - - /* XXX: are the three pins inverted inside the chip between the - * tsc and the cpu (N4111)? */ - qemu_irq penirq = NULL; /* NC */ - qemu_irq kbirq = qdev_get_gpio_in(s->mpu->gpio, N800_TSC_KP_IRQ_GPIO); - qemu_irq dav = qdev_get_gpio_in(s->mpu->gpio, N800_TSC_TS_GPIO); - - s->ts.chip = tsc2301_init(penirq, kbirq, dav); - s->ts.opaque = s->ts.chip->opaque; - s->ts.txrx = tsc210x_txrx; - - for (i = 0; i < 0x80; i++) { - s->keymap[i] = -1; - } - for (i = 0; i < 0x10; i++) { - if (n800_keys[i] >= 0) { - s->keymap[n800_keys[i]] = i; - } - } - - qemu_add_kbd_event_handler(n800_key_event, s); - - tsc210x_set_transform(s->ts.chip, &n800_pointercal); -} - -static void n810_tsc_setup(struct n800_s *s) -{ - qemu_irq pintdav = qdev_get_gpio_in(s->mpu->gpio, N810_TSC_TS_GPIO); - - s->ts.opaque = tsc2005_init(pintdav); - s->ts.txrx = tsc2005_txrx; - - tsc2005_set_transform(s->ts.opaque, &n810_pointercal); -} - -/* N810 Keyboard controller */ -static void n810_key_event(void *opaque, int keycode) -{ - struct n800_s *s = (struct n800_s *) opaque; - int code = s->keymap[keycode & 0x7f]; - - if (code == -1) { - if ((keycode & 0x7f) == RETU_KEYCODE) { - retu_key_event(s->retu, !(keycode & 0x80)); - } - return; - } - - lm832x_key_event(s->kbd, code, !(keycode & 0x80)); -} - -#define M 0 - -static int n810_keys[0x80] = { - [0x01] = 16, /* Q */ - [0x02] = 37, /* K */ - [0x03] = 24, /* O */ - [0x04] = 25, /* P */ - [0x05] = 14, /* Backspace */ - [0x06] = 30, /* A */ - [0x07] = 31, /* S */ - [0x08] = 32, /* D */ - [0x09] = 33, /* F */ - [0x0a] = 34, /* G */ - [0x0b] = 35, /* H */ - [0x0c] = 36, /* J */ - - [0x11] = 17, /* W */ - [0x12] = 62, /* Menu (F4) */ - [0x13] = 38, /* L */ - [0x14] = 40, /* ' (Apostrophe) */ - [0x16] = 44, /* Z */ - [0x17] = 45, /* X */ - [0x18] = 46, /* C */ - [0x19] = 47, /* V */ - [0x1a] = 48, /* B */ - [0x1b] = 49, /* N */ - [0x1c] = 42, /* Shift (Left shift) */ - [0x1f] = 65, /* Zoom+ (F7) */ - - [0x21] = 18, /* E */ - [0x22] = 39, /* ; (Semicolon) */ - [0x23] = 12, /* - (Minus) */ - [0x24] = 13, /* = (Equal) */ - [0x2b] = 56, /* Fn (Left Alt) */ - [0x2c] = 50, /* M */ - [0x2f] = 66, /* Zoom- (F8) */ - - [0x31] = 19, /* R */ - [0x32] = 29 | M, /* Right Ctrl */ - [0x34] = 57, /* Space */ - [0x35] = 51, /* , (Comma) */ - [0x37] = 72 | M, /* Up */ - [0x3c] = 82 | M, /* Compose (Insert) */ - [0x3f] = 64, /* FullScreen (F6) */ - - [0x41] = 20, /* T */ - [0x44] = 52, /* . (Dot) */ - [0x46] = 77 | M, /* Right */ - [0x4f] = 63, /* Home (F5) */ - [0x51] = 21, /* Y */ - [0x53] = 80 | M, /* Down */ - [0x55] = 28, /* Enter */ - [0x5f] = 1, /* Cycle (ESC) */ - - [0x61] = 22, /* U */ - [0x64] = 75 | M, /* Left */ - - [0x71] = 23, /* I */ -#if 0 - [0x75] = 28 | M, /* KP Enter (KP Enter) */ -#else - [0x75] = 15, /* KP Enter (Tab) */ -#endif -}; - -#undef M - -static void n810_kbd_setup(struct n800_s *s) -{ - qemu_irq kbd_irq = qdev_get_gpio_in(s->mpu->gpio, N810_KEYBOARD_GPIO); - int i; - - for (i = 0; i < 0x80; i++) { - s->keymap[i] = -1; - } - for (i = 0; i < 0x80; i++) { - if (n810_keys[i] > 0) { - s->keymap[n810_keys[i]] = i; - } - } - - qemu_add_kbd_event_handler(n810_key_event, s); - - /* Attach the LM8322 keyboard to the I2C bus, - * should happen in n8x0_i2c_setup and s->kbd be initialised here. */ - s->kbd = i2c_create_slave(omap_i2c_bus(s->mpu->i2c[0]), - "lm8323", N810_LM8323_ADDR); - qdev_connect_gpio_out(s->kbd, 0, kbd_irq); -} - -/* LCD MIPI DBI-C controller (URAL) */ -struct mipid_s { - int resp[4]; - int param[4]; - int p; - int pm; - int cmd; - - int sleep; - int booster; - int te; - int selfcheck; - int partial; - int normal; - int vscr; - int invert; - int onoff; - int gamma; - uint32_t id; -}; - -static void mipid_reset(struct mipid_s *s) -{ - s->pm = 0; - s->cmd = 0; - - s->sleep = 1; - s->booster = 0; - s->selfcheck = - (1 << 7) | /* Register loading OK. */ - (1 << 5) | /* The chip is attached. */ - (1 << 4); /* Display glass still in one piece. */ - s->te = 0; - s->partial = 0; - s->normal = 1; - s->vscr = 0; - s->invert = 0; - s->onoff = 1; - s->gamma = 0; -} - -static uint32_t mipid_txrx(void *opaque, uint32_t cmd, int len) -{ - struct mipid_s *s = (struct mipid_s *) opaque; - uint8_t ret; - - if (len > 9) { - hw_error("%s: FIXME: bad SPI word width %i\n", __FUNCTION__, len); - } - - if (s->p >= ARRAY_SIZE(s->resp)) { - ret = 0; - } else { - ret = s->resp[s->p++]; - } - if (s->pm-- > 0) { - s->param[s->pm] = cmd; - } else { - s->cmd = cmd; - } - - switch (s->cmd) { - case 0x00: /* NOP */ - break; - - case 0x01: /* SWRESET */ - mipid_reset(s); - break; - - case 0x02: /* BSTROFF */ - s->booster = 0; - break; - case 0x03: /* BSTRON */ - s->booster = 1; - break; - - case 0x04: /* RDDID */ - s->p = 0; - s->resp[0] = (s->id >> 16) & 0xff; - s->resp[1] = (s->id >> 8) & 0xff; - s->resp[2] = (s->id >> 0) & 0xff; - break; - - case 0x06: /* RD_RED */ - case 0x07: /* RD_GREEN */ - /* XXX the bootloader sometimes issues RD_BLUE meaning RDDID so - * for the bootloader one needs to change this. */ - case 0x08: /* RD_BLUE */ - s->p = 0; - /* TODO: return first pixel components */ - s->resp[0] = 0x01; - break; - - case 0x09: /* RDDST */ - s->p = 0; - s->resp[0] = s->booster << 7; - s->resp[1] = (5 << 4) | (s->partial << 2) | - (s->sleep << 1) | s->normal; - s->resp[2] = (s->vscr << 7) | (s->invert << 5) | - (s->onoff << 2) | (s->te << 1) | (s->gamma >> 2); - s->resp[3] = s->gamma << 6; - break; - - case 0x0a: /* RDDPM */ - s->p = 0; - s->resp[0] = (s->onoff << 2) | (s->normal << 3) | (s->sleep << 4) | - (s->partial << 5) | (s->sleep << 6) | (s->booster << 7); - break; - case 0x0b: /* RDDMADCTR */ - s->p = 0; - s->resp[0] = 0; - break; - case 0x0c: /* RDDCOLMOD */ - s->p = 0; - s->resp[0] = 5; /* 65K colours */ - break; - case 0x0d: /* RDDIM */ - s->p = 0; - s->resp[0] = (s->invert << 5) | (s->vscr << 7) | s->gamma; - break; - case 0x0e: /* RDDSM */ - s->p = 0; - s->resp[0] = s->te << 7; - break; - case 0x0f: /* RDDSDR */ - s->p = 0; - s->resp[0] = s->selfcheck; - break; - - case 0x10: /* SLPIN */ - s->sleep = 1; - break; - case 0x11: /* SLPOUT */ - s->sleep = 0; - s->selfcheck ^= 1 << 6; /* POFF self-diagnosis Ok */ - break; - - case 0x12: /* PTLON */ - s->partial = 1; - s->normal = 0; - s->vscr = 0; - break; - case 0x13: /* NORON */ - s->partial = 0; - s->normal = 1; - s->vscr = 0; - break; - - case 0x20: /* INVOFF */ - s->invert = 0; - break; - case 0x21: /* INVON */ - s->invert = 1; - break; - - case 0x22: /* APOFF */ - case 0x23: /* APON */ - goto bad_cmd; - - case 0x25: /* WRCNTR */ - if (s->pm < 0) { - s->pm = 1; - } - goto bad_cmd; - - case 0x26: /* GAMSET */ - if (!s->pm) { - s->gamma = ctz32(s->param[0] & 0xf); - if (s->gamma == 32) { - s->gamma = -1; /* XXX: should this be 0? */ - } - } else if (s->pm < 0) { - s->pm = 1; - } - break; - - case 0x28: /* DISPOFF */ - s->onoff = 0; - break; - case 0x29: /* DISPON */ - s->onoff = 1; - break; - - case 0x2a: /* CASET */ - case 0x2b: /* RASET */ - case 0x2c: /* RAMWR */ - case 0x2d: /* RGBSET */ - case 0x2e: /* RAMRD */ - case 0x30: /* PTLAR */ - case 0x33: /* SCRLAR */ - goto bad_cmd; - - case 0x34: /* TEOFF */ - s->te = 0; - break; - case 0x35: /* TEON */ - if (!s->pm) { - s->te = 1; - } else if (s->pm < 0) { - s->pm = 1; - } - break; - - case 0x36: /* MADCTR */ - goto bad_cmd; - - case 0x37: /* VSCSAD */ - s->partial = 0; - s->normal = 0; - s->vscr = 1; - break; - - case 0x38: /* IDMOFF */ - case 0x39: /* IDMON */ - case 0x3a: /* COLMOD */ - goto bad_cmd; - - case 0xb0: /* CLKINT / DISCTL */ - case 0xb1: /* CLKEXT */ - if (s->pm < 0) { - s->pm = 2; - } - break; - - case 0xb4: /* FRMSEL */ - break; - - case 0xb5: /* FRM8SEL */ - case 0xb6: /* TMPRNG / INIESC */ - case 0xb7: /* TMPHIS / NOP2 */ - case 0xb8: /* TMPREAD / MADCTL */ - case 0xba: /* DISTCTR */ - case 0xbb: /* EPVOL */ - goto bad_cmd; - - case 0xbd: /* Unknown */ - s->p = 0; - s->resp[0] = 0; - s->resp[1] = 1; - break; - - case 0xc2: /* IFMOD */ - if (s->pm < 0) { - s->pm = 2; - } - break; - - case 0xc6: /* PWRCTL */ - case 0xc7: /* PPWRCTL */ - case 0xd0: /* EPWROUT */ - case 0xd1: /* EPWRIN */ - case 0xd4: /* RDEV */ - case 0xd5: /* RDRR */ - goto bad_cmd; - - case 0xda: /* RDID1 */ - s->p = 0; - s->resp[0] = (s->id >> 16) & 0xff; - break; - case 0xdb: /* RDID2 */ - s->p = 0; - s->resp[0] = (s->id >> 8) & 0xff; - break; - case 0xdc: /* RDID3 */ - s->p = 0; - s->resp[0] = (s->id >> 0) & 0xff; - break; - - default: - bad_cmd: - qemu_log_mask(LOG_GUEST_ERROR, - "%s: unknown command %02x\n", __func__, s->cmd); - break; - } - - return ret; -} - -static void *mipid_init(void) -{ - struct mipid_s *s = (struct mipid_s *) g_malloc0(sizeof(*s)); - - s->id = 0x838f03; - mipid_reset(s); - - return s; -} - -static void n8x0_spi_setup(struct n800_s *s) -{ - void *tsc = s->ts.opaque; - void *mipid = mipid_init(); - - omap_mcspi_attach(s->mpu->mcspi[0], s->ts.txrx, tsc, 0); - omap_mcspi_attach(s->mpu->mcspi[0], mipid_txrx, mipid, 1); -} - -/* This task is normally performed by the bootloader. If we're loading - * a kernel directly, we need to enable the Blizzard ourselves. */ -static void n800_dss_init(struct rfbi_chip_s *chip) -{ - uint8_t *fb_blank; - - chip->write(chip->opaque, 0, 0x2a); /* LCD Width register */ - chip->write(chip->opaque, 1, 0x64); - chip->write(chip->opaque, 0, 0x2c); /* LCD HNDP register */ - chip->write(chip->opaque, 1, 0x1e); - chip->write(chip->opaque, 0, 0x2e); /* LCD Height 0 register */ - chip->write(chip->opaque, 1, 0xe0); - chip->write(chip->opaque, 0, 0x30); /* LCD Height 1 register */ - chip->write(chip->opaque, 1, 0x01); - chip->write(chip->opaque, 0, 0x32); /* LCD VNDP register */ - chip->write(chip->opaque, 1, 0x06); - chip->write(chip->opaque, 0, 0x68); /* Display Mode register */ - chip->write(chip->opaque, 1, 1); /* Enable bit */ - - chip->write(chip->opaque, 0, 0x6c); - chip->write(chip->opaque, 1, 0x00); /* Input X Start Position */ - chip->write(chip->opaque, 1, 0x00); /* Input X Start Position */ - chip->write(chip->opaque, 1, 0x00); /* Input Y Start Position */ - chip->write(chip->opaque, 1, 0x00); /* Input Y Start Position */ - chip->write(chip->opaque, 1, 0x1f); /* Input X End Position */ - chip->write(chip->opaque, 1, 0x03); /* Input X End Position */ - chip->write(chip->opaque, 1, 0xdf); /* Input Y End Position */ - chip->write(chip->opaque, 1, 0x01); /* Input Y End Position */ - chip->write(chip->opaque, 1, 0x00); /* Output X Start Position */ - chip->write(chip->opaque, 1, 0x00); /* Output X Start Position */ - chip->write(chip->opaque, 1, 0x00); /* Output Y Start Position */ - chip->write(chip->opaque, 1, 0x00); /* Output Y Start Position */ - chip->write(chip->opaque, 1, 0x1f); /* Output X End Position */ - chip->write(chip->opaque, 1, 0x03); /* Output X End Position */ - chip->write(chip->opaque, 1, 0xdf); /* Output Y End Position */ - chip->write(chip->opaque, 1, 0x01); /* Output Y End Position */ - chip->write(chip->opaque, 1, 0x01); /* Input Data Format */ - chip->write(chip->opaque, 1, 0x01); /* Data Source Select */ - - fb_blank = memset(g_malloc(800 * 480 * 2), 0xff, 800 * 480 * 2); - /* Display Memory Data Port */ - chip->block(chip->opaque, 1, fb_blank, 800 * 480 * 2, 800); - g_free(fb_blank); -} - -static void n8x0_dss_setup(struct n800_s *s) -{ - s->blizzard.opaque = s1d13745_init(NULL); - s->blizzard.block = s1d13745_write_block; - s->blizzard.write = s1d13745_write; - s->blizzard.read = s1d13745_read; - - omap_rfbi_attach(s->mpu->dss, 0, &s->blizzard); -} - -static void n8x0_cbus_setup(struct n800_s *s) -{ - qemu_irq dat_out = qdev_get_gpio_in(s->mpu->gpio, N8X0_CBUS_DAT_GPIO); - qemu_irq retu_irq = qdev_get_gpio_in(s->mpu->gpio, N8X0_RETU_GPIO); - qemu_irq tahvo_irq = qdev_get_gpio_in(s->mpu->gpio, N8X0_TAHVO_GPIO); - - CBus *cbus = cbus_init(dat_out); - - qdev_connect_gpio_out(s->mpu->gpio, N8X0_CBUS_CLK_GPIO, cbus->clk); - qdev_connect_gpio_out(s->mpu->gpio, N8X0_CBUS_DAT_GPIO, cbus->dat); - qdev_connect_gpio_out(s->mpu->gpio, N8X0_CBUS_SEL_GPIO, cbus->sel); - - cbus_attach(cbus, s->retu = retu_init(retu_irq, 1)); - cbus_attach(cbus, s->tahvo = tahvo_init(tahvo_irq, 1)); -} - -static void n8x0_uart_setup(struct n800_s *s) -{ - CharDriverState *radio = uart_hci_init( - qdev_get_gpio_in(s->mpu->gpio, N8X0_BT_HOST_WKUP_GPIO)); - - qdev_connect_gpio_out(s->mpu->gpio, N8X0_BT_RESET_GPIO, - csrhci_pins_get(radio)[csrhci_pin_reset]); - qdev_connect_gpio_out(s->mpu->gpio, N8X0_BT_WKUP_GPIO, - csrhci_pins_get(radio)[csrhci_pin_wakeup]); - - omap_uart_attach(s->mpu->uart[BT_UART], radio); -} - -static void n8x0_usb_setup(struct n800_s *s) -{ - SysBusDevice *dev; - s->usb = qdev_create(NULL, "tusb6010"); - dev = SYS_BUS_DEVICE(s->usb); - qdev_init_nofail(s->usb); - sysbus_connect_irq(dev, 0, - qdev_get_gpio_in(s->mpu->gpio, N8X0_TUSB_INT_GPIO)); - /* Using the NOR interface */ - omap_gpmc_attach(s->mpu->gpmc, N8X0_USB_ASYNC_CS, - sysbus_mmio_get_region(dev, 0)); - omap_gpmc_attach(s->mpu->gpmc, N8X0_USB_SYNC_CS, - sysbus_mmio_get_region(dev, 1)); - qdev_connect_gpio_out(s->mpu->gpio, N8X0_TUSB_ENABLE_GPIO, - qdev_get_gpio_in(s->usb, 0)); /* tusb_pwr */ -} - -/* Setup done before the main bootloader starts by some early setup code - * - used when we want to run the main bootloader in emulation. This - * isn't documented. */ -static uint32_t n800_pinout[104] = { - 0x080f00d8, 0x00d40808, 0x03080808, 0x080800d0, - 0x00dc0808, 0x0b0f0f00, 0x080800b4, 0x00c00808, - 0x08080808, 0x180800c4, 0x00b80000, 0x08080808, - 0x080800bc, 0x00cc0808, 0x08081818, 0x18180128, - 0x01241800, 0x18181818, 0x000000f0, 0x01300000, - 0x00001b0b, 0x1b0f0138, 0x00e0181b, 0x1b031b0b, - 0x180f0078, 0x00740018, 0x0f0f0f1a, 0x00000080, - 0x007c0000, 0x00000000, 0x00000088, 0x00840000, - 0x00000000, 0x00000094, 0x00980300, 0x0f180003, - 0x0000008c, 0x00900f0f, 0x0f0f1b00, 0x0f00009c, - 0x01140000, 0x1b1b0f18, 0x0818013c, 0x01400008, - 0x00001818, 0x000b0110, 0x010c1800, 0x0b030b0f, - 0x181800f4, 0x00f81818, 0x00000018, 0x000000fc, - 0x00401808, 0x00000000, 0x0f1b0030, 0x003c0008, - 0x00000000, 0x00000038, 0x00340000, 0x00000000, - 0x1a080070, 0x00641a1a, 0x08080808, 0x08080060, - 0x005c0808, 0x08080808, 0x08080058, 0x00540808, - 0x08080808, 0x0808006c, 0x00680808, 0x08080808, - 0x000000a8, 0x00b00000, 0x08080808, 0x000000a0, - 0x00a40000, 0x00000000, 0x08ff0050, 0x004c0808, - 0xffffffff, 0xffff0048, 0x0044ffff, 0xffffffff, - 0x000000ac, 0x01040800, 0x08080b0f, 0x18180100, - 0x01081818, 0x0b0b1808, 0x1a0300e4, 0x012c0b1a, - 0x02020018, 0x0b000134, 0x011c0800, 0x0b1b1b00, - 0x0f0000c8, 0x00ec181b, 0x000f0f02, 0x00180118, - 0x01200000, 0x0f0b1b1b, 0x0f0200e8, 0x0000020b, -}; - -static void n800_setup_nolo_tags(void *sram_base) -{ - int i; - uint32_t *p = sram_base + 0x8000; - uint32_t *v = sram_base + 0xa000; - - memset(p, 0, 0x3000); - - strcpy((void *) (p + 0), "QEMU N800"); - - strcpy((void *) (p + 8), "F5"); - - stl_p(p + 10, 0x04f70000); - strcpy((void *) (p + 9), "RX-34"); - - /* RAM size in MB? */ - stl_p(p + 12, 0x80); - - /* Pointer to the list of tags */ - stl_p(p + 13, OMAP2_SRAM_BASE + 0x9000); - - /* The NOLO tags start here */ - p = sram_base + 0x9000; -#define ADD_TAG(tag, len) \ - stw_p((uint16_t *) p + 0, tag); \ - stw_p((uint16_t *) p + 1, len); p++; \ - stl_p(p++, OMAP2_SRAM_BASE | (((void *) v - sram_base) & 0xffff)); - - /* OMAP STI console? Pin out settings? */ - ADD_TAG(0x6e01, 414); - for (i = 0; i < ARRAY_SIZE(n800_pinout); i++) { - stl_p(v++, n800_pinout[i]); - } - - /* Kernel memsize? */ - ADD_TAG(0x6e05, 1); - stl_p(v++, 2); - - /* NOLO serial console */ - ADD_TAG(0x6e02, 4); - stl_p(v++, XLDR_LL_UART); /* UART number (1 - 3) */ - -#if 0 - /* CBUS settings (Retu/AVilma) */ - ADD_TAG(0x6e03, 6); - stw_p((uint16_t *) v + 0, 65); /* CBUS GPIO0 */ - stw_p((uint16_t *) v + 1, 66); /* CBUS GPIO1 */ - stw_p((uint16_t *) v + 2, 64); /* CBUS GPIO2 */ - v += 2; -#endif - - /* Nokia ASIC BB5 (Retu/Tahvo) */ - ADD_TAG(0x6e0a, 4); - stw_p((uint16_t *) v + 0, 111); /* "Retu" interrupt GPIO */ - stw_p((uint16_t *) v + 1, 108); /* "Tahvo" interrupt GPIO */ - v++; - - /* LCD console? */ - ADD_TAG(0x6e04, 4); - stw_p((uint16_t *) v + 0, 30); /* ??? */ - stw_p((uint16_t *) v + 1, 24); /* ??? */ - v++; - -#if 0 - /* LCD settings */ - ADD_TAG(0x6e06, 2); - stw_p((uint16_t *) (v++), 15); /* ??? */ -#endif - - /* I^2C (Menelaus) */ - ADD_TAG(0x6e07, 4); - stl_p(v++, 0x00720000); /* ??? */ - - /* Unknown */ - ADD_TAG(0x6e0b, 6); - stw_p((uint16_t *) v + 0, 94); /* ??? */ - stw_p((uint16_t *) v + 1, 23); /* ??? */ - stw_p((uint16_t *) v + 2, 0); /* ??? */ - v += 2; - - /* OMAP gpio switch info */ - ADD_TAG(0x6e0c, 80); - strcpy((void *) v, "bat_cover"); v += 3; - stw_p((uint16_t *) v + 0, 110); /* GPIO num ??? */ - stw_p((uint16_t *) v + 1, 1); /* GPIO num ??? */ - v += 2; - strcpy((void *) v, "cam_act"); v += 3; - stw_p((uint16_t *) v + 0, 95); /* GPIO num ??? */ - stw_p((uint16_t *) v + 1, 32); /* GPIO num ??? */ - v += 2; - strcpy((void *) v, "cam_turn"); v += 3; - stw_p((uint16_t *) v + 0, 12); /* GPIO num ??? */ - stw_p((uint16_t *) v + 1, 33); /* GPIO num ??? */ - v += 2; - strcpy((void *) v, "headphone"); v += 3; - stw_p((uint16_t *) v + 0, 107); /* GPIO num ??? */ - stw_p((uint16_t *) v + 1, 17); /* GPIO num ??? */ - v += 2; - - /* Bluetooth */ - ADD_TAG(0x6e0e, 12); - stl_p(v++, 0x5c623d01); /* ??? */ - stl_p(v++, 0x00000201); /* ??? */ - stl_p(v++, 0x00000000); /* ??? */ - - /* CX3110x WLAN settings */ - ADD_TAG(0x6e0f, 8); - stl_p(v++, 0x00610025); /* ??? */ - stl_p(v++, 0xffff0057); /* ??? */ - - /* MMC host settings */ - ADD_TAG(0x6e10, 12); - stl_p(v++, 0xffff000f); /* ??? */ - stl_p(v++, 0xffffffff); /* ??? */ - stl_p(v++, 0x00000060); /* ??? */ - - /* OneNAND chip select */ - ADD_TAG(0x6e11, 10); - stl_p(v++, 0x00000401); /* ??? */ - stl_p(v++, 0x0002003a); /* ??? */ - stl_p(v++, 0x00000002); /* ??? */ - - /* TEA5761 sensor settings */ - ADD_TAG(0x6e12, 2); - stl_p(v++, 93); /* GPIO num ??? */ - -#if 0 - /* Unknown tag */ - ADD_TAG(6e09, 0); - - /* Kernel UART / console */ - ADD_TAG(6e12, 0); -#endif - - /* End of the list */ - stl_p(p++, 0x00000000); - stl_p(p++, 0x00000000); -} - -/* This task is normally performed by the bootloader. If we're loading - * a kernel directly, we need to set up GPMC mappings ourselves. */ -static void n800_gpmc_init(struct n800_s *s) -{ - uint32_t config7 = - (0xf << 8) | /* MASKADDRESS */ - (1 << 6) | /* CSVALID */ - (4 << 0); /* BASEADDRESS */ - - cpu_physical_memory_write(0x6800a078, /* GPMC_CONFIG7_0 */ - &config7, sizeof(config7)); -} - -/* Setup sequence done by the bootloader */ -static void n8x0_boot_init(void *opaque) -{ - struct n800_s *s = (struct n800_s *) opaque; - uint32_t buf; - - /* PRCM setup */ -#define omap_writel(addr, val) \ - buf = (val); \ - cpu_physical_memory_write(addr, &buf, sizeof(buf)) - - omap_writel(0x48008060, 0x41); /* PRCM_CLKSRC_CTRL */ - omap_writel(0x48008070, 1); /* PRCM_CLKOUT_CTRL */ - omap_writel(0x48008078, 0); /* PRCM_CLKEMUL_CTRL */ - omap_writel(0x48008090, 0); /* PRCM_VOLTSETUP */ - omap_writel(0x48008094, 0); /* PRCM_CLKSSETUP */ - omap_writel(0x48008098, 0); /* PRCM_POLCTRL */ - omap_writel(0x48008140, 2); /* CM_CLKSEL_MPU */ - omap_writel(0x48008148, 0); /* CM_CLKSTCTRL_MPU */ - omap_writel(0x48008158, 1); /* RM_RSTST_MPU */ - omap_writel(0x480081c8, 0x15); /* PM_WKDEP_MPU */ - omap_writel(0x480081d4, 0x1d4); /* PM_EVGENCTRL_MPU */ - omap_writel(0x480081d8, 0); /* PM_EVEGENONTIM_MPU */ - omap_writel(0x480081dc, 0); /* PM_EVEGENOFFTIM_MPU */ - omap_writel(0x480081e0, 0xc); /* PM_PWSTCTRL_MPU */ - omap_writel(0x48008200, 0x047e7ff7); /* CM_FCLKEN1_CORE */ - omap_writel(0x48008204, 0x00000004); /* CM_FCLKEN2_CORE */ - omap_writel(0x48008210, 0x047e7ff1); /* CM_ICLKEN1_CORE */ - omap_writel(0x48008214, 0x00000004); /* CM_ICLKEN2_CORE */ - omap_writel(0x4800821c, 0x00000000); /* CM_ICLKEN4_CORE */ - omap_writel(0x48008230, 0); /* CM_AUTOIDLE1_CORE */ - omap_writel(0x48008234, 0); /* CM_AUTOIDLE2_CORE */ - omap_writel(0x48008238, 7); /* CM_AUTOIDLE3_CORE */ - omap_writel(0x4800823c, 0); /* CM_AUTOIDLE4_CORE */ - omap_writel(0x48008240, 0x04360626); /* CM_CLKSEL1_CORE */ - omap_writel(0x48008244, 0x00000014); /* CM_CLKSEL2_CORE */ - omap_writel(0x48008248, 0); /* CM_CLKSTCTRL_CORE */ - omap_writel(0x48008300, 0x00000000); /* CM_FCLKEN_GFX */ - omap_writel(0x48008310, 0x00000000); /* CM_ICLKEN_GFX */ - omap_writel(0x48008340, 0x00000001); /* CM_CLKSEL_GFX */ - omap_writel(0x48008400, 0x00000004); /* CM_FCLKEN_WKUP */ - omap_writel(0x48008410, 0x00000004); /* CM_ICLKEN_WKUP */ - omap_writel(0x48008440, 0x00000000); /* CM_CLKSEL_WKUP */ - omap_writel(0x48008500, 0x000000cf); /* CM_CLKEN_PLL */ - omap_writel(0x48008530, 0x0000000c); /* CM_AUTOIDLE_PLL */ - omap_writel(0x48008540, /* CM_CLKSEL1_PLL */ - (0x78 << 12) | (6 << 8)); - omap_writel(0x48008544, 2); /* CM_CLKSEL2_PLL */ - - /* GPMC setup */ - n800_gpmc_init(s); - - /* Video setup */ - n800_dss_init(&s->blizzard); - - /* CPU setup */ - s->mpu->cpu->env.GE = 0x5; - - /* If the machine has a slided keyboard, open it */ - if (s->kbd) { - qemu_irq_raise(qdev_get_gpio_in(s->mpu->gpio, N810_SLIDE_GPIO)); - } -} - -#define OMAP_TAG_NOKIA_BT 0x4e01 -#define OMAP_TAG_WLAN_CX3110X 0x4e02 -#define OMAP_TAG_CBUS 0x4e03 -#define OMAP_TAG_EM_ASIC_BB5 0x4e04 - -static struct omap_gpiosw_info_s { - const char *name; - int line; - int type; -} n800_gpiosw_info[] = { - { - "bat_cover", N800_BAT_COVER_GPIO, - OMAP_GPIOSW_TYPE_COVER | OMAP_GPIOSW_INVERTED, - }, { - "cam_act", N800_CAM_ACT_GPIO, - OMAP_GPIOSW_TYPE_ACTIVITY, - }, { - "cam_turn", N800_CAM_TURN_GPIO, - OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_INVERTED, - }, { - "headphone", N8X0_HEADPHONE_GPIO, - OMAP_GPIOSW_TYPE_CONNECTION | OMAP_GPIOSW_INVERTED, - }, - { NULL } -}, n810_gpiosw_info[] = { - { - "gps_reset", N810_GPS_RESET_GPIO, - OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_OUTPUT, - }, { - "gps_wakeup", N810_GPS_WAKEUP_GPIO, - OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_OUTPUT, - }, { - "headphone", N8X0_HEADPHONE_GPIO, - OMAP_GPIOSW_TYPE_CONNECTION | OMAP_GPIOSW_INVERTED, - }, { - "kb_lock", N810_KB_LOCK_GPIO, - OMAP_GPIOSW_TYPE_COVER | OMAP_GPIOSW_INVERTED, - }, { - "sleepx_led", N810_SLEEPX_LED_GPIO, - OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_INVERTED | OMAP_GPIOSW_OUTPUT, - }, { - "slide", N810_SLIDE_GPIO, - OMAP_GPIOSW_TYPE_COVER | OMAP_GPIOSW_INVERTED, - }, - { NULL } -}; - -static struct omap_partition_info_s { - uint32_t offset; - uint32_t size; - int mask; - const char *name; -} n800_part_info[] = { - { 0x00000000, 0x00020000, 0x3, "bootloader" }, - { 0x00020000, 0x00060000, 0x0, "config" }, - { 0x00080000, 0x00200000, 0x0, "kernel" }, - { 0x00280000, 0x00200000, 0x3, "initfs" }, - { 0x00480000, 0x0fb80000, 0x3, "rootfs" }, - - { 0, 0, 0, NULL } -}, n810_part_info[] = { - { 0x00000000, 0x00020000, 0x3, "bootloader" }, - { 0x00020000, 0x00060000, 0x0, "config" }, - { 0x00080000, 0x00220000, 0x0, "kernel" }, - { 0x002a0000, 0x00400000, 0x0, "initfs" }, - { 0x006a0000, 0x0f960000, 0x0, "rootfs" }, - - { 0, 0, 0, NULL } -}; - -static bdaddr_t n8x0_bd_addr = {{ N8X0_BD_ADDR }}; - -static int n8x0_atag_setup(void *p, int model) -{ - uint8_t *b; - uint16_t *w; - uint32_t *l; - struct omap_gpiosw_info_s *gpiosw; - struct omap_partition_info_s *partition; - const char *tag; - - w = p; - - stw_p(w++, OMAP_TAG_UART); /* u16 tag */ - stw_p(w++, 4); /* u16 len */ - stw_p(w++, (1 << 2) | (1 << 1) | (1 << 0)); /* uint enabled_uarts */ - w++; - -#if 0 - stw_p(w++, OMAP_TAG_SERIAL_CONSOLE); /* u16 tag */ - stw_p(w++, 4); /* u16 len */ - stw_p(w++, XLDR_LL_UART + 1); /* u8 console_uart */ - stw_p(w++, 115200); /* u32 console_speed */ -#endif - - stw_p(w++, OMAP_TAG_LCD); /* u16 tag */ - stw_p(w++, 36); /* u16 len */ - strcpy((void *) w, "QEMU LCD panel"); /* char panel_name[16] */ - w += 8; - strcpy((void *) w, "blizzard"); /* char ctrl_name[16] */ - w += 8; - stw_p(w++, N810_BLIZZARD_RESET_GPIO); /* TODO: n800 s16 nreset_gpio */ - stw_p(w++, 24); /* u8 data_lines */ - - stw_p(w++, OMAP_TAG_CBUS); /* u16 tag */ - stw_p(w++, 8); /* u16 len */ - stw_p(w++, N8X0_CBUS_CLK_GPIO); /* s16 clk_gpio */ - stw_p(w++, N8X0_CBUS_DAT_GPIO); /* s16 dat_gpio */ - stw_p(w++, N8X0_CBUS_SEL_GPIO); /* s16 sel_gpio */ - w++; - - stw_p(w++, OMAP_TAG_EM_ASIC_BB5); /* u16 tag */ - stw_p(w++, 4); /* u16 len */ - stw_p(w++, N8X0_RETU_GPIO); /* s16 retu_irq_gpio */ - stw_p(w++, N8X0_TAHVO_GPIO); /* s16 tahvo_irq_gpio */ - - gpiosw = (model == 810) ? n810_gpiosw_info : n800_gpiosw_info; - for (; gpiosw->name; gpiosw++) { - stw_p(w++, OMAP_TAG_GPIO_SWITCH); /* u16 tag */ - stw_p(w++, 20); /* u16 len */ - strcpy((void *) w, gpiosw->name); /* char name[12] */ - w += 6; - stw_p(w++, gpiosw->line); /* u16 gpio */ - stw_p(w++, gpiosw->type); - stw_p(w++, 0); - stw_p(w++, 0); - } - - stw_p(w++, OMAP_TAG_NOKIA_BT); /* u16 tag */ - stw_p(w++, 12); /* u16 len */ - b = (void *) w; - stb_p(b++, 0x01); /* u8 chip_type (CSR) */ - stb_p(b++, N8X0_BT_WKUP_GPIO); /* u8 bt_wakeup_gpio */ - stb_p(b++, N8X0_BT_HOST_WKUP_GPIO); /* u8 host_wakeup_gpio */ - stb_p(b++, N8X0_BT_RESET_GPIO); /* u8 reset_gpio */ - stb_p(b++, BT_UART + 1); /* u8 bt_uart */ - memcpy(b, &n8x0_bd_addr, 6); /* u8 bd_addr[6] */ - b += 6; - stb_p(b++, 0x02); /* u8 bt_sysclk (38.4) */ - w = (void *) b; - - stw_p(w++, OMAP_TAG_WLAN_CX3110X); /* u16 tag */ - stw_p(w++, 8); /* u16 len */ - stw_p(w++, 0x25); /* u8 chip_type */ - stw_p(w++, N8X0_WLAN_PWR_GPIO); /* s16 power_gpio */ - stw_p(w++, N8X0_WLAN_IRQ_GPIO); /* s16 irq_gpio */ - stw_p(w++, -1); /* s16 spi_cs_gpio */ - - stw_p(w++, OMAP_TAG_MMC); /* u16 tag */ - stw_p(w++, 16); /* u16 len */ - if (model == 810) { - stw_p(w++, 0x23f); /* unsigned flags */ - stw_p(w++, -1); /* s16 power_pin */ - stw_p(w++, -1); /* s16 switch_pin */ - stw_p(w++, -1); /* s16 wp_pin */ - stw_p(w++, 0x240); /* unsigned flags */ - stw_p(w++, 0xc000); /* s16 power_pin */ - stw_p(w++, 0x0248); /* s16 switch_pin */ - stw_p(w++, 0xc000); /* s16 wp_pin */ - } else { - stw_p(w++, 0xf); /* unsigned flags */ - stw_p(w++, -1); /* s16 power_pin */ - stw_p(w++, -1); /* s16 switch_pin */ - stw_p(w++, -1); /* s16 wp_pin */ - stw_p(w++, 0); /* unsigned flags */ - stw_p(w++, 0); /* s16 power_pin */ - stw_p(w++, 0); /* s16 switch_pin */ - stw_p(w++, 0); /* s16 wp_pin */ - } - - stw_p(w++, OMAP_TAG_TEA5761); /* u16 tag */ - stw_p(w++, 4); /* u16 len */ - stw_p(w++, N8X0_TEA5761_CS_GPIO); /* u16 enable_gpio */ - w++; - - partition = (model == 810) ? n810_part_info : n800_part_info; - for (; partition->name; partition++) { - stw_p(w++, OMAP_TAG_PARTITION); /* u16 tag */ - stw_p(w++, 28); /* u16 len */ - strcpy((void *) w, partition->name); /* char name[16] */ - l = (void *) (w + 8); - stl_p(l++, partition->size); /* unsigned int size */ - stl_p(l++, partition->offset); /* unsigned int offset */ - stl_p(l++, partition->mask); /* unsigned int mask_flags */ - w = (void *) l; - } - - stw_p(w++, OMAP_TAG_BOOT_REASON); /* u16 tag */ - stw_p(w++, 12); /* u16 len */ -#if 0 - strcpy((void *) w, "por"); /* char reason_str[12] */ - strcpy((void *) w, "charger"); /* char reason_str[12] */ - strcpy((void *) w, "32wd_to"); /* char reason_str[12] */ - strcpy((void *) w, "sw_rst"); /* char reason_str[12] */ - strcpy((void *) w, "mbus"); /* char reason_str[12] */ - strcpy((void *) w, "unknown"); /* char reason_str[12] */ - strcpy((void *) w, "swdg_to"); /* char reason_str[12] */ - strcpy((void *) w, "sec_vio"); /* char reason_str[12] */ - strcpy((void *) w, "pwr_key"); /* char reason_str[12] */ - strcpy((void *) w, "rtc_alarm"); /* char reason_str[12] */ -#else - strcpy((void *) w, "pwr_key"); /* char reason_str[12] */ -#endif - w += 6; - - tag = (model == 810) ? "RX-44" : "RX-34"; - stw_p(w++, OMAP_TAG_VERSION_STR); /* u16 tag */ - stw_p(w++, 24); /* u16 len */ - strcpy((void *) w, "product"); /* char component[12] */ - w += 6; - strcpy((void *) w, tag); /* char version[12] */ - w += 6; - - stw_p(w++, OMAP_TAG_VERSION_STR); /* u16 tag */ - stw_p(w++, 24); /* u16 len */ - strcpy((void *) w, "hw-build"); /* char component[12] */ - w += 6; - strcpy((void *) w, "QEMU "); - pstrcat((void *) w, 12, qemu_hw_version()); /* char version[12] */ - w += 6; - - tag = (model == 810) ? "1.1.10-qemu" : "1.1.6-qemu"; - stw_p(w++, OMAP_TAG_VERSION_STR); /* u16 tag */ - stw_p(w++, 24); /* u16 len */ - strcpy((void *) w, "nolo"); /* char component[12] */ - w += 6; - strcpy((void *) w, tag); /* char version[12] */ - w += 6; - - return (void *) w - p; -} - -static int n800_atag_setup(const struct arm_boot_info *info, void *p) -{ - return n8x0_atag_setup(p, 800); -} - -static int n810_atag_setup(const struct arm_boot_info *info, void *p) -{ - return n8x0_atag_setup(p, 810); -} - -static void n8x0_init(MachineState *machine, - struct arm_boot_info *binfo, int model) -{ - MemoryRegion *sysmem = get_system_memory(); - struct n800_s *s = (struct n800_s *) g_malloc0(sizeof(*s)); - int sdram_size = binfo->ram_size; - - s->mpu = omap2420_mpu_init(sysmem, sdram_size, machine->cpu_model); - - /* Setup peripherals - * - * Believed external peripherals layout in the N810: - * (spi bus 1) - * tsc2005 - * lcd_mipid - * (spi bus 2) - * Conexant cx3110x (WLAN) - * optional: pc2400m (WiMAX) - * (i2c bus 0) - * TLV320AIC33 (audio codec) - * TCM825x (camera by Toshiba) - * lp5521 (clever LEDs) - * tsl2563 (light sensor, hwmon, model 7, rev. 0) - * lm8323 (keypad, manf 00, rev 04) - * (i2c bus 1) - * tmp105 (temperature sensor, hwmon) - * menelaus (pm) - * (somewhere on i2c - maybe N800-only) - * tea5761 (FM tuner) - * (serial 0) - * GPS - * (some serial port) - * csr41814 (Bluetooth) - */ - n8x0_gpio_setup(s); - n8x0_nand_setup(s); - n8x0_i2c_setup(s); - if (model == 800) { - n800_tsc_kbd_setup(s); - } else if (model == 810) { - n810_tsc_setup(s); - n810_kbd_setup(s); - } - n8x0_spi_setup(s); - n8x0_dss_setup(s); - n8x0_cbus_setup(s); - n8x0_uart_setup(s); - if (usb_enabled()) { - n8x0_usb_setup(s); - } - - if (machine->kernel_filename) { - /* Or at the linux loader. */ - binfo->kernel_filename = machine->kernel_filename; - binfo->kernel_cmdline = machine->kernel_cmdline; - binfo->initrd_filename = machine->initrd_filename; - arm_load_kernel(s->mpu->cpu, binfo); - - qemu_register_reset(n8x0_boot_init, s); - } - - if (option_rom[0].name && - (machine->boot_order[0] == 'n' || !machine->kernel_filename)) { - uint8_t nolo_tags[0x10000]; - /* No, wait, better start at the ROM. */ - s->mpu->cpu->env.regs[15] = OMAP2_Q2_BASE + 0x400000; - - /* This is intended for loading the `secondary.bin' program from - * Nokia images (the NOLO bootloader). The entry point seems - * to be at OMAP2_Q2_BASE + 0x400000. - * - * The `2nd.bin' files contain some kind of earlier boot code and - * for them the entry point needs to be set to OMAP2_SRAM_BASE. - * - * The code above is for loading the `zImage' file from Nokia - * images. */ - load_image_targphys(option_rom[0].name, - OMAP2_Q2_BASE + 0x400000, - sdram_size - 0x400000); - - n800_setup_nolo_tags(nolo_tags); - cpu_physical_memory_write(OMAP2_SRAM_BASE, nolo_tags, 0x10000); - } -} - -static struct arm_boot_info n800_binfo = { - .loader_start = OMAP2_Q2_BASE, - /* Actually two chips of 0x4000000 bytes each */ - .ram_size = 0x08000000, - .board_id = 0x4f7, - .atag_board = n800_atag_setup, -}; - -static struct arm_boot_info n810_binfo = { - .loader_start = OMAP2_Q2_BASE, - /* Actually two chips of 0x4000000 bytes each */ - .ram_size = 0x08000000, - /* 0x60c and 0x6bf (WiMAX Edition) have been assigned but are not - * used by some older versions of the bootloader and 5555 is used - * instead (including versions that shipped with many devices). */ - .board_id = 0x60c, - .atag_board = n810_atag_setup, -}; - -static void n800_init(MachineState *machine) -{ - n8x0_init(machine, &n800_binfo, 800); -} - -static void n810_init(MachineState *machine) -{ - n8x0_init(machine, &n810_binfo, 810); -} - -static void n800_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "Nokia N800 tablet aka. RX-34 (OMAP2420)"; - mc->init = n800_init; - mc->default_boot_order = ""; -} - -static const TypeInfo n800_type = { - .name = MACHINE_TYPE_NAME("n800"), - .parent = TYPE_MACHINE, - .class_init = n800_class_init, -}; - -static void n810_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "Nokia N810 tablet aka. RX-44 (OMAP2420)"; - mc->init = n810_init; - mc->default_boot_order = ""; -} - -static const TypeInfo n810_type = { - .name = MACHINE_TYPE_NAME("n810"), - .parent = TYPE_MACHINE, - .class_init = n810_class_init, -}; - -static void nseries_machine_init(void) -{ - type_register_static(&n800_type); - type_register_static(&n810_type); -} - -type_init(nseries_machine_init) diff --git a/qemu/hw/arm/omap1.c b/qemu/hw/arm/omap1.c deleted file mode 100644 index b3cf0ec69..000000000 --- a/qemu/hw/arm/omap1.c +++ /dev/null @@ -1,4086 +0,0 @@ -/* - * TI OMAP processors emulation. - * - * Copyright (C) 2006-2008 Andrzej Zaborowski <balrog@zabor.org> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "qemu-common.h" -#include "cpu.h" -#include "hw/boards.h" -#include "hw/hw.h" -#include "hw/arm/arm.h" -#include "hw/arm/omap.h" -#include "sysemu/sysemu.h" -#include "hw/arm/soc_dma.h" -#include "sysemu/block-backend.h" -#include "sysemu/blockdev.h" -#include "qemu/range.h" -#include "hw/sysbus.h" -#include "qemu/cutils.h" -#include "qemu/bcd.h" - -/* Should signal the TCMI/GPMC */ -uint32_t omap_badwidth_read8(void *opaque, hwaddr addr) -{ - uint8_t ret; - - OMAP_8B_REG(addr); - cpu_physical_memory_read(addr, &ret, 1); - return ret; -} - -void omap_badwidth_write8(void *opaque, hwaddr addr, - uint32_t value) -{ - uint8_t val8 = value; - - OMAP_8B_REG(addr); - cpu_physical_memory_write(addr, &val8, 1); -} - -uint32_t omap_badwidth_read16(void *opaque, hwaddr addr) -{ - uint16_t ret; - - OMAP_16B_REG(addr); - cpu_physical_memory_read(addr, &ret, 2); - return ret; -} - -void omap_badwidth_write16(void *opaque, hwaddr addr, - uint32_t value) -{ - uint16_t val16 = value; - - OMAP_16B_REG(addr); - cpu_physical_memory_write(addr, &val16, 2); -} - -uint32_t omap_badwidth_read32(void *opaque, hwaddr addr) -{ - uint32_t ret; - - OMAP_32B_REG(addr); - cpu_physical_memory_read(addr, &ret, 4); - return ret; -} - -void omap_badwidth_write32(void *opaque, hwaddr addr, - uint32_t value) -{ - OMAP_32B_REG(addr); - cpu_physical_memory_write(addr, &value, 4); -} - -/* MPU OS timers */ -struct omap_mpu_timer_s { - MemoryRegion iomem; - qemu_irq irq; - omap_clk clk; - uint32_t val; - int64_t time; - QEMUTimer *timer; - QEMUBH *tick; - int64_t rate; - int it_ena; - - int enable; - int ptv; - int ar; - int st; - uint32_t reset_val; -}; - -static inline uint32_t omap_timer_read(struct omap_mpu_timer_s *timer) -{ - uint64_t distance = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - timer->time; - - if (timer->st && timer->enable && timer->rate) - return timer->val - muldiv64(distance >> (timer->ptv + 1), - timer->rate, NANOSECONDS_PER_SECOND); - else - return timer->val; -} - -static inline void omap_timer_sync(struct omap_mpu_timer_s *timer) -{ - timer->val = omap_timer_read(timer); - timer->time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); -} - -static inline void omap_timer_update(struct omap_mpu_timer_s *timer) -{ - int64_t expires; - - if (timer->enable && timer->st && timer->rate) { - timer->val = timer->reset_val; /* Should skip this on clk enable */ - expires = muldiv64((uint64_t) timer->val << (timer->ptv + 1), - NANOSECONDS_PER_SECOND, timer->rate); - - /* If timer expiry would be sooner than in about 1 ms and - * auto-reload isn't set, then fire immediately. This is a hack - * to make systems like PalmOS run in acceptable time. PalmOS - * sets the interval to a very low value and polls the status bit - * in a busy loop when it wants to sleep just a couple of CPU - * ticks. */ - if (expires > (NANOSECONDS_PER_SECOND >> 10) || timer->ar) { - timer_mod(timer->timer, timer->time + expires); - } else { - qemu_bh_schedule(timer->tick); - } - } else - timer_del(timer->timer); -} - -static void omap_timer_fire(void *opaque) -{ - struct omap_mpu_timer_s *timer = opaque; - - if (!timer->ar) { - timer->val = 0; - timer->st = 0; - } - - if (timer->it_ena) - /* Edge-triggered irq */ - qemu_irq_pulse(timer->irq); -} - -static void omap_timer_tick(void *opaque) -{ - struct omap_mpu_timer_s *timer = (struct omap_mpu_timer_s *) opaque; - - omap_timer_sync(timer); - omap_timer_fire(timer); - omap_timer_update(timer); -} - -static void omap_timer_clk_update(void *opaque, int line, int on) -{ - struct omap_mpu_timer_s *timer = (struct omap_mpu_timer_s *) opaque; - - omap_timer_sync(timer); - timer->rate = on ? omap_clk_getrate(timer->clk) : 0; - omap_timer_update(timer); -} - -static void omap_timer_clk_setup(struct omap_mpu_timer_s *timer) -{ - omap_clk_adduser(timer->clk, - qemu_allocate_irq(omap_timer_clk_update, timer, 0)); - timer->rate = omap_clk_getrate(timer->clk); -} - -static uint64_t omap_mpu_timer_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *) opaque; - - if (size != 4) { - return omap_badwidth_read32(opaque, addr); - } - - switch (addr) { - case 0x00: /* CNTL_TIMER */ - return (s->enable << 5) | (s->ptv << 2) | (s->ar << 1) | s->st; - - case 0x04: /* LOAD_TIM */ - break; - - case 0x08: /* READ_TIM */ - return omap_timer_read(s); - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_mpu_timer_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *) opaque; - - if (size != 4) { - omap_badwidth_write32(opaque, addr, value); - return; - } - - switch (addr) { - case 0x00: /* CNTL_TIMER */ - omap_timer_sync(s); - s->enable = (value >> 5) & 1; - s->ptv = (value >> 2) & 7; - s->ar = (value >> 1) & 1; - s->st = value & 1; - omap_timer_update(s); - return; - - case 0x04: /* LOAD_TIM */ - s->reset_val = value; - return; - - case 0x08: /* READ_TIM */ - OMAP_RO_REG(addr); - break; - - default: - OMAP_BAD_REG(addr); - } -} - -static const MemoryRegionOps omap_mpu_timer_ops = { - .read = omap_mpu_timer_read, - .write = omap_mpu_timer_write, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - -static void omap_mpu_timer_reset(struct omap_mpu_timer_s *s) -{ - timer_del(s->timer); - s->enable = 0; - s->reset_val = 31337; - s->val = 0; - s->ptv = 0; - s->ar = 0; - s->st = 0; - s->it_ena = 1; -} - -static struct omap_mpu_timer_s *omap_mpu_timer_init(MemoryRegion *system_memory, - hwaddr base, - qemu_irq irq, omap_clk clk) -{ - struct omap_mpu_timer_s *s = g_new0(struct omap_mpu_timer_s, 1); - - s->irq = irq; - s->clk = clk; - s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, omap_timer_tick, s); - s->tick = qemu_bh_new(omap_timer_fire, s); - omap_mpu_timer_reset(s); - omap_timer_clk_setup(s); - - memory_region_init_io(&s->iomem, NULL, &omap_mpu_timer_ops, s, - "omap-mpu-timer", 0x100); - - memory_region_add_subregion(system_memory, base, &s->iomem); - - return s; -} - -/* Watchdog timer */ -struct omap_watchdog_timer_s { - struct omap_mpu_timer_s timer; - MemoryRegion iomem; - uint8_t last_wr; - int mode; - int free; - int reset; -}; - -static uint64_t omap_wd_timer_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *) opaque; - - if (size != 2) { - return omap_badwidth_read16(opaque, addr); - } - - switch (addr) { - case 0x00: /* CNTL_TIMER */ - return (s->timer.ptv << 9) | (s->timer.ar << 8) | - (s->timer.st << 7) | (s->free << 1); - - case 0x04: /* READ_TIMER */ - return omap_timer_read(&s->timer); - - case 0x08: /* TIMER_MODE */ - return s->mode << 15; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_wd_timer_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *) opaque; - - if (size != 2) { - omap_badwidth_write16(opaque, addr, value); - return; - } - - switch (addr) { - case 0x00: /* CNTL_TIMER */ - omap_timer_sync(&s->timer); - s->timer.ptv = (value >> 9) & 7; - s->timer.ar = (value >> 8) & 1; - s->timer.st = (value >> 7) & 1; - s->free = (value >> 1) & 1; - omap_timer_update(&s->timer); - break; - - case 0x04: /* LOAD_TIMER */ - s->timer.reset_val = value & 0xffff; - break; - - case 0x08: /* TIMER_MODE */ - if (!s->mode && ((value >> 15) & 1)) - omap_clk_get(s->timer.clk); - s->mode |= (value >> 15) & 1; - if (s->last_wr == 0xf5) { - if ((value & 0xff) == 0xa0) { - if (s->mode) { - s->mode = 0; - omap_clk_put(s->timer.clk); - } - } else { - /* XXX: on T|E hardware somehow this has no effect, - * on Zire 71 it works as specified. */ - s->reset = 1; - qemu_system_reset_request(); - } - } - s->last_wr = value & 0xff; - break; - - default: - OMAP_BAD_REG(addr); - } -} - -static const MemoryRegionOps omap_wd_timer_ops = { - .read = omap_wd_timer_read, - .write = omap_wd_timer_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void omap_wd_timer_reset(struct omap_watchdog_timer_s *s) -{ - timer_del(s->timer.timer); - if (!s->mode) - omap_clk_get(s->timer.clk); - s->mode = 1; - s->free = 1; - s->reset = 0; - s->timer.enable = 1; - s->timer.it_ena = 1; - s->timer.reset_val = 0xffff; - s->timer.val = 0; - s->timer.st = 0; - s->timer.ptv = 0; - s->timer.ar = 0; - omap_timer_update(&s->timer); -} - -static struct omap_watchdog_timer_s *omap_wd_timer_init(MemoryRegion *memory, - hwaddr base, - qemu_irq irq, omap_clk clk) -{ - struct omap_watchdog_timer_s *s = g_new0(struct omap_watchdog_timer_s, 1); - - s->timer.irq = irq; - s->timer.clk = clk; - s->timer.timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, omap_timer_tick, &s->timer); - omap_wd_timer_reset(s); - omap_timer_clk_setup(&s->timer); - - memory_region_init_io(&s->iomem, NULL, &omap_wd_timer_ops, s, - "omap-wd-timer", 0x100); - memory_region_add_subregion(memory, base, &s->iomem); - - return s; -} - -/* 32-kHz timer */ -struct omap_32khz_timer_s { - struct omap_mpu_timer_s timer; - MemoryRegion iomem; -}; - -static uint64_t omap_os_timer_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - - if (size != 4) { - return omap_badwidth_read32(opaque, addr); - } - - switch (offset) { - case 0x00: /* TVR */ - return s->timer.reset_val; - - case 0x04: /* TCR */ - return omap_timer_read(&s->timer); - - case 0x08: /* CR */ - return (s->timer.ar << 3) | (s->timer.it_ena << 2) | s->timer.st; - - default: - break; - } - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_os_timer_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - - if (size != 4) { - omap_badwidth_write32(opaque, addr, value); - return; - } - - switch (offset) { - case 0x00: /* TVR */ - s->timer.reset_val = value & 0x00ffffff; - break; - - case 0x04: /* TCR */ - OMAP_RO_REG(addr); - break; - - case 0x08: /* CR */ - s->timer.ar = (value >> 3) & 1; - s->timer.it_ena = (value >> 2) & 1; - if (s->timer.st != (value & 1) || (value & 2)) { - omap_timer_sync(&s->timer); - s->timer.enable = value & 1; - s->timer.st = value & 1; - omap_timer_update(&s->timer); - } - break; - - default: - OMAP_BAD_REG(addr); - } -} - -static const MemoryRegionOps omap_os_timer_ops = { - .read = omap_os_timer_read, - .write = omap_os_timer_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void omap_os_timer_reset(struct omap_32khz_timer_s *s) -{ - timer_del(s->timer.timer); - s->timer.enable = 0; - s->timer.it_ena = 0; - s->timer.reset_val = 0x00ffffff; - s->timer.val = 0; - s->timer.st = 0; - s->timer.ptv = 0; - s->timer.ar = 1; -} - -static struct omap_32khz_timer_s *omap_os_timer_init(MemoryRegion *memory, - hwaddr base, - qemu_irq irq, omap_clk clk) -{ - struct omap_32khz_timer_s *s = g_new0(struct omap_32khz_timer_s, 1); - - s->timer.irq = irq; - s->timer.clk = clk; - s->timer.timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, omap_timer_tick, &s->timer); - omap_os_timer_reset(s); - omap_timer_clk_setup(&s->timer); - - memory_region_init_io(&s->iomem, NULL, &omap_os_timer_ops, s, - "omap-os-timer", 0x800); - memory_region_add_subregion(memory, base, &s->iomem); - - return s; -} - -/* Ultra Low-Power Device Module */ -static uint64_t omap_ulpd_pm_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; - uint16_t ret; - - if (size != 2) { - return omap_badwidth_read16(opaque, addr); - } - - switch (addr) { - case 0x14: /* IT_STATUS */ - ret = s->ulpd_pm_regs[addr >> 2]; - s->ulpd_pm_regs[addr >> 2] = 0; - qemu_irq_lower(qdev_get_gpio_in(s->ih[1], OMAP_INT_GAUGE_32K)); - return ret; - - case 0x18: /* Reserved */ - case 0x1c: /* Reserved */ - case 0x20: /* Reserved */ - case 0x28: /* Reserved */ - case 0x2c: /* Reserved */ - OMAP_BAD_REG(addr); - /* fall through */ - case 0x00: /* COUNTER_32_LSB */ - case 0x04: /* COUNTER_32_MSB */ - case 0x08: /* COUNTER_HIGH_FREQ_LSB */ - case 0x0c: /* COUNTER_HIGH_FREQ_MSB */ - case 0x10: /* GAUGING_CTRL */ - case 0x24: /* SETUP_ANALOG_CELL3_ULPD1 */ - case 0x30: /* CLOCK_CTRL */ - case 0x34: /* SOFT_REQ */ - case 0x38: /* COUNTER_32_FIQ */ - case 0x3c: /* DPLL_CTRL */ - case 0x40: /* STATUS_REQ */ - /* XXX: check clk::usecount state for every clock */ - case 0x48: /* LOCL_TIME */ - case 0x4c: /* APLL_CTRL */ - case 0x50: /* POWER_CTRL */ - return s->ulpd_pm_regs[addr >> 2]; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static inline void omap_ulpd_clk_update(struct omap_mpu_state_s *s, - uint16_t diff, uint16_t value) -{ - if (diff & (1 << 4)) /* USB_MCLK_EN */ - omap_clk_onoff(omap_findclk(s, "usb_clk0"), (value >> 4) & 1); - if (diff & (1 << 5)) /* DIS_USB_PVCI_CLK */ - omap_clk_onoff(omap_findclk(s, "usb_w2fc_ck"), (~value >> 5) & 1); -} - -static inline void omap_ulpd_req_update(struct omap_mpu_state_s *s, - uint16_t diff, uint16_t value) -{ - if (diff & (1 << 0)) /* SOFT_DPLL_REQ */ - omap_clk_canidle(omap_findclk(s, "dpll4"), (~value >> 0) & 1); - if (diff & (1 << 1)) /* SOFT_COM_REQ */ - omap_clk_canidle(omap_findclk(s, "com_mclk_out"), (~value >> 1) & 1); - if (diff & (1 << 2)) /* SOFT_SDW_REQ */ - omap_clk_canidle(omap_findclk(s, "bt_mclk_out"), (~value >> 2) & 1); - if (diff & (1 << 3)) /* SOFT_USB_REQ */ - omap_clk_canidle(omap_findclk(s, "usb_clk0"), (~value >> 3) & 1); -} - -static void omap_ulpd_pm_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; - int64_t now, ticks; - int div, mult; - static const int bypass_div[4] = { 1, 2, 4, 4 }; - uint16_t diff; - - if (size != 2) { - omap_badwidth_write16(opaque, addr, value); - return; - } - - switch (addr) { - case 0x00: /* COUNTER_32_LSB */ - case 0x04: /* COUNTER_32_MSB */ - case 0x08: /* COUNTER_HIGH_FREQ_LSB */ - case 0x0c: /* COUNTER_HIGH_FREQ_MSB */ - case 0x14: /* IT_STATUS */ - case 0x40: /* STATUS_REQ */ - OMAP_RO_REG(addr); - break; - - case 0x10: /* GAUGING_CTRL */ - /* Bits 0 and 1 seem to be confused in the OMAP 310 TRM */ - if ((s->ulpd_pm_regs[addr >> 2] ^ value) & 1) { - now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - - if (value & 1) - s->ulpd_gauge_start = now; - else { - now -= s->ulpd_gauge_start; - - /* 32-kHz ticks */ - ticks = muldiv64(now, 32768, NANOSECONDS_PER_SECOND); - s->ulpd_pm_regs[0x00 >> 2] = (ticks >> 0) & 0xffff; - s->ulpd_pm_regs[0x04 >> 2] = (ticks >> 16) & 0xffff; - if (ticks >> 32) /* OVERFLOW_32K */ - s->ulpd_pm_regs[0x14 >> 2] |= 1 << 2; - - /* High frequency ticks */ - ticks = muldiv64(now, 12000000, NANOSECONDS_PER_SECOND); - s->ulpd_pm_regs[0x08 >> 2] = (ticks >> 0) & 0xffff; - s->ulpd_pm_regs[0x0c >> 2] = (ticks >> 16) & 0xffff; - if (ticks >> 32) /* OVERFLOW_HI_FREQ */ - s->ulpd_pm_regs[0x14 >> 2] |= 1 << 1; - - s->ulpd_pm_regs[0x14 >> 2] |= 1 << 0; /* IT_GAUGING */ - qemu_irq_raise(qdev_get_gpio_in(s->ih[1], OMAP_INT_GAUGE_32K)); - } - } - s->ulpd_pm_regs[addr >> 2] = value; - break; - - case 0x18: /* Reserved */ - case 0x1c: /* Reserved */ - case 0x20: /* Reserved */ - case 0x28: /* Reserved */ - case 0x2c: /* Reserved */ - OMAP_BAD_REG(addr); - /* fall through */ - case 0x24: /* SETUP_ANALOG_CELL3_ULPD1 */ - case 0x38: /* COUNTER_32_FIQ */ - case 0x48: /* LOCL_TIME */ - case 0x50: /* POWER_CTRL */ - s->ulpd_pm_regs[addr >> 2] = value; - break; - - case 0x30: /* CLOCK_CTRL */ - diff = s->ulpd_pm_regs[addr >> 2] ^ value; - s->ulpd_pm_regs[addr >> 2] = value & 0x3f; - omap_ulpd_clk_update(s, diff, value); - break; - - case 0x34: /* SOFT_REQ */ - diff = s->ulpd_pm_regs[addr >> 2] ^ value; - s->ulpd_pm_regs[addr >> 2] = value & 0x1f; - omap_ulpd_req_update(s, diff, value); - break; - - case 0x3c: /* DPLL_CTRL */ - /* XXX: OMAP310 TRM claims bit 3 is PLL_ENABLE, and bit 4 is - * omitted altogether, probably a typo. */ - /* This register has identical semantics with DPLL(1:3) control - * registers, see omap_dpll_write() */ - diff = s->ulpd_pm_regs[addr >> 2] & value; - s->ulpd_pm_regs[addr >> 2] = value & 0x2fff; - if (diff & (0x3ff << 2)) { - if (value & (1 << 4)) { /* PLL_ENABLE */ - div = ((value >> 5) & 3) + 1; /* PLL_DIV */ - mult = MIN((value >> 7) & 0x1f, 1); /* PLL_MULT */ - } else { - div = bypass_div[((value >> 2) & 3)]; /* BYPASS_DIV */ - mult = 1; - } - omap_clk_setrate(omap_findclk(s, "dpll4"), div, mult); - } - - /* Enter the desired mode. */ - s->ulpd_pm_regs[addr >> 2] = - (s->ulpd_pm_regs[addr >> 2] & 0xfffe) | - ((s->ulpd_pm_regs[addr >> 2] >> 4) & 1); - - /* Act as if the lock is restored. */ - s->ulpd_pm_regs[addr >> 2] |= 2; - break; - - case 0x4c: /* APLL_CTRL */ - diff = s->ulpd_pm_regs[addr >> 2] & value; - s->ulpd_pm_regs[addr >> 2] = value & 0xf; - if (diff & (1 << 0)) /* APLL_NDPLL_SWITCH */ - omap_clk_reparent(omap_findclk(s, "ck_48m"), omap_findclk(s, - (value & (1 << 0)) ? "apll" : "dpll4")); - break; - - default: - OMAP_BAD_REG(addr); - } -} - -static const MemoryRegionOps omap_ulpd_pm_ops = { - .read = omap_ulpd_pm_read, - .write = omap_ulpd_pm_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void omap_ulpd_pm_reset(struct omap_mpu_state_s *mpu) -{ - mpu->ulpd_pm_regs[0x00 >> 2] = 0x0001; - mpu->ulpd_pm_regs[0x04 >> 2] = 0x0000; - mpu->ulpd_pm_regs[0x08 >> 2] = 0x0001; - mpu->ulpd_pm_regs[0x0c >> 2] = 0x0000; - mpu->ulpd_pm_regs[0x10 >> 2] = 0x0000; - mpu->ulpd_pm_regs[0x18 >> 2] = 0x01; - mpu->ulpd_pm_regs[0x1c >> 2] = 0x01; - mpu->ulpd_pm_regs[0x20 >> 2] = 0x01; - mpu->ulpd_pm_regs[0x24 >> 2] = 0x03ff; - mpu->ulpd_pm_regs[0x28 >> 2] = 0x01; - mpu->ulpd_pm_regs[0x2c >> 2] = 0x01; - omap_ulpd_clk_update(mpu, mpu->ulpd_pm_regs[0x30 >> 2], 0x0000); - mpu->ulpd_pm_regs[0x30 >> 2] = 0x0000; - omap_ulpd_req_update(mpu, mpu->ulpd_pm_regs[0x34 >> 2], 0x0000); - mpu->ulpd_pm_regs[0x34 >> 2] = 0x0000; - mpu->ulpd_pm_regs[0x38 >> 2] = 0x0001; - mpu->ulpd_pm_regs[0x3c >> 2] = 0x2211; - mpu->ulpd_pm_regs[0x40 >> 2] = 0x0000; /* FIXME: dump a real STATUS_REQ */ - mpu->ulpd_pm_regs[0x48 >> 2] = 0x960; - mpu->ulpd_pm_regs[0x4c >> 2] = 0x08; - mpu->ulpd_pm_regs[0x50 >> 2] = 0x08; - omap_clk_setrate(omap_findclk(mpu, "dpll4"), 1, 4); - omap_clk_reparent(omap_findclk(mpu, "ck_48m"), omap_findclk(mpu, "dpll4")); -} - -static void omap_ulpd_pm_init(MemoryRegion *system_memory, - hwaddr base, - struct omap_mpu_state_s *mpu) -{ - memory_region_init_io(&mpu->ulpd_pm_iomem, NULL, &omap_ulpd_pm_ops, mpu, - "omap-ulpd-pm", 0x800); - memory_region_add_subregion(system_memory, base, &mpu->ulpd_pm_iomem); - omap_ulpd_pm_reset(mpu); -} - -/* OMAP Pin Configuration */ -static uint64_t omap_pin_cfg_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 0x00: /* FUNC_MUX_CTRL_0 */ - case 0x04: /* FUNC_MUX_CTRL_1 */ - case 0x08: /* FUNC_MUX_CTRL_2 */ - return s->func_mux_ctrl[addr >> 2]; - - case 0x0c: /* COMP_MODE_CTRL_0 */ - return s->comp_mode_ctrl[0]; - - case 0x10: /* FUNC_MUX_CTRL_3 */ - case 0x14: /* FUNC_MUX_CTRL_4 */ - case 0x18: /* FUNC_MUX_CTRL_5 */ - case 0x1c: /* FUNC_MUX_CTRL_6 */ - case 0x20: /* FUNC_MUX_CTRL_7 */ - case 0x24: /* FUNC_MUX_CTRL_8 */ - case 0x28: /* FUNC_MUX_CTRL_9 */ - case 0x2c: /* FUNC_MUX_CTRL_A */ - case 0x30: /* FUNC_MUX_CTRL_B */ - case 0x34: /* FUNC_MUX_CTRL_C */ - case 0x38: /* FUNC_MUX_CTRL_D */ - return s->func_mux_ctrl[(addr >> 2) - 1]; - - case 0x40: /* PULL_DWN_CTRL_0 */ - case 0x44: /* PULL_DWN_CTRL_1 */ - case 0x48: /* PULL_DWN_CTRL_2 */ - case 0x4c: /* PULL_DWN_CTRL_3 */ - return s->pull_dwn_ctrl[(addr & 0xf) >> 2]; - - case 0x50: /* GATE_INH_CTRL_0 */ - return s->gate_inh_ctrl[0]; - - case 0x60: /* VOLTAGE_CTRL_0 */ - return s->voltage_ctrl[0]; - - case 0x70: /* TEST_DBG_CTRL_0 */ - return s->test_dbg_ctrl[0]; - - case 0x80: /* MOD_CONF_CTRL_0 */ - return s->mod_conf_ctrl[0]; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static inline void omap_pin_funcmux0_update(struct omap_mpu_state_s *s, - uint32_t diff, uint32_t value) -{ - if (s->compat1509) { - if (diff & (1 << 9)) /* BLUETOOTH */ - omap_clk_onoff(omap_findclk(s, "bt_mclk_out"), - (~value >> 9) & 1); - if (diff & (1 << 7)) /* USB.CLKO */ - omap_clk_onoff(omap_findclk(s, "usb.clko"), - (value >> 7) & 1); - } -} - -static inline void omap_pin_funcmux1_update(struct omap_mpu_state_s *s, - uint32_t diff, uint32_t value) -{ - if (s->compat1509) { - if (diff & (1U << 31)) { - /* MCBSP3_CLK_HIZ_DI */ - omap_clk_onoff(omap_findclk(s, "mcbsp3.clkx"), (value >> 31) & 1); - } - if (diff & (1 << 1)) { - /* CLK32K */ - omap_clk_onoff(omap_findclk(s, "clk32k_out"), (~value >> 1) & 1); - } - } -} - -static inline void omap_pin_modconf1_update(struct omap_mpu_state_s *s, - uint32_t diff, uint32_t value) -{ - if (diff & (1U << 31)) { - /* CONF_MOD_UART3_CLK_MODE_R */ - omap_clk_reparent(omap_findclk(s, "uart3_ck"), - omap_findclk(s, ((value >> 31) & 1) ? - "ck_48m" : "armper_ck")); - } - if (diff & (1 << 30)) /* CONF_MOD_UART2_CLK_MODE_R */ - omap_clk_reparent(omap_findclk(s, "uart2_ck"), - omap_findclk(s, ((value >> 30) & 1) ? - "ck_48m" : "armper_ck")); - if (diff & (1 << 29)) /* CONF_MOD_UART1_CLK_MODE_R */ - omap_clk_reparent(omap_findclk(s, "uart1_ck"), - omap_findclk(s, ((value >> 29) & 1) ? - "ck_48m" : "armper_ck")); - if (diff & (1 << 23)) /* CONF_MOD_MMC_SD_CLK_REQ_R */ - omap_clk_reparent(omap_findclk(s, "mmc_ck"), - omap_findclk(s, ((value >> 23) & 1) ? - "ck_48m" : "armper_ck")); - if (diff & (1 << 12)) /* CONF_MOD_COM_MCLK_12_48_S */ - omap_clk_reparent(omap_findclk(s, "com_mclk_out"), - omap_findclk(s, ((value >> 12) & 1) ? - "ck_48m" : "armper_ck")); - if (diff & (1 << 9)) /* CONF_MOD_USB_HOST_HHC_UHO */ - omap_clk_onoff(omap_findclk(s, "usb_hhc_ck"), (value >> 9) & 1); -} - -static void omap_pin_cfg_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; - uint32_t diff; - - if (size != 4) { - omap_badwidth_write32(opaque, addr, value); - return; - } - - switch (addr) { - case 0x00: /* FUNC_MUX_CTRL_0 */ - diff = s->func_mux_ctrl[addr >> 2] ^ value; - s->func_mux_ctrl[addr >> 2] = value; - omap_pin_funcmux0_update(s, diff, value); - return; - - case 0x04: /* FUNC_MUX_CTRL_1 */ - diff = s->func_mux_ctrl[addr >> 2] ^ value; - s->func_mux_ctrl[addr >> 2] = value; - omap_pin_funcmux1_update(s, diff, value); - return; - - case 0x08: /* FUNC_MUX_CTRL_2 */ - s->func_mux_ctrl[addr >> 2] = value; - return; - - case 0x0c: /* COMP_MODE_CTRL_0 */ - s->comp_mode_ctrl[0] = value; - s->compat1509 = (value != 0x0000eaef); - omap_pin_funcmux0_update(s, ~0, s->func_mux_ctrl[0]); - omap_pin_funcmux1_update(s, ~0, s->func_mux_ctrl[1]); - return; - - case 0x10: /* FUNC_MUX_CTRL_3 */ - case 0x14: /* FUNC_MUX_CTRL_4 */ - case 0x18: /* FUNC_MUX_CTRL_5 */ - case 0x1c: /* FUNC_MUX_CTRL_6 */ - case 0x20: /* FUNC_MUX_CTRL_7 */ - case 0x24: /* FUNC_MUX_CTRL_8 */ - case 0x28: /* FUNC_MUX_CTRL_9 */ - case 0x2c: /* FUNC_MUX_CTRL_A */ - case 0x30: /* FUNC_MUX_CTRL_B */ - case 0x34: /* FUNC_MUX_CTRL_C */ - case 0x38: /* FUNC_MUX_CTRL_D */ - s->func_mux_ctrl[(addr >> 2) - 1] = value; - return; - - case 0x40: /* PULL_DWN_CTRL_0 */ - case 0x44: /* PULL_DWN_CTRL_1 */ - case 0x48: /* PULL_DWN_CTRL_2 */ - case 0x4c: /* PULL_DWN_CTRL_3 */ - s->pull_dwn_ctrl[(addr & 0xf) >> 2] = value; - return; - - case 0x50: /* GATE_INH_CTRL_0 */ - s->gate_inh_ctrl[0] = value; - return; - - case 0x60: /* VOLTAGE_CTRL_0 */ - s->voltage_ctrl[0] = value; - return; - - case 0x70: /* TEST_DBG_CTRL_0 */ - s->test_dbg_ctrl[0] = value; - return; - - case 0x80: /* MOD_CONF_CTRL_0 */ - diff = s->mod_conf_ctrl[0] ^ value; - s->mod_conf_ctrl[0] = value; - omap_pin_modconf1_update(s, diff, value); - return; - - default: - OMAP_BAD_REG(addr); - } -} - -static const MemoryRegionOps omap_pin_cfg_ops = { - .read = omap_pin_cfg_read, - .write = omap_pin_cfg_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void omap_pin_cfg_reset(struct omap_mpu_state_s *mpu) -{ - /* Start in Compatibility Mode. */ - mpu->compat1509 = 1; - omap_pin_funcmux0_update(mpu, mpu->func_mux_ctrl[0], 0); - omap_pin_funcmux1_update(mpu, mpu->func_mux_ctrl[1], 0); - omap_pin_modconf1_update(mpu, mpu->mod_conf_ctrl[0], 0); - memset(mpu->func_mux_ctrl, 0, sizeof(mpu->func_mux_ctrl)); - memset(mpu->comp_mode_ctrl, 0, sizeof(mpu->comp_mode_ctrl)); - memset(mpu->pull_dwn_ctrl, 0, sizeof(mpu->pull_dwn_ctrl)); - memset(mpu->gate_inh_ctrl, 0, sizeof(mpu->gate_inh_ctrl)); - memset(mpu->voltage_ctrl, 0, sizeof(mpu->voltage_ctrl)); - memset(mpu->test_dbg_ctrl, 0, sizeof(mpu->test_dbg_ctrl)); - memset(mpu->mod_conf_ctrl, 0, sizeof(mpu->mod_conf_ctrl)); -} - -static void omap_pin_cfg_init(MemoryRegion *system_memory, - hwaddr base, - struct omap_mpu_state_s *mpu) -{ - memory_region_init_io(&mpu->pin_cfg_iomem, NULL, &omap_pin_cfg_ops, mpu, - "omap-pin-cfg", 0x800); - memory_region_add_subregion(system_memory, base, &mpu->pin_cfg_iomem); - omap_pin_cfg_reset(mpu); -} - -/* Device Identification, Die Identification */ -static uint64_t omap_id_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 0xfffe1800: /* DIE_ID_LSB */ - return 0xc9581f0e; - case 0xfffe1804: /* DIE_ID_MSB */ - return 0xa8858bfa; - - case 0xfffe2000: /* PRODUCT_ID_LSB */ - return 0x00aaaafc; - case 0xfffe2004: /* PRODUCT_ID_MSB */ - return 0xcafeb574; - - case 0xfffed400: /* JTAG_ID_LSB */ - switch (s->mpu_model) { - case omap310: - return 0x03310315; - case omap1510: - return 0x03310115; - default: - hw_error("%s: bad mpu model\n", __FUNCTION__); - } - break; - - case 0xfffed404: /* JTAG_ID_MSB */ - switch (s->mpu_model) { - case omap310: - return 0xfb57402f; - case omap1510: - return 0xfb47002f; - default: - hw_error("%s: bad mpu model\n", __FUNCTION__); - } - break; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_id_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - if (size != 4) { - omap_badwidth_write32(opaque, addr, value); - return; - } - - OMAP_BAD_REG(addr); -} - -static const MemoryRegionOps omap_id_ops = { - .read = omap_id_read, - .write = omap_id_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void omap_id_init(MemoryRegion *memory, struct omap_mpu_state_s *mpu) -{ - memory_region_init_io(&mpu->id_iomem, NULL, &omap_id_ops, mpu, - "omap-id", 0x100000000ULL); - memory_region_init_alias(&mpu->id_iomem_e18, NULL, "omap-id-e18", &mpu->id_iomem, - 0xfffe1800, 0x800); - memory_region_add_subregion(memory, 0xfffe1800, &mpu->id_iomem_e18); - memory_region_init_alias(&mpu->id_iomem_ed4, NULL, "omap-id-ed4", &mpu->id_iomem, - 0xfffed400, 0x100); - memory_region_add_subregion(memory, 0xfffed400, &mpu->id_iomem_ed4); - if (!cpu_is_omap15xx(mpu)) { - memory_region_init_alias(&mpu->id_iomem_ed4, NULL, "omap-id-e20", - &mpu->id_iomem, 0xfffe2000, 0x800); - memory_region_add_subregion(memory, 0xfffe2000, &mpu->id_iomem_e20); - } -} - -/* MPUI Control (Dummy) */ -static uint64_t omap_mpui_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 0x00: /* CTRL */ - return s->mpui_ctrl; - case 0x04: /* DEBUG_ADDR */ - return 0x01ffffff; - case 0x08: /* DEBUG_DATA */ - return 0xffffffff; - case 0x0c: /* DEBUG_FLAG */ - return 0x00000800; - case 0x10: /* STATUS */ - return 0x00000000; - - /* Not in OMAP310 */ - case 0x14: /* DSP_STATUS */ - case 0x18: /* DSP_BOOT_CONFIG */ - return 0x00000000; - case 0x1c: /* DSP_MPUI_CONFIG */ - return 0x0000ffff; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_mpui_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; - - if (size != 4) { - omap_badwidth_write32(opaque, addr, value); - return; - } - - switch (addr) { - case 0x00: /* CTRL */ - s->mpui_ctrl = value & 0x007fffff; - break; - - case 0x04: /* DEBUG_ADDR */ - case 0x08: /* DEBUG_DATA */ - case 0x0c: /* DEBUG_FLAG */ - case 0x10: /* STATUS */ - /* Not in OMAP310 */ - case 0x14: /* DSP_STATUS */ - OMAP_RO_REG(addr); - break; - case 0x18: /* DSP_BOOT_CONFIG */ - case 0x1c: /* DSP_MPUI_CONFIG */ - break; - - default: - OMAP_BAD_REG(addr); - } -} - -static const MemoryRegionOps omap_mpui_ops = { - .read = omap_mpui_read, - .write = omap_mpui_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void omap_mpui_reset(struct omap_mpu_state_s *s) -{ - s->mpui_ctrl = 0x0003ff1b; -} - -static void omap_mpui_init(MemoryRegion *memory, hwaddr base, - struct omap_mpu_state_s *mpu) -{ - memory_region_init_io(&mpu->mpui_iomem, NULL, &omap_mpui_ops, mpu, - "omap-mpui", 0x100); - memory_region_add_subregion(memory, base, &mpu->mpui_iomem); - - omap_mpui_reset(mpu); -} - -/* TIPB Bridges */ -struct omap_tipb_bridge_s { - qemu_irq abort; - MemoryRegion iomem; - - int width_intr; - uint16_t control; - uint16_t alloc; - uint16_t buffer; - uint16_t enh_control; -}; - -static uint64_t omap_tipb_bridge_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct omap_tipb_bridge_s *s = (struct omap_tipb_bridge_s *) opaque; - - if (size < 2) { - return omap_badwidth_read16(opaque, addr); - } - - switch (addr) { - case 0x00: /* TIPB_CNTL */ - return s->control; - case 0x04: /* TIPB_BUS_ALLOC */ - return s->alloc; - case 0x08: /* MPU_TIPB_CNTL */ - return s->buffer; - case 0x0c: /* ENHANCED_TIPB_CNTL */ - return s->enh_control; - case 0x10: /* ADDRESS_DBG */ - case 0x14: /* DATA_DEBUG_LOW */ - case 0x18: /* DATA_DEBUG_HIGH */ - return 0xffff; - case 0x1c: /* DEBUG_CNTR_SIG */ - return 0x00f8; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_tipb_bridge_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct omap_tipb_bridge_s *s = (struct omap_tipb_bridge_s *) opaque; - - if (size < 2) { - omap_badwidth_write16(opaque, addr, value); - return; - } - - switch (addr) { - case 0x00: /* TIPB_CNTL */ - s->control = value & 0xffff; - break; - - case 0x04: /* TIPB_BUS_ALLOC */ - s->alloc = value & 0x003f; - break; - - case 0x08: /* MPU_TIPB_CNTL */ - s->buffer = value & 0x0003; - break; - - case 0x0c: /* ENHANCED_TIPB_CNTL */ - s->width_intr = !(value & 2); - s->enh_control = value & 0x000f; - break; - - case 0x10: /* ADDRESS_DBG */ - case 0x14: /* DATA_DEBUG_LOW */ - case 0x18: /* DATA_DEBUG_HIGH */ - case 0x1c: /* DEBUG_CNTR_SIG */ - OMAP_RO_REG(addr); - break; - - default: - OMAP_BAD_REG(addr); - } -} - -static const MemoryRegionOps omap_tipb_bridge_ops = { - .read = omap_tipb_bridge_read, - .write = omap_tipb_bridge_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void omap_tipb_bridge_reset(struct omap_tipb_bridge_s *s) -{ - s->control = 0xffff; - s->alloc = 0x0009; - s->buffer = 0x0000; - s->enh_control = 0x000f; -} - -static struct omap_tipb_bridge_s *omap_tipb_bridge_init( - MemoryRegion *memory, hwaddr base, - qemu_irq abort_irq, omap_clk clk) -{ - struct omap_tipb_bridge_s *s = g_new0(struct omap_tipb_bridge_s, 1); - - s->abort = abort_irq; - omap_tipb_bridge_reset(s); - - memory_region_init_io(&s->iomem, NULL, &omap_tipb_bridge_ops, s, - "omap-tipb-bridge", 0x100); - memory_region_add_subregion(memory, base, &s->iomem); - - return s; -} - -/* Dummy Traffic Controller's Memory Interface */ -static uint64_t omap_tcmi_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; - uint32_t ret; - - if (size != 4) { - return omap_badwidth_read32(opaque, addr); - } - - switch (addr) { - case 0x00: /* IMIF_PRIO */ - case 0x04: /* EMIFS_PRIO */ - case 0x08: /* EMIFF_PRIO */ - case 0x0c: /* EMIFS_CONFIG */ - case 0x10: /* EMIFS_CS0_CONFIG */ - case 0x14: /* EMIFS_CS1_CONFIG */ - case 0x18: /* EMIFS_CS2_CONFIG */ - case 0x1c: /* EMIFS_CS3_CONFIG */ - case 0x24: /* EMIFF_MRS */ - case 0x28: /* TIMEOUT1 */ - case 0x2c: /* TIMEOUT2 */ - case 0x30: /* TIMEOUT3 */ - case 0x3c: /* EMIFF_SDRAM_CONFIG_2 */ - case 0x40: /* EMIFS_CFG_DYN_WAIT */ - return s->tcmi_regs[addr >> 2]; - - case 0x20: /* EMIFF_SDRAM_CONFIG */ - ret = s->tcmi_regs[addr >> 2]; - s->tcmi_regs[addr >> 2] &= ~1; /* XXX: Clear SLRF on SDRAM access */ - /* XXX: We can try using the VGA_DIRTY flag for this */ - return ret; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_tcmi_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; - - if (size != 4) { - omap_badwidth_write32(opaque, addr, value); - return; - } - - switch (addr) { - case 0x00: /* IMIF_PRIO */ - case 0x04: /* EMIFS_PRIO */ - case 0x08: /* EMIFF_PRIO */ - case 0x10: /* EMIFS_CS0_CONFIG */ - case 0x14: /* EMIFS_CS1_CONFIG */ - case 0x18: /* EMIFS_CS2_CONFIG */ - case 0x1c: /* EMIFS_CS3_CONFIG */ - case 0x20: /* EMIFF_SDRAM_CONFIG */ - case 0x24: /* EMIFF_MRS */ - case 0x28: /* TIMEOUT1 */ - case 0x2c: /* TIMEOUT2 */ - case 0x30: /* TIMEOUT3 */ - case 0x3c: /* EMIFF_SDRAM_CONFIG_2 */ - case 0x40: /* EMIFS_CFG_DYN_WAIT */ - s->tcmi_regs[addr >> 2] = value; - break; - case 0x0c: /* EMIFS_CONFIG */ - s->tcmi_regs[addr >> 2] = (value & 0xf) | (1 << 4); - break; - - default: - OMAP_BAD_REG(addr); - } -} - -static const MemoryRegionOps omap_tcmi_ops = { - .read = omap_tcmi_read, - .write = omap_tcmi_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void omap_tcmi_reset(struct omap_mpu_state_s *mpu) -{ - mpu->tcmi_regs[0x00 >> 2] = 0x00000000; - mpu->tcmi_regs[0x04 >> 2] = 0x00000000; - mpu->tcmi_regs[0x08 >> 2] = 0x00000000; - mpu->tcmi_regs[0x0c >> 2] = 0x00000010; - mpu->tcmi_regs[0x10 >> 2] = 0x0010fffb; - mpu->tcmi_regs[0x14 >> 2] = 0x0010fffb; - mpu->tcmi_regs[0x18 >> 2] = 0x0010fffb; - mpu->tcmi_regs[0x1c >> 2] = 0x0010fffb; - mpu->tcmi_regs[0x20 >> 2] = 0x00618800; - mpu->tcmi_regs[0x24 >> 2] = 0x00000037; - mpu->tcmi_regs[0x28 >> 2] = 0x00000000; - mpu->tcmi_regs[0x2c >> 2] = 0x00000000; - mpu->tcmi_regs[0x30 >> 2] = 0x00000000; - mpu->tcmi_regs[0x3c >> 2] = 0x00000003; - mpu->tcmi_regs[0x40 >> 2] = 0x00000000; -} - -static void omap_tcmi_init(MemoryRegion *memory, hwaddr base, - struct omap_mpu_state_s *mpu) -{ - memory_region_init_io(&mpu->tcmi_iomem, NULL, &omap_tcmi_ops, mpu, - "omap-tcmi", 0x100); - memory_region_add_subregion(memory, base, &mpu->tcmi_iomem); - omap_tcmi_reset(mpu); -} - -/* Digital phase-locked loops control */ -struct dpll_ctl_s { - MemoryRegion iomem; - uint16_t mode; - omap_clk dpll; -}; - -static uint64_t omap_dpll_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct dpll_ctl_s *s = (struct dpll_ctl_s *) opaque; - - if (size != 2) { - return omap_badwidth_read16(opaque, addr); - } - - if (addr == 0x00) /* CTL_REG */ - return s->mode; - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_dpll_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct dpll_ctl_s *s = (struct dpll_ctl_s *) opaque; - uint16_t diff; - static const int bypass_div[4] = { 1, 2, 4, 4 }; - int div, mult; - - if (size != 2) { - omap_badwidth_write16(opaque, addr, value); - return; - } - - if (addr == 0x00) { /* CTL_REG */ - /* See omap_ulpd_pm_write() too */ - diff = s->mode & value; - s->mode = value & 0x2fff; - if (diff & (0x3ff << 2)) { - if (value & (1 << 4)) { /* PLL_ENABLE */ - div = ((value >> 5) & 3) + 1; /* PLL_DIV */ - mult = MIN((value >> 7) & 0x1f, 1); /* PLL_MULT */ - } else { - div = bypass_div[((value >> 2) & 3)]; /* BYPASS_DIV */ - mult = 1; - } - omap_clk_setrate(s->dpll, div, mult); - } - - /* Enter the desired mode. */ - s->mode = (s->mode & 0xfffe) | ((s->mode >> 4) & 1); - - /* Act as if the lock is restored. */ - s->mode |= 2; - } else { - OMAP_BAD_REG(addr); - } -} - -static const MemoryRegionOps omap_dpll_ops = { - .read = omap_dpll_read, - .write = omap_dpll_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void omap_dpll_reset(struct dpll_ctl_s *s) -{ - s->mode = 0x2002; - omap_clk_setrate(s->dpll, 1, 1); -} - -static struct dpll_ctl_s *omap_dpll_init(MemoryRegion *memory, - hwaddr base, omap_clk clk) -{ - struct dpll_ctl_s *s = g_malloc0(sizeof(*s)); - memory_region_init_io(&s->iomem, NULL, &omap_dpll_ops, s, "omap-dpll", 0x100); - - s->dpll = clk; - omap_dpll_reset(s); - - memory_region_add_subregion(memory, base, &s->iomem); - return s; -} - -/* MPU Clock/Reset/Power Mode Control */ -static uint64_t omap_clkm_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; - - if (size != 2) { - return omap_badwidth_read16(opaque, addr); - } - - switch (addr) { - case 0x00: /* ARM_CKCTL */ - return s->clkm.arm_ckctl; - - case 0x04: /* ARM_IDLECT1 */ - return s->clkm.arm_idlect1; - - case 0x08: /* ARM_IDLECT2 */ - return s->clkm.arm_idlect2; - - case 0x0c: /* ARM_EWUPCT */ - return s->clkm.arm_ewupct; - - case 0x10: /* ARM_RSTCT1 */ - return s->clkm.arm_rstct1; - - case 0x14: /* ARM_RSTCT2 */ - return s->clkm.arm_rstct2; - - case 0x18: /* ARM_SYSST */ - return (s->clkm.clocking_scheme << 11) | s->clkm.cold_start; - - case 0x1c: /* ARM_CKOUT1 */ - return s->clkm.arm_ckout1; - - case 0x20: /* ARM_CKOUT2 */ - break; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static inline void omap_clkm_ckctl_update(struct omap_mpu_state_s *s, - uint16_t diff, uint16_t value) -{ - omap_clk clk; - - if (diff & (1 << 14)) { /* ARM_INTHCK_SEL */ - if (value & (1 << 14)) - /* Reserved */; - else { - clk = omap_findclk(s, "arminth_ck"); - omap_clk_reparent(clk, omap_findclk(s, "tc_ck")); - } - } - if (diff & (1 << 12)) { /* ARM_TIMXO */ - clk = omap_findclk(s, "armtim_ck"); - if (value & (1 << 12)) - omap_clk_reparent(clk, omap_findclk(s, "clkin")); - else - omap_clk_reparent(clk, omap_findclk(s, "ck_gen1")); - } - /* XXX: en_dspck */ - if (diff & (3 << 10)) { /* DSPMMUDIV */ - clk = omap_findclk(s, "dspmmu_ck"); - omap_clk_setrate(clk, 1 << ((value >> 10) & 3), 1); - } - if (diff & (3 << 8)) { /* TCDIV */ - clk = omap_findclk(s, "tc_ck"); - omap_clk_setrate(clk, 1 << ((value >> 8) & 3), 1); - } - if (diff & (3 << 6)) { /* DSPDIV */ - clk = omap_findclk(s, "dsp_ck"); - omap_clk_setrate(clk, 1 << ((value >> 6) & 3), 1); - } - if (diff & (3 << 4)) { /* ARMDIV */ - clk = omap_findclk(s, "arm_ck"); - omap_clk_setrate(clk, 1 << ((value >> 4) & 3), 1); - } - if (diff & (3 << 2)) { /* LCDDIV */ - clk = omap_findclk(s, "lcd_ck"); - omap_clk_setrate(clk, 1 << ((value >> 2) & 3), 1); - } - if (diff & (3 << 0)) { /* PERDIV */ - clk = omap_findclk(s, "armper_ck"); - omap_clk_setrate(clk, 1 << ((value >> 0) & 3), 1); - } -} - -static inline void omap_clkm_idlect1_update(struct omap_mpu_state_s *s, - uint16_t diff, uint16_t value) -{ - omap_clk clk; - - if (value & (1 << 11)) { /* SETARM_IDLE */ - cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_HALT); - } - if (!(value & (1 << 10))) /* WKUP_MODE */ - qemu_system_shutdown_request(); /* XXX: disable wakeup from IRQ */ - -#define SET_CANIDLE(clock, bit) \ - if (diff & (1 << bit)) { \ - clk = omap_findclk(s, clock); \ - omap_clk_canidle(clk, (value >> bit) & 1); \ - } - SET_CANIDLE("mpuwd_ck", 0) /* IDLWDT_ARM */ - SET_CANIDLE("armxor_ck", 1) /* IDLXORP_ARM */ - SET_CANIDLE("mpuper_ck", 2) /* IDLPER_ARM */ - SET_CANIDLE("lcd_ck", 3) /* IDLLCD_ARM */ - SET_CANIDLE("lb_ck", 4) /* IDLLB_ARM */ - SET_CANIDLE("hsab_ck", 5) /* IDLHSAB_ARM */ - SET_CANIDLE("tipb_ck", 6) /* IDLIF_ARM */ - SET_CANIDLE("dma_ck", 6) /* IDLIF_ARM */ - SET_CANIDLE("tc_ck", 6) /* IDLIF_ARM */ - SET_CANIDLE("dpll1", 7) /* IDLDPLL_ARM */ - SET_CANIDLE("dpll2", 7) /* IDLDPLL_ARM */ - SET_CANIDLE("dpll3", 7) /* IDLDPLL_ARM */ - SET_CANIDLE("mpui_ck", 8) /* IDLAPI_ARM */ - SET_CANIDLE("armtim_ck", 9) /* IDLTIM_ARM */ -} - -static inline void omap_clkm_idlect2_update(struct omap_mpu_state_s *s, - uint16_t diff, uint16_t value) -{ - omap_clk clk; - -#define SET_ONOFF(clock, bit) \ - if (diff & (1 << bit)) { \ - clk = omap_findclk(s, clock); \ - omap_clk_onoff(clk, (value >> bit) & 1); \ - } - SET_ONOFF("mpuwd_ck", 0) /* EN_WDTCK */ - SET_ONOFF("armxor_ck", 1) /* EN_XORPCK */ - SET_ONOFF("mpuper_ck", 2) /* EN_PERCK */ - SET_ONOFF("lcd_ck", 3) /* EN_LCDCK */ - SET_ONOFF("lb_ck", 4) /* EN_LBCK */ - SET_ONOFF("hsab_ck", 5) /* EN_HSABCK */ - SET_ONOFF("mpui_ck", 6) /* EN_APICK */ - SET_ONOFF("armtim_ck", 7) /* EN_TIMCK */ - SET_CANIDLE("dma_ck", 8) /* DMACK_REQ */ - SET_ONOFF("arm_gpio_ck", 9) /* EN_GPIOCK */ - SET_ONOFF("lbfree_ck", 10) /* EN_LBFREECK */ -} - -static inline void omap_clkm_ckout1_update(struct omap_mpu_state_s *s, - uint16_t diff, uint16_t value) -{ - omap_clk clk; - - if (diff & (3 << 4)) { /* TCLKOUT */ - clk = omap_findclk(s, "tclk_out"); - switch ((value >> 4) & 3) { - case 1: - omap_clk_reparent(clk, omap_findclk(s, "ck_gen3")); - omap_clk_onoff(clk, 1); - break; - case 2: - omap_clk_reparent(clk, omap_findclk(s, "tc_ck")); - omap_clk_onoff(clk, 1); - break; - default: - omap_clk_onoff(clk, 0); - } - } - if (diff & (3 << 2)) { /* DCLKOUT */ - clk = omap_findclk(s, "dclk_out"); - switch ((value >> 2) & 3) { - case 0: - omap_clk_reparent(clk, omap_findclk(s, "dspmmu_ck")); - break; - case 1: - omap_clk_reparent(clk, omap_findclk(s, "ck_gen2")); - break; - case 2: - omap_clk_reparent(clk, omap_findclk(s, "dsp_ck")); - break; - case 3: - omap_clk_reparent(clk, omap_findclk(s, "ck_ref14")); - break; - } - } - if (diff & (3 << 0)) { /* ACLKOUT */ - clk = omap_findclk(s, "aclk_out"); - switch ((value >> 0) & 3) { - case 1: - omap_clk_reparent(clk, omap_findclk(s, "ck_gen1")); - omap_clk_onoff(clk, 1); - break; - case 2: - omap_clk_reparent(clk, omap_findclk(s, "arm_ck")); - omap_clk_onoff(clk, 1); - break; - case 3: - omap_clk_reparent(clk, omap_findclk(s, "ck_ref14")); - omap_clk_onoff(clk, 1); - break; - default: - omap_clk_onoff(clk, 0); - } - } -} - -static void omap_clkm_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; - uint16_t diff; - omap_clk clk; - static const char *clkschemename[8] = { - "fully synchronous", "fully asynchronous", "synchronous scalable", - "mix mode 1", "mix mode 2", "bypass mode", "mix mode 3", "mix mode 4", - }; - - if (size != 2) { - omap_badwidth_write16(opaque, addr, value); - return; - } - - switch (addr) { - case 0x00: /* ARM_CKCTL */ - diff = s->clkm.arm_ckctl ^ value; - s->clkm.arm_ckctl = value & 0x7fff; - omap_clkm_ckctl_update(s, diff, value); - return; - - case 0x04: /* ARM_IDLECT1 */ - diff = s->clkm.arm_idlect1 ^ value; - s->clkm.arm_idlect1 = value & 0x0fff; - omap_clkm_idlect1_update(s, diff, value); - return; - - case 0x08: /* ARM_IDLECT2 */ - diff = s->clkm.arm_idlect2 ^ value; - s->clkm.arm_idlect2 = value & 0x07ff; - omap_clkm_idlect2_update(s, diff, value); - return; - - case 0x0c: /* ARM_EWUPCT */ - s->clkm.arm_ewupct = value & 0x003f; - return; - - case 0x10: /* ARM_RSTCT1 */ - diff = s->clkm.arm_rstct1 ^ value; - s->clkm.arm_rstct1 = value & 0x0007; - if (value & 9) { - qemu_system_reset_request(); - s->clkm.cold_start = 0xa; - } - if (diff & ~value & 4) { /* DSP_RST */ - omap_mpui_reset(s); - omap_tipb_bridge_reset(s->private_tipb); - omap_tipb_bridge_reset(s->public_tipb); - } - if (diff & 2) { /* DSP_EN */ - clk = omap_findclk(s, "dsp_ck"); - omap_clk_canidle(clk, (~value >> 1) & 1); - } - return; - - case 0x14: /* ARM_RSTCT2 */ - s->clkm.arm_rstct2 = value & 0x0001; - return; - - case 0x18: /* ARM_SYSST */ - if ((s->clkm.clocking_scheme ^ (value >> 11)) & 7) { - s->clkm.clocking_scheme = (value >> 11) & 7; - printf("%s: clocking scheme set to %s\n", __FUNCTION__, - clkschemename[s->clkm.clocking_scheme]); - } - s->clkm.cold_start &= value & 0x3f; - return; - - case 0x1c: /* ARM_CKOUT1 */ - diff = s->clkm.arm_ckout1 ^ value; - s->clkm.arm_ckout1 = value & 0x003f; - omap_clkm_ckout1_update(s, diff, value); - return; - - case 0x20: /* ARM_CKOUT2 */ - default: - OMAP_BAD_REG(addr); - } -} - -static const MemoryRegionOps omap_clkm_ops = { - .read = omap_clkm_read, - .write = omap_clkm_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static uint64_t omap_clkdsp_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; - CPUState *cpu = CPU(s->cpu); - - if (size != 2) { - return omap_badwidth_read16(opaque, addr); - } - - switch (addr) { - case 0x04: /* DSP_IDLECT1 */ - return s->clkm.dsp_idlect1; - - case 0x08: /* DSP_IDLECT2 */ - return s->clkm.dsp_idlect2; - - case 0x14: /* DSP_RSTCT2 */ - return s->clkm.dsp_rstct2; - - case 0x18: /* DSP_SYSST */ - cpu = CPU(s->cpu); - return (s->clkm.clocking_scheme << 11) | s->clkm.cold_start | - (cpu->halted << 6); /* Quite useless... */ - } - - OMAP_BAD_REG(addr); - return 0; -} - -static inline void omap_clkdsp_idlect1_update(struct omap_mpu_state_s *s, - uint16_t diff, uint16_t value) -{ - omap_clk clk; - - SET_CANIDLE("dspxor_ck", 1); /* IDLXORP_DSP */ -} - -static inline void omap_clkdsp_idlect2_update(struct omap_mpu_state_s *s, - uint16_t diff, uint16_t value) -{ - omap_clk clk; - - SET_ONOFF("dspxor_ck", 1); /* EN_XORPCK */ -} - -static void omap_clkdsp_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; - uint16_t diff; - - if (size != 2) { - omap_badwidth_write16(opaque, addr, value); - return; - } - - switch (addr) { - case 0x04: /* DSP_IDLECT1 */ - diff = s->clkm.dsp_idlect1 ^ value; - s->clkm.dsp_idlect1 = value & 0x01f7; - omap_clkdsp_idlect1_update(s, diff, value); - break; - - case 0x08: /* DSP_IDLECT2 */ - s->clkm.dsp_idlect2 = value & 0x0037; - diff = s->clkm.dsp_idlect1 ^ value; - omap_clkdsp_idlect2_update(s, diff, value); - break; - - case 0x14: /* DSP_RSTCT2 */ - s->clkm.dsp_rstct2 = value & 0x0001; - break; - - case 0x18: /* DSP_SYSST */ - s->clkm.cold_start &= value & 0x3f; - break; - - default: - OMAP_BAD_REG(addr); - } -} - -static const MemoryRegionOps omap_clkdsp_ops = { - .read = omap_clkdsp_read, - .write = omap_clkdsp_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void omap_clkm_reset(struct omap_mpu_state_s *s) -{ - if (s->wdt && s->wdt->reset) - s->clkm.cold_start = 0x6; - s->clkm.clocking_scheme = 0; - omap_clkm_ckctl_update(s, ~0, 0x3000); - s->clkm.arm_ckctl = 0x3000; - omap_clkm_idlect1_update(s, s->clkm.arm_idlect1 ^ 0x0400, 0x0400); - s->clkm.arm_idlect1 = 0x0400; - omap_clkm_idlect2_update(s, s->clkm.arm_idlect2 ^ 0x0100, 0x0100); - s->clkm.arm_idlect2 = 0x0100; - s->clkm.arm_ewupct = 0x003f; - s->clkm.arm_rstct1 = 0x0000; - s->clkm.arm_rstct2 = 0x0000; - s->clkm.arm_ckout1 = 0x0015; - s->clkm.dpll1_mode = 0x2002; - omap_clkdsp_idlect1_update(s, s->clkm.dsp_idlect1 ^ 0x0040, 0x0040); - s->clkm.dsp_idlect1 = 0x0040; - omap_clkdsp_idlect2_update(s, ~0, 0x0000); - s->clkm.dsp_idlect2 = 0x0000; - s->clkm.dsp_rstct2 = 0x0000; -} - -static void omap_clkm_init(MemoryRegion *memory, hwaddr mpu_base, - hwaddr dsp_base, struct omap_mpu_state_s *s) -{ - memory_region_init_io(&s->clkm_iomem, NULL, &omap_clkm_ops, s, - "omap-clkm", 0x100); - memory_region_init_io(&s->clkdsp_iomem, NULL, &omap_clkdsp_ops, s, - "omap-clkdsp", 0x1000); - - s->clkm.arm_idlect1 = 0x03ff; - s->clkm.arm_idlect2 = 0x0100; - s->clkm.dsp_idlect1 = 0x0002; - omap_clkm_reset(s); - s->clkm.cold_start = 0x3a; - - memory_region_add_subregion(memory, mpu_base, &s->clkm_iomem); - memory_region_add_subregion(memory, dsp_base, &s->clkdsp_iomem); -} - -/* MPU I/O */ -struct omap_mpuio_s { - qemu_irq irq; - qemu_irq kbd_irq; - qemu_irq *in; - qemu_irq handler[16]; - qemu_irq wakeup; - MemoryRegion iomem; - - uint16_t inputs; - uint16_t outputs; - uint16_t dir; - uint16_t edge; - uint16_t mask; - uint16_t ints; - - uint16_t debounce; - uint16_t latch; - uint8_t event; - - uint8_t buttons[5]; - uint8_t row_latch; - uint8_t cols; - int kbd_mask; - int clk; -}; - -static void omap_mpuio_set(void *opaque, int line, int level) -{ - struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque; - uint16_t prev = s->inputs; - - if (level) - s->inputs |= 1 << line; - else - s->inputs &= ~(1 << line); - - if (((1 << line) & s->dir & ~s->mask) && s->clk) { - if ((s->edge & s->inputs & ~prev) | (~s->edge & ~s->inputs & prev)) { - s->ints |= 1 << line; - qemu_irq_raise(s->irq); - /* TODO: wakeup */ - } - if ((s->event & (1 << 0)) && /* SET_GPIO_EVENT_MODE */ - (s->event >> 1) == line) /* PIN_SELECT */ - s->latch = s->inputs; - } -} - -static void omap_mpuio_kbd_update(struct omap_mpuio_s *s) -{ - int i; - uint8_t *row, rows = 0, cols = ~s->cols; - - for (row = s->buttons + 4, i = 1 << 4; i; row --, i >>= 1) - if (*row & cols) - rows |= i; - - qemu_set_irq(s->kbd_irq, rows && !s->kbd_mask && s->clk); - s->row_latch = ~rows; -} - -static uint64_t omap_mpuio_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - uint16_t ret; - - if (size != 2) { - return omap_badwidth_read16(opaque, addr); - } - - switch (offset) { - case 0x00: /* INPUT_LATCH */ - return s->inputs; - - case 0x04: /* OUTPUT_REG */ - return s->outputs; - - case 0x08: /* IO_CNTL */ - return s->dir; - - case 0x10: /* KBR_LATCH */ - return s->row_latch; - - case 0x14: /* KBC_REG */ - return s->cols; - - case 0x18: /* GPIO_EVENT_MODE_REG */ - return s->event; - - case 0x1c: /* GPIO_INT_EDGE_REG */ - return s->edge; - - case 0x20: /* KBD_INT */ - return (~s->row_latch & 0x1f) && !s->kbd_mask; - - case 0x24: /* GPIO_INT */ - ret = s->ints; - s->ints &= s->mask; - if (ret) - qemu_irq_lower(s->irq); - return ret; - - case 0x28: /* KBD_MASKIT */ - return s->kbd_mask; - - case 0x2c: /* GPIO_MASKIT */ - return s->mask; - - case 0x30: /* GPIO_DEBOUNCING_REG */ - return s->debounce; - - case 0x34: /* GPIO_LATCH_REG */ - return s->latch; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_mpuio_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - uint16_t diff; - int ln; - - if (size != 2) { - omap_badwidth_write16(opaque, addr, value); - return; - } - - switch (offset) { - case 0x04: /* OUTPUT_REG */ - diff = (s->outputs ^ value) & ~s->dir; - s->outputs = value; - while ((ln = ctz32(diff)) != 32) { - if (s->handler[ln]) - qemu_set_irq(s->handler[ln], (value >> ln) & 1); - diff &= ~(1 << ln); - } - break; - - case 0x08: /* IO_CNTL */ - diff = s->outputs & (s->dir ^ value); - s->dir = value; - - value = s->outputs & ~s->dir; - while ((ln = ctz32(diff)) != 32) { - if (s->handler[ln]) - qemu_set_irq(s->handler[ln], (value >> ln) & 1); - diff &= ~(1 << ln); - } - break; - - case 0x14: /* KBC_REG */ - s->cols = value; - omap_mpuio_kbd_update(s); - break; - - case 0x18: /* GPIO_EVENT_MODE_REG */ - s->event = value & 0x1f; - break; - - case 0x1c: /* GPIO_INT_EDGE_REG */ - s->edge = value; - break; - - case 0x28: /* KBD_MASKIT */ - s->kbd_mask = value & 1; - omap_mpuio_kbd_update(s); - break; - - case 0x2c: /* GPIO_MASKIT */ - s->mask = value; - break; - - case 0x30: /* GPIO_DEBOUNCING_REG */ - s->debounce = value & 0x1ff; - break; - - case 0x00: /* INPUT_LATCH */ - case 0x10: /* KBR_LATCH */ - case 0x20: /* KBD_INT */ - case 0x24: /* GPIO_INT */ - case 0x34: /* GPIO_LATCH_REG */ - OMAP_RO_REG(addr); - return; - - default: - OMAP_BAD_REG(addr); - return; - } -} - -static const MemoryRegionOps omap_mpuio_ops = { - .read = omap_mpuio_read, - .write = omap_mpuio_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void omap_mpuio_reset(struct omap_mpuio_s *s) -{ - s->inputs = 0; - s->outputs = 0; - s->dir = ~0; - s->event = 0; - s->edge = 0; - s->kbd_mask = 0; - s->mask = 0; - s->debounce = 0; - s->latch = 0; - s->ints = 0; - s->row_latch = 0x1f; - s->clk = 1; -} - -static void omap_mpuio_onoff(void *opaque, int line, int on) -{ - struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque; - - s->clk = on; - if (on) - omap_mpuio_kbd_update(s); -} - -static struct omap_mpuio_s *omap_mpuio_init(MemoryRegion *memory, - hwaddr base, - qemu_irq kbd_int, qemu_irq gpio_int, qemu_irq wakeup, - omap_clk clk) -{ - struct omap_mpuio_s *s = g_new0(struct omap_mpuio_s, 1); - - s->irq = gpio_int; - s->kbd_irq = kbd_int; - s->wakeup = wakeup; - s->in = qemu_allocate_irqs(omap_mpuio_set, s, 16); - omap_mpuio_reset(s); - - memory_region_init_io(&s->iomem, NULL, &omap_mpuio_ops, s, - "omap-mpuio", 0x800); - memory_region_add_subregion(memory, base, &s->iomem); - - omap_clk_adduser(clk, qemu_allocate_irq(omap_mpuio_onoff, s, 0)); - - return s; -} - -qemu_irq *omap_mpuio_in_get(struct omap_mpuio_s *s) -{ - return s->in; -} - -void omap_mpuio_out_set(struct omap_mpuio_s *s, int line, qemu_irq handler) -{ - if (line >= 16 || line < 0) - hw_error("%s: No GPIO line %i\n", __FUNCTION__, line); - s->handler[line] = handler; -} - -void omap_mpuio_key(struct omap_mpuio_s *s, int row, int col, int down) -{ - if (row >= 5 || row < 0) - hw_error("%s: No key %i-%i\n", __FUNCTION__, col, row); - - if (down) - s->buttons[row] |= 1 << col; - else - s->buttons[row] &= ~(1 << col); - - omap_mpuio_kbd_update(s); -} - -/* MicroWire Interface */ -struct omap_uwire_s { - MemoryRegion iomem; - qemu_irq txirq; - qemu_irq rxirq; - qemu_irq txdrq; - - uint16_t txbuf; - uint16_t rxbuf; - uint16_t control; - uint16_t setup[5]; - - uWireSlave *chip[4]; -}; - -static void omap_uwire_transfer_start(struct omap_uwire_s *s) -{ - int chipselect = (s->control >> 10) & 3; /* INDEX */ - uWireSlave *slave = s->chip[chipselect]; - - if ((s->control >> 5) & 0x1f) { /* NB_BITS_WR */ - if (s->control & (1 << 12)) /* CS_CMD */ - if (slave && slave->send) - slave->send(slave->opaque, - s->txbuf >> (16 - ((s->control >> 5) & 0x1f))); - s->control &= ~(1 << 14); /* CSRB */ - /* TODO: depending on s->setup[4] bits [1:0] assert an IRQ or - * a DRQ. When is the level IRQ supposed to be reset? */ - } - - if ((s->control >> 0) & 0x1f) { /* NB_BITS_RD */ - if (s->control & (1 << 12)) /* CS_CMD */ - if (slave && slave->receive) - s->rxbuf = slave->receive(slave->opaque); - s->control |= 1 << 15; /* RDRB */ - /* TODO: depending on s->setup[4] bits [1:0] assert an IRQ or - * a DRQ. When is the level IRQ supposed to be reset? */ - } -} - -static uint64_t omap_uwire_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct omap_uwire_s *s = (struct omap_uwire_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - - if (size != 2) { - return omap_badwidth_read16(opaque, addr); - } - - switch (offset) { - case 0x00: /* RDR */ - s->control &= ~(1 << 15); /* RDRB */ - return s->rxbuf; - - case 0x04: /* CSR */ - return s->control; - - case 0x08: /* SR1 */ - return s->setup[0]; - case 0x0c: /* SR2 */ - return s->setup[1]; - case 0x10: /* SR3 */ - return s->setup[2]; - case 0x14: /* SR4 */ - return s->setup[3]; - case 0x18: /* SR5 */ - return s->setup[4]; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_uwire_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct omap_uwire_s *s = (struct omap_uwire_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - - if (size != 2) { - omap_badwidth_write16(opaque, addr, value); - return; - } - - switch (offset) { - case 0x00: /* TDR */ - s->txbuf = value; /* TD */ - if ((s->setup[4] & (1 << 2)) && /* AUTO_TX_EN */ - ((s->setup[4] & (1 << 3)) || /* CS_TOGGLE_TX_EN */ - (s->control & (1 << 12)))) { /* CS_CMD */ - s->control |= 1 << 14; /* CSRB */ - omap_uwire_transfer_start(s); - } - break; - - case 0x04: /* CSR */ - s->control = value & 0x1fff; - if (value & (1 << 13)) /* START */ - omap_uwire_transfer_start(s); - break; - - case 0x08: /* SR1 */ - s->setup[0] = value & 0x003f; - break; - - case 0x0c: /* SR2 */ - s->setup[1] = value & 0x0fc0; - break; - - case 0x10: /* SR3 */ - s->setup[2] = value & 0x0003; - break; - - case 0x14: /* SR4 */ - s->setup[3] = value & 0x0001; - break; - - case 0x18: /* SR5 */ - s->setup[4] = value & 0x000f; - break; - - default: - OMAP_BAD_REG(addr); - return; - } -} - -static const MemoryRegionOps omap_uwire_ops = { - .read = omap_uwire_read, - .write = omap_uwire_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void omap_uwire_reset(struct omap_uwire_s *s) -{ - s->control = 0; - s->setup[0] = 0; - s->setup[1] = 0; - s->setup[2] = 0; - s->setup[3] = 0; - s->setup[4] = 0; -} - -static struct omap_uwire_s *omap_uwire_init(MemoryRegion *system_memory, - hwaddr base, - qemu_irq txirq, qemu_irq rxirq, - qemu_irq dma, - omap_clk clk) -{ - struct omap_uwire_s *s = g_new0(struct omap_uwire_s, 1); - - s->txirq = txirq; - s->rxirq = rxirq; - s->txdrq = dma; - omap_uwire_reset(s); - - memory_region_init_io(&s->iomem, NULL, &omap_uwire_ops, s, "omap-uwire", 0x800); - memory_region_add_subregion(system_memory, base, &s->iomem); - - return s; -} - -void omap_uwire_attach(struct omap_uwire_s *s, - uWireSlave *slave, int chipselect) -{ - if (chipselect < 0 || chipselect > 3) { - fprintf(stderr, "%s: Bad chipselect %i\n", __FUNCTION__, chipselect); - exit(-1); - } - - s->chip[chipselect] = slave; -} - -/* Pseudonoise Pulse-Width Light Modulator */ -struct omap_pwl_s { - MemoryRegion iomem; - uint8_t output; - uint8_t level; - uint8_t enable; - int clk; -}; - -static void omap_pwl_update(struct omap_pwl_s *s) -{ - int output = (s->clk && s->enable) ? s->level : 0; - - if (output != s->output) { - s->output = output; - printf("%s: Backlight now at %i/256\n", __FUNCTION__, output); - } -} - -static uint64_t omap_pwl_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct omap_pwl_s *s = (struct omap_pwl_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - - if (size != 1) { - return omap_badwidth_read8(opaque, addr); - } - - switch (offset) { - case 0x00: /* PWL_LEVEL */ - return s->level; - case 0x04: /* PWL_CTRL */ - return s->enable; - } - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_pwl_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct omap_pwl_s *s = (struct omap_pwl_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - - if (size != 1) { - omap_badwidth_write8(opaque, addr, value); - return; - } - - switch (offset) { - case 0x00: /* PWL_LEVEL */ - s->level = value; - omap_pwl_update(s); - break; - case 0x04: /* PWL_CTRL */ - s->enable = value & 1; - omap_pwl_update(s); - break; - default: - OMAP_BAD_REG(addr); - return; - } -} - -static const MemoryRegionOps omap_pwl_ops = { - .read = omap_pwl_read, - .write = omap_pwl_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void omap_pwl_reset(struct omap_pwl_s *s) -{ - s->output = 0; - s->level = 0; - s->enable = 0; - s->clk = 1; - omap_pwl_update(s); -} - -static void omap_pwl_clk_update(void *opaque, int line, int on) -{ - struct omap_pwl_s *s = (struct omap_pwl_s *) opaque; - - s->clk = on; - omap_pwl_update(s); -} - -static struct omap_pwl_s *omap_pwl_init(MemoryRegion *system_memory, - hwaddr base, - omap_clk clk) -{ - struct omap_pwl_s *s = g_malloc0(sizeof(*s)); - - omap_pwl_reset(s); - - memory_region_init_io(&s->iomem, NULL, &omap_pwl_ops, s, - "omap-pwl", 0x800); - memory_region_add_subregion(system_memory, base, &s->iomem); - - omap_clk_adduser(clk, qemu_allocate_irq(omap_pwl_clk_update, s, 0)); - return s; -} - -/* Pulse-Width Tone module */ -struct omap_pwt_s { - MemoryRegion iomem; - uint8_t frc; - uint8_t vrc; - uint8_t gcr; - omap_clk clk; -}; - -static uint64_t omap_pwt_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct omap_pwt_s *s = (struct omap_pwt_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - - if (size != 1) { - return omap_badwidth_read8(opaque, addr); - } - - switch (offset) { - case 0x00: /* FRC */ - return s->frc; - case 0x04: /* VCR */ - return s->vrc; - case 0x08: /* GCR */ - return s->gcr; - } - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_pwt_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct omap_pwt_s *s = (struct omap_pwt_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - - if (size != 1) { - omap_badwidth_write8(opaque, addr, value); - return; - } - - switch (offset) { - case 0x00: /* FRC */ - s->frc = value & 0x3f; - break; - case 0x04: /* VRC */ - if ((value ^ s->vrc) & 1) { - if (value & 1) - printf("%s: %iHz buzz on\n", __FUNCTION__, (int) - /* 1.5 MHz from a 12-MHz or 13-MHz PWT_CLK */ - ((omap_clk_getrate(s->clk) >> 3) / - /* Pre-multiplexer divider */ - ((s->gcr & 2) ? 1 : 154) / - /* Octave multiplexer */ - (2 << (value & 3)) * - /* 101/107 divider */ - ((value & (1 << 2)) ? 101 : 107) * - /* 49/55 divider */ - ((value & (1 << 3)) ? 49 : 55) * - /* 50/63 divider */ - ((value & (1 << 4)) ? 50 : 63) * - /* 80/127 divider */ - ((value & (1 << 5)) ? 80 : 127) / - (107 * 55 * 63 * 127))); - else - printf("%s: silence!\n", __FUNCTION__); - } - s->vrc = value & 0x7f; - break; - case 0x08: /* GCR */ - s->gcr = value & 3; - break; - default: - OMAP_BAD_REG(addr); - return; - } -} - -static const MemoryRegionOps omap_pwt_ops = { - .read =omap_pwt_read, - .write = omap_pwt_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void omap_pwt_reset(struct omap_pwt_s *s) -{ - s->frc = 0; - s->vrc = 0; - s->gcr = 0; -} - -static struct omap_pwt_s *omap_pwt_init(MemoryRegion *system_memory, - hwaddr base, - omap_clk clk) -{ - struct omap_pwt_s *s = g_malloc0(sizeof(*s)); - s->clk = clk; - omap_pwt_reset(s); - - memory_region_init_io(&s->iomem, NULL, &omap_pwt_ops, s, - "omap-pwt", 0x800); - memory_region_add_subregion(system_memory, base, &s->iomem); - return s; -} - -/* Real-time Clock module */ -struct omap_rtc_s { - MemoryRegion iomem; - qemu_irq irq; - qemu_irq alarm; - QEMUTimer *clk; - - uint8_t interrupts; - uint8_t status; - int16_t comp_reg; - int running; - int pm_am; - int auto_comp; - int round; - struct tm alarm_tm; - time_t alarm_ti; - - struct tm current_tm; - time_t ti; - uint64_t tick; -}; - -static void omap_rtc_interrupts_update(struct omap_rtc_s *s) -{ - /* s->alarm is level-triggered */ - qemu_set_irq(s->alarm, (s->status >> 6) & 1); -} - -static void omap_rtc_alarm_update(struct omap_rtc_s *s) -{ - s->alarm_ti = mktimegm(&s->alarm_tm); - if (s->alarm_ti == -1) - printf("%s: conversion failed\n", __FUNCTION__); -} - -static uint64_t omap_rtc_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct omap_rtc_s *s = (struct omap_rtc_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - uint8_t i; - - if (size != 1) { - return omap_badwidth_read8(opaque, addr); - } - - switch (offset) { - case 0x00: /* SECONDS_REG */ - return to_bcd(s->current_tm.tm_sec); - - case 0x04: /* MINUTES_REG */ - return to_bcd(s->current_tm.tm_min); - - case 0x08: /* HOURS_REG */ - if (s->pm_am) - return ((s->current_tm.tm_hour > 11) << 7) | - to_bcd(((s->current_tm.tm_hour - 1) % 12) + 1); - else - return to_bcd(s->current_tm.tm_hour); - - case 0x0c: /* DAYS_REG */ - return to_bcd(s->current_tm.tm_mday); - - case 0x10: /* MONTHS_REG */ - return to_bcd(s->current_tm.tm_mon + 1); - - case 0x14: /* YEARS_REG */ - return to_bcd(s->current_tm.tm_year % 100); - - case 0x18: /* WEEK_REG */ - return s->current_tm.tm_wday; - - case 0x20: /* ALARM_SECONDS_REG */ - return to_bcd(s->alarm_tm.tm_sec); - - case 0x24: /* ALARM_MINUTES_REG */ - return to_bcd(s->alarm_tm.tm_min); - - case 0x28: /* ALARM_HOURS_REG */ - if (s->pm_am) - return ((s->alarm_tm.tm_hour > 11) << 7) | - to_bcd(((s->alarm_tm.tm_hour - 1) % 12) + 1); - else - return to_bcd(s->alarm_tm.tm_hour); - - case 0x2c: /* ALARM_DAYS_REG */ - return to_bcd(s->alarm_tm.tm_mday); - - case 0x30: /* ALARM_MONTHS_REG */ - return to_bcd(s->alarm_tm.tm_mon + 1); - - case 0x34: /* ALARM_YEARS_REG */ - return to_bcd(s->alarm_tm.tm_year % 100); - - case 0x40: /* RTC_CTRL_REG */ - return (s->pm_am << 3) | (s->auto_comp << 2) | - (s->round << 1) | s->running; - - case 0x44: /* RTC_STATUS_REG */ - i = s->status; - s->status &= ~0x3d; - return i; - - case 0x48: /* RTC_INTERRUPTS_REG */ - return s->interrupts; - - case 0x4c: /* RTC_COMP_LSB_REG */ - return ((uint16_t) s->comp_reg) & 0xff; - - case 0x50: /* RTC_COMP_MSB_REG */ - return ((uint16_t) s->comp_reg) >> 8; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_rtc_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct omap_rtc_s *s = (struct omap_rtc_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - struct tm new_tm; - time_t ti[2]; - - if (size != 1) { - omap_badwidth_write8(opaque, addr, value); - return; - } - - switch (offset) { - case 0x00: /* SECONDS_REG */ -#ifdef ALMDEBUG - printf("RTC SEC_REG <-- %02x\n", value); -#endif - s->ti -= s->current_tm.tm_sec; - s->ti += from_bcd(value); - return; - - case 0x04: /* MINUTES_REG */ -#ifdef ALMDEBUG - printf("RTC MIN_REG <-- %02x\n", value); -#endif - s->ti -= s->current_tm.tm_min * 60; - s->ti += from_bcd(value) * 60; - return; - - case 0x08: /* HOURS_REG */ -#ifdef ALMDEBUG - printf("RTC HRS_REG <-- %02x\n", value); -#endif - s->ti -= s->current_tm.tm_hour * 3600; - if (s->pm_am) { - s->ti += (from_bcd(value & 0x3f) & 12) * 3600; - s->ti += ((value >> 7) & 1) * 43200; - } else - s->ti += from_bcd(value & 0x3f) * 3600; - return; - - case 0x0c: /* DAYS_REG */ -#ifdef ALMDEBUG - printf("RTC DAY_REG <-- %02x\n", value); -#endif - s->ti -= s->current_tm.tm_mday * 86400; - s->ti += from_bcd(value) * 86400; - return; - - case 0x10: /* MONTHS_REG */ -#ifdef ALMDEBUG - printf("RTC MTH_REG <-- %02x\n", value); -#endif - memcpy(&new_tm, &s->current_tm, sizeof(new_tm)); - new_tm.tm_mon = from_bcd(value); - ti[0] = mktimegm(&s->current_tm); - ti[1] = mktimegm(&new_tm); - - if (ti[0] != -1 && ti[1] != -1) { - s->ti -= ti[0]; - s->ti += ti[1]; - } else { - /* A less accurate version */ - s->ti -= s->current_tm.tm_mon * 2592000; - s->ti += from_bcd(value) * 2592000; - } - return; - - case 0x14: /* YEARS_REG */ -#ifdef ALMDEBUG - printf("RTC YRS_REG <-- %02x\n", value); -#endif - memcpy(&new_tm, &s->current_tm, sizeof(new_tm)); - new_tm.tm_year += from_bcd(value) - (new_tm.tm_year % 100); - ti[0] = mktimegm(&s->current_tm); - ti[1] = mktimegm(&new_tm); - - if (ti[0] != -1 && ti[1] != -1) { - s->ti -= ti[0]; - s->ti += ti[1]; - } else { - /* A less accurate version */ - s->ti -= (time_t)(s->current_tm.tm_year % 100) * 31536000; - s->ti += (time_t)from_bcd(value) * 31536000; - } - return; - - case 0x18: /* WEEK_REG */ - return; /* Ignored */ - - case 0x20: /* ALARM_SECONDS_REG */ -#ifdef ALMDEBUG - printf("ALM SEC_REG <-- %02x\n", value); -#endif - s->alarm_tm.tm_sec = from_bcd(value); - omap_rtc_alarm_update(s); - return; - - case 0x24: /* ALARM_MINUTES_REG */ -#ifdef ALMDEBUG - printf("ALM MIN_REG <-- %02x\n", value); -#endif - s->alarm_tm.tm_min = from_bcd(value); - omap_rtc_alarm_update(s); - return; - - case 0x28: /* ALARM_HOURS_REG */ -#ifdef ALMDEBUG - printf("ALM HRS_REG <-- %02x\n", value); -#endif - if (s->pm_am) - s->alarm_tm.tm_hour = - ((from_bcd(value & 0x3f)) % 12) + - ((value >> 7) & 1) * 12; - else - s->alarm_tm.tm_hour = from_bcd(value); - omap_rtc_alarm_update(s); - return; - - case 0x2c: /* ALARM_DAYS_REG */ -#ifdef ALMDEBUG - printf("ALM DAY_REG <-- %02x\n", value); -#endif - s->alarm_tm.tm_mday = from_bcd(value); - omap_rtc_alarm_update(s); - return; - - case 0x30: /* ALARM_MONTHS_REG */ -#ifdef ALMDEBUG - printf("ALM MON_REG <-- %02x\n", value); -#endif - s->alarm_tm.tm_mon = from_bcd(value); - omap_rtc_alarm_update(s); - return; - - case 0x34: /* ALARM_YEARS_REG */ -#ifdef ALMDEBUG - printf("ALM YRS_REG <-- %02x\n", value); -#endif - s->alarm_tm.tm_year = from_bcd(value); - omap_rtc_alarm_update(s); - return; - - case 0x40: /* RTC_CTRL_REG */ -#ifdef ALMDEBUG - printf("RTC CONTROL <-- %02x\n", value); -#endif - s->pm_am = (value >> 3) & 1; - s->auto_comp = (value >> 2) & 1; - s->round = (value >> 1) & 1; - s->running = value & 1; - s->status &= 0xfd; - s->status |= s->running << 1; - return; - - case 0x44: /* RTC_STATUS_REG */ -#ifdef ALMDEBUG - printf("RTC STATUSL <-- %02x\n", value); -#endif - s->status &= ~((value & 0xc0) ^ 0x80); - omap_rtc_interrupts_update(s); - return; - - case 0x48: /* RTC_INTERRUPTS_REG */ -#ifdef ALMDEBUG - printf("RTC INTRS <-- %02x\n", value); -#endif - s->interrupts = value; - return; - - case 0x4c: /* RTC_COMP_LSB_REG */ -#ifdef ALMDEBUG - printf("RTC COMPLSB <-- %02x\n", value); -#endif - s->comp_reg &= 0xff00; - s->comp_reg |= 0x00ff & value; - return; - - case 0x50: /* RTC_COMP_MSB_REG */ -#ifdef ALMDEBUG - printf("RTC COMPMSB <-- %02x\n", value); -#endif - s->comp_reg &= 0x00ff; - s->comp_reg |= 0xff00 & (value << 8); - return; - - default: - OMAP_BAD_REG(addr); - return; - } -} - -static const MemoryRegionOps omap_rtc_ops = { - .read = omap_rtc_read, - .write = omap_rtc_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void omap_rtc_tick(void *opaque) -{ - struct omap_rtc_s *s = opaque; - - if (s->round) { - /* Round to nearest full minute. */ - if (s->current_tm.tm_sec < 30) - s->ti -= s->current_tm.tm_sec; - else - s->ti += 60 - s->current_tm.tm_sec; - - s->round = 0; - } - - localtime_r(&s->ti, &s->current_tm); - - if ((s->interrupts & 0x08) && s->ti == s->alarm_ti) { - s->status |= 0x40; - omap_rtc_interrupts_update(s); - } - - if (s->interrupts & 0x04) - switch (s->interrupts & 3) { - case 0: - s->status |= 0x04; - qemu_irq_pulse(s->irq); - break; - case 1: - if (s->current_tm.tm_sec) - break; - s->status |= 0x08; - qemu_irq_pulse(s->irq); - break; - case 2: - if (s->current_tm.tm_sec || s->current_tm.tm_min) - break; - s->status |= 0x10; - qemu_irq_pulse(s->irq); - break; - case 3: - if (s->current_tm.tm_sec || - s->current_tm.tm_min || s->current_tm.tm_hour) - break; - s->status |= 0x20; - qemu_irq_pulse(s->irq); - break; - } - - /* Move on */ - if (s->running) - s->ti ++; - s->tick += 1000; - - /* - * Every full hour add a rough approximation of the compensation - * register to the 32kHz Timer (which drives the RTC) value. - */ - if (s->auto_comp && !s->current_tm.tm_sec && !s->current_tm.tm_min) - s->tick += s->comp_reg * 1000 / 32768; - - timer_mod(s->clk, s->tick); -} - -static void omap_rtc_reset(struct omap_rtc_s *s) -{ - struct tm tm; - - s->interrupts = 0; - s->comp_reg = 0; - s->running = 0; - s->pm_am = 0; - s->auto_comp = 0; - s->round = 0; - s->tick = qemu_clock_get_ms(rtc_clock); - memset(&s->alarm_tm, 0, sizeof(s->alarm_tm)); - s->alarm_tm.tm_mday = 0x01; - s->status = 1 << 7; - qemu_get_timedate(&tm, 0); - s->ti = mktimegm(&tm); - - omap_rtc_alarm_update(s); - omap_rtc_tick(s); -} - -static struct omap_rtc_s *omap_rtc_init(MemoryRegion *system_memory, - hwaddr base, - qemu_irq timerirq, qemu_irq alarmirq, - omap_clk clk) -{ - struct omap_rtc_s *s = g_new0(struct omap_rtc_s, 1); - - s->irq = timerirq; - s->alarm = alarmirq; - s->clk = timer_new_ms(rtc_clock, omap_rtc_tick, s); - - omap_rtc_reset(s); - - memory_region_init_io(&s->iomem, NULL, &omap_rtc_ops, s, - "omap-rtc", 0x800); - memory_region_add_subregion(system_memory, base, &s->iomem); - - return s; -} - -/* Multi-channel Buffered Serial Port interfaces */ -struct omap_mcbsp_s { - MemoryRegion iomem; - qemu_irq txirq; - qemu_irq rxirq; - qemu_irq txdrq; - qemu_irq rxdrq; - - uint16_t spcr[2]; - uint16_t rcr[2]; - uint16_t xcr[2]; - uint16_t srgr[2]; - uint16_t mcr[2]; - uint16_t pcr; - uint16_t rcer[8]; - uint16_t xcer[8]; - int tx_rate; - int rx_rate; - int tx_req; - int rx_req; - - I2SCodec *codec; - QEMUTimer *source_timer; - QEMUTimer *sink_timer; -}; - -static void omap_mcbsp_intr_update(struct omap_mcbsp_s *s) -{ - int irq; - - switch ((s->spcr[0] >> 4) & 3) { /* RINTM */ - case 0: - irq = (s->spcr[0] >> 1) & 1; /* RRDY */ - break; - case 3: - irq = (s->spcr[0] >> 3) & 1; /* RSYNCERR */ - break; - default: - irq = 0; - break; - } - - if (irq) - qemu_irq_pulse(s->rxirq); - - switch ((s->spcr[1] >> 4) & 3) { /* XINTM */ - case 0: - irq = (s->spcr[1] >> 1) & 1; /* XRDY */ - break; - case 3: - irq = (s->spcr[1] >> 3) & 1; /* XSYNCERR */ - break; - default: - irq = 0; - break; - } - - if (irq) - qemu_irq_pulse(s->txirq); -} - -static void omap_mcbsp_rx_newdata(struct omap_mcbsp_s *s) -{ - if ((s->spcr[0] >> 1) & 1) /* RRDY */ - s->spcr[0] |= 1 << 2; /* RFULL */ - s->spcr[0] |= 1 << 1; /* RRDY */ - qemu_irq_raise(s->rxdrq); - omap_mcbsp_intr_update(s); -} - -static void omap_mcbsp_source_tick(void *opaque) -{ - struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; - static const int bps[8] = { 0, 1, 1, 2, 2, 2, -255, -255 }; - - if (!s->rx_rate) - return; - if (s->rx_req) - printf("%s: Rx FIFO overrun\n", __FUNCTION__); - - s->rx_req = s->rx_rate << bps[(s->rcr[0] >> 5) & 7]; - - omap_mcbsp_rx_newdata(s); - timer_mod(s->source_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + - NANOSECONDS_PER_SECOND); -} - -static void omap_mcbsp_rx_start(struct omap_mcbsp_s *s) -{ - if (!s->codec || !s->codec->rts) - omap_mcbsp_source_tick(s); - else if (s->codec->in.len) { - s->rx_req = s->codec->in.len; - omap_mcbsp_rx_newdata(s); - } -} - -static void omap_mcbsp_rx_stop(struct omap_mcbsp_s *s) -{ - timer_del(s->source_timer); -} - -static void omap_mcbsp_rx_done(struct omap_mcbsp_s *s) -{ - s->spcr[0] &= ~(1 << 1); /* RRDY */ - qemu_irq_lower(s->rxdrq); - omap_mcbsp_intr_update(s); -} - -static void omap_mcbsp_tx_newdata(struct omap_mcbsp_s *s) -{ - s->spcr[1] |= 1 << 1; /* XRDY */ - qemu_irq_raise(s->txdrq); - omap_mcbsp_intr_update(s); -} - -static void omap_mcbsp_sink_tick(void *opaque) -{ - struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; - static const int bps[8] = { 0, 1, 1, 2, 2, 2, -255, -255 }; - - if (!s->tx_rate) - return; - if (s->tx_req) - printf("%s: Tx FIFO underrun\n", __FUNCTION__); - - s->tx_req = s->tx_rate << bps[(s->xcr[0] >> 5) & 7]; - - omap_mcbsp_tx_newdata(s); - timer_mod(s->sink_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + - NANOSECONDS_PER_SECOND); -} - -static void omap_mcbsp_tx_start(struct omap_mcbsp_s *s) -{ - if (!s->codec || !s->codec->cts) - omap_mcbsp_sink_tick(s); - else if (s->codec->out.size) { - s->tx_req = s->codec->out.size; - omap_mcbsp_tx_newdata(s); - } -} - -static void omap_mcbsp_tx_done(struct omap_mcbsp_s *s) -{ - s->spcr[1] &= ~(1 << 1); /* XRDY */ - qemu_irq_lower(s->txdrq); - omap_mcbsp_intr_update(s); - if (s->codec && s->codec->cts) - s->codec->tx_swallow(s->codec->opaque); -} - -static void omap_mcbsp_tx_stop(struct omap_mcbsp_s *s) -{ - s->tx_req = 0; - omap_mcbsp_tx_done(s); - timer_del(s->sink_timer); -} - -static void omap_mcbsp_req_update(struct omap_mcbsp_s *s) -{ - int prev_rx_rate, prev_tx_rate; - int rx_rate = 0, tx_rate = 0; - int cpu_rate = 1500000; /* XXX */ - - /* TODO: check CLKSTP bit */ - if (s->spcr[1] & (1 << 6)) { /* GRST */ - if (s->spcr[0] & (1 << 0)) { /* RRST */ - if ((s->srgr[1] & (1 << 13)) && /* CLKSM */ - (s->pcr & (1 << 8))) { /* CLKRM */ - if (~s->pcr & (1 << 7)) /* SCLKME */ - rx_rate = cpu_rate / - ((s->srgr[0] & 0xff) + 1); /* CLKGDV */ - } else - if (s->codec) - rx_rate = s->codec->rx_rate; - } - - if (s->spcr[1] & (1 << 0)) { /* XRST */ - if ((s->srgr[1] & (1 << 13)) && /* CLKSM */ - (s->pcr & (1 << 9))) { /* CLKXM */ - if (~s->pcr & (1 << 7)) /* SCLKME */ - tx_rate = cpu_rate / - ((s->srgr[0] & 0xff) + 1); /* CLKGDV */ - } else - if (s->codec) - tx_rate = s->codec->tx_rate; - } - } - prev_tx_rate = s->tx_rate; - prev_rx_rate = s->rx_rate; - s->tx_rate = tx_rate; - s->rx_rate = rx_rate; - - if (s->codec) - s->codec->set_rate(s->codec->opaque, rx_rate, tx_rate); - - if (!prev_tx_rate && tx_rate) - omap_mcbsp_tx_start(s); - else if (s->tx_rate && !tx_rate) - omap_mcbsp_tx_stop(s); - - if (!prev_rx_rate && rx_rate) - omap_mcbsp_rx_start(s); - else if (prev_tx_rate && !tx_rate) - omap_mcbsp_rx_stop(s); -} - -static uint64_t omap_mcbsp_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - uint16_t ret; - - if (size != 2) { - return omap_badwidth_read16(opaque, addr); - } - - switch (offset) { - case 0x00: /* DRR2 */ - if (((s->rcr[0] >> 5) & 7) < 3) /* RWDLEN1 */ - return 0x0000; - /* Fall through. */ - case 0x02: /* DRR1 */ - if (s->rx_req < 2) { - printf("%s: Rx FIFO underrun\n", __FUNCTION__); - omap_mcbsp_rx_done(s); - } else { - s->tx_req -= 2; - if (s->codec && s->codec->in.len >= 2) { - ret = s->codec->in.fifo[s->codec->in.start ++] << 8; - ret |= s->codec->in.fifo[s->codec->in.start ++]; - s->codec->in.len -= 2; - } else - ret = 0x0000; - if (!s->tx_req) - omap_mcbsp_rx_done(s); - return ret; - } - return 0x0000; - - case 0x04: /* DXR2 */ - case 0x06: /* DXR1 */ - return 0x0000; - - case 0x08: /* SPCR2 */ - return s->spcr[1]; - case 0x0a: /* SPCR1 */ - return s->spcr[0]; - case 0x0c: /* RCR2 */ - return s->rcr[1]; - case 0x0e: /* RCR1 */ - return s->rcr[0]; - case 0x10: /* XCR2 */ - return s->xcr[1]; - case 0x12: /* XCR1 */ - return s->xcr[0]; - case 0x14: /* SRGR2 */ - return s->srgr[1]; - case 0x16: /* SRGR1 */ - return s->srgr[0]; - case 0x18: /* MCR2 */ - return s->mcr[1]; - case 0x1a: /* MCR1 */ - return s->mcr[0]; - case 0x1c: /* RCERA */ - return s->rcer[0]; - case 0x1e: /* RCERB */ - return s->rcer[1]; - case 0x20: /* XCERA */ - return s->xcer[0]; - case 0x22: /* XCERB */ - return s->xcer[1]; - case 0x24: /* PCR0 */ - return s->pcr; - case 0x26: /* RCERC */ - return s->rcer[2]; - case 0x28: /* RCERD */ - return s->rcer[3]; - case 0x2a: /* XCERC */ - return s->xcer[2]; - case 0x2c: /* XCERD */ - return s->xcer[3]; - case 0x2e: /* RCERE */ - return s->rcer[4]; - case 0x30: /* RCERF */ - return s->rcer[5]; - case 0x32: /* XCERE */ - return s->xcer[4]; - case 0x34: /* XCERF */ - return s->xcer[5]; - case 0x36: /* RCERG */ - return s->rcer[6]; - case 0x38: /* RCERH */ - return s->rcer[7]; - case 0x3a: /* XCERG */ - return s->xcer[6]; - case 0x3c: /* XCERH */ - return s->xcer[7]; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_mcbsp_writeh(void *opaque, hwaddr addr, - uint32_t value) -{ - struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - - switch (offset) { - case 0x00: /* DRR2 */ - case 0x02: /* DRR1 */ - OMAP_RO_REG(addr); - return; - - case 0x04: /* DXR2 */ - if (((s->xcr[0] >> 5) & 7) < 3) /* XWDLEN1 */ - return; - /* Fall through. */ - case 0x06: /* DXR1 */ - if (s->tx_req > 1) { - s->tx_req -= 2; - if (s->codec && s->codec->cts) { - s->codec->out.fifo[s->codec->out.len ++] = (value >> 8) & 0xff; - s->codec->out.fifo[s->codec->out.len ++] = (value >> 0) & 0xff; - } - if (s->tx_req < 2) - omap_mcbsp_tx_done(s); - } else - printf("%s: Tx FIFO overrun\n", __FUNCTION__); - return; - - case 0x08: /* SPCR2 */ - s->spcr[1] &= 0x0002; - s->spcr[1] |= 0x03f9 & value; - s->spcr[1] |= 0x0004 & (value << 2); /* XEMPTY := XRST */ - if (~value & 1) /* XRST */ - s->spcr[1] &= ~6; - omap_mcbsp_req_update(s); - return; - case 0x0a: /* SPCR1 */ - s->spcr[0] &= 0x0006; - s->spcr[0] |= 0xf8f9 & value; - if (value & (1 << 15)) /* DLB */ - printf("%s: Digital Loopback mode enable attempt\n", __FUNCTION__); - if (~value & 1) { /* RRST */ - s->spcr[0] &= ~6; - s->rx_req = 0; - omap_mcbsp_rx_done(s); - } - omap_mcbsp_req_update(s); - return; - - case 0x0c: /* RCR2 */ - s->rcr[1] = value & 0xffff; - return; - case 0x0e: /* RCR1 */ - s->rcr[0] = value & 0x7fe0; - return; - case 0x10: /* XCR2 */ - s->xcr[1] = value & 0xffff; - return; - case 0x12: /* XCR1 */ - s->xcr[0] = value & 0x7fe0; - return; - case 0x14: /* SRGR2 */ - s->srgr[1] = value & 0xffff; - omap_mcbsp_req_update(s); - return; - case 0x16: /* SRGR1 */ - s->srgr[0] = value & 0xffff; - omap_mcbsp_req_update(s); - return; - case 0x18: /* MCR2 */ - s->mcr[1] = value & 0x03e3; - if (value & 3) /* XMCM */ - printf("%s: Tx channel selection mode enable attempt\n", - __FUNCTION__); - return; - case 0x1a: /* MCR1 */ - s->mcr[0] = value & 0x03e1; - if (value & 1) /* RMCM */ - printf("%s: Rx channel selection mode enable attempt\n", - __FUNCTION__); - return; - case 0x1c: /* RCERA */ - s->rcer[0] = value & 0xffff; - return; - case 0x1e: /* RCERB */ - s->rcer[1] = value & 0xffff; - return; - case 0x20: /* XCERA */ - s->xcer[0] = value & 0xffff; - return; - case 0x22: /* XCERB */ - s->xcer[1] = value & 0xffff; - return; - case 0x24: /* PCR0 */ - s->pcr = value & 0x7faf; - return; - case 0x26: /* RCERC */ - s->rcer[2] = value & 0xffff; - return; - case 0x28: /* RCERD */ - s->rcer[3] = value & 0xffff; - return; - case 0x2a: /* XCERC */ - s->xcer[2] = value & 0xffff; - return; - case 0x2c: /* XCERD */ - s->xcer[3] = value & 0xffff; - return; - case 0x2e: /* RCERE */ - s->rcer[4] = value & 0xffff; - return; - case 0x30: /* RCERF */ - s->rcer[5] = value & 0xffff; - return; - case 0x32: /* XCERE */ - s->xcer[4] = value & 0xffff; - return; - case 0x34: /* XCERF */ - s->xcer[5] = value & 0xffff; - return; - case 0x36: /* RCERG */ - s->rcer[6] = value & 0xffff; - return; - case 0x38: /* RCERH */ - s->rcer[7] = value & 0xffff; - return; - case 0x3a: /* XCERG */ - s->xcer[6] = value & 0xffff; - return; - case 0x3c: /* XCERH */ - s->xcer[7] = value & 0xffff; - return; - } - - OMAP_BAD_REG(addr); -} - -static void omap_mcbsp_writew(void *opaque, hwaddr addr, - uint32_t value) -{ - struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - - if (offset == 0x04) { /* DXR */ - if (((s->xcr[0] >> 5) & 7) < 3) /* XWDLEN1 */ - return; - if (s->tx_req > 3) { - s->tx_req -= 4; - if (s->codec && s->codec->cts) { - s->codec->out.fifo[s->codec->out.len ++] = - (value >> 24) & 0xff; - s->codec->out.fifo[s->codec->out.len ++] = - (value >> 16) & 0xff; - s->codec->out.fifo[s->codec->out.len ++] = - (value >> 8) & 0xff; - s->codec->out.fifo[s->codec->out.len ++] = - (value >> 0) & 0xff; - } - if (s->tx_req < 4) - omap_mcbsp_tx_done(s); - } else - printf("%s: Tx FIFO overrun\n", __FUNCTION__); - return; - } - - omap_badwidth_write16(opaque, addr, value); -} - -static void omap_mcbsp_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - switch (size) { - case 2: - omap_mcbsp_writeh(opaque, addr, value); - break; - case 4: - omap_mcbsp_writew(opaque, addr, value); - break; - default: - omap_badwidth_write16(opaque, addr, value); - } -} - -static const MemoryRegionOps omap_mcbsp_ops = { - .read = omap_mcbsp_read, - .write = omap_mcbsp_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void omap_mcbsp_reset(struct omap_mcbsp_s *s) -{ - memset(&s->spcr, 0, sizeof(s->spcr)); - memset(&s->rcr, 0, sizeof(s->rcr)); - memset(&s->xcr, 0, sizeof(s->xcr)); - s->srgr[0] = 0x0001; - s->srgr[1] = 0x2000; - memset(&s->mcr, 0, sizeof(s->mcr)); - memset(&s->pcr, 0, sizeof(s->pcr)); - memset(&s->rcer, 0, sizeof(s->rcer)); - memset(&s->xcer, 0, sizeof(s->xcer)); - s->tx_req = 0; - s->rx_req = 0; - s->tx_rate = 0; - s->rx_rate = 0; - timer_del(s->source_timer); - timer_del(s->sink_timer); -} - -static struct omap_mcbsp_s *omap_mcbsp_init(MemoryRegion *system_memory, - hwaddr base, - qemu_irq txirq, qemu_irq rxirq, - qemu_irq *dma, omap_clk clk) -{ - struct omap_mcbsp_s *s = g_new0(struct omap_mcbsp_s, 1); - - s->txirq = txirq; - s->rxirq = rxirq; - s->txdrq = dma[0]; - s->rxdrq = dma[1]; - s->sink_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, omap_mcbsp_sink_tick, s); - s->source_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, omap_mcbsp_source_tick, s); - omap_mcbsp_reset(s); - - memory_region_init_io(&s->iomem, NULL, &omap_mcbsp_ops, s, "omap-mcbsp", 0x800); - memory_region_add_subregion(system_memory, base, &s->iomem); - - return s; -} - -static void omap_mcbsp_i2s_swallow(void *opaque, int line, int level) -{ - struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; - - if (s->rx_rate) { - s->rx_req = s->codec->in.len; - omap_mcbsp_rx_newdata(s); - } -} - -static void omap_mcbsp_i2s_start(void *opaque, int line, int level) -{ - struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; - - if (s->tx_rate) { - s->tx_req = s->codec->out.size; - omap_mcbsp_tx_newdata(s); - } -} - -void omap_mcbsp_i2s_attach(struct omap_mcbsp_s *s, I2SCodec *slave) -{ - s->codec = slave; - slave->rx_swallow = qemu_allocate_irq(omap_mcbsp_i2s_swallow, s, 0); - slave->tx_start = qemu_allocate_irq(omap_mcbsp_i2s_start, s, 0); -} - -/* LED Pulse Generators */ -struct omap_lpg_s { - MemoryRegion iomem; - QEMUTimer *tm; - - uint8_t control; - uint8_t power; - int64_t on; - int64_t period; - int clk; - int cycle; -}; - -static void omap_lpg_tick(void *opaque) -{ - struct omap_lpg_s *s = opaque; - - if (s->cycle) - timer_mod(s->tm, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + s->period - s->on); - else - timer_mod(s->tm, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + s->on); - - s->cycle = !s->cycle; - printf("%s: LED is %s\n", __FUNCTION__, s->cycle ? "on" : "off"); -} - -static void omap_lpg_update(struct omap_lpg_s *s) -{ - int64_t on, period = 1, ticks = 1000; - static const int per[8] = { 1, 2, 4, 8, 12, 16, 20, 24 }; - - if (~s->control & (1 << 6)) /* LPGRES */ - on = 0; - else if (s->control & (1 << 7)) /* PERM_ON */ - on = period; - else { - period = muldiv64(ticks, per[s->control & 7], /* PERCTRL */ - 256 / 32); - on = (s->clk && s->power) ? muldiv64(ticks, - per[(s->control >> 3) & 7], 256) : 0; /* ONCTRL */ - } - - timer_del(s->tm); - if (on == period && s->on < s->period) - printf("%s: LED is on\n", __FUNCTION__); - else if (on == 0 && s->on) - printf("%s: LED is off\n", __FUNCTION__); - else if (on && (on != s->on || period != s->period)) { - s->cycle = 0; - s->on = on; - s->period = period; - omap_lpg_tick(s); - return; - } - - s->on = on; - s->period = period; -} - -static void omap_lpg_reset(struct omap_lpg_s *s) -{ - s->control = 0x00; - s->power = 0x00; - s->clk = 1; - omap_lpg_update(s); -} - -static uint64_t omap_lpg_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct omap_lpg_s *s = (struct omap_lpg_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - - if (size != 1) { - return omap_badwidth_read8(opaque, addr); - } - - switch (offset) { - case 0x00: /* LCR */ - return s->control; - - case 0x04: /* PMR */ - return s->power; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_lpg_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct omap_lpg_s *s = (struct omap_lpg_s *) opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - - if (size != 1) { - omap_badwidth_write8(opaque, addr, value); - return; - } - - switch (offset) { - case 0x00: /* LCR */ - if (~value & (1 << 6)) /* LPGRES */ - omap_lpg_reset(s); - s->control = value & 0xff; - omap_lpg_update(s); - return; - - case 0x04: /* PMR */ - s->power = value & 0x01; - omap_lpg_update(s); - return; - - default: - OMAP_BAD_REG(addr); - return; - } -} - -static const MemoryRegionOps omap_lpg_ops = { - .read = omap_lpg_read, - .write = omap_lpg_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void omap_lpg_clk_update(void *opaque, int line, int on) -{ - struct omap_lpg_s *s = (struct omap_lpg_s *) opaque; - - s->clk = on; - omap_lpg_update(s); -} - -static struct omap_lpg_s *omap_lpg_init(MemoryRegion *system_memory, - hwaddr base, omap_clk clk) -{ - struct omap_lpg_s *s = g_new0(struct omap_lpg_s, 1); - - s->tm = timer_new_ms(QEMU_CLOCK_VIRTUAL, omap_lpg_tick, s); - - omap_lpg_reset(s); - - memory_region_init_io(&s->iomem, NULL, &omap_lpg_ops, s, "omap-lpg", 0x800); - memory_region_add_subregion(system_memory, base, &s->iomem); - - omap_clk_adduser(clk, qemu_allocate_irq(omap_lpg_clk_update, s, 0)); - - return s; -} - -/* MPUI Peripheral Bridge configuration */ -static uint64_t omap_mpui_io_read(void *opaque, hwaddr addr, - unsigned size) -{ - if (size != 2) { - return omap_badwidth_read16(opaque, addr); - } - - if (addr == OMAP_MPUI_BASE) /* CMR */ - return 0xfe4d; - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_mpui_io_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - /* FIXME: infinite loop */ - omap_badwidth_write16(opaque, addr, value); -} - -static const MemoryRegionOps omap_mpui_io_ops = { - .read = omap_mpui_io_read, - .write = omap_mpui_io_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void omap_setup_mpui_io(MemoryRegion *system_memory, - struct omap_mpu_state_s *mpu) -{ - memory_region_init_io(&mpu->mpui_io_iomem, NULL, &omap_mpui_io_ops, mpu, - "omap-mpui-io", 0x7fff); - memory_region_add_subregion(system_memory, OMAP_MPUI_BASE, - &mpu->mpui_io_iomem); -} - -/* General chip reset */ -static void omap1_mpu_reset(void *opaque) -{ - struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque; - - omap_dma_reset(mpu->dma); - omap_mpu_timer_reset(mpu->timer[0]); - omap_mpu_timer_reset(mpu->timer[1]); - omap_mpu_timer_reset(mpu->timer[2]); - omap_wd_timer_reset(mpu->wdt); - omap_os_timer_reset(mpu->os_timer); - omap_lcdc_reset(mpu->lcd); - omap_ulpd_pm_reset(mpu); - omap_pin_cfg_reset(mpu); - omap_mpui_reset(mpu); - omap_tipb_bridge_reset(mpu->private_tipb); - omap_tipb_bridge_reset(mpu->public_tipb); - omap_dpll_reset(mpu->dpll[0]); - omap_dpll_reset(mpu->dpll[1]); - omap_dpll_reset(mpu->dpll[2]); - omap_uart_reset(mpu->uart[0]); - omap_uart_reset(mpu->uart[1]); - omap_uart_reset(mpu->uart[2]); - omap_mmc_reset(mpu->mmc); - omap_mpuio_reset(mpu->mpuio); - omap_uwire_reset(mpu->microwire); - omap_pwl_reset(mpu->pwl); - omap_pwt_reset(mpu->pwt); - omap_rtc_reset(mpu->rtc); - omap_mcbsp_reset(mpu->mcbsp1); - omap_mcbsp_reset(mpu->mcbsp2); - omap_mcbsp_reset(mpu->mcbsp3); - omap_lpg_reset(mpu->led[0]); - omap_lpg_reset(mpu->led[1]); - omap_clkm_reset(mpu); - cpu_reset(CPU(mpu->cpu)); -} - -static const struct omap_map_s { - hwaddr phys_dsp; - hwaddr phys_mpu; - uint32_t size; - const char *name; -} omap15xx_dsp_mm[] = { - /* Strobe 0 */ - { 0xe1010000, 0xfffb0000, 0x800, "UART1 BT" }, /* CS0 */ - { 0xe1010800, 0xfffb0800, 0x800, "UART2 COM" }, /* CS1 */ - { 0xe1011800, 0xfffb1800, 0x800, "McBSP1 audio" }, /* CS3 */ - { 0xe1012000, 0xfffb2000, 0x800, "MCSI2 communication" }, /* CS4 */ - { 0xe1012800, 0xfffb2800, 0x800, "MCSI1 BT u-Law" }, /* CS5 */ - { 0xe1013000, 0xfffb3000, 0x800, "uWire" }, /* CS6 */ - { 0xe1013800, 0xfffb3800, 0x800, "I^2C" }, /* CS7 */ - { 0xe1014000, 0xfffb4000, 0x800, "USB W2FC" }, /* CS8 */ - { 0xe1014800, 0xfffb4800, 0x800, "RTC" }, /* CS9 */ - { 0xe1015000, 0xfffb5000, 0x800, "MPUIO" }, /* CS10 */ - { 0xe1015800, 0xfffb5800, 0x800, "PWL" }, /* CS11 */ - { 0xe1016000, 0xfffb6000, 0x800, "PWT" }, /* CS12 */ - { 0xe1017000, 0xfffb7000, 0x800, "McBSP3" }, /* CS14 */ - { 0xe1017800, 0xfffb7800, 0x800, "MMC" }, /* CS15 */ - { 0xe1019000, 0xfffb9000, 0x800, "32-kHz timer" }, /* CS18 */ - { 0xe1019800, 0xfffb9800, 0x800, "UART3" }, /* CS19 */ - { 0xe101c800, 0xfffbc800, 0x800, "TIPB switches" }, /* CS25 */ - /* Strobe 1 */ - { 0xe101e000, 0xfffce000, 0x800, "GPIOs" }, /* CS28 */ - - { 0 } -}; - -static void omap_setup_dsp_mapping(MemoryRegion *system_memory, - const struct omap_map_s *map) -{ - MemoryRegion *io; - - for (; map->phys_dsp; map ++) { - io = g_new(MemoryRegion, 1); - memory_region_init_alias(io, NULL, map->name, - system_memory, map->phys_mpu, map->size); - memory_region_add_subregion(system_memory, map->phys_dsp, io); - } -} - -void omap_mpu_wakeup(void *opaque, int irq, int req) -{ - struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque; - CPUState *cpu = CPU(mpu->cpu); - - if (cpu->halted) { - cpu_interrupt(cpu, CPU_INTERRUPT_EXITTB); - } -} - -static const struct dma_irq_map omap1_dma_irq_map[] = { - { 0, OMAP_INT_DMA_CH0_6 }, - { 0, OMAP_INT_DMA_CH1_7 }, - { 0, OMAP_INT_DMA_CH2_8 }, - { 0, OMAP_INT_DMA_CH3 }, - { 0, OMAP_INT_DMA_CH4 }, - { 0, OMAP_INT_DMA_CH5 }, - { 1, OMAP_INT_1610_DMA_CH6 }, - { 1, OMAP_INT_1610_DMA_CH7 }, - { 1, OMAP_INT_1610_DMA_CH8 }, - { 1, OMAP_INT_1610_DMA_CH9 }, - { 1, OMAP_INT_1610_DMA_CH10 }, - { 1, OMAP_INT_1610_DMA_CH11 }, - { 1, OMAP_INT_1610_DMA_CH12 }, - { 1, OMAP_INT_1610_DMA_CH13 }, - { 1, OMAP_INT_1610_DMA_CH14 }, - { 1, OMAP_INT_1610_DMA_CH15 } -}; - -/* DMA ports for OMAP1 */ -static int omap_validate_emiff_addr(struct omap_mpu_state_s *s, - hwaddr addr) -{ - return range_covers_byte(OMAP_EMIFF_BASE, s->sdram_size, addr); -} - -static int omap_validate_emifs_addr(struct omap_mpu_state_s *s, - hwaddr addr) -{ - return range_covers_byte(OMAP_EMIFS_BASE, OMAP_EMIFF_BASE - OMAP_EMIFS_BASE, - addr); -} - -static int omap_validate_imif_addr(struct omap_mpu_state_s *s, - hwaddr addr) -{ - return range_covers_byte(OMAP_IMIF_BASE, s->sram_size, addr); -} - -static int omap_validate_tipb_addr(struct omap_mpu_state_s *s, - hwaddr addr) -{ - return range_covers_byte(0xfffb0000, 0xffff0000 - 0xfffb0000, addr); -} - -static int omap_validate_local_addr(struct omap_mpu_state_s *s, - hwaddr addr) -{ - return range_covers_byte(OMAP_LOCALBUS_BASE, 0x1000000, addr); -} - -static int omap_validate_tipb_mpui_addr(struct omap_mpu_state_s *s, - hwaddr addr) -{ - return range_covers_byte(0xe1010000, 0xe1020004 - 0xe1010000, addr); -} - -struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory, - unsigned long sdram_size, - const char *core) -{ - int i; - struct omap_mpu_state_s *s = g_new0(struct omap_mpu_state_s, 1); - qemu_irq dma_irqs[6]; - DriveInfo *dinfo; - SysBusDevice *busdev; - - if (!core) - core = "ti925t"; - - /* Core */ - s->mpu_model = omap310; - s->cpu = cpu_arm_init(core); - if (s->cpu == NULL) { - fprintf(stderr, "Unable to find CPU definition\n"); - exit(1); - } - s->sdram_size = sdram_size; - s->sram_size = OMAP15XX_SRAM_SIZE; - - s->wakeup = qemu_allocate_irq(omap_mpu_wakeup, s, 0); - - /* Clocks */ - omap_clk_init(s); - - /* Memory-mapped stuff */ - memory_region_allocate_system_memory(&s->emiff_ram, NULL, "omap1.dram", - s->sdram_size); - memory_region_add_subregion(system_memory, OMAP_EMIFF_BASE, &s->emiff_ram); - memory_region_init_ram(&s->imif_ram, NULL, "omap1.sram", s->sram_size, - &error_fatal); - vmstate_register_ram_global(&s->imif_ram); - memory_region_add_subregion(system_memory, OMAP_IMIF_BASE, &s->imif_ram); - - omap_clkm_init(system_memory, 0xfffece00, 0xe1008000, s); - - s->ih[0] = qdev_create(NULL, "omap-intc"); - qdev_prop_set_uint32(s->ih[0], "size", 0x100); - qdev_prop_set_ptr(s->ih[0], "clk", omap_findclk(s, "arminth_ck")); - qdev_init_nofail(s->ih[0]); - busdev = SYS_BUS_DEVICE(s->ih[0]); - sysbus_connect_irq(busdev, 0, - qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_IRQ)); - sysbus_connect_irq(busdev, 1, - qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_FIQ)); - sysbus_mmio_map(busdev, 0, 0xfffecb00); - s->ih[1] = qdev_create(NULL, "omap-intc"); - qdev_prop_set_uint32(s->ih[1], "size", 0x800); - qdev_prop_set_ptr(s->ih[1], "clk", omap_findclk(s, "arminth_ck")); - qdev_init_nofail(s->ih[1]); - busdev = SYS_BUS_DEVICE(s->ih[1]); - sysbus_connect_irq(busdev, 0, - qdev_get_gpio_in(s->ih[0], OMAP_INT_15XX_IH2_IRQ)); - /* The second interrupt controller's FIQ output is not wired up */ - sysbus_mmio_map(busdev, 0, 0xfffe0000); - - for (i = 0; i < 6; i++) { - dma_irqs[i] = qdev_get_gpio_in(s->ih[omap1_dma_irq_map[i].ih], - omap1_dma_irq_map[i].intr); - } - s->dma = omap_dma_init(0xfffed800, dma_irqs, system_memory, - qdev_get_gpio_in(s->ih[0], OMAP_INT_DMA_LCD), - s, omap_findclk(s, "dma_ck"), omap_dma_3_1); - - s->port[emiff ].addr_valid = omap_validate_emiff_addr; - s->port[emifs ].addr_valid = omap_validate_emifs_addr; - s->port[imif ].addr_valid = omap_validate_imif_addr; - s->port[tipb ].addr_valid = omap_validate_tipb_addr; - s->port[local ].addr_valid = omap_validate_local_addr; - s->port[tipb_mpui].addr_valid = omap_validate_tipb_mpui_addr; - - /* Register SDRAM and SRAM DMA ports for fast transfers. */ - soc_dma_port_add_mem(s->dma, memory_region_get_ram_ptr(&s->emiff_ram), - OMAP_EMIFF_BASE, s->sdram_size); - soc_dma_port_add_mem(s->dma, memory_region_get_ram_ptr(&s->imif_ram), - OMAP_IMIF_BASE, s->sram_size); - - s->timer[0] = omap_mpu_timer_init(system_memory, 0xfffec500, - qdev_get_gpio_in(s->ih[0], OMAP_INT_TIMER1), - omap_findclk(s, "mputim_ck")); - s->timer[1] = omap_mpu_timer_init(system_memory, 0xfffec600, - qdev_get_gpio_in(s->ih[0], OMAP_INT_TIMER2), - omap_findclk(s, "mputim_ck")); - s->timer[2] = omap_mpu_timer_init(system_memory, 0xfffec700, - qdev_get_gpio_in(s->ih[0], OMAP_INT_TIMER3), - omap_findclk(s, "mputim_ck")); - - s->wdt = omap_wd_timer_init(system_memory, 0xfffec800, - qdev_get_gpio_in(s->ih[0], OMAP_INT_WD_TIMER), - omap_findclk(s, "armwdt_ck")); - - s->os_timer = omap_os_timer_init(system_memory, 0xfffb9000, - qdev_get_gpio_in(s->ih[1], OMAP_INT_OS_TIMER), - omap_findclk(s, "clk32-kHz")); - - s->lcd = omap_lcdc_init(system_memory, 0xfffec000, - qdev_get_gpio_in(s->ih[0], OMAP_INT_LCD_CTRL), - omap_dma_get_lcdch(s->dma), - omap_findclk(s, "lcd_ck")); - - omap_ulpd_pm_init(system_memory, 0xfffe0800, s); - omap_pin_cfg_init(system_memory, 0xfffe1000, s); - omap_id_init(system_memory, s); - - omap_mpui_init(system_memory, 0xfffec900, s); - - s->private_tipb = omap_tipb_bridge_init(system_memory, 0xfffeca00, - qdev_get_gpio_in(s->ih[0], OMAP_INT_BRIDGE_PRIV), - omap_findclk(s, "tipb_ck")); - s->public_tipb = omap_tipb_bridge_init(system_memory, 0xfffed300, - qdev_get_gpio_in(s->ih[0], OMAP_INT_BRIDGE_PUB), - omap_findclk(s, "tipb_ck")); - - omap_tcmi_init(system_memory, 0xfffecc00, s); - - s->uart[0] = omap_uart_init(0xfffb0000, - qdev_get_gpio_in(s->ih[1], OMAP_INT_UART1), - omap_findclk(s, "uart1_ck"), - omap_findclk(s, "uart1_ck"), - s->drq[OMAP_DMA_UART1_TX], s->drq[OMAP_DMA_UART1_RX], - "uart1", - serial_hds[0]); - s->uart[1] = omap_uart_init(0xfffb0800, - qdev_get_gpio_in(s->ih[1], OMAP_INT_UART2), - omap_findclk(s, "uart2_ck"), - omap_findclk(s, "uart2_ck"), - s->drq[OMAP_DMA_UART2_TX], s->drq[OMAP_DMA_UART2_RX], - "uart2", - serial_hds[0] ? serial_hds[1] : NULL); - s->uart[2] = omap_uart_init(0xfffb9800, - qdev_get_gpio_in(s->ih[0], OMAP_INT_UART3), - omap_findclk(s, "uart3_ck"), - omap_findclk(s, "uart3_ck"), - s->drq[OMAP_DMA_UART3_TX], s->drq[OMAP_DMA_UART3_RX], - "uart3", - serial_hds[0] && serial_hds[1] ? serial_hds[2] : NULL); - - s->dpll[0] = omap_dpll_init(system_memory, 0xfffecf00, - omap_findclk(s, "dpll1")); - s->dpll[1] = omap_dpll_init(system_memory, 0xfffed000, - omap_findclk(s, "dpll2")); - s->dpll[2] = omap_dpll_init(system_memory, 0xfffed100, - omap_findclk(s, "dpll3")); - - dinfo = drive_get(IF_SD, 0, 0); - if (!dinfo) { - fprintf(stderr, "qemu: missing SecureDigital device\n"); - exit(1); - } - s->mmc = omap_mmc_init(0xfffb7800, system_memory, - blk_by_legacy_dinfo(dinfo), - qdev_get_gpio_in(s->ih[1], OMAP_INT_OQN), - &s->drq[OMAP_DMA_MMC_TX], - omap_findclk(s, "mmc_ck")); - - s->mpuio = omap_mpuio_init(system_memory, 0xfffb5000, - qdev_get_gpio_in(s->ih[1], OMAP_INT_KEYBOARD), - qdev_get_gpio_in(s->ih[1], OMAP_INT_MPUIO), - s->wakeup, omap_findclk(s, "clk32-kHz")); - - s->gpio = qdev_create(NULL, "omap-gpio"); - qdev_prop_set_int32(s->gpio, "mpu_model", s->mpu_model); - qdev_prop_set_ptr(s->gpio, "clk", omap_findclk(s, "arm_gpio_ck")); - qdev_init_nofail(s->gpio); - sysbus_connect_irq(SYS_BUS_DEVICE(s->gpio), 0, - qdev_get_gpio_in(s->ih[0], OMAP_INT_GPIO_BANK1)); - sysbus_mmio_map(SYS_BUS_DEVICE(s->gpio), 0, 0xfffce000); - - s->microwire = omap_uwire_init(system_memory, 0xfffb3000, - qdev_get_gpio_in(s->ih[1], OMAP_INT_uWireTX), - qdev_get_gpio_in(s->ih[1], OMAP_INT_uWireRX), - s->drq[OMAP_DMA_UWIRE_TX], omap_findclk(s, "mpuper_ck")); - - s->pwl = omap_pwl_init(system_memory, 0xfffb5800, - omap_findclk(s, "armxor_ck")); - s->pwt = omap_pwt_init(system_memory, 0xfffb6000, - omap_findclk(s, "armxor_ck")); - - s->i2c[0] = qdev_create(NULL, "omap_i2c"); - qdev_prop_set_uint8(s->i2c[0], "revision", 0x11); - qdev_prop_set_ptr(s->i2c[0], "fclk", omap_findclk(s, "mpuper_ck")); - qdev_init_nofail(s->i2c[0]); - busdev = SYS_BUS_DEVICE(s->i2c[0]); - sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(s->ih[1], OMAP_INT_I2C)); - sysbus_connect_irq(busdev, 1, s->drq[OMAP_DMA_I2C_TX]); - sysbus_connect_irq(busdev, 2, s->drq[OMAP_DMA_I2C_RX]); - sysbus_mmio_map(busdev, 0, 0xfffb3800); - - s->rtc = omap_rtc_init(system_memory, 0xfffb4800, - qdev_get_gpio_in(s->ih[1], OMAP_INT_RTC_TIMER), - qdev_get_gpio_in(s->ih[1], OMAP_INT_RTC_ALARM), - omap_findclk(s, "clk32-kHz")); - - s->mcbsp1 = omap_mcbsp_init(system_memory, 0xfffb1800, - qdev_get_gpio_in(s->ih[1], OMAP_INT_McBSP1TX), - qdev_get_gpio_in(s->ih[1], OMAP_INT_McBSP1RX), - &s->drq[OMAP_DMA_MCBSP1_TX], omap_findclk(s, "dspxor_ck")); - s->mcbsp2 = omap_mcbsp_init(system_memory, 0xfffb1000, - qdev_get_gpio_in(s->ih[0], - OMAP_INT_310_McBSP2_TX), - qdev_get_gpio_in(s->ih[0], - OMAP_INT_310_McBSP2_RX), - &s->drq[OMAP_DMA_MCBSP2_TX], omap_findclk(s, "mpuper_ck")); - s->mcbsp3 = omap_mcbsp_init(system_memory, 0xfffb7000, - qdev_get_gpio_in(s->ih[1], OMAP_INT_McBSP3TX), - qdev_get_gpio_in(s->ih[1], OMAP_INT_McBSP3RX), - &s->drq[OMAP_DMA_MCBSP3_TX], omap_findclk(s, "dspxor_ck")); - - s->led[0] = omap_lpg_init(system_memory, - 0xfffbd000, omap_findclk(s, "clk32-kHz")); - s->led[1] = omap_lpg_init(system_memory, - 0xfffbd800, omap_findclk(s, "clk32-kHz")); - - /* Register mappings not currenlty implemented: - * MCSI2 Comm fffb2000 - fffb27ff (not mapped on OMAP310) - * MCSI1 Bluetooth fffb2800 - fffb2fff (not mapped on OMAP310) - * USB W2FC fffb4000 - fffb47ff - * Camera Interface fffb6800 - fffb6fff - * USB Host fffba000 - fffba7ff - * FAC fffba800 - fffbafff - * HDQ/1-Wire fffbc000 - fffbc7ff - * TIPB switches fffbc800 - fffbcfff - * Mailbox fffcf000 - fffcf7ff - * Local bus IF fffec100 - fffec1ff - * Local bus MMU fffec200 - fffec2ff - * DSP MMU fffed200 - fffed2ff - */ - - omap_setup_dsp_mapping(system_memory, omap15xx_dsp_mm); - omap_setup_mpui_io(system_memory, s); - - qemu_register_reset(omap1_mpu_reset, s); - - return s; -} diff --git a/qemu/hw/arm/omap2.c b/qemu/hw/arm/omap2.c deleted file mode 100644 index 3a0d77714..000000000 --- a/qemu/hw/arm/omap2.c +++ /dev/null @@ -1,2691 +0,0 @@ -/* - * TI OMAP processors emulation. - * - * Copyright (C) 2007-2008 Nokia Corporation - * Written by Andrzej Zaborowski <andrew@openedhand.com> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "qemu-common.h" -#include "cpu.h" -#include "sysemu/block-backend.h" -#include "sysemu/blockdev.h" -#include "hw/boards.h" -#include "hw/hw.h" -#include "hw/arm/arm.h" -#include "hw/arm/omap.h" -#include "sysemu/sysemu.h" -#include "qemu/timer.h" -#include "sysemu/char.h" -#include "hw/block/flash.h" -#include "hw/arm/soc_dma.h" -#include "hw/sysbus.h" -#include "audio/audio.h" - -/* Enhanced Audio Controller (CODEC only) */ -struct omap_eac_s { - qemu_irq irq; - MemoryRegion iomem; - - uint16_t sysconfig; - uint8_t config[4]; - uint8_t control; - uint8_t address; - uint16_t data; - uint8_t vtol; - uint8_t vtsl; - uint16_t mixer; - uint16_t gain[4]; - uint8_t att; - uint16_t max[7]; - - struct { - qemu_irq txdrq; - qemu_irq rxdrq; - uint32_t (*txrx)(void *opaque, uint32_t, int); - void *opaque; - -#define EAC_BUF_LEN 1024 - uint32_t rxbuf[EAC_BUF_LEN]; - int rxoff; - int rxlen; - int rxavail; - uint32_t txbuf[EAC_BUF_LEN]; - int txlen; - int txavail; - - int enable; - int rate; - - uint16_t config[4]; - - /* These need to be moved to the actual codec */ - QEMUSoundCard card; - SWVoiceIn *in_voice; - SWVoiceOut *out_voice; - int hw_enable; - } codec; - - struct { - uint8_t control; - uint16_t config; - } modem, bt; -}; - -static inline void omap_eac_interrupt_update(struct omap_eac_s *s) -{ - qemu_set_irq(s->irq, (s->codec.config[1] >> 14) & 1); /* AURDI */ -} - -static inline void omap_eac_in_dmarequest_update(struct omap_eac_s *s) -{ - qemu_set_irq(s->codec.rxdrq, (s->codec.rxavail || s->codec.rxlen) && - ((s->codec.config[1] >> 12) & 1)); /* DMAREN */ -} - -static inline void omap_eac_out_dmarequest_update(struct omap_eac_s *s) -{ - qemu_set_irq(s->codec.txdrq, s->codec.txlen < s->codec.txavail && - ((s->codec.config[1] >> 11) & 1)); /* DMAWEN */ -} - -static inline void omap_eac_in_refill(struct omap_eac_s *s) -{ - int left = MIN(EAC_BUF_LEN - s->codec.rxlen, s->codec.rxavail) << 2; - int start = ((s->codec.rxoff + s->codec.rxlen) & (EAC_BUF_LEN - 1)) << 2; - int leftwrap = MIN(left, (EAC_BUF_LEN << 2) - start); - int recv = 1; - uint8_t *buf = (uint8_t *) s->codec.rxbuf + start; - - left -= leftwrap; - start = 0; - while (leftwrap && (recv = AUD_read(s->codec.in_voice, buf + start, - leftwrap)) > 0) { /* Be defensive */ - start += recv; - leftwrap -= recv; - } - if (recv <= 0) - s->codec.rxavail = 0; - else - s->codec.rxavail -= start >> 2; - s->codec.rxlen += start >> 2; - - if (recv > 0 && left > 0) { - start = 0; - while (left && (recv = AUD_read(s->codec.in_voice, - (uint8_t *) s->codec.rxbuf + start, - left)) > 0) { /* Be defensive */ - start += recv; - left -= recv; - } - if (recv <= 0) - s->codec.rxavail = 0; - else - s->codec.rxavail -= start >> 2; - s->codec.rxlen += start >> 2; - } -} - -static inline void omap_eac_out_empty(struct omap_eac_s *s) -{ - int left = s->codec.txlen << 2; - int start = 0; - int sent = 1; - - while (left && (sent = AUD_write(s->codec.out_voice, - (uint8_t *) s->codec.txbuf + start, - left)) > 0) { /* Be defensive */ - start += sent; - left -= sent; - } - - if (!sent) { - s->codec.txavail = 0; - omap_eac_out_dmarequest_update(s); - } - - if (start) - s->codec.txlen = 0; -} - -static void omap_eac_in_cb(void *opaque, int avail_b) -{ - struct omap_eac_s *s = (struct omap_eac_s *) opaque; - - s->codec.rxavail = avail_b >> 2; - omap_eac_in_refill(s); - /* TODO: possibly discard current buffer if overrun */ - omap_eac_in_dmarequest_update(s); -} - -static void omap_eac_out_cb(void *opaque, int free_b) -{ - struct omap_eac_s *s = (struct omap_eac_s *) opaque; - - s->codec.txavail = free_b >> 2; - if (s->codec.txlen) - omap_eac_out_empty(s); - else - omap_eac_out_dmarequest_update(s); -} - -static void omap_eac_enable_update(struct omap_eac_s *s) -{ - s->codec.enable = !(s->codec.config[1] & 1) && /* EACPWD */ - (s->codec.config[1] & 2) && /* AUDEN */ - s->codec.hw_enable; -} - -static const int omap_eac_fsint[4] = { - 8000, - 11025, - 22050, - 44100, -}; - -static const int omap_eac_fsint2[8] = { - 8000, - 11025, - 22050, - 44100, - 48000, - 0, 0, 0, -}; - -static const int omap_eac_fsint3[16] = { - 8000, - 11025, - 16000, - 22050, - 24000, - 32000, - 44100, - 48000, - 0, 0, 0, 0, 0, 0, 0, 0, -}; - -static void omap_eac_rate_update(struct omap_eac_s *s) -{ - int fsint[3]; - - fsint[2] = (s->codec.config[3] >> 9) & 0xf; - fsint[1] = (s->codec.config[2] >> 0) & 0x7; - fsint[0] = (s->codec.config[0] >> 6) & 0x3; - if (fsint[2] < 0xf) - s->codec.rate = omap_eac_fsint3[fsint[2]]; - else if (fsint[1] < 0x7) - s->codec.rate = omap_eac_fsint2[fsint[1]]; - else - s->codec.rate = omap_eac_fsint[fsint[0]]; -} - -static void omap_eac_volume_update(struct omap_eac_s *s) -{ - /* TODO */ -} - -static void omap_eac_format_update(struct omap_eac_s *s) -{ - struct audsettings fmt; - - /* The hardware buffers at most one sample */ - if (s->codec.rxlen) - s->codec.rxlen = 1; - - if (s->codec.in_voice) { - AUD_set_active_in(s->codec.in_voice, 0); - AUD_close_in(&s->codec.card, s->codec.in_voice); - s->codec.in_voice = NULL; - } - if (s->codec.out_voice) { - omap_eac_out_empty(s); - AUD_set_active_out(s->codec.out_voice, 0); - AUD_close_out(&s->codec.card, s->codec.out_voice); - s->codec.out_voice = NULL; - s->codec.txavail = 0; - } - /* Discard what couldn't be written */ - s->codec.txlen = 0; - - omap_eac_enable_update(s); - if (!s->codec.enable) - return; - - omap_eac_rate_update(s); - fmt.endianness = ((s->codec.config[0] >> 8) & 1); /* LI_BI */ - fmt.nchannels = ((s->codec.config[0] >> 10) & 1) ? 2 : 1; /* MN_ST */ - fmt.freq = s->codec.rate; - /* TODO: signedness possibly depends on the CODEC hardware - or - * does I2S specify it? */ - /* All register writes are 16 bits so we we store 16-bit samples - * in the buffers regardless of AGCFR[B8_16] value. */ - fmt.fmt = AUD_FMT_U16; - - s->codec.in_voice = AUD_open_in(&s->codec.card, s->codec.in_voice, - "eac.codec.in", s, omap_eac_in_cb, &fmt); - s->codec.out_voice = AUD_open_out(&s->codec.card, s->codec.out_voice, - "eac.codec.out", s, omap_eac_out_cb, &fmt); - - omap_eac_volume_update(s); - - AUD_set_active_in(s->codec.in_voice, 1); - AUD_set_active_out(s->codec.out_voice, 1); -} - -static void omap_eac_reset(struct omap_eac_s *s) -{ - s->sysconfig = 0; - s->config[0] = 0x0c; - s->config[1] = 0x09; - s->config[2] = 0xab; - s->config[3] = 0x03; - s->control = 0x00; - s->address = 0x00; - s->data = 0x0000; - s->vtol = 0x00; - s->vtsl = 0x00; - s->mixer = 0x0000; - s->gain[0] = 0xe7e7; - s->gain[1] = 0x6767; - s->gain[2] = 0x6767; - s->gain[3] = 0x6767; - s->att = 0xce; - s->max[0] = 0; - s->max[1] = 0; - s->max[2] = 0; - s->max[3] = 0; - s->max[4] = 0; - s->max[5] = 0; - s->max[6] = 0; - - s->modem.control = 0x00; - s->modem.config = 0x0000; - s->bt.control = 0x00; - s->bt.config = 0x0000; - s->codec.config[0] = 0x0649; - s->codec.config[1] = 0x0000; - s->codec.config[2] = 0x0007; - s->codec.config[3] = 0x1ffc; - s->codec.rxoff = 0; - s->codec.rxlen = 0; - s->codec.txlen = 0; - s->codec.rxavail = 0; - s->codec.txavail = 0; - - omap_eac_format_update(s); - omap_eac_interrupt_update(s); -} - -static uint64_t omap_eac_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct omap_eac_s *s = (struct omap_eac_s *) opaque; - uint32_t ret; - - if (size != 2) { - return omap_badwidth_read16(opaque, addr); - } - - switch (addr) { - case 0x000: /* CPCFR1 */ - return s->config[0]; - case 0x004: /* CPCFR2 */ - return s->config[1]; - case 0x008: /* CPCFR3 */ - return s->config[2]; - case 0x00c: /* CPCFR4 */ - return s->config[3]; - - case 0x010: /* CPTCTL */ - return s->control | ((s->codec.rxavail + s->codec.rxlen > 0) << 7) | - ((s->codec.txlen < s->codec.txavail) << 5); - - case 0x014: /* CPTTADR */ - return s->address; - case 0x018: /* CPTDATL */ - return s->data & 0xff; - case 0x01c: /* CPTDATH */ - return s->data >> 8; - case 0x020: /* CPTVSLL */ - return s->vtol; - case 0x024: /* CPTVSLH */ - return s->vtsl | (3 << 5); /* CRDY1 | CRDY2 */ - case 0x040: /* MPCTR */ - return s->modem.control; - case 0x044: /* MPMCCFR */ - return s->modem.config; - case 0x060: /* BPCTR */ - return s->bt.control; - case 0x064: /* BPMCCFR */ - return s->bt.config; - case 0x080: /* AMSCFR */ - return s->mixer; - case 0x084: /* AMVCTR */ - return s->gain[0]; - case 0x088: /* AM1VCTR */ - return s->gain[1]; - case 0x08c: /* AM2VCTR */ - return s->gain[2]; - case 0x090: /* AM3VCTR */ - return s->gain[3]; - case 0x094: /* ASTCTR */ - return s->att; - case 0x098: /* APD1LCR */ - return s->max[0]; - case 0x09c: /* APD1RCR */ - return s->max[1]; - case 0x0a0: /* APD2LCR */ - return s->max[2]; - case 0x0a4: /* APD2RCR */ - return s->max[3]; - case 0x0a8: /* APD3LCR */ - return s->max[4]; - case 0x0ac: /* APD3RCR */ - return s->max[5]; - case 0x0b0: /* APD4R */ - return s->max[6]; - case 0x0b4: /* ADWR */ - /* This should be write-only? Docs list it as read-only. */ - return 0x0000; - case 0x0b8: /* ADRDR */ - if (likely(s->codec.rxlen > 1)) { - ret = s->codec.rxbuf[s->codec.rxoff ++]; - s->codec.rxlen --; - s->codec.rxoff &= EAC_BUF_LEN - 1; - return ret; - } else if (s->codec.rxlen) { - ret = s->codec.rxbuf[s->codec.rxoff ++]; - s->codec.rxlen --; - s->codec.rxoff &= EAC_BUF_LEN - 1; - if (s->codec.rxavail) - omap_eac_in_refill(s); - omap_eac_in_dmarequest_update(s); - return ret; - } - return 0x0000; - case 0x0bc: /* AGCFR */ - return s->codec.config[0]; - case 0x0c0: /* AGCTR */ - return s->codec.config[1] | ((s->codec.config[1] & 2) << 14); - case 0x0c4: /* AGCFR2 */ - return s->codec.config[2]; - case 0x0c8: /* AGCFR3 */ - return s->codec.config[3]; - case 0x0cc: /* MBPDMACTR */ - case 0x0d0: /* MPDDMARR */ - case 0x0d8: /* MPUDMARR */ - case 0x0e4: /* BPDDMARR */ - case 0x0ec: /* BPUDMARR */ - return 0x0000; - - case 0x100: /* VERSION_NUMBER */ - return 0x0010; - - case 0x104: /* SYSCONFIG */ - return s->sysconfig; - - case 0x108: /* SYSSTATUS */ - return 1 | 0xe; /* RESETDONE | stuff */ - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_eac_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct omap_eac_s *s = (struct omap_eac_s *) opaque; - - if (size != 2) { - omap_badwidth_write16(opaque, addr, value); - return; - } - - switch (addr) { - case 0x098: /* APD1LCR */ - case 0x09c: /* APD1RCR */ - case 0x0a0: /* APD2LCR */ - case 0x0a4: /* APD2RCR */ - case 0x0a8: /* APD3LCR */ - case 0x0ac: /* APD3RCR */ - case 0x0b0: /* APD4R */ - case 0x0b8: /* ADRDR */ - case 0x0d0: /* MPDDMARR */ - case 0x0d8: /* MPUDMARR */ - case 0x0e4: /* BPDDMARR */ - case 0x0ec: /* BPUDMARR */ - case 0x100: /* VERSION_NUMBER */ - case 0x108: /* SYSSTATUS */ - OMAP_RO_REG(addr); - return; - - case 0x000: /* CPCFR1 */ - s->config[0] = value & 0xff; - omap_eac_format_update(s); - break; - case 0x004: /* CPCFR2 */ - s->config[1] = value & 0xff; - omap_eac_format_update(s); - break; - case 0x008: /* CPCFR3 */ - s->config[2] = value & 0xff; - omap_eac_format_update(s); - break; - case 0x00c: /* CPCFR4 */ - s->config[3] = value & 0xff; - omap_eac_format_update(s); - break; - - case 0x010: /* CPTCTL */ - /* Assuming TXF and TXE bits are read-only... */ - s->control = value & 0x5f; - omap_eac_interrupt_update(s); - break; - - case 0x014: /* CPTTADR */ - s->address = value & 0xff; - break; - case 0x018: /* CPTDATL */ - s->data &= 0xff00; - s->data |= value & 0xff; - break; - case 0x01c: /* CPTDATH */ - s->data &= 0x00ff; - s->data |= value << 8; - break; - case 0x020: /* CPTVSLL */ - s->vtol = value & 0xf8; - break; - case 0x024: /* CPTVSLH */ - s->vtsl = value & 0x9f; - break; - case 0x040: /* MPCTR */ - s->modem.control = value & 0x8f; - break; - case 0x044: /* MPMCCFR */ - s->modem.config = value & 0x7fff; - break; - case 0x060: /* BPCTR */ - s->bt.control = value & 0x8f; - break; - case 0x064: /* BPMCCFR */ - s->bt.config = value & 0x7fff; - break; - case 0x080: /* AMSCFR */ - s->mixer = value & 0x0fff; - break; - case 0x084: /* AMVCTR */ - s->gain[0] = value & 0xffff; - break; - case 0x088: /* AM1VCTR */ - s->gain[1] = value & 0xff7f; - break; - case 0x08c: /* AM2VCTR */ - s->gain[2] = value & 0xff7f; - break; - case 0x090: /* AM3VCTR */ - s->gain[3] = value & 0xff7f; - break; - case 0x094: /* ASTCTR */ - s->att = value & 0xff; - break; - - case 0x0b4: /* ADWR */ - s->codec.txbuf[s->codec.txlen ++] = value; - if (unlikely(s->codec.txlen == EAC_BUF_LEN || - s->codec.txlen == s->codec.txavail)) { - if (s->codec.txavail) - omap_eac_out_empty(s); - /* Discard what couldn't be written */ - s->codec.txlen = 0; - } - break; - - case 0x0bc: /* AGCFR */ - s->codec.config[0] = value & 0x07ff; - omap_eac_format_update(s); - break; - case 0x0c0: /* AGCTR */ - s->codec.config[1] = value & 0x780f; - omap_eac_format_update(s); - break; - case 0x0c4: /* AGCFR2 */ - s->codec.config[2] = value & 0x003f; - omap_eac_format_update(s); - break; - case 0x0c8: /* AGCFR3 */ - s->codec.config[3] = value & 0xffff; - omap_eac_format_update(s); - break; - case 0x0cc: /* MBPDMACTR */ - case 0x0d4: /* MPDDMAWR */ - case 0x0e0: /* MPUDMAWR */ - case 0x0e8: /* BPDDMAWR */ - case 0x0f0: /* BPUDMAWR */ - break; - - case 0x104: /* SYSCONFIG */ - if (value & (1 << 1)) /* SOFTRESET */ - omap_eac_reset(s); - s->sysconfig = value & 0x31d; - break; - - default: - OMAP_BAD_REG(addr); - return; - } -} - -static const MemoryRegionOps omap_eac_ops = { - .read = omap_eac_read, - .write = omap_eac_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static struct omap_eac_s *omap_eac_init(struct omap_target_agent_s *ta, - qemu_irq irq, qemu_irq *drq, omap_clk fclk, omap_clk iclk) -{ - struct omap_eac_s *s = g_new0(struct omap_eac_s, 1); - - s->irq = irq; - s->codec.rxdrq = *drq ++; - s->codec.txdrq = *drq; - omap_eac_reset(s); - - AUD_register_card("OMAP EAC", &s->codec.card); - - memory_region_init_io(&s->iomem, NULL, &omap_eac_ops, s, "omap.eac", - omap_l4_region_size(ta, 0)); - omap_l4_attach(ta, 0, &s->iomem); - - return s; -} - -/* STI/XTI (emulation interface) console - reverse engineered only */ -struct omap_sti_s { - qemu_irq irq; - MemoryRegion iomem; - MemoryRegion iomem_fifo; - CharDriverState *chr; - - uint32_t sysconfig; - uint32_t systest; - uint32_t irqst; - uint32_t irqen; - uint32_t clkcontrol; - uint32_t serial_config; -}; - -#define STI_TRACE_CONSOLE_CHANNEL 239 -#define STI_TRACE_CONTROL_CHANNEL 253 - -static inline void omap_sti_interrupt_update(struct omap_sti_s *s) -{ - qemu_set_irq(s->irq, s->irqst & s->irqen); -} - -static void omap_sti_reset(struct omap_sti_s *s) -{ - s->sysconfig = 0; - s->irqst = 0; - s->irqen = 0; - s->clkcontrol = 0; - s->serial_config = 0; - - omap_sti_interrupt_update(s); -} - -static uint64_t omap_sti_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct omap_sti_s *s = (struct omap_sti_s *) opaque; - - if (size != 4) { - return omap_badwidth_read32(opaque, addr); - } - - switch (addr) { - case 0x00: /* STI_REVISION */ - return 0x10; - - case 0x10: /* STI_SYSCONFIG */ - return s->sysconfig; - - case 0x14: /* STI_SYSSTATUS / STI_RX_STATUS / XTI_SYSSTATUS */ - return 0x00; - - case 0x18: /* STI_IRQSTATUS */ - return s->irqst; - - case 0x1c: /* STI_IRQSETEN / STI_IRQCLREN */ - return s->irqen; - - case 0x24: /* STI_ER / STI_DR / XTI_TRACESELECT */ - case 0x28: /* STI_RX_DR / XTI_RXDATA */ - /* TODO */ - return 0; - - case 0x2c: /* STI_CLK_CTRL / XTI_SCLKCRTL */ - return s->clkcontrol; - - case 0x30: /* STI_SERIAL_CFG / XTI_SCONFIG */ - return s->serial_config; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_sti_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct omap_sti_s *s = (struct omap_sti_s *) opaque; - - if (size != 4) { - omap_badwidth_write32(opaque, addr, value); - return; - } - - switch (addr) { - case 0x00: /* STI_REVISION */ - case 0x14: /* STI_SYSSTATUS / STI_RX_STATUS / XTI_SYSSTATUS */ - OMAP_RO_REG(addr); - return; - - case 0x10: /* STI_SYSCONFIG */ - if (value & (1 << 1)) /* SOFTRESET */ - omap_sti_reset(s); - s->sysconfig = value & 0xfe; - break; - - case 0x18: /* STI_IRQSTATUS */ - s->irqst &= ~value; - omap_sti_interrupt_update(s); - break; - - case 0x1c: /* STI_IRQSETEN / STI_IRQCLREN */ - s->irqen = value & 0xffff; - omap_sti_interrupt_update(s); - break; - - case 0x2c: /* STI_CLK_CTRL / XTI_SCLKCRTL */ - s->clkcontrol = value & 0xff; - break; - - case 0x30: /* STI_SERIAL_CFG / XTI_SCONFIG */ - s->serial_config = value & 0xff; - break; - - case 0x24: /* STI_ER / STI_DR / XTI_TRACESELECT */ - case 0x28: /* STI_RX_DR / XTI_RXDATA */ - /* TODO */ - return; - - default: - OMAP_BAD_REG(addr); - return; - } -} - -static const MemoryRegionOps omap_sti_ops = { - .read = omap_sti_read, - .write = omap_sti_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static uint64_t omap_sti_fifo_read(void *opaque, hwaddr addr, - unsigned size) -{ - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_sti_fifo_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct omap_sti_s *s = (struct omap_sti_s *) opaque; - int ch = addr >> 6; - uint8_t byte = value; - - if (size != 1) { - omap_badwidth_write8(opaque, addr, size); - return; - } - - if (ch == STI_TRACE_CONTROL_CHANNEL) { - /* Flush channel <i>value</i>. */ - qemu_chr_fe_write(s->chr, (const uint8_t *) "\r", 1); - } else if (ch == STI_TRACE_CONSOLE_CHANNEL || 1) { - if (value == 0xc0 || value == 0xc3) { - /* Open channel <i>ch</i>. */ - } else if (value == 0x00) - qemu_chr_fe_write(s->chr, (const uint8_t *) "\n", 1); - else - qemu_chr_fe_write(s->chr, &byte, 1); - } -} - -static const MemoryRegionOps omap_sti_fifo_ops = { - .read = omap_sti_fifo_read, - .write = omap_sti_fifo_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static struct omap_sti_s *omap_sti_init(struct omap_target_agent_s *ta, - MemoryRegion *sysmem, - hwaddr channel_base, qemu_irq irq, omap_clk clk, - CharDriverState *chr) -{ - struct omap_sti_s *s = g_new0(struct omap_sti_s, 1); - - s->irq = irq; - omap_sti_reset(s); - - s->chr = chr ?: qemu_chr_new("null", "null", NULL); - - memory_region_init_io(&s->iomem, NULL, &omap_sti_ops, s, "omap.sti", - omap_l4_region_size(ta, 0)); - omap_l4_attach(ta, 0, &s->iomem); - - memory_region_init_io(&s->iomem_fifo, NULL, &omap_sti_fifo_ops, s, - "omap.sti.fifo", 0x10000); - memory_region_add_subregion(sysmem, channel_base, &s->iomem_fifo); - - return s; -} - -/* L4 Interconnect */ -#define L4TA(n) (n) -#define L4TAO(n) ((n) + 39) - -static const struct omap_l4_region_s omap_l4_region[125] = { - [ 1] = { 0x40800, 0x800, 32 }, /* Initiator agent */ - [ 2] = { 0x41000, 0x1000, 32 }, /* Link agent */ - [ 0] = { 0x40000, 0x800, 32 }, /* Address and protection */ - [ 3] = { 0x00000, 0x1000, 32 | 16 | 8 }, /* System Control and Pinout */ - [ 4] = { 0x01000, 0x1000, 32 | 16 | 8 }, /* L4TAO1 */ - [ 5] = { 0x04000, 0x1000, 32 | 16 }, /* 32K Timer */ - [ 6] = { 0x05000, 0x1000, 32 | 16 | 8 }, /* L4TAO2 */ - [ 7] = { 0x08000, 0x800, 32 }, /* PRCM Region A */ - [ 8] = { 0x08800, 0x800, 32 }, /* PRCM Region B */ - [ 9] = { 0x09000, 0x1000, 32 | 16 | 8 }, /* L4TAO */ - [ 10] = { 0x12000, 0x1000, 32 | 16 | 8 }, /* Test (BCM) */ - [ 11] = { 0x13000, 0x1000, 32 | 16 | 8 }, /* L4TA1 */ - [ 12] = { 0x14000, 0x1000, 32 }, /* Test/emulation (TAP) */ - [ 13] = { 0x15000, 0x1000, 32 | 16 | 8 }, /* L4TA2 */ - [ 14] = { 0x18000, 0x1000, 32 | 16 | 8 }, /* GPIO1 */ - [ 16] = { 0x1a000, 0x1000, 32 | 16 | 8 }, /* GPIO2 */ - [ 18] = { 0x1c000, 0x1000, 32 | 16 | 8 }, /* GPIO3 */ - [ 19] = { 0x1e000, 0x1000, 32 | 16 | 8 }, /* GPIO4 */ - [ 15] = { 0x19000, 0x1000, 32 | 16 | 8 }, /* Quad GPIO TOP */ - [ 17] = { 0x1b000, 0x1000, 32 | 16 | 8 }, /* L4TA3 */ - [ 20] = { 0x20000, 0x1000, 32 | 16 | 8 }, /* WD Timer 1 (Secure) */ - [ 22] = { 0x22000, 0x1000, 32 | 16 | 8 }, /* WD Timer 2 (OMAP) */ - [ 21] = { 0x21000, 0x1000, 32 | 16 | 8 }, /* Dual WD timer TOP */ - [ 23] = { 0x23000, 0x1000, 32 | 16 | 8 }, /* L4TA4 */ - [ 24] = { 0x28000, 0x1000, 32 | 16 | 8 }, /* GP Timer 1 */ - [ 25] = { 0x29000, 0x1000, 32 | 16 | 8 }, /* L4TA7 */ - [ 26] = { 0x48000, 0x2000, 32 | 16 | 8 }, /* Emulation (ARM11ETB) */ - [ 27] = { 0x4a000, 0x1000, 32 | 16 | 8 }, /* L4TA9 */ - [ 28] = { 0x50000, 0x400, 32 | 16 | 8 }, /* Display top */ - [ 29] = { 0x50400, 0x400, 32 | 16 | 8 }, /* Display control */ - [ 30] = { 0x50800, 0x400, 32 | 16 | 8 }, /* Display RFBI */ - [ 31] = { 0x50c00, 0x400, 32 | 16 | 8 }, /* Display encoder */ - [ 32] = { 0x51000, 0x1000, 32 | 16 | 8 }, /* L4TA10 */ - [ 33] = { 0x52000, 0x400, 32 | 16 | 8 }, /* Camera top */ - [ 34] = { 0x52400, 0x400, 32 | 16 | 8 }, /* Camera core */ - [ 35] = { 0x52800, 0x400, 32 | 16 | 8 }, /* Camera DMA */ - [ 36] = { 0x52c00, 0x400, 32 | 16 | 8 }, /* Camera MMU */ - [ 37] = { 0x53000, 0x1000, 32 | 16 | 8 }, /* L4TA11 */ - [ 38] = { 0x56000, 0x1000, 32 | 16 | 8 }, /* sDMA */ - [ 39] = { 0x57000, 0x1000, 32 | 16 | 8 }, /* L4TA12 */ - [ 40] = { 0x58000, 0x1000, 32 | 16 | 8 }, /* SSI top */ - [ 41] = { 0x59000, 0x1000, 32 | 16 | 8 }, /* SSI GDD */ - [ 42] = { 0x5a000, 0x1000, 32 | 16 | 8 }, /* SSI Port1 */ - [ 43] = { 0x5b000, 0x1000, 32 | 16 | 8 }, /* SSI Port2 */ - [ 44] = { 0x5c000, 0x1000, 32 | 16 | 8 }, /* L4TA13 */ - [ 45] = { 0x5e000, 0x1000, 32 | 16 | 8 }, /* USB OTG */ - [ 46] = { 0x5f000, 0x1000, 32 | 16 | 8 }, /* L4TAO4 */ - [ 47] = { 0x60000, 0x1000, 32 | 16 | 8 }, /* Emulation (WIN_TRACER1SDRC) */ - [ 48] = { 0x61000, 0x1000, 32 | 16 | 8 }, /* L4TA14 */ - [ 49] = { 0x62000, 0x1000, 32 | 16 | 8 }, /* Emulation (WIN_TRACER2GPMC) */ - [ 50] = { 0x63000, 0x1000, 32 | 16 | 8 }, /* L4TA15 */ - [ 51] = { 0x64000, 0x1000, 32 | 16 | 8 }, /* Emulation (WIN_TRACER3OCM) */ - [ 52] = { 0x65000, 0x1000, 32 | 16 | 8 }, /* L4TA16 */ - [ 53] = { 0x66000, 0x300, 32 | 16 | 8 }, /* Emulation (WIN_TRACER4L4) */ - [ 54] = { 0x67000, 0x1000, 32 | 16 | 8 }, /* L4TA17 */ - [ 55] = { 0x68000, 0x1000, 32 | 16 | 8 }, /* Emulation (XTI) */ - [ 56] = { 0x69000, 0x1000, 32 | 16 | 8 }, /* L4TA18 */ - [ 57] = { 0x6a000, 0x1000, 16 | 8 }, /* UART1 */ - [ 58] = { 0x6b000, 0x1000, 32 | 16 | 8 }, /* L4TA19 */ - [ 59] = { 0x6c000, 0x1000, 16 | 8 }, /* UART2 */ - [ 60] = { 0x6d000, 0x1000, 32 | 16 | 8 }, /* L4TA20 */ - [ 61] = { 0x6e000, 0x1000, 16 | 8 }, /* UART3 */ - [ 62] = { 0x6f000, 0x1000, 32 | 16 | 8 }, /* L4TA21 */ - [ 63] = { 0x70000, 0x1000, 16 }, /* I2C1 */ - [ 64] = { 0x71000, 0x1000, 32 | 16 | 8 }, /* L4TAO5 */ - [ 65] = { 0x72000, 0x1000, 16 }, /* I2C2 */ - [ 66] = { 0x73000, 0x1000, 32 | 16 | 8 }, /* L4TAO6 */ - [ 67] = { 0x74000, 0x1000, 16 }, /* McBSP1 */ - [ 68] = { 0x75000, 0x1000, 32 | 16 | 8 }, /* L4TAO7 */ - [ 69] = { 0x76000, 0x1000, 16 }, /* McBSP2 */ - [ 70] = { 0x77000, 0x1000, 32 | 16 | 8 }, /* L4TAO8 */ - [ 71] = { 0x24000, 0x1000, 32 | 16 | 8 }, /* WD Timer 3 (DSP) */ - [ 72] = { 0x25000, 0x1000, 32 | 16 | 8 }, /* L4TA5 */ - [ 73] = { 0x26000, 0x1000, 32 | 16 | 8 }, /* WD Timer 4 (IVA) */ - [ 74] = { 0x27000, 0x1000, 32 | 16 | 8 }, /* L4TA6 */ - [ 75] = { 0x2a000, 0x1000, 32 | 16 | 8 }, /* GP Timer 2 */ - [ 76] = { 0x2b000, 0x1000, 32 | 16 | 8 }, /* L4TA8 */ - [ 77] = { 0x78000, 0x1000, 32 | 16 | 8 }, /* GP Timer 3 */ - [ 78] = { 0x79000, 0x1000, 32 | 16 | 8 }, /* L4TA22 */ - [ 79] = { 0x7a000, 0x1000, 32 | 16 | 8 }, /* GP Timer 4 */ - [ 80] = { 0x7b000, 0x1000, 32 | 16 | 8 }, /* L4TA23 */ - [ 81] = { 0x7c000, 0x1000, 32 | 16 | 8 }, /* GP Timer 5 */ - [ 82] = { 0x7d000, 0x1000, 32 | 16 | 8 }, /* L4TA24 */ - [ 83] = { 0x7e000, 0x1000, 32 | 16 | 8 }, /* GP Timer 6 */ - [ 84] = { 0x7f000, 0x1000, 32 | 16 | 8 }, /* L4TA25 */ - [ 85] = { 0x80000, 0x1000, 32 | 16 | 8 }, /* GP Timer 7 */ - [ 86] = { 0x81000, 0x1000, 32 | 16 | 8 }, /* L4TA26 */ - [ 87] = { 0x82000, 0x1000, 32 | 16 | 8 }, /* GP Timer 8 */ - [ 88] = { 0x83000, 0x1000, 32 | 16 | 8 }, /* L4TA27 */ - [ 89] = { 0x84000, 0x1000, 32 | 16 | 8 }, /* GP Timer 9 */ - [ 90] = { 0x85000, 0x1000, 32 | 16 | 8 }, /* L4TA28 */ - [ 91] = { 0x86000, 0x1000, 32 | 16 | 8 }, /* GP Timer 10 */ - [ 92] = { 0x87000, 0x1000, 32 | 16 | 8 }, /* L4TA29 */ - [ 93] = { 0x88000, 0x1000, 32 | 16 | 8 }, /* GP Timer 11 */ - [ 94] = { 0x89000, 0x1000, 32 | 16 | 8 }, /* L4TA30 */ - [ 95] = { 0x8a000, 0x1000, 32 | 16 | 8 }, /* GP Timer 12 */ - [ 96] = { 0x8b000, 0x1000, 32 | 16 | 8 }, /* L4TA31 */ - [ 97] = { 0x90000, 0x1000, 16 }, /* EAC */ - [ 98] = { 0x91000, 0x1000, 32 | 16 | 8 }, /* L4TA32 */ - [ 99] = { 0x92000, 0x1000, 16 }, /* FAC */ - [100] = { 0x93000, 0x1000, 32 | 16 | 8 }, /* L4TA33 */ - [101] = { 0x94000, 0x1000, 32 | 16 | 8 }, /* IPC (MAILBOX) */ - [102] = { 0x95000, 0x1000, 32 | 16 | 8 }, /* L4TA34 */ - [103] = { 0x98000, 0x1000, 32 | 16 | 8 }, /* SPI1 */ - [104] = { 0x99000, 0x1000, 32 | 16 | 8 }, /* L4TA35 */ - [105] = { 0x9a000, 0x1000, 32 | 16 | 8 }, /* SPI2 */ - [106] = { 0x9b000, 0x1000, 32 | 16 | 8 }, /* L4TA36 */ - [107] = { 0x9c000, 0x1000, 16 | 8 }, /* MMC SDIO */ - [108] = { 0x9d000, 0x1000, 32 | 16 | 8 }, /* L4TAO9 */ - [109] = { 0x9e000, 0x1000, 32 | 16 | 8 }, /* MS_PRO */ - [110] = { 0x9f000, 0x1000, 32 | 16 | 8 }, /* L4TAO10 */ - [111] = { 0xa0000, 0x1000, 32 }, /* RNG */ - [112] = { 0xa1000, 0x1000, 32 | 16 | 8 }, /* L4TAO11 */ - [113] = { 0xa2000, 0x1000, 32 }, /* DES3DES */ - [114] = { 0xa3000, 0x1000, 32 | 16 | 8 }, /* L4TAO12 */ - [115] = { 0xa4000, 0x1000, 32 }, /* SHA1MD5 */ - [116] = { 0xa5000, 0x1000, 32 | 16 | 8 }, /* L4TAO13 */ - [117] = { 0xa6000, 0x1000, 32 }, /* AES */ - [118] = { 0xa7000, 0x1000, 32 | 16 | 8 }, /* L4TA37 */ - [119] = { 0xa8000, 0x2000, 32 }, /* PKA */ - [120] = { 0xaa000, 0x1000, 32 | 16 | 8 }, /* L4TA38 */ - [121] = { 0xb0000, 0x1000, 32 }, /* MG */ - [122] = { 0xb1000, 0x1000, 32 | 16 | 8 }, - [123] = { 0xb2000, 0x1000, 32 }, /* HDQ/1-Wire */ - [124] = { 0xb3000, 0x1000, 32 | 16 | 8 }, /* L4TA39 */ -}; - -static const struct omap_l4_agent_info_s omap_l4_agent_info[54] = { - { 0, 0, 3, 2 }, /* L4IA initiatior agent */ - { L4TAO(1), 3, 2, 1 }, /* Control and pinout module */ - { L4TAO(2), 5, 2, 1 }, /* 32K timer */ - { L4TAO(3), 7, 3, 2 }, /* PRCM */ - { L4TA(1), 10, 2, 1 }, /* BCM */ - { L4TA(2), 12, 2, 1 }, /* Test JTAG */ - { L4TA(3), 14, 6, 3 }, /* Quad GPIO */ - { L4TA(4), 20, 4, 3 }, /* WD timer 1/2 */ - { L4TA(7), 24, 2, 1 }, /* GP timer 1 */ - { L4TA(9), 26, 2, 1 }, /* ATM11 ETB */ - { L4TA(10), 28, 5, 4 }, /* Display subsystem */ - { L4TA(11), 33, 5, 4 }, /* Camera subsystem */ - { L4TA(12), 38, 2, 1 }, /* sDMA */ - { L4TA(13), 40, 5, 4 }, /* SSI */ - { L4TAO(4), 45, 2, 1 }, /* USB */ - { L4TA(14), 47, 2, 1 }, /* Win Tracer1 */ - { L4TA(15), 49, 2, 1 }, /* Win Tracer2 */ - { L4TA(16), 51, 2, 1 }, /* Win Tracer3 */ - { L4TA(17), 53, 2, 1 }, /* Win Tracer4 */ - { L4TA(18), 55, 2, 1 }, /* XTI */ - { L4TA(19), 57, 2, 1 }, /* UART1 */ - { L4TA(20), 59, 2, 1 }, /* UART2 */ - { L4TA(21), 61, 2, 1 }, /* UART3 */ - { L4TAO(5), 63, 2, 1 }, /* I2C1 */ - { L4TAO(6), 65, 2, 1 }, /* I2C2 */ - { L4TAO(7), 67, 2, 1 }, /* McBSP1 */ - { L4TAO(8), 69, 2, 1 }, /* McBSP2 */ - { L4TA(5), 71, 2, 1 }, /* WD Timer 3 (DSP) */ - { L4TA(6), 73, 2, 1 }, /* WD Timer 4 (IVA) */ - { L4TA(8), 75, 2, 1 }, /* GP Timer 2 */ - { L4TA(22), 77, 2, 1 }, /* GP Timer 3 */ - { L4TA(23), 79, 2, 1 }, /* GP Timer 4 */ - { L4TA(24), 81, 2, 1 }, /* GP Timer 5 */ - { L4TA(25), 83, 2, 1 }, /* GP Timer 6 */ - { L4TA(26), 85, 2, 1 }, /* GP Timer 7 */ - { L4TA(27), 87, 2, 1 }, /* GP Timer 8 */ - { L4TA(28), 89, 2, 1 }, /* GP Timer 9 */ - { L4TA(29), 91, 2, 1 }, /* GP Timer 10 */ - { L4TA(30), 93, 2, 1 }, /* GP Timer 11 */ - { L4TA(31), 95, 2, 1 }, /* GP Timer 12 */ - { L4TA(32), 97, 2, 1 }, /* EAC */ - { L4TA(33), 99, 2, 1 }, /* FAC */ - { L4TA(34), 101, 2, 1 }, /* IPC */ - { L4TA(35), 103, 2, 1 }, /* SPI1 */ - { L4TA(36), 105, 2, 1 }, /* SPI2 */ - { L4TAO(9), 107, 2, 1 }, /* MMC SDIO */ - { L4TAO(10), 109, 2, 1 }, - { L4TAO(11), 111, 2, 1 }, /* RNG */ - { L4TAO(12), 113, 2, 1 }, /* DES3DES */ - { L4TAO(13), 115, 2, 1 }, /* SHA1MD5 */ - { L4TA(37), 117, 2, 1 }, /* AES */ - { L4TA(38), 119, 2, 1 }, /* PKA */ - { -1, 121, 2, 1 }, - { L4TA(39), 123, 2, 1 }, /* HDQ/1-Wire */ -}; - -#define omap_l4ta(bus, cs) \ - omap_l4ta_get(bus, omap_l4_region, omap_l4_agent_info, L4TA(cs)) -#define omap_l4tao(bus, cs) \ - omap_l4ta_get(bus, omap_l4_region, omap_l4_agent_info, L4TAO(cs)) - -/* Power, Reset, and Clock Management */ -struct omap_prcm_s { - qemu_irq irq[3]; - struct omap_mpu_state_s *mpu; - MemoryRegion iomem0; - MemoryRegion iomem1; - - uint32_t irqst[3]; - uint32_t irqen[3]; - - uint32_t sysconfig; - uint32_t voltctrl; - uint32_t scratch[20]; - - uint32_t clksrc[1]; - uint32_t clkout[1]; - uint32_t clkemul[1]; - uint32_t clkpol[1]; - uint32_t clksel[8]; - uint32_t clken[12]; - uint32_t clkctrl[4]; - uint32_t clkidle[7]; - uint32_t setuptime[2]; - - uint32_t wkup[3]; - uint32_t wken[3]; - uint32_t wkst[3]; - uint32_t rst[4]; - uint32_t rstctrl[1]; - uint32_t power[4]; - uint32_t rsttime_wkup; - - uint32_t ev; - uint32_t evtime[2]; - - int dpll_lock, apll_lock[2]; -}; - -static void omap_prcm_int_update(struct omap_prcm_s *s, int dom) -{ - qemu_set_irq(s->irq[dom], s->irqst[dom] & s->irqen[dom]); - /* XXX or is the mask applied before PRCM_IRQSTATUS_* ? */ -} - -static uint64_t omap_prcm_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct omap_prcm_s *s = (struct omap_prcm_s *) opaque; - uint32_t ret; - - if (size != 4) { - return omap_badwidth_read32(opaque, addr); - } - - switch (addr) { - case 0x000: /* PRCM_REVISION */ - return 0x10; - - case 0x010: /* PRCM_SYSCONFIG */ - return s->sysconfig; - - case 0x018: /* PRCM_IRQSTATUS_MPU */ - return s->irqst[0]; - - case 0x01c: /* PRCM_IRQENABLE_MPU */ - return s->irqen[0]; - - case 0x050: /* PRCM_VOLTCTRL */ - return s->voltctrl; - case 0x054: /* PRCM_VOLTST */ - return s->voltctrl & 3; - - case 0x060: /* PRCM_CLKSRC_CTRL */ - return s->clksrc[0]; - case 0x070: /* PRCM_CLKOUT_CTRL */ - return s->clkout[0]; - case 0x078: /* PRCM_CLKEMUL_CTRL */ - return s->clkemul[0]; - case 0x080: /* PRCM_CLKCFG_CTRL */ - case 0x084: /* PRCM_CLKCFG_STATUS */ - return 0; - - case 0x090: /* PRCM_VOLTSETUP */ - return s->setuptime[0]; - - case 0x094: /* PRCM_CLKSSETUP */ - return s->setuptime[1]; - - case 0x098: /* PRCM_POLCTRL */ - return s->clkpol[0]; - - case 0x0b0: /* GENERAL_PURPOSE1 */ - case 0x0b4: /* GENERAL_PURPOSE2 */ - case 0x0b8: /* GENERAL_PURPOSE3 */ - case 0x0bc: /* GENERAL_PURPOSE4 */ - case 0x0c0: /* GENERAL_PURPOSE5 */ - case 0x0c4: /* GENERAL_PURPOSE6 */ - case 0x0c8: /* GENERAL_PURPOSE7 */ - case 0x0cc: /* GENERAL_PURPOSE8 */ - case 0x0d0: /* GENERAL_PURPOSE9 */ - case 0x0d4: /* GENERAL_PURPOSE10 */ - case 0x0d8: /* GENERAL_PURPOSE11 */ - case 0x0dc: /* GENERAL_PURPOSE12 */ - case 0x0e0: /* GENERAL_PURPOSE13 */ - case 0x0e4: /* GENERAL_PURPOSE14 */ - case 0x0e8: /* GENERAL_PURPOSE15 */ - case 0x0ec: /* GENERAL_PURPOSE16 */ - case 0x0f0: /* GENERAL_PURPOSE17 */ - case 0x0f4: /* GENERAL_PURPOSE18 */ - case 0x0f8: /* GENERAL_PURPOSE19 */ - case 0x0fc: /* GENERAL_PURPOSE20 */ - return s->scratch[(addr - 0xb0) >> 2]; - - case 0x140: /* CM_CLKSEL_MPU */ - return s->clksel[0]; - case 0x148: /* CM_CLKSTCTRL_MPU */ - return s->clkctrl[0]; - - case 0x158: /* RM_RSTST_MPU */ - return s->rst[0]; - case 0x1c8: /* PM_WKDEP_MPU */ - return s->wkup[0]; - case 0x1d4: /* PM_EVGENCTRL_MPU */ - return s->ev; - case 0x1d8: /* PM_EVEGENONTIM_MPU */ - return s->evtime[0]; - case 0x1dc: /* PM_EVEGENOFFTIM_MPU */ - return s->evtime[1]; - case 0x1e0: /* PM_PWSTCTRL_MPU */ - return s->power[0]; - case 0x1e4: /* PM_PWSTST_MPU */ - return 0; - - case 0x200: /* CM_FCLKEN1_CORE */ - return s->clken[0]; - case 0x204: /* CM_FCLKEN2_CORE */ - return s->clken[1]; - case 0x210: /* CM_ICLKEN1_CORE */ - return s->clken[2]; - case 0x214: /* CM_ICLKEN2_CORE */ - return s->clken[3]; - case 0x21c: /* CM_ICLKEN4_CORE */ - return s->clken[4]; - - case 0x220: /* CM_IDLEST1_CORE */ - /* TODO: check the actual iclk status */ - return 0x7ffffff9; - case 0x224: /* CM_IDLEST2_CORE */ - /* TODO: check the actual iclk status */ - return 0x00000007; - case 0x22c: /* CM_IDLEST4_CORE */ - /* TODO: check the actual iclk status */ - return 0x0000001f; - - case 0x230: /* CM_AUTOIDLE1_CORE */ - return s->clkidle[0]; - case 0x234: /* CM_AUTOIDLE2_CORE */ - return s->clkidle[1]; - case 0x238: /* CM_AUTOIDLE3_CORE */ - return s->clkidle[2]; - case 0x23c: /* CM_AUTOIDLE4_CORE */ - return s->clkidle[3]; - - case 0x240: /* CM_CLKSEL1_CORE */ - return s->clksel[1]; - case 0x244: /* CM_CLKSEL2_CORE */ - return s->clksel[2]; - - case 0x248: /* CM_CLKSTCTRL_CORE */ - return s->clkctrl[1]; - - case 0x2a0: /* PM_WKEN1_CORE */ - return s->wken[0]; - case 0x2a4: /* PM_WKEN2_CORE */ - return s->wken[1]; - - case 0x2b0: /* PM_WKST1_CORE */ - return s->wkst[0]; - case 0x2b4: /* PM_WKST2_CORE */ - return s->wkst[1]; - case 0x2c8: /* PM_WKDEP_CORE */ - return 0x1e; - - case 0x2e0: /* PM_PWSTCTRL_CORE */ - return s->power[1]; - case 0x2e4: /* PM_PWSTST_CORE */ - return 0x000030 | (s->power[1] & 0xfc00); - - case 0x300: /* CM_FCLKEN_GFX */ - return s->clken[5]; - case 0x310: /* CM_ICLKEN_GFX */ - return s->clken[6]; - case 0x320: /* CM_IDLEST_GFX */ - /* TODO: check the actual iclk status */ - return 0x00000001; - case 0x340: /* CM_CLKSEL_GFX */ - return s->clksel[3]; - case 0x348: /* CM_CLKSTCTRL_GFX */ - return s->clkctrl[2]; - case 0x350: /* RM_RSTCTRL_GFX */ - return s->rstctrl[0]; - case 0x358: /* RM_RSTST_GFX */ - return s->rst[1]; - case 0x3c8: /* PM_WKDEP_GFX */ - return s->wkup[1]; - - case 0x3e0: /* PM_PWSTCTRL_GFX */ - return s->power[2]; - case 0x3e4: /* PM_PWSTST_GFX */ - return s->power[2] & 3; - - case 0x400: /* CM_FCLKEN_WKUP */ - return s->clken[7]; - case 0x410: /* CM_ICLKEN_WKUP */ - return s->clken[8]; - case 0x420: /* CM_IDLEST_WKUP */ - /* TODO: check the actual iclk status */ - return 0x0000003f; - case 0x430: /* CM_AUTOIDLE_WKUP */ - return s->clkidle[4]; - case 0x440: /* CM_CLKSEL_WKUP */ - return s->clksel[4]; - case 0x450: /* RM_RSTCTRL_WKUP */ - return 0; - case 0x454: /* RM_RSTTIME_WKUP */ - return s->rsttime_wkup; - case 0x458: /* RM_RSTST_WKUP */ - return s->rst[2]; - case 0x4a0: /* PM_WKEN_WKUP */ - return s->wken[2]; - case 0x4b0: /* PM_WKST_WKUP */ - return s->wkst[2]; - - case 0x500: /* CM_CLKEN_PLL */ - return s->clken[9]; - case 0x520: /* CM_IDLEST_CKGEN */ - ret = 0x0000070 | (s->apll_lock[0] << 9) | (s->apll_lock[1] << 8); - if (!(s->clksel[6] & 3)) - /* Core uses 32-kHz clock */ - ret |= 3 << 0; - else if (!s->dpll_lock) - /* DPLL not locked, core uses ref_clk */ - ret |= 1 << 0; - else - /* Core uses DPLL */ - ret |= 2 << 0; - return ret; - case 0x530: /* CM_AUTOIDLE_PLL */ - return s->clkidle[5]; - case 0x540: /* CM_CLKSEL1_PLL */ - return s->clksel[5]; - case 0x544: /* CM_CLKSEL2_PLL */ - return s->clksel[6]; - - case 0x800: /* CM_FCLKEN_DSP */ - return s->clken[10]; - case 0x810: /* CM_ICLKEN_DSP */ - return s->clken[11]; - case 0x820: /* CM_IDLEST_DSP */ - /* TODO: check the actual iclk status */ - return 0x00000103; - case 0x830: /* CM_AUTOIDLE_DSP */ - return s->clkidle[6]; - case 0x840: /* CM_CLKSEL_DSP */ - return s->clksel[7]; - case 0x848: /* CM_CLKSTCTRL_DSP */ - return s->clkctrl[3]; - case 0x850: /* RM_RSTCTRL_DSP */ - return 0; - case 0x858: /* RM_RSTST_DSP */ - return s->rst[3]; - case 0x8c8: /* PM_WKDEP_DSP */ - return s->wkup[2]; - case 0x8e0: /* PM_PWSTCTRL_DSP */ - return s->power[3]; - case 0x8e4: /* PM_PWSTST_DSP */ - return 0x008030 | (s->power[3] & 0x3003); - - case 0x8f0: /* PRCM_IRQSTATUS_DSP */ - return s->irqst[1]; - case 0x8f4: /* PRCM_IRQENABLE_DSP */ - return s->irqen[1]; - - case 0x8f8: /* PRCM_IRQSTATUS_IVA */ - return s->irqst[2]; - case 0x8fc: /* PRCM_IRQENABLE_IVA */ - return s->irqen[2]; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_prcm_apll_update(struct omap_prcm_s *s) -{ - int mode[2]; - - mode[0] = (s->clken[9] >> 6) & 3; - s->apll_lock[0] = (mode[0] == 3); - mode[1] = (s->clken[9] >> 2) & 3; - s->apll_lock[1] = (mode[1] == 3); - /* TODO: update clocks */ - - if (mode[0] == 1 || mode[0] == 2 || mode[1] == 1 || mode[1] == 2) - fprintf(stderr, "%s: bad EN_54M_PLL or bad EN_96M_PLL\n", - __FUNCTION__); -} - -static void omap_prcm_dpll_update(struct omap_prcm_s *s) -{ - omap_clk dpll = omap_findclk(s->mpu, "dpll"); - omap_clk dpll_x2 = omap_findclk(s->mpu, "dpll"); - omap_clk core = omap_findclk(s->mpu, "core_clk"); - int mode = (s->clken[9] >> 0) & 3; - int mult, div; - - mult = (s->clksel[5] >> 12) & 0x3ff; - div = (s->clksel[5] >> 8) & 0xf; - if (mult == 0 || mult == 1) - mode = 1; /* Bypass */ - - s->dpll_lock = 0; - switch (mode) { - case 0: - fprintf(stderr, "%s: bad EN_DPLL\n", __FUNCTION__); - break; - case 1: /* Low-power bypass mode (Default) */ - case 2: /* Fast-relock bypass mode */ - omap_clk_setrate(dpll, 1, 1); - omap_clk_setrate(dpll_x2, 1, 1); - break; - case 3: /* Lock mode */ - s->dpll_lock = 1; /* After 20 FINT cycles (ref_clk / (div + 1)). */ - - omap_clk_setrate(dpll, div + 1, mult); - omap_clk_setrate(dpll_x2, div + 1, mult * 2); - break; - } - - switch ((s->clksel[6] >> 0) & 3) { - case 0: - omap_clk_reparent(core, omap_findclk(s->mpu, "clk32-kHz")); - break; - case 1: - omap_clk_reparent(core, dpll); - break; - case 2: - /* Default */ - omap_clk_reparent(core, dpll_x2); - break; - case 3: - fprintf(stderr, "%s: bad CORE_CLK_SRC\n", __FUNCTION__); - break; - } -} - -static void omap_prcm_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct omap_prcm_s *s = (struct omap_prcm_s *) opaque; - - if (size != 4) { - omap_badwidth_write32(opaque, addr, value); - return; - } - - switch (addr) { - case 0x000: /* PRCM_REVISION */ - case 0x054: /* PRCM_VOLTST */ - case 0x084: /* PRCM_CLKCFG_STATUS */ - case 0x1e4: /* PM_PWSTST_MPU */ - case 0x220: /* CM_IDLEST1_CORE */ - case 0x224: /* CM_IDLEST2_CORE */ - case 0x22c: /* CM_IDLEST4_CORE */ - case 0x2c8: /* PM_WKDEP_CORE */ - case 0x2e4: /* PM_PWSTST_CORE */ - case 0x320: /* CM_IDLEST_GFX */ - case 0x3e4: /* PM_PWSTST_GFX */ - case 0x420: /* CM_IDLEST_WKUP */ - case 0x520: /* CM_IDLEST_CKGEN */ - case 0x820: /* CM_IDLEST_DSP */ - case 0x8e4: /* PM_PWSTST_DSP */ - OMAP_RO_REG(addr); - return; - - case 0x010: /* PRCM_SYSCONFIG */ - s->sysconfig = value & 1; - break; - - case 0x018: /* PRCM_IRQSTATUS_MPU */ - s->irqst[0] &= ~value; - omap_prcm_int_update(s, 0); - break; - case 0x01c: /* PRCM_IRQENABLE_MPU */ - s->irqen[0] = value & 0x3f; - omap_prcm_int_update(s, 0); - break; - - case 0x050: /* PRCM_VOLTCTRL */ - s->voltctrl = value & 0xf1c3; - break; - - case 0x060: /* PRCM_CLKSRC_CTRL */ - s->clksrc[0] = value & 0xdb; - /* TODO update clocks */ - break; - - case 0x070: /* PRCM_CLKOUT_CTRL */ - s->clkout[0] = value & 0xbbbb; - /* TODO update clocks */ - break; - - case 0x078: /* PRCM_CLKEMUL_CTRL */ - s->clkemul[0] = value & 1; - /* TODO update clocks */ - break; - - case 0x080: /* PRCM_CLKCFG_CTRL */ - break; - - case 0x090: /* PRCM_VOLTSETUP */ - s->setuptime[0] = value & 0xffff; - break; - case 0x094: /* PRCM_CLKSSETUP */ - s->setuptime[1] = value & 0xffff; - break; - - case 0x098: /* PRCM_POLCTRL */ - s->clkpol[0] = value & 0x701; - break; - - case 0x0b0: /* GENERAL_PURPOSE1 */ - case 0x0b4: /* GENERAL_PURPOSE2 */ - case 0x0b8: /* GENERAL_PURPOSE3 */ - case 0x0bc: /* GENERAL_PURPOSE4 */ - case 0x0c0: /* GENERAL_PURPOSE5 */ - case 0x0c4: /* GENERAL_PURPOSE6 */ - case 0x0c8: /* GENERAL_PURPOSE7 */ - case 0x0cc: /* GENERAL_PURPOSE8 */ - case 0x0d0: /* GENERAL_PURPOSE9 */ - case 0x0d4: /* GENERAL_PURPOSE10 */ - case 0x0d8: /* GENERAL_PURPOSE11 */ - case 0x0dc: /* GENERAL_PURPOSE12 */ - case 0x0e0: /* GENERAL_PURPOSE13 */ - case 0x0e4: /* GENERAL_PURPOSE14 */ - case 0x0e8: /* GENERAL_PURPOSE15 */ - case 0x0ec: /* GENERAL_PURPOSE16 */ - case 0x0f0: /* GENERAL_PURPOSE17 */ - case 0x0f4: /* GENERAL_PURPOSE18 */ - case 0x0f8: /* GENERAL_PURPOSE19 */ - case 0x0fc: /* GENERAL_PURPOSE20 */ - s->scratch[(addr - 0xb0) >> 2] = value; - break; - - case 0x140: /* CM_CLKSEL_MPU */ - s->clksel[0] = value & 0x1f; - /* TODO update clocks */ - break; - case 0x148: /* CM_CLKSTCTRL_MPU */ - s->clkctrl[0] = value & 0x1f; - break; - - case 0x158: /* RM_RSTST_MPU */ - s->rst[0] &= ~value; - break; - case 0x1c8: /* PM_WKDEP_MPU */ - s->wkup[0] = value & 0x15; - break; - - case 0x1d4: /* PM_EVGENCTRL_MPU */ - s->ev = value & 0x1f; - break; - case 0x1d8: /* PM_EVEGENONTIM_MPU */ - s->evtime[0] = value; - break; - case 0x1dc: /* PM_EVEGENOFFTIM_MPU */ - s->evtime[1] = value; - break; - - case 0x1e0: /* PM_PWSTCTRL_MPU */ - s->power[0] = value & 0xc0f; - break; - - case 0x200: /* CM_FCLKEN1_CORE */ - s->clken[0] = value & 0xbfffffff; - /* TODO update clocks */ - /* The EN_EAC bit only gets/puts func_96m_clk. */ - break; - case 0x204: /* CM_FCLKEN2_CORE */ - s->clken[1] = value & 0x00000007; - /* TODO update clocks */ - break; - case 0x210: /* CM_ICLKEN1_CORE */ - s->clken[2] = value & 0xfffffff9; - /* TODO update clocks */ - /* The EN_EAC bit only gets/puts core_l4_iclk. */ - break; - case 0x214: /* CM_ICLKEN2_CORE */ - s->clken[3] = value & 0x00000007; - /* TODO update clocks */ - break; - case 0x21c: /* CM_ICLKEN4_CORE */ - s->clken[4] = value & 0x0000001f; - /* TODO update clocks */ - break; - - case 0x230: /* CM_AUTOIDLE1_CORE */ - s->clkidle[0] = value & 0xfffffff9; - /* TODO update clocks */ - break; - case 0x234: /* CM_AUTOIDLE2_CORE */ - s->clkidle[1] = value & 0x00000007; - /* TODO update clocks */ - break; - case 0x238: /* CM_AUTOIDLE3_CORE */ - s->clkidle[2] = value & 0x00000007; - /* TODO update clocks */ - break; - case 0x23c: /* CM_AUTOIDLE4_CORE */ - s->clkidle[3] = value & 0x0000001f; - /* TODO update clocks */ - break; - - case 0x240: /* CM_CLKSEL1_CORE */ - s->clksel[1] = value & 0x0fffbf7f; - /* TODO update clocks */ - break; - - case 0x244: /* CM_CLKSEL2_CORE */ - s->clksel[2] = value & 0x00fffffc; - /* TODO update clocks */ - break; - - case 0x248: /* CM_CLKSTCTRL_CORE */ - s->clkctrl[1] = value & 0x7; - break; - - case 0x2a0: /* PM_WKEN1_CORE */ - s->wken[0] = value & 0x04667ff8; - break; - case 0x2a4: /* PM_WKEN2_CORE */ - s->wken[1] = value & 0x00000005; - break; - - case 0x2b0: /* PM_WKST1_CORE */ - s->wkst[0] &= ~value; - break; - case 0x2b4: /* PM_WKST2_CORE */ - s->wkst[1] &= ~value; - break; - - case 0x2e0: /* PM_PWSTCTRL_CORE */ - s->power[1] = (value & 0x00fc3f) | (1 << 2); - break; - - case 0x300: /* CM_FCLKEN_GFX */ - s->clken[5] = value & 6; - /* TODO update clocks */ - break; - case 0x310: /* CM_ICLKEN_GFX */ - s->clken[6] = value & 1; - /* TODO update clocks */ - break; - case 0x340: /* CM_CLKSEL_GFX */ - s->clksel[3] = value & 7; - /* TODO update clocks */ - break; - case 0x348: /* CM_CLKSTCTRL_GFX */ - s->clkctrl[2] = value & 1; - break; - case 0x350: /* RM_RSTCTRL_GFX */ - s->rstctrl[0] = value & 1; - /* TODO: reset */ - break; - case 0x358: /* RM_RSTST_GFX */ - s->rst[1] &= ~value; - break; - case 0x3c8: /* PM_WKDEP_GFX */ - s->wkup[1] = value & 0x13; - break; - case 0x3e0: /* PM_PWSTCTRL_GFX */ - s->power[2] = (value & 0x00c0f) | (3 << 2); - break; - - case 0x400: /* CM_FCLKEN_WKUP */ - s->clken[7] = value & 0xd; - /* TODO update clocks */ - break; - case 0x410: /* CM_ICLKEN_WKUP */ - s->clken[8] = value & 0x3f; - /* TODO update clocks */ - break; - case 0x430: /* CM_AUTOIDLE_WKUP */ - s->clkidle[4] = value & 0x0000003f; - /* TODO update clocks */ - break; - case 0x440: /* CM_CLKSEL_WKUP */ - s->clksel[4] = value & 3; - /* TODO update clocks */ - break; - case 0x450: /* RM_RSTCTRL_WKUP */ - /* TODO: reset */ - if (value & 2) - qemu_system_reset_request(); - break; - case 0x454: /* RM_RSTTIME_WKUP */ - s->rsttime_wkup = value & 0x1fff; - break; - case 0x458: /* RM_RSTST_WKUP */ - s->rst[2] &= ~value; - break; - case 0x4a0: /* PM_WKEN_WKUP */ - s->wken[2] = value & 0x00000005; - break; - case 0x4b0: /* PM_WKST_WKUP */ - s->wkst[2] &= ~value; - break; - - case 0x500: /* CM_CLKEN_PLL */ - if (value & 0xffffff30) - fprintf(stderr, "%s: write 0s in CM_CLKEN_PLL for " - "future compatibility\n", __FUNCTION__); - if ((s->clken[9] ^ value) & 0xcc) { - s->clken[9] &= ~0xcc; - s->clken[9] |= value & 0xcc; - omap_prcm_apll_update(s); - } - if ((s->clken[9] ^ value) & 3) { - s->clken[9] &= ~3; - s->clken[9] |= value & 3; - omap_prcm_dpll_update(s); - } - break; - case 0x530: /* CM_AUTOIDLE_PLL */ - s->clkidle[5] = value & 0x000000cf; - /* TODO update clocks */ - break; - case 0x540: /* CM_CLKSEL1_PLL */ - if (value & 0xfc4000d7) - fprintf(stderr, "%s: write 0s in CM_CLKSEL1_PLL for " - "future compatibility\n", __FUNCTION__); - if ((s->clksel[5] ^ value) & 0x003fff00) { - s->clksel[5] = value & 0x03bfff28; - omap_prcm_dpll_update(s); - } - /* TODO update the other clocks */ - - s->clksel[5] = value & 0x03bfff28; - break; - case 0x544: /* CM_CLKSEL2_PLL */ - if (value & ~3) - fprintf(stderr, "%s: write 0s in CM_CLKSEL2_PLL[31:2] for " - "future compatibility\n", __FUNCTION__); - if (s->clksel[6] != (value & 3)) { - s->clksel[6] = value & 3; - omap_prcm_dpll_update(s); - } - break; - - case 0x800: /* CM_FCLKEN_DSP */ - s->clken[10] = value & 0x501; - /* TODO update clocks */ - break; - case 0x810: /* CM_ICLKEN_DSP */ - s->clken[11] = value & 0x2; - /* TODO update clocks */ - break; - case 0x830: /* CM_AUTOIDLE_DSP */ - s->clkidle[6] = value & 0x2; - /* TODO update clocks */ - break; - case 0x840: /* CM_CLKSEL_DSP */ - s->clksel[7] = value & 0x3fff; - /* TODO update clocks */ - break; - case 0x848: /* CM_CLKSTCTRL_DSP */ - s->clkctrl[3] = value & 0x101; - break; - case 0x850: /* RM_RSTCTRL_DSP */ - /* TODO: reset */ - break; - case 0x858: /* RM_RSTST_DSP */ - s->rst[3] &= ~value; - break; - case 0x8c8: /* PM_WKDEP_DSP */ - s->wkup[2] = value & 0x13; - break; - case 0x8e0: /* PM_PWSTCTRL_DSP */ - s->power[3] = (value & 0x03017) | (3 << 2); - break; - - case 0x8f0: /* PRCM_IRQSTATUS_DSP */ - s->irqst[1] &= ~value; - omap_prcm_int_update(s, 1); - break; - case 0x8f4: /* PRCM_IRQENABLE_DSP */ - s->irqen[1] = value & 0x7; - omap_prcm_int_update(s, 1); - break; - - case 0x8f8: /* PRCM_IRQSTATUS_IVA */ - s->irqst[2] &= ~value; - omap_prcm_int_update(s, 2); - break; - case 0x8fc: /* PRCM_IRQENABLE_IVA */ - s->irqen[2] = value & 0x7; - omap_prcm_int_update(s, 2); - break; - - default: - OMAP_BAD_REG(addr); - return; - } -} - -static const MemoryRegionOps omap_prcm_ops = { - .read = omap_prcm_read, - .write = omap_prcm_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void omap_prcm_reset(struct omap_prcm_s *s) -{ - s->sysconfig = 0; - s->irqst[0] = 0; - s->irqst[1] = 0; - s->irqst[2] = 0; - s->irqen[0] = 0; - s->irqen[1] = 0; - s->irqen[2] = 0; - s->voltctrl = 0x1040; - s->ev = 0x14; - s->evtime[0] = 0; - s->evtime[1] = 0; - s->clkctrl[0] = 0; - s->clkctrl[1] = 0; - s->clkctrl[2] = 0; - s->clkctrl[3] = 0; - s->clken[1] = 7; - s->clken[3] = 7; - s->clken[4] = 0; - s->clken[5] = 0; - s->clken[6] = 0; - s->clken[7] = 0xc; - s->clken[8] = 0x3e; - s->clken[9] = 0x0d; - s->clken[10] = 0; - s->clken[11] = 0; - s->clkidle[0] = 0; - s->clkidle[2] = 7; - s->clkidle[3] = 0; - s->clkidle[4] = 0; - s->clkidle[5] = 0x0c; - s->clkidle[6] = 0; - s->clksel[0] = 0x01; - s->clksel[1] = 0x02100121; - s->clksel[2] = 0x00000000; - s->clksel[3] = 0x01; - s->clksel[4] = 0; - s->clksel[7] = 0x0121; - s->wkup[0] = 0x15; - s->wkup[1] = 0x13; - s->wkup[2] = 0x13; - s->wken[0] = 0x04667ff8; - s->wken[1] = 0x00000005; - s->wken[2] = 5; - s->wkst[0] = 0; - s->wkst[1] = 0; - s->wkst[2] = 0; - s->power[0] = 0x00c; - s->power[1] = 4; - s->power[2] = 0x0000c; - s->power[3] = 0x14; - s->rstctrl[0] = 1; - s->rst[3] = 1; - omap_prcm_apll_update(s); - omap_prcm_dpll_update(s); -} - -static void omap_prcm_coldreset(struct omap_prcm_s *s) -{ - s->setuptime[0] = 0; - s->setuptime[1] = 0; - memset(&s->scratch, 0, sizeof(s->scratch)); - s->rst[0] = 0x01; - s->rst[1] = 0x00; - s->rst[2] = 0x01; - s->clken[0] = 0; - s->clken[2] = 0; - s->clkidle[1] = 0; - s->clksel[5] = 0; - s->clksel[6] = 2; - s->clksrc[0] = 0x43; - s->clkout[0] = 0x0303; - s->clkemul[0] = 0; - s->clkpol[0] = 0x100; - s->rsttime_wkup = 0x1002; - - omap_prcm_reset(s); -} - -static struct omap_prcm_s *omap_prcm_init(struct omap_target_agent_s *ta, - qemu_irq mpu_int, qemu_irq dsp_int, qemu_irq iva_int, - struct omap_mpu_state_s *mpu) -{ - struct omap_prcm_s *s = g_new0(struct omap_prcm_s, 1); - - s->irq[0] = mpu_int; - s->irq[1] = dsp_int; - s->irq[2] = iva_int; - s->mpu = mpu; - omap_prcm_coldreset(s); - - memory_region_init_io(&s->iomem0, NULL, &omap_prcm_ops, s, "omap.pcrm0", - omap_l4_region_size(ta, 0)); - memory_region_init_io(&s->iomem1, NULL, &omap_prcm_ops, s, "omap.pcrm1", - omap_l4_region_size(ta, 1)); - omap_l4_attach(ta, 0, &s->iomem0); - omap_l4_attach(ta, 1, &s->iomem1); - - return s; -} - -/* System and Pinout control */ -struct omap_sysctl_s { - struct omap_mpu_state_s *mpu; - MemoryRegion iomem; - - uint32_t sysconfig; - uint32_t devconfig; - uint32_t psaconfig; - uint32_t padconf[0x45]; - uint8_t obs; - uint32_t msuspendmux[5]; -}; - -static uint32_t omap_sysctl_read8(void *opaque, hwaddr addr) -{ - - struct omap_sysctl_s *s = (struct omap_sysctl_s *) opaque; - int pad_offset, byte_offset; - int value; - - switch (addr) { - case 0x030 ... 0x140: /* CONTROL_PADCONF - only used in the POP */ - pad_offset = (addr - 0x30) >> 2; - byte_offset = (addr - 0x30) & (4 - 1); - - value = s->padconf[pad_offset]; - value = (value >> (byte_offset * 8)) & 0xff; - - return value; - - default: - break; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static uint32_t omap_sysctl_read(void *opaque, hwaddr addr) -{ - struct omap_sysctl_s *s = (struct omap_sysctl_s *) opaque; - - switch (addr) { - case 0x000: /* CONTROL_REVISION */ - return 0x20; - - case 0x010: /* CONTROL_SYSCONFIG */ - return s->sysconfig; - - case 0x030 ... 0x140: /* CONTROL_PADCONF - only used in the POP */ - return s->padconf[(addr - 0x30) >> 2]; - - case 0x270: /* CONTROL_DEBOBS */ - return s->obs; - - case 0x274: /* CONTROL_DEVCONF */ - return s->devconfig; - - case 0x28c: /* CONTROL_EMU_SUPPORT */ - return 0; - - case 0x290: /* CONTROL_MSUSPENDMUX_0 */ - return s->msuspendmux[0]; - case 0x294: /* CONTROL_MSUSPENDMUX_1 */ - return s->msuspendmux[1]; - case 0x298: /* CONTROL_MSUSPENDMUX_2 */ - return s->msuspendmux[2]; - case 0x29c: /* CONTROL_MSUSPENDMUX_3 */ - return s->msuspendmux[3]; - case 0x2a0: /* CONTROL_MSUSPENDMUX_4 */ - return s->msuspendmux[4]; - case 0x2a4: /* CONTROL_MSUSPENDMUX_5 */ - return 0; - - case 0x2b8: /* CONTROL_PSA_CTRL */ - return s->psaconfig; - case 0x2bc: /* CONTROL_PSA_CMD */ - case 0x2c0: /* CONTROL_PSA_VALUE */ - return 0; - - case 0x2b0: /* CONTROL_SEC_CTRL */ - return 0x800000f1; - case 0x2d0: /* CONTROL_SEC_EMU */ - return 0x80000015; - case 0x2d4: /* CONTROL_SEC_TAP */ - return 0x8000007f; - case 0x2b4: /* CONTROL_SEC_TEST */ - case 0x2f0: /* CONTROL_SEC_STATUS */ - case 0x2f4: /* CONTROL_SEC_ERR_STATUS */ - /* Secure mode is not present on general-pusrpose device. Outside - * secure mode these values cannot be read or written. */ - return 0; - - case 0x2d8: /* CONTROL_OCM_RAM_PERM */ - return 0xff; - case 0x2dc: /* CONTROL_OCM_PUB_RAM_ADD */ - case 0x2e0: /* CONTROL_EXT_SEC_RAM_START_ADD */ - case 0x2e4: /* CONTROL_EXT_SEC_RAM_STOP_ADD */ - /* No secure mode so no Extended Secure RAM present. */ - return 0; - - case 0x2f8: /* CONTROL_STATUS */ - /* Device Type => General-purpose */ - return 0x0300; - case 0x2fc: /* CONTROL_GENERAL_PURPOSE_STATUS */ - - case 0x300: /* CONTROL_RPUB_KEY_H_0 */ - case 0x304: /* CONTROL_RPUB_KEY_H_1 */ - case 0x308: /* CONTROL_RPUB_KEY_H_2 */ - case 0x30c: /* CONTROL_RPUB_KEY_H_3 */ - return 0xdecafbad; - - case 0x310: /* CONTROL_RAND_KEY_0 */ - case 0x314: /* CONTROL_RAND_KEY_1 */ - case 0x318: /* CONTROL_RAND_KEY_2 */ - case 0x31c: /* CONTROL_RAND_KEY_3 */ - case 0x320: /* CONTROL_CUST_KEY_0 */ - case 0x324: /* CONTROL_CUST_KEY_1 */ - case 0x330: /* CONTROL_TEST_KEY_0 */ - case 0x334: /* CONTROL_TEST_KEY_1 */ - case 0x338: /* CONTROL_TEST_KEY_2 */ - case 0x33c: /* CONTROL_TEST_KEY_3 */ - case 0x340: /* CONTROL_TEST_KEY_4 */ - case 0x344: /* CONTROL_TEST_KEY_5 */ - case 0x348: /* CONTROL_TEST_KEY_6 */ - case 0x34c: /* CONTROL_TEST_KEY_7 */ - case 0x350: /* CONTROL_TEST_KEY_8 */ - case 0x354: /* CONTROL_TEST_KEY_9 */ - /* Can only be accessed in secure mode and when C_FieldAccEnable - * bit is set in CONTROL_SEC_CTRL. - * TODO: otherwise an interconnect access error is generated. */ - return 0; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_sysctl_write8(void *opaque, hwaddr addr, - uint32_t value) -{ - struct omap_sysctl_s *s = (struct omap_sysctl_s *) opaque; - int pad_offset, byte_offset; - int prev_value; - - switch (addr) { - case 0x030 ... 0x140: /* CONTROL_PADCONF - only used in the POP */ - pad_offset = (addr - 0x30) >> 2; - byte_offset = (addr - 0x30) & (4 - 1); - - prev_value = s->padconf[pad_offset]; - prev_value &= ~(0xff << (byte_offset * 8)); - prev_value |= ((value & 0x1f1f1f1f) << (byte_offset * 8)) & 0x1f1f1f1f; - s->padconf[pad_offset] = prev_value; - break; - - default: - OMAP_BAD_REG(addr); - break; - } -} - -static void omap_sysctl_write(void *opaque, hwaddr addr, - uint32_t value) -{ - struct omap_sysctl_s *s = (struct omap_sysctl_s *) opaque; - - switch (addr) { - case 0x000: /* CONTROL_REVISION */ - case 0x2a4: /* CONTROL_MSUSPENDMUX_5 */ - case 0x2c0: /* CONTROL_PSA_VALUE */ - case 0x2f8: /* CONTROL_STATUS */ - case 0x2fc: /* CONTROL_GENERAL_PURPOSE_STATUS */ - case 0x300: /* CONTROL_RPUB_KEY_H_0 */ - case 0x304: /* CONTROL_RPUB_KEY_H_1 */ - case 0x308: /* CONTROL_RPUB_KEY_H_2 */ - case 0x30c: /* CONTROL_RPUB_KEY_H_3 */ - case 0x310: /* CONTROL_RAND_KEY_0 */ - case 0x314: /* CONTROL_RAND_KEY_1 */ - case 0x318: /* CONTROL_RAND_KEY_2 */ - case 0x31c: /* CONTROL_RAND_KEY_3 */ - case 0x320: /* CONTROL_CUST_KEY_0 */ - case 0x324: /* CONTROL_CUST_KEY_1 */ - case 0x330: /* CONTROL_TEST_KEY_0 */ - case 0x334: /* CONTROL_TEST_KEY_1 */ - case 0x338: /* CONTROL_TEST_KEY_2 */ - case 0x33c: /* CONTROL_TEST_KEY_3 */ - case 0x340: /* CONTROL_TEST_KEY_4 */ - case 0x344: /* CONTROL_TEST_KEY_5 */ - case 0x348: /* CONTROL_TEST_KEY_6 */ - case 0x34c: /* CONTROL_TEST_KEY_7 */ - case 0x350: /* CONTROL_TEST_KEY_8 */ - case 0x354: /* CONTROL_TEST_KEY_9 */ - OMAP_RO_REG(addr); - return; - - case 0x010: /* CONTROL_SYSCONFIG */ - s->sysconfig = value & 0x1e; - break; - - case 0x030 ... 0x140: /* CONTROL_PADCONF - only used in the POP */ - /* XXX: should check constant bits */ - s->padconf[(addr - 0x30) >> 2] = value & 0x1f1f1f1f; - break; - - case 0x270: /* CONTROL_DEBOBS */ - s->obs = value & 0xff; - break; - - case 0x274: /* CONTROL_DEVCONF */ - s->devconfig = value & 0xffffc7ff; - break; - - case 0x28c: /* CONTROL_EMU_SUPPORT */ - break; - - case 0x290: /* CONTROL_MSUSPENDMUX_0 */ - s->msuspendmux[0] = value & 0x3fffffff; - break; - case 0x294: /* CONTROL_MSUSPENDMUX_1 */ - s->msuspendmux[1] = value & 0x3fffffff; - break; - case 0x298: /* CONTROL_MSUSPENDMUX_2 */ - s->msuspendmux[2] = value & 0x3fffffff; - break; - case 0x29c: /* CONTROL_MSUSPENDMUX_3 */ - s->msuspendmux[3] = value & 0x3fffffff; - break; - case 0x2a0: /* CONTROL_MSUSPENDMUX_4 */ - s->msuspendmux[4] = value & 0x3fffffff; - break; - - case 0x2b8: /* CONTROL_PSA_CTRL */ - s->psaconfig = value & 0x1c; - s->psaconfig |= (value & 0x20) ? 2 : 1; - break; - case 0x2bc: /* CONTROL_PSA_CMD */ - break; - - case 0x2b0: /* CONTROL_SEC_CTRL */ - case 0x2b4: /* CONTROL_SEC_TEST */ - case 0x2d0: /* CONTROL_SEC_EMU */ - case 0x2d4: /* CONTROL_SEC_TAP */ - case 0x2d8: /* CONTROL_OCM_RAM_PERM */ - case 0x2dc: /* CONTROL_OCM_PUB_RAM_ADD */ - case 0x2e0: /* CONTROL_EXT_SEC_RAM_START_ADD */ - case 0x2e4: /* CONTROL_EXT_SEC_RAM_STOP_ADD */ - case 0x2f0: /* CONTROL_SEC_STATUS */ - case 0x2f4: /* CONTROL_SEC_ERR_STATUS */ - break; - - default: - OMAP_BAD_REG(addr); - return; - } -} - -static const MemoryRegionOps omap_sysctl_ops = { - .old_mmio = { - .read = { - omap_sysctl_read8, - omap_badwidth_read32, /* TODO */ - omap_sysctl_read, - }, - .write = { - omap_sysctl_write8, - omap_badwidth_write32, /* TODO */ - omap_sysctl_write, - }, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void omap_sysctl_reset(struct omap_sysctl_s *s) -{ - /* (power-on reset) */ - s->sysconfig = 0; - s->obs = 0; - s->devconfig = 0x0c000000; - s->msuspendmux[0] = 0x00000000; - s->msuspendmux[1] = 0x00000000; - s->msuspendmux[2] = 0x00000000; - s->msuspendmux[3] = 0x00000000; - s->msuspendmux[4] = 0x00000000; - s->psaconfig = 1; - - s->padconf[0x00] = 0x000f0f0f; - s->padconf[0x01] = 0x00000000; - s->padconf[0x02] = 0x00000000; - s->padconf[0x03] = 0x00000000; - s->padconf[0x04] = 0x00000000; - s->padconf[0x05] = 0x00000000; - s->padconf[0x06] = 0x00000000; - s->padconf[0x07] = 0x00000000; - s->padconf[0x08] = 0x08080800; - s->padconf[0x09] = 0x08080808; - s->padconf[0x0a] = 0x08080808; - s->padconf[0x0b] = 0x08080808; - s->padconf[0x0c] = 0x08080808; - s->padconf[0x0d] = 0x08080800; - s->padconf[0x0e] = 0x08080808; - s->padconf[0x0f] = 0x08080808; - s->padconf[0x10] = 0x18181808; /* | 0x07070700 if SBoot3 */ - s->padconf[0x11] = 0x18181818; /* | 0x07070707 if SBoot3 */ - s->padconf[0x12] = 0x18181818; /* | 0x07070707 if SBoot3 */ - s->padconf[0x13] = 0x18181818; /* | 0x07070707 if SBoot3 */ - s->padconf[0x14] = 0x18181818; /* | 0x00070707 if SBoot3 */ - s->padconf[0x15] = 0x18181818; - s->padconf[0x16] = 0x18181818; /* | 0x07000000 if SBoot3 */ - s->padconf[0x17] = 0x1f001f00; - s->padconf[0x18] = 0x1f1f1f1f; - s->padconf[0x19] = 0x00000000; - s->padconf[0x1a] = 0x1f180000; - s->padconf[0x1b] = 0x00001f1f; - s->padconf[0x1c] = 0x1f001f00; - s->padconf[0x1d] = 0x00000000; - s->padconf[0x1e] = 0x00000000; - s->padconf[0x1f] = 0x08000000; - s->padconf[0x20] = 0x08080808; - s->padconf[0x21] = 0x08080808; - s->padconf[0x22] = 0x0f080808; - s->padconf[0x23] = 0x0f0f0f0f; - s->padconf[0x24] = 0x000f0f0f; - s->padconf[0x25] = 0x1f1f1f0f; - s->padconf[0x26] = 0x080f0f1f; - s->padconf[0x27] = 0x070f1808; - s->padconf[0x28] = 0x0f070707; - s->padconf[0x29] = 0x000f0f1f; - s->padconf[0x2a] = 0x0f0f0f1f; - s->padconf[0x2b] = 0x08000000; - s->padconf[0x2c] = 0x0000001f; - s->padconf[0x2d] = 0x0f0f1f00; - s->padconf[0x2e] = 0x1f1f0f0f; - s->padconf[0x2f] = 0x0f1f1f1f; - s->padconf[0x30] = 0x0f0f0f0f; - s->padconf[0x31] = 0x0f1f0f1f; - s->padconf[0x32] = 0x0f0f0f0f; - s->padconf[0x33] = 0x0f1f0f1f; - s->padconf[0x34] = 0x1f1f0f0f; - s->padconf[0x35] = 0x0f0f1f1f; - s->padconf[0x36] = 0x0f0f1f0f; - s->padconf[0x37] = 0x0f0f0f0f; - s->padconf[0x38] = 0x1f18180f; - s->padconf[0x39] = 0x1f1f1f1f; - s->padconf[0x3a] = 0x00001f1f; - s->padconf[0x3b] = 0x00000000; - s->padconf[0x3c] = 0x00000000; - s->padconf[0x3d] = 0x0f0f0f0f; - s->padconf[0x3e] = 0x18000f0f; - s->padconf[0x3f] = 0x00070000; - s->padconf[0x40] = 0x00000707; - s->padconf[0x41] = 0x0f1f0700; - s->padconf[0x42] = 0x1f1f070f; - s->padconf[0x43] = 0x0008081f; - s->padconf[0x44] = 0x00000800; -} - -static struct omap_sysctl_s *omap_sysctl_init(struct omap_target_agent_s *ta, - omap_clk iclk, struct omap_mpu_state_s *mpu) -{ - struct omap_sysctl_s *s = g_new0(struct omap_sysctl_s, 1); - - s->mpu = mpu; - omap_sysctl_reset(s); - - memory_region_init_io(&s->iomem, NULL, &omap_sysctl_ops, s, "omap.sysctl", - omap_l4_region_size(ta, 0)); - omap_l4_attach(ta, 0, &s->iomem); - - return s; -} - -/* General chip reset */ -static void omap2_mpu_reset(void *opaque) -{ - struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque; - - omap_dma_reset(mpu->dma); - omap_prcm_reset(mpu->prcm); - omap_sysctl_reset(mpu->sysc); - omap_gp_timer_reset(mpu->gptimer[0]); - omap_gp_timer_reset(mpu->gptimer[1]); - omap_gp_timer_reset(mpu->gptimer[2]); - omap_gp_timer_reset(mpu->gptimer[3]); - omap_gp_timer_reset(mpu->gptimer[4]); - omap_gp_timer_reset(mpu->gptimer[5]); - omap_gp_timer_reset(mpu->gptimer[6]); - omap_gp_timer_reset(mpu->gptimer[7]); - omap_gp_timer_reset(mpu->gptimer[8]); - omap_gp_timer_reset(mpu->gptimer[9]); - omap_gp_timer_reset(mpu->gptimer[10]); - omap_gp_timer_reset(mpu->gptimer[11]); - omap_synctimer_reset(mpu->synctimer); - omap_sdrc_reset(mpu->sdrc); - omap_gpmc_reset(mpu->gpmc); - omap_dss_reset(mpu->dss); - omap_uart_reset(mpu->uart[0]); - omap_uart_reset(mpu->uart[1]); - omap_uart_reset(mpu->uart[2]); - omap_mmc_reset(mpu->mmc); - omap_mcspi_reset(mpu->mcspi[0]); - omap_mcspi_reset(mpu->mcspi[1]); - cpu_reset(CPU(mpu->cpu)); -} - -static int omap2_validate_addr(struct omap_mpu_state_s *s, - hwaddr addr) -{ - return 1; -} - -static const struct dma_irq_map omap2_dma_irq_map[] = { - { 0, OMAP_INT_24XX_SDMA_IRQ0 }, - { 0, OMAP_INT_24XX_SDMA_IRQ1 }, - { 0, OMAP_INT_24XX_SDMA_IRQ2 }, - { 0, OMAP_INT_24XX_SDMA_IRQ3 }, -}; - -struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sysmem, - unsigned long sdram_size, - const char *core) -{ - struct omap_mpu_state_s *s = g_new0(struct omap_mpu_state_s, 1); - qemu_irq dma_irqs[4]; - DriveInfo *dinfo; - int i; - SysBusDevice *busdev; - struct omap_target_agent_s *ta; - - /* Core */ - s->mpu_model = omap2420; - s->cpu = cpu_arm_init(core ?: "arm1136-r2"); - if (s->cpu == NULL) { - fprintf(stderr, "Unable to find CPU definition\n"); - exit(1); - } - s->sdram_size = sdram_size; - s->sram_size = OMAP242X_SRAM_SIZE; - - s->wakeup = qemu_allocate_irq(omap_mpu_wakeup, s, 0); - - /* Clocks */ - omap_clk_init(s); - - /* Memory-mapped stuff */ - memory_region_allocate_system_memory(&s->sdram, NULL, "omap2.dram", - s->sdram_size); - memory_region_add_subregion(sysmem, OMAP2_Q2_BASE, &s->sdram); - memory_region_init_ram(&s->sram, NULL, "omap2.sram", s->sram_size, - &error_fatal); - vmstate_register_ram_global(&s->sram); - memory_region_add_subregion(sysmem, OMAP2_SRAM_BASE, &s->sram); - - s->l4 = omap_l4_init(sysmem, OMAP2_L4_BASE, 54); - - /* Actually mapped at any 2K boundary in the ARM11 private-peripheral if */ - s->ih[0] = qdev_create(NULL, "omap2-intc"); - qdev_prop_set_uint8(s->ih[0], "revision", 0x21); - qdev_prop_set_ptr(s->ih[0], "fclk", omap_findclk(s, "mpu_intc_fclk")); - qdev_prop_set_ptr(s->ih[0], "iclk", omap_findclk(s, "mpu_intc_iclk")); - qdev_init_nofail(s->ih[0]); - busdev = SYS_BUS_DEVICE(s->ih[0]); - sysbus_connect_irq(busdev, 0, - qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_IRQ)); - sysbus_connect_irq(busdev, 1, - qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_FIQ)); - sysbus_mmio_map(busdev, 0, 0x480fe000); - s->prcm = omap_prcm_init(omap_l4tao(s->l4, 3), - qdev_get_gpio_in(s->ih[0], - OMAP_INT_24XX_PRCM_MPU_IRQ), - NULL, NULL, s); - - s->sysc = omap_sysctl_init(omap_l4tao(s->l4, 1), - omap_findclk(s, "omapctrl_iclk"), s); - - for (i = 0; i < 4; i++) { - dma_irqs[i] = qdev_get_gpio_in(s->ih[omap2_dma_irq_map[i].ih], - omap2_dma_irq_map[i].intr); - } - s->dma = omap_dma4_init(0x48056000, dma_irqs, sysmem, s, 256, 32, - omap_findclk(s, "sdma_iclk"), - omap_findclk(s, "sdma_fclk")); - s->port->addr_valid = omap2_validate_addr; - - /* Register SDRAM and SRAM ports for fast DMA transfers. */ - soc_dma_port_add_mem(s->dma, memory_region_get_ram_ptr(&s->sdram), - OMAP2_Q2_BASE, s->sdram_size); - soc_dma_port_add_mem(s->dma, memory_region_get_ram_ptr(&s->sram), - OMAP2_SRAM_BASE, s->sram_size); - - s->uart[0] = omap2_uart_init(sysmem, omap_l4ta(s->l4, 19), - qdev_get_gpio_in(s->ih[0], - OMAP_INT_24XX_UART1_IRQ), - omap_findclk(s, "uart1_fclk"), - omap_findclk(s, "uart1_iclk"), - s->drq[OMAP24XX_DMA_UART1_TX], - s->drq[OMAP24XX_DMA_UART1_RX], - "uart1", - serial_hds[0]); - s->uart[1] = omap2_uart_init(sysmem, omap_l4ta(s->l4, 20), - qdev_get_gpio_in(s->ih[0], - OMAP_INT_24XX_UART2_IRQ), - omap_findclk(s, "uart2_fclk"), - omap_findclk(s, "uart2_iclk"), - s->drq[OMAP24XX_DMA_UART2_TX], - s->drq[OMAP24XX_DMA_UART2_RX], - "uart2", - serial_hds[0] ? serial_hds[1] : NULL); - s->uart[2] = omap2_uart_init(sysmem, omap_l4ta(s->l4, 21), - qdev_get_gpio_in(s->ih[0], - OMAP_INT_24XX_UART3_IRQ), - omap_findclk(s, "uart3_fclk"), - omap_findclk(s, "uart3_iclk"), - s->drq[OMAP24XX_DMA_UART3_TX], - s->drq[OMAP24XX_DMA_UART3_RX], - "uart3", - serial_hds[0] && serial_hds[1] ? serial_hds[2] : NULL); - - s->gptimer[0] = omap_gp_timer_init(omap_l4ta(s->l4, 7), - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER1), - omap_findclk(s, "wu_gpt1_clk"), - omap_findclk(s, "wu_l4_iclk")); - s->gptimer[1] = omap_gp_timer_init(omap_l4ta(s->l4, 8), - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER2), - omap_findclk(s, "core_gpt2_clk"), - omap_findclk(s, "core_l4_iclk")); - s->gptimer[2] = omap_gp_timer_init(omap_l4ta(s->l4, 22), - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER3), - omap_findclk(s, "core_gpt3_clk"), - omap_findclk(s, "core_l4_iclk")); - s->gptimer[3] = omap_gp_timer_init(omap_l4ta(s->l4, 23), - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER4), - omap_findclk(s, "core_gpt4_clk"), - omap_findclk(s, "core_l4_iclk")); - s->gptimer[4] = omap_gp_timer_init(omap_l4ta(s->l4, 24), - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER5), - omap_findclk(s, "core_gpt5_clk"), - omap_findclk(s, "core_l4_iclk")); - s->gptimer[5] = omap_gp_timer_init(omap_l4ta(s->l4, 25), - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER6), - omap_findclk(s, "core_gpt6_clk"), - omap_findclk(s, "core_l4_iclk")); - s->gptimer[6] = omap_gp_timer_init(omap_l4ta(s->l4, 26), - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER7), - omap_findclk(s, "core_gpt7_clk"), - omap_findclk(s, "core_l4_iclk")); - s->gptimer[7] = omap_gp_timer_init(omap_l4ta(s->l4, 27), - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER8), - omap_findclk(s, "core_gpt8_clk"), - omap_findclk(s, "core_l4_iclk")); - s->gptimer[8] = omap_gp_timer_init(omap_l4ta(s->l4, 28), - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER9), - omap_findclk(s, "core_gpt9_clk"), - omap_findclk(s, "core_l4_iclk")); - s->gptimer[9] = omap_gp_timer_init(omap_l4ta(s->l4, 29), - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER10), - omap_findclk(s, "core_gpt10_clk"), - omap_findclk(s, "core_l4_iclk")); - s->gptimer[10] = omap_gp_timer_init(omap_l4ta(s->l4, 30), - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER11), - omap_findclk(s, "core_gpt11_clk"), - omap_findclk(s, "core_l4_iclk")); - s->gptimer[11] = omap_gp_timer_init(omap_l4ta(s->l4, 31), - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER12), - omap_findclk(s, "core_gpt12_clk"), - omap_findclk(s, "core_l4_iclk")); - - omap_tap_init(omap_l4ta(s->l4, 2), s); - - s->synctimer = omap_synctimer_init(omap_l4tao(s->l4, 2), s, - omap_findclk(s, "clk32-kHz"), - omap_findclk(s, "core_l4_iclk")); - - s->i2c[0] = qdev_create(NULL, "omap_i2c"); - qdev_prop_set_uint8(s->i2c[0], "revision", 0x34); - qdev_prop_set_ptr(s->i2c[0], "iclk", omap_findclk(s, "i2c1.iclk")); - qdev_prop_set_ptr(s->i2c[0], "fclk", omap_findclk(s, "i2c1.fclk")); - qdev_init_nofail(s->i2c[0]); - busdev = SYS_BUS_DEVICE(s->i2c[0]); - sysbus_connect_irq(busdev, 0, - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_I2C1_IRQ)); - sysbus_connect_irq(busdev, 1, s->drq[OMAP24XX_DMA_I2C1_TX]); - sysbus_connect_irq(busdev, 2, s->drq[OMAP24XX_DMA_I2C1_RX]); - sysbus_mmio_map(busdev, 0, omap_l4_region_base(omap_l4tao(s->l4, 5), 0)); - - s->i2c[1] = qdev_create(NULL, "omap_i2c"); - qdev_prop_set_uint8(s->i2c[1], "revision", 0x34); - qdev_prop_set_ptr(s->i2c[1], "iclk", omap_findclk(s, "i2c2.iclk")); - qdev_prop_set_ptr(s->i2c[1], "fclk", omap_findclk(s, "i2c2.fclk")); - qdev_init_nofail(s->i2c[1]); - busdev = SYS_BUS_DEVICE(s->i2c[1]); - sysbus_connect_irq(busdev, 0, - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_I2C2_IRQ)); - sysbus_connect_irq(busdev, 1, s->drq[OMAP24XX_DMA_I2C2_TX]); - sysbus_connect_irq(busdev, 2, s->drq[OMAP24XX_DMA_I2C2_RX]); - sysbus_mmio_map(busdev, 0, omap_l4_region_base(omap_l4tao(s->l4, 6), 0)); - - s->gpio = qdev_create(NULL, "omap2-gpio"); - qdev_prop_set_int32(s->gpio, "mpu_model", s->mpu_model); - qdev_prop_set_ptr(s->gpio, "iclk", omap_findclk(s, "gpio_iclk")); - qdev_prop_set_ptr(s->gpio, "fclk0", omap_findclk(s, "gpio1_dbclk")); - qdev_prop_set_ptr(s->gpio, "fclk1", omap_findclk(s, "gpio2_dbclk")); - qdev_prop_set_ptr(s->gpio, "fclk2", omap_findclk(s, "gpio3_dbclk")); - qdev_prop_set_ptr(s->gpio, "fclk3", omap_findclk(s, "gpio4_dbclk")); - if (s->mpu_model == omap2430) { - qdev_prop_set_ptr(s->gpio, "fclk4", omap_findclk(s, "gpio5_dbclk")); - } - qdev_init_nofail(s->gpio); - busdev = SYS_BUS_DEVICE(s->gpio); - sysbus_connect_irq(busdev, 0, - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPIO_BANK1)); - sysbus_connect_irq(busdev, 3, - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPIO_BANK2)); - sysbus_connect_irq(busdev, 6, - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPIO_BANK3)); - sysbus_connect_irq(busdev, 9, - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPIO_BANK4)); - if (s->mpu_model == omap2430) { - sysbus_connect_irq(busdev, 12, - qdev_get_gpio_in(s->ih[0], - OMAP_INT_243X_GPIO_BANK5)); - } - ta = omap_l4ta(s->l4, 3); - sysbus_mmio_map(busdev, 0, omap_l4_region_base(ta, 1)); - sysbus_mmio_map(busdev, 1, omap_l4_region_base(ta, 0)); - sysbus_mmio_map(busdev, 2, omap_l4_region_base(ta, 2)); - sysbus_mmio_map(busdev, 3, omap_l4_region_base(ta, 4)); - sysbus_mmio_map(busdev, 4, omap_l4_region_base(ta, 5)); - - s->sdrc = omap_sdrc_init(sysmem, 0x68009000); - s->gpmc = omap_gpmc_init(s, 0x6800a000, - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPMC_IRQ), - s->drq[OMAP24XX_DMA_GPMC]); - - dinfo = drive_get(IF_SD, 0, 0); - if (!dinfo) { - fprintf(stderr, "qemu: missing SecureDigital device\n"); - exit(1); - } - s->mmc = omap2_mmc_init(omap_l4tao(s->l4, 9), - blk_by_legacy_dinfo(dinfo), - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_MMC_IRQ), - &s->drq[OMAP24XX_DMA_MMC1_TX], - omap_findclk(s, "mmc_fclk"), omap_findclk(s, "mmc_iclk")); - - s->mcspi[0] = omap_mcspi_init(omap_l4ta(s->l4, 35), 4, - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_MCSPI1_IRQ), - &s->drq[OMAP24XX_DMA_SPI1_TX0], - omap_findclk(s, "spi1_fclk"), - omap_findclk(s, "spi1_iclk")); - s->mcspi[1] = omap_mcspi_init(omap_l4ta(s->l4, 36), 2, - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_MCSPI2_IRQ), - &s->drq[OMAP24XX_DMA_SPI2_TX0], - omap_findclk(s, "spi2_fclk"), - omap_findclk(s, "spi2_iclk")); - - s->dss = omap_dss_init(omap_l4ta(s->l4, 10), sysmem, 0x68000800, - /* XXX wire M_IRQ_25, D_L2_IRQ_30 and I_IRQ_13 together */ - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_DSS_IRQ), - s->drq[OMAP24XX_DMA_DSS], - omap_findclk(s, "dss_clk1"), omap_findclk(s, "dss_clk2"), - omap_findclk(s, "dss_54m_clk"), - omap_findclk(s, "dss_l3_iclk"), - omap_findclk(s, "dss_l4_iclk")); - - omap_sti_init(omap_l4ta(s->l4, 18), sysmem, 0x54000000, - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_STI), - omap_findclk(s, "emul_ck"), - serial_hds[0] && serial_hds[1] && serial_hds[2] ? - serial_hds[3] : NULL); - - s->eac = omap_eac_init(omap_l4ta(s->l4, 32), - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_EAC_IRQ), - /* Ten consecutive lines */ - &s->drq[OMAP24XX_DMA_EAC_AC_RD], - omap_findclk(s, "func_96m_clk"), - omap_findclk(s, "core_l4_iclk")); - - /* All register mappings (includin those not currenlty implemented): - * SystemControlMod 48000000 - 48000fff - * SystemControlL4 48001000 - 48001fff - * 32kHz Timer Mod 48004000 - 48004fff - * 32kHz Timer L4 48005000 - 48005fff - * PRCM ModA 48008000 - 480087ff - * PRCM ModB 48008800 - 48008fff - * PRCM L4 48009000 - 48009fff - * TEST-BCM Mod 48012000 - 48012fff - * TEST-BCM L4 48013000 - 48013fff - * TEST-TAP Mod 48014000 - 48014fff - * TEST-TAP L4 48015000 - 48015fff - * GPIO1 Mod 48018000 - 48018fff - * GPIO Top 48019000 - 48019fff - * GPIO2 Mod 4801a000 - 4801afff - * GPIO L4 4801b000 - 4801bfff - * GPIO3 Mod 4801c000 - 4801cfff - * GPIO4 Mod 4801e000 - 4801efff - * WDTIMER1 Mod 48020000 - 48010fff - * WDTIMER Top 48021000 - 48011fff - * WDTIMER2 Mod 48022000 - 48012fff - * WDTIMER L4 48023000 - 48013fff - * WDTIMER3 Mod 48024000 - 48014fff - * WDTIMER3 L4 48025000 - 48015fff - * WDTIMER4 Mod 48026000 - 48016fff - * WDTIMER4 L4 48027000 - 48017fff - * GPTIMER1 Mod 48028000 - 48018fff - * GPTIMER1 L4 48029000 - 48019fff - * GPTIMER2 Mod 4802a000 - 4801afff - * GPTIMER2 L4 4802b000 - 4801bfff - * L4-Config AP 48040000 - 480407ff - * L4-Config IP 48040800 - 48040fff - * L4-Config LA 48041000 - 48041fff - * ARM11ETB Mod 48048000 - 48049fff - * ARM11ETB L4 4804a000 - 4804afff - * DISPLAY Top 48050000 - 480503ff - * DISPLAY DISPC 48050400 - 480507ff - * DISPLAY RFBI 48050800 - 48050bff - * DISPLAY VENC 48050c00 - 48050fff - * DISPLAY L4 48051000 - 48051fff - * CAMERA Top 48052000 - 480523ff - * CAMERA core 48052400 - 480527ff - * CAMERA DMA 48052800 - 48052bff - * CAMERA MMU 48052c00 - 48052fff - * CAMERA L4 48053000 - 48053fff - * SDMA Mod 48056000 - 48056fff - * SDMA L4 48057000 - 48057fff - * SSI Top 48058000 - 48058fff - * SSI GDD 48059000 - 48059fff - * SSI Port1 4805a000 - 4805afff - * SSI Port2 4805b000 - 4805bfff - * SSI L4 4805c000 - 4805cfff - * USB Mod 4805e000 - 480fefff - * USB L4 4805f000 - 480fffff - * WIN_TRACER1 Mod 48060000 - 48060fff - * WIN_TRACER1 L4 48061000 - 48061fff - * WIN_TRACER2 Mod 48062000 - 48062fff - * WIN_TRACER2 L4 48063000 - 48063fff - * WIN_TRACER3 Mod 48064000 - 48064fff - * WIN_TRACER3 L4 48065000 - 48065fff - * WIN_TRACER4 Top 48066000 - 480660ff - * WIN_TRACER4 ETT 48066100 - 480661ff - * WIN_TRACER4 WT 48066200 - 480662ff - * WIN_TRACER4 L4 48067000 - 48067fff - * XTI Mod 48068000 - 48068fff - * XTI L4 48069000 - 48069fff - * UART1 Mod 4806a000 - 4806afff - * UART1 L4 4806b000 - 4806bfff - * UART2 Mod 4806c000 - 4806cfff - * UART2 L4 4806d000 - 4806dfff - * UART3 Mod 4806e000 - 4806efff - * UART3 L4 4806f000 - 4806ffff - * I2C1 Mod 48070000 - 48070fff - * I2C1 L4 48071000 - 48071fff - * I2C2 Mod 48072000 - 48072fff - * I2C2 L4 48073000 - 48073fff - * McBSP1 Mod 48074000 - 48074fff - * McBSP1 L4 48075000 - 48075fff - * McBSP2 Mod 48076000 - 48076fff - * McBSP2 L4 48077000 - 48077fff - * GPTIMER3 Mod 48078000 - 48078fff - * GPTIMER3 L4 48079000 - 48079fff - * GPTIMER4 Mod 4807a000 - 4807afff - * GPTIMER4 L4 4807b000 - 4807bfff - * GPTIMER5 Mod 4807c000 - 4807cfff - * GPTIMER5 L4 4807d000 - 4807dfff - * GPTIMER6 Mod 4807e000 - 4807efff - * GPTIMER6 L4 4807f000 - 4807ffff - * GPTIMER7 Mod 48080000 - 48080fff - * GPTIMER7 L4 48081000 - 48081fff - * GPTIMER8 Mod 48082000 - 48082fff - * GPTIMER8 L4 48083000 - 48083fff - * GPTIMER9 Mod 48084000 - 48084fff - * GPTIMER9 L4 48085000 - 48085fff - * GPTIMER10 Mod 48086000 - 48086fff - * GPTIMER10 L4 48087000 - 48087fff - * GPTIMER11 Mod 48088000 - 48088fff - * GPTIMER11 L4 48089000 - 48089fff - * GPTIMER12 Mod 4808a000 - 4808afff - * GPTIMER12 L4 4808b000 - 4808bfff - * EAC Mod 48090000 - 48090fff - * EAC L4 48091000 - 48091fff - * FAC Mod 48092000 - 48092fff - * FAC L4 48093000 - 48093fff - * MAILBOX Mod 48094000 - 48094fff - * MAILBOX L4 48095000 - 48095fff - * SPI1 Mod 48098000 - 48098fff - * SPI1 L4 48099000 - 48099fff - * SPI2 Mod 4809a000 - 4809afff - * SPI2 L4 4809b000 - 4809bfff - * MMC/SDIO Mod 4809c000 - 4809cfff - * MMC/SDIO L4 4809d000 - 4809dfff - * MS_PRO Mod 4809e000 - 4809efff - * MS_PRO L4 4809f000 - 4809ffff - * RNG Mod 480a0000 - 480a0fff - * RNG L4 480a1000 - 480a1fff - * DES3DES Mod 480a2000 - 480a2fff - * DES3DES L4 480a3000 - 480a3fff - * SHA1MD5 Mod 480a4000 - 480a4fff - * SHA1MD5 L4 480a5000 - 480a5fff - * AES Mod 480a6000 - 480a6fff - * AES L4 480a7000 - 480a7fff - * PKA Mod 480a8000 - 480a9fff - * PKA L4 480aa000 - 480aafff - * MG Mod 480b0000 - 480b0fff - * MG L4 480b1000 - 480b1fff - * HDQ/1-wire Mod 480b2000 - 480b2fff - * HDQ/1-wire L4 480b3000 - 480b3fff - * MPU interrupt 480fe000 - 480fefff - * STI channel base 54000000 - 5400ffff - * IVA RAM 5c000000 - 5c01ffff - * IVA ROM 5c020000 - 5c027fff - * IMG_BUF_A 5c040000 - 5c040fff - * IMG_BUF_B 5c042000 - 5c042fff - * VLCDS 5c048000 - 5c0487ff - * IMX_COEF 5c049000 - 5c04afff - * IMX_CMD 5c051000 - 5c051fff - * VLCDQ 5c053000 - 5c0533ff - * VLCDH 5c054000 - 5c054fff - * SEQ_CMD 5c055000 - 5c055fff - * IMX_REG 5c056000 - 5c0560ff - * VLCD_REG 5c056100 - 5c0561ff - * SEQ_REG 5c056200 - 5c0562ff - * IMG_BUF_REG 5c056300 - 5c0563ff - * SEQIRQ_REG 5c056400 - 5c0564ff - * OCP_REG 5c060000 - 5c060fff - * SYSC_REG 5c070000 - 5c070fff - * MMU_REG 5d000000 - 5d000fff - * sDMA R 68000400 - 680005ff - * sDMA W 68000600 - 680007ff - * Display Control 68000800 - 680009ff - * DSP subsystem 68000a00 - 68000bff - * MPU subsystem 68000c00 - 68000dff - * IVA subsystem 68001000 - 680011ff - * USB 68001200 - 680013ff - * Camera 68001400 - 680015ff - * VLYNQ (firewall) 68001800 - 68001bff - * VLYNQ 68001e00 - 68001fff - * SSI 68002000 - 680021ff - * L4 68002400 - 680025ff - * DSP (firewall) 68002800 - 68002bff - * DSP subsystem 68002e00 - 68002fff - * IVA (firewall) 68003000 - 680033ff - * IVA 68003600 - 680037ff - * GFX 68003a00 - 68003bff - * CMDWR emulation 68003c00 - 68003dff - * SMS 68004000 - 680041ff - * OCM 68004200 - 680043ff - * GPMC 68004400 - 680045ff - * RAM (firewall) 68005000 - 680053ff - * RAM (err login) 68005400 - 680057ff - * ROM (firewall) 68005800 - 68005bff - * ROM (err login) 68005c00 - 68005fff - * GPMC (firewall) 68006000 - 680063ff - * GPMC (err login) 68006400 - 680067ff - * SMS (err login) 68006c00 - 68006fff - * SMS registers 68008000 - 68008fff - * SDRC registers 68009000 - 68009fff - * GPMC registers 6800a000 6800afff - */ - - qemu_register_reset(omap2_mpu_reset, s); - - return s; -} diff --git a/qemu/hw/arm/omap_sx1.c b/qemu/hw/arm/omap_sx1.c deleted file mode 100644 index 5d74026cb..000000000 --- a/qemu/hw/arm/omap_sx1.c +++ /dev/null @@ -1,256 +0,0 @@ -/* omap_sx1.c Support for the Siemens SX1 smartphone emulation. - * - * Copyright (C) 2008 - * Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> - * Copyright (C) 2007 Vladimir Ananiev <vovan888@gmail.com> - * - * based on PalmOne's (TM) PDAs support (palm.c) - */ - -/* - * PalmOne's (TM) PDAs. - * - * Copyright (C) 2006-2007 Andrzej Zaborowski <balrog@zabor.org> - * - * 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 <http://www.gnu.org/licenses/>. - */ -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "hw/hw.h" -#include "ui/console.h" -#include "hw/arm/omap.h" -#include "hw/boards.h" -#include "hw/arm/arm.h" -#include "hw/block/flash.h" -#include "sysemu/block-backend.h" -#include "sysemu/qtest.h" -#include "exec/address-spaces.h" - -/*****************************************************************************/ -/* Siemens SX1 Cellphone V1 */ -/* - ARM OMAP310 processor - * - SRAM 192 kB - * - SDRAM 32 MB at 0x10000000 - * - Boot flash 16 MB at 0x00000000 - * - Application flash 8 MB at 0x04000000 - * - 3 serial ports - * - 1 SecureDigital - * - 1 LCD display - * - 1 RTC - */ - -/*****************************************************************************/ -/* Siemens SX1 Cellphone V2 */ -/* - ARM OMAP310 processor - * - SRAM 192 kB - * - SDRAM 32 MB at 0x10000000 - * - Boot flash 32 MB at 0x00000000 - * - 3 serial ports - * - 1 SecureDigital - * - 1 LCD display - * - 1 RTC - */ - -static uint64_t static_read(void *opaque, hwaddr offset, - unsigned size) -{ - uint32_t *val = (uint32_t *) opaque; - uint32_t mask = (4 / size) - 1; - - return *val >> ((offset & mask) << 3); -} - -static void static_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ -#ifdef SPY - printf("%s: value %" PRIx64 " %u bytes written at 0x%x\n", - __func__, value, size, (int)offset); -#endif -} - -static const MemoryRegionOps static_ops = { - .read = static_read, - .write = static_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -#define sdram_size 0x02000000 -#define sector_size (128 * 1024) -#define flash0_size (16 * 1024 * 1024) -#define flash1_size ( 8 * 1024 * 1024) -#define flash2_size (32 * 1024 * 1024) -#define total_ram_v1 (sdram_size + flash0_size + flash1_size + OMAP15XX_SRAM_SIZE) -#define total_ram_v2 (sdram_size + flash2_size + OMAP15XX_SRAM_SIZE) - -static struct arm_boot_info sx1_binfo = { - .loader_start = OMAP_EMIFF_BASE, - .ram_size = sdram_size, - .board_id = 0x265, -}; - -static void sx1_init(MachineState *machine, const int version) -{ - struct omap_mpu_state_s *mpu; - MemoryRegion *address_space = get_system_memory(); - MemoryRegion *flash = g_new(MemoryRegion, 1); - MemoryRegion *cs = g_new(MemoryRegion, 4); - static uint32_t cs0val = 0x00213090; - static uint32_t cs1val = 0x00215070; - static uint32_t cs2val = 0x00001139; - static uint32_t cs3val = 0x00001139; - DriveInfo *dinfo; - int fl_idx; - uint32_t flash_size = flash0_size; - int be; - - if (version == 2) { - flash_size = flash2_size; - } - - mpu = omap310_mpu_init(address_space, sx1_binfo.ram_size, - machine->cpu_model); - - /* External Flash (EMIFS) */ - memory_region_init_ram(flash, NULL, "omap_sx1.flash0-0", flash_size, - &error_fatal); - vmstate_register_ram_global(flash); - memory_region_set_readonly(flash, true); - memory_region_add_subregion(address_space, OMAP_CS0_BASE, flash); - - memory_region_init_io(&cs[0], NULL, &static_ops, &cs0val, - "sx1.cs0", OMAP_CS0_SIZE - flash_size); - memory_region_add_subregion(address_space, - OMAP_CS0_BASE + flash_size, &cs[0]); - - - memory_region_init_io(&cs[2], NULL, &static_ops, &cs2val, - "sx1.cs2", OMAP_CS2_SIZE); - memory_region_add_subregion(address_space, - OMAP_CS2_BASE, &cs[2]); - - memory_region_init_io(&cs[3], NULL, &static_ops, &cs3val, - "sx1.cs3", OMAP_CS3_SIZE); - memory_region_add_subregion(address_space, - OMAP_CS2_BASE, &cs[3]); - - fl_idx = 0; -#ifdef TARGET_WORDS_BIGENDIAN - be = 1; -#else - be = 0; -#endif - - if ((dinfo = drive_get(IF_PFLASH, 0, fl_idx)) != NULL) { - if (!pflash_cfi01_register(OMAP_CS0_BASE, NULL, - "omap_sx1.flash0-1", flash_size, - blk_by_legacy_dinfo(dinfo), - sector_size, flash_size / sector_size, - 4, 0, 0, 0, 0, be)) { - fprintf(stderr, "qemu: Error registering flash memory %d.\n", - fl_idx); - } - fl_idx++; - } - - if ((version == 1) && - (dinfo = drive_get(IF_PFLASH, 0, fl_idx)) != NULL) { - MemoryRegion *flash_1 = g_new(MemoryRegion, 1); - memory_region_init_ram(flash_1, NULL, "omap_sx1.flash1-0", flash1_size, - &error_fatal); - vmstate_register_ram_global(flash_1); - memory_region_set_readonly(flash_1, true); - memory_region_add_subregion(address_space, OMAP_CS1_BASE, flash_1); - - memory_region_init_io(&cs[1], NULL, &static_ops, &cs1val, - "sx1.cs1", OMAP_CS1_SIZE - flash1_size); - memory_region_add_subregion(address_space, - OMAP_CS1_BASE + flash1_size, &cs[1]); - - if (!pflash_cfi01_register(OMAP_CS1_BASE, NULL, - "omap_sx1.flash1-1", flash1_size, - blk_by_legacy_dinfo(dinfo), - sector_size, flash1_size / sector_size, - 4, 0, 0, 0, 0, be)) { - fprintf(stderr, "qemu: Error registering flash memory %d.\n", - fl_idx); - } - fl_idx++; - } else { - memory_region_init_io(&cs[1], NULL, &static_ops, &cs1val, - "sx1.cs1", OMAP_CS1_SIZE); - memory_region_add_subregion(address_space, - OMAP_CS1_BASE, &cs[1]); - } - - if (!machine->kernel_filename && !fl_idx && !qtest_enabled()) { - fprintf(stderr, "Kernel or Flash image must be specified\n"); - exit(1); - } - - /* Load the kernel. */ - sx1_binfo.kernel_filename = machine->kernel_filename; - sx1_binfo.kernel_cmdline = machine->kernel_cmdline; - sx1_binfo.initrd_filename = machine->initrd_filename; - arm_load_kernel(mpu->cpu, &sx1_binfo); - - /* TODO: fix next line */ - //~ qemu_console_resize(ds, 640, 480); -} - -static void sx1_init_v1(MachineState *machine) -{ - sx1_init(machine, 1); -} - -static void sx1_init_v2(MachineState *machine) -{ - sx1_init(machine, 2); -} - -static void sx1_machine_v2_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "Siemens SX1 (OMAP310) V2"; - mc->init = sx1_init_v2; -} - -static const TypeInfo sx1_machine_v2_type = { - .name = MACHINE_TYPE_NAME("sx1"), - .parent = TYPE_MACHINE, - .class_init = sx1_machine_v2_class_init, -}; - -static void sx1_machine_v1_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "Siemens SX1 (OMAP310) V1"; - mc->init = sx1_init_v1; -} - -static const TypeInfo sx1_machine_v1_type = { - .name = MACHINE_TYPE_NAME("sx1-v1"), - .parent = TYPE_MACHINE, - .class_init = sx1_machine_v1_class_init, -}; - -static void sx1_machine_init(void) -{ - type_register_static(&sx1_machine_v1_type); - type_register_static(&sx1_machine_v2_type); -} - -type_init(sx1_machine_init) diff --git a/qemu/hw/arm/palm.c b/qemu/hw/arm/palm.c deleted file mode 100644 index 7f460732e..000000000 --- a/qemu/hw/arm/palm.c +++ /dev/null @@ -1,280 +0,0 @@ -/* - * PalmOne's (TM) PDAs. - * - * Copyright (C) 2006-2007 Andrzej Zaborowski <balrog@zabor.org> - * - * 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 <http://www.gnu.org/licenses/>. - */ -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "hw/hw.h" -#include "audio/audio.h" -#include "sysemu/sysemu.h" -#include "sysemu/qtest.h" -#include "ui/console.h" -#include "hw/arm/omap.h" -#include "hw/boards.h" -#include "hw/arm/arm.h" -#include "hw/devices.h" -#include "hw/loader.h" -#include "exec/address-spaces.h" - -static uint32_t static_readb(void *opaque, hwaddr offset) -{ - uint32_t *val = (uint32_t *) opaque; - return *val >> ((offset & 3) << 3); -} - -static uint32_t static_readh(void *opaque, hwaddr offset) -{ - uint32_t *val = (uint32_t *) opaque; - return *val >> ((offset & 1) << 3); -} - -static uint32_t static_readw(void *opaque, hwaddr offset) -{ - uint32_t *val = (uint32_t *) opaque; - return *val >> ((offset & 0) << 3); -} - -static void static_write(void *opaque, hwaddr offset, - uint32_t value) -{ -#ifdef SPY - printf("%s: value %08lx written at " PA_FMT "\n", - __FUNCTION__, value, offset); -#endif -} - -static const MemoryRegionOps static_ops = { - .old_mmio = { - .read = { static_readb, static_readh, static_readw, }, - .write = { static_write, static_write, static_write, }, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -/* Palm Tunsgten|E support */ - -/* Shared GPIOs */ -#define PALMTE_USBDETECT_GPIO 0 -#define PALMTE_USB_OR_DC_GPIO 1 -#define PALMTE_TSC_GPIO 4 -#define PALMTE_PINTDAV_GPIO 6 -#define PALMTE_MMC_WP_GPIO 8 -#define PALMTE_MMC_POWER_GPIO 9 -#define PALMTE_HDQ_GPIO 11 -#define PALMTE_HEADPHONES_GPIO 14 -#define PALMTE_SPEAKER_GPIO 15 -/* MPU private GPIOs */ -#define PALMTE_DC_GPIO 2 -#define PALMTE_MMC_SWITCH_GPIO 4 -#define PALMTE_MMC1_GPIO 6 -#define PALMTE_MMC2_GPIO 7 -#define PALMTE_MMC3_GPIO 11 - -static MouseTransformInfo palmte_pointercal = { - .x = 320, - .y = 320, - .a = { -5909, 8, 22465308, 104, 7644, -1219972, 65536 }, -}; - -static void palmte_microwire_setup(struct omap_mpu_state_s *cpu) -{ - uWireSlave *tsc; - - tsc = tsc2102_init(qdev_get_gpio_in(cpu->gpio, PALMTE_PINTDAV_GPIO)); - - omap_uwire_attach(cpu->microwire, tsc, 0); - omap_mcbsp_i2s_attach(cpu->mcbsp1, tsc210x_codec(tsc)); - - tsc210x_set_transform(tsc, &palmte_pointercal); -} - -static struct { - int row; - int column; -} palmte_keymap[0x80] = { - [0 ... 0x7f] = { -1, -1 }, - [0x3b] = { 0, 0 }, /* F1 -> Calendar */ - [0x3c] = { 1, 0 }, /* F2 -> Contacts */ - [0x3d] = { 2, 0 }, /* F3 -> Tasks List */ - [0x3e] = { 3, 0 }, /* F4 -> Note Pad */ - [0x01] = { 4, 0 }, /* Esc -> Power */ - [0x4b] = { 0, 1 }, /* Left */ - [0x50] = { 1, 1 }, /* Down */ - [0x48] = { 2, 1 }, /* Up */ - [0x4d] = { 3, 1 }, /* Right */ - [0x4c] = { 4, 1 }, /* Centre */ - [0x39] = { 4, 1 }, /* Spc -> Centre */ -}; - -static void palmte_button_event(void *opaque, int keycode) -{ - struct omap_mpu_state_s *cpu = (struct omap_mpu_state_s *) opaque; - - if (palmte_keymap[keycode & 0x7f].row != -1) - omap_mpuio_key(cpu->mpuio, - palmte_keymap[keycode & 0x7f].row, - palmte_keymap[keycode & 0x7f].column, - !(keycode & 0x80)); -} - -static void palmte_onoff_gpios(void *opaque, int line, int level) -{ - switch (line) { - case 0: - printf("%s: current to MMC/SD card %sabled.\n", - __FUNCTION__, level ? "dis" : "en"); - break; - case 1: - printf("%s: internal speaker amplifier %s.\n", - __FUNCTION__, level ? "down" : "on"); - break; - - /* These LCD & Audio output signals have not been identified yet. */ - case 2: - case 3: - case 4: - printf("%s: LCD GPIO%i %s.\n", - __FUNCTION__, line - 1, level ? "high" : "low"); - break; - case 5: - case 6: - printf("%s: Audio GPIO%i %s.\n", - __FUNCTION__, line - 4, level ? "high" : "low"); - break; - } -} - -static void palmte_gpio_setup(struct omap_mpu_state_s *cpu) -{ - qemu_irq *misc_gpio; - - omap_mmc_handlers(cpu->mmc, - qdev_get_gpio_in(cpu->gpio, PALMTE_MMC_WP_GPIO), - qemu_irq_invert(omap_mpuio_in_get(cpu->mpuio) - [PALMTE_MMC_SWITCH_GPIO])); - - misc_gpio = qemu_allocate_irqs(palmte_onoff_gpios, cpu, 7); - qdev_connect_gpio_out(cpu->gpio, PALMTE_MMC_POWER_GPIO, misc_gpio[0]); - qdev_connect_gpio_out(cpu->gpio, PALMTE_SPEAKER_GPIO, misc_gpio[1]); - qdev_connect_gpio_out(cpu->gpio, 11, misc_gpio[2]); - qdev_connect_gpio_out(cpu->gpio, 12, misc_gpio[3]); - qdev_connect_gpio_out(cpu->gpio, 13, misc_gpio[4]); - omap_mpuio_out_set(cpu->mpuio, 1, misc_gpio[5]); - omap_mpuio_out_set(cpu->mpuio, 3, misc_gpio[6]); - - /* Reset some inputs to initial state. */ - qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, PALMTE_USBDETECT_GPIO)); - qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, PALMTE_USB_OR_DC_GPIO)); - qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, 4)); - qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, PALMTE_HEADPHONES_GPIO)); - qemu_irq_lower(omap_mpuio_in_get(cpu->mpuio)[PALMTE_DC_GPIO]); - qemu_irq_raise(omap_mpuio_in_get(cpu->mpuio)[6]); - qemu_irq_raise(omap_mpuio_in_get(cpu->mpuio)[7]); - qemu_irq_raise(omap_mpuio_in_get(cpu->mpuio)[11]); -} - -static struct arm_boot_info palmte_binfo = { - .loader_start = OMAP_EMIFF_BASE, - .ram_size = 0x02000000, - .board_id = 0x331, -}; - -static void palmte_init(MachineState *machine) -{ - const char *cpu_model = machine->cpu_model; - const char *kernel_filename = machine->kernel_filename; - const char *kernel_cmdline = machine->kernel_cmdline; - const char *initrd_filename = machine->initrd_filename; - MemoryRegion *address_space_mem = get_system_memory(); - struct omap_mpu_state_s *mpu; - int flash_size = 0x00800000; - int sdram_size = palmte_binfo.ram_size; - static uint32_t cs0val = 0xffffffff; - static uint32_t cs1val = 0x0000e1a0; - static uint32_t cs2val = 0x0000e1a0; - static uint32_t cs3val = 0xe1a0e1a0; - int rom_size, rom_loaded = 0; - MemoryRegion *flash = g_new(MemoryRegion, 1); - MemoryRegion *cs = g_new(MemoryRegion, 4); - - mpu = omap310_mpu_init(address_space_mem, sdram_size, cpu_model); - - /* External Flash (EMIFS) */ - memory_region_init_ram(flash, NULL, "palmte.flash", flash_size, - &error_fatal); - vmstate_register_ram_global(flash); - memory_region_set_readonly(flash, true); - memory_region_add_subregion(address_space_mem, OMAP_CS0_BASE, flash); - - memory_region_init_io(&cs[0], NULL, &static_ops, &cs0val, "palmte-cs0", - OMAP_CS0_SIZE - flash_size); - memory_region_add_subregion(address_space_mem, OMAP_CS0_BASE + flash_size, - &cs[0]); - memory_region_init_io(&cs[1], NULL, &static_ops, &cs1val, "palmte-cs1", - OMAP_CS1_SIZE); - memory_region_add_subregion(address_space_mem, OMAP_CS1_BASE, &cs[1]); - memory_region_init_io(&cs[2], NULL, &static_ops, &cs2val, "palmte-cs2", - OMAP_CS2_SIZE); - memory_region_add_subregion(address_space_mem, OMAP_CS2_BASE, &cs[2]); - memory_region_init_io(&cs[3], NULL, &static_ops, &cs3val, "palmte-cs3", - OMAP_CS3_SIZE); - memory_region_add_subregion(address_space_mem, OMAP_CS3_BASE, &cs[3]); - - palmte_microwire_setup(mpu); - - qemu_add_kbd_event_handler(palmte_button_event, mpu); - - palmte_gpio_setup(mpu); - - /* Setup initial (reset) machine state */ - if (nb_option_roms) { - rom_size = get_image_size(option_rom[0].name); - if (rom_size > flash_size) { - fprintf(stderr, "%s: ROM image too big (%x > %x)\n", - __FUNCTION__, rom_size, flash_size); - rom_size = 0; - } - if (rom_size > 0) { - rom_size = load_image_targphys(option_rom[0].name, OMAP_CS0_BASE, - flash_size); - rom_loaded = 1; - } - if (rom_size < 0) { - fprintf(stderr, "%s: error loading '%s'\n", - __FUNCTION__, option_rom[0].name); - } - } - - if (!rom_loaded && !kernel_filename && !qtest_enabled()) { - fprintf(stderr, "Kernel or ROM image must be specified\n"); - exit(1); - } - - /* Load the kernel. */ - palmte_binfo.kernel_filename = kernel_filename; - palmte_binfo.kernel_cmdline = kernel_cmdline; - palmte_binfo.initrd_filename = initrd_filename; - arm_load_kernel(mpu->cpu, &palmte_binfo); -} - -static void palmte_machine_init(MachineClass *mc) -{ - mc->desc = "Palm Tungsten|E aka. Cheetah PDA (OMAP310)"; - mc->init = palmte_init; -} - -DEFINE_MACHINE("cheetah", palmte_machine_init) diff --git a/qemu/hw/arm/palmetto-bmc.c b/qemu/hw/arm/palmetto-bmc.c deleted file mode 100644 index 89ebd92b9..000000000 --- a/qemu/hw/arm/palmetto-bmc.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * OpenPOWER Palmetto BMC - * - * Andrew Jeffery <andrew@aj.id.au> - * - * Copyright 2016 IBM Corp. - * - * This code is licensed under the GPL version 2 or later. See - * the COPYING file in the top-level directory. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "qemu-common.h" -#include "cpu.h" -#include "exec/address-spaces.h" -#include "hw/arm/arm.h" -#include "hw/arm/ast2400.h" -#include "hw/boards.h" - -static struct arm_boot_info palmetto_bmc_binfo = { - .loader_start = AST2400_SDRAM_BASE, - .board_id = 0, - .nb_cpus = 1, -}; - -typedef struct PalmettoBMCState { - AST2400State soc; - MemoryRegion ram; -} PalmettoBMCState; - -static void palmetto_bmc_init(MachineState *machine) -{ - PalmettoBMCState *bmc; - - bmc = g_new0(PalmettoBMCState, 1); - object_initialize(&bmc->soc, (sizeof(bmc->soc)), TYPE_AST2400); - object_property_add_child(OBJECT(machine), "soc", OBJECT(&bmc->soc), - &error_abort); - - memory_region_allocate_system_memory(&bmc->ram, NULL, "ram", ram_size); - memory_region_add_subregion(get_system_memory(), AST2400_SDRAM_BASE, - &bmc->ram); - object_property_add_const_link(OBJECT(&bmc->soc), "ram", OBJECT(&bmc->ram), - &error_abort); - object_property_set_bool(OBJECT(&bmc->soc), true, "realized", - &error_abort); - - palmetto_bmc_binfo.kernel_filename = machine->kernel_filename; - palmetto_bmc_binfo.initrd_filename = machine->initrd_filename; - palmetto_bmc_binfo.kernel_cmdline = machine->kernel_cmdline; - palmetto_bmc_binfo.ram_size = ram_size; - arm_load_kernel(ARM_CPU(first_cpu), &palmetto_bmc_binfo); -} - -static void palmetto_bmc_machine_init(MachineClass *mc) -{ - mc->desc = "OpenPOWER Palmetto BMC"; - mc->init = palmetto_bmc_init; - mc->max_cpus = 1; - mc->no_sdcard = 1; - mc->no_floppy = 1; - mc->no_cdrom = 1; - mc->no_sdcard = 1; - mc->no_parallel = 1; -} - -DEFINE_MACHINE("palmetto-bmc", palmetto_bmc_machine_init); diff --git a/qemu/hw/arm/pxa2xx.c b/qemu/hw/arm/pxa2xx.c deleted file mode 100644 index 1a8c36033..000000000 --- a/qemu/hw/arm/pxa2xx.c +++ /dev/null @@ -1,2358 +0,0 @@ -/* - * Intel XScale PXA255/270 processor support. - * - * Copyright (c) 2006 Openedhand Ltd. - * Written by Andrzej Zaborowski <balrog@zabor.org> - * - * This code is licensed under the GPL. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "qemu-common.h" -#include "cpu.h" -#include "hw/sysbus.h" -#include "hw/arm/pxa.h" -#include "sysemu/sysemu.h" -#include "hw/char/serial.h" -#include "hw/i2c/i2c.h" -#include "hw/ssi/ssi.h" -#include "sysemu/char.h" -#include "sysemu/block-backend.h" -#include "sysemu/blockdev.h" -#include "qemu/cutils.h" - -static struct { - hwaddr io_base; - int irqn; -} pxa255_serial[] = { - { 0x40100000, PXA2XX_PIC_FFUART }, - { 0x40200000, PXA2XX_PIC_BTUART }, - { 0x40700000, PXA2XX_PIC_STUART }, - { 0x41600000, PXA25X_PIC_HWUART }, - { 0, 0 } -}, pxa270_serial[] = { - { 0x40100000, PXA2XX_PIC_FFUART }, - { 0x40200000, PXA2XX_PIC_BTUART }, - { 0x40700000, PXA2XX_PIC_STUART }, - { 0, 0 } -}; - -typedef struct PXASSPDef { - hwaddr io_base; - int irqn; -} PXASSPDef; - -#if 0 -static PXASSPDef pxa250_ssp[] = { - { 0x41000000, PXA2XX_PIC_SSP }, - { 0, 0 } -}; -#endif - -static PXASSPDef pxa255_ssp[] = { - { 0x41000000, PXA2XX_PIC_SSP }, - { 0x41400000, PXA25X_PIC_NSSP }, - { 0, 0 } -}; - -#if 0 -static PXASSPDef pxa26x_ssp[] = { - { 0x41000000, PXA2XX_PIC_SSP }, - { 0x41400000, PXA25X_PIC_NSSP }, - { 0x41500000, PXA26X_PIC_ASSP }, - { 0, 0 } -}; -#endif - -static PXASSPDef pxa27x_ssp[] = { - { 0x41000000, PXA2XX_PIC_SSP }, - { 0x41700000, PXA27X_PIC_SSP2 }, - { 0x41900000, PXA2XX_PIC_SSP3 }, - { 0, 0 } -}; - -#define PMCR 0x00 /* Power Manager Control register */ -#define PSSR 0x04 /* Power Manager Sleep Status register */ -#define PSPR 0x08 /* Power Manager Scratch-Pad register */ -#define PWER 0x0c /* Power Manager Wake-Up Enable register */ -#define PRER 0x10 /* Power Manager Rising-Edge Detect Enable register */ -#define PFER 0x14 /* Power Manager Falling-Edge Detect Enable register */ -#define PEDR 0x18 /* Power Manager Edge-Detect Status register */ -#define PCFR 0x1c /* Power Manager General Configuration register */ -#define PGSR0 0x20 /* Power Manager GPIO Sleep-State register 0 */ -#define PGSR1 0x24 /* Power Manager GPIO Sleep-State register 1 */ -#define PGSR2 0x28 /* Power Manager GPIO Sleep-State register 2 */ -#define PGSR3 0x2c /* Power Manager GPIO Sleep-State register 3 */ -#define RCSR 0x30 /* Reset Controller Status register */ -#define PSLR 0x34 /* Power Manager Sleep Configuration register */ -#define PTSR 0x38 /* Power Manager Standby Configuration register */ -#define PVCR 0x40 /* Power Manager Voltage Change Control register */ -#define PUCR 0x4c /* Power Manager USIM Card Control/Status register */ -#define PKWR 0x50 /* Power Manager Keyboard Wake-Up Enable register */ -#define PKSR 0x54 /* Power Manager Keyboard Level-Detect Status */ -#define PCMD0 0x80 /* Power Manager I2C Command register File 0 */ -#define PCMD31 0xfc /* Power Manager I2C Command register File 31 */ - -static uint64_t pxa2xx_pm_read(void *opaque, hwaddr addr, - unsigned size) -{ - PXA2xxState *s = (PXA2xxState *) opaque; - - switch (addr) { - case PMCR ... PCMD31: - if (addr & 3) - goto fail; - - return s->pm_regs[addr >> 2]; - default: - fail: - printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); - break; - } - return 0; -} - -static void pxa2xx_pm_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - PXA2xxState *s = (PXA2xxState *) opaque; - - switch (addr) { - case PMCR: - /* Clear the write-one-to-clear bits... */ - s->pm_regs[addr >> 2] &= ~(value & 0x2a); - /* ...and set the plain r/w bits */ - s->pm_regs[addr >> 2] &= ~0x15; - s->pm_regs[addr >> 2] |= value & 0x15; - break; - - case PSSR: /* Read-clean registers */ - case RCSR: - case PKSR: - s->pm_regs[addr >> 2] &= ~value; - break; - - default: /* Read-write registers */ - if (!(addr & 3)) { - s->pm_regs[addr >> 2] = value; - break; - } - - printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); - break; - } -} - -static const MemoryRegionOps pxa2xx_pm_ops = { - .read = pxa2xx_pm_read, - .write = pxa2xx_pm_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static const VMStateDescription vmstate_pxa2xx_pm = { - .name = "pxa2xx_pm", - .version_id = 0, - .minimum_version_id = 0, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(pm_regs, PXA2xxState, 0x40), - VMSTATE_END_OF_LIST() - } -}; - -#define CCCR 0x00 /* Core Clock Configuration register */ -#define CKEN 0x04 /* Clock Enable register */ -#define OSCC 0x08 /* Oscillator Configuration register */ -#define CCSR 0x0c /* Core Clock Status register */ - -static uint64_t pxa2xx_cm_read(void *opaque, hwaddr addr, - unsigned size) -{ - PXA2xxState *s = (PXA2xxState *) opaque; - - switch (addr) { - case CCCR: - case CKEN: - case OSCC: - return s->cm_regs[addr >> 2]; - - case CCSR: - return s->cm_regs[CCCR >> 2] | (3 << 28); - - default: - printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); - break; - } - return 0; -} - -static void pxa2xx_cm_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - PXA2xxState *s = (PXA2xxState *) opaque; - - switch (addr) { - case CCCR: - case CKEN: - s->cm_regs[addr >> 2] = value; - break; - - case OSCC: - s->cm_regs[addr >> 2] &= ~0x6c; - s->cm_regs[addr >> 2] |= value & 0x6e; - if ((value >> 1) & 1) /* OON */ - s->cm_regs[addr >> 2] |= 1 << 0; /* Oscillator is now stable */ - break; - - default: - printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); - break; - } -} - -static const MemoryRegionOps pxa2xx_cm_ops = { - .read = pxa2xx_cm_read, - .write = pxa2xx_cm_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static const VMStateDescription vmstate_pxa2xx_cm = { - .name = "pxa2xx_cm", - .version_id = 0, - .minimum_version_id = 0, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(cm_regs, PXA2xxState, 4), - VMSTATE_UINT32(clkcfg, PXA2xxState), - VMSTATE_UINT32(pmnc, PXA2xxState), - VMSTATE_END_OF_LIST() - } -}; - -static uint64_t pxa2xx_clkcfg_read(CPUARMState *env, const ARMCPRegInfo *ri) -{ - PXA2xxState *s = (PXA2xxState *)ri->opaque; - return s->clkcfg; -} - -static void pxa2xx_clkcfg_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - PXA2xxState *s = (PXA2xxState *)ri->opaque; - s->clkcfg = value & 0xf; - if (value & 2) { - printf("%s: CPU frequency change attempt\n", __func__); - } -} - -static void pxa2xx_pwrmode_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - PXA2xxState *s = (PXA2xxState *)ri->opaque; - static const char *pwrmode[8] = { - "Normal", "Idle", "Deep-idle", "Standby", - "Sleep", "reserved (!)", "reserved (!)", "Deep-sleep", - }; - - if (value & 8) { - printf("%s: CPU voltage change attempt\n", __func__); - } - switch (value & 7) { - case 0: - /* Do nothing */ - break; - - case 1: - /* Idle */ - if (!(s->cm_regs[CCCR >> 2] & (1U << 31))) { /* CPDIS */ - cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_HALT); - break; - } - /* Fall through. */ - - case 2: - /* Deep-Idle */ - cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_HALT); - s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */ - goto message; - - case 3: - s->cpu->env.uncached_cpsr = ARM_CPU_MODE_SVC; - s->cpu->env.daif = PSTATE_A | PSTATE_F | PSTATE_I; - s->cpu->env.cp15.sctlr_ns = 0; - s->cpu->env.cp15.cpacr_el1 = 0; - s->cpu->env.cp15.ttbr0_el[1] = 0; - s->cpu->env.cp15.dacr_ns = 0; - s->pm_regs[PSSR >> 2] |= 0x8; /* Set STS */ - s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */ - - /* - * The scratch-pad register is almost universally used - * for storing the return address on suspend. For the - * lack of a resuming bootloader, perform a jump - * directly to that address. - */ - memset(s->cpu->env.regs, 0, 4 * 15); - s->cpu->env.regs[15] = s->pm_regs[PSPR >> 2]; - -#if 0 - buffer = 0xe59ff000; /* ldr pc, [pc, #0] */ - cpu_physical_memory_write(0, &buffer, 4); - buffer = s->pm_regs[PSPR >> 2]; - cpu_physical_memory_write(8, &buffer, 4); -#endif - - /* Suspend */ - cpu_interrupt(current_cpu, CPU_INTERRUPT_HALT); - - goto message; - - default: - message: - printf("%s: machine entered %s mode\n", __func__, - pwrmode[value & 7]); - } -} - -static uint64_t pxa2xx_cppmnc_read(CPUARMState *env, const ARMCPRegInfo *ri) -{ - PXA2xxState *s = (PXA2xxState *)ri->opaque; - return s->pmnc; -} - -static void pxa2xx_cppmnc_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - PXA2xxState *s = (PXA2xxState *)ri->opaque; - s->pmnc = value; -} - -static uint64_t pxa2xx_cpccnt_read(CPUARMState *env, const ARMCPRegInfo *ri) -{ - PXA2xxState *s = (PXA2xxState *)ri->opaque; - if (s->pmnc & 1) { - return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - } else { - return 0; - } -} - -static const ARMCPRegInfo pxa_cp_reginfo[] = { - /* cp14 crm==1: perf registers */ - { .name = "CPPMNC", .cp = 14, .crn = 0, .crm = 1, .opc1 = 0, .opc2 = 0, - .access = PL1_RW, .type = ARM_CP_IO, - .readfn = pxa2xx_cppmnc_read, .writefn = pxa2xx_cppmnc_write }, - { .name = "CPCCNT", .cp = 14, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 0, - .access = PL1_RW, .type = ARM_CP_IO, - .readfn = pxa2xx_cpccnt_read, .writefn = arm_cp_write_ignore }, - { .name = "CPINTEN", .cp = 14, .crn = 4, .crm = 1, .opc1 = 0, .opc2 = 0, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CPFLAG", .cp = 14, .crn = 5, .crm = 1, .opc1 = 0, .opc2 = 0, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CPEVTSEL", .cp = 14, .crn = 8, .crm = 1, .opc1 = 0, .opc2 = 0, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - /* cp14 crm==2: performance count registers */ - { .name = "CPPMN0", .cp = 14, .crn = 0, .crm = 2, .opc1 = 0, .opc2 = 0, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CPPMN1", .cp = 14, .crn = 1, .crm = 2, .opc1 = 0, .opc2 = 0, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CPPMN2", .cp = 14, .crn = 2, .crm = 2, .opc1 = 0, .opc2 = 0, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CPPMN3", .cp = 14, .crn = 2, .crm = 3, .opc1 = 0, .opc2 = 0, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - /* cp14 crn==6: CLKCFG */ - { .name = "CLKCFG", .cp = 14, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0, - .access = PL1_RW, .type = ARM_CP_IO, - .readfn = pxa2xx_clkcfg_read, .writefn = pxa2xx_clkcfg_write }, - /* cp14 crn==7: PWRMODE */ - { .name = "PWRMODE", .cp = 14, .crn = 7, .crm = 0, .opc1 = 0, .opc2 = 0, - .access = PL1_RW, .type = ARM_CP_IO, - .readfn = arm_cp_read_zero, .writefn = pxa2xx_pwrmode_write }, - REGINFO_SENTINEL -}; - -static void pxa2xx_setup_cp14(PXA2xxState *s) -{ - define_arm_cp_regs_with_opaque(s->cpu, pxa_cp_reginfo, s); -} - -#define MDCNFG 0x00 /* SDRAM Configuration register */ -#define MDREFR 0x04 /* SDRAM Refresh Control register */ -#define MSC0 0x08 /* Static Memory Control register 0 */ -#define MSC1 0x0c /* Static Memory Control register 1 */ -#define MSC2 0x10 /* Static Memory Control register 2 */ -#define MECR 0x14 /* Expansion Memory Bus Config register */ -#define SXCNFG 0x1c /* Synchronous Static Memory Config register */ -#define MCMEM0 0x28 /* PC Card Memory Socket 0 Timing register */ -#define MCMEM1 0x2c /* PC Card Memory Socket 1 Timing register */ -#define MCATT0 0x30 /* PC Card Attribute Socket 0 register */ -#define MCATT1 0x34 /* PC Card Attribute Socket 1 register */ -#define MCIO0 0x38 /* PC Card I/O Socket 0 Timing register */ -#define MCIO1 0x3c /* PC Card I/O Socket 1 Timing register */ -#define MDMRS 0x40 /* SDRAM Mode Register Set Config register */ -#define BOOT_DEF 0x44 /* Boot-time Default Configuration register */ -#define ARB_CNTL 0x48 /* Arbiter Control register */ -#define BSCNTR0 0x4c /* Memory Buffer Strength Control register 0 */ -#define BSCNTR1 0x50 /* Memory Buffer Strength Control register 1 */ -#define LCDBSCNTR 0x54 /* LCD Buffer Strength Control register */ -#define MDMRSLP 0x58 /* Low Power SDRAM Mode Set Config register */ -#define BSCNTR2 0x5c /* Memory Buffer Strength Control register 2 */ -#define BSCNTR3 0x60 /* Memory Buffer Strength Control register 3 */ -#define SA1110 0x64 /* SA-1110 Memory Compatibility register */ - -static uint64_t pxa2xx_mm_read(void *opaque, hwaddr addr, - unsigned size) -{ - PXA2xxState *s = (PXA2xxState *) opaque; - - switch (addr) { - case MDCNFG ... SA1110: - if ((addr & 3) == 0) - return s->mm_regs[addr >> 2]; - - default: - printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); - break; - } - return 0; -} - -static void pxa2xx_mm_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - PXA2xxState *s = (PXA2xxState *) opaque; - - switch (addr) { - case MDCNFG ... SA1110: - if ((addr & 3) == 0) { - s->mm_regs[addr >> 2] = value; - break; - } - - default: - printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); - break; - } -} - -static const MemoryRegionOps pxa2xx_mm_ops = { - .read = pxa2xx_mm_read, - .write = pxa2xx_mm_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static const VMStateDescription vmstate_pxa2xx_mm = { - .name = "pxa2xx_mm", - .version_id = 0, - .minimum_version_id = 0, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(mm_regs, PXA2xxState, 0x1a), - VMSTATE_END_OF_LIST() - } -}; - -#define TYPE_PXA2XX_SSP "pxa2xx-ssp" -#define PXA2XX_SSP(obj) \ - OBJECT_CHECK(PXA2xxSSPState, (obj), TYPE_PXA2XX_SSP) - -/* Synchronous Serial Ports */ -typedef struct { - /*< private >*/ - SysBusDevice parent_obj; - /*< public >*/ - - MemoryRegion iomem; - qemu_irq irq; - uint32_t enable; - SSIBus *bus; - - uint32_t sscr[2]; - uint32_t sspsp; - uint32_t ssto; - uint32_t ssitr; - uint32_t sssr; - uint8_t sstsa; - uint8_t ssrsa; - uint8_t ssacd; - - uint32_t rx_fifo[16]; - uint32_t rx_level; - uint32_t rx_start; -} PXA2xxSSPState; - -static bool pxa2xx_ssp_vmstate_validate(void *opaque, int version_id) -{ - PXA2xxSSPState *s = opaque; - - return s->rx_start < sizeof(s->rx_fifo); -} - -static const VMStateDescription vmstate_pxa2xx_ssp = { - .name = "pxa2xx-ssp", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(enable, PXA2xxSSPState), - VMSTATE_UINT32_ARRAY(sscr, PXA2xxSSPState, 2), - VMSTATE_UINT32(sspsp, PXA2xxSSPState), - VMSTATE_UINT32(ssto, PXA2xxSSPState), - VMSTATE_UINT32(ssitr, PXA2xxSSPState), - VMSTATE_UINT32(sssr, PXA2xxSSPState), - VMSTATE_UINT8(sstsa, PXA2xxSSPState), - VMSTATE_UINT8(ssrsa, PXA2xxSSPState), - VMSTATE_UINT8(ssacd, PXA2xxSSPState), - VMSTATE_UINT32(rx_level, PXA2xxSSPState), - VMSTATE_UINT32(rx_start, PXA2xxSSPState), - VMSTATE_VALIDATE("fifo is 16 bytes", pxa2xx_ssp_vmstate_validate), - VMSTATE_UINT32_ARRAY(rx_fifo, PXA2xxSSPState, 16), - VMSTATE_END_OF_LIST() - } -}; - -#define SSCR0 0x00 /* SSP Control register 0 */ -#define SSCR1 0x04 /* SSP Control register 1 */ -#define SSSR 0x08 /* SSP Status register */ -#define SSITR 0x0c /* SSP Interrupt Test register */ -#define SSDR 0x10 /* SSP Data register */ -#define SSTO 0x28 /* SSP Time-Out register */ -#define SSPSP 0x2c /* SSP Programmable Serial Protocol register */ -#define SSTSA 0x30 /* SSP TX Time Slot Active register */ -#define SSRSA 0x34 /* SSP RX Time Slot Active register */ -#define SSTSS 0x38 /* SSP Time Slot Status register */ -#define SSACD 0x3c /* SSP Audio Clock Divider register */ - -/* Bitfields for above registers */ -#define SSCR0_SPI(x) (((x) & 0x30) == 0x00) -#define SSCR0_SSP(x) (((x) & 0x30) == 0x10) -#define SSCR0_UWIRE(x) (((x) & 0x30) == 0x20) -#define SSCR0_PSP(x) (((x) & 0x30) == 0x30) -#define SSCR0_SSE (1 << 7) -#define SSCR0_RIM (1 << 22) -#define SSCR0_TIM (1 << 23) -#define SSCR0_MOD (1U << 31) -#define SSCR0_DSS(x) (((((x) >> 16) & 0x10) | ((x) & 0xf)) + 1) -#define SSCR1_RIE (1 << 0) -#define SSCR1_TIE (1 << 1) -#define SSCR1_LBM (1 << 2) -#define SSCR1_MWDS (1 << 5) -#define SSCR1_TFT(x) ((((x) >> 6) & 0xf) + 1) -#define SSCR1_RFT(x) ((((x) >> 10) & 0xf) + 1) -#define SSCR1_EFWR (1 << 14) -#define SSCR1_PINTE (1 << 18) -#define SSCR1_TINTE (1 << 19) -#define SSCR1_RSRE (1 << 20) -#define SSCR1_TSRE (1 << 21) -#define SSCR1_EBCEI (1 << 29) -#define SSITR_INT (7 << 5) -#define SSSR_TNF (1 << 2) -#define SSSR_RNE (1 << 3) -#define SSSR_TFS (1 << 5) -#define SSSR_RFS (1 << 6) -#define SSSR_ROR (1 << 7) -#define SSSR_PINT (1 << 18) -#define SSSR_TINT (1 << 19) -#define SSSR_EOC (1 << 20) -#define SSSR_TUR (1 << 21) -#define SSSR_BCE (1 << 23) -#define SSSR_RW 0x00bc0080 - -static void pxa2xx_ssp_int_update(PXA2xxSSPState *s) -{ - int level = 0; - - level |= s->ssitr & SSITR_INT; - level |= (s->sssr & SSSR_BCE) && (s->sscr[1] & SSCR1_EBCEI); - level |= (s->sssr & SSSR_TUR) && !(s->sscr[0] & SSCR0_TIM); - level |= (s->sssr & SSSR_EOC) && (s->sssr & (SSSR_TINT | SSSR_PINT)); - level |= (s->sssr & SSSR_TINT) && (s->sscr[1] & SSCR1_TINTE); - level |= (s->sssr & SSSR_PINT) && (s->sscr[1] & SSCR1_PINTE); - level |= (s->sssr & SSSR_ROR) && !(s->sscr[0] & SSCR0_RIM); - level |= (s->sssr & SSSR_RFS) && (s->sscr[1] & SSCR1_RIE); - level |= (s->sssr & SSSR_TFS) && (s->sscr[1] & SSCR1_TIE); - qemu_set_irq(s->irq, !!level); -} - -static void pxa2xx_ssp_fifo_update(PXA2xxSSPState *s) -{ - s->sssr &= ~(0xf << 12); /* Clear RFL */ - s->sssr &= ~(0xf << 8); /* Clear TFL */ - s->sssr &= ~SSSR_TFS; - s->sssr &= ~SSSR_TNF; - if (s->enable) { - s->sssr |= ((s->rx_level - 1) & 0xf) << 12; - if (s->rx_level >= SSCR1_RFT(s->sscr[1])) - s->sssr |= SSSR_RFS; - else - s->sssr &= ~SSSR_RFS; - if (s->rx_level) - s->sssr |= SSSR_RNE; - else - s->sssr &= ~SSSR_RNE; - /* TX FIFO is never filled, so it is always in underrun - condition if SSP is enabled */ - s->sssr |= SSSR_TFS; - s->sssr |= SSSR_TNF; - } - - pxa2xx_ssp_int_update(s); -} - -static uint64_t pxa2xx_ssp_read(void *opaque, hwaddr addr, - unsigned size) -{ - PXA2xxSSPState *s = (PXA2xxSSPState *) opaque; - uint32_t retval; - - switch (addr) { - case SSCR0: - return s->sscr[0]; - case SSCR1: - return s->sscr[1]; - case SSPSP: - return s->sspsp; - case SSTO: - return s->ssto; - case SSITR: - return s->ssitr; - case SSSR: - return s->sssr | s->ssitr; - case SSDR: - if (!s->enable) - return 0xffffffff; - if (s->rx_level < 1) { - printf("%s: SSP Rx Underrun\n", __FUNCTION__); - return 0xffffffff; - } - s->rx_level --; - retval = s->rx_fifo[s->rx_start ++]; - s->rx_start &= 0xf; - pxa2xx_ssp_fifo_update(s); - return retval; - case SSTSA: - return s->sstsa; - case SSRSA: - return s->ssrsa; - case SSTSS: - return 0; - case SSACD: - return s->ssacd; - default: - printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); - break; - } - return 0; -} - -static void pxa2xx_ssp_write(void *opaque, hwaddr addr, - uint64_t value64, unsigned size) -{ - PXA2xxSSPState *s = (PXA2xxSSPState *) opaque; - uint32_t value = value64; - - switch (addr) { - case SSCR0: - s->sscr[0] = value & 0xc7ffffff; - s->enable = value & SSCR0_SSE; - if (value & SSCR0_MOD) - printf("%s: Attempt to use network mode\n", __FUNCTION__); - if (s->enable && SSCR0_DSS(value) < 4) - printf("%s: Wrong data size: %i bits\n", __FUNCTION__, - SSCR0_DSS(value)); - if (!(value & SSCR0_SSE)) { - s->sssr = 0; - s->ssitr = 0; - s->rx_level = 0; - } - pxa2xx_ssp_fifo_update(s); - break; - - case SSCR1: - s->sscr[1] = value; - if (value & (SSCR1_LBM | SSCR1_EFWR)) - printf("%s: Attempt to use SSP test mode\n", __FUNCTION__); - pxa2xx_ssp_fifo_update(s); - break; - - case SSPSP: - s->sspsp = value; - break; - - case SSTO: - s->ssto = value; - break; - - case SSITR: - s->ssitr = value & SSITR_INT; - pxa2xx_ssp_int_update(s); - break; - - case SSSR: - s->sssr &= ~(value & SSSR_RW); - pxa2xx_ssp_int_update(s); - break; - - case SSDR: - if (SSCR0_UWIRE(s->sscr[0])) { - if (s->sscr[1] & SSCR1_MWDS) - value &= 0xffff; - else - value &= 0xff; - } else - /* Note how 32bits overflow does no harm here */ - value &= (1 << SSCR0_DSS(s->sscr[0])) - 1; - - /* Data goes from here to the Tx FIFO and is shifted out from - * there directly to the slave, no need to buffer it. - */ - if (s->enable) { - uint32_t readval; - readval = ssi_transfer(s->bus, value); - if (s->rx_level < 0x10) { - s->rx_fifo[(s->rx_start + s->rx_level ++) & 0xf] = readval; - } else { - s->sssr |= SSSR_ROR; - } - } - pxa2xx_ssp_fifo_update(s); - break; - - case SSTSA: - s->sstsa = value; - break; - - case SSRSA: - s->ssrsa = value; - break; - - case SSACD: - s->ssacd = value; - break; - - default: - printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); - break; - } -} - -static const MemoryRegionOps pxa2xx_ssp_ops = { - .read = pxa2xx_ssp_read, - .write = pxa2xx_ssp_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void pxa2xx_ssp_reset(DeviceState *d) -{ - PXA2xxSSPState *s = PXA2XX_SSP(d); - - s->enable = 0; - s->sscr[0] = s->sscr[1] = 0; - s->sspsp = 0; - s->ssto = 0; - s->ssitr = 0; - s->sssr = 0; - s->sstsa = 0; - s->ssrsa = 0; - s->ssacd = 0; - s->rx_start = s->rx_level = 0; -} - -static int pxa2xx_ssp_init(SysBusDevice *sbd) -{ - DeviceState *dev = DEVICE(sbd); - PXA2xxSSPState *s = PXA2XX_SSP(dev); - - sysbus_init_irq(sbd, &s->irq); - - memory_region_init_io(&s->iomem, OBJECT(s), &pxa2xx_ssp_ops, s, - "pxa2xx-ssp", 0x1000); - sysbus_init_mmio(sbd, &s->iomem); - - s->bus = ssi_create_bus(dev, "ssi"); - return 0; -} - -/* Real-Time Clock */ -#define RCNR 0x00 /* RTC Counter register */ -#define RTAR 0x04 /* RTC Alarm register */ -#define RTSR 0x08 /* RTC Status register */ -#define RTTR 0x0c /* RTC Timer Trim register */ -#define RDCR 0x10 /* RTC Day Counter register */ -#define RYCR 0x14 /* RTC Year Counter register */ -#define RDAR1 0x18 /* RTC Wristwatch Day Alarm register 1 */ -#define RYAR1 0x1c /* RTC Wristwatch Year Alarm register 1 */ -#define RDAR2 0x20 /* RTC Wristwatch Day Alarm register 2 */ -#define RYAR2 0x24 /* RTC Wristwatch Year Alarm register 2 */ -#define SWCR 0x28 /* RTC Stopwatch Counter register */ -#define SWAR1 0x2c /* RTC Stopwatch Alarm register 1 */ -#define SWAR2 0x30 /* RTC Stopwatch Alarm register 2 */ -#define RTCPICR 0x34 /* RTC Periodic Interrupt Counter register */ -#define PIAR 0x38 /* RTC Periodic Interrupt Alarm register */ - -#define TYPE_PXA2XX_RTC "pxa2xx_rtc" -#define PXA2XX_RTC(obj) \ - OBJECT_CHECK(PXA2xxRTCState, (obj), TYPE_PXA2XX_RTC) - -typedef struct { - /*< private >*/ - SysBusDevice parent_obj; - /*< public >*/ - - MemoryRegion iomem; - uint32_t rttr; - uint32_t rtsr; - uint32_t rtar; - uint32_t rdar1; - uint32_t rdar2; - uint32_t ryar1; - uint32_t ryar2; - uint32_t swar1; - uint32_t swar2; - uint32_t piar; - uint32_t last_rcnr; - uint32_t last_rdcr; - uint32_t last_rycr; - uint32_t last_swcr; - uint32_t last_rtcpicr; - int64_t last_hz; - int64_t last_sw; - int64_t last_pi; - QEMUTimer *rtc_hz; - QEMUTimer *rtc_rdal1; - QEMUTimer *rtc_rdal2; - QEMUTimer *rtc_swal1; - QEMUTimer *rtc_swal2; - QEMUTimer *rtc_pi; - qemu_irq rtc_irq; -} PXA2xxRTCState; - -static inline void pxa2xx_rtc_int_update(PXA2xxRTCState *s) -{ - qemu_set_irq(s->rtc_irq, !!(s->rtsr & 0x2553)); -} - -static void pxa2xx_rtc_hzupdate(PXA2xxRTCState *s) -{ - int64_t rt = qemu_clock_get_ms(rtc_clock); - s->last_rcnr += ((rt - s->last_hz) << 15) / - (1000 * ((s->rttr & 0xffff) + 1)); - s->last_rdcr += ((rt - s->last_hz) << 15) / - (1000 * ((s->rttr & 0xffff) + 1)); - s->last_hz = rt; -} - -static void pxa2xx_rtc_swupdate(PXA2xxRTCState *s) -{ - int64_t rt = qemu_clock_get_ms(rtc_clock); - if (s->rtsr & (1 << 12)) - s->last_swcr += (rt - s->last_sw) / 10; - s->last_sw = rt; -} - -static void pxa2xx_rtc_piupdate(PXA2xxRTCState *s) -{ - int64_t rt = qemu_clock_get_ms(rtc_clock); - if (s->rtsr & (1 << 15)) - s->last_swcr += rt - s->last_pi; - s->last_pi = rt; -} - -static inline void pxa2xx_rtc_alarm_update(PXA2xxRTCState *s, - uint32_t rtsr) -{ - if ((rtsr & (1 << 2)) && !(rtsr & (1 << 0))) - timer_mod(s->rtc_hz, s->last_hz + - (((s->rtar - s->last_rcnr) * 1000 * - ((s->rttr & 0xffff) + 1)) >> 15)); - else - timer_del(s->rtc_hz); - - if ((rtsr & (1 << 5)) && !(rtsr & (1 << 4))) - timer_mod(s->rtc_rdal1, s->last_hz + - (((s->rdar1 - s->last_rdcr) * 1000 * - ((s->rttr & 0xffff) + 1)) >> 15)); /* TODO: fixup */ - else - timer_del(s->rtc_rdal1); - - if ((rtsr & (1 << 7)) && !(rtsr & (1 << 6))) - timer_mod(s->rtc_rdal2, s->last_hz + - (((s->rdar2 - s->last_rdcr) * 1000 * - ((s->rttr & 0xffff) + 1)) >> 15)); /* TODO: fixup */ - else - timer_del(s->rtc_rdal2); - - if ((rtsr & 0x1200) == 0x1200 && !(rtsr & (1 << 8))) - timer_mod(s->rtc_swal1, s->last_sw + - (s->swar1 - s->last_swcr) * 10); /* TODO: fixup */ - else - timer_del(s->rtc_swal1); - - if ((rtsr & 0x1800) == 0x1800 && !(rtsr & (1 << 10))) - timer_mod(s->rtc_swal2, s->last_sw + - (s->swar2 - s->last_swcr) * 10); /* TODO: fixup */ - else - timer_del(s->rtc_swal2); - - if ((rtsr & 0xc000) == 0xc000 && !(rtsr & (1 << 13))) - timer_mod(s->rtc_pi, s->last_pi + - (s->piar & 0xffff) - s->last_rtcpicr); - else - timer_del(s->rtc_pi); -} - -static inline void pxa2xx_rtc_hz_tick(void *opaque) -{ - PXA2xxRTCState *s = (PXA2xxRTCState *) opaque; - s->rtsr |= (1 << 0); - pxa2xx_rtc_alarm_update(s, s->rtsr); - pxa2xx_rtc_int_update(s); -} - -static inline void pxa2xx_rtc_rdal1_tick(void *opaque) -{ - PXA2xxRTCState *s = (PXA2xxRTCState *) opaque; - s->rtsr |= (1 << 4); - pxa2xx_rtc_alarm_update(s, s->rtsr); - pxa2xx_rtc_int_update(s); -} - -static inline void pxa2xx_rtc_rdal2_tick(void *opaque) -{ - PXA2xxRTCState *s = (PXA2xxRTCState *) opaque; - s->rtsr |= (1 << 6); - pxa2xx_rtc_alarm_update(s, s->rtsr); - pxa2xx_rtc_int_update(s); -} - -static inline void pxa2xx_rtc_swal1_tick(void *opaque) -{ - PXA2xxRTCState *s = (PXA2xxRTCState *) opaque; - s->rtsr |= (1 << 8); - pxa2xx_rtc_alarm_update(s, s->rtsr); - pxa2xx_rtc_int_update(s); -} - -static inline void pxa2xx_rtc_swal2_tick(void *opaque) -{ - PXA2xxRTCState *s = (PXA2xxRTCState *) opaque; - s->rtsr |= (1 << 10); - pxa2xx_rtc_alarm_update(s, s->rtsr); - pxa2xx_rtc_int_update(s); -} - -static inline void pxa2xx_rtc_pi_tick(void *opaque) -{ - PXA2xxRTCState *s = (PXA2xxRTCState *) opaque; - s->rtsr |= (1 << 13); - pxa2xx_rtc_piupdate(s); - s->last_rtcpicr = 0; - pxa2xx_rtc_alarm_update(s, s->rtsr); - pxa2xx_rtc_int_update(s); -} - -static uint64_t pxa2xx_rtc_read(void *opaque, hwaddr addr, - unsigned size) -{ - PXA2xxRTCState *s = (PXA2xxRTCState *) opaque; - - switch (addr) { - case RTTR: - return s->rttr; - case RTSR: - return s->rtsr; - case RTAR: - return s->rtar; - case RDAR1: - return s->rdar1; - case RDAR2: - return s->rdar2; - case RYAR1: - return s->ryar1; - case RYAR2: - return s->ryar2; - case SWAR1: - return s->swar1; - case SWAR2: - return s->swar2; - case PIAR: - return s->piar; - case RCNR: - return s->last_rcnr + - ((qemu_clock_get_ms(rtc_clock) - s->last_hz) << 15) / - (1000 * ((s->rttr & 0xffff) + 1)); - case RDCR: - return s->last_rdcr + - ((qemu_clock_get_ms(rtc_clock) - s->last_hz) << 15) / - (1000 * ((s->rttr & 0xffff) + 1)); - case RYCR: - return s->last_rycr; - case SWCR: - if (s->rtsr & (1 << 12)) - return s->last_swcr + - (qemu_clock_get_ms(rtc_clock) - s->last_sw) / 10; - else - return s->last_swcr; - default: - printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); - break; - } - return 0; -} - -static void pxa2xx_rtc_write(void *opaque, hwaddr addr, - uint64_t value64, unsigned size) -{ - PXA2xxRTCState *s = (PXA2xxRTCState *) opaque; - uint32_t value = value64; - - switch (addr) { - case RTTR: - if (!(s->rttr & (1U << 31))) { - pxa2xx_rtc_hzupdate(s); - s->rttr = value; - pxa2xx_rtc_alarm_update(s, s->rtsr); - } - break; - - case RTSR: - if ((s->rtsr ^ value) & (1 << 15)) - pxa2xx_rtc_piupdate(s); - - if ((s->rtsr ^ value) & (1 << 12)) - pxa2xx_rtc_swupdate(s); - - if (((s->rtsr ^ value) & 0x4aac) | (value & ~0xdaac)) - pxa2xx_rtc_alarm_update(s, value); - - s->rtsr = (value & 0xdaac) | (s->rtsr & ~(value & ~0xdaac)); - pxa2xx_rtc_int_update(s); - break; - - case RTAR: - s->rtar = value; - pxa2xx_rtc_alarm_update(s, s->rtsr); - break; - - case RDAR1: - s->rdar1 = value; - pxa2xx_rtc_alarm_update(s, s->rtsr); - break; - - case RDAR2: - s->rdar2 = value; - pxa2xx_rtc_alarm_update(s, s->rtsr); - break; - - case RYAR1: - s->ryar1 = value; - pxa2xx_rtc_alarm_update(s, s->rtsr); - break; - - case RYAR2: - s->ryar2 = value; - pxa2xx_rtc_alarm_update(s, s->rtsr); - break; - - case SWAR1: - pxa2xx_rtc_swupdate(s); - s->swar1 = value; - s->last_swcr = 0; - pxa2xx_rtc_alarm_update(s, s->rtsr); - break; - - case SWAR2: - s->swar2 = value; - pxa2xx_rtc_alarm_update(s, s->rtsr); - break; - - case PIAR: - s->piar = value; - pxa2xx_rtc_alarm_update(s, s->rtsr); - break; - - case RCNR: - pxa2xx_rtc_hzupdate(s); - s->last_rcnr = value; - pxa2xx_rtc_alarm_update(s, s->rtsr); - break; - - case RDCR: - pxa2xx_rtc_hzupdate(s); - s->last_rdcr = value; - pxa2xx_rtc_alarm_update(s, s->rtsr); - break; - - case RYCR: - s->last_rycr = value; - break; - - case SWCR: - pxa2xx_rtc_swupdate(s); - s->last_swcr = value; - pxa2xx_rtc_alarm_update(s, s->rtsr); - break; - - case RTCPICR: - pxa2xx_rtc_piupdate(s); - s->last_rtcpicr = value & 0xffff; - pxa2xx_rtc_alarm_update(s, s->rtsr); - break; - - default: - printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); - } -} - -static const MemoryRegionOps pxa2xx_rtc_ops = { - .read = pxa2xx_rtc_read, - .write = pxa2xx_rtc_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static int pxa2xx_rtc_init(SysBusDevice *dev) -{ - PXA2xxRTCState *s = PXA2XX_RTC(dev); - struct tm tm; - int wom; - - s->rttr = 0x7fff; - s->rtsr = 0; - - qemu_get_timedate(&tm, 0); - wom = ((tm.tm_mday - 1) / 7) + 1; - - s->last_rcnr = (uint32_t) mktimegm(&tm); - s->last_rdcr = (wom << 20) | ((tm.tm_wday + 1) << 17) | - (tm.tm_hour << 12) | (tm.tm_min << 6) | tm.tm_sec; - s->last_rycr = ((tm.tm_year + 1900) << 9) | - ((tm.tm_mon + 1) << 5) | tm.tm_mday; - s->last_swcr = (tm.tm_hour << 19) | - (tm.tm_min << 13) | (tm.tm_sec << 7); - s->last_rtcpicr = 0; - s->last_hz = s->last_sw = s->last_pi = qemu_clock_get_ms(rtc_clock); - - s->rtc_hz = timer_new_ms(rtc_clock, pxa2xx_rtc_hz_tick, s); - s->rtc_rdal1 = timer_new_ms(rtc_clock, pxa2xx_rtc_rdal1_tick, s); - s->rtc_rdal2 = timer_new_ms(rtc_clock, pxa2xx_rtc_rdal2_tick, s); - s->rtc_swal1 = timer_new_ms(rtc_clock, pxa2xx_rtc_swal1_tick, s); - s->rtc_swal2 = timer_new_ms(rtc_clock, pxa2xx_rtc_swal2_tick, s); - s->rtc_pi = timer_new_ms(rtc_clock, pxa2xx_rtc_pi_tick, s); - - sysbus_init_irq(dev, &s->rtc_irq); - - memory_region_init_io(&s->iomem, OBJECT(s), &pxa2xx_rtc_ops, s, - "pxa2xx-rtc", 0x10000); - sysbus_init_mmio(dev, &s->iomem); - - return 0; -} - -static void pxa2xx_rtc_pre_save(void *opaque) -{ - PXA2xxRTCState *s = (PXA2xxRTCState *) opaque; - - pxa2xx_rtc_hzupdate(s); - pxa2xx_rtc_piupdate(s); - pxa2xx_rtc_swupdate(s); -} - -static int pxa2xx_rtc_post_load(void *opaque, int version_id) -{ - PXA2xxRTCState *s = (PXA2xxRTCState *) opaque; - - pxa2xx_rtc_alarm_update(s, s->rtsr); - - return 0; -} - -static const VMStateDescription vmstate_pxa2xx_rtc_regs = { - .name = "pxa2xx_rtc", - .version_id = 0, - .minimum_version_id = 0, - .pre_save = pxa2xx_rtc_pre_save, - .post_load = pxa2xx_rtc_post_load, - .fields = (VMStateField[]) { - VMSTATE_UINT32(rttr, PXA2xxRTCState), - VMSTATE_UINT32(rtsr, PXA2xxRTCState), - VMSTATE_UINT32(rtar, PXA2xxRTCState), - VMSTATE_UINT32(rdar1, PXA2xxRTCState), - VMSTATE_UINT32(rdar2, PXA2xxRTCState), - VMSTATE_UINT32(ryar1, PXA2xxRTCState), - VMSTATE_UINT32(ryar2, PXA2xxRTCState), - VMSTATE_UINT32(swar1, PXA2xxRTCState), - VMSTATE_UINT32(swar2, PXA2xxRTCState), - VMSTATE_UINT32(piar, PXA2xxRTCState), - VMSTATE_UINT32(last_rcnr, PXA2xxRTCState), - VMSTATE_UINT32(last_rdcr, PXA2xxRTCState), - VMSTATE_UINT32(last_rycr, PXA2xxRTCState), - VMSTATE_UINT32(last_swcr, PXA2xxRTCState), - VMSTATE_UINT32(last_rtcpicr, PXA2xxRTCState), - VMSTATE_INT64(last_hz, PXA2xxRTCState), - VMSTATE_INT64(last_sw, PXA2xxRTCState), - VMSTATE_INT64(last_pi, PXA2xxRTCState), - VMSTATE_END_OF_LIST(), - }, -}; - -static void pxa2xx_rtc_sysbus_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = pxa2xx_rtc_init; - dc->desc = "PXA2xx RTC Controller"; - dc->vmsd = &vmstate_pxa2xx_rtc_regs; -} - -static const TypeInfo pxa2xx_rtc_sysbus_info = { - .name = TYPE_PXA2XX_RTC, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(PXA2xxRTCState), - .class_init = pxa2xx_rtc_sysbus_class_init, -}; - -/* I2C Interface */ - -#define TYPE_PXA2XX_I2C_SLAVE "pxa2xx-i2c-slave" -#define PXA2XX_I2C_SLAVE(obj) \ - OBJECT_CHECK(PXA2xxI2CSlaveState, (obj), TYPE_PXA2XX_I2C_SLAVE) - -typedef struct PXA2xxI2CSlaveState { - I2CSlave parent_obj; - - PXA2xxI2CState *host; -} PXA2xxI2CSlaveState; - -#define TYPE_PXA2XX_I2C "pxa2xx_i2c" -#define PXA2XX_I2C(obj) \ - OBJECT_CHECK(PXA2xxI2CState, (obj), TYPE_PXA2XX_I2C) - -struct PXA2xxI2CState { - /*< private >*/ - SysBusDevice parent_obj; - /*< public >*/ - - MemoryRegion iomem; - PXA2xxI2CSlaveState *slave; - I2CBus *bus; - qemu_irq irq; - uint32_t offset; - uint32_t region_size; - - uint16_t control; - uint16_t status; - uint8_t ibmr; - uint8_t data; -}; - -#define IBMR 0x80 /* I2C Bus Monitor register */ -#define IDBR 0x88 /* I2C Data Buffer register */ -#define ICR 0x90 /* I2C Control register */ -#define ISR 0x98 /* I2C Status register */ -#define ISAR 0xa0 /* I2C Slave Address register */ - -static void pxa2xx_i2c_update(PXA2xxI2CState *s) -{ - uint16_t level = 0; - level |= s->status & s->control & (1 << 10); /* BED */ - level |= (s->status & (1 << 7)) && (s->control & (1 << 9)); /* IRF */ - level |= (s->status & (1 << 6)) && (s->control & (1 << 8)); /* ITE */ - level |= s->status & (1 << 9); /* SAD */ - qemu_set_irq(s->irq, !!level); -} - -/* These are only stubs now. */ -static void pxa2xx_i2c_event(I2CSlave *i2c, enum i2c_event event) -{ - PXA2xxI2CSlaveState *slave = PXA2XX_I2C_SLAVE(i2c); - PXA2xxI2CState *s = slave->host; - - switch (event) { - case I2C_START_SEND: - s->status |= (1 << 9); /* set SAD */ - s->status &= ~(1 << 0); /* clear RWM */ - break; - case I2C_START_RECV: - s->status |= (1 << 9); /* set SAD */ - s->status |= 1 << 0; /* set RWM */ - break; - case I2C_FINISH: - s->status |= (1 << 4); /* set SSD */ - break; - case I2C_NACK: - s->status |= 1 << 1; /* set ACKNAK */ - break; - } - pxa2xx_i2c_update(s); -} - -static int pxa2xx_i2c_rx(I2CSlave *i2c) -{ - PXA2xxI2CSlaveState *slave = PXA2XX_I2C_SLAVE(i2c); - PXA2xxI2CState *s = slave->host; - - if ((s->control & (1 << 14)) || !(s->control & (1 << 6))) { - return 0; - } - - if (s->status & (1 << 0)) { /* RWM */ - s->status |= 1 << 6; /* set ITE */ - } - pxa2xx_i2c_update(s); - - return s->data; -} - -static int pxa2xx_i2c_tx(I2CSlave *i2c, uint8_t data) -{ - PXA2xxI2CSlaveState *slave = PXA2XX_I2C_SLAVE(i2c); - PXA2xxI2CState *s = slave->host; - - if ((s->control & (1 << 14)) || !(s->control & (1 << 6))) { - return 1; - } - - if (!(s->status & (1 << 0))) { /* RWM */ - s->status |= 1 << 7; /* set IRF */ - s->data = data; - } - pxa2xx_i2c_update(s); - - return 1; -} - -static uint64_t pxa2xx_i2c_read(void *opaque, hwaddr addr, - unsigned size) -{ - PXA2xxI2CState *s = (PXA2xxI2CState *) opaque; - I2CSlave *slave; - - addr -= s->offset; - switch (addr) { - case ICR: - return s->control; - case ISR: - return s->status | (i2c_bus_busy(s->bus) << 2); - case ISAR: - slave = I2C_SLAVE(s->slave); - return slave->address; - case IDBR: - return s->data; - case IBMR: - if (s->status & (1 << 2)) - s->ibmr ^= 3; /* Fake SCL and SDA pin changes */ - else - s->ibmr = 0; - return s->ibmr; - default: - printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); - break; - } - return 0; -} - -static void pxa2xx_i2c_write(void *opaque, hwaddr addr, - uint64_t value64, unsigned size) -{ - PXA2xxI2CState *s = (PXA2xxI2CState *) opaque; - uint32_t value = value64; - int ack; - - addr -= s->offset; - switch (addr) { - case ICR: - s->control = value & 0xfff7; - if ((value & (1 << 3)) && (value & (1 << 6))) { /* TB and IUE */ - /* TODO: slave mode */ - if (value & (1 << 0)) { /* START condition */ - if (s->data & 1) - s->status |= 1 << 0; /* set RWM */ - else - s->status &= ~(1 << 0); /* clear RWM */ - ack = !i2c_start_transfer(s->bus, s->data >> 1, s->data & 1); - } else { - if (s->status & (1 << 0)) { /* RWM */ - s->data = i2c_recv(s->bus); - if (value & (1 << 2)) /* ACKNAK */ - i2c_nack(s->bus); - ack = 1; - } else - ack = !i2c_send(s->bus, s->data); - } - - if (value & (1 << 1)) /* STOP condition */ - i2c_end_transfer(s->bus); - - if (ack) { - if (value & (1 << 0)) /* START condition */ - s->status |= 1 << 6; /* set ITE */ - else - if (s->status & (1 << 0)) /* RWM */ - s->status |= 1 << 7; /* set IRF */ - else - s->status |= 1 << 6; /* set ITE */ - s->status &= ~(1 << 1); /* clear ACKNAK */ - } else { - s->status |= 1 << 6; /* set ITE */ - s->status |= 1 << 10; /* set BED */ - s->status |= 1 << 1; /* set ACKNAK */ - } - } - if (!(value & (1 << 3)) && (value & (1 << 6))) /* !TB and IUE */ - if (value & (1 << 4)) /* MA */ - i2c_end_transfer(s->bus); - pxa2xx_i2c_update(s); - break; - - case ISR: - s->status &= ~(value & 0x07f0); - pxa2xx_i2c_update(s); - break; - - case ISAR: - i2c_set_slave_address(I2C_SLAVE(s->slave), value & 0x7f); - break; - - case IDBR: - s->data = value & 0xff; - break; - - default: - printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); - } -} - -static const MemoryRegionOps pxa2xx_i2c_ops = { - .read = pxa2xx_i2c_read, - .write = pxa2xx_i2c_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static const VMStateDescription vmstate_pxa2xx_i2c_slave = { - .name = "pxa2xx_i2c_slave", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_I2C_SLAVE(parent_obj, PXA2xxI2CSlaveState), - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription vmstate_pxa2xx_i2c = { - .name = "pxa2xx_i2c", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT16(control, PXA2xxI2CState), - VMSTATE_UINT16(status, PXA2xxI2CState), - VMSTATE_UINT8(ibmr, PXA2xxI2CState), - VMSTATE_UINT8(data, PXA2xxI2CState), - VMSTATE_STRUCT_POINTER(slave, PXA2xxI2CState, - vmstate_pxa2xx_i2c_slave, PXA2xxI2CSlaveState), - VMSTATE_END_OF_LIST() - } -}; - -static int pxa2xx_i2c_slave_init(I2CSlave *i2c) -{ - /* Nothing to do. */ - return 0; -} - -static void pxa2xx_i2c_slave_class_init(ObjectClass *klass, void *data) -{ - I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); - - k->init = pxa2xx_i2c_slave_init; - k->event = pxa2xx_i2c_event; - k->recv = pxa2xx_i2c_rx; - k->send = pxa2xx_i2c_tx; -} - -static const TypeInfo pxa2xx_i2c_slave_info = { - .name = TYPE_PXA2XX_I2C_SLAVE, - .parent = TYPE_I2C_SLAVE, - .instance_size = sizeof(PXA2xxI2CSlaveState), - .class_init = pxa2xx_i2c_slave_class_init, -}; - -PXA2xxI2CState *pxa2xx_i2c_init(hwaddr base, - qemu_irq irq, uint32_t region_size) -{ - DeviceState *dev; - SysBusDevice *i2c_dev; - PXA2xxI2CState *s; - I2CBus *i2cbus; - - dev = qdev_create(NULL, TYPE_PXA2XX_I2C); - qdev_prop_set_uint32(dev, "size", region_size + 1); - qdev_prop_set_uint32(dev, "offset", base & region_size); - qdev_init_nofail(dev); - - i2c_dev = SYS_BUS_DEVICE(dev); - sysbus_mmio_map(i2c_dev, 0, base & ~region_size); - sysbus_connect_irq(i2c_dev, 0, irq); - - s = PXA2XX_I2C(i2c_dev); - /* FIXME: Should the slave device really be on a separate bus? */ - i2cbus = i2c_init_bus(dev, "dummy"); - dev = i2c_create_slave(i2cbus, TYPE_PXA2XX_I2C_SLAVE, 0); - s->slave = PXA2XX_I2C_SLAVE(dev); - s->slave->host = s; - - return s; -} - -static int pxa2xx_i2c_initfn(SysBusDevice *sbd) -{ - DeviceState *dev = DEVICE(sbd); - PXA2xxI2CState *s = PXA2XX_I2C(dev); - - s->bus = i2c_init_bus(dev, "i2c"); - - memory_region_init_io(&s->iomem, OBJECT(s), &pxa2xx_i2c_ops, s, - "pxa2xx-i2c", s->region_size); - sysbus_init_mmio(sbd, &s->iomem); - sysbus_init_irq(sbd, &s->irq); - - return 0; -} - -I2CBus *pxa2xx_i2c_bus(PXA2xxI2CState *s) -{ - return s->bus; -} - -static Property pxa2xx_i2c_properties[] = { - DEFINE_PROP_UINT32("size", PXA2xxI2CState, region_size, 0x10000), - DEFINE_PROP_UINT32("offset", PXA2xxI2CState, offset, 0), - DEFINE_PROP_END_OF_LIST(), -}; - -static void pxa2xx_i2c_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = pxa2xx_i2c_initfn; - dc->desc = "PXA2xx I2C Bus Controller"; - dc->vmsd = &vmstate_pxa2xx_i2c; - dc->props = pxa2xx_i2c_properties; -} - -static const TypeInfo pxa2xx_i2c_info = { - .name = TYPE_PXA2XX_I2C, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(PXA2xxI2CState), - .class_init = pxa2xx_i2c_class_init, -}; - -/* PXA Inter-IC Sound Controller */ -static void pxa2xx_i2s_reset(PXA2xxI2SState *i2s) -{ - i2s->rx_len = 0; - i2s->tx_len = 0; - i2s->fifo_len = 0; - i2s->clk = 0x1a; - i2s->control[0] = 0x00; - i2s->control[1] = 0x00; - i2s->status = 0x00; - i2s->mask = 0x00; -} - -#define SACR_TFTH(val) ((val >> 8) & 0xf) -#define SACR_RFTH(val) ((val >> 12) & 0xf) -#define SACR_DREC(val) (val & (1 << 3)) -#define SACR_DPRL(val) (val & (1 << 4)) - -static inline void pxa2xx_i2s_update(PXA2xxI2SState *i2s) -{ - int rfs, tfs; - rfs = SACR_RFTH(i2s->control[0]) < i2s->rx_len && - !SACR_DREC(i2s->control[1]); - tfs = (i2s->tx_len || i2s->fifo_len < SACR_TFTH(i2s->control[0])) && - i2s->enable && !SACR_DPRL(i2s->control[1]); - - qemu_set_irq(i2s->rx_dma, rfs); - qemu_set_irq(i2s->tx_dma, tfs); - - i2s->status &= 0xe0; - if (i2s->fifo_len < 16 || !i2s->enable) - i2s->status |= 1 << 0; /* TNF */ - if (i2s->rx_len) - i2s->status |= 1 << 1; /* RNE */ - if (i2s->enable) - i2s->status |= 1 << 2; /* BSY */ - if (tfs) - i2s->status |= 1 << 3; /* TFS */ - if (rfs) - i2s->status |= 1 << 4; /* RFS */ - if (!(i2s->tx_len && i2s->enable)) - i2s->status |= i2s->fifo_len << 8; /* TFL */ - i2s->status |= MAX(i2s->rx_len, 0xf) << 12; /* RFL */ - - qemu_set_irq(i2s->irq, i2s->status & i2s->mask); -} - -#define SACR0 0x00 /* Serial Audio Global Control register */ -#define SACR1 0x04 /* Serial Audio I2S/MSB-Justified Control register */ -#define SASR0 0x0c /* Serial Audio Interface and FIFO Status register */ -#define SAIMR 0x14 /* Serial Audio Interrupt Mask register */ -#define SAICR 0x18 /* Serial Audio Interrupt Clear register */ -#define SADIV 0x60 /* Serial Audio Clock Divider register */ -#define SADR 0x80 /* Serial Audio Data register */ - -static uint64_t pxa2xx_i2s_read(void *opaque, hwaddr addr, - unsigned size) -{ - PXA2xxI2SState *s = (PXA2xxI2SState *) opaque; - - switch (addr) { - case SACR0: - return s->control[0]; - case SACR1: - return s->control[1]; - case SASR0: - return s->status; - case SAIMR: - return s->mask; - case SAICR: - return 0; - case SADIV: - return s->clk; - case SADR: - if (s->rx_len > 0) { - s->rx_len --; - pxa2xx_i2s_update(s); - return s->codec_in(s->opaque); - } - return 0; - default: - printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); - break; - } - return 0; -} - -static void pxa2xx_i2s_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - PXA2xxI2SState *s = (PXA2xxI2SState *) opaque; - uint32_t *sample; - - switch (addr) { - case SACR0: - if (value & (1 << 3)) /* RST */ - pxa2xx_i2s_reset(s); - s->control[0] = value & 0xff3d; - if (!s->enable && (value & 1) && s->tx_len) { /* ENB */ - for (sample = s->fifo; s->fifo_len > 0; s->fifo_len --, sample ++) - s->codec_out(s->opaque, *sample); - s->status &= ~(1 << 7); /* I2SOFF */ - } - if (value & (1 << 4)) /* EFWR */ - printf("%s: Attempt to use special function\n", __FUNCTION__); - s->enable = (value & 9) == 1; /* ENB && !RST*/ - pxa2xx_i2s_update(s); - break; - case SACR1: - s->control[1] = value & 0x0039; - if (value & (1 << 5)) /* ENLBF */ - printf("%s: Attempt to use loopback function\n", __FUNCTION__); - if (value & (1 << 4)) /* DPRL */ - s->fifo_len = 0; - pxa2xx_i2s_update(s); - break; - case SAIMR: - s->mask = value & 0x0078; - pxa2xx_i2s_update(s); - break; - case SAICR: - s->status &= ~(value & (3 << 5)); - pxa2xx_i2s_update(s); - break; - case SADIV: - s->clk = value & 0x007f; - break; - case SADR: - if (s->tx_len && s->enable) { - s->tx_len --; - pxa2xx_i2s_update(s); - s->codec_out(s->opaque, value); - } else if (s->fifo_len < 16) { - s->fifo[s->fifo_len ++] = value; - pxa2xx_i2s_update(s); - } - break; - default: - printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); - } -} - -static const MemoryRegionOps pxa2xx_i2s_ops = { - .read = pxa2xx_i2s_read, - .write = pxa2xx_i2s_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static const VMStateDescription vmstate_pxa2xx_i2s = { - .name = "pxa2xx_i2s", - .version_id = 0, - .minimum_version_id = 0, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(control, PXA2xxI2SState, 2), - VMSTATE_UINT32(status, PXA2xxI2SState), - VMSTATE_UINT32(mask, PXA2xxI2SState), - VMSTATE_UINT32(clk, PXA2xxI2SState), - VMSTATE_INT32(enable, PXA2xxI2SState), - VMSTATE_INT32(rx_len, PXA2xxI2SState), - VMSTATE_INT32(tx_len, PXA2xxI2SState), - VMSTATE_INT32(fifo_len, PXA2xxI2SState), - VMSTATE_END_OF_LIST() - } -}; - -static void pxa2xx_i2s_data_req(void *opaque, int tx, int rx) -{ - PXA2xxI2SState *s = (PXA2xxI2SState *) opaque; - uint32_t *sample; - - /* Signal FIFO errors */ - if (s->enable && s->tx_len) - s->status |= 1 << 5; /* TUR */ - if (s->enable && s->rx_len) - s->status |= 1 << 6; /* ROR */ - - /* Should be tx - MIN(tx, s->fifo_len) but we don't really need to - * handle the cases where it makes a difference. */ - s->tx_len = tx - s->fifo_len; - s->rx_len = rx; - /* Note that is s->codec_out wasn't set, we wouldn't get called. */ - if (s->enable) - for (sample = s->fifo; s->fifo_len; s->fifo_len --, sample ++) - s->codec_out(s->opaque, *sample); - pxa2xx_i2s_update(s); -} - -static PXA2xxI2SState *pxa2xx_i2s_init(MemoryRegion *sysmem, - hwaddr base, - qemu_irq irq, qemu_irq rx_dma, qemu_irq tx_dma) -{ - PXA2xxI2SState *s = g_new0(PXA2xxI2SState, 1); - - s->irq = irq; - s->rx_dma = rx_dma; - s->tx_dma = tx_dma; - s->data_req = pxa2xx_i2s_data_req; - - pxa2xx_i2s_reset(s); - - memory_region_init_io(&s->iomem, NULL, &pxa2xx_i2s_ops, s, - "pxa2xx-i2s", 0x100000); - memory_region_add_subregion(sysmem, base, &s->iomem); - - vmstate_register(NULL, base, &vmstate_pxa2xx_i2s, s); - - return s; -} - -/* PXA Fast Infra-red Communications Port */ -#define TYPE_PXA2XX_FIR "pxa2xx-fir" -#define PXA2XX_FIR(obj) OBJECT_CHECK(PXA2xxFIrState, (obj), TYPE_PXA2XX_FIR) - -struct PXA2xxFIrState { - /*< private >*/ - SysBusDevice parent_obj; - /*< public >*/ - - MemoryRegion iomem; - qemu_irq irq; - qemu_irq rx_dma; - qemu_irq tx_dma; - uint32_t enable; - CharDriverState *chr; - - uint8_t control[3]; - uint8_t status[2]; - - uint32_t rx_len; - uint32_t rx_start; - uint8_t rx_fifo[64]; -}; - -static void pxa2xx_fir_reset(DeviceState *d) -{ - PXA2xxFIrState *s = PXA2XX_FIR(d); - - s->control[0] = 0x00; - s->control[1] = 0x00; - s->control[2] = 0x00; - s->status[0] = 0x00; - s->status[1] = 0x00; - s->enable = 0; -} - -static inline void pxa2xx_fir_update(PXA2xxFIrState *s) -{ - static const int tresh[4] = { 8, 16, 32, 0 }; - int intr = 0; - if ((s->control[0] & (1 << 4)) && /* RXE */ - s->rx_len >= tresh[s->control[2] & 3]) /* TRIG */ - s->status[0] |= 1 << 4; /* RFS */ - else - s->status[0] &= ~(1 << 4); /* RFS */ - if (s->control[0] & (1 << 3)) /* TXE */ - s->status[0] |= 1 << 3; /* TFS */ - else - s->status[0] &= ~(1 << 3); /* TFS */ - if (s->rx_len) - s->status[1] |= 1 << 2; /* RNE */ - else - s->status[1] &= ~(1 << 2); /* RNE */ - if (s->control[0] & (1 << 4)) /* RXE */ - s->status[1] |= 1 << 0; /* RSY */ - else - s->status[1] &= ~(1 << 0); /* RSY */ - - intr |= (s->control[0] & (1 << 5)) && /* RIE */ - (s->status[0] & (1 << 4)); /* RFS */ - intr |= (s->control[0] & (1 << 6)) && /* TIE */ - (s->status[0] & (1 << 3)); /* TFS */ - intr |= (s->control[2] & (1 << 4)) && /* TRAIL */ - (s->status[0] & (1 << 6)); /* EOC */ - intr |= (s->control[0] & (1 << 2)) && /* TUS */ - (s->status[0] & (1 << 1)); /* TUR */ - intr |= s->status[0] & 0x25; /* FRE, RAB, EIF */ - - qemu_set_irq(s->rx_dma, (s->status[0] >> 4) & 1); - qemu_set_irq(s->tx_dma, (s->status[0] >> 3) & 1); - - qemu_set_irq(s->irq, intr && s->enable); -} - -#define ICCR0 0x00 /* FICP Control register 0 */ -#define ICCR1 0x04 /* FICP Control register 1 */ -#define ICCR2 0x08 /* FICP Control register 2 */ -#define ICDR 0x0c /* FICP Data register */ -#define ICSR0 0x14 /* FICP Status register 0 */ -#define ICSR1 0x18 /* FICP Status register 1 */ -#define ICFOR 0x1c /* FICP FIFO Occupancy Status register */ - -static uint64_t pxa2xx_fir_read(void *opaque, hwaddr addr, - unsigned size) -{ - PXA2xxFIrState *s = (PXA2xxFIrState *) opaque; - uint8_t ret; - - switch (addr) { - case ICCR0: - return s->control[0]; - case ICCR1: - return s->control[1]; - case ICCR2: - return s->control[2]; - case ICDR: - s->status[0] &= ~0x01; - s->status[1] &= ~0x72; - if (s->rx_len) { - s->rx_len --; - ret = s->rx_fifo[s->rx_start ++]; - s->rx_start &= 63; - pxa2xx_fir_update(s); - return ret; - } - printf("%s: Rx FIFO underrun.\n", __FUNCTION__); - break; - case ICSR0: - return s->status[0]; - case ICSR1: - return s->status[1] | (1 << 3); /* TNF */ - case ICFOR: - return s->rx_len; - default: - printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); - break; - } - return 0; -} - -static void pxa2xx_fir_write(void *opaque, hwaddr addr, - uint64_t value64, unsigned size) -{ - PXA2xxFIrState *s = (PXA2xxFIrState *) opaque; - uint32_t value = value64; - uint8_t ch; - - switch (addr) { - case ICCR0: - s->control[0] = value; - if (!(value & (1 << 4))) /* RXE */ - s->rx_len = s->rx_start = 0; - if (!(value & (1 << 3))) { /* TXE */ - /* Nop */ - } - s->enable = value & 1; /* ITR */ - if (!s->enable) - s->status[0] = 0; - pxa2xx_fir_update(s); - break; - case ICCR1: - s->control[1] = value; - break; - case ICCR2: - s->control[2] = value & 0x3f; - pxa2xx_fir_update(s); - break; - case ICDR: - if (s->control[2] & (1 << 2)) /* TXP */ - ch = value; - else - ch = ~value; - if (s->chr && s->enable && (s->control[0] & (1 << 3))) /* TXE */ - qemu_chr_fe_write(s->chr, &ch, 1); - break; - case ICSR0: - s->status[0] &= ~(value & 0x66); - pxa2xx_fir_update(s); - break; - case ICFOR: - break; - default: - printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); - } -} - -static const MemoryRegionOps pxa2xx_fir_ops = { - .read = pxa2xx_fir_read, - .write = pxa2xx_fir_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static int pxa2xx_fir_is_empty(void *opaque) -{ - PXA2xxFIrState *s = (PXA2xxFIrState *) opaque; - return (s->rx_len < 64); -} - -static void pxa2xx_fir_rx(void *opaque, const uint8_t *buf, int size) -{ - PXA2xxFIrState *s = (PXA2xxFIrState *) opaque; - if (!(s->control[0] & (1 << 4))) /* RXE */ - return; - - while (size --) { - s->status[1] |= 1 << 4; /* EOF */ - if (s->rx_len >= 64) { - s->status[1] |= 1 << 6; /* ROR */ - break; - } - - if (s->control[2] & (1 << 3)) /* RXP */ - s->rx_fifo[(s->rx_start + s->rx_len ++) & 63] = *(buf ++); - else - s->rx_fifo[(s->rx_start + s->rx_len ++) & 63] = ~*(buf ++); - } - - pxa2xx_fir_update(s); -} - -static void pxa2xx_fir_event(void *opaque, int event) -{ -} - -static void pxa2xx_fir_instance_init(Object *obj) -{ - PXA2xxFIrState *s = PXA2XX_FIR(obj); - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - - memory_region_init_io(&s->iomem, obj, &pxa2xx_fir_ops, s, - "pxa2xx-fir", 0x1000); - sysbus_init_mmio(sbd, &s->iomem); - sysbus_init_irq(sbd, &s->irq); - sysbus_init_irq(sbd, &s->rx_dma); - sysbus_init_irq(sbd, &s->tx_dma); -} - -static void pxa2xx_fir_realize(DeviceState *dev, Error **errp) -{ - PXA2xxFIrState *s = PXA2XX_FIR(dev); - - if (s->chr) { - qemu_chr_fe_claim_no_fail(s->chr); - qemu_chr_add_handlers(s->chr, pxa2xx_fir_is_empty, - pxa2xx_fir_rx, pxa2xx_fir_event, s); - } -} - -static bool pxa2xx_fir_vmstate_validate(void *opaque, int version_id) -{ - PXA2xxFIrState *s = opaque; - - return s->rx_start < ARRAY_SIZE(s->rx_fifo); -} - -static const VMStateDescription pxa2xx_fir_vmsd = { - .name = "pxa2xx-fir", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(enable, PXA2xxFIrState), - VMSTATE_UINT8_ARRAY(control, PXA2xxFIrState, 3), - VMSTATE_UINT8_ARRAY(status, PXA2xxFIrState, 2), - VMSTATE_UINT32(rx_len, PXA2xxFIrState), - VMSTATE_UINT32(rx_start, PXA2xxFIrState), - VMSTATE_VALIDATE("fifo is 64 bytes", pxa2xx_fir_vmstate_validate), - VMSTATE_UINT8_ARRAY(rx_fifo, PXA2xxFIrState, 64), - VMSTATE_END_OF_LIST() - } -}; - -static Property pxa2xx_fir_properties[] = { - DEFINE_PROP_CHR("chardev", PXA2xxFIrState, chr), - DEFINE_PROP_END_OF_LIST(), -}; - -static void pxa2xx_fir_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = pxa2xx_fir_realize; - dc->vmsd = &pxa2xx_fir_vmsd; - dc->props = pxa2xx_fir_properties; - dc->reset = pxa2xx_fir_reset; -} - -static const TypeInfo pxa2xx_fir_info = { - .name = TYPE_PXA2XX_FIR, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(PXA2xxFIrState), - .class_init = pxa2xx_fir_class_init, - .instance_init = pxa2xx_fir_instance_init, -}; - -static PXA2xxFIrState *pxa2xx_fir_init(MemoryRegion *sysmem, - hwaddr base, - qemu_irq irq, qemu_irq rx_dma, - qemu_irq tx_dma, - CharDriverState *chr) -{ - DeviceState *dev; - SysBusDevice *sbd; - - dev = qdev_create(NULL, TYPE_PXA2XX_FIR); - qdev_prop_set_chr(dev, "chardev", chr); - qdev_init_nofail(dev); - sbd = SYS_BUS_DEVICE(dev); - sysbus_mmio_map(sbd, 0, base); - sysbus_connect_irq(sbd, 0, irq); - sysbus_connect_irq(sbd, 1, rx_dma); - sysbus_connect_irq(sbd, 2, tx_dma); - return PXA2XX_FIR(dev); -} - -static void pxa2xx_reset(void *opaque, int line, int level) -{ - PXA2xxState *s = (PXA2xxState *) opaque; - - if (level && (s->pm_regs[PCFR >> 2] & 0x10)) { /* GPR_EN */ - cpu_reset(CPU(s->cpu)); - /* TODO: reset peripherals */ - } -} - -/* Initialise a PXA270 integrated chip (ARM based core). */ -PXA2xxState *pxa270_init(MemoryRegion *address_space, - unsigned int sdram_size, const char *revision) -{ - PXA2xxState *s; - int i; - DriveInfo *dinfo; - s = g_new0(PXA2xxState, 1); - - if (revision && strncmp(revision, "pxa27", 5)) { - fprintf(stderr, "Machine requires a PXA27x processor.\n"); - exit(1); - } - if (!revision) - revision = "pxa270"; - - s->cpu = cpu_arm_init(revision); - if (s->cpu == NULL) { - fprintf(stderr, "Unable to find CPU definition\n"); - exit(1); - } - s->reset = qemu_allocate_irq(pxa2xx_reset, s, 0); - - /* SDRAM & Internal Memory Storage */ - memory_region_init_ram(&s->sdram, NULL, "pxa270.sdram", sdram_size, - &error_fatal); - vmstate_register_ram_global(&s->sdram); - memory_region_add_subregion(address_space, PXA2XX_SDRAM_BASE, &s->sdram); - memory_region_init_ram(&s->internal, NULL, "pxa270.internal", 0x40000, - &error_fatal); - vmstate_register_ram_global(&s->internal); - memory_region_add_subregion(address_space, PXA2XX_INTERNAL_BASE, - &s->internal); - - s->pic = pxa2xx_pic_init(0x40d00000, s->cpu); - - s->dma = pxa27x_dma_init(0x40000000, - qdev_get_gpio_in(s->pic, PXA2XX_PIC_DMA)); - - sysbus_create_varargs("pxa27x-timer", 0x40a00000, - qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 0), - qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 1), - qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 2), - qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 3), - qdev_get_gpio_in(s->pic, PXA27X_PIC_OST_4_11), - NULL); - - s->gpio = pxa2xx_gpio_init(0x40e00000, s->cpu, s->pic, 121); - - dinfo = drive_get(IF_SD, 0, 0); - if (!dinfo) { - fprintf(stderr, "qemu: missing SecureDigital device\n"); - exit(1); - } - s->mmc = pxa2xx_mmci_init(address_space, 0x41100000, - blk_by_legacy_dinfo(dinfo), - qdev_get_gpio_in(s->pic, PXA2XX_PIC_MMC), - qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_MMCI), - qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_MMCI)); - - for (i = 0; pxa270_serial[i].io_base; i++) { - if (serial_hds[i]) { - serial_mm_init(address_space, pxa270_serial[i].io_base, 2, - qdev_get_gpio_in(s->pic, pxa270_serial[i].irqn), - 14857000 / 16, serial_hds[i], - DEVICE_NATIVE_ENDIAN); - } else { - break; - } - } - if (serial_hds[i]) - s->fir = pxa2xx_fir_init(address_space, 0x40800000, - qdev_get_gpio_in(s->pic, PXA2XX_PIC_ICP), - qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_ICP), - qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_ICP), - serial_hds[i]); - - s->lcd = pxa2xx_lcdc_init(address_space, 0x44000000, - qdev_get_gpio_in(s->pic, PXA2XX_PIC_LCD)); - - s->cm_base = 0x41300000; - s->cm_regs[CCCR >> 2] = 0x02000210; /* 416.0 MHz */ - s->clkcfg = 0x00000009; /* Turbo mode active */ - memory_region_init_io(&s->cm_iomem, NULL, &pxa2xx_cm_ops, s, "pxa2xx-cm", 0x1000); - memory_region_add_subregion(address_space, s->cm_base, &s->cm_iomem); - vmstate_register(NULL, 0, &vmstate_pxa2xx_cm, s); - - pxa2xx_setup_cp14(s); - - s->mm_base = 0x48000000; - s->mm_regs[MDMRS >> 2] = 0x00020002; - s->mm_regs[MDREFR >> 2] = 0x03ca4000; - s->mm_regs[MECR >> 2] = 0x00000001; /* Two PC Card sockets */ - memory_region_init_io(&s->mm_iomem, NULL, &pxa2xx_mm_ops, s, "pxa2xx-mm", 0x1000); - memory_region_add_subregion(address_space, s->mm_base, &s->mm_iomem); - vmstate_register(NULL, 0, &vmstate_pxa2xx_mm, s); - - s->pm_base = 0x40f00000; - memory_region_init_io(&s->pm_iomem, NULL, &pxa2xx_pm_ops, s, "pxa2xx-pm", 0x100); - memory_region_add_subregion(address_space, s->pm_base, &s->pm_iomem); - vmstate_register(NULL, 0, &vmstate_pxa2xx_pm, s); - - for (i = 0; pxa27x_ssp[i].io_base; i ++); - s->ssp = g_new0(SSIBus *, i); - for (i = 0; pxa27x_ssp[i].io_base; i ++) { - DeviceState *dev; - dev = sysbus_create_simple(TYPE_PXA2XX_SSP, pxa27x_ssp[i].io_base, - qdev_get_gpio_in(s->pic, pxa27x_ssp[i].irqn)); - s->ssp[i] = (SSIBus *)qdev_get_child_bus(dev, "ssi"); - } - - if (usb_enabled()) { - sysbus_create_simple("sysbus-ohci", 0x4c000000, - qdev_get_gpio_in(s->pic, PXA2XX_PIC_USBH1)); - } - - s->pcmcia[0] = pxa2xx_pcmcia_init(address_space, 0x20000000); - s->pcmcia[1] = pxa2xx_pcmcia_init(address_space, 0x30000000); - - sysbus_create_simple(TYPE_PXA2XX_RTC, 0x40900000, - qdev_get_gpio_in(s->pic, PXA2XX_PIC_RTCALARM)); - - s->i2c[0] = pxa2xx_i2c_init(0x40301600, - qdev_get_gpio_in(s->pic, PXA2XX_PIC_I2C), 0xffff); - s->i2c[1] = pxa2xx_i2c_init(0x40f00100, - qdev_get_gpio_in(s->pic, PXA2XX_PIC_PWRI2C), 0xff); - - s->i2s = pxa2xx_i2s_init(address_space, 0x40400000, - qdev_get_gpio_in(s->pic, PXA2XX_PIC_I2S), - qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_I2S), - qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_I2S)); - - s->kp = pxa27x_keypad_init(address_space, 0x41500000, - qdev_get_gpio_in(s->pic, PXA2XX_PIC_KEYPAD)); - - /* GPIO1 resets the processor */ - /* The handler can be overridden by board-specific code */ - qdev_connect_gpio_out(s->gpio, 1, s->reset); - return s; -} - -/* Initialise a PXA255 integrated chip (ARM based core). */ -PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size) -{ - PXA2xxState *s; - int i; - DriveInfo *dinfo; - - s = g_new0(PXA2xxState, 1); - - s->cpu = cpu_arm_init("pxa255"); - if (s->cpu == NULL) { - fprintf(stderr, "Unable to find CPU definition\n"); - exit(1); - } - s->reset = qemu_allocate_irq(pxa2xx_reset, s, 0); - - /* SDRAM & Internal Memory Storage */ - memory_region_init_ram(&s->sdram, NULL, "pxa255.sdram", sdram_size, - &error_fatal); - vmstate_register_ram_global(&s->sdram); - memory_region_add_subregion(address_space, PXA2XX_SDRAM_BASE, &s->sdram); - memory_region_init_ram(&s->internal, NULL, "pxa255.internal", - PXA2XX_INTERNAL_SIZE, &error_fatal); - vmstate_register_ram_global(&s->internal); - memory_region_add_subregion(address_space, PXA2XX_INTERNAL_BASE, - &s->internal); - - s->pic = pxa2xx_pic_init(0x40d00000, s->cpu); - - s->dma = pxa255_dma_init(0x40000000, - qdev_get_gpio_in(s->pic, PXA2XX_PIC_DMA)); - - sysbus_create_varargs("pxa25x-timer", 0x40a00000, - qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 0), - qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 1), - qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 2), - qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 3), - NULL); - - s->gpio = pxa2xx_gpio_init(0x40e00000, s->cpu, s->pic, 85); - - dinfo = drive_get(IF_SD, 0, 0); - if (!dinfo) { - fprintf(stderr, "qemu: missing SecureDigital device\n"); - exit(1); - } - s->mmc = pxa2xx_mmci_init(address_space, 0x41100000, - blk_by_legacy_dinfo(dinfo), - qdev_get_gpio_in(s->pic, PXA2XX_PIC_MMC), - qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_MMCI), - qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_MMCI)); - - for (i = 0; pxa255_serial[i].io_base; i++) { - if (serial_hds[i]) { - serial_mm_init(address_space, pxa255_serial[i].io_base, 2, - qdev_get_gpio_in(s->pic, pxa255_serial[i].irqn), - 14745600 / 16, serial_hds[i], - DEVICE_NATIVE_ENDIAN); - } else { - break; - } - } - if (serial_hds[i]) - s->fir = pxa2xx_fir_init(address_space, 0x40800000, - qdev_get_gpio_in(s->pic, PXA2XX_PIC_ICP), - qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_ICP), - qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_ICP), - serial_hds[i]); - - s->lcd = pxa2xx_lcdc_init(address_space, 0x44000000, - qdev_get_gpio_in(s->pic, PXA2XX_PIC_LCD)); - - s->cm_base = 0x41300000; - s->cm_regs[CCCR >> 2] = 0x02000210; /* 416.0 MHz */ - s->clkcfg = 0x00000009; /* Turbo mode active */ - memory_region_init_io(&s->cm_iomem, NULL, &pxa2xx_cm_ops, s, "pxa2xx-cm", 0x1000); - memory_region_add_subregion(address_space, s->cm_base, &s->cm_iomem); - vmstate_register(NULL, 0, &vmstate_pxa2xx_cm, s); - - pxa2xx_setup_cp14(s); - - s->mm_base = 0x48000000; - s->mm_regs[MDMRS >> 2] = 0x00020002; - s->mm_regs[MDREFR >> 2] = 0x03ca4000; - s->mm_regs[MECR >> 2] = 0x00000001; /* Two PC Card sockets */ - memory_region_init_io(&s->mm_iomem, NULL, &pxa2xx_mm_ops, s, "pxa2xx-mm", 0x1000); - memory_region_add_subregion(address_space, s->mm_base, &s->mm_iomem); - vmstate_register(NULL, 0, &vmstate_pxa2xx_mm, s); - - s->pm_base = 0x40f00000; - memory_region_init_io(&s->pm_iomem, NULL, &pxa2xx_pm_ops, s, "pxa2xx-pm", 0x100); - memory_region_add_subregion(address_space, s->pm_base, &s->pm_iomem); - vmstate_register(NULL, 0, &vmstate_pxa2xx_pm, s); - - for (i = 0; pxa255_ssp[i].io_base; i ++); - s->ssp = g_new0(SSIBus *, i); - for (i = 0; pxa255_ssp[i].io_base; i ++) { - DeviceState *dev; - dev = sysbus_create_simple(TYPE_PXA2XX_SSP, pxa255_ssp[i].io_base, - qdev_get_gpio_in(s->pic, pxa255_ssp[i].irqn)); - s->ssp[i] = (SSIBus *)qdev_get_child_bus(dev, "ssi"); - } - - if (usb_enabled()) { - sysbus_create_simple("sysbus-ohci", 0x4c000000, - qdev_get_gpio_in(s->pic, PXA2XX_PIC_USBH1)); - } - - s->pcmcia[0] = pxa2xx_pcmcia_init(address_space, 0x20000000); - s->pcmcia[1] = pxa2xx_pcmcia_init(address_space, 0x30000000); - - sysbus_create_simple(TYPE_PXA2XX_RTC, 0x40900000, - qdev_get_gpio_in(s->pic, PXA2XX_PIC_RTCALARM)); - - s->i2c[0] = pxa2xx_i2c_init(0x40301600, - qdev_get_gpio_in(s->pic, PXA2XX_PIC_I2C), 0xffff); - s->i2c[1] = pxa2xx_i2c_init(0x40f00100, - qdev_get_gpio_in(s->pic, PXA2XX_PIC_PWRI2C), 0xff); - - s->i2s = pxa2xx_i2s_init(address_space, 0x40400000, - qdev_get_gpio_in(s->pic, PXA2XX_PIC_I2S), - qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_I2S), - qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_I2S)); - - /* GPIO1 resets the processor */ - /* The handler can be overridden by board-specific code */ - qdev_connect_gpio_out(s->gpio, 1, s->reset); - return s; -} - -static void pxa2xx_ssp_class_init(ObjectClass *klass, void *data) -{ - SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); - DeviceClass *dc = DEVICE_CLASS(klass); - - sdc->init = pxa2xx_ssp_init; - dc->reset = pxa2xx_ssp_reset; - dc->vmsd = &vmstate_pxa2xx_ssp; -} - -static const TypeInfo pxa2xx_ssp_info = { - .name = TYPE_PXA2XX_SSP, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(PXA2xxSSPState), - .class_init = pxa2xx_ssp_class_init, -}; - -static void pxa2xx_register_types(void) -{ - type_register_static(&pxa2xx_i2c_slave_info); - type_register_static(&pxa2xx_ssp_info); - type_register_static(&pxa2xx_i2c_info); - type_register_static(&pxa2xx_rtc_sysbus_info); - type_register_static(&pxa2xx_fir_info); -} - -type_init(pxa2xx_register_types) diff --git a/qemu/hw/arm/pxa2xx_gpio.c b/qemu/hw/arm/pxa2xx_gpio.c deleted file mode 100644 index 67e7e7094..000000000 --- a/qemu/hw/arm/pxa2xx_gpio.c +++ /dev/null @@ -1,357 +0,0 @@ -/* - * Intel XScale PXA255/270 GPIO controller emulation. - * - * Copyright (c) 2006 Openedhand Ltd. - * Written by Andrzej Zaborowski <balrog@zabor.org> - * - * This code is licensed under the GPL. - */ - -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/sysbus.h" -#include "hw/arm/pxa.h" - -#define PXA2XX_GPIO_BANKS 4 - -#define TYPE_PXA2XX_GPIO "pxa2xx-gpio" -#define PXA2XX_GPIO(obj) \ - OBJECT_CHECK(PXA2xxGPIOInfo, (obj), TYPE_PXA2XX_GPIO) - -typedef struct PXA2xxGPIOInfo PXA2xxGPIOInfo; -struct PXA2xxGPIOInfo { - /*< private >*/ - SysBusDevice parent_obj; - /*< public >*/ - - MemoryRegion iomem; - qemu_irq irq0, irq1, irqX; - int lines; - int ncpu; - ARMCPU *cpu; - - /* XXX: GNU C vectors are more suitable */ - uint32_t ilevel[PXA2XX_GPIO_BANKS]; - uint32_t olevel[PXA2XX_GPIO_BANKS]; - uint32_t dir[PXA2XX_GPIO_BANKS]; - uint32_t rising[PXA2XX_GPIO_BANKS]; - uint32_t falling[PXA2XX_GPIO_BANKS]; - uint32_t status[PXA2XX_GPIO_BANKS]; - uint32_t gafr[PXA2XX_GPIO_BANKS * 2]; - - uint32_t prev_level[PXA2XX_GPIO_BANKS]; - qemu_irq handler[PXA2XX_GPIO_BANKS * 32]; - qemu_irq read_notify; -}; - -static struct { - enum { - GPIO_NONE, - GPLR, - GPSR, - GPCR, - GPDR, - GRER, - GFER, - GEDR, - GAFR_L, - GAFR_U, - } reg; - int bank; -} pxa2xx_gpio_regs[0x200] = { - [0 ... 0x1ff] = { GPIO_NONE, 0 }, -#define PXA2XX_REG(reg, a0, a1, a2, a3) \ - [a0] = { reg, 0 }, [a1] = { reg, 1 }, [a2] = { reg, 2 }, [a3] = { reg, 3 }, - - PXA2XX_REG(GPLR, 0x000, 0x004, 0x008, 0x100) - PXA2XX_REG(GPSR, 0x018, 0x01c, 0x020, 0x118) - PXA2XX_REG(GPCR, 0x024, 0x028, 0x02c, 0x124) - PXA2XX_REG(GPDR, 0x00c, 0x010, 0x014, 0x10c) - PXA2XX_REG(GRER, 0x030, 0x034, 0x038, 0x130) - PXA2XX_REG(GFER, 0x03c, 0x040, 0x044, 0x13c) - PXA2XX_REG(GEDR, 0x048, 0x04c, 0x050, 0x148) - PXA2XX_REG(GAFR_L, 0x054, 0x05c, 0x064, 0x06c) - PXA2XX_REG(GAFR_U, 0x058, 0x060, 0x068, 0x070) -}; - -static void pxa2xx_gpio_irq_update(PXA2xxGPIOInfo *s) -{ - if (s->status[0] & (1 << 0)) - qemu_irq_raise(s->irq0); - else - qemu_irq_lower(s->irq0); - - if (s->status[0] & (1 << 1)) - qemu_irq_raise(s->irq1); - else - qemu_irq_lower(s->irq1); - - if ((s->status[0] & ~3) | s->status[1] | s->status[2] | s->status[3]) - qemu_irq_raise(s->irqX); - else - qemu_irq_lower(s->irqX); -} - -/* Bitmap of pins used as standby and sleep wake-up sources. */ -static const int pxa2xx_gpio_wake[PXA2XX_GPIO_BANKS] = { - 0x8003fe1b, 0x002001fc, 0xec080000, 0x0012007f, -}; - -static void pxa2xx_gpio_set(void *opaque, int line, int level) -{ - PXA2xxGPIOInfo *s = (PXA2xxGPIOInfo *) opaque; - CPUState *cpu = CPU(s->cpu); - int bank; - uint32_t mask; - - if (line >= s->lines) { - printf("%s: No GPIO pin %i\n", __FUNCTION__, line); - return; - } - - bank = line >> 5; - mask = 1U << (line & 31); - - if (level) { - s->status[bank] |= s->rising[bank] & mask & - ~s->ilevel[bank] & ~s->dir[bank]; - s->ilevel[bank] |= mask; - } else { - s->status[bank] |= s->falling[bank] & mask & - s->ilevel[bank] & ~s->dir[bank]; - s->ilevel[bank] &= ~mask; - } - - if (s->status[bank] & mask) - pxa2xx_gpio_irq_update(s); - - /* Wake-up GPIOs */ - if (cpu->halted && (mask & ~s->dir[bank] & pxa2xx_gpio_wake[bank])) { - cpu_interrupt(cpu, CPU_INTERRUPT_EXITTB); - } -} - -static void pxa2xx_gpio_handler_update(PXA2xxGPIOInfo *s) { - uint32_t level, diff; - int i, bit, line; - for (i = 0; i < PXA2XX_GPIO_BANKS; i ++) { - level = s->olevel[i] & s->dir[i]; - - for (diff = s->prev_level[i] ^ level; diff; diff ^= 1 << bit) { - bit = ctz32(diff); - line = bit + 32 * i; - qemu_set_irq(s->handler[line], (level >> bit) & 1); - } - - s->prev_level[i] = level; - } -} - -static uint64_t pxa2xx_gpio_read(void *opaque, hwaddr offset, - unsigned size) -{ - PXA2xxGPIOInfo *s = (PXA2xxGPIOInfo *) opaque; - uint32_t ret; - int bank; - if (offset >= 0x200) - return 0; - - bank = pxa2xx_gpio_regs[offset].bank; - switch (pxa2xx_gpio_regs[offset].reg) { - case GPDR: /* GPIO Pin-Direction registers */ - return s->dir[bank]; - - case GPSR: /* GPIO Pin-Output Set registers */ - qemu_log_mask(LOG_GUEST_ERROR, - "pxa2xx GPIO: read from write only register GPSR\n"); - return 0; - - case GPCR: /* GPIO Pin-Output Clear registers */ - qemu_log_mask(LOG_GUEST_ERROR, - "pxa2xx GPIO: read from write only register GPCR\n"); - return 0; - - case GRER: /* GPIO Rising-Edge Detect Enable registers */ - return s->rising[bank]; - - case GFER: /* GPIO Falling-Edge Detect Enable registers */ - return s->falling[bank]; - - case GAFR_L: /* GPIO Alternate Function registers */ - return s->gafr[bank * 2]; - - case GAFR_U: /* GPIO Alternate Function registers */ - return s->gafr[bank * 2 + 1]; - - case GPLR: /* GPIO Pin-Level registers */ - ret = (s->olevel[bank] & s->dir[bank]) | - (s->ilevel[bank] & ~s->dir[bank]); - qemu_irq_raise(s->read_notify); - return ret; - - case GEDR: /* GPIO Edge Detect Status registers */ - return s->status[bank]; - - default: - hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset); - } - - return 0; -} - -static void pxa2xx_gpio_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - PXA2xxGPIOInfo *s = (PXA2xxGPIOInfo *) opaque; - int bank; - if (offset >= 0x200) - return; - - bank = pxa2xx_gpio_regs[offset].bank; - switch (pxa2xx_gpio_regs[offset].reg) { - case GPDR: /* GPIO Pin-Direction registers */ - s->dir[bank] = value; - pxa2xx_gpio_handler_update(s); - break; - - case GPSR: /* GPIO Pin-Output Set registers */ - s->olevel[bank] |= value; - pxa2xx_gpio_handler_update(s); - break; - - case GPCR: /* GPIO Pin-Output Clear registers */ - s->olevel[bank] &= ~value; - pxa2xx_gpio_handler_update(s); - break; - - case GRER: /* GPIO Rising-Edge Detect Enable registers */ - s->rising[bank] = value; - break; - - case GFER: /* GPIO Falling-Edge Detect Enable registers */ - s->falling[bank] = value; - break; - - case GAFR_L: /* GPIO Alternate Function registers */ - s->gafr[bank * 2] = value; - break; - - case GAFR_U: /* GPIO Alternate Function registers */ - s->gafr[bank * 2 + 1] = value; - break; - - case GEDR: /* GPIO Edge Detect Status registers */ - s->status[bank] &= ~value; - pxa2xx_gpio_irq_update(s); - break; - - default: - hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset); - } -} - -static const MemoryRegionOps pxa_gpio_ops = { - .read = pxa2xx_gpio_read, - .write = pxa2xx_gpio_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -DeviceState *pxa2xx_gpio_init(hwaddr base, - ARMCPU *cpu, DeviceState *pic, int lines) -{ - CPUState *cs = CPU(cpu); - DeviceState *dev; - - dev = qdev_create(NULL, TYPE_PXA2XX_GPIO); - qdev_prop_set_int32(dev, "lines", lines); - qdev_prop_set_int32(dev, "ncpu", cs->cpu_index); - qdev_init_nofail(dev); - - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, - qdev_get_gpio_in(pic, PXA2XX_PIC_GPIO_0)); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, - qdev_get_gpio_in(pic, PXA2XX_PIC_GPIO_1)); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, - qdev_get_gpio_in(pic, PXA2XX_PIC_GPIO_X)); - - return dev; -} - -static int pxa2xx_gpio_initfn(SysBusDevice *sbd) -{ - DeviceState *dev = DEVICE(sbd); - PXA2xxGPIOInfo *s = PXA2XX_GPIO(dev); - - s->cpu = ARM_CPU(qemu_get_cpu(s->ncpu)); - - qdev_init_gpio_in(dev, pxa2xx_gpio_set, s->lines); - qdev_init_gpio_out(dev, s->handler, s->lines); - - memory_region_init_io(&s->iomem, OBJECT(s), &pxa_gpio_ops, s, "pxa2xx-gpio", 0x1000); - sysbus_init_mmio(sbd, &s->iomem); - sysbus_init_irq(sbd, &s->irq0); - sysbus_init_irq(sbd, &s->irq1); - sysbus_init_irq(sbd, &s->irqX); - - return 0; -} - -/* - * Registers a callback to notify on GPLR reads. This normally - * shouldn't be needed but it is used for the hack on Spitz machines. - */ -void pxa2xx_gpio_read_notifier(DeviceState *dev, qemu_irq handler) -{ - PXA2xxGPIOInfo *s = PXA2XX_GPIO(dev); - - s->read_notify = handler; -} - -static const VMStateDescription vmstate_pxa2xx_gpio_regs = { - .name = "pxa2xx-gpio", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(ilevel, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS), - VMSTATE_UINT32_ARRAY(olevel, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS), - VMSTATE_UINT32_ARRAY(dir, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS), - VMSTATE_UINT32_ARRAY(rising, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS), - VMSTATE_UINT32_ARRAY(falling, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS), - VMSTATE_UINT32_ARRAY(status, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS), - VMSTATE_UINT32_ARRAY(gafr, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS * 2), - VMSTATE_UINT32_ARRAY(prev_level, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS), - VMSTATE_END_OF_LIST(), - }, -}; - -static Property pxa2xx_gpio_properties[] = { - DEFINE_PROP_INT32("lines", PXA2xxGPIOInfo, lines, 0), - DEFINE_PROP_INT32("ncpu", PXA2xxGPIOInfo, ncpu, 0), - DEFINE_PROP_END_OF_LIST(), -}; - -static void pxa2xx_gpio_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = pxa2xx_gpio_initfn; - dc->desc = "PXA2xx GPIO controller"; - dc->props = pxa2xx_gpio_properties; - dc->vmsd = &vmstate_pxa2xx_gpio_regs; -} - -static const TypeInfo pxa2xx_gpio_info = { - .name = TYPE_PXA2XX_GPIO, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(PXA2xxGPIOInfo), - .class_init = pxa2xx_gpio_class_init, -}; - -static void pxa2xx_gpio_register_types(void) -{ - type_register_static(&pxa2xx_gpio_info); -} - -type_init(pxa2xx_gpio_register_types) diff --git a/qemu/hw/arm/pxa2xx_pic.c b/qemu/hw/arm/pxa2xx_pic.c deleted file mode 100644 index 7e51532cd..000000000 --- a/qemu/hw/arm/pxa2xx_pic.c +++ /dev/null @@ -1,340 +0,0 @@ -/* - * Intel XScale PXA Programmable Interrupt Controller. - * - * Copyright (c) 2006 Openedhand Ltd. - * Copyright (c) 2006 Thorsten Zitterell - * Written by Andrzej Zaborowski <balrog@zabor.org> - * - * This code is licensed under the GPL. - */ - -#include "qemu/osdep.h" -#include "qemu-common.h" -#include "cpu.h" -#include "hw/hw.h" -#include "hw/arm/pxa.h" -#include "hw/sysbus.h" - -#define ICIP 0x00 /* Interrupt Controller IRQ Pending register */ -#define ICMR 0x04 /* Interrupt Controller Mask register */ -#define ICLR 0x08 /* Interrupt Controller Level register */ -#define ICFP 0x0c /* Interrupt Controller FIQ Pending register */ -#define ICPR 0x10 /* Interrupt Controller Pending register */ -#define ICCR 0x14 /* Interrupt Controller Control register */ -#define ICHP 0x18 /* Interrupt Controller Highest Priority register */ -#define IPR0 0x1c /* Interrupt Controller Priority register 0 */ -#define IPR31 0x98 /* Interrupt Controller Priority register 31 */ -#define ICIP2 0x9c /* Interrupt Controller IRQ Pending register 2 */ -#define ICMR2 0xa0 /* Interrupt Controller Mask register 2 */ -#define ICLR2 0xa4 /* Interrupt Controller Level register 2 */ -#define ICFP2 0xa8 /* Interrupt Controller FIQ Pending register 2 */ -#define ICPR2 0xac /* Interrupt Controller Pending register 2 */ -#define IPR32 0xb0 /* Interrupt Controller Priority register 32 */ -#define IPR39 0xcc /* Interrupt Controller Priority register 39 */ - -#define PXA2XX_PIC_SRCS 40 - -#define TYPE_PXA2XX_PIC "pxa2xx_pic" -#define PXA2XX_PIC(obj) \ - OBJECT_CHECK(PXA2xxPICState, (obj), TYPE_PXA2XX_PIC) - -typedef struct { - /*< private >*/ - SysBusDevice parent_obj; - /*< public >*/ - - MemoryRegion iomem; - ARMCPU *cpu; - uint32_t int_enabled[2]; - uint32_t int_pending[2]; - uint32_t is_fiq[2]; - uint32_t int_idle; - uint32_t priority[PXA2XX_PIC_SRCS]; -} PXA2xxPICState; - -static void pxa2xx_pic_update(void *opaque) -{ - uint32_t mask[2]; - PXA2xxPICState *s = (PXA2xxPICState *) opaque; - CPUState *cpu = CPU(s->cpu); - - if (cpu->halted) { - mask[0] = s->int_pending[0] & (s->int_enabled[0] | s->int_idle); - mask[1] = s->int_pending[1] & (s->int_enabled[1] | s->int_idle); - if (mask[0] || mask[1]) { - cpu_interrupt(cpu, CPU_INTERRUPT_EXITTB); - } - } - - mask[0] = s->int_pending[0] & s->int_enabled[0]; - mask[1] = s->int_pending[1] & s->int_enabled[1]; - - if ((mask[0] & s->is_fiq[0]) || (mask[1] & s->is_fiq[1])) { - cpu_interrupt(cpu, CPU_INTERRUPT_FIQ); - } else { - cpu_reset_interrupt(cpu, CPU_INTERRUPT_FIQ); - } - - if ((mask[0] & ~s->is_fiq[0]) || (mask[1] & ~s->is_fiq[1])) { - cpu_interrupt(cpu, CPU_INTERRUPT_HARD); - } else { - cpu_reset_interrupt(cpu, CPU_INTERRUPT_HARD); - } -} - -/* Note: Here level means state of the signal on a pin, not - * IRQ/FIQ distinction as in PXA Developer Manual. */ -static void pxa2xx_pic_set_irq(void *opaque, int irq, int level) -{ - PXA2xxPICState *s = (PXA2xxPICState *) opaque; - int int_set = (irq >= 32); - irq &= 31; - - if (level) - s->int_pending[int_set] |= 1 << irq; - else - s->int_pending[int_set] &= ~(1 << irq); - - pxa2xx_pic_update(opaque); -} - -static inline uint32_t pxa2xx_pic_highest(PXA2xxPICState *s) { - int i, int_set, irq; - uint32_t bit, mask[2]; - uint32_t ichp = 0x003f003f; /* Both IDs invalid */ - - mask[0] = s->int_pending[0] & s->int_enabled[0]; - mask[1] = s->int_pending[1] & s->int_enabled[1]; - - for (i = PXA2XX_PIC_SRCS - 1; i >= 0; i --) { - irq = s->priority[i] & 0x3f; - if ((s->priority[i] & (1U << 31)) && irq < PXA2XX_PIC_SRCS) { - /* Source peripheral ID is valid. */ - bit = 1 << (irq & 31); - int_set = (irq >= 32); - - if (mask[int_set] & bit & s->is_fiq[int_set]) { - /* FIQ asserted */ - ichp &= 0xffff0000; - ichp |= (1 << 15) | irq; - } - - if (mask[int_set] & bit & ~s->is_fiq[int_set]) { - /* IRQ asserted */ - ichp &= 0x0000ffff; - ichp |= (1U << 31) | (irq << 16); - } - } - } - - return ichp; -} - -static uint64_t pxa2xx_pic_mem_read(void *opaque, hwaddr offset, - unsigned size) -{ - PXA2xxPICState *s = (PXA2xxPICState *) opaque; - - switch (offset) { - case ICIP: /* IRQ Pending register */ - return s->int_pending[0] & ~s->is_fiq[0] & s->int_enabled[0]; - case ICIP2: /* IRQ Pending register 2 */ - return s->int_pending[1] & ~s->is_fiq[1] & s->int_enabled[1]; - case ICMR: /* Mask register */ - return s->int_enabled[0]; - case ICMR2: /* Mask register 2 */ - return s->int_enabled[1]; - case ICLR: /* Level register */ - return s->is_fiq[0]; - case ICLR2: /* Level register 2 */ - return s->is_fiq[1]; - case ICCR: /* Idle mask */ - return (s->int_idle == 0); - case ICFP: /* FIQ Pending register */ - return s->int_pending[0] & s->is_fiq[0] & s->int_enabled[0]; - case ICFP2: /* FIQ Pending register 2 */ - return s->int_pending[1] & s->is_fiq[1] & s->int_enabled[1]; - case ICPR: /* Pending register */ - return s->int_pending[0]; - case ICPR2: /* Pending register 2 */ - return s->int_pending[1]; - case IPR0 ... IPR31: - return s->priority[0 + ((offset - IPR0 ) >> 2)]; - case IPR32 ... IPR39: - return s->priority[32 + ((offset - IPR32) >> 2)]; - case ICHP: /* Highest Priority register */ - return pxa2xx_pic_highest(s); - default: - printf("%s: Bad register offset " REG_FMT "\n", __FUNCTION__, offset); - return 0; - } -} - -static void pxa2xx_pic_mem_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - PXA2xxPICState *s = (PXA2xxPICState *) opaque; - - switch (offset) { - case ICMR: /* Mask register */ - s->int_enabled[0] = value; - break; - case ICMR2: /* Mask register 2 */ - s->int_enabled[1] = value; - break; - case ICLR: /* Level register */ - s->is_fiq[0] = value; - break; - case ICLR2: /* Level register 2 */ - s->is_fiq[1] = value; - break; - case ICCR: /* Idle mask */ - s->int_idle = (value & 1) ? 0 : ~0; - break; - case IPR0 ... IPR31: - s->priority[0 + ((offset - IPR0 ) >> 2)] = value & 0x8000003f; - break; - case IPR32 ... IPR39: - s->priority[32 + ((offset - IPR32) >> 2)] = value & 0x8000003f; - break; - default: - printf("%s: Bad register offset " REG_FMT "\n", __FUNCTION__, offset); - return; - } - pxa2xx_pic_update(opaque); -} - -/* Interrupt Controller Coprocessor Space Register Mapping */ -static const int pxa2xx_cp_reg_map[0x10] = { - [0x0 ... 0xf] = -1, - [0x0] = ICIP, - [0x1] = ICMR, - [0x2] = ICLR, - [0x3] = ICFP, - [0x4] = ICPR, - [0x5] = ICHP, - [0x6] = ICIP2, - [0x7] = ICMR2, - [0x8] = ICLR2, - [0x9] = ICFP2, - [0xa] = ICPR2, -}; - -static uint64_t pxa2xx_pic_cp_read(CPUARMState *env, const ARMCPRegInfo *ri) -{ - int offset = pxa2xx_cp_reg_map[ri->crn]; - return pxa2xx_pic_mem_read(ri->opaque, offset, 4); -} - -static void pxa2xx_pic_cp_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - int offset = pxa2xx_cp_reg_map[ri->crn]; - pxa2xx_pic_mem_write(ri->opaque, offset, value, 4); -} - -#define REGINFO_FOR_PIC_CP(NAME, CRN) \ - { .name = NAME, .cp = 6, .crn = CRN, .crm = 0, .opc1 = 0, .opc2 = 0, \ - .access = PL1_RW, .type = ARM_CP_IO, \ - .readfn = pxa2xx_pic_cp_read, .writefn = pxa2xx_pic_cp_write } - -static const ARMCPRegInfo pxa_pic_cp_reginfo[] = { - REGINFO_FOR_PIC_CP("ICIP", 0), - REGINFO_FOR_PIC_CP("ICMR", 1), - REGINFO_FOR_PIC_CP("ICLR", 2), - REGINFO_FOR_PIC_CP("ICFP", 3), - REGINFO_FOR_PIC_CP("ICPR", 4), - REGINFO_FOR_PIC_CP("ICHP", 5), - REGINFO_FOR_PIC_CP("ICIP2", 6), - REGINFO_FOR_PIC_CP("ICMR2", 7), - REGINFO_FOR_PIC_CP("ICLR2", 8), - REGINFO_FOR_PIC_CP("ICFP2", 9), - REGINFO_FOR_PIC_CP("ICPR2", 0xa), - REGINFO_SENTINEL -}; - -static const MemoryRegionOps pxa2xx_pic_ops = { - .read = pxa2xx_pic_mem_read, - .write = pxa2xx_pic_mem_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static int pxa2xx_pic_post_load(void *opaque, int version_id) -{ - pxa2xx_pic_update(opaque); - return 0; -} - -DeviceState *pxa2xx_pic_init(hwaddr base, ARMCPU *cpu) -{ - DeviceState *dev = qdev_create(NULL, TYPE_PXA2XX_PIC); - PXA2xxPICState *s = PXA2XX_PIC(dev); - - s->cpu = cpu; - - s->int_pending[0] = 0; - s->int_pending[1] = 0; - s->int_enabled[0] = 0; - s->int_enabled[1] = 0; - s->is_fiq[0] = 0; - s->is_fiq[1] = 0; - - qdev_init_nofail(dev); - - qdev_init_gpio_in(dev, pxa2xx_pic_set_irq, PXA2XX_PIC_SRCS); - - /* Enable IC memory-mapped registers access. */ - memory_region_init_io(&s->iomem, OBJECT(s), &pxa2xx_pic_ops, s, - "pxa2xx-pic", 0x00100000); - sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); - - /* Enable IC coprocessor access. */ - define_arm_cp_regs_with_opaque(cpu, pxa_pic_cp_reginfo, s); - - return dev; -} - -static VMStateDescription vmstate_pxa2xx_pic_regs = { - .name = "pxa2xx_pic", - .version_id = 0, - .minimum_version_id = 0, - .post_load = pxa2xx_pic_post_load, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(int_enabled, PXA2xxPICState, 2), - VMSTATE_UINT32_ARRAY(int_pending, PXA2xxPICState, 2), - VMSTATE_UINT32_ARRAY(is_fiq, PXA2xxPICState, 2), - VMSTATE_UINT32(int_idle, PXA2xxPICState), - VMSTATE_UINT32_ARRAY(priority, PXA2xxPICState, PXA2XX_PIC_SRCS), - VMSTATE_END_OF_LIST(), - }, -}; - -static int pxa2xx_pic_initfn(SysBusDevice *dev) -{ - return 0; -} - -static void pxa2xx_pic_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = pxa2xx_pic_initfn; - dc->desc = "PXA2xx PIC"; - dc->vmsd = &vmstate_pxa2xx_pic_regs; -} - -static const TypeInfo pxa2xx_pic_info = { - .name = TYPE_PXA2XX_PIC, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(PXA2xxPICState), - .class_init = pxa2xx_pic_class_init, -}; - -static void pxa2xx_pic_register_types(void) -{ - type_register_static(&pxa2xx_pic_info); -} - -type_init(pxa2xx_pic_register_types) diff --git a/qemu/hw/arm/raspi.c b/qemu/hw/arm/raspi.c deleted file mode 100644 index 2b295f14c..000000000 --- a/qemu/hw/arm/raspi.c +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Raspberry Pi emulation (c) 2012 Gregory Estrade - * Upstreaming code cleanup [including bcm2835_*] (c) 2013 Jan Petrous - * - * Rasperry Pi 2 emulation Copyright (c) 2015, Microsoft - * Written by Andrew Baumann - * - * This code is licensed under the GNU GPLv2 and later. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "qemu-common.h" -#include "cpu.h" -#include "hw/arm/bcm2836.h" -#include "qemu/error-report.h" -#include "hw/boards.h" -#include "hw/loader.h" -#include "hw/arm/arm.h" -#include "sysemu/sysemu.h" - -#define SMPBOOT_ADDR 0x300 /* this should leave enough space for ATAGS */ -#define MVBAR_ADDR 0x400 /* secure vectors */ -#define BOARDSETUP_ADDR (MVBAR_ADDR + 0x20) /* board setup code */ -#define FIRMWARE_ADDR 0x8000 /* Pi loads kernel.img here by default */ - -/* Table of Linux board IDs for different Pi versions */ -static const int raspi_boardid[] = {[1] = 0xc42, [2] = 0xc43}; - -typedef struct RasPiState { - BCM2836State soc; - MemoryRegion ram; -} RasPiState; - -static void write_smpboot(ARMCPU *cpu, const struct arm_boot_info *info) -{ - static const uint32_t smpboot[] = { - 0xe1a0e00f, /* mov lr, pc */ - 0xe3a0fe00 + (BOARDSETUP_ADDR >> 4), /* mov pc, BOARDSETUP_ADDR */ - 0xee100fb0, /* mrc p15, 0, r0, c0, c0, 5;get core ID */ - 0xe7e10050, /* ubfx r0, r0, #0, #2 ;extract LSB */ - 0xe59f5014, /* ldr r5, =0x400000CC ;load mbox base */ - 0xe320f001, /* 1: yield */ - 0xe7953200, /* ldr r3, [r5, r0, lsl #4] ;read mbox for our core*/ - 0xe3530000, /* cmp r3, #0 ;spin while zero */ - 0x0afffffb, /* beq 1b */ - 0xe7853200, /* str r3, [r5, r0, lsl #4] ;clear mbox */ - 0xe12fff13, /* bx r3 ;jump to target */ - 0x400000cc, /* (constant: mailbox 3 read/clear base) */ - }; - - /* check that we don't overrun board setup vectors */ - QEMU_BUILD_BUG_ON(SMPBOOT_ADDR + sizeof(smpboot) > MVBAR_ADDR); - /* check that board setup address is correctly relocated */ - QEMU_BUILD_BUG_ON((BOARDSETUP_ADDR & 0xf) != 0 - || (BOARDSETUP_ADDR >> 4) >= 0x100); - - rom_add_blob_fixed("raspi_smpboot", smpboot, sizeof(smpboot), - info->smp_loader_start); -} - -static void write_board_setup(ARMCPU *cpu, const struct arm_boot_info *info) -{ - arm_write_secure_board_setup_dummy_smc(cpu, info, MVBAR_ADDR); -} - -static void reset_secondary(ARMCPU *cpu, const struct arm_boot_info *info) -{ - CPUState *cs = CPU(cpu); - cpu_set_pc(cs, info->smp_loader_start); -} - -static void setup_boot(MachineState *machine, int version, size_t ram_size) -{ - static struct arm_boot_info binfo; - int r; - - binfo.board_id = raspi_boardid[version]; - binfo.ram_size = ram_size; - binfo.nb_cpus = smp_cpus; - binfo.board_setup_addr = BOARDSETUP_ADDR; - binfo.write_board_setup = write_board_setup; - binfo.secure_board_setup = true; - binfo.secure_boot = true; - - /* Pi2 requires SMP setup */ - if (version == 2) { - binfo.smp_loader_start = SMPBOOT_ADDR; - binfo.write_secondary_boot = write_smpboot; - binfo.secondary_cpu_reset_hook = reset_secondary; - } - - /* If the user specified a "firmware" image (e.g. UEFI), we bypass - * the normal Linux boot process - */ - if (machine->firmware) { - /* load the firmware image (typically kernel.img) */ - r = load_image_targphys(machine->firmware, FIRMWARE_ADDR, - ram_size - FIRMWARE_ADDR); - if (r < 0) { - error_report("Failed to load firmware from %s", machine->firmware); - exit(1); - } - - binfo.entry = FIRMWARE_ADDR; - binfo.firmware_loaded = true; - } else { - binfo.kernel_filename = machine->kernel_filename; - binfo.kernel_cmdline = machine->kernel_cmdline; - binfo.initrd_filename = machine->initrd_filename; - } - - arm_load_kernel(ARM_CPU(first_cpu), &binfo); -} - -static void raspi2_init(MachineState *machine) -{ - RasPiState *s = g_new0(RasPiState, 1); - uint32_t vcram_size; - DriveInfo *di; - BlockBackend *blk; - BusState *bus; - DeviceState *carddev; - - object_initialize(&s->soc, sizeof(s->soc), TYPE_BCM2836); - object_property_add_child(OBJECT(machine), "soc", OBJECT(&s->soc), - &error_abort); - - /* Allocate and map RAM */ - memory_region_allocate_system_memory(&s->ram, OBJECT(machine), "ram", - machine->ram_size); - /* FIXME: Remove when we have custom CPU address space support */ - memory_region_add_subregion_overlap(get_system_memory(), 0, &s->ram, 0); - - /* Setup the SOC */ - object_property_add_const_link(OBJECT(&s->soc), "ram", OBJECT(&s->ram), - &error_abort); - object_property_set_int(OBJECT(&s->soc), smp_cpus, "enabled-cpus", - &error_abort); - object_property_set_int(OBJECT(&s->soc), 0xa21041, "board-rev", - &error_abort); - object_property_set_bool(OBJECT(&s->soc), true, "realized", &error_abort); - - /* Create and plug in the SD cards */ - di = drive_get_next(IF_SD); - blk = di ? blk_by_legacy_dinfo(di) : NULL; - bus = qdev_get_child_bus(DEVICE(&s->soc), "sd-bus"); - if (bus == NULL) { - error_report("No SD bus found in SOC object"); - exit(1); - } - carddev = qdev_create(bus, TYPE_SD_CARD); - qdev_prop_set_drive(carddev, "drive", blk, &error_fatal); - object_property_set_bool(OBJECT(carddev), true, "realized", &error_fatal); - - vcram_size = object_property_get_int(OBJECT(&s->soc), "vcram-size", - &error_abort); - setup_boot(machine, 2, machine->ram_size - vcram_size); -} - -static void raspi2_machine_init(MachineClass *mc) -{ - mc->desc = "Raspberry Pi 2"; - mc->init = raspi2_init; - mc->block_default_type = IF_SD; - mc->no_parallel = 1; - mc->no_floppy = 1; - mc->no_cdrom = 1; - mc->max_cpus = BCM2836_NCPUS; - mc->default_ram_size = 1024 * 1024 * 1024; -}; -DEFINE_MACHINE("raspi2", raspi2_machine_init) diff --git a/qemu/hw/arm/realview.c b/qemu/hw/arm/realview.c deleted file mode 100644 index 3222b360e..000000000 --- a/qemu/hw/arm/realview.c +++ /dev/null @@ -1,463 +0,0 @@ -/* - * ARM RealView Baseboard System emulation. - * - * Copyright (c) 2006-2007 CodeSourcery. - * Written by Paul Brook - * - * This code is licensed under the GPL. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "qemu-common.h" -#include "cpu.h" -#include "hw/sysbus.h" -#include "hw/arm/arm.h" -#include "hw/arm/primecell.h" -#include "hw/devices.h" -#include "hw/pci/pci.h" -#include "net/net.h" -#include "sysemu/sysemu.h" -#include "hw/boards.h" -#include "hw/i2c/i2c.h" -#include "sysemu/block-backend.h" -#include "exec/address-spaces.h" -#include "qemu/error-report.h" - -#define SMP_BOOT_ADDR 0xe0000000 -#define SMP_BOOTREG_ADDR 0x10000030 - -/* Board init. */ - -static struct arm_boot_info realview_binfo = { - .smp_loader_start = SMP_BOOT_ADDR, - .smp_bootreg_addr = SMP_BOOTREG_ADDR, -}; - -/* The following two lists must be consistent. */ -enum realview_board_type { - BOARD_EB, - BOARD_EB_MPCORE, - BOARD_PB_A8, - BOARD_PBX_A9, -}; - -static const int realview_board_id[] = { - 0x33b, - 0x33b, - 0x769, - 0x76d -}; - -static void realview_init(MachineState *machine, - enum realview_board_type board_type) -{ - ARMCPU *cpu = NULL; - CPUARMState *env; - ObjectClass *cpu_oc; - MemoryRegion *sysmem = get_system_memory(); - MemoryRegion *ram_lo; - MemoryRegion *ram_hi = g_new(MemoryRegion, 1); - MemoryRegion *ram_alias = g_new(MemoryRegion, 1); - MemoryRegion *ram_hack = g_new(MemoryRegion, 1); - DeviceState *dev, *sysctl, *gpio2, *pl041; - SysBusDevice *busdev; - qemu_irq pic[64]; - qemu_irq mmc_irq[2]; - PCIBus *pci_bus = NULL; - NICInfo *nd; - I2CBus *i2c; - int n; - int done_nic = 0; - qemu_irq cpu_irq[4]; - int is_mpcore = 0; - int is_pb = 0; - uint32_t proc_id = 0; - uint32_t sys_id; - ram_addr_t low_ram_size; - ram_addr_t ram_size = machine->ram_size; - hwaddr periphbase = 0; - - switch (board_type) { - case BOARD_EB: - break; - case BOARD_EB_MPCORE: - is_mpcore = 1; - periphbase = 0x10100000; - break; - case BOARD_PB_A8: - is_pb = 1; - break; - case BOARD_PBX_A9: - is_mpcore = 1; - is_pb = 1; - periphbase = 0x1f000000; - break; - } - - cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, machine->cpu_model); - if (!cpu_oc) { - fprintf(stderr, "Unable to find CPU definition\n"); - exit(1); - } - - for (n = 0; n < smp_cpus; n++) { - Object *cpuobj = object_new(object_class_get_name(cpu_oc)); - - /* By default A9,A15 and ARM1176 CPUs have EL3 enabled. This board - * does not currently support EL3 so the CPU EL3 property is disabled - * before realization. - */ - if (object_property_find(cpuobj, "has_el3", NULL)) { - object_property_set_bool(cpuobj, false, "has_el3", &error_fatal); - } - - if (is_pb && is_mpcore) { - object_property_set_int(cpuobj, periphbase, "reset-cbar", - &error_fatal); - } - - object_property_set_bool(cpuobj, true, "realized", &error_fatal); - - cpu_irq[n] = qdev_get_gpio_in(DEVICE(cpuobj), ARM_CPU_IRQ); - } - cpu = ARM_CPU(first_cpu); - env = &cpu->env; - if (arm_feature(env, ARM_FEATURE_V7)) { - if (is_mpcore) { - proc_id = 0x0c000000; - } else { - proc_id = 0x0e000000; - } - } else if (arm_feature(env, ARM_FEATURE_V6K)) { - proc_id = 0x06000000; - } else if (arm_feature(env, ARM_FEATURE_V6)) { - proc_id = 0x04000000; - } else { - proc_id = 0x02000000; - } - - if (is_pb && ram_size > 0x20000000) { - /* Core tile RAM. */ - ram_lo = g_new(MemoryRegion, 1); - low_ram_size = ram_size - 0x20000000; - ram_size = 0x20000000; - memory_region_init_ram(ram_lo, NULL, "realview.lowmem", low_ram_size, - &error_fatal); - vmstate_register_ram_global(ram_lo); - memory_region_add_subregion(sysmem, 0x20000000, ram_lo); - } - - memory_region_init_ram(ram_hi, NULL, "realview.highmem", ram_size, - &error_fatal); - vmstate_register_ram_global(ram_hi); - low_ram_size = ram_size; - if (low_ram_size > 0x10000000) - low_ram_size = 0x10000000; - /* SDRAM at address zero. */ - memory_region_init_alias(ram_alias, NULL, "realview.alias", - ram_hi, 0, low_ram_size); - memory_region_add_subregion(sysmem, 0, ram_alias); - if (is_pb) { - /* And again at a high address. */ - memory_region_add_subregion(sysmem, 0x70000000, ram_hi); - } else { - ram_size = low_ram_size; - } - - sys_id = is_pb ? 0x01780500 : 0xc1400400; - sysctl = qdev_create(NULL, "realview_sysctl"); - qdev_prop_set_uint32(sysctl, "sys_id", sys_id); - qdev_prop_set_uint32(sysctl, "proc_id", proc_id); - qdev_init_nofail(sysctl); - sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, 0x10000000); - - if (is_mpcore) { - dev = qdev_create(NULL, is_pb ? "a9mpcore_priv": "realview_mpcore"); - qdev_prop_set_uint32(dev, "num-cpu", smp_cpus); - qdev_init_nofail(dev); - busdev = SYS_BUS_DEVICE(dev); - sysbus_mmio_map(busdev, 0, periphbase); - for (n = 0; n < smp_cpus; n++) { - sysbus_connect_irq(busdev, n, cpu_irq[n]); - } - sysbus_create_varargs("l2x0", periphbase + 0x2000, NULL); - /* Both A9 and 11MPCore put the GIC CPU i/f at base + 0x100 */ - realview_binfo.gic_cpu_if_addr = periphbase + 0x100; - } else { - uint32_t gic_addr = is_pb ? 0x1e000000 : 0x10040000; - /* For now just create the nIRQ GIC, and ignore the others. */ - dev = sysbus_create_simple("realview_gic", gic_addr, cpu_irq[0]); - } - for (n = 0; n < 64; n++) { - pic[n] = qdev_get_gpio_in(dev, n); - } - - pl041 = qdev_create(NULL, "pl041"); - qdev_prop_set_uint32(pl041, "nc_fifo_depth", 512); - qdev_init_nofail(pl041); - sysbus_mmio_map(SYS_BUS_DEVICE(pl041), 0, 0x10004000); - sysbus_connect_irq(SYS_BUS_DEVICE(pl041), 0, pic[19]); - - sysbus_create_simple("pl050_keyboard", 0x10006000, pic[20]); - sysbus_create_simple("pl050_mouse", 0x10007000, pic[21]); - - sysbus_create_simple("pl011", 0x10009000, pic[12]); - sysbus_create_simple("pl011", 0x1000a000, pic[13]); - sysbus_create_simple("pl011", 0x1000b000, pic[14]); - sysbus_create_simple("pl011", 0x1000c000, pic[15]); - - /* DMA controller is optional, apparently. */ - sysbus_create_simple("pl081", 0x10030000, pic[24]); - - sysbus_create_simple("sp804", 0x10011000, pic[4]); - sysbus_create_simple("sp804", 0x10012000, pic[5]); - - sysbus_create_simple("pl061", 0x10013000, pic[6]); - sysbus_create_simple("pl061", 0x10014000, pic[7]); - gpio2 = sysbus_create_simple("pl061", 0x10015000, pic[8]); - - sysbus_create_simple("pl111", 0x10020000, pic[23]); - - dev = sysbus_create_varargs("pl181", 0x10005000, pic[17], pic[18], NULL); - /* Wire up MMC card detect and read-only signals. These have - * to go to both the PL061 GPIO and the sysctl register. - * Note that the PL181 orders these lines (readonly,inserted) - * and the PL061 has them the other way about. Also the card - * detect line is inverted. - */ - mmc_irq[0] = qemu_irq_split( - qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_WPROT), - qdev_get_gpio_in(gpio2, 1)); - mmc_irq[1] = qemu_irq_split( - qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_CARDIN), - qemu_irq_invert(qdev_get_gpio_in(gpio2, 0))); - qdev_connect_gpio_out(dev, 0, mmc_irq[0]); - qdev_connect_gpio_out(dev, 1, mmc_irq[1]); - - sysbus_create_simple("pl031", 0x10017000, pic[10]); - - if (!is_pb) { - dev = qdev_create(NULL, "realview_pci"); - busdev = SYS_BUS_DEVICE(dev); - qdev_init_nofail(dev); - sysbus_mmio_map(busdev, 0, 0x10019000); /* PCI controller registers */ - sysbus_mmio_map(busdev, 1, 0x60000000); /* PCI self-config */ - sysbus_mmio_map(busdev, 2, 0x61000000); /* PCI config */ - sysbus_mmio_map(busdev, 3, 0x62000000); /* PCI I/O */ - sysbus_mmio_map(busdev, 4, 0x63000000); /* PCI memory window 1 */ - sysbus_mmio_map(busdev, 5, 0x64000000); /* PCI memory window 2 */ - sysbus_mmio_map(busdev, 6, 0x68000000); /* PCI memory window 3 */ - sysbus_connect_irq(busdev, 0, pic[48]); - sysbus_connect_irq(busdev, 1, pic[49]); - sysbus_connect_irq(busdev, 2, pic[50]); - sysbus_connect_irq(busdev, 3, pic[51]); - pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci"); - if (usb_enabled()) { - pci_create_simple(pci_bus, -1, "pci-ohci"); - } - n = drive_get_max_bus(IF_SCSI); - while (n >= 0) { - pci_create_simple(pci_bus, -1, "lsi53c895a"); - n--; - } - } - for(n = 0; n < nb_nics; n++) { - nd = &nd_table[n]; - - if (!done_nic && (!nd->model || - strcmp(nd->model, is_pb ? "lan9118" : "smc91c111") == 0)) { - if (is_pb) { - lan9118_init(nd, 0x4e000000, pic[28]); - } else { - smc91c111_init(nd, 0x4e000000, pic[28]); - } - done_nic = 1; - } else { - if (pci_bus) { - pci_nic_init_nofail(nd, pci_bus, "rtl8139", NULL); - } - } - } - - dev = sysbus_create_simple("versatile_i2c", 0x10002000, NULL); - i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c"); - i2c_create_slave(i2c, "ds1338", 0x68); - - /* Memory map for RealView Emulation Baseboard: */ - /* 0x10000000 System registers. */ - /* 0x10001000 System controller. */ - /* 0x10002000 Two-Wire Serial Bus. */ - /* 0x10003000 Reserved. */ - /* 0x10004000 AACI. */ - /* 0x10005000 MCI. */ - /* 0x10006000 KMI0. */ - /* 0x10007000 KMI1. */ - /* 0x10008000 Character LCD. (EB) */ - /* 0x10009000 UART0. */ - /* 0x1000a000 UART1. */ - /* 0x1000b000 UART2. */ - /* 0x1000c000 UART3. */ - /* 0x1000d000 SSPI. */ - /* 0x1000e000 SCI. */ - /* 0x1000f000 Reserved. */ - /* 0x10010000 Watchdog. */ - /* 0x10011000 Timer 0+1. */ - /* 0x10012000 Timer 2+3. */ - /* 0x10013000 GPIO 0. */ - /* 0x10014000 GPIO 1. */ - /* 0x10015000 GPIO 2. */ - /* 0x10002000 Two-Wire Serial Bus - DVI. (PB) */ - /* 0x10017000 RTC. */ - /* 0x10018000 DMC. */ - /* 0x10019000 PCI controller config. */ - /* 0x10020000 CLCD. */ - /* 0x10030000 DMA Controller. */ - /* 0x10040000 GIC1. (EB) */ - /* 0x10050000 GIC2. (EB) */ - /* 0x10060000 GIC3. (EB) */ - /* 0x10070000 GIC4. (EB) */ - /* 0x10080000 SMC. */ - /* 0x1e000000 GIC1. (PB) */ - /* 0x1e001000 GIC2. (PB) */ - /* 0x1e002000 GIC3. (PB) */ - /* 0x1e003000 GIC4. (PB) */ - /* 0x40000000 NOR flash. */ - /* 0x44000000 DoC flash. */ - /* 0x48000000 SRAM. */ - /* 0x4c000000 Configuration flash. */ - /* 0x4e000000 Ethernet. */ - /* 0x4f000000 USB. */ - /* 0x50000000 PISMO. */ - /* 0x54000000 PISMO. */ - /* 0x58000000 PISMO. */ - /* 0x5c000000 PISMO. */ - /* 0x60000000 PCI. */ - /* 0x60000000 PCI Self Config. */ - /* 0x61000000 PCI Config. */ - /* 0x62000000 PCI IO. */ - /* 0x63000000 PCI mem 0. */ - /* 0x64000000 PCI mem 1. */ - /* 0x68000000 PCI mem 2. */ - - /* ??? Hack to map an additional page of ram for the secondary CPU - startup code. I guess this works on real hardware because the - BootROM happens to be in ROM/flash or in memory that isn't clobbered - until after Linux boots the secondary CPUs. */ - memory_region_init_ram(ram_hack, NULL, "realview.hack", 0x1000, - &error_fatal); - vmstate_register_ram_global(ram_hack); - memory_region_add_subregion(sysmem, SMP_BOOT_ADDR, ram_hack); - - realview_binfo.ram_size = ram_size; - realview_binfo.kernel_filename = machine->kernel_filename; - realview_binfo.kernel_cmdline = machine->kernel_cmdline; - realview_binfo.initrd_filename = machine->initrd_filename; - realview_binfo.nb_cpus = smp_cpus; - realview_binfo.board_id = realview_board_id[board_type]; - realview_binfo.loader_start = (board_type == BOARD_PB_A8 ? 0x70000000 : 0); - arm_load_kernel(ARM_CPU(first_cpu), &realview_binfo); -} - -static void realview_eb_init(MachineState *machine) -{ - if (!machine->cpu_model) { - machine->cpu_model = "arm926"; - } - realview_init(machine, BOARD_EB); -} - -static void realview_eb_mpcore_init(MachineState *machine) -{ - if (!machine->cpu_model) { - machine->cpu_model = "arm11mpcore"; - } - realview_init(machine, BOARD_EB_MPCORE); -} - -static void realview_pb_a8_init(MachineState *machine) -{ - if (!machine->cpu_model) { - machine->cpu_model = "cortex-a8"; - } - realview_init(machine, BOARD_PB_A8); -} - -static void realview_pbx_a9_init(MachineState *machine) -{ - if (!machine->cpu_model) { - machine->cpu_model = "cortex-a9"; - } - realview_init(machine, BOARD_PBX_A9); -} - -static void realview_eb_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "ARM RealView Emulation Baseboard (ARM926EJ-S)"; - mc->init = realview_eb_init; - mc->block_default_type = IF_SCSI; -} - -static const TypeInfo realview_eb_type = { - .name = MACHINE_TYPE_NAME("realview-eb"), - .parent = TYPE_MACHINE, - .class_init = realview_eb_class_init, -}; - -static void realview_eb_mpcore_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "ARM RealView Emulation Baseboard (ARM11MPCore)"; - mc->init = realview_eb_mpcore_init; - mc->block_default_type = IF_SCSI; - mc->max_cpus = 4; -} - -static const TypeInfo realview_eb_mpcore_type = { - .name = MACHINE_TYPE_NAME("realview-eb-mpcore"), - .parent = TYPE_MACHINE, - .class_init = realview_eb_mpcore_class_init, -}; - -static void realview_pb_a8_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "ARM RealView Platform Baseboard for Cortex-A8"; - mc->init = realview_pb_a8_init; -} - -static const TypeInfo realview_pb_a8_type = { - .name = MACHINE_TYPE_NAME("realview-pb-a8"), - .parent = TYPE_MACHINE, - .class_init = realview_pb_a8_class_init, -}; - -static void realview_pbx_a9_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "ARM RealView Platform Baseboard Explore for Cortex-A9"; - mc->init = realview_pbx_a9_init; - mc->block_default_type = IF_SCSI; - mc->max_cpus = 4; -} - -static const TypeInfo realview_pbx_a9_type = { - .name = MACHINE_TYPE_NAME("realview-pbx-a9"), - .parent = TYPE_MACHINE, - .class_init = realview_pbx_a9_class_init, -}; - -static void realview_machine_init(void) -{ - type_register_static(&realview_eb_type); - type_register_static(&realview_eb_mpcore_type); - type_register_static(&realview_pb_a8_type); - type_register_static(&realview_pbx_a9_type); -} - -type_init(realview_machine_init) diff --git a/qemu/hw/arm/spitz.c b/qemu/hw/arm/spitz.c deleted file mode 100644 index bf61d63b5..000000000 --- a/qemu/hw/arm/spitz.c +++ /dev/null @@ -1,1178 +0,0 @@ -/* - * PXA270-based Clamshell PDA platforms. - * - * Copyright (c) 2006 Openedhand Ltd. - * Written by Andrzej Zaborowski <balrog@zabor.org> - * - * 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 "qemu/osdep.h" -#include "qapi/error.h" -#include "hw/hw.h" -#include "hw/arm/pxa.h" -#include "hw/arm/arm.h" -#include "sysemu/sysemu.h" -#include "hw/pcmcia.h" -#include "hw/i2c/i2c.h" -#include "hw/ssi/ssi.h" -#include "hw/block/flash.h" -#include "qemu/timer.h" -#include "hw/devices.h" -#include "hw/arm/sharpsl.h" -#include "ui/console.h" -#include "audio/audio.h" -#include "hw/boards.h" -#include "sysemu/block-backend.h" -#include "hw/sysbus.h" -#include "exec/address-spaces.h" - -#undef REG_FMT -#define REG_FMT "0x%02lx" - -/* Spitz Flash */ -#define FLASH_BASE 0x0c000000 -#define FLASH_ECCLPLB 0x00 /* Line parity 7 - 0 bit */ -#define FLASH_ECCLPUB 0x04 /* Line parity 15 - 8 bit */ -#define FLASH_ECCCP 0x08 /* Column parity 5 - 0 bit */ -#define FLASH_ECCCNTR 0x0c /* ECC byte counter */ -#define FLASH_ECCCLRR 0x10 /* Clear ECC */ -#define FLASH_FLASHIO 0x14 /* Flash I/O */ -#define FLASH_FLASHCTL 0x18 /* Flash Control */ - -#define FLASHCTL_CE0 (1 << 0) -#define FLASHCTL_CLE (1 << 1) -#define FLASHCTL_ALE (1 << 2) -#define FLASHCTL_WP (1 << 3) -#define FLASHCTL_CE1 (1 << 4) -#define FLASHCTL_RYBY (1 << 5) -#define FLASHCTL_NCE (FLASHCTL_CE0 | FLASHCTL_CE1) - -#define TYPE_SL_NAND "sl-nand" -#define SL_NAND(obj) OBJECT_CHECK(SLNANDState, (obj), TYPE_SL_NAND) - -typedef struct { - SysBusDevice parent_obj; - - MemoryRegion iomem; - DeviceState *nand; - uint8_t ctl; - uint8_t manf_id; - uint8_t chip_id; - ECCState ecc; -} SLNANDState; - -static uint64_t sl_read(void *opaque, hwaddr addr, unsigned size) -{ - SLNANDState *s = (SLNANDState *) opaque; - int ryby; - - switch (addr) { -#define BSHR(byte, from, to) ((s->ecc.lp[byte] >> (from - to)) & (1 << to)) - case FLASH_ECCLPLB: - return BSHR(0, 4, 0) | BSHR(0, 5, 2) | BSHR(0, 6, 4) | BSHR(0, 7, 6) | - BSHR(1, 4, 1) | BSHR(1, 5, 3) | BSHR(1, 6, 5) | BSHR(1, 7, 7); - -#define BSHL(byte, from, to) ((s->ecc.lp[byte] << (to - from)) & (1 << to)) - case FLASH_ECCLPUB: - return BSHL(0, 0, 0) | BSHL(0, 1, 2) | BSHL(0, 2, 4) | BSHL(0, 3, 6) | - BSHL(1, 0, 1) | BSHL(1, 1, 3) | BSHL(1, 2, 5) | BSHL(1, 3, 7); - - case FLASH_ECCCP: - return s->ecc.cp; - - case FLASH_ECCCNTR: - return s->ecc.count & 0xff; - - case FLASH_FLASHCTL: - nand_getpins(s->nand, &ryby); - if (ryby) - return s->ctl | FLASHCTL_RYBY; - else - return s->ctl; - - case FLASH_FLASHIO: - if (size == 4) { - return ecc_digest(&s->ecc, nand_getio(s->nand)) | - (ecc_digest(&s->ecc, nand_getio(s->nand)) << 16); - } - return ecc_digest(&s->ecc, nand_getio(s->nand)); - - default: - zaurus_printf("Bad register offset " REG_FMT "\n", (unsigned long)addr); - } - return 0; -} - -static void sl_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - SLNANDState *s = (SLNANDState *) opaque; - - switch (addr) { - case FLASH_ECCCLRR: - /* Value is ignored. */ - ecc_reset(&s->ecc); - break; - - case FLASH_FLASHCTL: - s->ctl = value & 0xff & ~FLASHCTL_RYBY; - nand_setpins(s->nand, - s->ctl & FLASHCTL_CLE, - s->ctl & FLASHCTL_ALE, - s->ctl & FLASHCTL_NCE, - s->ctl & FLASHCTL_WP, - 0); - break; - - case FLASH_FLASHIO: - nand_setio(s->nand, ecc_digest(&s->ecc, value & 0xff)); - break; - - default: - zaurus_printf("Bad register offset " REG_FMT "\n", (unsigned long)addr); - } -} - -enum { - FLASH_128M, - FLASH_1024M, -}; - -static const MemoryRegionOps sl_ops = { - .read = sl_read, - .write = sl_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void sl_flash_register(PXA2xxState *cpu, int size) -{ - DeviceState *dev; - - dev = qdev_create(NULL, TYPE_SL_NAND); - - qdev_prop_set_uint8(dev, "manf_id", NAND_MFR_SAMSUNG); - if (size == FLASH_128M) - qdev_prop_set_uint8(dev, "chip_id", 0x73); - else if (size == FLASH_1024M) - qdev_prop_set_uint8(dev, "chip_id", 0xf1); - - qdev_init_nofail(dev); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, FLASH_BASE); -} - -static int sl_nand_init(SysBusDevice *dev) -{ - SLNANDState *s = SL_NAND(dev); - DriveInfo *nand; - - s->ctl = 0; - /* FIXME use a qdev drive property instead of drive_get() */ - nand = drive_get(IF_MTD, 0, 0); - s->nand = nand_init(nand ? blk_by_legacy_dinfo(nand) : NULL, - s->manf_id, s->chip_id); - - memory_region_init_io(&s->iomem, OBJECT(s), &sl_ops, s, "sl", 0x40); - sysbus_init_mmio(dev, &s->iomem); - - return 0; -} - -/* Spitz Keyboard */ - -#define SPITZ_KEY_STROBE_NUM 11 -#define SPITZ_KEY_SENSE_NUM 7 - -static const int spitz_gpio_key_sense[SPITZ_KEY_SENSE_NUM] = { - 12, 17, 91, 34, 36, 38, 39 -}; - -static const int spitz_gpio_key_strobe[SPITZ_KEY_STROBE_NUM] = { - 88, 23, 24, 25, 26, 27, 52, 103, 107, 108, 114 -}; - -/* Eighth additional row maps the special keys */ -static int spitz_keymap[SPITZ_KEY_SENSE_NUM + 1][SPITZ_KEY_STROBE_NUM] = { - { 0x1d, 0x02, 0x04, 0x06, 0x07, 0x08, 0x0a, 0x0b, 0x0e, 0x3f, 0x40 }, - { -1 , 0x03, 0x05, 0x13, 0x15, 0x09, 0x17, 0x18, 0x19, 0x41, 0x42 }, - { 0x0f, 0x10, 0x12, 0x14, 0x22, 0x16, 0x24, 0x25, -1 , -1 , -1 }, - { 0x3c, 0x11, 0x1f, 0x21, 0x2f, 0x23, 0x32, 0x26, -1 , 0x36, -1 }, - { 0x3b, 0x1e, 0x20, 0x2e, 0x30, 0x31, 0x34, -1 , 0x1c, 0x2a, -1 }, - { 0x44, 0x2c, 0x2d, 0x0c, 0x39, 0x33, -1 , 0x48, -1 , -1 , 0x38 }, - { 0x37, 0x3d, -1 , 0x45, 0x57, 0x58, 0x4b, 0x50, 0x4d, -1 , -1 }, - { 0x52, 0x43, 0x01, 0x47, 0x49, -1 , -1 , -1 , -1 , -1 , -1 }, -}; - -#define SPITZ_GPIO_AK_INT 13 /* Remote control */ -#define SPITZ_GPIO_SYNC 16 /* Sync button */ -#define SPITZ_GPIO_ON_KEY 95 /* Power button */ -#define SPITZ_GPIO_SWA 97 /* Lid */ -#define SPITZ_GPIO_SWB 96 /* Tablet mode */ - -/* The special buttons are mapped to unused keys */ -static const int spitz_gpiomap[5] = { - SPITZ_GPIO_AK_INT, SPITZ_GPIO_SYNC, SPITZ_GPIO_ON_KEY, - SPITZ_GPIO_SWA, SPITZ_GPIO_SWB, -}; - -#define TYPE_SPITZ_KEYBOARD "spitz-keyboard" -#define SPITZ_KEYBOARD(obj) \ - OBJECT_CHECK(SpitzKeyboardState, (obj), TYPE_SPITZ_KEYBOARD) - -typedef struct { - SysBusDevice parent_obj; - - qemu_irq sense[SPITZ_KEY_SENSE_NUM]; - qemu_irq gpiomap[5]; - int keymap[0x80]; - uint16_t keyrow[SPITZ_KEY_SENSE_NUM]; - uint16_t strobe_state; - uint16_t sense_state; - - uint16_t pre_map[0x100]; - uint16_t modifiers; - uint16_t imodifiers; - uint8_t fifo[16]; - int fifopos, fifolen; - QEMUTimer *kbdtimer; -} SpitzKeyboardState; - -static void spitz_keyboard_sense_update(SpitzKeyboardState *s) -{ - int i; - uint16_t strobe, sense = 0; - for (i = 0; i < SPITZ_KEY_SENSE_NUM; i ++) { - strobe = s->keyrow[i] & s->strobe_state; - if (strobe) { - sense |= 1 << i; - if (!(s->sense_state & (1 << i))) - qemu_irq_raise(s->sense[i]); - } else if (s->sense_state & (1 << i)) - qemu_irq_lower(s->sense[i]); - } - - s->sense_state = sense; -} - -static void spitz_keyboard_strobe(void *opaque, int line, int level) -{ - SpitzKeyboardState *s = (SpitzKeyboardState *) opaque; - - if (level) - s->strobe_state |= 1 << line; - else - s->strobe_state &= ~(1 << line); - spitz_keyboard_sense_update(s); -} - -static void spitz_keyboard_keydown(SpitzKeyboardState *s, int keycode) -{ - int spitz_keycode = s->keymap[keycode & 0x7f]; - if (spitz_keycode == -1) - return; - - /* Handle the additional keys */ - if ((spitz_keycode >> 4) == SPITZ_KEY_SENSE_NUM) { - qemu_set_irq(s->gpiomap[spitz_keycode & 0xf], (keycode < 0x80)); - return; - } - - if (keycode & 0x80) - s->keyrow[spitz_keycode >> 4] &= ~(1 << (spitz_keycode & 0xf)); - else - s->keyrow[spitz_keycode >> 4] |= 1 << (spitz_keycode & 0xf); - - spitz_keyboard_sense_update(s); -} - -#define SPITZ_MOD_SHIFT (1 << 7) -#define SPITZ_MOD_CTRL (1 << 8) -#define SPITZ_MOD_FN (1 << 9) - -#define QUEUE_KEY(c) s->fifo[(s->fifopos + s->fifolen ++) & 0xf] = c - -static void spitz_keyboard_handler(void *opaque, int keycode) -{ - SpitzKeyboardState *s = opaque; - uint16_t code; - int mapcode; - switch (keycode) { - case 0x2a: /* Left Shift */ - s->modifiers |= 1; - break; - case 0xaa: - s->modifiers &= ~1; - break; - case 0x36: /* Right Shift */ - s->modifiers |= 2; - break; - case 0xb6: - s->modifiers &= ~2; - break; - case 0x1d: /* Control */ - s->modifiers |= 4; - break; - case 0x9d: - s->modifiers &= ~4; - break; - case 0x38: /* Alt */ - s->modifiers |= 8; - break; - case 0xb8: - s->modifiers &= ~8; - break; - } - - code = s->pre_map[mapcode = ((s->modifiers & 3) ? - (keycode | SPITZ_MOD_SHIFT) : - (keycode & ~SPITZ_MOD_SHIFT))]; - - if (code != mapcode) { -#if 0 - if ((code & SPITZ_MOD_SHIFT) && !(s->modifiers & 1)) { - QUEUE_KEY(0x2a | (keycode & 0x80)); - } - if ((code & SPITZ_MOD_CTRL) && !(s->modifiers & 4)) { - QUEUE_KEY(0x1d | (keycode & 0x80)); - } - if ((code & SPITZ_MOD_FN) && !(s->modifiers & 8)) { - QUEUE_KEY(0x38 | (keycode & 0x80)); - } - if ((code & SPITZ_MOD_FN) && (s->modifiers & 1)) { - QUEUE_KEY(0x2a | (~keycode & 0x80)); - } - if ((code & SPITZ_MOD_FN) && (s->modifiers & 2)) { - QUEUE_KEY(0x36 | (~keycode & 0x80)); - } -#else - if (keycode & 0x80) { - if ((s->imodifiers & 1 ) && !(s->modifiers & 1)) - QUEUE_KEY(0x2a | 0x80); - if ((s->imodifiers & 4 ) && !(s->modifiers & 4)) - QUEUE_KEY(0x1d | 0x80); - if ((s->imodifiers & 8 ) && !(s->modifiers & 8)) - QUEUE_KEY(0x38 | 0x80); - if ((s->imodifiers & 0x10) && (s->modifiers & 1)) - QUEUE_KEY(0x2a); - if ((s->imodifiers & 0x20) && (s->modifiers & 2)) - QUEUE_KEY(0x36); - s->imodifiers = 0; - } else { - if ((code & SPITZ_MOD_SHIFT) && - !((s->modifiers | s->imodifiers) & 1)) { - QUEUE_KEY(0x2a); - s->imodifiers |= 1; - } - if ((code & SPITZ_MOD_CTRL) && - !((s->modifiers | s->imodifiers) & 4)) { - QUEUE_KEY(0x1d); - s->imodifiers |= 4; - } - if ((code & SPITZ_MOD_FN) && - !((s->modifiers | s->imodifiers) & 8)) { - QUEUE_KEY(0x38); - s->imodifiers |= 8; - } - if ((code & SPITZ_MOD_FN) && (s->modifiers & 1) && - !(s->imodifiers & 0x10)) { - QUEUE_KEY(0x2a | 0x80); - s->imodifiers |= 0x10; - } - if ((code & SPITZ_MOD_FN) && (s->modifiers & 2) && - !(s->imodifiers & 0x20)) { - QUEUE_KEY(0x36 | 0x80); - s->imodifiers |= 0x20; - } - } -#endif - } - - QUEUE_KEY((code & 0x7f) | (keycode & 0x80)); -} - -static void spitz_keyboard_tick(void *opaque) -{ - SpitzKeyboardState *s = (SpitzKeyboardState *) opaque; - - if (s->fifolen) { - spitz_keyboard_keydown(s, s->fifo[s->fifopos ++]); - s->fifolen --; - if (s->fifopos >= 16) - s->fifopos = 0; - } - - timer_mod(s->kbdtimer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + - NANOSECONDS_PER_SECOND / 32); -} - -static void spitz_keyboard_pre_map(SpitzKeyboardState *s) -{ - int i; - for (i = 0; i < 0x100; i ++) - s->pre_map[i] = i; - s->pre_map[0x02 | SPITZ_MOD_SHIFT] = 0x02 | SPITZ_MOD_SHIFT; /* exclam */ - s->pre_map[0x28 | SPITZ_MOD_SHIFT] = 0x03 | SPITZ_MOD_SHIFT; /* quotedbl */ - s->pre_map[0x04 | SPITZ_MOD_SHIFT] = 0x04 | SPITZ_MOD_SHIFT; /* # */ - s->pre_map[0x05 | SPITZ_MOD_SHIFT] = 0x05 | SPITZ_MOD_SHIFT; /* dollar */ - s->pre_map[0x06 | SPITZ_MOD_SHIFT] = 0x06 | SPITZ_MOD_SHIFT; /* percent */ - s->pre_map[0x08 | SPITZ_MOD_SHIFT] = 0x07 | SPITZ_MOD_SHIFT; /* ampersand */ - s->pre_map[0x28] = 0x08 | SPITZ_MOD_SHIFT; /* ' */ - s->pre_map[0x0a | SPITZ_MOD_SHIFT] = 0x09 | SPITZ_MOD_SHIFT; /* ( */ - s->pre_map[0x0b | SPITZ_MOD_SHIFT] = 0x0a | SPITZ_MOD_SHIFT; /* ) */ - s->pre_map[0x29 | SPITZ_MOD_SHIFT] = 0x0b | SPITZ_MOD_SHIFT; /* tilde */ - s->pre_map[0x03 | SPITZ_MOD_SHIFT] = 0x0c | SPITZ_MOD_SHIFT; /* at */ - s->pre_map[0xd3] = 0x0e | SPITZ_MOD_FN; /* Delete */ - s->pre_map[0x3a] = 0x0f | SPITZ_MOD_FN; /* Caps_Lock */ - s->pre_map[0x07 | SPITZ_MOD_SHIFT] = 0x11 | SPITZ_MOD_FN; /* ^ */ - s->pre_map[0x0d] = 0x12 | SPITZ_MOD_FN; /* equal */ - s->pre_map[0x0d | SPITZ_MOD_SHIFT] = 0x13 | SPITZ_MOD_FN; /* plus */ - s->pre_map[0x1a] = 0x14 | SPITZ_MOD_FN; /* [ */ - s->pre_map[0x1b] = 0x15 | SPITZ_MOD_FN; /* ] */ - s->pre_map[0x1a | SPITZ_MOD_SHIFT] = 0x16 | SPITZ_MOD_FN; /* { */ - s->pre_map[0x1b | SPITZ_MOD_SHIFT] = 0x17 | SPITZ_MOD_FN; /* } */ - s->pre_map[0x27] = 0x22 | SPITZ_MOD_FN; /* semicolon */ - s->pre_map[0x27 | SPITZ_MOD_SHIFT] = 0x23 | SPITZ_MOD_FN; /* colon */ - s->pre_map[0x09 | SPITZ_MOD_SHIFT] = 0x24 | SPITZ_MOD_FN; /* asterisk */ - s->pre_map[0x2b] = 0x25 | SPITZ_MOD_FN; /* backslash */ - s->pre_map[0x2b | SPITZ_MOD_SHIFT] = 0x26 | SPITZ_MOD_FN; /* bar */ - s->pre_map[0x0c | SPITZ_MOD_SHIFT] = 0x30 | SPITZ_MOD_FN; /* _ */ - s->pre_map[0x33 | SPITZ_MOD_SHIFT] = 0x33 | SPITZ_MOD_FN; /* less */ - s->pre_map[0x35] = 0x33 | SPITZ_MOD_SHIFT; /* slash */ - s->pre_map[0x34 | SPITZ_MOD_SHIFT] = 0x34 | SPITZ_MOD_FN; /* greater */ - s->pre_map[0x35 | SPITZ_MOD_SHIFT] = 0x34 | SPITZ_MOD_SHIFT; /* question */ - s->pre_map[0x49] = 0x48 | SPITZ_MOD_FN; /* Page_Up */ - s->pre_map[0x51] = 0x50 | SPITZ_MOD_FN; /* Page_Down */ - - s->modifiers = 0; - s->imodifiers = 0; - s->fifopos = 0; - s->fifolen = 0; -} - -#undef SPITZ_MOD_SHIFT -#undef SPITZ_MOD_CTRL -#undef SPITZ_MOD_FN - -static int spitz_keyboard_post_load(void *opaque, int version_id) -{ - SpitzKeyboardState *s = (SpitzKeyboardState *) opaque; - - /* Release all pressed keys */ - memset(s->keyrow, 0, sizeof(s->keyrow)); - spitz_keyboard_sense_update(s); - s->modifiers = 0; - s->imodifiers = 0; - s->fifopos = 0; - s->fifolen = 0; - - return 0; -} - -static void spitz_keyboard_register(PXA2xxState *cpu) -{ - int i; - DeviceState *dev; - SpitzKeyboardState *s; - - dev = sysbus_create_simple(TYPE_SPITZ_KEYBOARD, -1, NULL); - s = SPITZ_KEYBOARD(dev); - - for (i = 0; i < SPITZ_KEY_SENSE_NUM; i ++) - qdev_connect_gpio_out(dev, i, qdev_get_gpio_in(cpu->gpio, spitz_gpio_key_sense[i])); - - for (i = 0; i < 5; i ++) - s->gpiomap[i] = qdev_get_gpio_in(cpu->gpio, spitz_gpiomap[i]); - - if (!graphic_rotate) - s->gpiomap[4] = qemu_irq_invert(s->gpiomap[4]); - - for (i = 0; i < 5; i++) - qemu_set_irq(s->gpiomap[i], 0); - - for (i = 0; i < SPITZ_KEY_STROBE_NUM; i ++) - qdev_connect_gpio_out(cpu->gpio, spitz_gpio_key_strobe[i], - qdev_get_gpio_in(dev, i)); - - timer_mod(s->kbdtimer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); - - qemu_add_kbd_event_handler(spitz_keyboard_handler, s); -} - -static int spitz_keyboard_init(SysBusDevice *sbd) -{ - DeviceState *dev = DEVICE(sbd); - SpitzKeyboardState *s = SPITZ_KEYBOARD(dev); - int i, j; - - for (i = 0; i < 0x80; i ++) - s->keymap[i] = -1; - for (i = 0; i < SPITZ_KEY_SENSE_NUM + 1; i ++) - for (j = 0; j < SPITZ_KEY_STROBE_NUM; j ++) - if (spitz_keymap[i][j] != -1) - s->keymap[spitz_keymap[i][j]] = (i << 4) | j; - - spitz_keyboard_pre_map(s); - - s->kbdtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, spitz_keyboard_tick, s); - qdev_init_gpio_in(dev, spitz_keyboard_strobe, SPITZ_KEY_STROBE_NUM); - qdev_init_gpio_out(dev, s->sense, SPITZ_KEY_SENSE_NUM); - - return 0; -} - -/* LCD backlight controller */ - -#define LCDTG_RESCTL 0x00 -#define LCDTG_PHACTRL 0x01 -#define LCDTG_DUTYCTRL 0x02 -#define LCDTG_POWERREG0 0x03 -#define LCDTG_POWERREG1 0x04 -#define LCDTG_GPOR3 0x05 -#define LCDTG_PICTRL 0x06 -#define LCDTG_POLCTRL 0x07 - -typedef struct { - SSISlave ssidev; - uint32_t bl_intensity; - uint32_t bl_power; -} SpitzLCDTG; - -static void spitz_bl_update(SpitzLCDTG *s) -{ - if (s->bl_power && s->bl_intensity) - zaurus_printf("LCD Backlight now at %i/63\n", s->bl_intensity); - else - zaurus_printf("LCD Backlight now off\n"); -} - -/* FIXME: Implement GPIO properly and remove this hack. */ -static SpitzLCDTG *spitz_lcdtg; - -static inline void spitz_bl_bit5(void *opaque, int line, int level) -{ - SpitzLCDTG *s = spitz_lcdtg; - int prev = s->bl_intensity; - - if (level) - s->bl_intensity &= ~0x20; - else - s->bl_intensity |= 0x20; - - if (s->bl_power && prev != s->bl_intensity) - spitz_bl_update(s); -} - -static inline void spitz_bl_power(void *opaque, int line, int level) -{ - SpitzLCDTG *s = spitz_lcdtg; - s->bl_power = !!level; - spitz_bl_update(s); -} - -static uint32_t spitz_lcdtg_transfer(SSISlave *dev, uint32_t value) -{ - SpitzLCDTG *s = FROM_SSI_SLAVE(SpitzLCDTG, dev); - int addr; - addr = value >> 5; - value &= 0x1f; - - switch (addr) { - case LCDTG_RESCTL: - if (value) - zaurus_printf("LCD in QVGA mode\n"); - else - zaurus_printf("LCD in VGA mode\n"); - break; - - case LCDTG_DUTYCTRL: - s->bl_intensity &= ~0x1f; - s->bl_intensity |= value; - if (s->bl_power) - spitz_bl_update(s); - break; - - case LCDTG_POWERREG0: - /* Set common voltage to M62332FP */ - break; - } - return 0; -} - -static int spitz_lcdtg_init(SSISlave *dev) -{ - SpitzLCDTG *s = FROM_SSI_SLAVE(SpitzLCDTG, dev); - - spitz_lcdtg = s; - s->bl_power = 0; - s->bl_intensity = 0x20; - - return 0; -} - -/* SSP devices */ - -#define CORGI_SSP_PORT 2 - -#define SPITZ_GPIO_LCDCON_CS 53 -#define SPITZ_GPIO_ADS7846_CS 14 -#define SPITZ_GPIO_MAX1111_CS 20 -#define SPITZ_GPIO_TP_INT 11 - -static DeviceState *max1111; - -/* "Demux" the signal based on current chipselect */ -typedef struct { - SSISlave ssidev; - SSIBus *bus[3]; - uint32_t enable[3]; -} CorgiSSPState; - -static uint32_t corgi_ssp_transfer(SSISlave *dev, uint32_t value) -{ - CorgiSSPState *s = FROM_SSI_SLAVE(CorgiSSPState, dev); - int i; - - for (i = 0; i < 3; i++) { - if (s->enable[i]) { - return ssi_transfer(s->bus[i], value); - } - } - return 0; -} - -static void corgi_ssp_gpio_cs(void *opaque, int line, int level) -{ - CorgiSSPState *s = (CorgiSSPState *)opaque; - assert(line >= 0 && line < 3); - s->enable[line] = !level; -} - -#define MAX1111_BATT_VOLT 1 -#define MAX1111_BATT_TEMP 2 -#define MAX1111_ACIN_VOLT 3 - -#define SPITZ_BATTERY_TEMP 0xe0 /* About 2.9V */ -#define SPITZ_BATTERY_VOLT 0xd0 /* About 4.0V */ -#define SPITZ_CHARGEON_ACIN 0x80 /* About 5.0V */ - -static void spitz_adc_temp_on(void *opaque, int line, int level) -{ - if (!max1111) - return; - - if (level) - max111x_set_input(max1111, MAX1111_BATT_TEMP, SPITZ_BATTERY_TEMP); - else - max111x_set_input(max1111, MAX1111_BATT_TEMP, 0); -} - -static int corgi_ssp_init(SSISlave *d) -{ - DeviceState *dev = DEVICE(d); - CorgiSSPState *s = FROM_SSI_SLAVE(CorgiSSPState, d); - - qdev_init_gpio_in(dev, corgi_ssp_gpio_cs, 3); - s->bus[0] = ssi_create_bus(dev, "ssi0"); - s->bus[1] = ssi_create_bus(dev, "ssi1"); - s->bus[2] = ssi_create_bus(dev, "ssi2"); - - return 0; -} - -static void spitz_ssp_attach(PXA2xxState *cpu) -{ - DeviceState *mux; - DeviceState *dev; - void *bus; - - mux = ssi_create_slave(cpu->ssp[CORGI_SSP_PORT - 1], "corgi-ssp"); - - bus = qdev_get_child_bus(mux, "ssi0"); - ssi_create_slave(bus, "spitz-lcdtg"); - - bus = qdev_get_child_bus(mux, "ssi1"); - dev = ssi_create_slave(bus, "ads7846"); - qdev_connect_gpio_out(dev, 0, - qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_TP_INT)); - - bus = qdev_get_child_bus(mux, "ssi2"); - max1111 = ssi_create_slave(bus, "max1111"); - max111x_set_input(max1111, MAX1111_BATT_VOLT, SPITZ_BATTERY_VOLT); - max111x_set_input(max1111, MAX1111_BATT_TEMP, 0); - max111x_set_input(max1111, MAX1111_ACIN_VOLT, SPITZ_CHARGEON_ACIN); - - qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_LCDCON_CS, - qdev_get_gpio_in(mux, 0)); - qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_ADS7846_CS, - qdev_get_gpio_in(mux, 1)); - qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_MAX1111_CS, - qdev_get_gpio_in(mux, 2)); -} - -/* CF Microdrive */ - -static void spitz_microdrive_attach(PXA2xxState *cpu, int slot) -{ - PCMCIACardState *md; - DriveInfo *dinfo; - - dinfo = drive_get(IF_IDE, 0, 0); - if (!dinfo || dinfo->media_cd) - return; - md = dscm1xxxx_init(dinfo); - pxa2xx_pcmcia_attach(cpu->pcmcia[slot], md); -} - -/* Wm8750 and Max7310 on I2C */ - -#define AKITA_MAX_ADDR 0x18 -#define SPITZ_WM_ADDRL 0x1b -#define SPITZ_WM_ADDRH 0x1a - -#define SPITZ_GPIO_WM 5 - -static void spitz_wm8750_addr(void *opaque, int line, int level) -{ - I2CSlave *wm = (I2CSlave *) opaque; - if (level) - i2c_set_slave_address(wm, SPITZ_WM_ADDRH); - else - i2c_set_slave_address(wm, SPITZ_WM_ADDRL); -} - -static void spitz_i2c_setup(PXA2xxState *cpu) -{ - /* Attach the CPU on one end of our I2C bus. */ - I2CBus *bus = pxa2xx_i2c_bus(cpu->i2c[0]); - - DeviceState *wm; - - /* Attach a WM8750 to the bus */ - wm = i2c_create_slave(bus, "wm8750", 0); - - spitz_wm8750_addr(wm, 0, 0); - qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_WM, - qemu_allocate_irq(spitz_wm8750_addr, wm, 0)); - /* .. and to the sound interface. */ - cpu->i2s->opaque = wm; - cpu->i2s->codec_out = wm8750_dac_dat; - cpu->i2s->codec_in = wm8750_adc_dat; - wm8750_data_req_set(wm, cpu->i2s->data_req, cpu->i2s); -} - -static void spitz_akita_i2c_setup(PXA2xxState *cpu) -{ - /* Attach a Max7310 to Akita I2C bus. */ - i2c_create_slave(pxa2xx_i2c_bus(cpu->i2c[0]), "max7310", - AKITA_MAX_ADDR); -} - -/* Other peripherals */ - -static void spitz_out_switch(void *opaque, int line, int level) -{ - switch (line) { - case 0: - zaurus_printf("Charging %s.\n", level ? "off" : "on"); - break; - case 1: - zaurus_printf("Discharging %s.\n", level ? "on" : "off"); - break; - case 2: - zaurus_printf("Green LED %s.\n", level ? "on" : "off"); - break; - case 3: - zaurus_printf("Orange LED %s.\n", level ? "on" : "off"); - break; - case 4: - spitz_bl_bit5(opaque, line, level); - break; - case 5: - spitz_bl_power(opaque, line, level); - break; - case 6: - spitz_adc_temp_on(opaque, line, level); - break; - } -} - -#define SPITZ_SCP_LED_GREEN 1 -#define SPITZ_SCP_JK_B 2 -#define SPITZ_SCP_CHRG_ON 3 -#define SPITZ_SCP_MUTE_L 4 -#define SPITZ_SCP_MUTE_R 5 -#define SPITZ_SCP_CF_POWER 6 -#define SPITZ_SCP_LED_ORANGE 7 -#define SPITZ_SCP_JK_A 8 -#define SPITZ_SCP_ADC_TEMP_ON 9 -#define SPITZ_SCP2_IR_ON 1 -#define SPITZ_SCP2_AKIN_PULLUP 2 -#define SPITZ_SCP2_BACKLIGHT_CONT 7 -#define SPITZ_SCP2_BACKLIGHT_ON 8 -#define SPITZ_SCP2_MIC_BIAS 9 - -static void spitz_scoop_gpio_setup(PXA2xxState *cpu, - DeviceState *scp0, DeviceState *scp1) -{ - qemu_irq *outsignals = qemu_allocate_irqs(spitz_out_switch, cpu, 8); - - qdev_connect_gpio_out(scp0, SPITZ_SCP_CHRG_ON, outsignals[0]); - qdev_connect_gpio_out(scp0, SPITZ_SCP_JK_B, outsignals[1]); - qdev_connect_gpio_out(scp0, SPITZ_SCP_LED_GREEN, outsignals[2]); - qdev_connect_gpio_out(scp0, SPITZ_SCP_LED_ORANGE, outsignals[3]); - - if (scp1) { - qdev_connect_gpio_out(scp1, SPITZ_SCP2_BACKLIGHT_CONT, outsignals[4]); - qdev_connect_gpio_out(scp1, SPITZ_SCP2_BACKLIGHT_ON, outsignals[5]); - } - - qdev_connect_gpio_out(scp0, SPITZ_SCP_ADC_TEMP_ON, outsignals[6]); -} - -#define SPITZ_GPIO_HSYNC 22 -#define SPITZ_GPIO_SD_DETECT 9 -#define SPITZ_GPIO_SD_WP 81 -#define SPITZ_GPIO_ON_RESET 89 -#define SPITZ_GPIO_BAT_COVER 90 -#define SPITZ_GPIO_CF1_IRQ 105 -#define SPITZ_GPIO_CF1_CD 94 -#define SPITZ_GPIO_CF2_IRQ 106 -#define SPITZ_GPIO_CF2_CD 93 - -static int spitz_hsync; - -static void spitz_lcd_hsync_handler(void *opaque, int line, int level) -{ - PXA2xxState *cpu = (PXA2xxState *) opaque; - qemu_set_irq(qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_HSYNC), spitz_hsync); - spitz_hsync ^= 1; -} - -static void spitz_gpio_setup(PXA2xxState *cpu, int slots) -{ - qemu_irq lcd_hsync; - /* - * Bad hack: We toggle the LCD hsync GPIO on every GPIO status - * read to satisfy broken guests that poll-wait for hsync. - * Simulating a real hsync event would be less practical and - * wouldn't guarantee that a guest ever exits the loop. - */ - spitz_hsync = 0; - lcd_hsync = qemu_allocate_irq(spitz_lcd_hsync_handler, cpu, 0); - pxa2xx_gpio_read_notifier(cpu->gpio, lcd_hsync); - pxa2xx_lcd_vsync_notifier(cpu->lcd, lcd_hsync); - - /* MMC/SD host */ - pxa2xx_mmci_handlers(cpu->mmc, - qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_SD_WP), - qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_SD_DETECT)); - - /* Battery lock always closed */ - qemu_irq_raise(qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_BAT_COVER)); - - /* Handle reset */ - qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_ON_RESET, cpu->reset); - - /* PCMCIA signals: card's IRQ and Card-Detect */ - if (slots >= 1) - pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[0], - qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_CF1_IRQ), - qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_CF1_CD)); - if (slots >= 2) - pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[1], - qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_CF2_IRQ), - qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_CF2_CD)); -} - -/* Board init. */ -enum spitz_model_e { spitz, akita, borzoi, terrier }; - -#define SPITZ_RAM 0x04000000 -#define SPITZ_ROM 0x00800000 - -static struct arm_boot_info spitz_binfo = { - .loader_start = PXA2XX_SDRAM_BASE, - .ram_size = 0x04000000, -}; - -static void spitz_common_init(MachineState *machine, - enum spitz_model_e model, int arm_id) -{ - PXA2xxState *mpu; - DeviceState *scp0, *scp1 = NULL; - MemoryRegion *address_space_mem = get_system_memory(); - MemoryRegion *rom = g_new(MemoryRegion, 1); - const char *cpu_model = machine->cpu_model; - - if (!cpu_model) - cpu_model = (model == terrier) ? "pxa270-c5" : "pxa270-c0"; - - /* Setup CPU & memory */ - mpu = pxa270_init(address_space_mem, spitz_binfo.ram_size, cpu_model); - - sl_flash_register(mpu, (model == spitz) ? FLASH_128M : FLASH_1024M); - - memory_region_init_ram(rom, NULL, "spitz.rom", SPITZ_ROM, &error_fatal); - vmstate_register_ram_global(rom); - memory_region_set_readonly(rom, true); - memory_region_add_subregion(address_space_mem, 0, rom); - - /* Setup peripherals */ - spitz_keyboard_register(mpu); - - spitz_ssp_attach(mpu); - - scp0 = sysbus_create_simple("scoop", 0x10800000, NULL); - if (model != akita) { - scp1 = sysbus_create_simple("scoop", 0x08800040, NULL); - } - - spitz_scoop_gpio_setup(mpu, scp0, scp1); - - spitz_gpio_setup(mpu, (model == akita) ? 1 : 2); - - spitz_i2c_setup(mpu); - - if (model == akita) - spitz_akita_i2c_setup(mpu); - - if (model == terrier) - /* A 6.0 GB microdrive is permanently sitting in CF slot 1. */ - spitz_microdrive_attach(mpu, 1); - else if (model != akita) - /* A 4.0 GB microdrive is permanently sitting in CF slot 0. */ - spitz_microdrive_attach(mpu, 0); - - spitz_binfo.kernel_filename = machine->kernel_filename; - spitz_binfo.kernel_cmdline = machine->kernel_cmdline; - spitz_binfo.initrd_filename = machine->initrd_filename; - spitz_binfo.board_id = arm_id; - arm_load_kernel(mpu->cpu, &spitz_binfo); - sl_bootparam_write(SL_PXA_PARAM_BASE); -} - -static void spitz_init(MachineState *machine) -{ - spitz_common_init(machine, spitz, 0x2c9); -} - -static void borzoi_init(MachineState *machine) -{ - spitz_common_init(machine, borzoi, 0x33f); -} - -static void akita_init(MachineState *machine) -{ - spitz_common_init(machine, akita, 0x2e8); -} - -static void terrier_init(MachineState *machine) -{ - spitz_common_init(machine, terrier, 0x33f); -} - -static void akitapda_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "Sharp SL-C1000 (Akita) PDA (PXA270)"; - mc->init = akita_init; -} - -static const TypeInfo akitapda_type = { - .name = MACHINE_TYPE_NAME("akita"), - .parent = TYPE_MACHINE, - .class_init = akitapda_class_init, -}; - -static void spitzpda_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "Sharp SL-C3000 (Spitz) PDA (PXA270)"; - mc->init = spitz_init; -} - -static const TypeInfo spitzpda_type = { - .name = MACHINE_TYPE_NAME("spitz"), - .parent = TYPE_MACHINE, - .class_init = spitzpda_class_init, -}; - -static void borzoipda_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "Sharp SL-C3100 (Borzoi) PDA (PXA270)"; - mc->init = borzoi_init; -} - -static const TypeInfo borzoipda_type = { - .name = MACHINE_TYPE_NAME("borzoi"), - .parent = TYPE_MACHINE, - .class_init = borzoipda_class_init, -}; - -static void terrierpda_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "Sharp SL-C3200 (Terrier) PDA (PXA270)"; - mc->init = terrier_init; -} - -static const TypeInfo terrierpda_type = { - .name = MACHINE_TYPE_NAME("terrier"), - .parent = TYPE_MACHINE, - .class_init = terrierpda_class_init, -}; - -static void spitz_machine_init(void) -{ - type_register_static(&akitapda_type); - type_register_static(&spitzpda_type); - type_register_static(&borzoipda_type); - type_register_static(&terrierpda_type); -} - -type_init(spitz_machine_init) - -static bool is_version_0(void *opaque, int version_id) -{ - return version_id == 0; -} - -static VMStateDescription vmstate_sl_nand_info = { - .name = "sl-nand", - .version_id = 0, - .minimum_version_id = 0, - .fields = (VMStateField[]) { - VMSTATE_UINT8(ctl, SLNANDState), - VMSTATE_STRUCT(ecc, SLNANDState, 0, vmstate_ecc_state, ECCState), - VMSTATE_END_OF_LIST(), - }, -}; - -static Property sl_nand_properties[] = { - DEFINE_PROP_UINT8("manf_id", SLNANDState, manf_id, NAND_MFR_SAMSUNG), - DEFINE_PROP_UINT8("chip_id", SLNANDState, chip_id, 0xf1), - DEFINE_PROP_END_OF_LIST(), -}; - -static void sl_nand_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = sl_nand_init; - dc->vmsd = &vmstate_sl_nand_info; - dc->props = sl_nand_properties; - /* Reason: init() method uses drive_get() */ - dc->cannot_instantiate_with_device_add_yet = true; -} - -static const TypeInfo sl_nand_info = { - .name = TYPE_SL_NAND, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(SLNANDState), - .class_init = sl_nand_class_init, -}; - -static VMStateDescription vmstate_spitz_kbd = { - .name = "spitz-keyboard", - .version_id = 1, - .minimum_version_id = 0, - .post_load = spitz_keyboard_post_load, - .fields = (VMStateField[]) { - VMSTATE_UINT16(sense_state, SpitzKeyboardState), - VMSTATE_UINT16(strobe_state, SpitzKeyboardState), - VMSTATE_UNUSED_TEST(is_version_0, 5), - VMSTATE_END_OF_LIST(), - }, -}; - -static void spitz_keyboard_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = spitz_keyboard_init; - dc->vmsd = &vmstate_spitz_kbd; -} - -static const TypeInfo spitz_keyboard_info = { - .name = TYPE_SPITZ_KEYBOARD, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(SpitzKeyboardState), - .class_init = spitz_keyboard_class_init, -}; - -static const VMStateDescription vmstate_corgi_ssp_regs = { - .name = "corgi-ssp", - .version_id = 2, - .minimum_version_id = 2, - .fields = (VMStateField[]) { - VMSTATE_SSI_SLAVE(ssidev, CorgiSSPState), - VMSTATE_UINT32_ARRAY(enable, CorgiSSPState, 3), - VMSTATE_END_OF_LIST(), - } -}; - -static void corgi_ssp_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SSISlaveClass *k = SSI_SLAVE_CLASS(klass); - - k->init = corgi_ssp_init; - k->transfer = corgi_ssp_transfer; - dc->vmsd = &vmstate_corgi_ssp_regs; -} - -static const TypeInfo corgi_ssp_info = { - .name = "corgi-ssp", - .parent = TYPE_SSI_SLAVE, - .instance_size = sizeof(CorgiSSPState), - .class_init = corgi_ssp_class_init, -}; - -static const VMStateDescription vmstate_spitz_lcdtg_regs = { - .name = "spitz-lcdtg", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_SSI_SLAVE(ssidev, SpitzLCDTG), - VMSTATE_UINT32(bl_intensity, SpitzLCDTG), - VMSTATE_UINT32(bl_power, SpitzLCDTG), - VMSTATE_END_OF_LIST(), - } -}; - -static void spitz_lcdtg_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SSISlaveClass *k = SSI_SLAVE_CLASS(klass); - - k->init = spitz_lcdtg_init; - k->transfer = spitz_lcdtg_transfer; - dc->vmsd = &vmstate_spitz_lcdtg_regs; -} - -static const TypeInfo spitz_lcdtg_info = { - .name = "spitz-lcdtg", - .parent = TYPE_SSI_SLAVE, - .instance_size = sizeof(SpitzLCDTG), - .class_init = spitz_lcdtg_class_init, -}; - -static void spitz_register_types(void) -{ - type_register_static(&corgi_ssp_info); - type_register_static(&spitz_lcdtg_info); - type_register_static(&spitz_keyboard_info); - type_register_static(&sl_nand_info); -} - -type_init(spitz_register_types) diff --git a/qemu/hw/arm/stellaris.c b/qemu/hw/arm/stellaris.c deleted file mode 100644 index c1766f856..000000000 --- a/qemu/hw/arm/stellaris.c +++ /dev/null @@ -1,1475 +0,0 @@ -/* - * Luminary Micro Stellaris peripherals - * - * Copyright (c) 2006 CodeSourcery. - * Written by Paul Brook - * - * This code is licensed under the GPL. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "hw/sysbus.h" -#include "hw/ssi/ssi.h" -#include "hw/arm/arm.h" -#include "hw/devices.h" -#include "qemu/timer.h" -#include "hw/i2c/i2c.h" -#include "net/net.h" -#include "hw/boards.h" -#include "exec/address-spaces.h" -#include "sysemu/sysemu.h" - -#define GPIO_A 0 -#define GPIO_B 1 -#define GPIO_C 2 -#define GPIO_D 3 -#define GPIO_E 4 -#define GPIO_F 5 -#define GPIO_G 6 - -#define BP_OLED_I2C 0x01 -#define BP_OLED_SSI 0x02 -#define BP_GAMEPAD 0x04 - -#define NUM_IRQ_LINES 64 - -typedef const struct { - const char *name; - uint32_t did0; - uint32_t did1; - uint32_t dc0; - uint32_t dc1; - uint32_t dc2; - uint32_t dc3; - uint32_t dc4; - uint32_t peripherals; -} stellaris_board_info; - -/* General purpose timer module. */ - -#define TYPE_STELLARIS_GPTM "stellaris-gptm" -#define STELLARIS_GPTM(obj) \ - OBJECT_CHECK(gptm_state, (obj), TYPE_STELLARIS_GPTM) - -typedef struct gptm_state { - SysBusDevice parent_obj; - - MemoryRegion iomem; - uint32_t config; - uint32_t mode[2]; - uint32_t control; - uint32_t state; - uint32_t mask; - uint32_t load[2]; - uint32_t match[2]; - uint32_t prescale[2]; - uint32_t match_prescale[2]; - uint32_t rtc; - int64_t tick[2]; - struct gptm_state *opaque[2]; - QEMUTimer *timer[2]; - /* The timers have an alternate output used to trigger the ADC. */ - qemu_irq trigger; - qemu_irq irq; -} gptm_state; - -static void gptm_update_irq(gptm_state *s) -{ - int level; - level = (s->state & s->mask) != 0; - qemu_set_irq(s->irq, level); -} - -static void gptm_stop(gptm_state *s, int n) -{ - timer_del(s->timer[n]); -} - -static void gptm_reload(gptm_state *s, int n, int reset) -{ - int64_t tick; - if (reset) - tick = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - else - tick = s->tick[n]; - - if (s->config == 0) { - /* 32-bit CountDown. */ - uint32_t count; - count = s->load[0] | (s->load[1] << 16); - tick += (int64_t)count * system_clock_scale; - } else if (s->config == 1) { - /* 32-bit RTC. 1Hz tick. */ - tick += NANOSECONDS_PER_SECOND; - } else if (s->mode[n] == 0xa) { - /* PWM mode. Not implemented. */ - } else { - hw_error("TODO: 16-bit timer mode 0x%x\n", s->mode[n]); - } - s->tick[n] = tick; - timer_mod(s->timer[n], tick); -} - -static void gptm_tick(void *opaque) -{ - gptm_state **p = (gptm_state **)opaque; - gptm_state *s; - int n; - - s = *p; - n = p - s->opaque; - if (s->config == 0) { - s->state |= 1; - if ((s->control & 0x20)) { - /* Output trigger. */ - qemu_irq_pulse(s->trigger); - } - if (s->mode[0] & 1) { - /* One-shot. */ - s->control &= ~1; - } else { - /* Periodic. */ - gptm_reload(s, 0, 0); - } - } else if (s->config == 1) { - /* RTC. */ - uint32_t match; - s->rtc++; - match = s->match[0] | (s->match[1] << 16); - if (s->rtc > match) - s->rtc = 0; - if (s->rtc == 0) { - s->state |= 8; - } - gptm_reload(s, 0, 0); - } else if (s->mode[n] == 0xa) { - /* PWM mode. Not implemented. */ - } else { - hw_error("TODO: 16-bit timer mode 0x%x\n", s->mode[n]); - } - gptm_update_irq(s); -} - -static uint64_t gptm_read(void *opaque, hwaddr offset, - unsigned size) -{ - gptm_state *s = (gptm_state *)opaque; - - switch (offset) { - case 0x00: /* CFG */ - return s->config; - case 0x04: /* TAMR */ - return s->mode[0]; - case 0x08: /* TBMR */ - return s->mode[1]; - case 0x0c: /* CTL */ - return s->control; - case 0x18: /* IMR */ - return s->mask; - case 0x1c: /* RIS */ - return s->state; - case 0x20: /* MIS */ - return s->state & s->mask; - case 0x24: /* CR */ - return 0; - case 0x28: /* TAILR */ - return s->load[0] | ((s->config < 4) ? (s->load[1] << 16) : 0); - case 0x2c: /* TBILR */ - return s->load[1]; - case 0x30: /* TAMARCHR */ - return s->match[0] | ((s->config < 4) ? (s->match[1] << 16) : 0); - case 0x34: /* TBMATCHR */ - return s->match[1]; - case 0x38: /* TAPR */ - return s->prescale[0]; - case 0x3c: /* TBPR */ - return s->prescale[1]; - case 0x40: /* TAPMR */ - return s->match_prescale[0]; - case 0x44: /* TBPMR */ - return s->match_prescale[1]; - case 0x48: /* TAR */ - if (s->config == 1) { - return s->rtc; - } - qemu_log_mask(LOG_UNIMP, - "GPTM: read of TAR but timer read not supported"); - return 0; - case 0x4c: /* TBR */ - qemu_log_mask(LOG_UNIMP, - "GPTM: read of TBR but timer read not supported"); - return 0; - default: - qemu_log_mask(LOG_GUEST_ERROR, - "GPTM: read at bad offset 0x%x\n", (int)offset); - return 0; - } -} - -static void gptm_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - gptm_state *s = (gptm_state *)opaque; - uint32_t oldval; - - /* The timers should be disabled before changing the configuration. - We take advantage of this and defer everything until the timer - is enabled. */ - switch (offset) { - case 0x00: /* CFG */ - s->config = value; - break; - case 0x04: /* TAMR */ - s->mode[0] = value; - break; - case 0x08: /* TBMR */ - s->mode[1] = value; - break; - case 0x0c: /* CTL */ - oldval = s->control; - s->control = value; - /* TODO: Implement pause. */ - if ((oldval ^ value) & 1) { - if (value & 1) { - gptm_reload(s, 0, 1); - } else { - gptm_stop(s, 0); - } - } - if (((oldval ^ value) & 0x100) && s->config >= 4) { - if (value & 0x100) { - gptm_reload(s, 1, 1); - } else { - gptm_stop(s, 1); - } - } - break; - case 0x18: /* IMR */ - s->mask = value & 0x77; - gptm_update_irq(s); - break; - case 0x24: /* CR */ - s->state &= ~value; - break; - case 0x28: /* TAILR */ - s->load[0] = value & 0xffff; - if (s->config < 4) { - s->load[1] = value >> 16; - } - break; - case 0x2c: /* TBILR */ - s->load[1] = value & 0xffff; - break; - case 0x30: /* TAMARCHR */ - s->match[0] = value & 0xffff; - if (s->config < 4) { - s->match[1] = value >> 16; - } - break; - case 0x34: /* TBMATCHR */ - s->match[1] = value >> 16; - break; - case 0x38: /* TAPR */ - s->prescale[0] = value; - break; - case 0x3c: /* TBPR */ - s->prescale[1] = value; - break; - case 0x40: /* TAPMR */ - s->match_prescale[0] = value; - break; - case 0x44: /* TBPMR */ - s->match_prescale[0] = value; - break; - default: - hw_error("gptm_write: Bad offset 0x%x\n", (int)offset); - } - gptm_update_irq(s); -} - -static const MemoryRegionOps gptm_ops = { - .read = gptm_read, - .write = gptm_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static const VMStateDescription vmstate_stellaris_gptm = { - .name = "stellaris_gptm", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(config, gptm_state), - VMSTATE_UINT32_ARRAY(mode, gptm_state, 2), - VMSTATE_UINT32(control, gptm_state), - VMSTATE_UINT32(state, gptm_state), - VMSTATE_UINT32(mask, gptm_state), - VMSTATE_UNUSED(8), - VMSTATE_UINT32_ARRAY(load, gptm_state, 2), - VMSTATE_UINT32_ARRAY(match, gptm_state, 2), - VMSTATE_UINT32_ARRAY(prescale, gptm_state, 2), - VMSTATE_UINT32_ARRAY(match_prescale, gptm_state, 2), - VMSTATE_UINT32(rtc, gptm_state), - VMSTATE_INT64_ARRAY(tick, gptm_state, 2), - VMSTATE_TIMER_PTR_ARRAY(timer, gptm_state, 2), - VMSTATE_END_OF_LIST() - } -}; - -static int stellaris_gptm_init(SysBusDevice *sbd) -{ - DeviceState *dev = DEVICE(sbd); - gptm_state *s = STELLARIS_GPTM(dev); - - sysbus_init_irq(sbd, &s->irq); - qdev_init_gpio_out(dev, &s->trigger, 1); - - memory_region_init_io(&s->iomem, OBJECT(s), &gptm_ops, s, - "gptm", 0x1000); - sysbus_init_mmio(sbd, &s->iomem); - - s->opaque[0] = s->opaque[1] = s; - s->timer[0] = timer_new_ns(QEMU_CLOCK_VIRTUAL, gptm_tick, &s->opaque[0]); - s->timer[1] = timer_new_ns(QEMU_CLOCK_VIRTUAL, gptm_tick, &s->opaque[1]); - vmstate_register(dev, -1, &vmstate_stellaris_gptm, s); - return 0; -} - - -/* System controller. */ - -typedef struct { - MemoryRegion iomem; - uint32_t pborctl; - uint32_t ldopctl; - uint32_t int_status; - uint32_t int_mask; - uint32_t resc; - uint32_t rcc; - uint32_t rcc2; - uint32_t rcgc[3]; - uint32_t scgc[3]; - uint32_t dcgc[3]; - uint32_t clkvclr; - uint32_t ldoarst; - uint32_t user0; - uint32_t user1; - qemu_irq irq; - stellaris_board_info *board; -} ssys_state; - -static void ssys_update(ssys_state *s) -{ - qemu_set_irq(s->irq, (s->int_status & s->int_mask) != 0); -} - -static uint32_t pllcfg_sandstorm[16] = { - 0x31c0, /* 1 Mhz */ - 0x1ae0, /* 1.8432 Mhz */ - 0x18c0, /* 2 Mhz */ - 0xd573, /* 2.4576 Mhz */ - 0x37a6, /* 3.57954 Mhz */ - 0x1ae2, /* 3.6864 Mhz */ - 0x0c40, /* 4 Mhz */ - 0x98bc, /* 4.906 Mhz */ - 0x935b, /* 4.9152 Mhz */ - 0x09c0, /* 5 Mhz */ - 0x4dee, /* 5.12 Mhz */ - 0x0c41, /* 6 Mhz */ - 0x75db, /* 6.144 Mhz */ - 0x1ae6, /* 7.3728 Mhz */ - 0x0600, /* 8 Mhz */ - 0x585b /* 8.192 Mhz */ -}; - -static uint32_t pllcfg_fury[16] = { - 0x3200, /* 1 Mhz */ - 0x1b20, /* 1.8432 Mhz */ - 0x1900, /* 2 Mhz */ - 0xf42b, /* 2.4576 Mhz */ - 0x37e3, /* 3.57954 Mhz */ - 0x1b21, /* 3.6864 Mhz */ - 0x0c80, /* 4 Mhz */ - 0x98ee, /* 4.906 Mhz */ - 0xd5b4, /* 4.9152 Mhz */ - 0x0a00, /* 5 Mhz */ - 0x4e27, /* 5.12 Mhz */ - 0x1902, /* 6 Mhz */ - 0xec1c, /* 6.144 Mhz */ - 0x1b23, /* 7.3728 Mhz */ - 0x0640, /* 8 Mhz */ - 0xb11c /* 8.192 Mhz */ -}; - -#define DID0_VER_MASK 0x70000000 -#define DID0_VER_0 0x00000000 -#define DID0_VER_1 0x10000000 - -#define DID0_CLASS_MASK 0x00FF0000 -#define DID0_CLASS_SANDSTORM 0x00000000 -#define DID0_CLASS_FURY 0x00010000 - -static int ssys_board_class(const ssys_state *s) -{ - uint32_t did0 = s->board->did0; - switch (did0 & DID0_VER_MASK) { - case DID0_VER_0: - return DID0_CLASS_SANDSTORM; - case DID0_VER_1: - switch (did0 & DID0_CLASS_MASK) { - case DID0_CLASS_SANDSTORM: - case DID0_CLASS_FURY: - return did0 & DID0_CLASS_MASK; - } - /* for unknown classes, fall through */ - default: - hw_error("ssys_board_class: Unknown class 0x%08x\n", did0); - } -} - -static uint64_t ssys_read(void *opaque, hwaddr offset, - unsigned size) -{ - ssys_state *s = (ssys_state *)opaque; - - switch (offset) { - case 0x000: /* DID0 */ - return s->board->did0; - case 0x004: /* DID1 */ - return s->board->did1; - case 0x008: /* DC0 */ - return s->board->dc0; - case 0x010: /* DC1 */ - return s->board->dc1; - case 0x014: /* DC2 */ - return s->board->dc2; - case 0x018: /* DC3 */ - return s->board->dc3; - case 0x01c: /* DC4 */ - return s->board->dc4; - case 0x030: /* PBORCTL */ - return s->pborctl; - case 0x034: /* LDOPCTL */ - return s->ldopctl; - case 0x040: /* SRCR0 */ - return 0; - case 0x044: /* SRCR1 */ - return 0; - case 0x048: /* SRCR2 */ - return 0; - case 0x050: /* RIS */ - return s->int_status; - case 0x054: /* IMC */ - return s->int_mask; - case 0x058: /* MISC */ - return s->int_status & s->int_mask; - case 0x05c: /* RESC */ - return s->resc; - case 0x060: /* RCC */ - return s->rcc; - case 0x064: /* PLLCFG */ - { - int xtal; - xtal = (s->rcc >> 6) & 0xf; - switch (ssys_board_class(s)) { - case DID0_CLASS_FURY: - return pllcfg_fury[xtal]; - case DID0_CLASS_SANDSTORM: - return pllcfg_sandstorm[xtal]; - default: - hw_error("ssys_read: Unhandled class for PLLCFG read.\n"); - return 0; - } - } - case 0x070: /* RCC2 */ - return s->rcc2; - case 0x100: /* RCGC0 */ - return s->rcgc[0]; - case 0x104: /* RCGC1 */ - return s->rcgc[1]; - case 0x108: /* RCGC2 */ - return s->rcgc[2]; - case 0x110: /* SCGC0 */ - return s->scgc[0]; - case 0x114: /* SCGC1 */ - return s->scgc[1]; - case 0x118: /* SCGC2 */ - return s->scgc[2]; - case 0x120: /* DCGC0 */ - return s->dcgc[0]; - case 0x124: /* DCGC1 */ - return s->dcgc[1]; - case 0x128: /* DCGC2 */ - return s->dcgc[2]; - case 0x150: /* CLKVCLR */ - return s->clkvclr; - case 0x160: /* LDOARST */ - return s->ldoarst; - case 0x1e0: /* USER0 */ - return s->user0; - case 0x1e4: /* USER1 */ - return s->user1; - default: - hw_error("ssys_read: Bad offset 0x%x\n", (int)offset); - return 0; - } -} - -static bool ssys_use_rcc2(ssys_state *s) -{ - return (s->rcc2 >> 31) & 0x1; -} - -/* - * Caculate the sys. clock period in ms. - */ -static void ssys_calculate_system_clock(ssys_state *s) -{ - if (ssys_use_rcc2(s)) { - system_clock_scale = 5 * (((s->rcc2 >> 23) & 0x3f) + 1); - } else { - system_clock_scale = 5 * (((s->rcc >> 23) & 0xf) + 1); - } -} - -static void ssys_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - ssys_state *s = (ssys_state *)opaque; - - switch (offset) { - case 0x030: /* PBORCTL */ - s->pborctl = value & 0xffff; - break; - case 0x034: /* LDOPCTL */ - s->ldopctl = value & 0x1f; - break; - case 0x040: /* SRCR0 */ - case 0x044: /* SRCR1 */ - case 0x048: /* SRCR2 */ - fprintf(stderr, "Peripheral reset not implemented\n"); - break; - case 0x054: /* IMC */ - s->int_mask = value & 0x7f; - break; - case 0x058: /* MISC */ - s->int_status &= ~value; - break; - case 0x05c: /* RESC */ - s->resc = value & 0x3f; - break; - case 0x060: /* RCC */ - if ((s->rcc & (1 << 13)) != 0 && (value & (1 << 13)) == 0) { - /* PLL enable. */ - s->int_status |= (1 << 6); - } - s->rcc = value; - ssys_calculate_system_clock(s); - break; - case 0x070: /* RCC2 */ - if (ssys_board_class(s) == DID0_CLASS_SANDSTORM) { - break; - } - - if ((s->rcc2 & (1 << 13)) != 0 && (value & (1 << 13)) == 0) { - /* PLL enable. */ - s->int_status |= (1 << 6); - } - s->rcc2 = value; - ssys_calculate_system_clock(s); - break; - case 0x100: /* RCGC0 */ - s->rcgc[0] = value; - break; - case 0x104: /* RCGC1 */ - s->rcgc[1] = value; - break; - case 0x108: /* RCGC2 */ - s->rcgc[2] = value; - break; - case 0x110: /* SCGC0 */ - s->scgc[0] = value; - break; - case 0x114: /* SCGC1 */ - s->scgc[1] = value; - break; - case 0x118: /* SCGC2 */ - s->scgc[2] = value; - break; - case 0x120: /* DCGC0 */ - s->dcgc[0] = value; - break; - case 0x124: /* DCGC1 */ - s->dcgc[1] = value; - break; - case 0x128: /* DCGC2 */ - s->dcgc[2] = value; - break; - case 0x150: /* CLKVCLR */ - s->clkvclr = value; - break; - case 0x160: /* LDOARST */ - s->ldoarst = value; - break; - default: - hw_error("ssys_write: Bad offset 0x%x\n", (int)offset); - } - ssys_update(s); -} - -static const MemoryRegionOps ssys_ops = { - .read = ssys_read, - .write = ssys_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void ssys_reset(void *opaque) -{ - ssys_state *s = (ssys_state *)opaque; - - s->pborctl = 0x7ffd; - s->rcc = 0x078e3ac0; - - if (ssys_board_class(s) == DID0_CLASS_SANDSTORM) { - s->rcc2 = 0; - } else { - s->rcc2 = 0x07802810; - } - s->rcgc[0] = 1; - s->scgc[0] = 1; - s->dcgc[0] = 1; - ssys_calculate_system_clock(s); -} - -static int stellaris_sys_post_load(void *opaque, int version_id) -{ - ssys_state *s = opaque; - - ssys_calculate_system_clock(s); - - return 0; -} - -static const VMStateDescription vmstate_stellaris_sys = { - .name = "stellaris_sys", - .version_id = 2, - .minimum_version_id = 1, - .post_load = stellaris_sys_post_load, - .fields = (VMStateField[]) { - VMSTATE_UINT32(pborctl, ssys_state), - VMSTATE_UINT32(ldopctl, ssys_state), - VMSTATE_UINT32(int_mask, ssys_state), - VMSTATE_UINT32(int_status, ssys_state), - VMSTATE_UINT32(resc, ssys_state), - VMSTATE_UINT32(rcc, ssys_state), - VMSTATE_UINT32_V(rcc2, ssys_state, 2), - VMSTATE_UINT32_ARRAY(rcgc, ssys_state, 3), - VMSTATE_UINT32_ARRAY(scgc, ssys_state, 3), - VMSTATE_UINT32_ARRAY(dcgc, ssys_state, 3), - VMSTATE_UINT32(clkvclr, ssys_state), - VMSTATE_UINT32(ldoarst, ssys_state), - VMSTATE_END_OF_LIST() - } -}; - -static int stellaris_sys_init(uint32_t base, qemu_irq irq, - stellaris_board_info * board, - uint8_t *macaddr) -{ - ssys_state *s; - - s = g_new0(ssys_state, 1); - s->irq = irq; - s->board = board; - /* Most devices come preprogrammed with a MAC address in the user data. */ - s->user0 = macaddr[0] | (macaddr[1] << 8) | (macaddr[2] << 16); - s->user1 = macaddr[3] | (macaddr[4] << 8) | (macaddr[5] << 16); - - memory_region_init_io(&s->iomem, NULL, &ssys_ops, s, "ssys", 0x00001000); - memory_region_add_subregion(get_system_memory(), base, &s->iomem); - ssys_reset(s); - vmstate_register(NULL, -1, &vmstate_stellaris_sys, s); - return 0; -} - - -/* I2C controller. */ - -#define TYPE_STELLARIS_I2C "stellaris-i2c" -#define STELLARIS_I2C(obj) \ - OBJECT_CHECK(stellaris_i2c_state, (obj), TYPE_STELLARIS_I2C) - -typedef struct { - SysBusDevice parent_obj; - - I2CBus *bus; - qemu_irq irq; - MemoryRegion iomem; - uint32_t msa; - uint32_t mcs; - uint32_t mdr; - uint32_t mtpr; - uint32_t mimr; - uint32_t mris; - uint32_t mcr; -} stellaris_i2c_state; - -#define STELLARIS_I2C_MCS_BUSY 0x01 -#define STELLARIS_I2C_MCS_ERROR 0x02 -#define STELLARIS_I2C_MCS_ADRACK 0x04 -#define STELLARIS_I2C_MCS_DATACK 0x08 -#define STELLARIS_I2C_MCS_ARBLST 0x10 -#define STELLARIS_I2C_MCS_IDLE 0x20 -#define STELLARIS_I2C_MCS_BUSBSY 0x40 - -static uint64_t stellaris_i2c_read(void *opaque, hwaddr offset, - unsigned size) -{ - stellaris_i2c_state *s = (stellaris_i2c_state *)opaque; - - switch (offset) { - case 0x00: /* MSA */ - return s->msa; - case 0x04: /* MCS */ - /* We don't emulate timing, so the controller is never busy. */ - return s->mcs | STELLARIS_I2C_MCS_IDLE; - case 0x08: /* MDR */ - return s->mdr; - case 0x0c: /* MTPR */ - return s->mtpr; - case 0x10: /* MIMR */ - return s->mimr; - case 0x14: /* MRIS */ - return s->mris; - case 0x18: /* MMIS */ - return s->mris & s->mimr; - case 0x20: /* MCR */ - return s->mcr; - default: - hw_error("strllaris_i2c_read: Bad offset 0x%x\n", (int)offset); - return 0; - } -} - -static void stellaris_i2c_update(stellaris_i2c_state *s) -{ - int level; - - level = (s->mris & s->mimr) != 0; - qemu_set_irq(s->irq, level); -} - -static void stellaris_i2c_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - stellaris_i2c_state *s = (stellaris_i2c_state *)opaque; - - switch (offset) { - case 0x00: /* MSA */ - s->msa = value & 0xff; - break; - case 0x04: /* MCS */ - if ((s->mcr & 0x10) == 0) { - /* Disabled. Do nothing. */ - break; - } - /* Grab the bus if this is starting a transfer. */ - if ((value & 2) && (s->mcs & STELLARIS_I2C_MCS_BUSBSY) == 0) { - if (i2c_start_transfer(s->bus, s->msa >> 1, s->msa & 1)) { - s->mcs |= STELLARIS_I2C_MCS_ARBLST; - } else { - s->mcs &= ~STELLARIS_I2C_MCS_ARBLST; - s->mcs |= STELLARIS_I2C_MCS_BUSBSY; - } - } - /* If we don't have the bus then indicate an error. */ - if (!i2c_bus_busy(s->bus) - || (s->mcs & STELLARIS_I2C_MCS_BUSBSY) == 0) { - s->mcs |= STELLARIS_I2C_MCS_ERROR; - break; - } - s->mcs &= ~STELLARIS_I2C_MCS_ERROR; - if (value & 1) { - /* Transfer a byte. */ - /* TODO: Handle errors. */ - if (s->msa & 1) { - /* Recv */ - s->mdr = i2c_recv(s->bus) & 0xff; - } else { - /* Send */ - i2c_send(s->bus, s->mdr); - } - /* Raise an interrupt. */ - s->mris |= 1; - } - if (value & 4) { - /* Finish transfer. */ - i2c_end_transfer(s->bus); - s->mcs &= ~STELLARIS_I2C_MCS_BUSBSY; - } - break; - case 0x08: /* MDR */ - s->mdr = value & 0xff; - break; - case 0x0c: /* MTPR */ - s->mtpr = value & 0xff; - break; - case 0x10: /* MIMR */ - s->mimr = 1; - break; - case 0x1c: /* MICR */ - s->mris &= ~value; - break; - case 0x20: /* MCR */ - if (value & 1) - hw_error( - "stellaris_i2c_write: Loopback not implemented\n"); - if (value & 0x20) - hw_error( - "stellaris_i2c_write: Slave mode not implemented\n"); - s->mcr = value & 0x31; - break; - default: - hw_error("stellaris_i2c_write: Bad offset 0x%x\n", - (int)offset); - } - stellaris_i2c_update(s); -} - -static void stellaris_i2c_reset(stellaris_i2c_state *s) -{ - if (s->mcs & STELLARIS_I2C_MCS_BUSBSY) - i2c_end_transfer(s->bus); - - s->msa = 0; - s->mcs = 0; - s->mdr = 0; - s->mtpr = 1; - s->mimr = 0; - s->mris = 0; - s->mcr = 0; - stellaris_i2c_update(s); -} - -static const MemoryRegionOps stellaris_i2c_ops = { - .read = stellaris_i2c_read, - .write = stellaris_i2c_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static const VMStateDescription vmstate_stellaris_i2c = { - .name = "stellaris_i2c", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(msa, stellaris_i2c_state), - VMSTATE_UINT32(mcs, stellaris_i2c_state), - VMSTATE_UINT32(mdr, stellaris_i2c_state), - VMSTATE_UINT32(mtpr, stellaris_i2c_state), - VMSTATE_UINT32(mimr, stellaris_i2c_state), - VMSTATE_UINT32(mris, stellaris_i2c_state), - VMSTATE_UINT32(mcr, stellaris_i2c_state), - VMSTATE_END_OF_LIST() - } -}; - -static int stellaris_i2c_init(SysBusDevice *sbd) -{ - DeviceState *dev = DEVICE(sbd); - stellaris_i2c_state *s = STELLARIS_I2C(dev); - I2CBus *bus; - - sysbus_init_irq(sbd, &s->irq); - bus = i2c_init_bus(dev, "i2c"); - s->bus = bus; - - memory_region_init_io(&s->iomem, OBJECT(s), &stellaris_i2c_ops, s, - "i2c", 0x1000); - sysbus_init_mmio(sbd, &s->iomem); - /* ??? For now we only implement the master interface. */ - stellaris_i2c_reset(s); - vmstate_register(dev, -1, &vmstate_stellaris_i2c, s); - return 0; -} - -/* Analogue to Digital Converter. This is only partially implemented, - enough for applications that use a combined ADC and timer tick. */ - -#define STELLARIS_ADC_EM_CONTROLLER 0 -#define STELLARIS_ADC_EM_COMP 1 -#define STELLARIS_ADC_EM_EXTERNAL 4 -#define STELLARIS_ADC_EM_TIMER 5 -#define STELLARIS_ADC_EM_PWM0 6 -#define STELLARIS_ADC_EM_PWM1 7 -#define STELLARIS_ADC_EM_PWM2 8 - -#define STELLARIS_ADC_FIFO_EMPTY 0x0100 -#define STELLARIS_ADC_FIFO_FULL 0x1000 - -#define TYPE_STELLARIS_ADC "stellaris-adc" -#define STELLARIS_ADC(obj) \ - OBJECT_CHECK(stellaris_adc_state, (obj), TYPE_STELLARIS_ADC) - -typedef struct StellarisADCState { - SysBusDevice parent_obj; - - MemoryRegion iomem; - uint32_t actss; - uint32_t ris; - uint32_t im; - uint32_t emux; - uint32_t ostat; - uint32_t ustat; - uint32_t sspri; - uint32_t sac; - struct { - uint32_t state; - uint32_t data[16]; - } fifo[4]; - uint32_t ssmux[4]; - uint32_t ssctl[4]; - uint32_t noise; - qemu_irq irq[4]; -} stellaris_adc_state; - -static uint32_t stellaris_adc_fifo_read(stellaris_adc_state *s, int n) -{ - int tail; - - tail = s->fifo[n].state & 0xf; - if (s->fifo[n].state & STELLARIS_ADC_FIFO_EMPTY) { - s->ustat |= 1 << n; - } else { - s->fifo[n].state = (s->fifo[n].state & ~0xf) | ((tail + 1) & 0xf); - s->fifo[n].state &= ~STELLARIS_ADC_FIFO_FULL; - if (tail + 1 == ((s->fifo[n].state >> 4) & 0xf)) - s->fifo[n].state |= STELLARIS_ADC_FIFO_EMPTY; - } - return s->fifo[n].data[tail]; -} - -static void stellaris_adc_fifo_write(stellaris_adc_state *s, int n, - uint32_t value) -{ - int head; - - /* TODO: Real hardware has limited size FIFOs. We have a full 16 entry - FIFO fir each sequencer. */ - head = (s->fifo[n].state >> 4) & 0xf; - if (s->fifo[n].state & STELLARIS_ADC_FIFO_FULL) { - s->ostat |= 1 << n; - return; - } - s->fifo[n].data[head] = value; - head = (head + 1) & 0xf; - s->fifo[n].state &= ~STELLARIS_ADC_FIFO_EMPTY; - s->fifo[n].state = (s->fifo[n].state & ~0xf0) | (head << 4); - if ((s->fifo[n].state & 0xf) == head) - s->fifo[n].state |= STELLARIS_ADC_FIFO_FULL; -} - -static void stellaris_adc_update(stellaris_adc_state *s) -{ - int level; - int n; - - for (n = 0; n < 4; n++) { - level = (s->ris & s->im & (1 << n)) != 0; - qemu_set_irq(s->irq[n], level); - } -} - -static void stellaris_adc_trigger(void *opaque, int irq, int level) -{ - stellaris_adc_state *s = (stellaris_adc_state *)opaque; - int n; - - for (n = 0; n < 4; n++) { - if ((s->actss & (1 << n)) == 0) { - continue; - } - - if (((s->emux >> (n * 4)) & 0xff) != 5) { - continue; - } - - /* Some applications use the ADC as a random number source, so introduce - some variation into the signal. */ - s->noise = s->noise * 314159 + 1; - /* ??? actual inputs not implemented. Return an arbitrary value. */ - stellaris_adc_fifo_write(s, n, 0x200 + ((s->noise >> 16) & 7)); - s->ris |= (1 << n); - stellaris_adc_update(s); - } -} - -static void stellaris_adc_reset(stellaris_adc_state *s) -{ - int n; - - for (n = 0; n < 4; n++) { - s->ssmux[n] = 0; - s->ssctl[n] = 0; - s->fifo[n].state = STELLARIS_ADC_FIFO_EMPTY; - } -} - -static uint64_t stellaris_adc_read(void *opaque, hwaddr offset, - unsigned size) -{ - stellaris_adc_state *s = (stellaris_adc_state *)opaque; - - /* TODO: Implement this. */ - if (offset >= 0x40 && offset < 0xc0) { - int n; - n = (offset - 0x40) >> 5; - switch (offset & 0x1f) { - case 0x00: /* SSMUX */ - return s->ssmux[n]; - case 0x04: /* SSCTL */ - return s->ssctl[n]; - case 0x08: /* SSFIFO */ - return stellaris_adc_fifo_read(s, n); - case 0x0c: /* SSFSTAT */ - return s->fifo[n].state; - default: - break; - } - } - switch (offset) { - case 0x00: /* ACTSS */ - return s->actss; - case 0x04: /* RIS */ - return s->ris; - case 0x08: /* IM */ - return s->im; - case 0x0c: /* ISC */ - return s->ris & s->im; - case 0x10: /* OSTAT */ - return s->ostat; - case 0x14: /* EMUX */ - return s->emux; - case 0x18: /* USTAT */ - return s->ustat; - case 0x20: /* SSPRI */ - return s->sspri; - case 0x30: /* SAC */ - return s->sac; - default: - hw_error("strllaris_adc_read: Bad offset 0x%x\n", - (int)offset); - return 0; - } -} - -static void stellaris_adc_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - stellaris_adc_state *s = (stellaris_adc_state *)opaque; - - /* TODO: Implement this. */ - if (offset >= 0x40 && offset < 0xc0) { - int n; - n = (offset - 0x40) >> 5; - switch (offset & 0x1f) { - case 0x00: /* SSMUX */ - s->ssmux[n] = value & 0x33333333; - return; - case 0x04: /* SSCTL */ - if (value != 6) { - hw_error("ADC: Unimplemented sequence %" PRIx64 "\n", - value); - } - s->ssctl[n] = value; - return; - default: - break; - } - } - switch (offset) { - case 0x00: /* ACTSS */ - s->actss = value & 0xf; - break; - case 0x08: /* IM */ - s->im = value; - break; - case 0x0c: /* ISC */ - s->ris &= ~value; - break; - case 0x10: /* OSTAT */ - s->ostat &= ~value; - break; - case 0x14: /* EMUX */ - s->emux = value; - break; - case 0x18: /* USTAT */ - s->ustat &= ~value; - break; - case 0x20: /* SSPRI */ - s->sspri = value; - break; - case 0x28: /* PSSI */ - hw_error("Not implemented: ADC sample initiate\n"); - break; - case 0x30: /* SAC */ - s->sac = value; - break; - default: - hw_error("stellaris_adc_write: Bad offset 0x%x\n", (int)offset); - } - stellaris_adc_update(s); -} - -static const MemoryRegionOps stellaris_adc_ops = { - .read = stellaris_adc_read, - .write = stellaris_adc_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static const VMStateDescription vmstate_stellaris_adc = { - .name = "stellaris_adc", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(actss, stellaris_adc_state), - VMSTATE_UINT32(ris, stellaris_adc_state), - VMSTATE_UINT32(im, stellaris_adc_state), - VMSTATE_UINT32(emux, stellaris_adc_state), - VMSTATE_UINT32(ostat, stellaris_adc_state), - VMSTATE_UINT32(ustat, stellaris_adc_state), - VMSTATE_UINT32(sspri, stellaris_adc_state), - VMSTATE_UINT32(sac, stellaris_adc_state), - VMSTATE_UINT32(fifo[0].state, stellaris_adc_state), - VMSTATE_UINT32_ARRAY(fifo[0].data, stellaris_adc_state, 16), - VMSTATE_UINT32(ssmux[0], stellaris_adc_state), - VMSTATE_UINT32(ssctl[0], stellaris_adc_state), - VMSTATE_UINT32(fifo[1].state, stellaris_adc_state), - VMSTATE_UINT32_ARRAY(fifo[1].data, stellaris_adc_state, 16), - VMSTATE_UINT32(ssmux[1], stellaris_adc_state), - VMSTATE_UINT32(ssctl[1], stellaris_adc_state), - VMSTATE_UINT32(fifo[2].state, stellaris_adc_state), - VMSTATE_UINT32_ARRAY(fifo[2].data, stellaris_adc_state, 16), - VMSTATE_UINT32(ssmux[2], stellaris_adc_state), - VMSTATE_UINT32(ssctl[2], stellaris_adc_state), - VMSTATE_UINT32(fifo[3].state, stellaris_adc_state), - VMSTATE_UINT32_ARRAY(fifo[3].data, stellaris_adc_state, 16), - VMSTATE_UINT32(ssmux[3], stellaris_adc_state), - VMSTATE_UINT32(ssctl[3], stellaris_adc_state), - VMSTATE_UINT32(noise, stellaris_adc_state), - VMSTATE_END_OF_LIST() - } -}; - -static int stellaris_adc_init(SysBusDevice *sbd) -{ - DeviceState *dev = DEVICE(sbd); - stellaris_adc_state *s = STELLARIS_ADC(dev); - int n; - - for (n = 0; n < 4; n++) { - sysbus_init_irq(sbd, &s->irq[n]); - } - - memory_region_init_io(&s->iomem, OBJECT(s), &stellaris_adc_ops, s, - "adc", 0x1000); - sysbus_init_mmio(sbd, &s->iomem); - stellaris_adc_reset(s); - qdev_init_gpio_in(dev, stellaris_adc_trigger, 1); - vmstate_register(dev, -1, &vmstate_stellaris_adc, s); - return 0; -} - -static -void do_sys_reset(void *opaque, int n, int level) -{ - if (level) { - qemu_system_reset_request(); - } -} - -/* Board init. */ -static stellaris_board_info stellaris_boards[] = { - { "LM3S811EVB", - 0, - 0x0032000e, - 0x001f001f, /* dc0 */ - 0x001132bf, - 0x01071013, - 0x3f0f01ff, - 0x0000001f, - BP_OLED_I2C - }, - { "LM3S6965EVB", - 0x10010002, - 0x1073402e, - 0x00ff007f, /* dc0 */ - 0x001133ff, - 0x030f5317, - 0x0f0f87ff, - 0x5000007f, - BP_OLED_SSI | BP_GAMEPAD - } -}; - -static void stellaris_init(const char *kernel_filename, const char *cpu_model, - stellaris_board_info *board) -{ - static const int uart_irq[] = {5, 6, 33, 34}; - static const int timer_irq[] = {19, 21, 23, 35}; - static const uint32_t gpio_addr[7] = - { 0x40004000, 0x40005000, 0x40006000, 0x40007000, - 0x40024000, 0x40025000, 0x40026000}; - static const int gpio_irq[7] = {0, 1, 2, 3, 4, 30, 31}; - - DeviceState *gpio_dev[7], *nvic; - qemu_irq gpio_in[7][8]; - qemu_irq gpio_out[7][8]; - qemu_irq adc; - int sram_size; - int flash_size; - I2CBus *i2c; - DeviceState *dev; - int i; - int j; - - MemoryRegion *sram = g_new(MemoryRegion, 1); - MemoryRegion *flash = g_new(MemoryRegion, 1); - MemoryRegion *system_memory = get_system_memory(); - - flash_size = (((board->dc0 & 0xffff) + 1) << 1) * 1024; - sram_size = ((board->dc0 >> 18) + 1) * 1024; - - /* Flash programming is done via the SCU, so pretend it is ROM. */ - memory_region_init_ram(flash, NULL, "stellaris.flash", flash_size, - &error_fatal); - vmstate_register_ram_global(flash); - memory_region_set_readonly(flash, true); - memory_region_add_subregion(system_memory, 0, flash); - - memory_region_init_ram(sram, NULL, "stellaris.sram", sram_size, - &error_fatal); - vmstate_register_ram_global(sram); - memory_region_add_subregion(system_memory, 0x20000000, sram); - - nvic = armv7m_init(system_memory, flash_size, NUM_IRQ_LINES, - kernel_filename, cpu_model); - - qdev_connect_gpio_out_named(nvic, "SYSRESETREQ", 0, - qemu_allocate_irq(&do_sys_reset, NULL, 0)); - - if (board->dc1 & (1 << 16)) { - dev = sysbus_create_varargs(TYPE_STELLARIS_ADC, 0x40038000, - qdev_get_gpio_in(nvic, 14), - qdev_get_gpio_in(nvic, 15), - qdev_get_gpio_in(nvic, 16), - qdev_get_gpio_in(nvic, 17), - NULL); - adc = qdev_get_gpio_in(dev, 0); - } else { - adc = NULL; - } - for (i = 0; i < 4; i++) { - if (board->dc2 & (0x10000 << i)) { - dev = sysbus_create_simple(TYPE_STELLARIS_GPTM, - 0x40030000 + i * 0x1000, - qdev_get_gpio_in(nvic, timer_irq[i])); - /* TODO: This is incorrect, but we get away with it because - the ADC output is only ever pulsed. */ - qdev_connect_gpio_out(dev, 0, adc); - } - } - - stellaris_sys_init(0x400fe000, qdev_get_gpio_in(nvic, 28), - board, nd_table[0].macaddr.a); - - for (i = 0; i < 7; i++) { - if (board->dc4 & (1 << i)) { - gpio_dev[i] = sysbus_create_simple("pl061_luminary", gpio_addr[i], - qdev_get_gpio_in(nvic, - gpio_irq[i])); - for (j = 0; j < 8; j++) { - gpio_in[i][j] = qdev_get_gpio_in(gpio_dev[i], j); - gpio_out[i][j] = NULL; - } - } - } - - if (board->dc2 & (1 << 12)) { - dev = sysbus_create_simple(TYPE_STELLARIS_I2C, 0x40020000, - qdev_get_gpio_in(nvic, 8)); - i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c"); - if (board->peripherals & BP_OLED_I2C) { - i2c_create_slave(i2c, "ssd0303", 0x3d); - } - } - - for (i = 0; i < 4; i++) { - if (board->dc2 & (1 << i)) { - sysbus_create_simple("pl011_luminary", 0x4000c000 + i * 0x1000, - qdev_get_gpio_in(nvic, uart_irq[i])); - } - } - if (board->dc2 & (1 << 4)) { - dev = sysbus_create_simple("pl022", 0x40008000, - qdev_get_gpio_in(nvic, 7)); - if (board->peripherals & BP_OLED_SSI) { - void *bus; - DeviceState *sddev; - DeviceState *ssddev; - - /* Some boards have both an OLED controller and SD card connected to - * the same SSI port, with the SD card chip select connected to a - * GPIO pin. Technically the OLED chip select is connected to the - * SSI Fss pin. We do not bother emulating that as both devices - * should never be selected simultaneously, and our OLED controller - * ignores stray 0xff commands that occur when deselecting the SD - * card. - */ - bus = qdev_get_child_bus(dev, "ssi"); - - sddev = ssi_create_slave(bus, "ssi-sd"); - ssddev = ssi_create_slave(bus, "ssd0323"); - gpio_out[GPIO_D][0] = qemu_irq_split( - qdev_get_gpio_in_named(sddev, SSI_GPIO_CS, 0), - qdev_get_gpio_in_named(ssddev, SSI_GPIO_CS, 0)); - gpio_out[GPIO_C][7] = qdev_get_gpio_in(ssddev, 0); - - /* Make sure the select pin is high. */ - qemu_irq_raise(gpio_out[GPIO_D][0]); - } - } - if (board->dc4 & (1 << 28)) { - DeviceState *enet; - - qemu_check_nic_model(&nd_table[0], "stellaris"); - - enet = qdev_create(NULL, "stellaris_enet"); - qdev_set_nic_properties(enet, &nd_table[0]); - qdev_init_nofail(enet); - sysbus_mmio_map(SYS_BUS_DEVICE(enet), 0, 0x40048000); - sysbus_connect_irq(SYS_BUS_DEVICE(enet), 0, qdev_get_gpio_in(nvic, 42)); - } - if (board->peripherals & BP_GAMEPAD) { - qemu_irq gpad_irq[5]; - static const int gpad_keycode[5] = { 0xc8, 0xd0, 0xcb, 0xcd, 0x1d }; - - gpad_irq[0] = qemu_irq_invert(gpio_in[GPIO_E][0]); /* up */ - gpad_irq[1] = qemu_irq_invert(gpio_in[GPIO_E][1]); /* down */ - gpad_irq[2] = qemu_irq_invert(gpio_in[GPIO_E][2]); /* left */ - gpad_irq[3] = qemu_irq_invert(gpio_in[GPIO_E][3]); /* right */ - gpad_irq[4] = qemu_irq_invert(gpio_in[GPIO_F][1]); /* select */ - - stellaris_gamepad_init(5, gpad_irq, gpad_keycode); - } - for (i = 0; i < 7; i++) { - if (board->dc4 & (1 << i)) { - for (j = 0; j < 8; j++) { - if (gpio_out[i][j]) { - qdev_connect_gpio_out(gpio_dev[i], j, gpio_out[i][j]); - } - } - } - } -} - -/* FIXME: Figure out how to generate these from stellaris_boards. */ -static void lm3s811evb_init(MachineState *machine) -{ - const char *cpu_model = machine->cpu_model; - const char *kernel_filename = machine->kernel_filename; - stellaris_init(kernel_filename, cpu_model, &stellaris_boards[0]); -} - -static void lm3s6965evb_init(MachineState *machine) -{ - const char *cpu_model = machine->cpu_model; - const char *kernel_filename = machine->kernel_filename; - stellaris_init(kernel_filename, cpu_model, &stellaris_boards[1]); -} - -static void lm3s811evb_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "Stellaris LM3S811EVB"; - mc->init = lm3s811evb_init; -} - -static const TypeInfo lm3s811evb_type = { - .name = MACHINE_TYPE_NAME("lm3s811evb"), - .parent = TYPE_MACHINE, - .class_init = lm3s811evb_class_init, -}; - -static void lm3s6965evb_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "Stellaris LM3S6965EVB"; - mc->init = lm3s6965evb_init; -} - -static const TypeInfo lm3s6965evb_type = { - .name = MACHINE_TYPE_NAME("lm3s6965evb"), - .parent = TYPE_MACHINE, - .class_init = lm3s6965evb_class_init, -}; - -static void stellaris_machine_init(void) -{ - type_register_static(&lm3s811evb_type); - type_register_static(&lm3s6965evb_type); -} - -type_init(stellaris_machine_init) - -static void stellaris_i2c_class_init(ObjectClass *klass, void *data) -{ - SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); - - sdc->init = stellaris_i2c_init; -} - -static const TypeInfo stellaris_i2c_info = { - .name = TYPE_STELLARIS_I2C, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(stellaris_i2c_state), - .class_init = stellaris_i2c_class_init, -}; - -static void stellaris_gptm_class_init(ObjectClass *klass, void *data) -{ - SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); - - sdc->init = stellaris_gptm_init; -} - -static const TypeInfo stellaris_gptm_info = { - .name = TYPE_STELLARIS_GPTM, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(gptm_state), - .class_init = stellaris_gptm_class_init, -}; - -static void stellaris_adc_class_init(ObjectClass *klass, void *data) -{ - SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); - - sdc->init = stellaris_adc_init; -} - -static const TypeInfo stellaris_adc_info = { - .name = TYPE_STELLARIS_ADC, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(stellaris_adc_state), - .class_init = stellaris_adc_class_init, -}; - -static void stellaris_register_types(void) -{ - type_register_static(&stellaris_i2c_info); - type_register_static(&stellaris_gptm_info); - type_register_static(&stellaris_adc_info); -} - -type_init(stellaris_register_types) diff --git a/qemu/hw/arm/stm32f205_soc.c b/qemu/hw/arm/stm32f205_soc.c deleted file mode 100644 index a5ea1e237..000000000 --- a/qemu/hw/arm/stm32f205_soc.c +++ /dev/null @@ -1,165 +0,0 @@ -/* - * STM32F205 SoC - * - * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me> - * - * 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 "qemu/osdep.h" -#include "qapi/error.h" -#include "qemu-common.h" -#include "cpu.h" -#include "hw/arm/arm.h" -#include "exec/address-spaces.h" -#include "hw/arm/stm32f205_soc.h" - -/* At the moment only Timer 2 to 5 are modelled */ -static const uint32_t timer_addr[STM_NUM_TIMERS] = { 0x40000000, 0x40000400, - 0x40000800, 0x40000C00 }; -static const uint32_t usart_addr[STM_NUM_USARTS] = { 0x40011000, 0x40004400, - 0x40004800, 0x40004C00, 0x40005000, 0x40011400 }; - -static const int timer_irq[STM_NUM_TIMERS] = {28, 29, 30, 50}; -static const int usart_irq[STM_NUM_USARTS] = {37, 38, 39, 52, 53, 71}; - -static void stm32f205_soc_initfn(Object *obj) -{ - STM32F205State *s = STM32F205_SOC(obj); - int i; - - object_initialize(&s->syscfg, sizeof(s->syscfg), TYPE_STM32F2XX_SYSCFG); - qdev_set_parent_bus(DEVICE(&s->syscfg), sysbus_get_default()); - - for (i = 0; i < STM_NUM_USARTS; i++) { - object_initialize(&s->usart[i], sizeof(s->usart[i]), - TYPE_STM32F2XX_USART); - qdev_set_parent_bus(DEVICE(&s->usart[i]), sysbus_get_default()); - } - - for (i = 0; i < STM_NUM_TIMERS; i++) { - object_initialize(&s->timer[i], sizeof(s->timer[i]), - TYPE_STM32F2XX_TIMER); - qdev_set_parent_bus(DEVICE(&s->timer[i]), sysbus_get_default()); - } -} - -static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp) -{ - STM32F205State *s = STM32F205_SOC(dev_soc); - DeviceState *syscfgdev, *usartdev, *timerdev, *nvic; - SysBusDevice *syscfgbusdev, *usartbusdev, *timerbusdev; - Error *err = NULL; - int i; - - MemoryRegion *system_memory = get_system_memory(); - MemoryRegion *sram = g_new(MemoryRegion, 1); - MemoryRegion *flash = g_new(MemoryRegion, 1); - MemoryRegion *flash_alias = g_new(MemoryRegion, 1); - - memory_region_init_ram(flash, NULL, "STM32F205.flash", FLASH_SIZE, - &error_fatal); - memory_region_init_alias(flash_alias, NULL, "STM32F205.flash.alias", - flash, 0, FLASH_SIZE); - - vmstate_register_ram_global(flash); - - memory_region_set_readonly(flash, true); - memory_region_set_readonly(flash_alias, true); - - memory_region_add_subregion(system_memory, FLASH_BASE_ADDRESS, flash); - memory_region_add_subregion(system_memory, 0, flash_alias); - - memory_region_init_ram(sram, NULL, "STM32F205.sram", SRAM_SIZE, - &error_fatal); - vmstate_register_ram_global(sram); - memory_region_add_subregion(system_memory, SRAM_BASE_ADDRESS, sram); - - nvic = armv7m_init(get_system_memory(), FLASH_SIZE, 96, - s->kernel_filename, s->cpu_model); - - /* System configuration controller */ - syscfgdev = DEVICE(&s->syscfg); - object_property_set_bool(OBJECT(&s->syscfg), true, "realized", &err); - if (err != NULL) { - error_propagate(errp, err); - return; - } - syscfgbusdev = SYS_BUS_DEVICE(syscfgdev); - sysbus_mmio_map(syscfgbusdev, 0, 0x40013800); - sysbus_connect_irq(syscfgbusdev, 0, qdev_get_gpio_in(nvic, 71)); - - /* Attach UART (uses USART registers) and USART controllers */ - for (i = 0; i < STM_NUM_USARTS; i++) { - usartdev = DEVICE(&(s->usart[i])); - object_property_set_bool(OBJECT(&s->usart[i]), true, "realized", &err); - if (err != NULL) { - error_propagate(errp, err); - return; - } - usartbusdev = SYS_BUS_DEVICE(usartdev); - sysbus_mmio_map(usartbusdev, 0, usart_addr[i]); - sysbus_connect_irq(usartbusdev, 0, - qdev_get_gpio_in(nvic, usart_irq[i])); - } - - /* Timer 2 to 5 */ - for (i = 0; i < STM_NUM_TIMERS; i++) { - timerdev = DEVICE(&(s->timer[i])); - qdev_prop_set_uint64(timerdev, "clock-frequency", 1000000000); - object_property_set_bool(OBJECT(&s->timer[i]), true, "realized", &err); - if (err != NULL) { - error_propagate(errp, err); - return; - } - timerbusdev = SYS_BUS_DEVICE(timerdev); - sysbus_mmio_map(timerbusdev, 0, timer_addr[i]); - sysbus_connect_irq(timerbusdev, 0, - qdev_get_gpio_in(nvic, timer_irq[i])); - } -} - -static Property stm32f205_soc_properties[] = { - DEFINE_PROP_STRING("kernel-filename", STM32F205State, kernel_filename), - DEFINE_PROP_STRING("cpu-model", STM32F205State, cpu_model), - DEFINE_PROP_END_OF_LIST(), -}; - -static void stm32f205_soc_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = stm32f205_soc_realize; - dc->props = stm32f205_soc_properties; -} - -static const TypeInfo stm32f205_soc_info = { - .name = TYPE_STM32F205_SOC, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(STM32F205State), - .instance_init = stm32f205_soc_initfn, - .class_init = stm32f205_soc_class_init, -}; - -static void stm32f205_soc_types(void) -{ - type_register_static(&stm32f205_soc_info); -} - -type_init(stm32f205_soc_types) diff --git a/qemu/hw/arm/strongarm.c b/qemu/hw/arm/strongarm.c deleted file mode 100644 index 1eeb1ab39..000000000 --- a/qemu/hw/arm/strongarm.c +++ /dev/null @@ -1,1662 +0,0 @@ -/* - * StrongARM SA-1100/SA-1110 emulation - * - * Copyright (C) 2011 Dmitry Eremin-Solenikov - * - * Largely based on StrongARM emulation: - * Copyright (c) 2006 Openedhand Ltd. - * Written by Andrzej Zaborowski <balrog@zabor.org> - * - * UART code based on QEMU 16550A UART emulation - * Copyright (c) 2003-2004 Fabrice Bellard - * Copyright (c) 2008 Citrix Systems, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 <http://www.gnu.org/licenses/>. - * - * Contributions after 2012-01-13 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. - */ - -#include "qemu/osdep.h" -#include "cpu.h" -#include "hw/boards.h" -#include "hw/sysbus.h" -#include "strongarm.h" -#include "qemu/error-report.h" -#include "hw/arm/arm.h" -#include "sysemu/char.h" -#include "sysemu/sysemu.h" -#include "hw/ssi/ssi.h" -#include "qemu/cutils.h" - -//#define DEBUG - -/* - TODO - - Implement cp15, c14 ? - - Implement cp15, c15 !!! (idle used in L) - - Implement idle mode handling/DIM - - Implement sleep mode/Wake sources - - Implement reset control - - Implement memory control regs - - PCMCIA handling - - Maybe support MBGNT/MBREQ - - DMA channels - - GPCLK - - IrDA - - MCP - - Enhance UART with modem signals - */ - -#ifdef DEBUG -# define DPRINTF(format, ...) printf(format , ## __VA_ARGS__) -#else -# define DPRINTF(format, ...) do { } while (0) -#endif - -static struct { - hwaddr io_base; - int irq; -} sa_serial[] = { - { 0x80010000, SA_PIC_UART1 }, - { 0x80030000, SA_PIC_UART2 }, - { 0x80050000, SA_PIC_UART3 }, - { 0, 0 } -}; - -/* Interrupt Controller */ - -#define TYPE_STRONGARM_PIC "strongarm_pic" -#define STRONGARM_PIC(obj) \ - OBJECT_CHECK(StrongARMPICState, (obj), TYPE_STRONGARM_PIC) - -typedef struct StrongARMPICState { - SysBusDevice parent_obj; - - MemoryRegion iomem; - qemu_irq irq; - qemu_irq fiq; - - uint32_t pending; - uint32_t enabled; - uint32_t is_fiq; - uint32_t int_idle; -} StrongARMPICState; - -#define ICIP 0x00 -#define ICMR 0x04 -#define ICLR 0x08 -#define ICFP 0x10 -#define ICPR 0x20 -#define ICCR 0x0c - -#define SA_PIC_SRCS 32 - - -static void strongarm_pic_update(void *opaque) -{ - StrongARMPICState *s = opaque; - - /* FIXME: reflect DIM */ - qemu_set_irq(s->fiq, s->pending & s->enabled & s->is_fiq); - qemu_set_irq(s->irq, s->pending & s->enabled & ~s->is_fiq); -} - -static void strongarm_pic_set_irq(void *opaque, int irq, int level) -{ - StrongARMPICState *s = opaque; - - if (level) { - s->pending |= 1 << irq; - } else { - s->pending &= ~(1 << irq); - } - - strongarm_pic_update(s); -} - -static uint64_t strongarm_pic_mem_read(void *opaque, hwaddr offset, - unsigned size) -{ - StrongARMPICState *s = opaque; - - switch (offset) { - case ICIP: - return s->pending & ~s->is_fiq & s->enabled; - case ICMR: - return s->enabled; - case ICLR: - return s->is_fiq; - case ICCR: - return s->int_idle == 0; - case ICFP: - return s->pending & s->is_fiq & s->enabled; - case ICPR: - return s->pending; - default: - printf("%s: Bad register offset 0x" TARGET_FMT_plx "\n", - __func__, offset); - return 0; - } -} - -static void strongarm_pic_mem_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - StrongARMPICState *s = opaque; - - switch (offset) { - case ICMR: - s->enabled = value; - break; - case ICLR: - s->is_fiq = value; - break; - case ICCR: - s->int_idle = (value & 1) ? 0 : ~0; - break; - default: - printf("%s: Bad register offset 0x" TARGET_FMT_plx "\n", - __func__, offset); - break; - } - strongarm_pic_update(s); -} - -static const MemoryRegionOps strongarm_pic_ops = { - .read = strongarm_pic_mem_read, - .write = strongarm_pic_mem_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static int strongarm_pic_initfn(SysBusDevice *sbd) -{ - DeviceState *dev = DEVICE(sbd); - StrongARMPICState *s = STRONGARM_PIC(dev); - - qdev_init_gpio_in(dev, strongarm_pic_set_irq, SA_PIC_SRCS); - memory_region_init_io(&s->iomem, OBJECT(s), &strongarm_pic_ops, s, - "pic", 0x1000); - sysbus_init_mmio(sbd, &s->iomem); - sysbus_init_irq(sbd, &s->irq); - sysbus_init_irq(sbd, &s->fiq); - - return 0; -} - -static int strongarm_pic_post_load(void *opaque, int version_id) -{ - strongarm_pic_update(opaque); - return 0; -} - -static VMStateDescription vmstate_strongarm_pic_regs = { - .name = "strongarm_pic", - .version_id = 0, - .minimum_version_id = 0, - .post_load = strongarm_pic_post_load, - .fields = (VMStateField[]) { - VMSTATE_UINT32(pending, StrongARMPICState), - VMSTATE_UINT32(enabled, StrongARMPICState), - VMSTATE_UINT32(is_fiq, StrongARMPICState), - VMSTATE_UINT32(int_idle, StrongARMPICState), - VMSTATE_END_OF_LIST(), - }, -}; - -static void strongarm_pic_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = strongarm_pic_initfn; - dc->desc = "StrongARM PIC"; - dc->vmsd = &vmstate_strongarm_pic_regs; -} - -static const TypeInfo strongarm_pic_info = { - .name = TYPE_STRONGARM_PIC, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(StrongARMPICState), - .class_init = strongarm_pic_class_init, -}; - -/* Real-Time Clock */ -#define RTAR 0x00 /* RTC Alarm register */ -#define RCNR 0x04 /* RTC Counter register */ -#define RTTR 0x08 /* RTC Timer Trim register */ -#define RTSR 0x10 /* RTC Status register */ - -#define RTSR_AL (1 << 0) /* RTC Alarm detected */ -#define RTSR_HZ (1 << 1) /* RTC 1Hz detected */ -#define RTSR_ALE (1 << 2) /* RTC Alarm enable */ -#define RTSR_HZE (1 << 3) /* RTC 1Hz enable */ - -/* 16 LSB of RTTR are clockdiv for internal trim logic, - * trim delete isn't emulated, so - * f = 32 768 / (RTTR_trim + 1) */ - -#define TYPE_STRONGARM_RTC "strongarm-rtc" -#define STRONGARM_RTC(obj) \ - OBJECT_CHECK(StrongARMRTCState, (obj), TYPE_STRONGARM_RTC) - -typedef struct StrongARMRTCState { - SysBusDevice parent_obj; - - MemoryRegion iomem; - uint32_t rttr; - uint32_t rtsr; - uint32_t rtar; - uint32_t last_rcnr; - int64_t last_hz; - QEMUTimer *rtc_alarm; - QEMUTimer *rtc_hz; - qemu_irq rtc_irq; - qemu_irq rtc_hz_irq; -} StrongARMRTCState; - -static inline void strongarm_rtc_int_update(StrongARMRTCState *s) -{ - qemu_set_irq(s->rtc_irq, s->rtsr & RTSR_AL); - qemu_set_irq(s->rtc_hz_irq, s->rtsr & RTSR_HZ); -} - -static void strongarm_rtc_hzupdate(StrongARMRTCState *s) -{ - int64_t rt = qemu_clock_get_ms(rtc_clock); - s->last_rcnr += ((rt - s->last_hz) << 15) / - (1000 * ((s->rttr & 0xffff) + 1)); - s->last_hz = rt; -} - -static inline void strongarm_rtc_timer_update(StrongARMRTCState *s) -{ - if ((s->rtsr & RTSR_HZE) && !(s->rtsr & RTSR_HZ)) { - timer_mod(s->rtc_hz, s->last_hz + 1000); - } else { - timer_del(s->rtc_hz); - } - - if ((s->rtsr & RTSR_ALE) && !(s->rtsr & RTSR_AL)) { - timer_mod(s->rtc_alarm, s->last_hz + - (((s->rtar - s->last_rcnr) * 1000 * - ((s->rttr & 0xffff) + 1)) >> 15)); - } else { - timer_del(s->rtc_alarm); - } -} - -static inline void strongarm_rtc_alarm_tick(void *opaque) -{ - StrongARMRTCState *s = opaque; - s->rtsr |= RTSR_AL; - strongarm_rtc_timer_update(s); - strongarm_rtc_int_update(s); -} - -static inline void strongarm_rtc_hz_tick(void *opaque) -{ - StrongARMRTCState *s = opaque; - s->rtsr |= RTSR_HZ; - strongarm_rtc_timer_update(s); - strongarm_rtc_int_update(s); -} - -static uint64_t strongarm_rtc_read(void *opaque, hwaddr addr, - unsigned size) -{ - StrongARMRTCState *s = opaque; - - switch (addr) { - case RTTR: - return s->rttr; - case RTSR: - return s->rtsr; - case RTAR: - return s->rtar; - case RCNR: - return s->last_rcnr + - ((qemu_clock_get_ms(rtc_clock) - s->last_hz) << 15) / - (1000 * ((s->rttr & 0xffff) + 1)); - default: - printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr); - return 0; - } -} - -static void strongarm_rtc_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - StrongARMRTCState *s = opaque; - uint32_t old_rtsr; - - switch (addr) { - case RTTR: - strongarm_rtc_hzupdate(s); - s->rttr = value; - strongarm_rtc_timer_update(s); - break; - - case RTSR: - old_rtsr = s->rtsr; - s->rtsr = (value & (RTSR_ALE | RTSR_HZE)) | - (s->rtsr & ~(value & (RTSR_AL | RTSR_HZ))); - - if (s->rtsr != old_rtsr) { - strongarm_rtc_timer_update(s); - } - - strongarm_rtc_int_update(s); - break; - - case RTAR: - s->rtar = value; - strongarm_rtc_timer_update(s); - break; - - case RCNR: - strongarm_rtc_hzupdate(s); - s->last_rcnr = value; - strongarm_rtc_timer_update(s); - break; - - default: - printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr); - } -} - -static const MemoryRegionOps strongarm_rtc_ops = { - .read = strongarm_rtc_read, - .write = strongarm_rtc_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static int strongarm_rtc_init(SysBusDevice *dev) -{ - StrongARMRTCState *s = STRONGARM_RTC(dev); - struct tm tm; - - s->rttr = 0x0; - s->rtsr = 0; - - qemu_get_timedate(&tm, 0); - - s->last_rcnr = (uint32_t) mktimegm(&tm); - s->last_hz = qemu_clock_get_ms(rtc_clock); - - s->rtc_alarm = timer_new_ms(rtc_clock, strongarm_rtc_alarm_tick, s); - s->rtc_hz = timer_new_ms(rtc_clock, strongarm_rtc_hz_tick, s); - - sysbus_init_irq(dev, &s->rtc_irq); - sysbus_init_irq(dev, &s->rtc_hz_irq); - - memory_region_init_io(&s->iomem, OBJECT(s), &strongarm_rtc_ops, s, - "rtc", 0x10000); - sysbus_init_mmio(dev, &s->iomem); - - return 0; -} - -static void strongarm_rtc_pre_save(void *opaque) -{ - StrongARMRTCState *s = opaque; - - strongarm_rtc_hzupdate(s); -} - -static int strongarm_rtc_post_load(void *opaque, int version_id) -{ - StrongARMRTCState *s = opaque; - - strongarm_rtc_timer_update(s); - strongarm_rtc_int_update(s); - - return 0; -} - -static const VMStateDescription vmstate_strongarm_rtc_regs = { - .name = "strongarm-rtc", - .version_id = 0, - .minimum_version_id = 0, - .pre_save = strongarm_rtc_pre_save, - .post_load = strongarm_rtc_post_load, - .fields = (VMStateField[]) { - VMSTATE_UINT32(rttr, StrongARMRTCState), - VMSTATE_UINT32(rtsr, StrongARMRTCState), - VMSTATE_UINT32(rtar, StrongARMRTCState), - VMSTATE_UINT32(last_rcnr, StrongARMRTCState), - VMSTATE_INT64(last_hz, StrongARMRTCState), - VMSTATE_END_OF_LIST(), - }, -}; - -static void strongarm_rtc_sysbus_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = strongarm_rtc_init; - dc->desc = "StrongARM RTC Controller"; - dc->vmsd = &vmstate_strongarm_rtc_regs; -} - -static const TypeInfo strongarm_rtc_sysbus_info = { - .name = TYPE_STRONGARM_RTC, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(StrongARMRTCState), - .class_init = strongarm_rtc_sysbus_class_init, -}; - -/* GPIO */ -#define GPLR 0x00 -#define GPDR 0x04 -#define GPSR 0x08 -#define GPCR 0x0c -#define GRER 0x10 -#define GFER 0x14 -#define GEDR 0x18 -#define GAFR 0x1c - -#define TYPE_STRONGARM_GPIO "strongarm-gpio" -#define STRONGARM_GPIO(obj) \ - OBJECT_CHECK(StrongARMGPIOInfo, (obj), TYPE_STRONGARM_GPIO) - -typedef struct StrongARMGPIOInfo StrongARMGPIOInfo; -struct StrongARMGPIOInfo { - SysBusDevice busdev; - MemoryRegion iomem; - qemu_irq handler[28]; - qemu_irq irqs[11]; - qemu_irq irqX; - - uint32_t ilevel; - uint32_t olevel; - uint32_t dir; - uint32_t rising; - uint32_t falling; - uint32_t status; - uint32_t gafr; - - uint32_t prev_level; -}; - - -static void strongarm_gpio_irq_update(StrongARMGPIOInfo *s) -{ - int i; - for (i = 0; i < 11; i++) { - qemu_set_irq(s->irqs[i], s->status & (1 << i)); - } - - qemu_set_irq(s->irqX, (s->status & ~0x7ff)); -} - -static void strongarm_gpio_set(void *opaque, int line, int level) -{ - StrongARMGPIOInfo *s = opaque; - uint32_t mask; - - mask = 1 << line; - - if (level) { - s->status |= s->rising & mask & - ~s->ilevel & ~s->dir; - s->ilevel |= mask; - } else { - s->status |= s->falling & mask & - s->ilevel & ~s->dir; - s->ilevel &= ~mask; - } - - if (s->status & mask) { - strongarm_gpio_irq_update(s); - } -} - -static void strongarm_gpio_handler_update(StrongARMGPIOInfo *s) -{ - uint32_t level, diff; - int bit; - - level = s->olevel & s->dir; - - for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) { - bit = ctz32(diff); - qemu_set_irq(s->handler[bit], (level >> bit) & 1); - } - - s->prev_level = level; -} - -static uint64_t strongarm_gpio_read(void *opaque, hwaddr offset, - unsigned size) -{ - StrongARMGPIOInfo *s = opaque; - - switch (offset) { - case GPDR: /* GPIO Pin-Direction registers */ - return s->dir; - - case GPSR: /* GPIO Pin-Output Set registers */ - qemu_log_mask(LOG_GUEST_ERROR, - "strongarm GPIO: read from write only register GPSR\n"); - return 0; - - case GPCR: /* GPIO Pin-Output Clear registers */ - qemu_log_mask(LOG_GUEST_ERROR, - "strongarm GPIO: read from write only register GPCR\n"); - return 0; - - case GRER: /* GPIO Rising-Edge Detect Enable registers */ - return s->rising; - - case GFER: /* GPIO Falling-Edge Detect Enable registers */ - return s->falling; - - case GAFR: /* GPIO Alternate Function registers */ - return s->gafr; - - case GPLR: /* GPIO Pin-Level registers */ - return (s->olevel & s->dir) | - (s->ilevel & ~s->dir); - - case GEDR: /* GPIO Edge Detect Status registers */ - return s->status; - - default: - printf("%s: Bad offset 0x" TARGET_FMT_plx "\n", __func__, offset); - } - - return 0; -} - -static void strongarm_gpio_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - StrongARMGPIOInfo *s = opaque; - - switch (offset) { - case GPDR: /* GPIO Pin-Direction registers */ - s->dir = value; - strongarm_gpio_handler_update(s); - break; - - case GPSR: /* GPIO Pin-Output Set registers */ - s->olevel |= value; - strongarm_gpio_handler_update(s); - break; - - case GPCR: /* GPIO Pin-Output Clear registers */ - s->olevel &= ~value; - strongarm_gpio_handler_update(s); - break; - - case GRER: /* GPIO Rising-Edge Detect Enable registers */ - s->rising = value; - break; - - case GFER: /* GPIO Falling-Edge Detect Enable registers */ - s->falling = value; - break; - - case GAFR: /* GPIO Alternate Function registers */ - s->gafr = value; - break; - - case GEDR: /* GPIO Edge Detect Status registers */ - s->status &= ~value; - strongarm_gpio_irq_update(s); - break; - - default: - printf("%s: Bad offset 0x" TARGET_FMT_plx "\n", __func__, offset); - } -} - -static const MemoryRegionOps strongarm_gpio_ops = { - .read = strongarm_gpio_read, - .write = strongarm_gpio_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static DeviceState *strongarm_gpio_init(hwaddr base, - DeviceState *pic) -{ - DeviceState *dev; - int i; - - dev = qdev_create(NULL, TYPE_STRONGARM_GPIO); - qdev_init_nofail(dev); - - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); - for (i = 0; i < 12; i++) - sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, - qdev_get_gpio_in(pic, SA_PIC_GPIO0_EDGE + i)); - - return dev; -} - -static int strongarm_gpio_initfn(SysBusDevice *sbd) -{ - DeviceState *dev = DEVICE(sbd); - StrongARMGPIOInfo *s = STRONGARM_GPIO(dev); - int i; - - qdev_init_gpio_in(dev, strongarm_gpio_set, 28); - qdev_init_gpio_out(dev, s->handler, 28); - - memory_region_init_io(&s->iomem, OBJECT(s), &strongarm_gpio_ops, s, - "gpio", 0x1000); - - sysbus_init_mmio(sbd, &s->iomem); - for (i = 0; i < 11; i++) { - sysbus_init_irq(sbd, &s->irqs[i]); - } - sysbus_init_irq(sbd, &s->irqX); - - return 0; -} - -static const VMStateDescription vmstate_strongarm_gpio_regs = { - .name = "strongarm-gpio", - .version_id = 0, - .minimum_version_id = 0, - .fields = (VMStateField[]) { - VMSTATE_UINT32(ilevel, StrongARMGPIOInfo), - VMSTATE_UINT32(olevel, StrongARMGPIOInfo), - VMSTATE_UINT32(dir, StrongARMGPIOInfo), - VMSTATE_UINT32(rising, StrongARMGPIOInfo), - VMSTATE_UINT32(falling, StrongARMGPIOInfo), - VMSTATE_UINT32(status, StrongARMGPIOInfo), - VMSTATE_UINT32(gafr, StrongARMGPIOInfo), - VMSTATE_UINT32(prev_level, StrongARMGPIOInfo), - VMSTATE_END_OF_LIST(), - }, -}; - -static void strongarm_gpio_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = strongarm_gpio_initfn; - dc->desc = "StrongARM GPIO controller"; - dc->vmsd = &vmstate_strongarm_gpio_regs; -} - -static const TypeInfo strongarm_gpio_info = { - .name = TYPE_STRONGARM_GPIO, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(StrongARMGPIOInfo), - .class_init = strongarm_gpio_class_init, -}; - -/* Peripheral Pin Controller */ -#define PPDR 0x00 -#define PPSR 0x04 -#define PPAR 0x08 -#define PSDR 0x0c -#define PPFR 0x10 - -#define TYPE_STRONGARM_PPC "strongarm-ppc" -#define STRONGARM_PPC(obj) \ - OBJECT_CHECK(StrongARMPPCInfo, (obj), TYPE_STRONGARM_PPC) - -typedef struct StrongARMPPCInfo StrongARMPPCInfo; -struct StrongARMPPCInfo { - SysBusDevice parent_obj; - - MemoryRegion iomem; - qemu_irq handler[28]; - - uint32_t ilevel; - uint32_t olevel; - uint32_t dir; - uint32_t ppar; - uint32_t psdr; - uint32_t ppfr; - - uint32_t prev_level; -}; - -static void strongarm_ppc_set(void *opaque, int line, int level) -{ - StrongARMPPCInfo *s = opaque; - - if (level) { - s->ilevel |= 1 << line; - } else { - s->ilevel &= ~(1 << line); - } -} - -static void strongarm_ppc_handler_update(StrongARMPPCInfo *s) -{ - uint32_t level, diff; - int bit; - - level = s->olevel & s->dir; - - for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) { - bit = ctz32(diff); - qemu_set_irq(s->handler[bit], (level >> bit) & 1); - } - - s->prev_level = level; -} - -static uint64_t strongarm_ppc_read(void *opaque, hwaddr offset, - unsigned size) -{ - StrongARMPPCInfo *s = opaque; - - switch (offset) { - case PPDR: /* PPC Pin Direction registers */ - return s->dir | ~0x3fffff; - - case PPSR: /* PPC Pin State registers */ - return (s->olevel & s->dir) | - (s->ilevel & ~s->dir) | - ~0x3fffff; - - case PPAR: - return s->ppar | ~0x41000; - - case PSDR: - return s->psdr; - - case PPFR: - return s->ppfr | ~0x7f001; - - default: - printf("%s: Bad offset 0x" TARGET_FMT_plx "\n", __func__, offset); - } - - return 0; -} - -static void strongarm_ppc_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - StrongARMPPCInfo *s = opaque; - - switch (offset) { - case PPDR: /* PPC Pin Direction registers */ - s->dir = value & 0x3fffff; - strongarm_ppc_handler_update(s); - break; - - case PPSR: /* PPC Pin State registers */ - s->olevel = value & s->dir & 0x3fffff; - strongarm_ppc_handler_update(s); - break; - - case PPAR: - s->ppar = value & 0x41000; - break; - - case PSDR: - s->psdr = value & 0x3fffff; - break; - - case PPFR: - s->ppfr = value & 0x7f001; - break; - - default: - printf("%s: Bad offset 0x" TARGET_FMT_plx "\n", __func__, offset); - } -} - -static const MemoryRegionOps strongarm_ppc_ops = { - .read = strongarm_ppc_read, - .write = strongarm_ppc_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static int strongarm_ppc_init(SysBusDevice *sbd) -{ - DeviceState *dev = DEVICE(sbd); - StrongARMPPCInfo *s = STRONGARM_PPC(dev); - - qdev_init_gpio_in(dev, strongarm_ppc_set, 22); - qdev_init_gpio_out(dev, s->handler, 22); - - memory_region_init_io(&s->iomem, OBJECT(s), &strongarm_ppc_ops, s, - "ppc", 0x1000); - - sysbus_init_mmio(sbd, &s->iomem); - - return 0; -} - -static const VMStateDescription vmstate_strongarm_ppc_regs = { - .name = "strongarm-ppc", - .version_id = 0, - .minimum_version_id = 0, - .fields = (VMStateField[]) { - VMSTATE_UINT32(ilevel, StrongARMPPCInfo), - VMSTATE_UINT32(olevel, StrongARMPPCInfo), - VMSTATE_UINT32(dir, StrongARMPPCInfo), - VMSTATE_UINT32(ppar, StrongARMPPCInfo), - VMSTATE_UINT32(psdr, StrongARMPPCInfo), - VMSTATE_UINT32(ppfr, StrongARMPPCInfo), - VMSTATE_UINT32(prev_level, StrongARMPPCInfo), - VMSTATE_END_OF_LIST(), - }, -}; - -static void strongarm_ppc_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = strongarm_ppc_init; - dc->desc = "StrongARM PPC controller"; - dc->vmsd = &vmstate_strongarm_ppc_regs; -} - -static const TypeInfo strongarm_ppc_info = { - .name = TYPE_STRONGARM_PPC, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(StrongARMPPCInfo), - .class_init = strongarm_ppc_class_init, -}; - -/* UART Ports */ -#define UTCR0 0x00 -#define UTCR1 0x04 -#define UTCR2 0x08 -#define UTCR3 0x0c -#define UTDR 0x14 -#define UTSR0 0x1c -#define UTSR1 0x20 - -#define UTCR0_PE (1 << 0) /* Parity enable */ -#define UTCR0_OES (1 << 1) /* Even parity */ -#define UTCR0_SBS (1 << 2) /* 2 stop bits */ -#define UTCR0_DSS (1 << 3) /* 8-bit data */ - -#define UTCR3_RXE (1 << 0) /* Rx enable */ -#define UTCR3_TXE (1 << 1) /* Tx enable */ -#define UTCR3_BRK (1 << 2) /* Force Break */ -#define UTCR3_RIE (1 << 3) /* Rx int enable */ -#define UTCR3_TIE (1 << 4) /* Tx int enable */ -#define UTCR3_LBM (1 << 5) /* Loopback */ - -#define UTSR0_TFS (1 << 0) /* Tx FIFO nearly empty */ -#define UTSR0_RFS (1 << 1) /* Rx FIFO nearly full */ -#define UTSR0_RID (1 << 2) /* Receiver Idle */ -#define UTSR0_RBB (1 << 3) /* Receiver begin break */ -#define UTSR0_REB (1 << 4) /* Receiver end break */ -#define UTSR0_EIF (1 << 5) /* Error in FIFO */ - -#define UTSR1_RNE (1 << 1) /* Receive FIFO not empty */ -#define UTSR1_TNF (1 << 2) /* Transmit FIFO not full */ -#define UTSR1_PRE (1 << 3) /* Parity error */ -#define UTSR1_FRE (1 << 4) /* Frame error */ -#define UTSR1_ROR (1 << 5) /* Receive Over Run */ - -#define RX_FIFO_PRE (1 << 8) -#define RX_FIFO_FRE (1 << 9) -#define RX_FIFO_ROR (1 << 10) - -#define TYPE_STRONGARM_UART "strongarm-uart" -#define STRONGARM_UART(obj) \ - OBJECT_CHECK(StrongARMUARTState, (obj), TYPE_STRONGARM_UART) - -typedef struct StrongARMUARTState { - SysBusDevice parent_obj; - - MemoryRegion iomem; - CharDriverState *chr; - qemu_irq irq; - - uint8_t utcr0; - uint16_t brd; - uint8_t utcr3; - uint8_t utsr0; - uint8_t utsr1; - - uint8_t tx_fifo[8]; - uint8_t tx_start; - uint8_t tx_len; - uint16_t rx_fifo[12]; /* value + error flags in high bits */ - uint8_t rx_start; - uint8_t rx_len; - - uint64_t char_transmit_time; /* time to transmit a char in ticks*/ - bool wait_break_end; - QEMUTimer *rx_timeout_timer; - QEMUTimer *tx_timer; -} StrongARMUARTState; - -static void strongarm_uart_update_status(StrongARMUARTState *s) -{ - uint16_t utsr1 = 0; - - if (s->tx_len != 8) { - utsr1 |= UTSR1_TNF; - } - - if (s->rx_len != 0) { - uint16_t ent = s->rx_fifo[s->rx_start]; - - utsr1 |= UTSR1_RNE; - if (ent & RX_FIFO_PRE) { - s->utsr1 |= UTSR1_PRE; - } - if (ent & RX_FIFO_FRE) { - s->utsr1 |= UTSR1_FRE; - } - if (ent & RX_FIFO_ROR) { - s->utsr1 |= UTSR1_ROR; - } - } - - s->utsr1 = utsr1; -} - -static void strongarm_uart_update_int_status(StrongARMUARTState *s) -{ - uint16_t utsr0 = s->utsr0 & - (UTSR0_REB | UTSR0_RBB | UTSR0_RID); - int i; - - if ((s->utcr3 & UTCR3_TXE) && - (s->utcr3 & UTCR3_TIE) && - s->tx_len <= 4) { - utsr0 |= UTSR0_TFS; - } - - if ((s->utcr3 & UTCR3_RXE) && - (s->utcr3 & UTCR3_RIE) && - s->rx_len > 4) { - utsr0 |= UTSR0_RFS; - } - - for (i = 0; i < s->rx_len && i < 4; i++) - if (s->rx_fifo[(s->rx_start + i) % 12] & ~0xff) { - utsr0 |= UTSR0_EIF; - break; - } - - s->utsr0 = utsr0; - qemu_set_irq(s->irq, utsr0); -} - -static void strongarm_uart_update_parameters(StrongARMUARTState *s) -{ - int speed, parity, data_bits, stop_bits, frame_size; - QEMUSerialSetParams ssp; - - /* Start bit. */ - frame_size = 1; - if (s->utcr0 & UTCR0_PE) { - /* Parity bit. */ - frame_size++; - if (s->utcr0 & UTCR0_OES) { - parity = 'E'; - } else { - parity = 'O'; - } - } else { - parity = 'N'; - } - if (s->utcr0 & UTCR0_SBS) { - stop_bits = 2; - } else { - stop_bits = 1; - } - - data_bits = (s->utcr0 & UTCR0_DSS) ? 8 : 7; - frame_size += data_bits + stop_bits; - speed = 3686400 / 16 / (s->brd + 1); - ssp.speed = speed; - ssp.parity = parity; - ssp.data_bits = data_bits; - ssp.stop_bits = stop_bits; - s->char_transmit_time = (NANOSECONDS_PER_SECOND / speed) * frame_size; - if (s->chr) { - qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp); - } - - DPRINTF(stderr, "%s speed=%d parity=%c data=%d stop=%d\n", s->chr->label, - speed, parity, data_bits, stop_bits); -} - -static void strongarm_uart_rx_to(void *opaque) -{ - StrongARMUARTState *s = opaque; - - if (s->rx_len) { - s->utsr0 |= UTSR0_RID; - strongarm_uart_update_int_status(s); - } -} - -static void strongarm_uart_rx_push(StrongARMUARTState *s, uint16_t c) -{ - if ((s->utcr3 & UTCR3_RXE) == 0) { - /* rx disabled */ - return; - } - - if (s->wait_break_end) { - s->utsr0 |= UTSR0_REB; - s->wait_break_end = false; - } - - if (s->rx_len < 12) { - s->rx_fifo[(s->rx_start + s->rx_len) % 12] = c; - s->rx_len++; - } else - s->rx_fifo[(s->rx_start + 11) % 12] |= RX_FIFO_ROR; -} - -static int strongarm_uart_can_receive(void *opaque) -{ - StrongARMUARTState *s = opaque; - - if (s->rx_len == 12) { - return 0; - } - /* It's best not to get more than 2/3 of RX FIFO, so advertise that much */ - if (s->rx_len < 8) { - return 8 - s->rx_len; - } - return 1; -} - -static void strongarm_uart_receive(void *opaque, const uint8_t *buf, int size) -{ - StrongARMUARTState *s = opaque; - int i; - - for (i = 0; i < size; i++) { - strongarm_uart_rx_push(s, buf[i]); - } - - /* call the timeout receive callback in 3 char transmit time */ - timer_mod(s->rx_timeout_timer, - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->char_transmit_time * 3); - - strongarm_uart_update_status(s); - strongarm_uart_update_int_status(s); -} - -static void strongarm_uart_event(void *opaque, int event) -{ - StrongARMUARTState *s = opaque; - if (event == CHR_EVENT_BREAK) { - s->utsr0 |= UTSR0_RBB; - strongarm_uart_rx_push(s, RX_FIFO_FRE); - s->wait_break_end = true; - strongarm_uart_update_status(s); - strongarm_uart_update_int_status(s); - } -} - -static void strongarm_uart_tx(void *opaque) -{ - StrongARMUARTState *s = opaque; - uint64_t new_xmit_ts = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - - if (s->utcr3 & UTCR3_LBM) /* loopback */ { - strongarm_uart_receive(s, &s->tx_fifo[s->tx_start], 1); - } else if (s->chr) { - qemu_chr_fe_write(s->chr, &s->tx_fifo[s->tx_start], 1); - } - - s->tx_start = (s->tx_start + 1) % 8; - s->tx_len--; - if (s->tx_len) { - timer_mod(s->tx_timer, new_xmit_ts + s->char_transmit_time); - } - strongarm_uart_update_status(s); - strongarm_uart_update_int_status(s); -} - -static uint64_t strongarm_uart_read(void *opaque, hwaddr addr, - unsigned size) -{ - StrongARMUARTState *s = opaque; - uint16_t ret; - - switch (addr) { - case UTCR0: - return s->utcr0; - - case UTCR1: - return s->brd >> 8; - - case UTCR2: - return s->brd & 0xff; - - case UTCR3: - return s->utcr3; - - case UTDR: - if (s->rx_len != 0) { - ret = s->rx_fifo[s->rx_start]; - s->rx_start = (s->rx_start + 1) % 12; - s->rx_len--; - strongarm_uart_update_status(s); - strongarm_uart_update_int_status(s); - return ret; - } - return 0; - - case UTSR0: - return s->utsr0; - - case UTSR1: - return s->utsr1; - - default: - printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr); - return 0; - } -} - -static void strongarm_uart_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - StrongARMUARTState *s = opaque; - - switch (addr) { - case UTCR0: - s->utcr0 = value & 0x7f; - strongarm_uart_update_parameters(s); - break; - - case UTCR1: - s->brd = (s->brd & 0xff) | ((value & 0xf) << 8); - strongarm_uart_update_parameters(s); - break; - - case UTCR2: - s->brd = (s->brd & 0xf00) | (value & 0xff); - strongarm_uart_update_parameters(s); - break; - - case UTCR3: - s->utcr3 = value & 0x3f; - if ((s->utcr3 & UTCR3_RXE) == 0) { - s->rx_len = 0; - } - if ((s->utcr3 & UTCR3_TXE) == 0) { - s->tx_len = 0; - } - strongarm_uart_update_status(s); - strongarm_uart_update_int_status(s); - break; - - case UTDR: - if ((s->utcr3 & UTCR3_TXE) && s->tx_len != 8) { - s->tx_fifo[(s->tx_start + s->tx_len) % 8] = value; - s->tx_len++; - strongarm_uart_update_status(s); - strongarm_uart_update_int_status(s); - if (s->tx_len == 1) { - strongarm_uart_tx(s); - } - } - break; - - case UTSR0: - s->utsr0 = s->utsr0 & ~(value & - (UTSR0_REB | UTSR0_RBB | UTSR0_RID)); - strongarm_uart_update_int_status(s); - break; - - default: - printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr); - } -} - -static const MemoryRegionOps strongarm_uart_ops = { - .read = strongarm_uart_read, - .write = strongarm_uart_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static int strongarm_uart_init(SysBusDevice *dev) -{ - StrongARMUARTState *s = STRONGARM_UART(dev); - - memory_region_init_io(&s->iomem, OBJECT(s), &strongarm_uart_ops, s, - "uart", 0x10000); - sysbus_init_mmio(dev, &s->iomem); - sysbus_init_irq(dev, &s->irq); - - s->rx_timeout_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, strongarm_uart_rx_to, s); - s->tx_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, strongarm_uart_tx, s); - - if (s->chr) { - qemu_chr_add_handlers(s->chr, - strongarm_uart_can_receive, - strongarm_uart_receive, - strongarm_uart_event, - s); - } - - return 0; -} - -static void strongarm_uart_reset(DeviceState *dev) -{ - StrongARMUARTState *s = STRONGARM_UART(dev); - - s->utcr0 = UTCR0_DSS; /* 8 data, no parity */ - s->brd = 23; /* 9600 */ - /* enable send & recv - this actually violates spec */ - s->utcr3 = UTCR3_TXE | UTCR3_RXE; - - s->rx_len = s->tx_len = 0; - - strongarm_uart_update_parameters(s); - strongarm_uart_update_status(s); - strongarm_uart_update_int_status(s); -} - -static int strongarm_uart_post_load(void *opaque, int version_id) -{ - StrongARMUARTState *s = opaque; - - strongarm_uart_update_parameters(s); - strongarm_uart_update_status(s); - strongarm_uart_update_int_status(s); - - /* tx and restart timer */ - if (s->tx_len) { - strongarm_uart_tx(s); - } - - /* restart rx timeout timer */ - if (s->rx_len) { - timer_mod(s->rx_timeout_timer, - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->char_transmit_time * 3); - } - - return 0; -} - -static const VMStateDescription vmstate_strongarm_uart_regs = { - .name = "strongarm-uart", - .version_id = 0, - .minimum_version_id = 0, - .post_load = strongarm_uart_post_load, - .fields = (VMStateField[]) { - VMSTATE_UINT8(utcr0, StrongARMUARTState), - VMSTATE_UINT16(brd, StrongARMUARTState), - VMSTATE_UINT8(utcr3, StrongARMUARTState), - VMSTATE_UINT8(utsr0, StrongARMUARTState), - VMSTATE_UINT8_ARRAY(tx_fifo, StrongARMUARTState, 8), - VMSTATE_UINT8(tx_start, StrongARMUARTState), - VMSTATE_UINT8(tx_len, StrongARMUARTState), - VMSTATE_UINT16_ARRAY(rx_fifo, StrongARMUARTState, 12), - VMSTATE_UINT8(rx_start, StrongARMUARTState), - VMSTATE_UINT8(rx_len, StrongARMUARTState), - VMSTATE_BOOL(wait_break_end, StrongARMUARTState), - VMSTATE_END_OF_LIST(), - }, -}; - -static Property strongarm_uart_properties[] = { - DEFINE_PROP_CHR("chardev", StrongARMUARTState, chr), - DEFINE_PROP_END_OF_LIST(), -}; - -static void strongarm_uart_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = strongarm_uart_init; - dc->desc = "StrongARM UART controller"; - dc->reset = strongarm_uart_reset; - dc->vmsd = &vmstate_strongarm_uart_regs; - dc->props = strongarm_uart_properties; -} - -static const TypeInfo strongarm_uart_info = { - .name = TYPE_STRONGARM_UART, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(StrongARMUARTState), - .class_init = strongarm_uart_class_init, -}; - -/* Synchronous Serial Ports */ - -#define TYPE_STRONGARM_SSP "strongarm-ssp" -#define STRONGARM_SSP(obj) \ - OBJECT_CHECK(StrongARMSSPState, (obj), TYPE_STRONGARM_SSP) - -typedef struct StrongARMSSPState { - SysBusDevice parent_obj; - - MemoryRegion iomem; - qemu_irq irq; - SSIBus *bus; - - uint16_t sscr[2]; - uint16_t sssr; - - uint16_t rx_fifo[8]; - uint8_t rx_level; - uint8_t rx_start; -} StrongARMSSPState; - -#define SSCR0 0x60 /* SSP Control register 0 */ -#define SSCR1 0x64 /* SSP Control register 1 */ -#define SSDR 0x6c /* SSP Data register */ -#define SSSR 0x74 /* SSP Status register */ - -/* Bitfields for above registers */ -#define SSCR0_SPI(x) (((x) & 0x30) == 0x00) -#define SSCR0_SSP(x) (((x) & 0x30) == 0x10) -#define SSCR0_UWIRE(x) (((x) & 0x30) == 0x20) -#define SSCR0_PSP(x) (((x) & 0x30) == 0x30) -#define SSCR0_SSE (1 << 7) -#define SSCR0_DSS(x) (((x) & 0xf) + 1) -#define SSCR1_RIE (1 << 0) -#define SSCR1_TIE (1 << 1) -#define SSCR1_LBM (1 << 2) -#define SSSR_TNF (1 << 2) -#define SSSR_RNE (1 << 3) -#define SSSR_TFS (1 << 5) -#define SSSR_RFS (1 << 6) -#define SSSR_ROR (1 << 7) -#define SSSR_RW 0x0080 - -static void strongarm_ssp_int_update(StrongARMSSPState *s) -{ - int level = 0; - - level |= (s->sssr & SSSR_ROR); - level |= (s->sssr & SSSR_RFS) && (s->sscr[1] & SSCR1_RIE); - level |= (s->sssr & SSSR_TFS) && (s->sscr[1] & SSCR1_TIE); - qemu_set_irq(s->irq, level); -} - -static void strongarm_ssp_fifo_update(StrongARMSSPState *s) -{ - s->sssr &= ~SSSR_TFS; - s->sssr &= ~SSSR_TNF; - if (s->sscr[0] & SSCR0_SSE) { - if (s->rx_level >= 4) { - s->sssr |= SSSR_RFS; - } else { - s->sssr &= ~SSSR_RFS; - } - if (s->rx_level) { - s->sssr |= SSSR_RNE; - } else { - s->sssr &= ~SSSR_RNE; - } - /* TX FIFO is never filled, so it is always in underrun - condition if SSP is enabled */ - s->sssr |= SSSR_TFS; - s->sssr |= SSSR_TNF; - } - - strongarm_ssp_int_update(s); -} - -static uint64_t strongarm_ssp_read(void *opaque, hwaddr addr, - unsigned size) -{ - StrongARMSSPState *s = opaque; - uint32_t retval; - - switch (addr) { - case SSCR0: - return s->sscr[0]; - case SSCR1: - return s->sscr[1]; - case SSSR: - return s->sssr; - case SSDR: - if (~s->sscr[0] & SSCR0_SSE) { - return 0xffffffff; - } - if (s->rx_level < 1) { - printf("%s: SSP Rx Underrun\n", __func__); - return 0xffffffff; - } - s->rx_level--; - retval = s->rx_fifo[s->rx_start++]; - s->rx_start &= 0x7; - strongarm_ssp_fifo_update(s); - return retval; - default: - printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr); - break; - } - return 0; -} - -static void strongarm_ssp_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - StrongARMSSPState *s = opaque; - - switch (addr) { - case SSCR0: - s->sscr[0] = value & 0xffbf; - if ((s->sscr[0] & SSCR0_SSE) && SSCR0_DSS(value) < 4) { - printf("%s: Wrong data size: %i bits\n", __func__, - (int)SSCR0_DSS(value)); - } - if (!(value & SSCR0_SSE)) { - s->sssr = 0; - s->rx_level = 0; - } - strongarm_ssp_fifo_update(s); - break; - - case SSCR1: - s->sscr[1] = value & 0x2f; - if (value & SSCR1_LBM) { - printf("%s: Attempt to use SSP LBM mode\n", __func__); - } - strongarm_ssp_fifo_update(s); - break; - - case SSSR: - s->sssr &= ~(value & SSSR_RW); - strongarm_ssp_int_update(s); - break; - - case SSDR: - if (SSCR0_UWIRE(s->sscr[0])) { - value &= 0xff; - } else - /* Note how 32bits overflow does no harm here */ - value &= (1 << SSCR0_DSS(s->sscr[0])) - 1; - - /* Data goes from here to the Tx FIFO and is shifted out from - * there directly to the slave, no need to buffer it. - */ - if (s->sscr[0] & SSCR0_SSE) { - uint32_t readval; - if (s->sscr[1] & SSCR1_LBM) { - readval = value; - } else { - readval = ssi_transfer(s->bus, value); - } - - if (s->rx_level < 0x08) { - s->rx_fifo[(s->rx_start + s->rx_level++) & 0x7] = readval; - } else { - s->sssr |= SSSR_ROR; - } - } - strongarm_ssp_fifo_update(s); - break; - - default: - printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr); - break; - } -} - -static const MemoryRegionOps strongarm_ssp_ops = { - .read = strongarm_ssp_read, - .write = strongarm_ssp_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static int strongarm_ssp_post_load(void *opaque, int version_id) -{ - StrongARMSSPState *s = opaque; - - strongarm_ssp_fifo_update(s); - - return 0; -} - -static int strongarm_ssp_init(SysBusDevice *sbd) -{ - DeviceState *dev = DEVICE(sbd); - StrongARMSSPState *s = STRONGARM_SSP(dev); - - sysbus_init_irq(sbd, &s->irq); - - memory_region_init_io(&s->iomem, OBJECT(s), &strongarm_ssp_ops, s, - "ssp", 0x1000); - sysbus_init_mmio(sbd, &s->iomem); - - s->bus = ssi_create_bus(dev, "ssi"); - return 0; -} - -static void strongarm_ssp_reset(DeviceState *dev) -{ - StrongARMSSPState *s = STRONGARM_SSP(dev); - - s->sssr = 0x03; /* 3 bit data, SPI, disabled */ - s->rx_start = 0; - s->rx_level = 0; -} - -static const VMStateDescription vmstate_strongarm_ssp_regs = { - .name = "strongarm-ssp", - .version_id = 0, - .minimum_version_id = 0, - .post_load = strongarm_ssp_post_load, - .fields = (VMStateField[]) { - VMSTATE_UINT16_ARRAY(sscr, StrongARMSSPState, 2), - VMSTATE_UINT16(sssr, StrongARMSSPState), - VMSTATE_UINT16_ARRAY(rx_fifo, StrongARMSSPState, 8), - VMSTATE_UINT8(rx_start, StrongARMSSPState), - VMSTATE_UINT8(rx_level, StrongARMSSPState), - VMSTATE_END_OF_LIST(), - }, -}; - -static void strongarm_ssp_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = strongarm_ssp_init; - dc->desc = "StrongARM SSP controller"; - dc->reset = strongarm_ssp_reset; - dc->vmsd = &vmstate_strongarm_ssp_regs; -} - -static const TypeInfo strongarm_ssp_info = { - .name = TYPE_STRONGARM_SSP, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(StrongARMSSPState), - .class_init = strongarm_ssp_class_init, -}; - -/* Main CPU functions */ -StrongARMState *sa1110_init(MemoryRegion *sysmem, - unsigned int sdram_size, const char *rev) -{ - StrongARMState *s; - int i; - - s = g_new0(StrongARMState, 1); - - if (!rev) { - rev = "sa1110-b5"; - } - - if (strncmp(rev, "sa1110", 6)) { - error_report("Machine requires a SA1110 processor."); - exit(1); - } - - s->cpu = cpu_arm_init(rev); - - if (!s->cpu) { - error_report("Unable to find CPU definition"); - exit(1); - } - - memory_region_allocate_system_memory(&s->sdram, NULL, "strongarm.sdram", - sdram_size); - memory_region_add_subregion(sysmem, SA_SDCS0, &s->sdram); - - s->pic = sysbus_create_varargs("strongarm_pic", 0x90050000, - qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_IRQ), - qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_FIQ), - NULL); - - sysbus_create_varargs("pxa25x-timer", 0x90000000, - qdev_get_gpio_in(s->pic, SA_PIC_OSTC0), - qdev_get_gpio_in(s->pic, SA_PIC_OSTC1), - qdev_get_gpio_in(s->pic, SA_PIC_OSTC2), - qdev_get_gpio_in(s->pic, SA_PIC_OSTC3), - NULL); - - sysbus_create_simple(TYPE_STRONGARM_RTC, 0x90010000, - qdev_get_gpio_in(s->pic, SA_PIC_RTC_ALARM)); - - s->gpio = strongarm_gpio_init(0x90040000, s->pic); - - s->ppc = sysbus_create_varargs(TYPE_STRONGARM_PPC, 0x90060000, NULL); - - for (i = 0; sa_serial[i].io_base; i++) { - DeviceState *dev = qdev_create(NULL, TYPE_STRONGARM_UART); - qdev_prop_set_chr(dev, "chardev", serial_hds[i]); - qdev_init_nofail(dev); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, - sa_serial[i].io_base); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, - qdev_get_gpio_in(s->pic, sa_serial[i].irq)); - } - - s->ssp = sysbus_create_varargs(TYPE_STRONGARM_SSP, 0x80070000, - qdev_get_gpio_in(s->pic, SA_PIC_SSP), NULL); - s->ssp_bus = (SSIBus *)qdev_get_child_bus(s->ssp, "ssi"); - - return s; -} - -static void strongarm_register_types(void) -{ - type_register_static(&strongarm_pic_info); - type_register_static(&strongarm_rtc_sysbus_info); - type_register_static(&strongarm_gpio_info); - type_register_static(&strongarm_ppc_info); - type_register_static(&strongarm_uart_info); - type_register_static(&strongarm_ssp_info); -} - -type_init(strongarm_register_types) diff --git a/qemu/hw/arm/strongarm.h b/qemu/hw/arm/strongarm.h deleted file mode 100644 index 2893f9444..000000000 --- a/qemu/hw/arm/strongarm.h +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef _STRONGARM_H -#define _STRONGARM_H - -#include "exec/memory.h" - -#define SA_CS0 0x00000000 -#define SA_CS1 0x08000000 -#define SA_CS2 0x10000000 -#define SA_CS3 0x18000000 -#define SA_PCMCIA_CS0 0x20000000 -#define SA_PCMCIA_CS1 0x30000000 -#define SA_CS4 0x40000000 -#define SA_CS5 0x48000000 -/* system registers here */ -#define SA_SDCS0 0xc0000000 -#define SA_SDCS1 0xc8000000 -#define SA_SDCS2 0xd0000000 -#define SA_SDCS3 0xd8000000 - -enum { - SA_PIC_GPIO0_EDGE = 0, - SA_PIC_GPIO1_EDGE, - SA_PIC_GPIO2_EDGE, - SA_PIC_GPIO3_EDGE, - SA_PIC_GPIO4_EDGE, - SA_PIC_GPIO5_EDGE, - SA_PIC_GPIO6_EDGE, - SA_PIC_GPIO7_EDGE, - SA_PIC_GPIO8_EDGE, - SA_PIC_GPIO9_EDGE, - SA_PIC_GPIO10_EDGE, - SA_PIC_GPIOX_EDGE, - SA_PIC_LCD, - SA_PIC_UDC, - SA_PIC_RSVD1, - SA_PIC_UART1, - SA_PIC_UART2, - SA_PIC_UART3, - SA_PIC_MCP, - SA_PIC_SSP, - SA_PIC_DMA_CH0, - SA_PIC_DMA_CH1, - SA_PIC_DMA_CH2, - SA_PIC_DMA_CH3, - SA_PIC_DMA_CH4, - SA_PIC_DMA_CH5, - SA_PIC_OSTC0, - SA_PIC_OSTC1, - SA_PIC_OSTC2, - SA_PIC_OSTC3, - SA_PIC_RTC_HZ, - SA_PIC_RTC_ALARM, -}; - -typedef struct { - ARMCPU *cpu; - MemoryRegion sdram; - DeviceState *pic; - DeviceState *gpio; - DeviceState *ppc; - DeviceState *ssp; - SSIBus *ssp_bus; -} StrongARMState; - -StrongARMState *sa1110_init(MemoryRegion *sysmem, - unsigned int sdram_size, const char *rev); - -#endif diff --git a/qemu/hw/arm/sysbus-fdt.c b/qemu/hw/arm/sysbus-fdt.c deleted file mode 100644 index 5debb3348..000000000 --- a/qemu/hw/arm/sysbus-fdt.c +++ /dev/null @@ -1,542 +0,0 @@ -/* - * ARM Platform Bus device tree generation helpers - * - * Copyright (c) 2014 Linaro Limited - * - * Authors: - * Alex Graf <agraf@suse.de> - * Eric Auger <eric.auger@linaro.org> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2 or later, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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 <http://www.gnu.org/licenses/>. - * - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include <libfdt.h> -#include "qemu-common.h" -#ifdef CONFIG_LINUX -#include <linux/vfio.h> -#endif -#include "hw/arm/sysbus-fdt.h" -#include "qemu/error-report.h" -#include "sysemu/device_tree.h" -#include "hw/platform-bus.h" -#include "sysemu/sysemu.h" -#include "hw/vfio/vfio-platform.h" -#include "hw/vfio/vfio-calxeda-xgmac.h" -#include "hw/vfio/vfio-amd-xgbe.h" -#include "hw/arm/fdt.h" - -/* - * internal struct that contains the information to create dynamic - * sysbus device node - */ -typedef struct PlatformBusFDTData { - void *fdt; /* device tree handle */ - int irq_start; /* index of the first IRQ usable by platform bus devices */ - const char *pbus_node_name; /* name of the platform bus node */ - PlatformBusDevice *pbus; -} PlatformBusFDTData; - -/* - * struct used when calling the machine init done notifier - * that constructs the fdt nodes of platform bus devices - */ -typedef struct PlatformBusFDTNotifierParams { - Notifier notifier; - ARMPlatformBusFDTParams *fdt_params; -} PlatformBusFDTNotifierParams; - -/* struct that associates a device type name and a node creation function */ -typedef struct NodeCreationPair { - const char *typename; - int (*add_fdt_node_fn)(SysBusDevice *sbdev, void *opaque); -} NodeCreationPair; - -/* helpers */ - -typedef struct HostProperty { - const char *name; - bool optional; -} HostProperty; - -#ifdef CONFIG_LINUX - -/** - * copy_properties_from_host - * - * copies properties listed in an array from host device tree to - * guest device tree. If a non optional property is not found, the - * function asserts. An optional property is ignored if not found - * in the host device tree. - * @props: array of HostProperty to copy - * @nb_props: number of properties in the array - * @host_dt: host device tree blob - * @guest_dt: guest device tree blob - * @node_path: host dt node path where the property is supposed to be - found - * @nodename: guest node name the properties should be added to - */ -static void copy_properties_from_host(HostProperty *props, int nb_props, - void *host_fdt, void *guest_fdt, - char *node_path, char *nodename) -{ - int i, prop_len; - const void *r; - Error *err = NULL; - - for (i = 0; i < nb_props; i++) { - r = qemu_fdt_getprop(host_fdt, node_path, - props[i].name, - &prop_len, - props[i].optional ? &err : &error_fatal); - if (r) { - qemu_fdt_setprop(guest_fdt, nodename, - props[i].name, r, prop_len); - } else { - if (prop_len != -FDT_ERR_NOTFOUND) { - /* optional property not returned although property exists */ - error_report_err(err); - } else { - error_free(err); - } - } - } -} - -/* clock properties whose values are copied/pasted from host */ -static HostProperty clock_copied_properties[] = { - {"compatible", false}, - {"#clock-cells", false}, - {"clock-frequency", true}, - {"clock-output-names", true}, -}; - -/** - * fdt_build_clock_node - * - * Build a guest clock node, used as a dependency from a passthrough'ed - * device. Most information are retrieved from the host clock node. - * Also check the host clock is a fixed one. - * - * @host_fdt: host device tree blob from which info are retrieved - * @guest_fdt: guest device tree blob where the clock node is added - * @host_phandle: phandle of the clock in host device tree - * @guest_phandle: phandle to assign to the guest node - */ -static void fdt_build_clock_node(void *host_fdt, void *guest_fdt, - uint32_t host_phandle, - uint32_t guest_phandle) -{ - char *node_path = NULL; - char *nodename; - const void *r; - int ret, node_offset, prop_len, path_len = 16; - - node_offset = fdt_node_offset_by_phandle(host_fdt, host_phandle); - if (node_offset <= 0) { - error_setg(&error_fatal, - "not able to locate clock handle %d in host device tree", - host_phandle); - } - node_path = g_malloc(path_len); - while ((ret = fdt_get_path(host_fdt, node_offset, node_path, path_len)) - == -FDT_ERR_NOSPACE) { - path_len += 16; - node_path = g_realloc(node_path, path_len); - } - if (ret < 0) { - error_setg(&error_fatal, - "not able to retrieve node path for clock handle %d", - host_phandle); - } - - r = qemu_fdt_getprop(host_fdt, node_path, "compatible", &prop_len, - &error_fatal); - if (strcmp(r, "fixed-clock")) { - error_setg(&error_fatal, - "clock handle %d is not a fixed clock", host_phandle); - } - - nodename = strrchr(node_path, '/'); - qemu_fdt_add_subnode(guest_fdt, nodename); - - copy_properties_from_host(clock_copied_properties, - ARRAY_SIZE(clock_copied_properties), - host_fdt, guest_fdt, - node_path, nodename); - - qemu_fdt_setprop_cell(guest_fdt, nodename, "phandle", guest_phandle); - - g_free(node_path); -} - -/** - * sysfs_to_dt_name: convert the name found in sysfs into the node name - * for instance e0900000.xgmac is converted into xgmac@e0900000 - * @sysfs_name: directory name in sysfs - * - * returns the device tree name upon success or NULL in case the sysfs name - * does not match the expected format - */ -static char *sysfs_to_dt_name(const char *sysfs_name) -{ - gchar **substrings = g_strsplit(sysfs_name, ".", 2); - char *dt_name = NULL; - - if (!substrings || !substrings[0] || !substrings[1]) { - goto out; - } - dt_name = g_strdup_printf("%s@%s", substrings[1], substrings[0]); -out: - g_strfreev(substrings); - return dt_name; -} - -/* Device Specific Code */ - -/** - * add_calxeda_midway_xgmac_fdt_node - * - * Generates a simple node with following properties: - * compatible string, regs, interrupts, dma-coherent - */ -static int add_calxeda_midway_xgmac_fdt_node(SysBusDevice *sbdev, void *opaque) -{ - PlatformBusFDTData *data = opaque; - PlatformBusDevice *pbus = data->pbus; - void *fdt = data->fdt; - const char *parent_node = data->pbus_node_name; - int compat_str_len, i; - char *nodename; - uint32_t *irq_attr, *reg_attr; - uint64_t mmio_base, irq_number; - VFIOPlatformDevice *vdev = VFIO_PLATFORM_DEVICE(sbdev); - VFIODevice *vbasedev = &vdev->vbasedev; - - mmio_base = platform_bus_get_mmio_addr(pbus, sbdev, 0); - nodename = g_strdup_printf("%s/%s@%" PRIx64, parent_node, - vbasedev->name, mmio_base); - qemu_fdt_add_subnode(fdt, nodename); - - compat_str_len = strlen(vdev->compat) + 1; - qemu_fdt_setprop(fdt, nodename, "compatible", - vdev->compat, compat_str_len); - - qemu_fdt_setprop(fdt, nodename, "dma-coherent", "", 0); - - reg_attr = g_new(uint32_t, vbasedev->num_regions * 2); - for (i = 0; i < vbasedev->num_regions; i++) { - mmio_base = platform_bus_get_mmio_addr(pbus, sbdev, i); - reg_attr[2 * i] = cpu_to_be32(mmio_base); - reg_attr[2 * i + 1] = cpu_to_be32( - memory_region_size(vdev->regions[i]->mem)); - } - qemu_fdt_setprop(fdt, nodename, "reg", reg_attr, - vbasedev->num_regions * 2 * sizeof(uint32_t)); - - irq_attr = g_new(uint32_t, vbasedev->num_irqs * 3); - for (i = 0; i < vbasedev->num_irqs; i++) { - irq_number = platform_bus_get_irqn(pbus, sbdev , i) - + data->irq_start; - irq_attr[3 * i] = cpu_to_be32(GIC_FDT_IRQ_TYPE_SPI); - irq_attr[3 * i + 1] = cpu_to_be32(irq_number); - irq_attr[3 * i + 2] = cpu_to_be32(GIC_FDT_IRQ_FLAGS_LEVEL_HI); - } - qemu_fdt_setprop(fdt, nodename, "interrupts", - irq_attr, vbasedev->num_irqs * 3 * sizeof(uint32_t)); - g_free(irq_attr); - g_free(reg_attr); - g_free(nodename); - return 0; -} - -/* AMD xgbe properties whose values are copied/pasted from host */ -static HostProperty amd_xgbe_copied_properties[] = { - {"compatible", false}, - {"dma-coherent", true}, - {"amd,per-channel-interrupt", true}, - {"phy-mode", false}, - {"mac-address", true}, - {"amd,speed-set", false}, - {"amd,serdes-blwc", true}, - {"amd,serdes-cdr-rate", true}, - {"amd,serdes-pq-skew", true}, - {"amd,serdes-tx-amp", true}, - {"amd,serdes-dfe-tap-config", true}, - {"amd,serdes-dfe-tap-enable", true}, - {"clock-names", false}, -}; - -/** - * add_amd_xgbe_fdt_node - * - * Generates the combined xgbe/phy node following kernel >=4.2 - * binding documentation: - * Documentation/devicetree/bindings/net/amd-xgbe.txt: - * Also 2 clock nodes are created (dma and ptp) - * - * Asserts in case of error - */ -static int add_amd_xgbe_fdt_node(SysBusDevice *sbdev, void *opaque) -{ - PlatformBusFDTData *data = opaque; - PlatformBusDevice *pbus = data->pbus; - VFIOPlatformDevice *vdev = VFIO_PLATFORM_DEVICE(sbdev); - VFIODevice *vbasedev = &vdev->vbasedev; - VFIOINTp *intp; - const char *parent_node = data->pbus_node_name; - char **node_path, *nodename, *dt_name; - void *guest_fdt = data->fdt, *host_fdt; - const void *r; - int i, prop_len; - uint32_t *irq_attr, *reg_attr, *host_clock_phandles; - uint64_t mmio_base, irq_number; - uint32_t guest_clock_phandles[2]; - - host_fdt = load_device_tree_from_sysfs(); - - dt_name = sysfs_to_dt_name(vbasedev->name); - if (!dt_name) { - error_setg(&error_fatal, "%s incorrect sysfs device name %s", - __func__, vbasedev->name); - } - node_path = qemu_fdt_node_path(host_fdt, dt_name, vdev->compat, - &error_fatal); - if (!node_path || !node_path[0]) { - error_setg(&error_fatal, "%s unable to retrieve node path for %s/%s", - __func__, dt_name, vdev->compat); - } - - if (node_path[1]) { - error_setg(&error_fatal, "%s more than one node matching %s/%s!", - __func__, dt_name, vdev->compat); - } - - g_free(dt_name); - - if (vbasedev->num_regions != 5) { - error_setg(&error_fatal, "%s Does the host dt node combine XGBE/PHY?", - __func__); - } - - /* generate nodes for DMA_CLK and PTP_CLK */ - r = qemu_fdt_getprop(host_fdt, node_path[0], "clocks", - &prop_len, &error_fatal); - if (prop_len != 8) { - error_setg(&error_fatal, "%s clocks property should contain 2 handles", - __func__); - } - host_clock_phandles = (uint32_t *)r; - guest_clock_phandles[0] = qemu_fdt_alloc_phandle(guest_fdt); - guest_clock_phandles[1] = qemu_fdt_alloc_phandle(guest_fdt); - - /** - * clock handles fetched from host dt are in be32 layout whereas - * rest of the code uses cpu layout. Also guest clock handles are - * in cpu layout. - */ - fdt_build_clock_node(host_fdt, guest_fdt, - be32_to_cpu(host_clock_phandles[0]), - guest_clock_phandles[0]); - - fdt_build_clock_node(host_fdt, guest_fdt, - be32_to_cpu(host_clock_phandles[1]), - guest_clock_phandles[1]); - - /* combined XGBE/PHY node */ - mmio_base = platform_bus_get_mmio_addr(pbus, sbdev, 0); - nodename = g_strdup_printf("%s/%s@%" PRIx64, parent_node, - vbasedev->name, mmio_base); - qemu_fdt_add_subnode(guest_fdt, nodename); - - copy_properties_from_host(amd_xgbe_copied_properties, - ARRAY_SIZE(amd_xgbe_copied_properties), - host_fdt, guest_fdt, - node_path[0], nodename); - - qemu_fdt_setprop_cells(guest_fdt, nodename, "clocks", - guest_clock_phandles[0], - guest_clock_phandles[1]); - - reg_attr = g_new(uint32_t, vbasedev->num_regions * 2); - for (i = 0; i < vbasedev->num_regions; i++) { - mmio_base = platform_bus_get_mmio_addr(pbus, sbdev, i); - reg_attr[2 * i] = cpu_to_be32(mmio_base); - reg_attr[2 * i + 1] = cpu_to_be32( - memory_region_size(vdev->regions[i]->mem)); - } - qemu_fdt_setprop(guest_fdt, nodename, "reg", reg_attr, - vbasedev->num_regions * 2 * sizeof(uint32_t)); - - irq_attr = g_new(uint32_t, vbasedev->num_irqs * 3); - for (i = 0; i < vbasedev->num_irqs; i++) { - irq_number = platform_bus_get_irqn(pbus, sbdev , i) - + data->irq_start; - irq_attr[3 * i] = cpu_to_be32(GIC_FDT_IRQ_TYPE_SPI); - irq_attr[3 * i + 1] = cpu_to_be32(irq_number); - /* - * General device interrupt and PCS auto-negotiation interrupts are - * level-sensitive while the 4 per-channel interrupts are edge - * sensitive - */ - QLIST_FOREACH(intp, &vdev->intp_list, next) { - if (intp->pin == i) { - break; - } - } - if (intp->flags & VFIO_IRQ_INFO_AUTOMASKED) { - irq_attr[3 * i + 2] = cpu_to_be32(GIC_FDT_IRQ_FLAGS_LEVEL_HI); - } else { - irq_attr[3 * i + 2] = cpu_to_be32(GIC_FDT_IRQ_FLAGS_EDGE_LO_HI); - } - } - qemu_fdt_setprop(guest_fdt, nodename, "interrupts", - irq_attr, vbasedev->num_irqs * 3 * sizeof(uint32_t)); - - g_free(host_fdt); - g_strfreev(node_path); - g_free(irq_attr); - g_free(reg_attr); - g_free(nodename); - return 0; -} - -#endif /* CONFIG_LINUX */ - -/* list of supported dynamic sysbus devices */ -static const NodeCreationPair add_fdt_node_functions[] = { -#ifdef CONFIG_LINUX - {TYPE_VFIO_CALXEDA_XGMAC, add_calxeda_midway_xgmac_fdt_node}, - {TYPE_VFIO_AMD_XGBE, add_amd_xgbe_fdt_node}, -#endif - {"", NULL}, /* last element */ -}; - -/* Generic Code */ - -/** - * add_fdt_node - add the device tree node of a dynamic sysbus device - * - * @sbdev: handle to the sysbus device - * @opaque: handle to the PlatformBusFDTData - * - * Checks the sysbus type belongs to the list of device types that - * are dynamically instantiable and if so call the node creation - * function. - */ -static int add_fdt_node(SysBusDevice *sbdev, void *opaque) -{ - int i, ret; - - for (i = 0; i < ARRAY_SIZE(add_fdt_node_functions); i++) { - if (!strcmp(object_get_typename(OBJECT(sbdev)), - add_fdt_node_functions[i].typename)) { - ret = add_fdt_node_functions[i].add_fdt_node_fn(sbdev, opaque); - assert(!ret); - return 0; - } - } - error_report("Device %s can not be dynamically instantiated", - qdev_fw_name(DEVICE(sbdev))); - exit(1); -} - -/** - * add_all_platform_bus_fdt_nodes - create all the platform bus nodes - * - * builds the parent platform bus node and all the nodes of dynamic - * sysbus devices attached to it. - */ -static void add_all_platform_bus_fdt_nodes(ARMPlatformBusFDTParams *fdt_params) -{ - const char platcomp[] = "qemu,platform\0simple-bus"; - PlatformBusDevice *pbus; - DeviceState *dev; - gchar *node; - uint64_t addr, size; - int irq_start, dtb_size; - struct arm_boot_info *info = fdt_params->binfo; - const ARMPlatformBusSystemParams *params = fdt_params->system_params; - const char *intc = fdt_params->intc; - void *fdt = info->get_dtb(info, &dtb_size); - - /* - * If the user provided a dtb, we assume the dynamic sysbus nodes - * already are integrated there. This corresponds to a use case where - * the dynamic sysbus nodes are complex and their generation is not yet - * supported. In that case the user can take charge of the guest dt - * while qemu takes charge of the qom stuff. - */ - if (info->dtb_filename) { - return; - } - - assert(fdt); - - node = g_strdup_printf("/platform@%"PRIx64, params->platform_bus_base); - addr = params->platform_bus_base; - size = params->platform_bus_size; - irq_start = params->platform_bus_first_irq; - - /* Create a /platform node that we can put all devices into */ - qemu_fdt_add_subnode(fdt, node); - qemu_fdt_setprop(fdt, node, "compatible", platcomp, sizeof(platcomp)); - - /* Our platform bus region is less than 32bits, so 1 cell is enough for - * address and size - */ - qemu_fdt_setprop_cells(fdt, node, "#size-cells", 1); - qemu_fdt_setprop_cells(fdt, node, "#address-cells", 1); - qemu_fdt_setprop_cells(fdt, node, "ranges", 0, addr >> 32, addr, size); - - qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", intc); - - dev = qdev_find_recursive(sysbus_get_default(), TYPE_PLATFORM_BUS_DEVICE); - pbus = PLATFORM_BUS_DEVICE(dev); - - /* We can only create dt nodes for dynamic devices when they're ready */ - assert(pbus->done_gathering); - - PlatformBusFDTData data = { - .fdt = fdt, - .irq_start = irq_start, - .pbus_node_name = node, - .pbus = pbus, - }; - - /* Loop through all dynamic sysbus devices and create their node */ - foreach_dynamic_sysbus_device(add_fdt_node, &data); - - g_free(node); -} - -static void platform_bus_fdt_notify(Notifier *notifier, void *data) -{ - PlatformBusFDTNotifierParams *p = DO_UPCAST(PlatformBusFDTNotifierParams, - notifier, notifier); - - add_all_platform_bus_fdt_nodes(p->fdt_params); - g_free(p->fdt_params); - g_free(p); -} - -void arm_register_platform_bus_fdt_creator(ARMPlatformBusFDTParams *fdt_params) -{ - PlatformBusFDTNotifierParams *p = g_new(PlatformBusFDTNotifierParams, 1); - - p->fdt_params = fdt_params; - p->notifier.notify = platform_bus_fdt_notify; - qemu_add_machine_init_done_notifier(&p->notifier); -} diff --git a/qemu/hw/arm/tosa.c b/qemu/hw/arm/tosa.c deleted file mode 100644 index 4e9494f94..000000000 --- a/qemu/hw/arm/tosa.c +++ /dev/null @@ -1,303 +0,0 @@ -/* vim:set shiftwidth=4 ts=4 et: */ -/* - * PXA255 Sharp Zaurus SL-6000 PDA platform - * - * Copyright (c) 2008 Dmitry Baryshkov - * - * Code based on spitz platform by Andrzej Zaborowski <balrog@zabor.org> - * 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 "qemu/osdep.h" -#include "qapi/error.h" -#include "hw/hw.h" -#include "hw/arm/pxa.h" -#include "hw/arm/arm.h" -#include "hw/devices.h" -#include "hw/arm/sharpsl.h" -#include "hw/pcmcia.h" -#include "hw/boards.h" -#include "hw/i2c/i2c.h" -#include "hw/ssi/ssi.h" -#include "sysemu/block-backend.h" -#include "hw/sysbus.h" -#include "exec/address-spaces.h" - -#define TOSA_RAM 0x04000000 -#define TOSA_ROM 0x00800000 - -#define TOSA_GPIO_USB_IN (5) -#define TOSA_GPIO_nSD_DETECT (9) -#define TOSA_GPIO_ON_RESET (19) -#define TOSA_GPIO_CF_IRQ (21) /* CF slot0 Ready */ -#define TOSA_GPIO_CF_CD (13) -#define TOSA_GPIO_TC6393XB_INT (15) -#define TOSA_GPIO_JC_CF_IRQ (36) /* CF slot1 Ready */ - -#define TOSA_SCOOP_GPIO_BASE 1 -#define TOSA_GPIO_IR_POWERDWN (TOSA_SCOOP_GPIO_BASE + 2) -#define TOSA_GPIO_SD_WP (TOSA_SCOOP_GPIO_BASE + 3) -#define TOSA_GPIO_PWR_ON (TOSA_SCOOP_GPIO_BASE + 4) - -#define TOSA_SCOOP_JC_GPIO_BASE 1 -#define TOSA_GPIO_BT_LED (TOSA_SCOOP_JC_GPIO_BASE + 0) -#define TOSA_GPIO_NOTE_LED (TOSA_SCOOP_JC_GPIO_BASE + 1) -#define TOSA_GPIO_CHRG_ERR_LED (TOSA_SCOOP_JC_GPIO_BASE + 2) -#define TOSA_GPIO_TC6393XB_L3V_ON (TOSA_SCOOP_JC_GPIO_BASE + 5) -#define TOSA_GPIO_WLAN_LED (TOSA_SCOOP_JC_GPIO_BASE + 7) - -#define DAC_BASE 0x4e -#define DAC_CH1 0 -#define DAC_CH2 1 - -static void tosa_microdrive_attach(PXA2xxState *cpu) -{ - PCMCIACardState *md; - DriveInfo *dinfo; - - dinfo = drive_get(IF_IDE, 0, 0); - if (!dinfo || dinfo->media_cd) - return; - md = dscm1xxxx_init(dinfo); - pxa2xx_pcmcia_attach(cpu->pcmcia[0], md); -} - -static void tosa_out_switch(void *opaque, int line, int level) -{ - switch (line) { - case 0: - fprintf(stderr, "blue LED %s.\n", level ? "on" : "off"); - break; - case 1: - fprintf(stderr, "green LED %s.\n", level ? "on" : "off"); - break; - case 2: - fprintf(stderr, "amber LED %s.\n", level ? "on" : "off"); - break; - case 3: - fprintf(stderr, "wlan LED %s.\n", level ? "on" : "off"); - break; - default: - fprintf(stderr, "Uhandled out event: %d = %d\n", line, level); - break; - } -} - - -static void tosa_gpio_setup(PXA2xxState *cpu, - DeviceState *scp0, - DeviceState *scp1, - TC6393xbState *tmio) -{ - qemu_irq *outsignals = qemu_allocate_irqs(tosa_out_switch, cpu, 4); - /* MMC/SD host */ - pxa2xx_mmci_handlers(cpu->mmc, - qdev_get_gpio_in(scp0, TOSA_GPIO_SD_WP), - qemu_irq_invert(qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_nSD_DETECT))); - - /* Handle reset */ - qdev_connect_gpio_out(cpu->gpio, TOSA_GPIO_ON_RESET, cpu->reset); - - /* PCMCIA signals: card's IRQ and Card-Detect */ - pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[0], - qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_CF_IRQ), - qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_CF_CD)); - - pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[1], - qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_JC_CF_IRQ), - NULL); - - qdev_connect_gpio_out(scp1, TOSA_GPIO_BT_LED, outsignals[0]); - qdev_connect_gpio_out(scp1, TOSA_GPIO_NOTE_LED, outsignals[1]); - qdev_connect_gpio_out(scp1, TOSA_GPIO_CHRG_ERR_LED, outsignals[2]); - qdev_connect_gpio_out(scp1, TOSA_GPIO_WLAN_LED, outsignals[3]); - - qdev_connect_gpio_out(scp1, TOSA_GPIO_TC6393XB_L3V_ON, tc6393xb_l3v_get(tmio)); - - /* UDC Vbus */ - qemu_irq_raise(qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_USB_IN)); -} - -static uint32_t tosa_ssp_tansfer(SSISlave *dev, uint32_t value) -{ - fprintf(stderr, "TG: %d %02x\n", value >> 5, value & 0x1f); - return 0; -} - -static int tosa_ssp_init(SSISlave *dev) -{ - /* Nothing to do. */ - return 0; -} - -#define TYPE_TOSA_DAC "tosa_dac" -#define TOSA_DAC(obj) OBJECT_CHECK(TosaDACState, (obj), TYPE_TOSA_DAC) - -typedef struct { - I2CSlave parent_obj; - - int len; - char buf[3]; -} TosaDACState; - -static int tosa_dac_send(I2CSlave *i2c, uint8_t data) -{ - TosaDACState *s = TOSA_DAC(i2c); - - s->buf[s->len] = data; - if (s->len ++ > 2) { -#ifdef VERBOSE - fprintf(stderr, "%s: message too long (%i bytes)\n", __FUNCTION__, s->len); -#endif - return 1; - } - - if (s->len == 2) { - fprintf(stderr, "dac: channel %d value 0x%02x\n", - s->buf[0], s->buf[1]); - } - - return 0; -} - -static void tosa_dac_event(I2CSlave *i2c, enum i2c_event event) -{ - TosaDACState *s = TOSA_DAC(i2c); - - s->len = 0; - switch (event) { - case I2C_START_SEND: - break; - case I2C_START_RECV: - printf("%s: recv not supported!!!\n", __FUNCTION__); - break; - case I2C_FINISH: -#ifdef VERBOSE - if (s->len < 2) - printf("%s: message too short (%i bytes)\n", __FUNCTION__, s->len); - if (s->len > 2) - printf("%s: message too long\n", __FUNCTION__); -#endif - break; - default: - break; - } -} - -static int tosa_dac_recv(I2CSlave *s) -{ - printf("%s: recv not supported!!!\n", __FUNCTION__); - return -1; -} - -static int tosa_dac_init(I2CSlave *i2c) -{ - /* Nothing to do. */ - return 0; -} - -static void tosa_tg_init(PXA2xxState *cpu) -{ - I2CBus *bus = pxa2xx_i2c_bus(cpu->i2c[0]); - i2c_create_slave(bus, TYPE_TOSA_DAC, DAC_BASE); - ssi_create_slave(cpu->ssp[1], "tosa-ssp"); -} - - -static struct arm_boot_info tosa_binfo = { - .loader_start = PXA2XX_SDRAM_BASE, - .ram_size = 0x04000000, -}; - -static void tosa_init(MachineState *machine) -{ - const char *cpu_model = machine->cpu_model; - const char *kernel_filename = machine->kernel_filename; - const char *kernel_cmdline = machine->kernel_cmdline; - const char *initrd_filename = machine->initrd_filename; - MemoryRegion *address_space_mem = get_system_memory(); - MemoryRegion *rom = g_new(MemoryRegion, 1); - PXA2xxState *mpu; - TC6393xbState *tmio; - DeviceState *scp0, *scp1; - - if (!cpu_model) - cpu_model = "pxa255"; - - mpu = pxa255_init(address_space_mem, tosa_binfo.ram_size); - - memory_region_init_ram(rom, NULL, "tosa.rom", TOSA_ROM, &error_fatal); - vmstate_register_ram_global(rom); - memory_region_set_readonly(rom, true); - memory_region_add_subregion(address_space_mem, 0, rom); - - tmio = tc6393xb_init(address_space_mem, 0x10000000, - qdev_get_gpio_in(mpu->gpio, TOSA_GPIO_TC6393XB_INT)); - - scp0 = sysbus_create_simple("scoop", 0x08800000, NULL); - scp1 = sysbus_create_simple("scoop", 0x14800040, NULL); - - tosa_gpio_setup(mpu, scp0, scp1, tmio); - - tosa_microdrive_attach(mpu); - - tosa_tg_init(mpu); - - tosa_binfo.kernel_filename = kernel_filename; - tosa_binfo.kernel_cmdline = kernel_cmdline; - tosa_binfo.initrd_filename = initrd_filename; - tosa_binfo.board_id = 0x208; - arm_load_kernel(mpu->cpu, &tosa_binfo); - sl_bootparam_write(SL_PXA_PARAM_BASE); -} - -static void tosapda_machine_init(MachineClass *mc) -{ - mc->desc = "Sharp SL-6000 (Tosa) PDA (PXA255)"; - mc->init = tosa_init; -} - -DEFINE_MACHINE("tosa", tosapda_machine_init) - -static void tosa_dac_class_init(ObjectClass *klass, void *data) -{ - I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); - - k->init = tosa_dac_init; - k->event = tosa_dac_event; - k->recv = tosa_dac_recv; - k->send = tosa_dac_send; -} - -static const TypeInfo tosa_dac_info = { - .name = TYPE_TOSA_DAC, - .parent = TYPE_I2C_SLAVE, - .instance_size = sizeof(TosaDACState), - .class_init = tosa_dac_class_init, -}; - -static void tosa_ssp_class_init(ObjectClass *klass, void *data) -{ - SSISlaveClass *k = SSI_SLAVE_CLASS(klass); - - k->init = tosa_ssp_init; - k->transfer = tosa_ssp_tansfer; -} - -static const TypeInfo tosa_ssp_info = { - .name = "tosa-ssp", - .parent = TYPE_SSI_SLAVE, - .instance_size = sizeof(SSISlave), - .class_init = tosa_ssp_class_init, -}; - -static void tosa_register_types(void) -{ - type_register_static(&tosa_dac_info); - type_register_static(&tosa_ssp_info); -} - -type_init(tosa_register_types) diff --git a/qemu/hw/arm/versatilepb.c b/qemu/hw/arm/versatilepb.c deleted file mode 100644 index e5a80c2d2..000000000 --- a/qemu/hw/arm/versatilepb.c +++ /dev/null @@ -1,448 +0,0 @@ -/* - * ARM Versatile Platform/Application Baseboard System emulation. - * - * Copyright (c) 2005-2007 CodeSourcery. - * Written by Paul Brook - * - * This code is licensed under the GPL. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "qemu-common.h" -#include "cpu.h" -#include "hw/sysbus.h" -#include "hw/arm/arm.h" -#include "hw/devices.h" -#include "net/net.h" -#include "sysemu/sysemu.h" -#include "hw/pci/pci.h" -#include "hw/i2c/i2c.h" -#include "hw/boards.h" -#include "sysemu/block-backend.h" -#include "exec/address-spaces.h" -#include "hw/block/flash.h" -#include "qemu/error-report.h" - -#define VERSATILE_FLASH_ADDR 0x34000000 -#define VERSATILE_FLASH_SIZE (64 * 1024 * 1024) -#define VERSATILE_FLASH_SECT_SIZE (256 * 1024) - -/* Primary interrupt controller. */ - -#define TYPE_VERSATILE_PB_SIC "versatilepb_sic" -#define VERSATILE_PB_SIC(obj) \ - OBJECT_CHECK(vpb_sic_state, (obj), TYPE_VERSATILE_PB_SIC) - -typedef struct vpb_sic_state { - SysBusDevice parent_obj; - - MemoryRegion iomem; - uint32_t level; - uint32_t mask; - uint32_t pic_enable; - qemu_irq parent[32]; - int irq; -} vpb_sic_state; - -static const VMStateDescription vmstate_vpb_sic = { - .name = "versatilepb_sic", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(level, vpb_sic_state), - VMSTATE_UINT32(mask, vpb_sic_state), - VMSTATE_UINT32(pic_enable, vpb_sic_state), - VMSTATE_END_OF_LIST() - } -}; - -static void vpb_sic_update(vpb_sic_state *s) -{ - uint32_t flags; - - flags = s->level & s->mask; - qemu_set_irq(s->parent[s->irq], flags != 0); -} - -static void vpb_sic_update_pic(vpb_sic_state *s) -{ - int i; - uint32_t mask; - - for (i = 21; i <= 30; i++) { - mask = 1u << i; - if (!(s->pic_enable & mask)) - continue; - qemu_set_irq(s->parent[i], (s->level & mask) != 0); - } -} - -static void vpb_sic_set_irq(void *opaque, int irq, int level) -{ - vpb_sic_state *s = (vpb_sic_state *)opaque; - if (level) - s->level |= 1u << irq; - else - s->level &= ~(1u << irq); - if (s->pic_enable & (1u << irq)) - qemu_set_irq(s->parent[irq], level); - vpb_sic_update(s); -} - -static uint64_t vpb_sic_read(void *opaque, hwaddr offset, - unsigned size) -{ - vpb_sic_state *s = (vpb_sic_state *)opaque; - - switch (offset >> 2) { - case 0: /* STATUS */ - return s->level & s->mask; - case 1: /* RAWSTAT */ - return s->level; - case 2: /* ENABLE */ - return s->mask; - case 4: /* SOFTINT */ - return s->level & 1; - case 8: /* PICENABLE */ - return s->pic_enable; - default: - printf ("vpb_sic_read: Bad register offset 0x%x\n", (int)offset); - return 0; - } -} - -static void vpb_sic_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - vpb_sic_state *s = (vpb_sic_state *)opaque; - - switch (offset >> 2) { - case 2: /* ENSET */ - s->mask |= value; - break; - case 3: /* ENCLR */ - s->mask &= ~value; - break; - case 4: /* SOFTINTSET */ - if (value) - s->mask |= 1; - break; - case 5: /* SOFTINTCLR */ - if (value) - s->mask &= ~1u; - break; - case 8: /* PICENSET */ - s->pic_enable |= (value & 0x7fe00000); - vpb_sic_update_pic(s); - break; - case 9: /* PICENCLR */ - s->pic_enable &= ~value; - vpb_sic_update_pic(s); - break; - default: - printf ("vpb_sic_write: Bad register offset 0x%x\n", (int)offset); - return; - } - vpb_sic_update(s); -} - -static const MemoryRegionOps vpb_sic_ops = { - .read = vpb_sic_read, - .write = vpb_sic_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static int vpb_sic_init(SysBusDevice *sbd) -{ - DeviceState *dev = DEVICE(sbd); - vpb_sic_state *s = VERSATILE_PB_SIC(dev); - int i; - - qdev_init_gpio_in(dev, vpb_sic_set_irq, 32); - for (i = 0; i < 32; i++) { - sysbus_init_irq(sbd, &s->parent[i]); - } - s->irq = 31; - memory_region_init_io(&s->iomem, OBJECT(s), &vpb_sic_ops, s, - "vpb-sic", 0x1000); - sysbus_init_mmio(sbd, &s->iomem); - return 0; -} - -/* Board init. */ - -/* The AB and PB boards both use the same core, just with different - peripherals and expansion busses. For now we emulate a subset of the - PB peripherals and just change the board ID. */ - -static struct arm_boot_info versatile_binfo; - -static void versatile_init(MachineState *machine, int board_id) -{ - ObjectClass *cpu_oc; - Object *cpuobj; - ARMCPU *cpu; - MemoryRegion *sysmem = get_system_memory(); - MemoryRegion *ram = g_new(MemoryRegion, 1); - qemu_irq pic[32]; - qemu_irq sic[32]; - DeviceState *dev, *sysctl; - SysBusDevice *busdev; - DeviceState *pl041; - PCIBus *pci_bus; - NICInfo *nd; - I2CBus *i2c; - int n; - int done_smc = 0; - DriveInfo *dinfo; - - if (!machine->cpu_model) { - machine->cpu_model = "arm926"; - } - - cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, machine->cpu_model); - if (!cpu_oc) { - fprintf(stderr, "Unable to find CPU definition\n"); - exit(1); - } - - cpuobj = object_new(object_class_get_name(cpu_oc)); - - /* By default ARM1176 CPUs have EL3 enabled. This board does not - * currently support EL3 so the CPU EL3 property is disabled before - * realization. - */ - if (object_property_find(cpuobj, "has_el3", NULL)) { - object_property_set_bool(cpuobj, false, "has_el3", &error_fatal); - } - - object_property_set_bool(cpuobj, true, "realized", &error_fatal); - - cpu = ARM_CPU(cpuobj); - - memory_region_allocate_system_memory(ram, NULL, "versatile.ram", - machine->ram_size); - /* ??? RAM should repeat to fill physical memory space. */ - /* SDRAM at address zero. */ - memory_region_add_subregion(sysmem, 0, ram); - - sysctl = qdev_create(NULL, "realview_sysctl"); - qdev_prop_set_uint32(sysctl, "sys_id", 0x41007004); - qdev_prop_set_uint32(sysctl, "proc_id", 0x02000000); - qdev_init_nofail(sysctl); - sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, 0x10000000); - - dev = sysbus_create_varargs("pl190", 0x10140000, - qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ), - qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_FIQ), - NULL); - for (n = 0; n < 32; n++) { - pic[n] = qdev_get_gpio_in(dev, n); - } - dev = sysbus_create_simple(TYPE_VERSATILE_PB_SIC, 0x10003000, NULL); - for (n = 0; n < 32; n++) { - sysbus_connect_irq(SYS_BUS_DEVICE(dev), n, pic[n]); - sic[n] = qdev_get_gpio_in(dev, n); - } - - sysbus_create_simple("pl050_keyboard", 0x10006000, sic[3]); - sysbus_create_simple("pl050_mouse", 0x10007000, sic[4]); - - dev = qdev_create(NULL, "versatile_pci"); - busdev = SYS_BUS_DEVICE(dev); - qdev_init_nofail(dev); - sysbus_mmio_map(busdev, 0, 0x10001000); /* PCI controller regs */ - sysbus_mmio_map(busdev, 1, 0x41000000); /* PCI self-config */ - sysbus_mmio_map(busdev, 2, 0x42000000); /* PCI config */ - sysbus_mmio_map(busdev, 3, 0x43000000); /* PCI I/O */ - sysbus_mmio_map(busdev, 4, 0x44000000); /* PCI memory window 1 */ - sysbus_mmio_map(busdev, 5, 0x50000000); /* PCI memory window 2 */ - sysbus_mmio_map(busdev, 6, 0x60000000); /* PCI memory window 3 */ - sysbus_connect_irq(busdev, 0, sic[27]); - sysbus_connect_irq(busdev, 1, sic[28]); - sysbus_connect_irq(busdev, 2, sic[29]); - sysbus_connect_irq(busdev, 3, sic[30]); - pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci"); - - for(n = 0; n < nb_nics; n++) { - nd = &nd_table[n]; - - if (!done_smc && (!nd->model || strcmp(nd->model, "smc91c111") == 0)) { - smc91c111_init(nd, 0x10010000, sic[25]); - done_smc = 1; - } else { - pci_nic_init_nofail(nd, pci_bus, "rtl8139", NULL); - } - } - if (usb_enabled()) { - pci_create_simple(pci_bus, -1, "pci-ohci"); - } - n = drive_get_max_bus(IF_SCSI); - while (n >= 0) { - pci_create_simple(pci_bus, -1, "lsi53c895a"); - n--; - } - - sysbus_create_simple("pl011", 0x101f1000, pic[12]); - sysbus_create_simple("pl011", 0x101f2000, pic[13]); - sysbus_create_simple("pl011", 0x101f3000, pic[14]); - sysbus_create_simple("pl011", 0x10009000, sic[6]); - - sysbus_create_simple("pl080", 0x10130000, pic[17]); - sysbus_create_simple("sp804", 0x101e2000, pic[4]); - sysbus_create_simple("sp804", 0x101e3000, pic[5]); - - sysbus_create_simple("pl061", 0x101e4000, pic[6]); - sysbus_create_simple("pl061", 0x101e5000, pic[7]); - sysbus_create_simple("pl061", 0x101e6000, pic[8]); - sysbus_create_simple("pl061", 0x101e7000, pic[9]); - - /* The versatile/PB actually has a modified Color LCD controller - that includes hardware cursor support from the PL111. */ - dev = sysbus_create_simple("pl110_versatile", 0x10120000, pic[16]); - /* Wire up the mux control signals from the SYS_CLCD register */ - qdev_connect_gpio_out(sysctl, 0, qdev_get_gpio_in(dev, 0)); - - sysbus_create_varargs("pl181", 0x10005000, sic[22], sic[1], NULL); - sysbus_create_varargs("pl181", 0x1000b000, sic[23], sic[2], NULL); - - /* Add PL031 Real Time Clock. */ - sysbus_create_simple("pl031", 0x101e8000, pic[10]); - - dev = sysbus_create_simple("versatile_i2c", 0x10002000, NULL); - i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c"); - i2c_create_slave(i2c, "ds1338", 0x68); - - /* Add PL041 AACI Interface to the LM4549 codec */ - pl041 = qdev_create(NULL, "pl041"); - qdev_prop_set_uint32(pl041, "nc_fifo_depth", 512); - qdev_init_nofail(pl041); - sysbus_mmio_map(SYS_BUS_DEVICE(pl041), 0, 0x10004000); - sysbus_connect_irq(SYS_BUS_DEVICE(pl041), 0, sic[24]); - - /* Memory map for Versatile/PB: */ - /* 0x10000000 System registers. */ - /* 0x10001000 PCI controller config registers. */ - /* 0x10002000 Serial bus interface. */ - /* 0x10003000 Secondary interrupt controller. */ - /* 0x10004000 AACI (audio). */ - /* 0x10005000 MMCI0. */ - /* 0x10006000 KMI0 (keyboard). */ - /* 0x10007000 KMI1 (mouse). */ - /* 0x10008000 Character LCD Interface. */ - /* 0x10009000 UART3. */ - /* 0x1000a000 Smart card 1. */ - /* 0x1000b000 MMCI1. */ - /* 0x10010000 Ethernet. */ - /* 0x10020000 USB. */ - /* 0x10100000 SSMC. */ - /* 0x10110000 MPMC. */ - /* 0x10120000 CLCD Controller. */ - /* 0x10130000 DMA Controller. */ - /* 0x10140000 Vectored interrupt controller. */ - /* 0x101d0000 AHB Monitor Interface. */ - /* 0x101e0000 System Controller. */ - /* 0x101e1000 Watchdog Interface. */ - /* 0x101e2000 Timer 0/1. */ - /* 0x101e3000 Timer 2/3. */ - /* 0x101e4000 GPIO port 0. */ - /* 0x101e5000 GPIO port 1. */ - /* 0x101e6000 GPIO port 2. */ - /* 0x101e7000 GPIO port 3. */ - /* 0x101e8000 RTC. */ - /* 0x101f0000 Smart card 0. */ - /* 0x101f1000 UART0. */ - /* 0x101f2000 UART1. */ - /* 0x101f3000 UART2. */ - /* 0x101f4000 SSPI. */ - /* 0x34000000 NOR Flash */ - - dinfo = drive_get(IF_PFLASH, 0, 0); - if (!pflash_cfi01_register(VERSATILE_FLASH_ADDR, NULL, "versatile.flash", - VERSATILE_FLASH_SIZE, - dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, - VERSATILE_FLASH_SECT_SIZE, - VERSATILE_FLASH_SIZE / VERSATILE_FLASH_SECT_SIZE, - 4, 0x0089, 0x0018, 0x0000, 0x0, 0)) { - fprintf(stderr, "qemu: Error registering flash memory.\n"); - } - - versatile_binfo.ram_size = machine->ram_size; - versatile_binfo.kernel_filename = machine->kernel_filename; - versatile_binfo.kernel_cmdline = machine->kernel_cmdline; - versatile_binfo.initrd_filename = machine->initrd_filename; - versatile_binfo.board_id = board_id; - arm_load_kernel(cpu, &versatile_binfo); -} - -static void vpb_init(MachineState *machine) -{ - versatile_init(machine, 0x183); -} - -static void vab_init(MachineState *machine) -{ - versatile_init(machine, 0x25e); -} - -static void versatilepb_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "ARM Versatile/PB (ARM926EJ-S)"; - mc->init = vpb_init; - mc->block_default_type = IF_SCSI; -} - -static const TypeInfo versatilepb_type = { - .name = MACHINE_TYPE_NAME("versatilepb"), - .parent = TYPE_MACHINE, - .class_init = versatilepb_class_init, -}; - -static void versatileab_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "ARM Versatile/AB (ARM926EJ-S)"; - mc->init = vab_init; - mc->block_default_type = IF_SCSI; -} - -static const TypeInfo versatileab_type = { - .name = MACHINE_TYPE_NAME("versatileab"), - .parent = TYPE_MACHINE, - .class_init = versatileab_class_init, -}; - -static void versatile_machine_init(void) -{ - type_register_static(&versatilepb_type); - type_register_static(&versatileab_type); -} - -type_init(versatile_machine_init) - -static void vpb_sic_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = vpb_sic_init; - dc->vmsd = &vmstate_vpb_sic; -} - -static const TypeInfo vpb_sic_info = { - .name = TYPE_VERSATILE_PB_SIC, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(vpb_sic_state), - .class_init = vpb_sic_class_init, -}; - -static void versatilepb_register_types(void) -{ - type_register_static(&vpb_sic_info); -} - -type_init(versatilepb_register_types) diff --git a/qemu/hw/arm/vexpress.c b/qemu/hw/arm/vexpress.c deleted file mode 100644 index 70b3e701e..000000000 --- a/qemu/hw/arm/vexpress.c +++ /dev/null @@ -1,806 +0,0 @@ -/* - * ARM Versatile Express emulation. - * - * Copyright (c) 2010 - 2011 B Labs Ltd. - * Copyright (c) 2011 Linaro Limited - * Written by Bahadir Balban, Amit Mahajan, Peter Maydell - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 <http://www.gnu.org/licenses/>. - * - * Contributions after 2012-01-13 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "qemu-common.h" -#include "cpu.h" -#include "hw/sysbus.h" -#include "hw/arm/arm.h" -#include "hw/arm/primecell.h" -#include "hw/devices.h" -#include "net/net.h" -#include "sysemu/sysemu.h" -#include "hw/boards.h" -#include "hw/loader.h" -#include "exec/address-spaces.h" -#include "sysemu/block-backend.h" -#include "hw/block/flash.h" -#include "sysemu/device_tree.h" -#include "qemu/error-report.h" -#include <libfdt.h> - -#define VEXPRESS_BOARD_ID 0x8e0 -#define VEXPRESS_FLASH_SIZE (64 * 1024 * 1024) -#define VEXPRESS_FLASH_SECT_SIZE (256 * 1024) - -/* Number of virtio transports to create (0..8; limited by - * number of available IRQ lines). - */ -#define NUM_VIRTIO_TRANSPORTS 4 - -/* Address maps for peripherals: - * the Versatile Express motherboard has two possible maps, - * the "legacy" one (used for A9) and the "Cortex-A Series" - * map (used for newer cores). - * Individual daughterboards can also have different maps for - * their peripherals. - */ - -enum { - VE_SYSREGS, - VE_SP810, - VE_SERIALPCI, - VE_PL041, - VE_MMCI, - VE_KMI0, - VE_KMI1, - VE_UART0, - VE_UART1, - VE_UART2, - VE_UART3, - VE_WDT, - VE_TIMER01, - VE_TIMER23, - VE_SERIALDVI, - VE_RTC, - VE_COMPACTFLASH, - VE_CLCD, - VE_NORFLASH0, - VE_NORFLASH1, - VE_NORFLASHALIAS, - VE_SRAM, - VE_VIDEORAM, - VE_ETHERNET, - VE_USB, - VE_DAPROM, - VE_VIRTIO, -}; - -static hwaddr motherboard_legacy_map[] = { - [VE_NORFLASHALIAS] = 0, - /* CS7: 0x10000000 .. 0x10020000 */ - [VE_SYSREGS] = 0x10000000, - [VE_SP810] = 0x10001000, - [VE_SERIALPCI] = 0x10002000, - [VE_PL041] = 0x10004000, - [VE_MMCI] = 0x10005000, - [VE_KMI0] = 0x10006000, - [VE_KMI1] = 0x10007000, - [VE_UART0] = 0x10009000, - [VE_UART1] = 0x1000a000, - [VE_UART2] = 0x1000b000, - [VE_UART3] = 0x1000c000, - [VE_WDT] = 0x1000f000, - [VE_TIMER01] = 0x10011000, - [VE_TIMER23] = 0x10012000, - [VE_VIRTIO] = 0x10013000, - [VE_SERIALDVI] = 0x10016000, - [VE_RTC] = 0x10017000, - [VE_COMPACTFLASH] = 0x1001a000, - [VE_CLCD] = 0x1001f000, - /* CS0: 0x40000000 .. 0x44000000 */ - [VE_NORFLASH0] = 0x40000000, - /* CS1: 0x44000000 .. 0x48000000 */ - [VE_NORFLASH1] = 0x44000000, - /* CS2: 0x48000000 .. 0x4a000000 */ - [VE_SRAM] = 0x48000000, - /* CS3: 0x4c000000 .. 0x50000000 */ - [VE_VIDEORAM] = 0x4c000000, - [VE_ETHERNET] = 0x4e000000, - [VE_USB] = 0x4f000000, -}; - -static hwaddr motherboard_aseries_map[] = { - [VE_NORFLASHALIAS] = 0, - /* CS0: 0x08000000 .. 0x0c000000 */ - [VE_NORFLASH0] = 0x08000000, - /* CS4: 0x0c000000 .. 0x10000000 */ - [VE_NORFLASH1] = 0x0c000000, - /* CS5: 0x10000000 .. 0x14000000 */ - /* CS1: 0x14000000 .. 0x18000000 */ - [VE_SRAM] = 0x14000000, - /* CS2: 0x18000000 .. 0x1c000000 */ - [VE_VIDEORAM] = 0x18000000, - [VE_ETHERNET] = 0x1a000000, - [VE_USB] = 0x1b000000, - /* CS3: 0x1c000000 .. 0x20000000 */ - [VE_DAPROM] = 0x1c000000, - [VE_SYSREGS] = 0x1c010000, - [VE_SP810] = 0x1c020000, - [VE_SERIALPCI] = 0x1c030000, - [VE_PL041] = 0x1c040000, - [VE_MMCI] = 0x1c050000, - [VE_KMI0] = 0x1c060000, - [VE_KMI1] = 0x1c070000, - [VE_UART0] = 0x1c090000, - [VE_UART1] = 0x1c0a0000, - [VE_UART2] = 0x1c0b0000, - [VE_UART3] = 0x1c0c0000, - [VE_WDT] = 0x1c0f0000, - [VE_TIMER01] = 0x1c110000, - [VE_TIMER23] = 0x1c120000, - [VE_VIRTIO] = 0x1c130000, - [VE_SERIALDVI] = 0x1c160000, - [VE_RTC] = 0x1c170000, - [VE_COMPACTFLASH] = 0x1c1a0000, - [VE_CLCD] = 0x1c1f0000, -}; - -/* Structure defining the peculiarities of a specific daughterboard */ - -typedef struct VEDBoardInfo VEDBoardInfo; - -typedef struct { - MachineClass parent; - VEDBoardInfo *daughterboard; -} VexpressMachineClass; - -typedef struct { - MachineState parent; - bool secure; -} VexpressMachineState; - -#define TYPE_VEXPRESS_MACHINE "vexpress" -#define TYPE_VEXPRESS_A9_MACHINE MACHINE_TYPE_NAME("vexpress-a9") -#define TYPE_VEXPRESS_A15_MACHINE MACHINE_TYPE_NAME("vexpress-a15") -#define VEXPRESS_MACHINE(obj) \ - OBJECT_CHECK(VexpressMachineState, (obj), TYPE_VEXPRESS_MACHINE) -#define VEXPRESS_MACHINE_GET_CLASS(obj) \ - OBJECT_GET_CLASS(VexpressMachineClass, obj, TYPE_VEXPRESS_MACHINE) -#define VEXPRESS_MACHINE_CLASS(klass) \ - OBJECT_CLASS_CHECK(VexpressMachineClass, klass, TYPE_VEXPRESS_MACHINE) - -typedef void DBoardInitFn(const VexpressMachineState *machine, - ram_addr_t ram_size, - const char *cpu_model, - qemu_irq *pic); - -struct VEDBoardInfo { - struct arm_boot_info bootinfo; - const hwaddr *motherboard_map; - hwaddr loader_start; - const hwaddr gic_cpu_if_addr; - uint32_t proc_id; - uint32_t num_voltage_sensors; - const uint32_t *voltages; - uint32_t num_clocks; - const uint32_t *clocks; - DBoardInitFn *init; -}; - -static void init_cpus(const char *cpu_model, const char *privdev, - hwaddr periphbase, qemu_irq *pic, bool secure) -{ - ObjectClass *cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model); - DeviceState *dev; - SysBusDevice *busdev; - int n; - - if (!cpu_oc) { - fprintf(stderr, "Unable to find CPU definition\n"); - exit(1); - } - - /* Create the actual CPUs */ - for (n = 0; n < smp_cpus; n++) { - Object *cpuobj = object_new(object_class_get_name(cpu_oc)); - - if (!secure) { - object_property_set_bool(cpuobj, false, "has_el3", NULL); - } - - if (object_property_find(cpuobj, "reset-cbar", NULL)) { - object_property_set_int(cpuobj, periphbase, - "reset-cbar", &error_abort); - } - object_property_set_bool(cpuobj, true, "realized", &error_fatal); - } - - /* Create the private peripheral devices (including the GIC); - * this must happen after the CPUs are created because a15mpcore_priv - * wires itself up to the CPU's generic_timer gpio out lines. - */ - dev = qdev_create(NULL, privdev); - qdev_prop_set_uint32(dev, "num-cpu", smp_cpus); - qdev_init_nofail(dev); - busdev = SYS_BUS_DEVICE(dev); - sysbus_mmio_map(busdev, 0, periphbase); - - /* Interrupts [42:0] are from the motherboard; - * [47:43] are reserved; [63:48] are daughterboard - * peripherals. Note that some documentation numbers - * external interrupts starting from 32 (because there - * are internal interrupts 0..31). - */ - for (n = 0; n < 64; n++) { - pic[n] = qdev_get_gpio_in(dev, n); - } - - /* Connect the CPUs to the GIC */ - for (n = 0; n < smp_cpus; n++) { - DeviceState *cpudev = DEVICE(qemu_get_cpu(n)); - - sysbus_connect_irq(busdev, n, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ)); - sysbus_connect_irq(busdev, n + smp_cpus, - qdev_get_gpio_in(cpudev, ARM_CPU_FIQ)); - } -} - -static void a9_daughterboard_init(const VexpressMachineState *vms, - ram_addr_t ram_size, - const char *cpu_model, - qemu_irq *pic) -{ - MemoryRegion *sysmem = get_system_memory(); - MemoryRegion *ram = g_new(MemoryRegion, 1); - MemoryRegion *lowram = g_new(MemoryRegion, 1); - ram_addr_t low_ram_size; - - if (!cpu_model) { - cpu_model = "cortex-a9"; - } - - if (ram_size > 0x40000000) { - /* 1GB is the maximum the address space permits */ - fprintf(stderr, "vexpress-a9: cannot model more than 1GB RAM\n"); - exit(1); - } - - memory_region_allocate_system_memory(ram, NULL, "vexpress.highmem", - ram_size); - low_ram_size = ram_size; - if (low_ram_size > 0x4000000) { - low_ram_size = 0x4000000; - } - /* RAM is from 0x60000000 upwards. The bottom 64MB of the - * address space should in theory be remappable to various - * things including ROM or RAM; we always map the RAM there. - */ - memory_region_init_alias(lowram, NULL, "vexpress.lowmem", ram, 0, low_ram_size); - memory_region_add_subregion(sysmem, 0x0, lowram); - memory_region_add_subregion(sysmem, 0x60000000, ram); - - /* 0x1e000000 A9MPCore (SCU) private memory region */ - init_cpus(cpu_model, "a9mpcore_priv", 0x1e000000, pic, vms->secure); - - /* Daughterboard peripherals : 0x10020000 .. 0x20000000 */ - - /* 0x10020000 PL111 CLCD (daughterboard) */ - sysbus_create_simple("pl111", 0x10020000, pic[44]); - - /* 0x10060000 AXI RAM */ - /* 0x100e0000 PL341 Dynamic Memory Controller */ - /* 0x100e1000 PL354 Static Memory Controller */ - /* 0x100e2000 System Configuration Controller */ - - sysbus_create_simple("sp804", 0x100e4000, pic[48]); - /* 0x100e5000 SP805 Watchdog module */ - /* 0x100e6000 BP147 TrustZone Protection Controller */ - /* 0x100e9000 PL301 'Fast' AXI matrix */ - /* 0x100ea000 PL301 'Slow' AXI matrix */ - /* 0x100ec000 TrustZone Address Space Controller */ - /* 0x10200000 CoreSight debug APB */ - /* 0x1e00a000 PL310 L2 Cache Controller */ - sysbus_create_varargs("l2x0", 0x1e00a000, NULL); -} - -/* Voltage values for SYS_CFG_VOLT daughterboard registers; - * values are in microvolts. - */ -static const uint32_t a9_voltages[] = { - 1000000, /* VD10 : 1.0V : SoC internal logic voltage */ - 1000000, /* VD10_S2 : 1.0V : PL310, L2 cache, RAM, non-PL310 logic */ - 1000000, /* VD10_S3 : 1.0V : Cortex-A9, cores, MPEs, SCU, PL310 logic */ - 1800000, /* VCC1V8 : 1.8V : DDR2 SDRAM, test chip DDR2 I/O supply */ - 900000, /* DDR2VTT : 0.9V : DDR2 SDRAM VTT termination voltage */ - 3300000, /* VCC3V3 : 3.3V : local board supply for misc external logic */ -}; - -/* Reset values for daughterboard oscillators (in Hz) */ -static const uint32_t a9_clocks[] = { - 45000000, /* AMBA AXI ACLK: 45MHz */ - 23750000, /* daughterboard CLCD clock: 23.75MHz */ - 66670000, /* Test chip reference clock: 66.67MHz */ -}; - -static VEDBoardInfo a9_daughterboard = { - .motherboard_map = motherboard_legacy_map, - .loader_start = 0x60000000, - .gic_cpu_if_addr = 0x1e000100, - .proc_id = 0x0c000191, - .num_voltage_sensors = ARRAY_SIZE(a9_voltages), - .voltages = a9_voltages, - .num_clocks = ARRAY_SIZE(a9_clocks), - .clocks = a9_clocks, - .init = a9_daughterboard_init, -}; - -static void a15_daughterboard_init(const VexpressMachineState *vms, - ram_addr_t ram_size, - const char *cpu_model, - qemu_irq *pic) -{ - MemoryRegion *sysmem = get_system_memory(); - MemoryRegion *ram = g_new(MemoryRegion, 1); - MemoryRegion *sram = g_new(MemoryRegion, 1); - - if (!cpu_model) { - cpu_model = "cortex-a15"; - } - - { - /* We have to use a separate 64 bit variable here to avoid the gcc - * "comparison is always false due to limited range of data type" - * warning if we are on a host where ram_addr_t is 32 bits. - */ - uint64_t rsz = ram_size; - if (rsz > (30ULL * 1024 * 1024 * 1024)) { - fprintf(stderr, "vexpress-a15: cannot model more than 30GB RAM\n"); - exit(1); - } - } - - memory_region_allocate_system_memory(ram, NULL, "vexpress.highmem", - ram_size); - /* RAM is from 0x80000000 upwards; there is no low-memory alias for it. */ - memory_region_add_subregion(sysmem, 0x80000000, ram); - - /* 0x2c000000 A15MPCore private memory region (GIC) */ - init_cpus(cpu_model, "a15mpcore_priv", 0x2c000000, pic, vms->secure); - - /* A15 daughterboard peripherals: */ - - /* 0x20000000: CoreSight interfaces: not modelled */ - /* 0x2a000000: PL301 AXI interconnect: not modelled */ - /* 0x2a420000: SCC: not modelled */ - /* 0x2a430000: system counter: not modelled */ - /* 0x2b000000: HDLCD controller: not modelled */ - /* 0x2b060000: SP805 watchdog: not modelled */ - /* 0x2b0a0000: PL341 dynamic memory controller: not modelled */ - /* 0x2e000000: system SRAM */ - memory_region_init_ram(sram, NULL, "vexpress.a15sram", 0x10000, - &error_fatal); - vmstate_register_ram_global(sram); - memory_region_add_subregion(sysmem, 0x2e000000, sram); - - /* 0x7ffb0000: DMA330 DMA controller: not modelled */ - /* 0x7ffd0000: PL354 static memory controller: not modelled */ -} - -static const uint32_t a15_voltages[] = { - 900000, /* Vcore: 0.9V : CPU core voltage */ -}; - -static const uint32_t a15_clocks[] = { - 60000000, /* OSCCLK0: 60MHz : CPU_CLK reference */ - 0, /* OSCCLK1: reserved */ - 0, /* OSCCLK2: reserved */ - 0, /* OSCCLK3: reserved */ - 40000000, /* OSCCLK4: 40MHz : external AXI master clock */ - 23750000, /* OSCCLK5: 23.75MHz : HDLCD PLL reference */ - 50000000, /* OSCCLK6: 50MHz : static memory controller clock */ - 60000000, /* OSCCLK7: 60MHz : SYSCLK reference */ - 40000000, /* OSCCLK8: 40MHz : DDR2 PLL reference */ -}; - -static VEDBoardInfo a15_daughterboard = { - .motherboard_map = motherboard_aseries_map, - .loader_start = 0x80000000, - .gic_cpu_if_addr = 0x2c002000, - .proc_id = 0x14000237, - .num_voltage_sensors = ARRAY_SIZE(a15_voltages), - .voltages = a15_voltages, - .num_clocks = ARRAY_SIZE(a15_clocks), - .clocks = a15_clocks, - .init = a15_daughterboard_init, -}; - -static int add_virtio_mmio_node(void *fdt, uint32_t acells, uint32_t scells, - hwaddr addr, hwaddr size, uint32_t intc, - int irq) -{ - /* Add a virtio_mmio node to the device tree blob: - * virtio_mmio@ADDRESS { - * compatible = "virtio,mmio"; - * reg = <ADDRESS, SIZE>; - * interrupt-parent = <&intc>; - * interrupts = <0, irq, 1>; - * } - * (Note that the format of the interrupts property is dependent on the - * interrupt controller that interrupt-parent points to; these are for - * the ARM GIC and indicate an SPI interrupt, rising-edge-triggered.) - */ - int rc; - char *nodename = g_strdup_printf("/virtio_mmio@%" PRIx64, addr); - - rc = qemu_fdt_add_subnode(fdt, nodename); - rc |= qemu_fdt_setprop_string(fdt, nodename, - "compatible", "virtio,mmio"); - rc |= qemu_fdt_setprop_sized_cells(fdt, nodename, "reg", - acells, addr, scells, size); - qemu_fdt_setprop_cells(fdt, nodename, "interrupt-parent", intc); - qemu_fdt_setprop_cells(fdt, nodename, "interrupts", 0, irq, 1); - g_free(nodename); - if (rc) { - return -1; - } - return 0; -} - -static uint32_t find_int_controller(void *fdt) -{ - /* Find the FDT node corresponding to the interrupt controller - * for virtio-mmio devices. We do this by scanning the fdt for - * a node with the right compatibility, since we know there is - * only one GIC on a vexpress board. - * We return the phandle of the node, or 0 if none was found. - */ - const char *compat = "arm,cortex-a9-gic"; - int offset; - - offset = fdt_node_offset_by_compatible(fdt, -1, compat); - if (offset >= 0) { - return fdt_get_phandle(fdt, offset); - } - return 0; -} - -static void vexpress_modify_dtb(const struct arm_boot_info *info, void *fdt) -{ - uint32_t acells, scells, intc; - const VEDBoardInfo *daughterboard = (const VEDBoardInfo *)info; - - acells = qemu_fdt_getprop_cell(fdt, "/", "#address-cells", - NULL, &error_fatal); - scells = qemu_fdt_getprop_cell(fdt, "/", "#size-cells", - NULL, &error_fatal); - intc = find_int_controller(fdt); - if (!intc) { - /* Not fatal, we just won't provide virtio. This will - * happen with older device tree blobs. - */ - fprintf(stderr, "QEMU: warning: couldn't find interrupt controller in " - "dtb; will not include virtio-mmio devices in the dtb.\n"); - } else { - int i; - const hwaddr *map = daughterboard->motherboard_map; - - /* We iterate backwards here because adding nodes - * to the dtb puts them in last-first. - */ - for (i = NUM_VIRTIO_TRANSPORTS - 1; i >= 0; i--) { - add_virtio_mmio_node(fdt, acells, scells, - map[VE_VIRTIO] + 0x200 * i, - 0x200, intc, 40 + i); - } - } -} - - -/* Open code a private version of pflash registration since we - * need to set non-default device width for VExpress platform. - */ -static pflash_t *ve_pflash_cfi01_register(hwaddr base, const char *name, - DriveInfo *di) -{ - DeviceState *dev = qdev_create(NULL, "cfi.pflash01"); - - if (di) { - qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(di), - &error_abort); - } - - qdev_prop_set_uint32(dev, "num-blocks", - VEXPRESS_FLASH_SIZE / VEXPRESS_FLASH_SECT_SIZE); - qdev_prop_set_uint64(dev, "sector-length", VEXPRESS_FLASH_SECT_SIZE); - qdev_prop_set_uint8(dev, "width", 4); - qdev_prop_set_uint8(dev, "device-width", 2); - qdev_prop_set_bit(dev, "big-endian", false); - qdev_prop_set_uint16(dev, "id0", 0x89); - qdev_prop_set_uint16(dev, "id1", 0x18); - qdev_prop_set_uint16(dev, "id2", 0x00); - qdev_prop_set_uint16(dev, "id3", 0x00); - qdev_prop_set_string(dev, "name", name); - qdev_init_nofail(dev); - - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); - return OBJECT_CHECK(pflash_t, (dev), "cfi.pflash01"); -} - -static void vexpress_common_init(MachineState *machine) -{ - VexpressMachineState *vms = VEXPRESS_MACHINE(machine); - VexpressMachineClass *vmc = VEXPRESS_MACHINE_GET_CLASS(machine); - VEDBoardInfo *daughterboard = vmc->daughterboard; - DeviceState *dev, *sysctl, *pl041; - qemu_irq pic[64]; - uint32_t sys_id; - DriveInfo *dinfo; - pflash_t *pflash0; - ram_addr_t vram_size, sram_size; - MemoryRegion *sysmem = get_system_memory(); - MemoryRegion *vram = g_new(MemoryRegion, 1); - MemoryRegion *sram = g_new(MemoryRegion, 1); - MemoryRegion *flashalias = g_new(MemoryRegion, 1); - MemoryRegion *flash0mem; - const hwaddr *map = daughterboard->motherboard_map; - int i; - - daughterboard->init(vms, machine->ram_size, machine->cpu_model, pic); - - /* - * If a bios file was provided, attempt to map it into memory - */ - if (bios_name) { - char *fn; - int image_size; - - if (drive_get(IF_PFLASH, 0, 0)) { - error_report("The contents of the first flash device may be " - "specified with -bios or with -drive if=pflash... " - "but you cannot use both options at once"); - exit(1); - } - fn = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); - if (!fn) { - error_report("Could not find ROM image '%s'", bios_name); - exit(1); - } - image_size = load_image_targphys(fn, map[VE_NORFLASH0], - VEXPRESS_FLASH_SIZE); - g_free(fn); - if (image_size < 0) { - error_report("Could not load ROM image '%s'", bios_name); - exit(1); - } - } - - /* Motherboard peripherals: the wiring is the same but the - * addresses vary between the legacy and A-Series memory maps. - */ - - sys_id = 0x1190f500; - - sysctl = qdev_create(NULL, "realview_sysctl"); - qdev_prop_set_uint32(sysctl, "sys_id", sys_id); - qdev_prop_set_uint32(sysctl, "proc_id", daughterboard->proc_id); - qdev_prop_set_uint32(sysctl, "len-db-voltage", - daughterboard->num_voltage_sensors); - for (i = 0; i < daughterboard->num_voltage_sensors; i++) { - char *propname = g_strdup_printf("db-voltage[%d]", i); - qdev_prop_set_uint32(sysctl, propname, daughterboard->voltages[i]); - g_free(propname); - } - qdev_prop_set_uint32(sysctl, "len-db-clock", - daughterboard->num_clocks); - for (i = 0; i < daughterboard->num_clocks; i++) { - char *propname = g_strdup_printf("db-clock[%d]", i); - qdev_prop_set_uint32(sysctl, propname, daughterboard->clocks[i]); - g_free(propname); - } - qdev_init_nofail(sysctl); - sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, map[VE_SYSREGS]); - - /* VE_SP810: not modelled */ - /* VE_SERIALPCI: not modelled */ - - pl041 = qdev_create(NULL, "pl041"); - qdev_prop_set_uint32(pl041, "nc_fifo_depth", 512); - qdev_init_nofail(pl041); - sysbus_mmio_map(SYS_BUS_DEVICE(pl041), 0, map[VE_PL041]); - sysbus_connect_irq(SYS_BUS_DEVICE(pl041), 0, pic[11]); - - dev = sysbus_create_varargs("pl181", map[VE_MMCI], pic[9], pic[10], NULL); - /* Wire up MMC card detect and read-only signals */ - qdev_connect_gpio_out(dev, 0, - qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_WPROT)); - qdev_connect_gpio_out(dev, 1, - qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_CARDIN)); - - sysbus_create_simple("pl050_keyboard", map[VE_KMI0], pic[12]); - sysbus_create_simple("pl050_mouse", map[VE_KMI1], pic[13]); - - sysbus_create_simple("pl011", map[VE_UART0], pic[5]); - sysbus_create_simple("pl011", map[VE_UART1], pic[6]); - sysbus_create_simple("pl011", map[VE_UART2], pic[7]); - sysbus_create_simple("pl011", map[VE_UART3], pic[8]); - - sysbus_create_simple("sp804", map[VE_TIMER01], pic[2]); - sysbus_create_simple("sp804", map[VE_TIMER23], pic[3]); - - /* VE_SERIALDVI: not modelled */ - - sysbus_create_simple("pl031", map[VE_RTC], pic[4]); /* RTC */ - - /* VE_COMPACTFLASH: not modelled */ - - sysbus_create_simple("pl111", map[VE_CLCD], pic[14]); - - dinfo = drive_get_next(IF_PFLASH); - pflash0 = ve_pflash_cfi01_register(map[VE_NORFLASH0], "vexpress.flash0", - dinfo); - if (!pflash0) { - fprintf(stderr, "vexpress: error registering flash 0.\n"); - exit(1); - } - - if (map[VE_NORFLASHALIAS] != -1) { - /* Map flash 0 as an alias into low memory */ - flash0mem = sysbus_mmio_get_region(SYS_BUS_DEVICE(pflash0), 0); - memory_region_init_alias(flashalias, NULL, "vexpress.flashalias", - flash0mem, 0, VEXPRESS_FLASH_SIZE); - memory_region_add_subregion(sysmem, map[VE_NORFLASHALIAS], flashalias); - } - - dinfo = drive_get_next(IF_PFLASH); - if (!ve_pflash_cfi01_register(map[VE_NORFLASH1], "vexpress.flash1", - dinfo)) { - fprintf(stderr, "vexpress: error registering flash 1.\n"); - exit(1); - } - - sram_size = 0x2000000; - memory_region_init_ram(sram, NULL, "vexpress.sram", sram_size, - &error_fatal); - vmstate_register_ram_global(sram); - memory_region_add_subregion(sysmem, map[VE_SRAM], sram); - - vram_size = 0x800000; - memory_region_init_ram(vram, NULL, "vexpress.vram", vram_size, - &error_fatal); - vmstate_register_ram_global(vram); - memory_region_add_subregion(sysmem, map[VE_VIDEORAM], vram); - - /* 0x4e000000 LAN9118 Ethernet */ - if (nd_table[0].used) { - lan9118_init(&nd_table[0], map[VE_ETHERNET], pic[15]); - } - - /* VE_USB: not modelled */ - - /* VE_DAPROM: not modelled */ - - /* Create mmio transports, so the user can create virtio backends - * (which will be automatically plugged in to the transports). If - * no backend is created the transport will just sit harmlessly idle. - */ - for (i = 0; i < NUM_VIRTIO_TRANSPORTS; i++) { - sysbus_create_simple("virtio-mmio", map[VE_VIRTIO] + 0x200 * i, - pic[40 + i]); - } - - daughterboard->bootinfo.ram_size = machine->ram_size; - daughterboard->bootinfo.kernel_filename = machine->kernel_filename; - daughterboard->bootinfo.kernel_cmdline = machine->kernel_cmdline; - daughterboard->bootinfo.initrd_filename = machine->initrd_filename; - daughterboard->bootinfo.nb_cpus = smp_cpus; - daughterboard->bootinfo.board_id = VEXPRESS_BOARD_ID; - daughterboard->bootinfo.loader_start = daughterboard->loader_start; - daughterboard->bootinfo.smp_loader_start = map[VE_SRAM]; - daughterboard->bootinfo.smp_bootreg_addr = map[VE_SYSREGS] + 0x30; - daughterboard->bootinfo.gic_cpu_if_addr = daughterboard->gic_cpu_if_addr; - daughterboard->bootinfo.modify_dtb = vexpress_modify_dtb; - /* Indicate that when booting Linux we should be in secure state */ - daughterboard->bootinfo.secure_boot = true; - arm_load_kernel(ARM_CPU(first_cpu), &daughterboard->bootinfo); -} - -static bool vexpress_get_secure(Object *obj, Error **errp) -{ - VexpressMachineState *vms = VEXPRESS_MACHINE(obj); - - return vms->secure; -} - -static void vexpress_set_secure(Object *obj, bool value, Error **errp) -{ - VexpressMachineState *vms = VEXPRESS_MACHINE(obj); - - vms->secure = value; -} - -static void vexpress_instance_init(Object *obj) -{ - VexpressMachineState *vms = VEXPRESS_MACHINE(obj); - - /* EL3 is enabled by default on vexpress */ - vms->secure = true; - object_property_add_bool(obj, "secure", vexpress_get_secure, - vexpress_set_secure, NULL); - object_property_set_description(obj, "secure", - "Set on/off to enable/disable the ARM " - "Security Extensions (TrustZone)", - NULL); -} - -static void vexpress_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "ARM Versatile Express"; - mc->init = vexpress_common_init; - mc->block_default_type = IF_SCSI; - mc->max_cpus = 4; -} - -static void vexpress_a9_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - VexpressMachineClass *vmc = VEXPRESS_MACHINE_CLASS(oc); - - mc->desc = "ARM Versatile Express for Cortex-A9"; - - vmc->daughterboard = &a9_daughterboard; -} - -static void vexpress_a15_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - VexpressMachineClass *vmc = VEXPRESS_MACHINE_CLASS(oc); - - mc->desc = "ARM Versatile Express for Cortex-A15"; - - vmc->daughterboard = &a15_daughterboard; -} - -static const TypeInfo vexpress_info = { - .name = TYPE_VEXPRESS_MACHINE, - .parent = TYPE_MACHINE, - .abstract = true, - .instance_size = sizeof(VexpressMachineState), - .instance_init = vexpress_instance_init, - .class_size = sizeof(VexpressMachineClass), - .class_init = vexpress_class_init, -}; - -static const TypeInfo vexpress_a9_info = { - .name = TYPE_VEXPRESS_A9_MACHINE, - .parent = TYPE_VEXPRESS_MACHINE, - .class_init = vexpress_a9_class_init, -}; - -static const TypeInfo vexpress_a15_info = { - .name = TYPE_VEXPRESS_A15_MACHINE, - .parent = TYPE_VEXPRESS_MACHINE, - .class_init = vexpress_a15_class_init, -}; - -static void vexpress_machine_init(void) -{ - type_register_static(&vexpress_info); - type_register_static(&vexpress_a9_info); - type_register_static(&vexpress_a15_info); -} - -type_init(vexpress_machine_init); diff --git a/qemu/hw/arm/virt-acpi-build.c b/qemu/hw/arm/virt-acpi-build.c deleted file mode 100644 index f51fe396c..000000000 --- a/qemu/hw/arm/virt-acpi-build.c +++ /dev/null @@ -1,755 +0,0 @@ -/* Support for generating ACPI tables and passing them to Guests - * - * ARM virt ACPI generation - * - * Copyright (C) 2008-2010 Kevin O'Connor <kevin@koconnor.net> - * Copyright (C) 2006 Fabrice Bellard - * Copyright (C) 2013 Red Hat Inc - * - * Author: Michael S. Tsirkin <mst@redhat.com> - * - * Copyright (c) 2015 HUAWEI TECHNOLOGIES CO.,LTD. - * - * Author: Shannon Zhao <zhaoshenglong@huawei.com> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "qemu-common.h" -#include "hw/arm/virt-acpi-build.h" -#include "qemu/bitmap.h" -#include "trace.h" -#include "qom/cpu.h" -#include "target-arm/cpu.h" -#include "hw/acpi/acpi-defs.h" -#include "hw/acpi/acpi.h" -#include "hw/nvram/fw_cfg.h" -#include "hw/acpi/bios-linker-loader.h" -#include "hw/loader.h" -#include "hw/hw.h" -#include "hw/acpi/aml-build.h" -#include "hw/pci/pcie_host.h" -#include "hw/pci/pci.h" - -#define ARM_SPI_BASE 32 -#define ACPI_POWER_BUTTON_DEVICE "PWRB" - -static void acpi_dsdt_add_cpus(Aml *scope, int smp_cpus) -{ - uint16_t i; - - for (i = 0; i < smp_cpus; i++) { - Aml *dev = aml_device("C%03x", i); - aml_append(dev, aml_name_decl("_HID", aml_string("ACPI0007"))); - aml_append(dev, aml_name_decl("_UID", aml_int(i))); - aml_append(scope, dev); - } -} - -static void acpi_dsdt_add_uart(Aml *scope, const MemMapEntry *uart_memmap, - uint32_t uart_irq) -{ - Aml *dev = aml_device("COM0"); - aml_append(dev, aml_name_decl("_HID", aml_string("ARMH0011"))); - aml_append(dev, aml_name_decl("_UID", aml_int(0))); - - Aml *crs = aml_resource_template(); - aml_append(crs, aml_memory32_fixed(uart_memmap->base, - uart_memmap->size, AML_READ_WRITE)); - aml_append(crs, - aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, - AML_EXCLUSIVE, &uart_irq, 1)); - aml_append(dev, aml_name_decl("_CRS", crs)); - - /* The _ADR entry is used to link this device to the UART described - * in the SPCR table, i.e. SPCR.base_address.address == _ADR. - */ - aml_append(dev, aml_name_decl("_ADR", aml_int(uart_memmap->base))); - - aml_append(scope, dev); -} - -static void acpi_dsdt_add_fw_cfg(Aml *scope, const MemMapEntry *fw_cfg_memmap) -{ - Aml *dev = aml_device("FWCF"); - aml_append(dev, aml_name_decl("_HID", aml_string("QEMU0002"))); - /* device present, functioning, decoding, not shown in UI */ - aml_append(dev, aml_name_decl("_STA", aml_int(0xB))); - - Aml *crs = aml_resource_template(); - aml_append(crs, aml_memory32_fixed(fw_cfg_memmap->base, - fw_cfg_memmap->size, AML_READ_WRITE)); - aml_append(dev, aml_name_decl("_CRS", crs)); - aml_append(scope, dev); -} - -static void acpi_dsdt_add_flash(Aml *scope, const MemMapEntry *flash_memmap) -{ - Aml *dev, *crs; - hwaddr base = flash_memmap->base; - hwaddr size = flash_memmap->size / 2; - - dev = aml_device("FLS0"); - aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0015"))); - aml_append(dev, aml_name_decl("_UID", aml_int(0))); - - crs = aml_resource_template(); - aml_append(crs, aml_memory32_fixed(base, size, AML_READ_WRITE)); - aml_append(dev, aml_name_decl("_CRS", crs)); - aml_append(scope, dev); - - dev = aml_device("FLS1"); - aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0015"))); - aml_append(dev, aml_name_decl("_UID", aml_int(1))); - crs = aml_resource_template(); - aml_append(crs, aml_memory32_fixed(base + size, size, AML_READ_WRITE)); - aml_append(dev, aml_name_decl("_CRS", crs)); - aml_append(scope, dev); -} - -static void acpi_dsdt_add_virtio(Aml *scope, - const MemMapEntry *virtio_mmio_memmap, - uint32_t mmio_irq, int num) -{ - hwaddr base = virtio_mmio_memmap->base; - hwaddr size = virtio_mmio_memmap->size; - int i; - - for (i = 0; i < num; i++) { - uint32_t irq = mmio_irq + i; - Aml *dev = aml_device("VR%02u", i); - aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0005"))); - aml_append(dev, aml_name_decl("_UID", aml_int(i))); - - Aml *crs = aml_resource_template(); - aml_append(crs, aml_memory32_fixed(base, size, AML_READ_WRITE)); - aml_append(crs, - aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, - AML_EXCLUSIVE, &irq, 1)); - aml_append(dev, aml_name_decl("_CRS", crs)); - aml_append(scope, dev); - base += size; - } -} - -static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap, - uint32_t irq, bool use_highmem) -{ - Aml *method, *crs, *ifctx, *UUID, *ifctx1, *elsectx, *buf; - int i, bus_no; - hwaddr base_mmio = memmap[VIRT_PCIE_MMIO].base; - hwaddr size_mmio = memmap[VIRT_PCIE_MMIO].size; - hwaddr base_pio = memmap[VIRT_PCIE_PIO].base; - hwaddr size_pio = memmap[VIRT_PCIE_PIO].size; - hwaddr base_ecam = memmap[VIRT_PCIE_ECAM].base; - hwaddr size_ecam = memmap[VIRT_PCIE_ECAM].size; - int nr_pcie_buses = size_ecam / PCIE_MMCFG_SIZE_MIN; - - Aml *dev = aml_device("%s", "PCI0"); - aml_append(dev, aml_name_decl("_HID", aml_string("PNP0A08"))); - aml_append(dev, aml_name_decl("_CID", aml_string("PNP0A03"))); - aml_append(dev, aml_name_decl("_SEG", aml_int(0))); - aml_append(dev, aml_name_decl("_BBN", aml_int(0))); - aml_append(dev, aml_name_decl("_ADR", aml_int(0))); - aml_append(dev, aml_name_decl("_UID", aml_string("PCI0"))); - aml_append(dev, aml_name_decl("_STR", aml_unicode("PCIe 0 Device"))); - aml_append(dev, aml_name_decl("_CCA", aml_int(1))); - - /* Declare the PCI Routing Table. */ - Aml *rt_pkg = aml_package(nr_pcie_buses * PCI_NUM_PINS); - for (bus_no = 0; bus_no < nr_pcie_buses; bus_no++) { - for (i = 0; i < PCI_NUM_PINS; i++) { - int gsi = (i + bus_no) % PCI_NUM_PINS; - Aml *pkg = aml_package(4); - aml_append(pkg, aml_int((bus_no << 16) | 0xFFFF)); - aml_append(pkg, aml_int(i)); - aml_append(pkg, aml_name("GSI%d", gsi)); - aml_append(pkg, aml_int(0)); - aml_append(rt_pkg, pkg); - } - } - aml_append(dev, aml_name_decl("_PRT", rt_pkg)); - - /* Create GSI link device */ - for (i = 0; i < PCI_NUM_PINS; i++) { - uint32_t irqs = irq + i; - Aml *dev_gsi = aml_device("GSI%d", i); - aml_append(dev_gsi, aml_name_decl("_HID", aml_string("PNP0C0F"))); - aml_append(dev_gsi, aml_name_decl("_UID", aml_int(0))); - crs = aml_resource_template(); - aml_append(crs, - aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, - AML_EXCLUSIVE, &irqs, 1)); - aml_append(dev_gsi, aml_name_decl("_PRS", crs)); - crs = aml_resource_template(); - aml_append(crs, - aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, - AML_EXCLUSIVE, &irqs, 1)); - aml_append(dev_gsi, aml_name_decl("_CRS", crs)); - method = aml_method("_SRS", 1, AML_NOTSERIALIZED); - aml_append(dev_gsi, method); - aml_append(dev, dev_gsi); - } - - method = aml_method("_CBA", 0, AML_NOTSERIALIZED); - aml_append(method, aml_return(aml_int(base_ecam))); - aml_append(dev, method); - - method = aml_method("_CRS", 0, AML_NOTSERIALIZED); - Aml *rbuf = aml_resource_template(); - aml_append(rbuf, - aml_word_bus_number(AML_MIN_FIXED, AML_MAX_FIXED, AML_POS_DECODE, - 0x0000, 0x0000, nr_pcie_buses - 1, 0x0000, - nr_pcie_buses)); - aml_append(rbuf, - aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, - AML_NON_CACHEABLE, AML_READ_WRITE, 0x0000, base_mmio, - base_mmio + size_mmio - 1, 0x0000, size_mmio)); - aml_append(rbuf, - aml_dword_io(AML_MIN_FIXED, AML_MAX_FIXED, AML_POS_DECODE, - AML_ENTIRE_RANGE, 0x0000, 0x0000, size_pio - 1, base_pio, - size_pio)); - - if (use_highmem) { - hwaddr base_mmio_high = memmap[VIRT_PCIE_MMIO_HIGH].base; - hwaddr size_mmio_high = memmap[VIRT_PCIE_MMIO_HIGH].size; - - aml_append(rbuf, - aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, - AML_NON_CACHEABLE, AML_READ_WRITE, 0x0000, - base_mmio_high, base_mmio_high, 0x0000, - size_mmio_high)); - } - - aml_append(method, aml_name_decl("RBUF", rbuf)); - aml_append(method, aml_return(rbuf)); - aml_append(dev, method); - - /* Declare an _OSC (OS Control Handoff) method */ - aml_append(dev, aml_name_decl("SUPP", aml_int(0))); - aml_append(dev, aml_name_decl("CTRL", aml_int(0))); - method = aml_method("_OSC", 4, AML_NOTSERIALIZED); - aml_append(method, - aml_create_dword_field(aml_arg(3), aml_int(0), "CDW1")); - - /* PCI Firmware Specification 3.0 - * 4.5.1. _OSC Interface for PCI Host Bridge Devices - * The _OSC interface for a PCI/PCI-X/PCI Express hierarchy is - * identified by the Universal Unique IDentifier (UUID) - * 33DB4D5B-1FF7-401C-9657-7441C03DD766 - */ - UUID = aml_touuid("33DB4D5B-1FF7-401C-9657-7441C03DD766"); - ifctx = aml_if(aml_equal(aml_arg(0), UUID)); - aml_append(ifctx, - aml_create_dword_field(aml_arg(3), aml_int(4), "CDW2")); - aml_append(ifctx, - aml_create_dword_field(aml_arg(3), aml_int(8), "CDW3")); - aml_append(ifctx, aml_store(aml_name("CDW2"), aml_name("SUPP"))); - aml_append(ifctx, aml_store(aml_name("CDW3"), aml_name("CTRL"))); - aml_append(ifctx, aml_store(aml_and(aml_name("CTRL"), aml_int(0x1D), NULL), - aml_name("CTRL"))); - - ifctx1 = aml_if(aml_lnot(aml_equal(aml_arg(1), aml_int(0x1)))); - aml_append(ifctx1, aml_store(aml_or(aml_name("CDW1"), aml_int(0x08), NULL), - aml_name("CDW1"))); - aml_append(ifctx, ifctx1); - - ifctx1 = aml_if(aml_lnot(aml_equal(aml_name("CDW3"), aml_name("CTRL")))); - aml_append(ifctx1, aml_store(aml_or(aml_name("CDW1"), aml_int(0x10), NULL), - aml_name("CDW1"))); - aml_append(ifctx, ifctx1); - - aml_append(ifctx, aml_store(aml_name("CTRL"), aml_name("CDW3"))); - aml_append(ifctx, aml_return(aml_arg(3))); - aml_append(method, ifctx); - - elsectx = aml_else(); - aml_append(elsectx, aml_store(aml_or(aml_name("CDW1"), aml_int(4), NULL), - aml_name("CDW1"))); - aml_append(elsectx, aml_return(aml_arg(3))); - aml_append(method, elsectx); - aml_append(dev, method); - - method = aml_method("_DSM", 4, AML_NOTSERIALIZED); - - /* PCI Firmware Specification 3.0 - * 4.6.1. _DSM for PCI Express Slot Information - * The UUID in _DSM in this context is - * {E5C937D0-3553-4D7A-9117-EA4D19C3434D} - */ - UUID = aml_touuid("E5C937D0-3553-4D7A-9117-EA4D19C3434D"); - ifctx = aml_if(aml_equal(aml_arg(0), UUID)); - ifctx1 = aml_if(aml_equal(aml_arg(2), aml_int(0))); - uint8_t byte_list[1] = {1}; - buf = aml_buffer(1, byte_list); - aml_append(ifctx1, aml_return(buf)); - aml_append(ifctx, ifctx1); - aml_append(method, ifctx); - - byte_list[0] = 0; - buf = aml_buffer(1, byte_list); - aml_append(method, aml_return(buf)); - aml_append(dev, method); - - Aml *dev_rp0 = aml_device("%s", "RP0"); - aml_append(dev_rp0, aml_name_decl("_ADR", aml_int(0))); - aml_append(dev, dev_rp0); - aml_append(scope, dev); -} - -static void acpi_dsdt_add_gpio(Aml *scope, const MemMapEntry *gpio_memmap, - uint32_t gpio_irq) -{ - Aml *dev = aml_device("GPO0"); - aml_append(dev, aml_name_decl("_HID", aml_string("ARMH0061"))); - aml_append(dev, aml_name_decl("_ADR", aml_int(0))); - aml_append(dev, aml_name_decl("_UID", aml_int(0))); - - Aml *crs = aml_resource_template(); - aml_append(crs, aml_memory32_fixed(gpio_memmap->base, gpio_memmap->size, - AML_READ_WRITE)); - aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, - AML_EXCLUSIVE, &gpio_irq, 1)); - aml_append(dev, aml_name_decl("_CRS", crs)); - - Aml *aei = aml_resource_template(); - /* Pin 3 for power button */ - const uint32_t pin_list[1] = {3}; - aml_append(aei, aml_gpio_int(AML_CONSUMER, AML_EDGE, AML_ACTIVE_HIGH, - AML_EXCLUSIVE, AML_PULL_UP, 0, pin_list, 1, - "GPO0", NULL, 0)); - aml_append(dev, aml_name_decl("_AEI", aei)); - - /* _E03 is handle for power button */ - Aml *method = aml_method("_E03", 0, AML_NOTSERIALIZED); - aml_append(method, aml_notify(aml_name(ACPI_POWER_BUTTON_DEVICE), - aml_int(0x80))); - aml_append(dev, method); - aml_append(scope, dev); -} - -static void acpi_dsdt_add_power_button(Aml *scope) -{ - Aml *dev = aml_device(ACPI_POWER_BUTTON_DEVICE); - aml_append(dev, aml_name_decl("_HID", aml_string("PNP0C0C"))); - aml_append(dev, aml_name_decl("_ADR", aml_int(0))); - aml_append(dev, aml_name_decl("_UID", aml_int(0))); - aml_append(scope, dev); -} - -/* RSDP */ -static GArray * -build_rsdp(GArray *rsdp_table, GArray *linker, unsigned rsdt) -{ - AcpiRsdpDescriptor *rsdp = acpi_data_push(rsdp_table, sizeof *rsdp); - - bios_linker_loader_alloc(linker, ACPI_BUILD_RSDP_FILE, 16, - true /* fseg memory */); - - memcpy(&rsdp->signature, "RSD PTR ", sizeof(rsdp->signature)); - memcpy(rsdp->oem_id, ACPI_BUILD_APPNAME6, sizeof(rsdp->oem_id)); - rsdp->length = cpu_to_le32(sizeof(*rsdp)); - rsdp->revision = 0x02; - - /* Point to RSDT */ - rsdp->rsdt_physical_address = cpu_to_le32(rsdt); - /* Address to be filled by Guest linker */ - bios_linker_loader_add_pointer(linker, ACPI_BUILD_RSDP_FILE, - ACPI_BUILD_TABLE_FILE, - rsdp_table, &rsdp->rsdt_physical_address, - sizeof rsdp->rsdt_physical_address); - rsdp->checksum = 0; - /* Checksum to be filled by Guest linker */ - bios_linker_loader_add_checksum(linker, ACPI_BUILD_RSDP_FILE, - rsdp_table, rsdp, sizeof *rsdp, - &rsdp->checksum); - - return rsdp_table; -} - -static void -build_spcr(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info) -{ - AcpiSerialPortConsoleRedirection *spcr; - const MemMapEntry *uart_memmap = &guest_info->memmap[VIRT_UART]; - int irq = guest_info->irqmap[VIRT_UART] + ARM_SPI_BASE; - - spcr = acpi_data_push(table_data, sizeof(*spcr)); - - spcr->interface_type = 0x3; /* ARM PL011 UART */ - - spcr->base_address.space_id = AML_SYSTEM_MEMORY; - spcr->base_address.bit_width = 8; - spcr->base_address.bit_offset = 0; - spcr->base_address.access_width = 1; - spcr->base_address.address = cpu_to_le64(uart_memmap->base); - - spcr->interrupt_types = (1 << 3); /* Bit[3] ARMH GIC interrupt */ - spcr->gsi = cpu_to_le32(irq); /* Global System Interrupt */ - - spcr->baud = 3; /* Baud Rate: 3 = 9600 */ - spcr->parity = 0; /* No Parity */ - spcr->stopbits = 1; /* 1 Stop bit */ - spcr->flowctrl = (1 << 1); /* Bit[1] = RTS/CTS hardware flow control */ - spcr->term_type = 0; /* Terminal Type: 0 = VT100 */ - - spcr->pci_device_id = 0xffff; /* PCI Device ID: not a PCI device */ - spcr->pci_vendor_id = 0xffff; /* PCI Vendor ID: not a PCI device */ - - build_header(linker, table_data, (void *)spcr, "SPCR", sizeof(*spcr), 2, - NULL, NULL); -} - -static void -build_mcfg(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info) -{ - AcpiTableMcfg *mcfg; - const MemMapEntry *memmap = guest_info->memmap; - int len = sizeof(*mcfg) + sizeof(mcfg->allocation[0]); - - mcfg = acpi_data_push(table_data, len); - mcfg->allocation[0].address = cpu_to_le64(memmap[VIRT_PCIE_ECAM].base); - - /* Only a single allocation so no need to play with segments */ - mcfg->allocation[0].pci_segment = cpu_to_le16(0); - mcfg->allocation[0].start_bus_number = 0; - mcfg->allocation[0].end_bus_number = (memmap[VIRT_PCIE_ECAM].size - / PCIE_MMCFG_SIZE_MIN) - 1; - - build_header(linker, table_data, (void *)mcfg, "MCFG", len, 1, NULL, NULL); -} - -/* GTDT */ -static void -build_gtdt(GArray *table_data, GArray *linker) -{ - int gtdt_start = table_data->len; - AcpiGenericTimerTable *gtdt; - - gtdt = acpi_data_push(table_data, sizeof *gtdt); - /* The interrupt values are the same with the device tree when adding 16 */ - gtdt->secure_el1_interrupt = ARCH_TIMER_S_EL1_IRQ + 16; - gtdt->secure_el1_flags = ACPI_EDGE_SENSITIVE; - - gtdt->non_secure_el1_interrupt = ARCH_TIMER_NS_EL1_IRQ + 16; - gtdt->non_secure_el1_flags = ACPI_EDGE_SENSITIVE | ACPI_GTDT_ALWAYS_ON; - - gtdt->virtual_timer_interrupt = ARCH_TIMER_VIRT_IRQ + 16; - gtdt->virtual_timer_flags = ACPI_EDGE_SENSITIVE; - - gtdt->non_secure_el2_interrupt = ARCH_TIMER_NS_EL2_IRQ + 16; - gtdt->non_secure_el2_flags = ACPI_EDGE_SENSITIVE; - - build_header(linker, table_data, - (void *)(table_data->data + gtdt_start), "GTDT", - table_data->len - gtdt_start, 2, NULL, NULL); -} - -/* MADT */ -static void -build_madt(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info) -{ - int madt_start = table_data->len; - const MemMapEntry *memmap = guest_info->memmap; - const int *irqmap = guest_info->irqmap; - AcpiMultipleApicTable *madt; - AcpiMadtGenericDistributor *gicd; - AcpiMadtGenericMsiFrame *gic_msi; - int i; - - madt = acpi_data_push(table_data, sizeof *madt); - - gicd = acpi_data_push(table_data, sizeof *gicd); - gicd->type = ACPI_APIC_GENERIC_DISTRIBUTOR; - gicd->length = sizeof(*gicd); - gicd->base_address = memmap[VIRT_GIC_DIST].base; - - for (i = 0; i < guest_info->smp_cpus; i++) { - AcpiMadtGenericInterrupt *gicc = acpi_data_push(table_data, - sizeof *gicc); - ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(i)); - - gicc->type = ACPI_APIC_GENERIC_INTERRUPT; - gicc->length = sizeof(*gicc); - if (guest_info->gic_version == 2) { - gicc->base_address = memmap[VIRT_GIC_CPU].base; - } - gicc->cpu_interface_number = i; - gicc->arm_mpidr = armcpu->mp_affinity; - gicc->uid = i; - gicc->flags = cpu_to_le32(ACPI_GICC_ENABLED); - } - - if (guest_info->gic_version == 3) { - AcpiMadtGenericRedistributor *gicr = acpi_data_push(table_data, - sizeof *gicr); - - gicr->type = ACPI_APIC_GENERIC_REDISTRIBUTOR; - gicr->length = sizeof(*gicr); - gicr->base_address = cpu_to_le64(memmap[VIRT_GIC_REDIST].base); - gicr->range_length = cpu_to_le32(memmap[VIRT_GIC_REDIST].size); - } else { - gic_msi = acpi_data_push(table_data, sizeof *gic_msi); - gic_msi->type = ACPI_APIC_GENERIC_MSI_FRAME; - gic_msi->length = sizeof(*gic_msi); - gic_msi->gic_msi_frame_id = 0; - gic_msi->base_address = cpu_to_le64(memmap[VIRT_GIC_V2M].base); - gic_msi->flags = cpu_to_le32(1); - gic_msi->spi_count = cpu_to_le16(NUM_GICV2M_SPIS); - gic_msi->spi_base = cpu_to_le16(irqmap[VIRT_GIC_V2M] + ARM_SPI_BASE); - } - - build_header(linker, table_data, - (void *)(table_data->data + madt_start), "APIC", - table_data->len - madt_start, 3, NULL, NULL); -} - -/* FADT */ -static void -build_fadt(GArray *table_data, GArray *linker, unsigned dsdt) -{ - AcpiFadtDescriptorRev5_1 *fadt = acpi_data_push(table_data, sizeof(*fadt)); - - /* Hardware Reduced = 1 and use PSCI 0.2+ and with HVC */ - fadt->flags = cpu_to_le32(1 << ACPI_FADT_F_HW_REDUCED_ACPI); - fadt->arm_boot_flags = cpu_to_le16((1 << ACPI_FADT_ARM_USE_PSCI_G_0_2) | - (1 << ACPI_FADT_ARM_PSCI_USE_HVC)); - - /* ACPI v5.1 (fadt->revision.fadt->minor_revision) */ - fadt->minor_revision = 0x1; - - fadt->dsdt = cpu_to_le32(dsdt); - /* DSDT address to be filled by Guest linker */ - bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE, - ACPI_BUILD_TABLE_FILE, - table_data, &fadt->dsdt, - sizeof fadt->dsdt); - - build_header(linker, table_data, - (void *)fadt, "FACP", sizeof(*fadt), 5, NULL, NULL); -} - -/* DSDT */ -static void -build_dsdt(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info) -{ - Aml *scope, *dsdt; - const MemMapEntry *memmap = guest_info->memmap; - const int *irqmap = guest_info->irqmap; - - dsdt = init_aml_allocator(); - /* Reserve space for header */ - acpi_data_push(dsdt->buf, sizeof(AcpiTableHeader)); - - /* When booting the VM with UEFI, UEFI takes ownership of the RTC hardware. - * While UEFI can use libfdt to disable the RTC device node in the DTB that - * it passes to the OS, it cannot modify AML. Therefore, we won't generate - * the RTC ACPI device at all when using UEFI. - */ - scope = aml_scope("\\_SB"); - acpi_dsdt_add_cpus(scope, guest_info->smp_cpus); - acpi_dsdt_add_uart(scope, &memmap[VIRT_UART], - (irqmap[VIRT_UART] + ARM_SPI_BASE)); - acpi_dsdt_add_flash(scope, &memmap[VIRT_FLASH]); - acpi_dsdt_add_fw_cfg(scope, &memmap[VIRT_FW_CFG]); - acpi_dsdt_add_virtio(scope, &memmap[VIRT_MMIO], - (irqmap[VIRT_MMIO] + ARM_SPI_BASE), NUM_VIRTIO_TRANSPORTS); - acpi_dsdt_add_pci(scope, memmap, (irqmap[VIRT_PCIE] + ARM_SPI_BASE), - guest_info->use_highmem); - acpi_dsdt_add_gpio(scope, &memmap[VIRT_GPIO], - (irqmap[VIRT_GPIO] + ARM_SPI_BASE)); - acpi_dsdt_add_power_button(scope); - - aml_append(dsdt, scope); - - /* copy AML table into ACPI tables blob and patch header there */ - g_array_append_vals(table_data, dsdt->buf->data, dsdt->buf->len); - build_header(linker, table_data, - (void *)(table_data->data + table_data->len - dsdt->buf->len), - "DSDT", dsdt->buf->len, 2, NULL, NULL); - free_aml_allocator(); -} - -typedef -struct AcpiBuildState { - /* Copy of table in RAM (for patching). */ - MemoryRegion *table_mr; - MemoryRegion *rsdp_mr; - MemoryRegion *linker_mr; - /* Is table patched? */ - bool patched; - VirtGuestInfo *guest_info; -} AcpiBuildState; - -static -void virt_acpi_build(VirtGuestInfo *guest_info, AcpiBuildTables *tables) -{ - GArray *table_offsets; - unsigned dsdt, rsdt; - GArray *tables_blob = tables->table_data; - - table_offsets = g_array_new(false, true /* clear */, - sizeof(uint32_t)); - - bios_linker_loader_alloc(tables->linker, ACPI_BUILD_TABLE_FILE, - 64, false /* high memory */); - - /* - * The ACPI v5.1 tables for Hardware-reduced ACPI platform are: - * RSDP - * RSDT - * FADT - * GTDT - * MADT - * MCFG - * DSDT - */ - - /* DSDT is pointed to by FADT */ - dsdt = tables_blob->len; - build_dsdt(tables_blob, tables->linker, guest_info); - - /* FADT MADT GTDT MCFG SPCR pointed to by RSDT */ - acpi_add_table(table_offsets, tables_blob); - build_fadt(tables_blob, tables->linker, dsdt); - - acpi_add_table(table_offsets, tables_blob); - build_madt(tables_blob, tables->linker, guest_info); - - acpi_add_table(table_offsets, tables_blob); - build_gtdt(tables_blob, tables->linker); - - acpi_add_table(table_offsets, tables_blob); - build_mcfg(tables_blob, tables->linker, guest_info); - - acpi_add_table(table_offsets, tables_blob); - build_spcr(tables_blob, tables->linker, guest_info); - - /* RSDT is pointed to by RSDP */ - rsdt = tables_blob->len; - build_rsdt(tables_blob, tables->linker, table_offsets, NULL, NULL); - - /* RSDP is in FSEG memory, so allocate it separately */ - build_rsdp(tables->rsdp, tables->linker, rsdt); - - /* Cleanup memory that's no longer used. */ - g_array_free(table_offsets, true); -} - -static void acpi_ram_update(MemoryRegion *mr, GArray *data) -{ - uint32_t size = acpi_data_len(data); - - /* Make sure RAM size is correct - in case it got changed - * e.g. by migration */ - memory_region_ram_resize(mr, size, &error_abort); - - memcpy(memory_region_get_ram_ptr(mr), data->data, size); - memory_region_set_dirty(mr, 0, size); -} - -static void virt_acpi_build_update(void *build_opaque) -{ - AcpiBuildState *build_state = build_opaque; - AcpiBuildTables tables; - - /* No state to update or already patched? Nothing to do. */ - if (!build_state || build_state->patched) { - return; - } - build_state->patched = true; - - acpi_build_tables_init(&tables); - - virt_acpi_build(build_state->guest_info, &tables); - - acpi_ram_update(build_state->table_mr, tables.table_data); - acpi_ram_update(build_state->rsdp_mr, tables.rsdp); - acpi_ram_update(build_state->linker_mr, tables.linker); - - - acpi_build_tables_cleanup(&tables, true); -} - -static void virt_acpi_build_reset(void *build_opaque) -{ - AcpiBuildState *build_state = build_opaque; - build_state->patched = false; -} - -static MemoryRegion *acpi_add_rom_blob(AcpiBuildState *build_state, - GArray *blob, const char *name, - uint64_t max_size) -{ - return rom_add_blob(name, blob->data, acpi_data_len(blob), max_size, -1, - name, virt_acpi_build_update, build_state); -} - -static const VMStateDescription vmstate_virt_acpi_build = { - .name = "virt_acpi_build", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_BOOL(patched, AcpiBuildState), - VMSTATE_END_OF_LIST() - }, -}; - -void virt_acpi_setup(VirtGuestInfo *guest_info) -{ - AcpiBuildTables tables; - AcpiBuildState *build_state; - - if (!guest_info->fw_cfg) { - trace_virt_acpi_setup(); - return; - } - - if (!acpi_enabled) { - trace_virt_acpi_setup(); - return; - } - - build_state = g_malloc0(sizeof *build_state); - build_state->guest_info = guest_info; - - acpi_build_tables_init(&tables); - virt_acpi_build(build_state->guest_info, &tables); - - /* Now expose it all to Guest */ - build_state->table_mr = acpi_add_rom_blob(build_state, tables.table_data, - ACPI_BUILD_TABLE_FILE, - ACPI_BUILD_TABLE_MAX_SIZE); - assert(build_state->table_mr != NULL); - - build_state->linker_mr = - acpi_add_rom_blob(build_state, tables.linker, "etc/table-loader", 0); - - fw_cfg_add_file(guest_info->fw_cfg, ACPI_BUILD_TPMLOG_FILE, - tables.tcpalog->data, acpi_data_len(tables.tcpalog)); - - build_state->rsdp_mr = acpi_add_rom_blob(build_state, tables.rsdp, - ACPI_BUILD_RSDP_FILE, 0); - - qemu_register_reset(virt_acpi_build_reset, build_state); - virt_acpi_build_reset(build_state); - vmstate_register(NULL, 0, &vmstate_virt_acpi_build, build_state); - - /* Cleanup tables but don't free the memory: we track it - * in build_state. - */ - acpi_build_tables_cleanup(&tables, false); -} diff --git a/qemu/hw/arm/virt.c b/qemu/hw/arm/virt.c deleted file mode 100644 index 56d35c771..000000000 --- a/qemu/hw/arm/virt.c +++ /dev/null @@ -1,1435 +0,0 @@ -/* - * ARM mach-virt emulation - * - * Copyright (c) 2013 Linaro Limited - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2 or later, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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 <http://www.gnu.org/licenses/>. - * - * Emulate a virtual board which works by passing Linux all the information - * it needs about what devices are present via the device tree. - * There are some restrictions about what we can do here: - * + we can only present devices whose Linux drivers will work based - * purely on the device tree with no platform data at all - * + we want to present a very stripped-down minimalist platform, - * both because this reduces the security attack surface from the guest - * and also because it reduces our exposure to being broken when - * the kernel updates its device tree bindings and requires further - * information in a device binding that we aren't providing. - * This is essentially the same approach kvmtool uses. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "hw/sysbus.h" -#include "hw/arm/arm.h" -#include "hw/arm/primecell.h" -#include "hw/arm/virt.h" -#include "hw/devices.h" -#include "net/net.h" -#include "sysemu/block-backend.h" -#include "sysemu/device_tree.h" -#include "sysemu/sysemu.h" -#include "sysemu/kvm.h" -#include "hw/boards.h" -#include "hw/loader.h" -#include "exec/address-spaces.h" -#include "qemu/bitops.h" -#include "qemu/error-report.h" -#include "hw/pci-host/gpex.h" -#include "hw/arm/virt-acpi-build.h" -#include "hw/arm/sysbus-fdt.h" -#include "hw/platform-bus.h" -#include "hw/arm/fdt.h" -#include "hw/intc/arm_gic_common.h" -#include "kvm_arm.h" -#include "hw/smbios/smbios.h" -#include "qapi/visitor.h" -#include "standard-headers/linux/input.h" - -/* Number of external interrupt lines to configure the GIC with */ -#define NUM_IRQS 256 - -#define PLATFORM_BUS_NUM_IRQS 64 - -static ARMPlatformBusSystemParams platform_bus_params; - -typedef struct VirtBoardInfo { - struct arm_boot_info bootinfo; - const char *cpu_model; - const MemMapEntry *memmap; - const int *irqmap; - int smp_cpus; - void *fdt; - int fdt_size; - uint32_t clock_phandle; - uint32_t gic_phandle; - uint32_t v2m_phandle; - bool using_psci; -} VirtBoardInfo; - -typedef struct { - MachineClass parent; - VirtBoardInfo *daughterboard; -} VirtMachineClass; - -typedef struct { - MachineState parent; - bool secure; - bool highmem; - int32_t gic_version; -} VirtMachineState; - -#define TYPE_VIRT_MACHINE MACHINE_TYPE_NAME("virt") -#define VIRT_MACHINE(obj) \ - OBJECT_CHECK(VirtMachineState, (obj), TYPE_VIRT_MACHINE) -#define VIRT_MACHINE_GET_CLASS(obj) \ - OBJECT_GET_CLASS(VirtMachineClass, obj, TYPE_VIRT_MACHINE) -#define VIRT_MACHINE_CLASS(klass) \ - OBJECT_CLASS_CHECK(VirtMachineClass, klass, TYPE_VIRT_MACHINE) - -/* RAM limit in GB. Since VIRT_MEM starts at the 1GB mark, this means - * RAM can go up to the 256GB mark, leaving 256GB of the physical - * address space unallocated and free for future use between 256G and 512G. - * If we need to provide more RAM to VMs in the future then we need to: - * * allocate a second bank of RAM starting at 2TB and working up - * * fix the DT and ACPI table generation code in QEMU to correctly - * report two split lumps of RAM to the guest - * * fix KVM in the host kernel to allow guests with >40 bit address spaces - * (We don't want to fill all the way up to 512GB with RAM because - * we might want it for non-RAM purposes later. Conversely it seems - * reasonable to assume that anybody configuring a VM with a quarter - * of a terabyte of RAM will be doing it on a host with more than a - * terabyte of physical address space.) - */ -#define RAMLIMIT_GB 255 -#define RAMLIMIT_BYTES (RAMLIMIT_GB * 1024ULL * 1024 * 1024) - -/* Addresses and sizes of our components. - * 0..128MB is space for a flash device so we can run bootrom code such as UEFI. - * 128MB..256MB is used for miscellaneous device I/O. - * 256MB..1GB is reserved for possible future PCI support (ie where the - * PCI memory window will go if we add a PCI host controller). - * 1GB and up is RAM (which may happily spill over into the - * high memory region beyond 4GB). - * This represents a compromise between how much RAM can be given to - * a 32 bit VM and leaving space for expansion and in particular for PCI. - * Note that devices should generally be placed at multiples of 0x10000, - * to accommodate guests using 64K pages. - */ -static const MemMapEntry a15memmap[] = { - /* Space up to 0x8000000 is reserved for a boot ROM */ - [VIRT_FLASH] = { 0, 0x08000000 }, - [VIRT_CPUPERIPHS] = { 0x08000000, 0x00020000 }, - /* GIC distributor and CPU interfaces sit inside the CPU peripheral space */ - [VIRT_GIC_DIST] = { 0x08000000, 0x00010000 }, - [VIRT_GIC_CPU] = { 0x08010000, 0x00010000 }, - [VIRT_GIC_V2M] = { 0x08020000, 0x00001000 }, - /* The space in between here is reserved for GICv3 CPU/vCPU/HYP */ - [VIRT_GIC_ITS] = { 0x08080000, 0x00020000 }, - /* This redistributor space allows up to 2*64kB*123 CPUs */ - [VIRT_GIC_REDIST] = { 0x080A0000, 0x00F60000 }, - [VIRT_UART] = { 0x09000000, 0x00001000 }, - [VIRT_RTC] = { 0x09010000, 0x00001000 }, - [VIRT_FW_CFG] = { 0x09020000, 0x00000018 }, - [VIRT_GPIO] = { 0x09030000, 0x00001000 }, - [VIRT_SECURE_UART] = { 0x09040000, 0x00001000 }, - [VIRT_MMIO] = { 0x0a000000, 0x00000200 }, - /* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */ - [VIRT_PLATFORM_BUS] = { 0x0c000000, 0x02000000 }, - [VIRT_SECURE_MEM] = { 0x0e000000, 0x01000000 }, - [VIRT_PCIE_MMIO] = { 0x10000000, 0x2eff0000 }, - [VIRT_PCIE_PIO] = { 0x3eff0000, 0x00010000 }, - [VIRT_PCIE_ECAM] = { 0x3f000000, 0x01000000 }, - [VIRT_MEM] = { 0x40000000, RAMLIMIT_BYTES }, - /* Second PCIe window, 512GB wide at the 512GB boundary */ - [VIRT_PCIE_MMIO_HIGH] = { 0x8000000000ULL, 0x8000000000ULL }, -}; - -static const int a15irqmap[] = { - [VIRT_UART] = 1, - [VIRT_RTC] = 2, - [VIRT_PCIE] = 3, /* ... to 6 */ - [VIRT_GPIO] = 7, - [VIRT_SECURE_UART] = 8, - [VIRT_MMIO] = 16, /* ...to 16 + NUM_VIRTIO_TRANSPORTS - 1 */ - [VIRT_GIC_V2M] = 48, /* ...to 48 + NUM_GICV2M_SPIS - 1 */ - [VIRT_PLATFORM_BUS] = 112, /* ...to 112 + PLATFORM_BUS_NUM_IRQS -1 */ -}; - -static VirtBoardInfo machines[] = { - { - .cpu_model = "cortex-a15", - .memmap = a15memmap, - .irqmap = a15irqmap, - }, - { - .cpu_model = "cortex-a53", - .memmap = a15memmap, - .irqmap = a15irqmap, - }, - { - .cpu_model = "cortex-a57", - .memmap = a15memmap, - .irqmap = a15irqmap, - }, - { - .cpu_model = "host", - .memmap = a15memmap, - .irqmap = a15irqmap, - }, -}; - -static VirtBoardInfo *find_machine_info(const char *cpu) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(machines); i++) { - if (strcmp(cpu, machines[i].cpu_model) == 0) { - return &machines[i]; - } - } - return NULL; -} - -static void create_fdt(VirtBoardInfo *vbi) -{ - void *fdt = create_device_tree(&vbi->fdt_size); - - if (!fdt) { - error_report("create_device_tree() failed"); - exit(1); - } - - vbi->fdt = fdt; - - /* Header */ - qemu_fdt_setprop_string(fdt, "/", "compatible", "linux,dummy-virt"); - qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 0x2); - qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 0x2); - - /* - * /chosen and /memory nodes must exist for load_dtb - * to fill in necessary properties later - */ - qemu_fdt_add_subnode(fdt, "/chosen"); - qemu_fdt_add_subnode(fdt, "/memory"); - qemu_fdt_setprop_string(fdt, "/memory", "device_type", "memory"); - - /* Clock node, for the benefit of the UART. The kernel device tree - * binding documentation claims the PL011 node clock properties are - * optional but in practice if you omit them the kernel refuses to - * probe for the device. - */ - vbi->clock_phandle = qemu_fdt_alloc_phandle(fdt); - qemu_fdt_add_subnode(fdt, "/apb-pclk"); - qemu_fdt_setprop_string(fdt, "/apb-pclk", "compatible", "fixed-clock"); - qemu_fdt_setprop_cell(fdt, "/apb-pclk", "#clock-cells", 0x0); - qemu_fdt_setprop_cell(fdt, "/apb-pclk", "clock-frequency", 24000000); - qemu_fdt_setprop_string(fdt, "/apb-pclk", "clock-output-names", - "clk24mhz"); - qemu_fdt_setprop_cell(fdt, "/apb-pclk", "phandle", vbi->clock_phandle); - -} - -static void fdt_add_psci_node(const VirtBoardInfo *vbi) -{ - uint32_t cpu_suspend_fn; - uint32_t cpu_off_fn; - uint32_t cpu_on_fn; - uint32_t migrate_fn; - void *fdt = vbi->fdt; - ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(0)); - - if (!vbi->using_psci) { - return; - } - - qemu_fdt_add_subnode(fdt, "/psci"); - if (armcpu->psci_version == 2) { - const char comp[] = "arm,psci-0.2\0arm,psci"; - qemu_fdt_setprop(fdt, "/psci", "compatible", comp, sizeof(comp)); - - cpu_off_fn = QEMU_PSCI_0_2_FN_CPU_OFF; - if (arm_feature(&armcpu->env, ARM_FEATURE_AARCH64)) { - cpu_suspend_fn = QEMU_PSCI_0_2_FN64_CPU_SUSPEND; - cpu_on_fn = QEMU_PSCI_0_2_FN64_CPU_ON; - migrate_fn = QEMU_PSCI_0_2_FN64_MIGRATE; - } else { - cpu_suspend_fn = QEMU_PSCI_0_2_FN_CPU_SUSPEND; - cpu_on_fn = QEMU_PSCI_0_2_FN_CPU_ON; - migrate_fn = QEMU_PSCI_0_2_FN_MIGRATE; - } - } else { - qemu_fdt_setprop_string(fdt, "/psci", "compatible", "arm,psci"); - - cpu_suspend_fn = QEMU_PSCI_0_1_FN_CPU_SUSPEND; - cpu_off_fn = QEMU_PSCI_0_1_FN_CPU_OFF; - cpu_on_fn = QEMU_PSCI_0_1_FN_CPU_ON; - migrate_fn = QEMU_PSCI_0_1_FN_MIGRATE; - } - - /* We adopt the PSCI spec's nomenclature, and use 'conduit' to refer - * to the instruction that should be used to invoke PSCI functions. - * However, the device tree binding uses 'method' instead, so that is - * what we should use here. - */ - qemu_fdt_setprop_string(fdt, "/psci", "method", "hvc"); - - qemu_fdt_setprop_cell(fdt, "/psci", "cpu_suspend", cpu_suspend_fn); - qemu_fdt_setprop_cell(fdt, "/psci", "cpu_off", cpu_off_fn); - qemu_fdt_setprop_cell(fdt, "/psci", "cpu_on", cpu_on_fn); - qemu_fdt_setprop_cell(fdt, "/psci", "migrate", migrate_fn); -} - -static void fdt_add_timer_nodes(const VirtBoardInfo *vbi, int gictype) -{ - /* Note that on A15 h/w these interrupts are level-triggered, - * but for the GIC implementation provided by both QEMU and KVM - * they are edge-triggered. - */ - ARMCPU *armcpu; - uint32_t irqflags = GIC_FDT_IRQ_FLAGS_EDGE_LO_HI; - - if (gictype == 2) { - irqflags = deposit32(irqflags, GIC_FDT_IRQ_PPI_CPU_START, - GIC_FDT_IRQ_PPI_CPU_WIDTH, - (1 << vbi->smp_cpus) - 1); - } - - qemu_fdt_add_subnode(vbi->fdt, "/timer"); - - armcpu = ARM_CPU(qemu_get_cpu(0)); - if (arm_feature(&armcpu->env, ARM_FEATURE_V8)) { - const char compat[] = "arm,armv8-timer\0arm,armv7-timer"; - qemu_fdt_setprop(vbi->fdt, "/timer", "compatible", - compat, sizeof(compat)); - } else { - qemu_fdt_setprop_string(vbi->fdt, "/timer", "compatible", - "arm,armv7-timer"); - } - qemu_fdt_setprop(vbi->fdt, "/timer", "always-on", NULL, 0); - qemu_fdt_setprop_cells(vbi->fdt, "/timer", "interrupts", - GIC_FDT_IRQ_TYPE_PPI, ARCH_TIMER_S_EL1_IRQ, irqflags, - GIC_FDT_IRQ_TYPE_PPI, ARCH_TIMER_NS_EL1_IRQ, irqflags, - GIC_FDT_IRQ_TYPE_PPI, ARCH_TIMER_VIRT_IRQ, irqflags, - GIC_FDT_IRQ_TYPE_PPI, ARCH_TIMER_NS_EL2_IRQ, irqflags); -} - -static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi) -{ - int cpu; - int addr_cells = 1; - - /* - * From Documentation/devicetree/bindings/arm/cpus.txt - * On ARM v8 64-bit systems value should be set to 2, - * that corresponds to the MPIDR_EL1 register size. - * If MPIDR_EL1[63:32] value is equal to 0 on all CPUs - * in the system, #address-cells can be set to 1, since - * MPIDR_EL1[63:32] bits are not used for CPUs - * identification. - * - * Here we actually don't know whether our system is 32- or 64-bit one. - * The simplest way to go is to examine affinity IDs of all our CPUs. If - * at least one of them has Aff3 populated, we set #address-cells to 2. - */ - for (cpu = 0; cpu < vbi->smp_cpus; cpu++) { - ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(cpu)); - - if (armcpu->mp_affinity & ARM_AFF3_MASK) { - addr_cells = 2; - break; - } - } - - qemu_fdt_add_subnode(vbi->fdt, "/cpus"); - qemu_fdt_setprop_cell(vbi->fdt, "/cpus", "#address-cells", addr_cells); - qemu_fdt_setprop_cell(vbi->fdt, "/cpus", "#size-cells", 0x0); - - for (cpu = vbi->smp_cpus - 1; cpu >= 0; cpu--) { - char *nodename = g_strdup_printf("/cpus/cpu@%d", cpu); - ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(cpu)); - - qemu_fdt_add_subnode(vbi->fdt, nodename); - qemu_fdt_setprop_string(vbi->fdt, nodename, "device_type", "cpu"); - qemu_fdt_setprop_string(vbi->fdt, nodename, "compatible", - armcpu->dtb_compatible); - - if (vbi->using_psci && vbi->smp_cpus > 1) { - qemu_fdt_setprop_string(vbi->fdt, nodename, - "enable-method", "psci"); - } - - if (addr_cells == 2) { - qemu_fdt_setprop_u64(vbi->fdt, nodename, "reg", - armcpu->mp_affinity); - } else { - qemu_fdt_setprop_cell(vbi->fdt, nodename, "reg", - armcpu->mp_affinity); - } - - g_free(nodename); - } -} - -static void fdt_add_v2m_gic_node(VirtBoardInfo *vbi) -{ - vbi->v2m_phandle = qemu_fdt_alloc_phandle(vbi->fdt); - qemu_fdt_add_subnode(vbi->fdt, "/intc/v2m"); - qemu_fdt_setprop_string(vbi->fdt, "/intc/v2m", "compatible", - "arm,gic-v2m-frame"); - qemu_fdt_setprop(vbi->fdt, "/intc/v2m", "msi-controller", NULL, 0); - qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc/v2m", "reg", - 2, vbi->memmap[VIRT_GIC_V2M].base, - 2, vbi->memmap[VIRT_GIC_V2M].size); - qemu_fdt_setprop_cell(vbi->fdt, "/intc/v2m", "phandle", vbi->v2m_phandle); -} - -static void fdt_add_gic_node(VirtBoardInfo *vbi, int type) -{ - vbi->gic_phandle = qemu_fdt_alloc_phandle(vbi->fdt); - qemu_fdt_setprop_cell(vbi->fdt, "/", "interrupt-parent", vbi->gic_phandle); - - qemu_fdt_add_subnode(vbi->fdt, "/intc"); - qemu_fdt_setprop_cell(vbi->fdt, "/intc", "#interrupt-cells", 3); - qemu_fdt_setprop(vbi->fdt, "/intc", "interrupt-controller", NULL, 0); - qemu_fdt_setprop_cell(vbi->fdt, "/intc", "#address-cells", 0x2); - qemu_fdt_setprop_cell(vbi->fdt, "/intc", "#size-cells", 0x2); - qemu_fdt_setprop(vbi->fdt, "/intc", "ranges", NULL, 0); - if (type == 3) { - qemu_fdt_setprop_string(vbi->fdt, "/intc", "compatible", - "arm,gic-v3"); - qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc", "reg", - 2, vbi->memmap[VIRT_GIC_DIST].base, - 2, vbi->memmap[VIRT_GIC_DIST].size, - 2, vbi->memmap[VIRT_GIC_REDIST].base, - 2, vbi->memmap[VIRT_GIC_REDIST].size); - } else { - /* 'cortex-a15-gic' means 'GIC v2' */ - qemu_fdt_setprop_string(vbi->fdt, "/intc", "compatible", - "arm,cortex-a15-gic"); - qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc", "reg", - 2, vbi->memmap[VIRT_GIC_DIST].base, - 2, vbi->memmap[VIRT_GIC_DIST].size, - 2, vbi->memmap[VIRT_GIC_CPU].base, - 2, vbi->memmap[VIRT_GIC_CPU].size); - } - - qemu_fdt_setprop_cell(vbi->fdt, "/intc", "phandle", vbi->gic_phandle); -} - -static void create_v2m(VirtBoardInfo *vbi, qemu_irq *pic) -{ - int i; - int irq = vbi->irqmap[VIRT_GIC_V2M]; - DeviceState *dev; - - dev = qdev_create(NULL, "arm-gicv2m"); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vbi->memmap[VIRT_GIC_V2M].base); - qdev_prop_set_uint32(dev, "base-spi", irq); - qdev_prop_set_uint32(dev, "num-spi", NUM_GICV2M_SPIS); - qdev_init_nofail(dev); - - for (i = 0; i < NUM_GICV2M_SPIS; i++) { - sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pic[irq + i]); - } - - fdt_add_v2m_gic_node(vbi); -} - -static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic, int type, bool secure) -{ - /* We create a standalone GIC */ - DeviceState *gicdev; - SysBusDevice *gicbusdev; - const char *gictype; - int i; - - gictype = (type == 3) ? gicv3_class_name() : gic_class_name(); - - gicdev = qdev_create(NULL, gictype); - qdev_prop_set_uint32(gicdev, "revision", type); - qdev_prop_set_uint32(gicdev, "num-cpu", smp_cpus); - /* Note that the num-irq property counts both internal and external - * interrupts; there are always 32 of the former (mandated by GIC spec). - */ - qdev_prop_set_uint32(gicdev, "num-irq", NUM_IRQS + 32); - if (!kvm_irqchip_in_kernel()) { - qdev_prop_set_bit(gicdev, "has-security-extensions", secure); - } - qdev_init_nofail(gicdev); - gicbusdev = SYS_BUS_DEVICE(gicdev); - sysbus_mmio_map(gicbusdev, 0, vbi->memmap[VIRT_GIC_DIST].base); - if (type == 3) { - sysbus_mmio_map(gicbusdev, 1, vbi->memmap[VIRT_GIC_REDIST].base); - } else { - sysbus_mmio_map(gicbusdev, 1, vbi->memmap[VIRT_GIC_CPU].base); - } - - /* Wire the outputs from each CPU's generic timer to the - * appropriate GIC PPI inputs, and the GIC's IRQ output to - * the CPU's IRQ input. - */ - for (i = 0; i < smp_cpus; i++) { - DeviceState *cpudev = DEVICE(qemu_get_cpu(i)); - int ppibase = NUM_IRQS + i * GIC_INTERNAL + GIC_NR_SGIS; - int irq; - /* Mapping from the output timer irq lines from the CPU to the - * GIC PPI inputs we use for the virt board. - */ - const int timer_irq[] = { - [GTIMER_PHYS] = ARCH_TIMER_NS_EL1_IRQ, - [GTIMER_VIRT] = ARCH_TIMER_VIRT_IRQ, - [GTIMER_HYP] = ARCH_TIMER_NS_EL2_IRQ, - [GTIMER_SEC] = ARCH_TIMER_S_EL1_IRQ, - }; - - for (irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) { - qdev_connect_gpio_out(cpudev, irq, - qdev_get_gpio_in(gicdev, - ppibase + timer_irq[irq])); - } - - sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ)); - sysbus_connect_irq(gicbusdev, i + smp_cpus, - qdev_get_gpio_in(cpudev, ARM_CPU_FIQ)); - } - - for (i = 0; i < NUM_IRQS; i++) { - pic[i] = qdev_get_gpio_in(gicdev, i); - } - - fdt_add_gic_node(vbi, type); - - if (type == 2) { - create_v2m(vbi, pic); - } -} - -static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic, int uart, - MemoryRegion *mem) -{ - char *nodename; - hwaddr base = vbi->memmap[uart].base; - hwaddr size = vbi->memmap[uart].size; - int irq = vbi->irqmap[uart]; - const char compat[] = "arm,pl011\0arm,primecell"; - const char clocknames[] = "uartclk\0apb_pclk"; - DeviceState *dev = qdev_create(NULL, "pl011"); - SysBusDevice *s = SYS_BUS_DEVICE(dev); - - qdev_init_nofail(dev); - memory_region_add_subregion(mem, base, - sysbus_mmio_get_region(s, 0)); - sysbus_connect_irq(s, 0, pic[irq]); - - nodename = g_strdup_printf("/pl011@%" PRIx64, base); - qemu_fdt_add_subnode(vbi->fdt, nodename); - /* Note that we can't use setprop_string because of the embedded NUL */ - qemu_fdt_setprop(vbi->fdt, nodename, "compatible", - compat, sizeof(compat)); - qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", - 2, base, 2, size); - qemu_fdt_setprop_cells(vbi->fdt, nodename, "interrupts", - GIC_FDT_IRQ_TYPE_SPI, irq, - GIC_FDT_IRQ_FLAGS_LEVEL_HI); - qemu_fdt_setprop_cells(vbi->fdt, nodename, "clocks", - vbi->clock_phandle, vbi->clock_phandle); - qemu_fdt_setprop(vbi->fdt, nodename, "clock-names", - clocknames, sizeof(clocknames)); - - if (uart == VIRT_UART) { - qemu_fdt_setprop_string(vbi->fdt, "/chosen", "stdout-path", nodename); - } else { - /* Mark as not usable by the normal world */ - qemu_fdt_setprop_string(vbi->fdt, nodename, "status", "disabled"); - qemu_fdt_setprop_string(vbi->fdt, nodename, "secure-status", "okay"); - } - - g_free(nodename); -} - -static void create_rtc(const VirtBoardInfo *vbi, qemu_irq *pic) -{ - char *nodename; - hwaddr base = vbi->memmap[VIRT_RTC].base; - hwaddr size = vbi->memmap[VIRT_RTC].size; - int irq = vbi->irqmap[VIRT_RTC]; - const char compat[] = "arm,pl031\0arm,primecell"; - - sysbus_create_simple("pl031", base, pic[irq]); - - nodename = g_strdup_printf("/pl031@%" PRIx64, base); - qemu_fdt_add_subnode(vbi->fdt, nodename); - qemu_fdt_setprop(vbi->fdt, nodename, "compatible", compat, sizeof(compat)); - qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", - 2, base, 2, size); - qemu_fdt_setprop_cells(vbi->fdt, nodename, "interrupts", - GIC_FDT_IRQ_TYPE_SPI, irq, - GIC_FDT_IRQ_FLAGS_LEVEL_HI); - qemu_fdt_setprop_cell(vbi->fdt, nodename, "clocks", vbi->clock_phandle); - qemu_fdt_setprop_string(vbi->fdt, nodename, "clock-names", "apb_pclk"); - g_free(nodename); -} - -static DeviceState *gpio_key_dev; -static void virt_powerdown_req(Notifier *n, void *opaque) -{ - /* use gpio Pin 3 for power button event */ - qemu_set_irq(qdev_get_gpio_in(gpio_key_dev, 0), 1); -} - -static Notifier virt_system_powerdown_notifier = { - .notify = virt_powerdown_req -}; - -static void create_gpio(const VirtBoardInfo *vbi, qemu_irq *pic) -{ - char *nodename; - DeviceState *pl061_dev; - hwaddr base = vbi->memmap[VIRT_GPIO].base; - hwaddr size = vbi->memmap[VIRT_GPIO].size; - int irq = vbi->irqmap[VIRT_GPIO]; - const char compat[] = "arm,pl061\0arm,primecell"; - - pl061_dev = sysbus_create_simple("pl061", base, pic[irq]); - - uint32_t phandle = qemu_fdt_alloc_phandle(vbi->fdt); - nodename = g_strdup_printf("/pl061@%" PRIx64, base); - qemu_fdt_add_subnode(vbi->fdt, nodename); - qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", - 2, base, 2, size); - qemu_fdt_setprop(vbi->fdt, nodename, "compatible", compat, sizeof(compat)); - qemu_fdt_setprop_cell(vbi->fdt, nodename, "#gpio-cells", 2); - qemu_fdt_setprop(vbi->fdt, nodename, "gpio-controller", NULL, 0); - qemu_fdt_setprop_cells(vbi->fdt, nodename, "interrupts", - GIC_FDT_IRQ_TYPE_SPI, irq, - GIC_FDT_IRQ_FLAGS_LEVEL_HI); - qemu_fdt_setprop_cell(vbi->fdt, nodename, "clocks", vbi->clock_phandle); - qemu_fdt_setprop_string(vbi->fdt, nodename, "clock-names", "apb_pclk"); - qemu_fdt_setprop_cell(vbi->fdt, nodename, "phandle", phandle); - - gpio_key_dev = sysbus_create_simple("gpio-key", -1, - qdev_get_gpio_in(pl061_dev, 3)); - qemu_fdt_add_subnode(vbi->fdt, "/gpio-keys"); - qemu_fdt_setprop_string(vbi->fdt, "/gpio-keys", "compatible", "gpio-keys"); - qemu_fdt_setprop_cell(vbi->fdt, "/gpio-keys", "#size-cells", 0); - qemu_fdt_setprop_cell(vbi->fdt, "/gpio-keys", "#address-cells", 1); - - qemu_fdt_add_subnode(vbi->fdt, "/gpio-keys/poweroff"); - qemu_fdt_setprop_string(vbi->fdt, "/gpio-keys/poweroff", - "label", "GPIO Key Poweroff"); - qemu_fdt_setprop_cell(vbi->fdt, "/gpio-keys/poweroff", "linux,code", - KEY_POWER); - qemu_fdt_setprop_cells(vbi->fdt, "/gpio-keys/poweroff", - "gpios", phandle, 3, 0); - - /* connect powerdown request */ - qemu_register_powerdown_notifier(&virt_system_powerdown_notifier); - - g_free(nodename); -} - -static void create_virtio_devices(const VirtBoardInfo *vbi, qemu_irq *pic) -{ - int i; - hwaddr size = vbi->memmap[VIRT_MMIO].size; - - /* We create the transports in forwards order. Since qbus_realize() - * prepends (not appends) new child buses, the incrementing loop below will - * create a list of virtio-mmio buses with decreasing base addresses. - * - * When a -device option is processed from the command line, - * qbus_find_recursive() picks the next free virtio-mmio bus in forwards - * order. The upshot is that -device options in increasing command line - * order are mapped to virtio-mmio buses with decreasing base addresses. - * - * When this code was originally written, that arrangement ensured that the - * guest Linux kernel would give the lowest "name" (/dev/vda, eth0, etc) to - * the first -device on the command line. (The end-to-end order is a - * function of this loop, qbus_realize(), qbus_find_recursive(), and the - * guest kernel's name-to-address assignment strategy.) - * - * Meanwhile, the kernel's traversal seems to have been reversed; see eg. - * the message, if not necessarily the code, of commit 70161ff336. - * Therefore the loop now establishes the inverse of the original intent. - * - * Unfortunately, we can't counteract the kernel change by reversing the - * loop; it would break existing command lines. - * - * In any case, the kernel makes no guarantee about the stability of - * enumeration order of virtio devices (as demonstrated by it changing - * between kernel versions). For reliable and stable identification - * of disks users must use UUIDs or similar mechanisms. - */ - for (i = 0; i < NUM_VIRTIO_TRANSPORTS; i++) { - int irq = vbi->irqmap[VIRT_MMIO] + i; - hwaddr base = vbi->memmap[VIRT_MMIO].base + i * size; - - sysbus_create_simple("virtio-mmio", base, pic[irq]); - } - - /* We add dtb nodes in reverse order so that they appear in the finished - * device tree lowest address first. - * - * Note that this mapping is independent of the loop above. The previous - * loop influences virtio device to virtio transport assignment, whereas - * this loop controls how virtio transports are laid out in the dtb. - */ - for (i = NUM_VIRTIO_TRANSPORTS - 1; i >= 0; i--) { - char *nodename; - int irq = vbi->irqmap[VIRT_MMIO] + i; - hwaddr base = vbi->memmap[VIRT_MMIO].base + i * size; - - nodename = g_strdup_printf("/virtio_mmio@%" PRIx64, base); - qemu_fdt_add_subnode(vbi->fdt, nodename); - qemu_fdt_setprop_string(vbi->fdt, nodename, - "compatible", "virtio,mmio"); - qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", - 2, base, 2, size); - qemu_fdt_setprop_cells(vbi->fdt, nodename, "interrupts", - GIC_FDT_IRQ_TYPE_SPI, irq, - GIC_FDT_IRQ_FLAGS_EDGE_LO_HI); - g_free(nodename); - } -} - -static void create_one_flash(const char *name, hwaddr flashbase, - hwaddr flashsize, const char *file, - MemoryRegion *sysmem) -{ - /* Create and map a single flash device. We use the same - * parameters as the flash devices on the Versatile Express board. - */ - DriveInfo *dinfo = drive_get_next(IF_PFLASH); - DeviceState *dev = qdev_create(NULL, "cfi.pflash01"); - SysBusDevice *sbd = SYS_BUS_DEVICE(dev); - const uint64_t sectorlength = 256 * 1024; - - if (dinfo) { - qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(dinfo), - &error_abort); - } - - qdev_prop_set_uint32(dev, "num-blocks", flashsize / sectorlength); - qdev_prop_set_uint64(dev, "sector-length", sectorlength); - qdev_prop_set_uint8(dev, "width", 4); - qdev_prop_set_uint8(dev, "device-width", 2); - qdev_prop_set_bit(dev, "big-endian", false); - qdev_prop_set_uint16(dev, "id0", 0x89); - qdev_prop_set_uint16(dev, "id1", 0x18); - qdev_prop_set_uint16(dev, "id2", 0x00); - qdev_prop_set_uint16(dev, "id3", 0x00); - qdev_prop_set_string(dev, "name", name); - qdev_init_nofail(dev); - - memory_region_add_subregion(sysmem, flashbase, - sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0)); - - if (file) { - char *fn; - int image_size; - - if (drive_get(IF_PFLASH, 0, 0)) { - error_report("The contents of the first flash device may be " - "specified with -bios or with -drive if=pflash... " - "but you cannot use both options at once"); - exit(1); - } - fn = qemu_find_file(QEMU_FILE_TYPE_BIOS, file); - if (!fn) { - error_report("Could not find ROM image '%s'", file); - exit(1); - } - image_size = load_image_mr(fn, sysbus_mmio_get_region(sbd, 0)); - g_free(fn); - if (image_size < 0) { - error_report("Could not load ROM image '%s'", file); - exit(1); - } - } -} - -static void create_flash(const VirtBoardInfo *vbi, - MemoryRegion *sysmem, - MemoryRegion *secure_sysmem) -{ - /* Create two flash devices to fill the VIRT_FLASH space in the memmap. - * Any file passed via -bios goes in the first of these. - * sysmem is the system memory space. secure_sysmem is the secure view - * of the system, and the first flash device should be made visible only - * there. The second flash device is visible to both secure and nonsecure. - * If sysmem == secure_sysmem this means there is no separate Secure - * address space and both flash devices are generally visible. - */ - hwaddr flashsize = vbi->memmap[VIRT_FLASH].size / 2; - hwaddr flashbase = vbi->memmap[VIRT_FLASH].base; - char *nodename; - - create_one_flash("virt.flash0", flashbase, flashsize, - bios_name, secure_sysmem); - create_one_flash("virt.flash1", flashbase + flashsize, flashsize, - NULL, sysmem); - - if (sysmem == secure_sysmem) { - /* Report both flash devices as a single node in the DT */ - nodename = g_strdup_printf("/flash@%" PRIx64, flashbase); - qemu_fdt_add_subnode(vbi->fdt, nodename); - qemu_fdt_setprop_string(vbi->fdt, nodename, "compatible", "cfi-flash"); - qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", - 2, flashbase, 2, flashsize, - 2, flashbase + flashsize, 2, flashsize); - qemu_fdt_setprop_cell(vbi->fdt, nodename, "bank-width", 4); - g_free(nodename); - } else { - /* Report the devices as separate nodes so we can mark one as - * only visible to the secure world. - */ - nodename = g_strdup_printf("/secflash@%" PRIx64, flashbase); - qemu_fdt_add_subnode(vbi->fdt, nodename); - qemu_fdt_setprop_string(vbi->fdt, nodename, "compatible", "cfi-flash"); - qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", - 2, flashbase, 2, flashsize); - qemu_fdt_setprop_cell(vbi->fdt, nodename, "bank-width", 4); - qemu_fdt_setprop_string(vbi->fdt, nodename, "status", "disabled"); - qemu_fdt_setprop_string(vbi->fdt, nodename, "secure-status", "okay"); - g_free(nodename); - - nodename = g_strdup_printf("/flash@%" PRIx64, flashbase); - qemu_fdt_add_subnode(vbi->fdt, nodename); - qemu_fdt_setprop_string(vbi->fdt, nodename, "compatible", "cfi-flash"); - qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", - 2, flashbase + flashsize, 2, flashsize); - qemu_fdt_setprop_cell(vbi->fdt, nodename, "bank-width", 4); - g_free(nodename); - } -} - -static void create_fw_cfg(const VirtBoardInfo *vbi, AddressSpace *as) -{ - hwaddr base = vbi->memmap[VIRT_FW_CFG].base; - hwaddr size = vbi->memmap[VIRT_FW_CFG].size; - char *nodename; - - fw_cfg_init_mem_wide(base + 8, base, 8, base + 16, as); - - nodename = g_strdup_printf("/fw-cfg@%" PRIx64, base); - qemu_fdt_add_subnode(vbi->fdt, nodename); - qemu_fdt_setprop_string(vbi->fdt, nodename, - "compatible", "qemu,fw-cfg-mmio"); - qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", - 2, base, 2, size); - g_free(nodename); -} - -static void create_pcie_irq_map(const VirtBoardInfo *vbi, uint32_t gic_phandle, - int first_irq, const char *nodename) -{ - int devfn, pin; - uint32_t full_irq_map[4 * 4 * 10] = { 0 }; - uint32_t *irq_map = full_irq_map; - - for (devfn = 0; devfn <= 0x18; devfn += 0x8) { - for (pin = 0; pin < 4; pin++) { - int irq_type = GIC_FDT_IRQ_TYPE_SPI; - int irq_nr = first_irq + ((pin + PCI_SLOT(devfn)) % PCI_NUM_PINS); - int irq_level = GIC_FDT_IRQ_FLAGS_LEVEL_HI; - int i; - - uint32_t map[] = { - devfn << 8, 0, 0, /* devfn */ - pin + 1, /* PCI pin */ - gic_phandle, 0, 0, irq_type, irq_nr, irq_level }; /* GIC irq */ - - /* Convert map to big endian */ - for (i = 0; i < 10; i++) { - irq_map[i] = cpu_to_be32(map[i]); - } - irq_map += 10; - } - } - - qemu_fdt_setprop(vbi->fdt, nodename, "interrupt-map", - full_irq_map, sizeof(full_irq_map)); - - qemu_fdt_setprop_cells(vbi->fdt, nodename, "interrupt-map-mask", - 0x1800, 0, 0, /* devfn (PCI_SLOT(3)) */ - 0x7 /* PCI irq */); -} - -static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic, - bool use_highmem) -{ - hwaddr base_mmio = vbi->memmap[VIRT_PCIE_MMIO].base; - hwaddr size_mmio = vbi->memmap[VIRT_PCIE_MMIO].size; - hwaddr base_mmio_high = vbi->memmap[VIRT_PCIE_MMIO_HIGH].base; - hwaddr size_mmio_high = vbi->memmap[VIRT_PCIE_MMIO_HIGH].size; - hwaddr base_pio = vbi->memmap[VIRT_PCIE_PIO].base; - hwaddr size_pio = vbi->memmap[VIRT_PCIE_PIO].size; - hwaddr base_ecam = vbi->memmap[VIRT_PCIE_ECAM].base; - hwaddr size_ecam = vbi->memmap[VIRT_PCIE_ECAM].size; - hwaddr base = base_mmio; - int nr_pcie_buses = size_ecam / PCIE_MMCFG_SIZE_MIN; - int irq = vbi->irqmap[VIRT_PCIE]; - MemoryRegion *mmio_alias; - MemoryRegion *mmio_reg; - MemoryRegion *ecam_alias; - MemoryRegion *ecam_reg; - DeviceState *dev; - char *nodename; - int i; - PCIHostState *pci; - - dev = qdev_create(NULL, TYPE_GPEX_HOST); - qdev_init_nofail(dev); - - /* Map only the first size_ecam bytes of ECAM space */ - ecam_alias = g_new0(MemoryRegion, 1); - ecam_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0); - memory_region_init_alias(ecam_alias, OBJECT(dev), "pcie-ecam", - ecam_reg, 0, size_ecam); - memory_region_add_subregion(get_system_memory(), base_ecam, ecam_alias); - - /* Map the MMIO window into system address space so as to expose - * the section of PCI MMIO space which starts at the same base address - * (ie 1:1 mapping for that part of PCI MMIO space visible through - * the window). - */ - mmio_alias = g_new0(MemoryRegion, 1); - mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1); - memory_region_init_alias(mmio_alias, OBJECT(dev), "pcie-mmio", - mmio_reg, base_mmio, size_mmio); - memory_region_add_subregion(get_system_memory(), base_mmio, mmio_alias); - - if (use_highmem) { - /* Map high MMIO space */ - MemoryRegion *high_mmio_alias = g_new0(MemoryRegion, 1); - - memory_region_init_alias(high_mmio_alias, OBJECT(dev), "pcie-mmio-high", - mmio_reg, base_mmio_high, size_mmio_high); - memory_region_add_subregion(get_system_memory(), base_mmio_high, - high_mmio_alias); - } - - /* Map IO port space */ - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, base_pio); - - for (i = 0; i < GPEX_NUM_IRQS; i++) { - sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pic[irq + i]); - } - - pci = PCI_HOST_BRIDGE(dev); - if (pci->bus) { - for (i = 0; i < nb_nics; i++) { - NICInfo *nd = &nd_table[i]; - - if (!nd->model) { - nd->model = g_strdup("virtio"); - } - - pci_nic_init_nofail(nd, pci->bus, nd->model, NULL); - } - } - - nodename = g_strdup_printf("/pcie@%" PRIx64, base); - qemu_fdt_add_subnode(vbi->fdt, nodename); - qemu_fdt_setprop_string(vbi->fdt, nodename, - "compatible", "pci-host-ecam-generic"); - qemu_fdt_setprop_string(vbi->fdt, nodename, "device_type", "pci"); - qemu_fdt_setprop_cell(vbi->fdt, nodename, "#address-cells", 3); - qemu_fdt_setprop_cell(vbi->fdt, nodename, "#size-cells", 2); - qemu_fdt_setprop_cells(vbi->fdt, nodename, "bus-range", 0, - nr_pcie_buses - 1); - - if (vbi->v2m_phandle) { - qemu_fdt_setprop_cells(vbi->fdt, nodename, "msi-parent", - vbi->v2m_phandle); - } - - qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", - 2, base_ecam, 2, size_ecam); - - if (use_highmem) { - qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "ranges", - 1, FDT_PCI_RANGE_IOPORT, 2, 0, - 2, base_pio, 2, size_pio, - 1, FDT_PCI_RANGE_MMIO, 2, base_mmio, - 2, base_mmio, 2, size_mmio, - 1, FDT_PCI_RANGE_MMIO_64BIT, - 2, base_mmio_high, - 2, base_mmio_high, 2, size_mmio_high); - } else { - qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "ranges", - 1, FDT_PCI_RANGE_IOPORT, 2, 0, - 2, base_pio, 2, size_pio, - 1, FDT_PCI_RANGE_MMIO, 2, base_mmio, - 2, base_mmio, 2, size_mmio); - } - - qemu_fdt_setprop_cell(vbi->fdt, nodename, "#interrupt-cells", 1); - create_pcie_irq_map(vbi, vbi->gic_phandle, irq, nodename); - - g_free(nodename); -} - -static void create_platform_bus(VirtBoardInfo *vbi, qemu_irq *pic) -{ - DeviceState *dev; - SysBusDevice *s; - int i; - ARMPlatformBusFDTParams *fdt_params = g_new(ARMPlatformBusFDTParams, 1); - MemoryRegion *sysmem = get_system_memory(); - - platform_bus_params.platform_bus_base = vbi->memmap[VIRT_PLATFORM_BUS].base; - platform_bus_params.platform_bus_size = vbi->memmap[VIRT_PLATFORM_BUS].size; - platform_bus_params.platform_bus_first_irq = vbi->irqmap[VIRT_PLATFORM_BUS]; - platform_bus_params.platform_bus_num_irqs = PLATFORM_BUS_NUM_IRQS; - - fdt_params->system_params = &platform_bus_params; - fdt_params->binfo = &vbi->bootinfo; - fdt_params->intc = "/intc"; - /* - * register a machine init done notifier that creates the device tree - * nodes of the platform bus and its children dynamic sysbus devices - */ - arm_register_platform_bus_fdt_creator(fdt_params); - - dev = qdev_create(NULL, TYPE_PLATFORM_BUS_DEVICE); - dev->id = TYPE_PLATFORM_BUS_DEVICE; - qdev_prop_set_uint32(dev, "num_irqs", - platform_bus_params.platform_bus_num_irqs); - qdev_prop_set_uint32(dev, "mmio_size", - platform_bus_params.platform_bus_size); - qdev_init_nofail(dev); - s = SYS_BUS_DEVICE(dev); - - for (i = 0; i < platform_bus_params.platform_bus_num_irqs; i++) { - int irqn = platform_bus_params.platform_bus_first_irq + i; - sysbus_connect_irq(s, i, pic[irqn]); - } - - memory_region_add_subregion(sysmem, - platform_bus_params.platform_bus_base, - sysbus_mmio_get_region(s, 0)); -} - -static void create_secure_ram(VirtBoardInfo *vbi, MemoryRegion *secure_sysmem) -{ - MemoryRegion *secram = g_new(MemoryRegion, 1); - char *nodename; - hwaddr base = vbi->memmap[VIRT_SECURE_MEM].base; - hwaddr size = vbi->memmap[VIRT_SECURE_MEM].size; - - memory_region_init_ram(secram, NULL, "virt.secure-ram", size, &error_fatal); - vmstate_register_ram_global(secram); - memory_region_add_subregion(secure_sysmem, base, secram); - - nodename = g_strdup_printf("/secram@%" PRIx64, base); - qemu_fdt_add_subnode(vbi->fdt, nodename); - qemu_fdt_setprop_string(vbi->fdt, nodename, "device_type", "memory"); - qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", 2, base, 2, size); - qemu_fdt_setprop_string(vbi->fdt, nodename, "status", "disabled"); - qemu_fdt_setprop_string(vbi->fdt, nodename, "secure-status", "okay"); - - g_free(nodename); -} - -static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size) -{ - const VirtBoardInfo *board = (const VirtBoardInfo *)binfo; - - *fdt_size = board->fdt_size; - return board->fdt; -} - -static void virt_build_smbios(VirtGuestInfo *guest_info) -{ - FWCfgState *fw_cfg = guest_info->fw_cfg; - uint8_t *smbios_tables, *smbios_anchor; - size_t smbios_tables_len, smbios_anchor_len; - const char *product = "QEMU Virtual Machine"; - - if (!fw_cfg) { - return; - } - - if (kvm_enabled()) { - product = "KVM Virtual Machine"; - } - - smbios_set_defaults("QEMU", product, - "1.0", false, true, SMBIOS_ENTRY_POINT_30); - - smbios_get_tables(NULL, 0, &smbios_tables, &smbios_tables_len, - &smbios_anchor, &smbios_anchor_len); - - if (smbios_anchor) { - fw_cfg_add_file(fw_cfg, "etc/smbios/smbios-tables", - smbios_tables, smbios_tables_len); - fw_cfg_add_file(fw_cfg, "etc/smbios/smbios-anchor", - smbios_anchor, smbios_anchor_len); - } -} - -static -void virt_guest_info_machine_done(Notifier *notifier, void *data) -{ - VirtGuestInfoState *guest_info_state = container_of(notifier, - VirtGuestInfoState, machine_done); - virt_acpi_setup(&guest_info_state->info); - virt_build_smbios(&guest_info_state->info); -} - -static void machvirt_init(MachineState *machine) -{ - VirtMachineState *vms = VIRT_MACHINE(machine); - qemu_irq pic[NUM_IRQS]; - MemoryRegion *sysmem = get_system_memory(); - MemoryRegion *secure_sysmem = NULL; - int gic_version = vms->gic_version; - int n, virt_max_cpus; - MemoryRegion *ram = g_new(MemoryRegion, 1); - const char *cpu_model = machine->cpu_model; - VirtBoardInfo *vbi; - VirtGuestInfoState *guest_info_state = g_malloc0(sizeof *guest_info_state); - VirtGuestInfo *guest_info = &guest_info_state->info; - char **cpustr; - bool firmware_loaded = bios_name || drive_get(IF_PFLASH, 0, 0); - - if (!cpu_model) { - cpu_model = "cortex-a15"; - } - - /* We can probe only here because during property set - * KVM is not available yet - */ - if (!gic_version) { - gic_version = kvm_arm_vgic_probe(); - if (!gic_version) { - error_report("Unable to determine GIC version supported by host"); - error_printf("KVM acceleration is probably not supported\n"); - exit(1); - } - } - - /* Separate the actual CPU model name from any appended features */ - cpustr = g_strsplit(cpu_model, ",", 2); - - vbi = find_machine_info(cpustr[0]); - - if (!vbi) { - error_report("mach-virt: CPU %s not supported", cpustr[0]); - exit(1); - } - - /* If we have an EL3 boot ROM then the assumption is that it will - * implement PSCI itself, so disable QEMU's internal implementation - * so it doesn't get in the way. Instead of starting secondary - * CPUs in PSCI powerdown state we will start them all running and - * let the boot ROM sort them out. - * The usual case is that we do use QEMU's PSCI implementation. - */ - vbi->using_psci = !(vms->secure && firmware_loaded); - - /* The maximum number of CPUs depends on the GIC version, or on how - * many redistributors we can fit into the memory map. - */ - if (gic_version == 3) { - virt_max_cpus = vbi->memmap[VIRT_GIC_REDIST].size / 0x20000; - } else { - virt_max_cpus = GIC_NCPU; - } - - if (max_cpus > virt_max_cpus) { - error_report("Number of SMP CPUs requested (%d) exceeds max CPUs " - "supported by machine 'mach-virt' (%d)", - max_cpus, virt_max_cpus); - exit(1); - } - - vbi->smp_cpus = smp_cpus; - - if (machine->ram_size > vbi->memmap[VIRT_MEM].size) { - error_report("mach-virt: cannot model more than %dGB RAM", RAMLIMIT_GB); - exit(1); - } - - if (vms->secure) { - if (kvm_enabled()) { - error_report("mach-virt: KVM does not support Security extensions"); - exit(1); - } - - /* The Secure view of the world is the same as the NonSecure, - * but with a few extra devices. Create it as a container region - * containing the system memory at low priority; any secure-only - * devices go in at higher priority and take precedence. - */ - secure_sysmem = g_new(MemoryRegion, 1); - memory_region_init(secure_sysmem, OBJECT(machine), "secure-memory", - UINT64_MAX); - memory_region_add_subregion_overlap(secure_sysmem, 0, sysmem, -1); - } - - create_fdt(vbi); - - for (n = 0; n < smp_cpus; n++) { - ObjectClass *oc = cpu_class_by_name(TYPE_ARM_CPU, cpustr[0]); - CPUClass *cc = CPU_CLASS(oc); - Object *cpuobj; - Error *err = NULL; - char *cpuopts = g_strdup(cpustr[1]); - - if (!oc) { - error_report("Unable to find CPU definition"); - exit(1); - } - cpuobj = object_new(object_class_get_name(oc)); - - /* Handle any CPU options specified by the user */ - cc->parse_features(CPU(cpuobj), cpuopts, &err); - g_free(cpuopts); - if (err) { - error_report_err(err); - exit(1); - } - - if (!vms->secure) { - object_property_set_bool(cpuobj, false, "has_el3", NULL); - } - - if (vbi->using_psci) { - object_property_set_int(cpuobj, QEMU_PSCI_CONDUIT_HVC, - "psci-conduit", NULL); - - /* Secondary CPUs start in PSCI powered-down state */ - if (n > 0) { - object_property_set_bool(cpuobj, true, - "start-powered-off", NULL); - } - } - - if (object_property_find(cpuobj, "reset-cbar", NULL)) { - object_property_set_int(cpuobj, vbi->memmap[VIRT_CPUPERIPHS].base, - "reset-cbar", &error_abort); - } - - object_property_set_link(cpuobj, OBJECT(sysmem), "memory", - &error_abort); - if (vms->secure) { - object_property_set_link(cpuobj, OBJECT(secure_sysmem), - "secure-memory", &error_abort); - } - - object_property_set_bool(cpuobj, true, "realized", NULL); - } - g_strfreev(cpustr); - fdt_add_timer_nodes(vbi, gic_version); - fdt_add_cpu_nodes(vbi); - fdt_add_psci_node(vbi); - - memory_region_allocate_system_memory(ram, NULL, "mach-virt.ram", - machine->ram_size); - memory_region_add_subregion(sysmem, vbi->memmap[VIRT_MEM].base, ram); - - create_flash(vbi, sysmem, secure_sysmem ? secure_sysmem : sysmem); - - create_gic(vbi, pic, gic_version, vms->secure); - - create_uart(vbi, pic, VIRT_UART, sysmem); - - if (vms->secure) { - create_secure_ram(vbi, secure_sysmem); - create_uart(vbi, pic, VIRT_SECURE_UART, secure_sysmem); - } - - create_rtc(vbi, pic); - - create_pcie(vbi, pic, vms->highmem); - - create_gpio(vbi, pic); - - /* Create mmio transports, so the user can create virtio backends - * (which will be automatically plugged in to the transports). If - * no backend is created the transport will just sit harmlessly idle. - */ - create_virtio_devices(vbi, pic); - - create_fw_cfg(vbi, &address_space_memory); - rom_set_fw(fw_cfg_find()); - - guest_info->smp_cpus = smp_cpus; - guest_info->fw_cfg = fw_cfg_find(); - guest_info->memmap = vbi->memmap; - guest_info->irqmap = vbi->irqmap; - guest_info->use_highmem = vms->highmem; - guest_info->gic_version = gic_version; - guest_info_state->machine_done.notify = virt_guest_info_machine_done; - qemu_add_machine_init_done_notifier(&guest_info_state->machine_done); - - vbi->bootinfo.ram_size = machine->ram_size; - vbi->bootinfo.kernel_filename = machine->kernel_filename; - vbi->bootinfo.kernel_cmdline = machine->kernel_cmdline; - vbi->bootinfo.initrd_filename = machine->initrd_filename; - vbi->bootinfo.nb_cpus = smp_cpus; - vbi->bootinfo.board_id = -1; - vbi->bootinfo.loader_start = vbi->memmap[VIRT_MEM].base; - vbi->bootinfo.get_dtb = machvirt_dtb; - vbi->bootinfo.firmware_loaded = firmware_loaded; - arm_load_kernel(ARM_CPU(first_cpu), &vbi->bootinfo); - - /* - * arm_load_kernel machine init done notifier registration must - * happen before the platform_bus_create call. In this latter, - * another notifier is registered which adds platform bus nodes. - * Notifiers are executed in registration reverse order. - */ - create_platform_bus(vbi, pic); -} - -static bool virt_get_secure(Object *obj, Error **errp) -{ - VirtMachineState *vms = VIRT_MACHINE(obj); - - return vms->secure; -} - -static void virt_set_secure(Object *obj, bool value, Error **errp) -{ - VirtMachineState *vms = VIRT_MACHINE(obj); - - vms->secure = value; -} - -static bool virt_get_highmem(Object *obj, Error **errp) -{ - VirtMachineState *vms = VIRT_MACHINE(obj); - - return vms->highmem; -} - -static void virt_set_highmem(Object *obj, bool value, Error **errp) -{ - VirtMachineState *vms = VIRT_MACHINE(obj); - - vms->highmem = value; -} - -static char *virt_get_gic_version(Object *obj, Error **errp) -{ - VirtMachineState *vms = VIRT_MACHINE(obj); - const char *val = vms->gic_version == 3 ? "3" : "2"; - - return g_strdup(val); -} - -static void virt_set_gic_version(Object *obj, const char *value, Error **errp) -{ - VirtMachineState *vms = VIRT_MACHINE(obj); - - if (!strcmp(value, "3")) { - vms->gic_version = 3; - } else if (!strcmp(value, "2")) { - vms->gic_version = 2; - } else if (!strcmp(value, "host")) { - vms->gic_version = 0; /* Will probe later */ - } else { - error_setg(errp, "Invalid gic-version value"); - error_append_hint(errp, "Valid values are 3, 2, host.\n"); - } -} - -static void virt_machine_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->init = machvirt_init; - /* Start max_cpus at the maximum QEMU supports. We'll further restrict - * it later in machvirt_init, where we have more information about the - * configuration of the particular instance. - */ - mc->max_cpus = MAX_CPUMASK_BITS; - mc->has_dynamic_sysbus = true; - mc->block_default_type = IF_VIRTIO; - mc->no_cdrom = 1; - mc->pci_allow_0_address = true; -} - -static const TypeInfo virt_machine_info = { - .name = TYPE_VIRT_MACHINE, - .parent = TYPE_MACHINE, - .abstract = true, - .instance_size = sizeof(VirtMachineState), - .class_size = sizeof(VirtMachineClass), - .class_init = virt_machine_class_init, -}; - -static void virt_2_6_instance_init(Object *obj) -{ - VirtMachineState *vms = VIRT_MACHINE(obj); - - /* EL3 is disabled by default on virt: this makes us consistent - * between KVM and TCG for this board, and it also allows us to - * boot UEFI blobs which assume no TrustZone support. - */ - vms->secure = false; - object_property_add_bool(obj, "secure", virt_get_secure, - virt_set_secure, NULL); - object_property_set_description(obj, "secure", - "Set on/off to enable/disable the ARM " - "Security Extensions (TrustZone)", - NULL); - - /* High memory is enabled by default */ - vms->highmem = true; - object_property_add_bool(obj, "highmem", virt_get_highmem, - virt_set_highmem, NULL); - object_property_set_description(obj, "highmem", - "Set on/off to enable/disable using " - "physical address space above 32 bits", - NULL); - /* Default GIC type is v2 */ - vms->gic_version = 2; - object_property_add_str(obj, "gic-version", virt_get_gic_version, - virt_set_gic_version, NULL); - object_property_set_description(obj, "gic-version", - "Set GIC version. " - "Valid values are 2, 3 and host", NULL); -} - -static void virt_2_6_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - static GlobalProperty compat_props[] = { - { /* end of list */ } - }; - - mc->desc = "QEMU 2.6 ARM Virtual Machine"; - mc->alias = "virt"; - mc->compat_props = compat_props; -} - -static const TypeInfo machvirt_info = { - .name = MACHINE_TYPE_NAME("virt-2.6"), - .parent = TYPE_VIRT_MACHINE, - .instance_init = virt_2_6_instance_init, - .class_init = virt_2_6_class_init, -}; - -static void machvirt_machine_init(void) -{ - type_register_static(&virt_machine_info); - type_register_static(&machvirt_info); -} - -type_init(machvirt_machine_init); diff --git a/qemu/hw/arm/xilinx_zynq.c b/qemu/hw/arm/xilinx_zynq.c deleted file mode 100644 index 98b17c9ae..000000000 --- a/qemu/hw/arm/xilinx_zynq.c +++ /dev/null @@ -1,318 +0,0 @@ -/* - * Xilinx Zynq Baseboard System emulation. - * - * Copyright (c) 2010 Xilinx. - * Copyright (c) 2012 Peter A.G. Crosthwaite (peter.croshtwaite@petalogix.com) - * Copyright (c) 2012 Petalogix Pty Ltd. - * Written by Haibing Ma - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "qemu-common.h" -#include "cpu.h" -#include "hw/sysbus.h" -#include "hw/arm/arm.h" -#include "net/net.h" -#include "exec/address-spaces.h" -#include "sysemu/sysemu.h" -#include "hw/boards.h" -#include "hw/block/flash.h" -#include "sysemu/block-backend.h" -#include "hw/loader.h" -#include "hw/misc/zynq-xadc.h" -#include "hw/ssi/ssi.h" -#include "qemu/error-report.h" -#include "hw/sd/sd.h" - -#define NUM_SPI_FLASHES 4 -#define NUM_QSPI_FLASHES 2 -#define NUM_QSPI_BUSSES 2 - -#define FLASH_SIZE (64 * 1024 * 1024) -#define FLASH_SECTOR_SIZE (128 * 1024) - -#define IRQ_OFFSET 32 /* pic interrupts start from index 32 */ - -#define MPCORE_PERIPHBASE 0xF8F00000 -#define ZYNQ_BOARD_MIDR 0x413FC090 - -static const int dma_irqs[8] = { - 46, 47, 48, 49, 72, 73, 74, 75 -}; - -#define BOARD_SETUP_ADDR 0x100 - -#define SLCR_LOCK_OFFSET 0x004 -#define SLCR_UNLOCK_OFFSET 0x008 -#define SLCR_ARM_PLL_OFFSET 0x100 - -#define SLCR_XILINX_UNLOCK_KEY 0xdf0d -#define SLCR_XILINX_LOCK_KEY 0x767b - -#define ARMV7_IMM16(x) (extract32((x), 0, 12) | \ - extract32((x), 12, 4) << 16) - -/* Write immediate val to address r0 + addr. r0 should contain base offset - * of the SLCR block. Clobbers r1. - */ - -#define SLCR_WRITE(addr, val) \ - 0xe3001000 + ARMV7_IMM16(extract32((val), 0, 16)), /* movw r1 ... */ \ - 0xe3401000 + ARMV7_IMM16(extract32((val), 16, 16)), /* movt r1 ... */ \ - 0xe5801000 + (addr) - -static void zynq_write_board_setup(ARMCPU *cpu, - const struct arm_boot_info *info) -{ - int n; - uint32_t board_setup_blob[] = { - 0xe3a004f8, /* mov r0, #0xf8000000 */ - SLCR_WRITE(SLCR_UNLOCK_OFFSET, SLCR_XILINX_UNLOCK_KEY), - SLCR_WRITE(SLCR_ARM_PLL_OFFSET, 0x00014008), - SLCR_WRITE(SLCR_LOCK_OFFSET, SLCR_XILINX_LOCK_KEY), - 0xe12fff1e, /* bx lr */ - }; - for (n = 0; n < ARRAY_SIZE(board_setup_blob); n++) { - board_setup_blob[n] = tswap32(board_setup_blob[n]); - } - rom_add_blob_fixed("board-setup", board_setup_blob, - sizeof(board_setup_blob), BOARD_SETUP_ADDR); -} - -static struct arm_boot_info zynq_binfo = {}; - -static void gem_init(NICInfo *nd, uint32_t base, qemu_irq irq) -{ - DeviceState *dev; - SysBusDevice *s; - - dev = qdev_create(NULL, "cadence_gem"); - if (nd->used) { - qemu_check_nic_model(nd, "cadence_gem"); - qdev_set_nic_properties(dev, nd); - } - qdev_init_nofail(dev); - s = SYS_BUS_DEVICE(dev); - sysbus_mmio_map(s, 0, base); - sysbus_connect_irq(s, 0, irq); -} - -static inline void zynq_init_spi_flashes(uint32_t base_addr, qemu_irq irq, - bool is_qspi) -{ - DeviceState *dev; - SysBusDevice *busdev; - SSIBus *spi; - DeviceState *flash_dev; - int i, j; - int num_busses = is_qspi ? NUM_QSPI_BUSSES : 1; - int num_ss = is_qspi ? NUM_QSPI_FLASHES : NUM_SPI_FLASHES; - - dev = qdev_create(NULL, is_qspi ? "xlnx.ps7-qspi" : "xlnx.ps7-spi"); - qdev_prop_set_uint8(dev, "num-txrx-bytes", is_qspi ? 4 : 1); - qdev_prop_set_uint8(dev, "num-ss-bits", num_ss); - qdev_prop_set_uint8(dev, "num-busses", num_busses); - qdev_init_nofail(dev); - busdev = SYS_BUS_DEVICE(dev); - sysbus_mmio_map(busdev, 0, base_addr); - if (is_qspi) { - sysbus_mmio_map(busdev, 1, 0xFC000000); - } - sysbus_connect_irq(busdev, 0, irq); - - for (i = 0; i < num_busses; ++i) { - char bus_name[16]; - qemu_irq cs_line; - - snprintf(bus_name, 16, "spi%d", i); - spi = (SSIBus *)qdev_get_child_bus(dev, bus_name); - - for (j = 0; j < num_ss; ++j) { - flash_dev = ssi_create_slave(spi, "n25q128"); - - cs_line = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0); - sysbus_connect_irq(busdev, i * num_ss + j + 1, cs_line); - } - } - -} - -static void zynq_init(MachineState *machine) -{ - ram_addr_t ram_size = machine->ram_size; - const char *cpu_model = machine->cpu_model; - const char *kernel_filename = machine->kernel_filename; - const char *kernel_cmdline = machine->kernel_cmdline; - const char *initrd_filename = machine->initrd_filename; - ObjectClass *cpu_oc; - ARMCPU *cpu; - MemoryRegion *address_space_mem = get_system_memory(); - MemoryRegion *ext_ram = g_new(MemoryRegion, 1); - MemoryRegion *ocm_ram = g_new(MemoryRegion, 1); - DeviceState *dev, *carddev; - SysBusDevice *busdev; - DriveInfo *di; - BlockBackend *blk; - qemu_irq pic[64]; - int n; - - if (!cpu_model) { - cpu_model = "cortex-a9"; - } - cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model); - - cpu = ARM_CPU(object_new(object_class_get_name(cpu_oc))); - - /* By default A9 CPUs have EL3 enabled. This board does not - * currently support EL3 so the CPU EL3 property is disabled before - * realization. - */ - if (object_property_find(OBJECT(cpu), "has_el3", NULL)) { - object_property_set_bool(OBJECT(cpu), false, "has_el3", &error_fatal); - } - - object_property_set_int(OBJECT(cpu), ZYNQ_BOARD_MIDR, "midr", - &error_fatal); - object_property_set_int(OBJECT(cpu), MPCORE_PERIPHBASE, "reset-cbar", - &error_fatal); - object_property_set_bool(OBJECT(cpu), true, "realized", &error_fatal); - - /* max 2GB ram */ - if (ram_size > 0x80000000) { - ram_size = 0x80000000; - } - - /* DDR remapped to address zero. */ - memory_region_allocate_system_memory(ext_ram, NULL, "zynq.ext_ram", - ram_size); - memory_region_add_subregion(address_space_mem, 0, ext_ram); - - /* 256K of on-chip memory */ - memory_region_init_ram(ocm_ram, NULL, "zynq.ocm_ram", 256 << 10, - &error_fatal); - vmstate_register_ram_global(ocm_ram); - memory_region_add_subregion(address_space_mem, 0xFFFC0000, ocm_ram); - - DriveInfo *dinfo = drive_get(IF_PFLASH, 0, 0); - - /* AMD */ - pflash_cfi02_register(0xe2000000, NULL, "zynq.pflash", FLASH_SIZE, - dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, - FLASH_SECTOR_SIZE, - FLASH_SIZE/FLASH_SECTOR_SIZE, 1, - 1, 0x0066, 0x0022, 0x0000, 0x0000, 0x0555, 0x2aa, - 0); - - dev = qdev_create(NULL, "xilinx,zynq_slcr"); - qdev_init_nofail(dev); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xF8000000); - - dev = qdev_create(NULL, "a9mpcore_priv"); - qdev_prop_set_uint32(dev, "num-cpu", 1); - qdev_init_nofail(dev); - busdev = SYS_BUS_DEVICE(dev); - sysbus_mmio_map(busdev, 0, MPCORE_PERIPHBASE); - sysbus_connect_irq(busdev, 0, - qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ)); - - for (n = 0; n < 64; n++) { - pic[n] = qdev_get_gpio_in(dev, n); - } - - zynq_init_spi_flashes(0xE0006000, pic[58-IRQ_OFFSET], false); - zynq_init_spi_flashes(0xE0007000, pic[81-IRQ_OFFSET], false); - zynq_init_spi_flashes(0xE000D000, pic[51-IRQ_OFFSET], true); - - sysbus_create_simple("xlnx,ps7-usb", 0xE0002000, pic[53-IRQ_OFFSET]); - sysbus_create_simple("xlnx,ps7-usb", 0xE0003000, pic[76-IRQ_OFFSET]); - - sysbus_create_simple("cadence_uart", 0xE0000000, pic[59-IRQ_OFFSET]); - sysbus_create_simple("cadence_uart", 0xE0001000, pic[82-IRQ_OFFSET]); - - sysbus_create_varargs("cadence_ttc", 0xF8001000, - pic[42-IRQ_OFFSET], pic[43-IRQ_OFFSET], pic[44-IRQ_OFFSET], NULL); - sysbus_create_varargs("cadence_ttc", 0xF8002000, - pic[69-IRQ_OFFSET], pic[70-IRQ_OFFSET], pic[71-IRQ_OFFSET], NULL); - - gem_init(&nd_table[0], 0xE000B000, pic[54-IRQ_OFFSET]); - gem_init(&nd_table[1], 0xE000C000, pic[77-IRQ_OFFSET]); - - dev = qdev_create(NULL, "generic-sdhci"); - qdev_init_nofail(dev); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xE0100000); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[56-IRQ_OFFSET]); - - di = drive_get_next(IF_SD); - blk = di ? blk_by_legacy_dinfo(di) : NULL; - carddev = qdev_create(qdev_get_child_bus(dev, "sd-bus"), TYPE_SD_CARD); - qdev_prop_set_drive(carddev, "drive", blk, &error_fatal); - object_property_set_bool(OBJECT(carddev), true, "realized", &error_fatal); - - dev = qdev_create(NULL, "generic-sdhci"); - qdev_init_nofail(dev); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xE0101000); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[79-IRQ_OFFSET]); - - di = drive_get_next(IF_SD); - blk = di ? blk_by_legacy_dinfo(di) : NULL; - carddev = qdev_create(qdev_get_child_bus(dev, "sd-bus"), TYPE_SD_CARD); - qdev_prop_set_drive(carddev, "drive", blk, &error_fatal); - object_property_set_bool(OBJECT(carddev), true, "realized", &error_fatal); - - dev = qdev_create(NULL, TYPE_ZYNQ_XADC); - qdev_init_nofail(dev); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xF8007100); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[39-IRQ_OFFSET]); - - dev = qdev_create(NULL, "pl330"); - qdev_prop_set_uint8(dev, "num_chnls", 8); - qdev_prop_set_uint8(dev, "num_periph_req", 4); - qdev_prop_set_uint8(dev, "num_events", 16); - - qdev_prop_set_uint8(dev, "data_width", 64); - qdev_prop_set_uint8(dev, "wr_cap", 8); - qdev_prop_set_uint8(dev, "wr_q_dep", 16); - qdev_prop_set_uint8(dev, "rd_cap", 8); - qdev_prop_set_uint8(dev, "rd_q_dep", 16); - qdev_prop_set_uint16(dev, "data_buffer_dep", 256); - - qdev_init_nofail(dev); - busdev = SYS_BUS_DEVICE(dev); - sysbus_mmio_map(busdev, 0, 0xF8003000); - sysbus_connect_irq(busdev, 0, pic[45-IRQ_OFFSET]); /* abort irq line */ - for (n = 0; n < 8; ++n) { /* event irqs */ - sysbus_connect_irq(busdev, n + 1, pic[dma_irqs[n] - IRQ_OFFSET]); - } - - zynq_binfo.ram_size = ram_size; - zynq_binfo.kernel_filename = kernel_filename; - zynq_binfo.kernel_cmdline = kernel_cmdline; - zynq_binfo.initrd_filename = initrd_filename; - zynq_binfo.nb_cpus = 1; - zynq_binfo.board_id = 0xd32; - zynq_binfo.loader_start = 0; - zynq_binfo.board_setup_addr = BOARD_SETUP_ADDR; - zynq_binfo.write_board_setup = zynq_write_board_setup; - - arm_load_kernel(ARM_CPU(first_cpu), &zynq_binfo); -} - -static void zynq_machine_init(MachineClass *mc) -{ - mc->desc = "Xilinx Zynq Platform Baseboard for Cortex-A9"; - mc->init = zynq_init; - mc->block_default_type = IF_SCSI; - mc->max_cpus = 1; - mc->no_sdcard = 1; -} - -DEFINE_MACHINE("xilinx-zynq-a9", zynq_machine_init) diff --git a/qemu/hw/arm/xlnx-ep108.c b/qemu/hw/arm/xlnx-ep108.c deleted file mode 100644 index 5f480182b..000000000 --- a/qemu/hw/arm/xlnx-ep108.c +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Xilinx ZynqMP EP108 board - * - * Copyright (C) 2015 Xilinx Inc - * Written by Peter Crosthwaite <peter.crosthwaite@xilinx.com> - * - * 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. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "qemu-common.h" -#include "cpu.h" -#include "hw/arm/xlnx-zynqmp.h" -#include "hw/boards.h" -#include "qemu/error-report.h" -#include "exec/address-spaces.h" - -typedef struct XlnxEP108 { - XlnxZynqMPState soc; - MemoryRegion ddr_ram; -} XlnxEP108; - -static struct arm_boot_info xlnx_ep108_binfo; - -static void xlnx_ep108_init(MachineState *machine) -{ - XlnxEP108 *s = g_new0(XlnxEP108, 1); - int i; - uint64_t ram_size = machine->ram_size; - - /* Create the memory region to pass to the SoC */ - if (ram_size > XLNX_ZYNQMP_MAX_RAM_SIZE) { - error_report("ERROR: RAM size 0x%" PRIx64 " above max supported of " - "0x%llx", ram_size, - XLNX_ZYNQMP_MAX_RAM_SIZE); - exit(1); - } - - if (ram_size < 0x08000000) { - qemu_log("WARNING: RAM size 0x%" PRIx64 " is small for EP108", - ram_size); - } - - memory_region_allocate_system_memory(&s->ddr_ram, NULL, "ddr-ram", - ram_size); - - object_initialize(&s->soc, sizeof(s->soc), TYPE_XLNX_ZYNQMP); - object_property_add_child(OBJECT(machine), "soc", OBJECT(&s->soc), - &error_abort); - - object_property_set_link(OBJECT(&s->soc), OBJECT(&s->ddr_ram), - "ddr-ram", &error_abort); - - object_property_set_bool(OBJECT(&s->soc), true, "realized", &error_fatal); - - /* Create and plug in the SD cards */ - for (i = 0; i < XLNX_ZYNQMP_NUM_SDHCI; i++) { - BusState *bus; - DriveInfo *di = drive_get_next(IF_SD); - BlockBackend *blk = di ? blk_by_legacy_dinfo(di) : NULL; - DeviceState *carddev; - char *bus_name; - - bus_name = g_strdup_printf("sd-bus%d", i); - bus = qdev_get_child_bus(DEVICE(&s->soc), bus_name); - g_free(bus_name); - if (!bus) { - error_report("No SD bus found for SD card %d", i); - exit(1); - } - carddev = qdev_create(bus, TYPE_SD_CARD); - qdev_prop_set_drive(carddev, "drive", blk, &error_fatal); - object_property_set_bool(OBJECT(carddev), true, "realized", - &error_fatal); - } - - for (i = 0; i < XLNX_ZYNQMP_NUM_SPIS; i++) { - SSIBus *spi_bus; - DeviceState *flash_dev; - qemu_irq cs_line; - gchar *bus_name = g_strdup_printf("spi%d", i); - - spi_bus = (SSIBus *)qdev_get_child_bus(DEVICE(&s->soc), bus_name); - g_free(bus_name); - - flash_dev = ssi_create_slave(spi_bus, "sst25wf080"); - cs_line = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0); - - sysbus_connect_irq(SYS_BUS_DEVICE(&s->soc.spi[i]), 1, cs_line); - } - - xlnx_ep108_binfo.ram_size = ram_size; - xlnx_ep108_binfo.kernel_filename = machine->kernel_filename; - xlnx_ep108_binfo.kernel_cmdline = machine->kernel_cmdline; - xlnx_ep108_binfo.initrd_filename = machine->initrd_filename; - xlnx_ep108_binfo.loader_start = 0; - arm_load_kernel(s->soc.boot_cpu_ptr, &xlnx_ep108_binfo); -} - -static void xlnx_ep108_machine_init(MachineClass *mc) -{ - mc->desc = "Xilinx ZynqMP EP108 board"; - mc->init = xlnx_ep108_init; -} - -DEFINE_MACHINE("xlnx-ep108", xlnx_ep108_machine_init) diff --git a/qemu/hw/arm/xlnx-zynqmp.c b/qemu/hw/arm/xlnx-zynqmp.c deleted file mode 100644 index 4d504da64..000000000 --- a/qemu/hw/arm/xlnx-zynqmp.c +++ /dev/null @@ -1,403 +0,0 @@ -/* - * Xilinx Zynq MPSoC emulation - * - * Copyright (C) 2015 Xilinx Inc - * Written by Peter Crosthwaite <peter.crosthwaite@xilinx.com> - * - * 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. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "qemu-common.h" -#include "cpu.h" -#include "hw/arm/xlnx-zynqmp.h" -#include "hw/intc/arm_gic_common.h" -#include "exec/address-spaces.h" - -#define GIC_NUM_SPI_INTR 160 - -#define ARM_PHYS_TIMER_PPI 30 -#define ARM_VIRT_TIMER_PPI 27 - -#define GIC_BASE_ADDR 0xf9000000 -#define GIC_DIST_ADDR 0xf9010000 -#define GIC_CPU_ADDR 0xf9020000 - -#define SATA_INTR 133 -#define SATA_ADDR 0xFD0C0000 -#define SATA_NUM_PORTS 2 - -static const uint64_t gem_addr[XLNX_ZYNQMP_NUM_GEMS] = { - 0xFF0B0000, 0xFF0C0000, 0xFF0D0000, 0xFF0E0000, -}; - -static const int gem_intr[XLNX_ZYNQMP_NUM_GEMS] = { - 57, 59, 61, 63, -}; - -static const uint64_t uart_addr[XLNX_ZYNQMP_NUM_UARTS] = { - 0xFF000000, 0xFF010000, -}; - -static const int uart_intr[XLNX_ZYNQMP_NUM_UARTS] = { - 21, 22, -}; - -static const uint64_t sdhci_addr[XLNX_ZYNQMP_NUM_SDHCI] = { - 0xFF160000, 0xFF170000, -}; - -static const int sdhci_intr[XLNX_ZYNQMP_NUM_SDHCI] = { - 48, 49, -}; - -static const uint64_t spi_addr[XLNX_ZYNQMP_NUM_SPIS] = { - 0xFF040000, 0xFF050000, -}; - -static const int spi_intr[XLNX_ZYNQMP_NUM_SPIS] = { - 19, 20, -}; - -typedef struct XlnxZynqMPGICRegion { - int region_index; - uint32_t address; -} XlnxZynqMPGICRegion; - -static const XlnxZynqMPGICRegion xlnx_zynqmp_gic_regions[] = { - { .region_index = 0, .address = GIC_DIST_ADDR, }, - { .region_index = 1, .address = GIC_CPU_ADDR, }, -}; - -static inline int arm_gic_ppi_index(int cpu_nr, int ppi_index) -{ - return GIC_NUM_SPI_INTR + cpu_nr * GIC_INTERNAL + ppi_index; -} - -static void xlnx_zynqmp_init(Object *obj) -{ - XlnxZynqMPState *s = XLNX_ZYNQMP(obj); - int i; - - for (i = 0; i < XLNX_ZYNQMP_NUM_APU_CPUS; i++) { - object_initialize(&s->apu_cpu[i], sizeof(s->apu_cpu[i]), - "cortex-a53-" TYPE_ARM_CPU); - object_property_add_child(obj, "apu-cpu[*]", OBJECT(&s->apu_cpu[i]), - &error_abort); - } - - for (i = 0; i < XLNX_ZYNQMP_NUM_RPU_CPUS; i++) { - object_initialize(&s->rpu_cpu[i], sizeof(s->rpu_cpu[i]), - "cortex-r5-" TYPE_ARM_CPU); - object_property_add_child(obj, "rpu-cpu[*]", OBJECT(&s->rpu_cpu[i]), - &error_abort); - } - - object_property_add_link(obj, "ddr-ram", TYPE_MEMORY_REGION, - (Object **)&s->ddr_ram, - qdev_prop_allow_set_link_before_realize, - OBJ_PROP_LINK_UNREF_ON_RELEASE, &error_abort); - - object_initialize(&s->gic, sizeof(s->gic), TYPE_ARM_GIC); - qdev_set_parent_bus(DEVICE(&s->gic), sysbus_get_default()); - - for (i = 0; i < XLNX_ZYNQMP_NUM_GEMS; i++) { - object_initialize(&s->gem[i], sizeof(s->gem[i]), TYPE_CADENCE_GEM); - qdev_set_parent_bus(DEVICE(&s->gem[i]), sysbus_get_default()); - } - - for (i = 0; i < XLNX_ZYNQMP_NUM_UARTS; i++) { - object_initialize(&s->uart[i], sizeof(s->uart[i]), TYPE_CADENCE_UART); - qdev_set_parent_bus(DEVICE(&s->uart[i]), sysbus_get_default()); - } - - object_initialize(&s->sata, sizeof(s->sata), TYPE_SYSBUS_AHCI); - qdev_set_parent_bus(DEVICE(&s->sata), sysbus_get_default()); - - for (i = 0; i < XLNX_ZYNQMP_NUM_SDHCI; i++) { - object_initialize(&s->sdhci[i], sizeof(s->sdhci[i]), - TYPE_SYSBUS_SDHCI); - qdev_set_parent_bus(DEVICE(&s->sdhci[i]), - sysbus_get_default()); - } - - for (i = 0; i < XLNX_ZYNQMP_NUM_SPIS; i++) { - object_initialize(&s->spi[i], sizeof(s->spi[i]), - TYPE_XILINX_SPIPS); - qdev_set_parent_bus(DEVICE(&s->spi[i]), sysbus_get_default()); - } -} - -static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) -{ - XlnxZynqMPState *s = XLNX_ZYNQMP(dev); - MemoryRegion *system_memory = get_system_memory(); - uint8_t i; - uint64_t ram_size; - const char *boot_cpu = s->boot_cpu ? s->boot_cpu : "apu-cpu[0]"; - ram_addr_t ddr_low_size, ddr_high_size; - qemu_irq gic_spi[GIC_NUM_SPI_INTR]; - Error *err = NULL; - - ram_size = memory_region_size(s->ddr_ram); - - /* Create the DDR Memory Regions. User friendly checks should happen at - * the board level - */ - if (ram_size > XLNX_ZYNQMP_MAX_LOW_RAM_SIZE) { - /* The RAM size is above the maximum available for the low DDR. - * Create the high DDR memory region as well. - */ - assert(ram_size <= XLNX_ZYNQMP_MAX_RAM_SIZE); - ddr_low_size = XLNX_ZYNQMP_MAX_LOW_RAM_SIZE; - ddr_high_size = ram_size - XLNX_ZYNQMP_MAX_LOW_RAM_SIZE; - - memory_region_init_alias(&s->ddr_ram_high, NULL, - "ddr-ram-high", s->ddr_ram, - ddr_low_size, ddr_high_size); - memory_region_add_subregion(get_system_memory(), - XLNX_ZYNQMP_HIGH_RAM_START, - &s->ddr_ram_high); - } else { - /* RAM must be non-zero */ - assert(ram_size); - ddr_low_size = ram_size; - } - - memory_region_init_alias(&s->ddr_ram_low, NULL, - "ddr-ram-low", s->ddr_ram, - 0, ddr_low_size); - memory_region_add_subregion(get_system_memory(), 0, &s->ddr_ram_low); - - /* Create the four OCM banks */ - for (i = 0; i < XLNX_ZYNQMP_NUM_OCM_BANKS; i++) { - char *ocm_name = g_strdup_printf("zynqmp.ocm_ram_bank_%d", i); - - memory_region_init_ram(&s->ocm_ram[i], NULL, ocm_name, - XLNX_ZYNQMP_OCM_RAM_SIZE, &error_fatal); - vmstate_register_ram_global(&s->ocm_ram[i]); - memory_region_add_subregion(get_system_memory(), - XLNX_ZYNQMP_OCM_RAM_0_ADDRESS + - i * XLNX_ZYNQMP_OCM_RAM_SIZE, - &s->ocm_ram[i]); - - g_free(ocm_name); - } - - qdev_prop_set_uint32(DEVICE(&s->gic), "num-irq", GIC_NUM_SPI_INTR + 32); - qdev_prop_set_uint32(DEVICE(&s->gic), "revision", 2); - qdev_prop_set_uint32(DEVICE(&s->gic), "num-cpu", XLNX_ZYNQMP_NUM_APU_CPUS); - object_property_set_bool(OBJECT(&s->gic), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - assert(ARRAY_SIZE(xlnx_zynqmp_gic_regions) == XLNX_ZYNQMP_GIC_REGIONS); - for (i = 0; i < XLNX_ZYNQMP_GIC_REGIONS; i++) { - SysBusDevice *gic = SYS_BUS_DEVICE(&s->gic); - const XlnxZynqMPGICRegion *r = &xlnx_zynqmp_gic_regions[i]; - MemoryRegion *mr = sysbus_mmio_get_region(gic, r->region_index); - uint32_t addr = r->address; - int j; - - sysbus_mmio_map(gic, r->region_index, addr); - - for (j = 0; j < XLNX_ZYNQMP_GIC_ALIASES; j++) { - MemoryRegion *alias = &s->gic_mr[i][j]; - - addr += XLNX_ZYNQMP_GIC_REGION_SIZE; - memory_region_init_alias(alias, OBJECT(s), "zynqmp-gic-alias", mr, - 0, XLNX_ZYNQMP_GIC_REGION_SIZE); - memory_region_add_subregion(system_memory, addr, alias); - } - } - - for (i = 0; i < XLNX_ZYNQMP_NUM_APU_CPUS; i++) { - qemu_irq irq; - char *name; - - object_property_set_int(OBJECT(&s->apu_cpu[i]), QEMU_PSCI_CONDUIT_SMC, - "psci-conduit", &error_abort); - - name = object_get_canonical_path_component(OBJECT(&s->apu_cpu[i])); - if (strcmp(name, boot_cpu)) { - /* Secondary CPUs start in PSCI powered-down state */ - object_property_set_bool(OBJECT(&s->apu_cpu[i]), true, - "start-powered-off", &error_abort); - } else { - s->boot_cpu_ptr = &s->apu_cpu[i]; - } - g_free(name); - - object_property_set_int(OBJECT(&s->apu_cpu[i]), GIC_BASE_ADDR, - "reset-cbar", &error_abort); - object_property_set_bool(OBJECT(&s->apu_cpu[i]), true, "realized", - &err); - if (err) { - error_propagate(errp, err); - return; - } - - sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), i, - qdev_get_gpio_in(DEVICE(&s->apu_cpu[i]), - ARM_CPU_IRQ)); - irq = qdev_get_gpio_in(DEVICE(&s->gic), - arm_gic_ppi_index(i, ARM_PHYS_TIMER_PPI)); - qdev_connect_gpio_out(DEVICE(&s->apu_cpu[i]), 0, irq); - irq = qdev_get_gpio_in(DEVICE(&s->gic), - arm_gic_ppi_index(i, ARM_VIRT_TIMER_PPI)); - qdev_connect_gpio_out(DEVICE(&s->apu_cpu[i]), 1, irq); - } - - for (i = 0; i < XLNX_ZYNQMP_NUM_RPU_CPUS; i++) { - char *name; - - name = object_get_canonical_path_component(OBJECT(&s->rpu_cpu[i])); - if (strcmp(name, boot_cpu)) { - /* Secondary CPUs start in PSCI powered-down state */ - object_property_set_bool(OBJECT(&s->rpu_cpu[i]), true, - "start-powered-off", &error_abort); - } else { - s->boot_cpu_ptr = &s->rpu_cpu[i]; - } - g_free(name); - - object_property_set_bool(OBJECT(&s->rpu_cpu[i]), true, "reset-hivecs", - &error_abort); - object_property_set_bool(OBJECT(&s->rpu_cpu[i]), true, "realized", - &err); - if (err) { - error_propagate(errp, err); - return; - } - } - - if (!s->boot_cpu_ptr) { - error_setg(errp, "ZynqMP Boot cpu %s not found", boot_cpu); - return; - } - - for (i = 0; i < GIC_NUM_SPI_INTR; i++) { - gic_spi[i] = qdev_get_gpio_in(DEVICE(&s->gic), i); - } - - for (i = 0; i < XLNX_ZYNQMP_NUM_GEMS; i++) { - NICInfo *nd = &nd_table[i]; - - if (nd->used) { - qemu_check_nic_model(nd, TYPE_CADENCE_GEM); - qdev_set_nic_properties(DEVICE(&s->gem[i]), nd); - } - object_property_set_bool(OBJECT(&s->gem[i]), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->gem[i]), 0, gem_addr[i]); - sysbus_connect_irq(SYS_BUS_DEVICE(&s->gem[i]), 0, - gic_spi[gem_intr[i]]); - } - - for (i = 0; i < XLNX_ZYNQMP_NUM_UARTS; i++) { - object_property_set_bool(OBJECT(&s->uart[i]), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->uart[i]), 0, uart_addr[i]); - sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart[i]), 0, - gic_spi[uart_intr[i]]); - } - - object_property_set_int(OBJECT(&s->sata), SATA_NUM_PORTS, "num-ports", - &error_abort); - object_property_set_bool(OBJECT(&s->sata), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - - sysbus_mmio_map(SYS_BUS_DEVICE(&s->sata), 0, SATA_ADDR); - sysbus_connect_irq(SYS_BUS_DEVICE(&s->sata), 0, gic_spi[SATA_INTR]); - - for (i = 0; i < XLNX_ZYNQMP_NUM_SDHCI; i++) { - char *bus_name; - - object_property_set_bool(OBJECT(&s->sdhci[i]), true, - "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdhci[i]), 0, - sdhci_addr[i]); - sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdhci[i]), 0, - gic_spi[sdhci_intr[i]]); - /* Alias controller SD bus to the SoC itself */ - bus_name = g_strdup_printf("sd-bus%d", i); - object_property_add_alias(OBJECT(s), bus_name, - OBJECT(&s->sdhci[i]), "sd-bus", - &error_abort); - g_free(bus_name); - } - - for (i = 0; i < XLNX_ZYNQMP_NUM_SPIS; i++) { - gchar *bus_name; - - object_property_set_bool(OBJECT(&s->spi[i]), true, "realized", &err); - - sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0, spi_addr[i]); - sysbus_connect_irq(SYS_BUS_DEVICE(&s->spi[i]), 0, - gic_spi[spi_intr[i]]); - - /* Alias controller SPI bus to the SoC itself */ - bus_name = g_strdup_printf("spi%d", i); - object_property_add_alias(OBJECT(s), bus_name, - OBJECT(&s->spi[i]), "spi0", - &error_abort); - g_free(bus_name); - } -} - -static Property xlnx_zynqmp_props[] = { - DEFINE_PROP_STRING("boot-cpu", XlnxZynqMPState, boot_cpu), - DEFINE_PROP_END_OF_LIST() -}; - -static void xlnx_zynqmp_class_init(ObjectClass *oc, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(oc); - - dc->props = xlnx_zynqmp_props; - dc->realize = xlnx_zynqmp_realize; - - /* - * Reason: creates an ARM CPU, thus use after free(), see - * arm_cpu_class_init() - */ - dc->cannot_destroy_with_object_finalize_yet = true; -} - -static const TypeInfo xlnx_zynqmp_type_info = { - .name = TYPE_XLNX_ZYNQMP, - .parent = TYPE_DEVICE, - .instance_size = sizeof(XlnxZynqMPState), - .instance_init = xlnx_zynqmp_init, - .class_init = xlnx_zynqmp_class_init, -}; - -static void xlnx_zynqmp_register_types(void) -{ - type_register_static(&xlnx_zynqmp_type_info); -} - -type_init(xlnx_zynqmp_register_types) diff --git a/qemu/hw/arm/z2.c b/qemu/hw/arm/z2.c deleted file mode 100644 index aea895a50..000000000 --- a/qemu/hw/arm/z2.c +++ /dev/null @@ -1,382 +0,0 @@ -/* - * PXA270-based Zipit Z2 device - * - * Copyright (c) 2011 by Vasily Khoruzhick <anarsoul@gmail.com> - * - * Code is based on mainstone platform. - * - * 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 "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/arm/pxa.h" -#include "hw/arm/arm.h" -#include "hw/devices.h" -#include "hw/i2c/i2c.h" -#include "hw/ssi/ssi.h" -#include "hw/boards.h" -#include "sysemu/sysemu.h" -#include "hw/block/flash.h" -#include "sysemu/block-backend.h" -#include "ui/console.h" -#include "audio/audio.h" -#include "exec/address-spaces.h" -#include "sysemu/qtest.h" - -#ifdef DEBUG_Z2 -#define DPRINTF(fmt, ...) \ - printf(fmt, ## __VA_ARGS__) -#else -#define DPRINTF(fmt, ...) -#endif - -static const struct keymap map[0x100] = { - [0 ... 0xff] = { -1, -1 }, - [0x3b] = {0, 0}, /* Option = F1 */ - [0xc8] = {0, 1}, /* Up */ - [0xd0] = {0, 2}, /* Down */ - [0xcb] = {0, 3}, /* Left */ - [0xcd] = {0, 4}, /* Right */ - [0xcf] = {0, 5}, /* End */ - [0x0d] = {0, 6}, /* KPPLUS */ - [0xc7] = {1, 0}, /* Home */ - [0x10] = {1, 1}, /* Q */ - [0x17] = {1, 2}, /* I */ - [0x22] = {1, 3}, /* G */ - [0x2d] = {1, 4}, /* X */ - [0x1c] = {1, 5}, /* Enter */ - [0x0c] = {1, 6}, /* KPMINUS */ - [0xc9] = {2, 0}, /* PageUp */ - [0x11] = {2, 1}, /* W */ - [0x18] = {2, 2}, /* O */ - [0x23] = {2, 3}, /* H */ - [0x2e] = {2, 4}, /* C */ - [0x38] = {2, 5}, /* LeftAlt */ - [0xd1] = {3, 0}, /* PageDown */ - [0x12] = {3, 1}, /* E */ - [0x19] = {3, 2}, /* P */ - [0x24] = {3, 3}, /* J */ - [0x2f] = {3, 4}, /* V */ - [0x2a] = {3, 5}, /* LeftShift */ - [0x01] = {4, 0}, /* Esc */ - [0x13] = {4, 1}, /* R */ - [0x1e] = {4, 2}, /* A */ - [0x25] = {4, 3}, /* K */ - [0x30] = {4, 4}, /* B */ - [0x1d] = {4, 5}, /* LeftCtrl */ - [0x0f] = {5, 0}, /* Tab */ - [0x14] = {5, 1}, /* T */ - [0x1f] = {5, 2}, /* S */ - [0x26] = {5, 3}, /* L */ - [0x31] = {5, 4}, /* N */ - [0x39] = {5, 5}, /* Space */ - [0x3c] = {6, 0}, /* Stop = F2 */ - [0x15] = {6, 1}, /* Y */ - [0x20] = {6, 2}, /* D */ - [0x0e] = {6, 3}, /* Backspace */ - [0x32] = {6, 4}, /* M */ - [0x33] = {6, 5}, /* Comma */ - [0x3d] = {7, 0}, /* Play = F3 */ - [0x16] = {7, 1}, /* U */ - [0x21] = {7, 2}, /* F */ - [0x2c] = {7, 3}, /* Z */ - [0x27] = {7, 4}, /* Semicolon */ - [0x34] = {7, 5}, /* Dot */ -}; - -#define Z2_RAM_SIZE 0x02000000 -#define Z2_FLASH_BASE 0x00000000 -#define Z2_FLASH_SIZE 0x00800000 - -static struct arm_boot_info z2_binfo = { - .loader_start = PXA2XX_SDRAM_BASE, - .ram_size = Z2_RAM_SIZE, -}; - -#define Z2_GPIO_SD_DETECT 96 -#define Z2_GPIO_AC_IN 0 -#define Z2_GPIO_KEY_ON 1 -#define Z2_GPIO_LCD_CS 88 - -typedef struct { - SSISlave ssidev; - int32_t selected; - int32_t enabled; - uint8_t buf[3]; - uint32_t cur_reg; - int pos; -} ZipitLCD; - -static uint32_t zipit_lcd_transfer(SSISlave *dev, uint32_t value) -{ - ZipitLCD *z = FROM_SSI_SLAVE(ZipitLCD, dev); - uint16_t val; - if (z->selected) { - z->buf[z->pos] = value & 0xff; - z->pos++; - } - if (z->pos == 3) { - switch (z->buf[0]) { - case 0x74: - DPRINTF("%s: reg: 0x%.2x\n", __func__, z->buf[2]); - z->cur_reg = z->buf[2]; - break; - case 0x76: - val = z->buf[1] << 8 | z->buf[2]; - DPRINTF("%s: value: 0x%.4x\n", __func__, val); - if (z->cur_reg == 0x22 && val == 0x0000) { - z->enabled = 1; - printf("%s: LCD enabled\n", __func__); - } else if (z->cur_reg == 0x10 && val == 0x0000) { - z->enabled = 0; - printf("%s: LCD disabled\n", __func__); - } - break; - default: - DPRINTF("%s: unknown command!\n", __func__); - break; - } - z->pos = 0; - } - return 0; -} - -static void z2_lcd_cs(void *opaque, int line, int level) -{ - ZipitLCD *z2_lcd = opaque; - z2_lcd->selected = !level; -} - -static int zipit_lcd_init(SSISlave *dev) -{ - ZipitLCD *z = FROM_SSI_SLAVE(ZipitLCD, dev); - z->selected = 0; - z->enabled = 0; - z->pos = 0; - - return 0; -} - -static VMStateDescription vmstate_zipit_lcd_state = { - .name = "zipit-lcd", - .version_id = 2, - .minimum_version_id = 2, - .fields = (VMStateField[]) { - VMSTATE_SSI_SLAVE(ssidev, ZipitLCD), - VMSTATE_INT32(selected, ZipitLCD), - VMSTATE_INT32(enabled, ZipitLCD), - VMSTATE_BUFFER(buf, ZipitLCD), - VMSTATE_UINT32(cur_reg, ZipitLCD), - VMSTATE_INT32(pos, ZipitLCD), - VMSTATE_END_OF_LIST(), - } -}; - -static void zipit_lcd_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SSISlaveClass *k = SSI_SLAVE_CLASS(klass); - - k->init = zipit_lcd_init; - k->transfer = zipit_lcd_transfer; - dc->vmsd = &vmstate_zipit_lcd_state; -} - -static const TypeInfo zipit_lcd_info = { - .name = "zipit-lcd", - .parent = TYPE_SSI_SLAVE, - .instance_size = sizeof(ZipitLCD), - .class_init = zipit_lcd_class_init, -}; - -#define TYPE_AER915 "aer915" -#define AER915(obj) OBJECT_CHECK(AER915State, (obj), TYPE_AER915) - -typedef struct AER915State { - I2CSlave parent_obj; - - int len; - uint8_t buf[3]; -} AER915State; - -static int aer915_send(I2CSlave *i2c, uint8_t data) -{ - AER915State *s = AER915(i2c); - - s->buf[s->len] = data; - if (s->len++ > 2) { - DPRINTF("%s: message too long (%i bytes)\n", - __func__, s->len); - return 1; - } - - if (s->len == 2) { - DPRINTF("%s: reg %d value 0x%02x\n", __func__, - s->buf[0], s->buf[1]); - } - - return 0; -} - -static void aer915_event(I2CSlave *i2c, enum i2c_event event) -{ - AER915State *s = AER915(i2c); - - switch (event) { - case I2C_START_SEND: - s->len = 0; - break; - case I2C_START_RECV: - if (s->len != 1) { - DPRINTF("%s: short message!?\n", __func__); - } - break; - case I2C_FINISH: - break; - default: - break; - } -} - -static int aer915_recv(I2CSlave *slave) -{ - AER915State *s = AER915(slave); - int retval = 0x00; - - switch (s->buf[0]) { - /* Return hardcoded battery voltage, - * 0xf0 means ~4.1V - */ - case 0x02: - retval = 0xf0; - break; - /* Return 0x00 for other regs, - * we don't know what they are for, - * anyway they return 0x00 on real hardware. - */ - default: - break; - } - - return retval; -} - -static int aer915_init(I2CSlave *i2c) -{ - /* Nothing to do. */ - return 0; -} - -static VMStateDescription vmstate_aer915_state = { - .name = "aer915", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_INT32(len, AER915State), - VMSTATE_BUFFER(buf, AER915State), - VMSTATE_END_OF_LIST(), - } -}; - -static void aer915_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); - - k->init = aer915_init; - k->event = aer915_event; - k->recv = aer915_recv; - k->send = aer915_send; - dc->vmsd = &vmstate_aer915_state; -} - -static const TypeInfo aer915_info = { - .name = TYPE_AER915, - .parent = TYPE_I2C_SLAVE, - .instance_size = sizeof(AER915State), - .class_init = aer915_class_init, -}; - -static void z2_init(MachineState *machine) -{ - const char *cpu_model = machine->cpu_model; - const char *kernel_filename = machine->kernel_filename; - const char *kernel_cmdline = machine->kernel_cmdline; - const char *initrd_filename = machine->initrd_filename; - MemoryRegion *address_space_mem = get_system_memory(); - uint32_t sector_len = 0x10000; - PXA2xxState *mpu; - DriveInfo *dinfo; - int be; - void *z2_lcd; - I2CBus *bus; - DeviceState *wm; - - if (!cpu_model) { - cpu_model = "pxa270-c5"; - } - - /* Setup CPU & memory */ - mpu = pxa270_init(address_space_mem, z2_binfo.ram_size, cpu_model); - -#ifdef TARGET_WORDS_BIGENDIAN - be = 1; -#else - be = 0; -#endif - dinfo = drive_get(IF_PFLASH, 0, 0); - if (!dinfo && !qtest_enabled()) { - fprintf(stderr, "Flash image must be given with the " - "'pflash' parameter\n"); - exit(1); - } - - if (!pflash_cfi01_register(Z2_FLASH_BASE, - NULL, "z2.flash0", Z2_FLASH_SIZE, - dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, - sector_len, Z2_FLASH_SIZE / sector_len, - 4, 0, 0, 0, 0, be)) { - fprintf(stderr, "qemu: Error registering flash memory.\n"); - exit(1); - } - - /* setup keypad */ - pxa27x_register_keypad(mpu->kp, map, 0x100); - - /* MMC/SD host */ - pxa2xx_mmci_handlers(mpu->mmc, - NULL, - qdev_get_gpio_in(mpu->gpio, Z2_GPIO_SD_DETECT)); - - type_register_static(&zipit_lcd_info); - type_register_static(&aer915_info); - z2_lcd = ssi_create_slave(mpu->ssp[1], "zipit-lcd"); - bus = pxa2xx_i2c_bus(mpu->i2c[0]); - i2c_create_slave(bus, TYPE_AER915, 0x55); - wm = i2c_create_slave(bus, "wm8750", 0x1b); - mpu->i2s->opaque = wm; - mpu->i2s->codec_out = wm8750_dac_dat; - mpu->i2s->codec_in = wm8750_adc_dat; - wm8750_data_req_set(wm, mpu->i2s->data_req, mpu->i2s); - - qdev_connect_gpio_out(mpu->gpio, Z2_GPIO_LCD_CS, - qemu_allocate_irq(z2_lcd_cs, z2_lcd, 0)); - - z2_binfo.kernel_filename = kernel_filename; - z2_binfo.kernel_cmdline = kernel_cmdline; - z2_binfo.initrd_filename = initrd_filename; - z2_binfo.board_id = 0x6dd; - arm_load_kernel(mpu->cpu, &z2_binfo); -} - -static void z2_machine_init(MachineClass *mc) -{ - mc->desc = "Zipit Z2 (PXA27x)"; - mc->init = z2_init; -} - -DEFINE_MACHINE("z2", z2_machine_init) |