>From 7f74f048f135d9c9c230a9e90f72451c841c6d35 Mon Sep 17 00:00:00 2001 From: John Bradley <fly...@rocketmail.com> Date: Sat, 13 May 2017 23:07:47 +0100 Subject: [PATCH] Changes to Broadcom(BCM) files and Raspberry Pi files. Addition of PanelEmu
The files add the ability to attach, via TCP, a panel emulator The include a unification of several PD Raspberry PI additions A modification to dev-network to all circle SDK WWW client to work The DummyPanel is not included but available at https://github.com/flypie/GDummyPanel.git Signed-off-by: John Bradley <fly...@rocketmail.com> --- .gitignore | 54 ++ hw/arm/Makefile.objs | 2 +- hw/arm/bcm2835.c | 114 ++++ hw/arm/bcm2835_peripherals.c | 104 ++++ hw/arm/bcm2836.c | 3 +- hw/arm/raspi.c | 77 ++- hw/gpio/bcm2835_gpio.c | 333 ++++++----- hw/misc/Makefile.objs | 2 + hw/misc/bcm2835_mphi.c | 163 ++++++ hw/misc/bcm2835_power.c | 106 ++++ hw/timer/Makefile.objs | 2 + hw/timer/bcm2835_st.c | 202 +++++++ hw/timer/bcm2835_timer.c | 224 +++++++ hw/usb/Makefile.objs | 4 +- hw/usb/bcm2835_usb.c | 604 +++++++++++++++++++ hw/usb/bcm2835_usb_regs.h | 1061 ++++++++++++++++++++++++++++++++++ hw/usb/dev-network.c | 2 +- include/hw/arm/bcm2835.h | 37 ++ include/hw/arm/bcm2835_peripherals.h | 10 + include/hw/gpio/bcm2835_gpio.h | 5 + include/hw/intc/bcm2835_control.h | 53 ++ include/hw/intc/bcm2836_control.h | 2 + include/hw/misc/bcm2835_mphi.h | 28 + include/hw/misc/bcm2835_power.h | 22 + include/hw/timer/bcm2835_st.h | 25 + include/hw/timer/bcm2835_timer.h | 32 + include/hw/usb/bcm2835_usb.h | 78 +++ include/qemu/PanelEmu.h | 53 ++ util/Makefile.objs | 1 + util/PanelEmu.c | 293 ++++++++++ 30 files changed, 3547 insertions(+), 149 deletions(-) create mode 100644 hw/arm/bcm2835.c create mode 100644 hw/misc/bcm2835_mphi.c create mode 100644 hw/misc/bcm2835_power.c create mode 100644 hw/timer/bcm2835_st.c create mode 100644 hw/timer/bcm2835_timer.c create mode 100644 hw/usb/bcm2835_usb.c create mode 100644 hw/usb/bcm2835_usb_regs.h create mode 100644 include/hw/arm/bcm2835.h create mode 100644 include/hw/intc/bcm2835_control.h create mode 100644 include/hw/misc/bcm2835_mphi.h create mode 100644 include/hw/misc/bcm2835_power.h create mode 100644 include/hw/timer/bcm2835_st.h create mode 100644 include/hw/timer/bcm2835_timer.h create mode 100644 include/hw/usb/bcm2835_usb.h create mode 100644 include/qemu/PanelEmu.h create mode 100644 util/PanelEmu.c diff --git a/.gitignore b/.gitignore index 55a001e3b8..08e0ac978f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +/bin /config-devices.* /config-all-devices.* /config-all-disas.* @@ -131,3 +132,56 @@ trace-dtrace-root.h trace-dtrace-root.dtrace trace-ust-all.h trace-ust-all.c + +bin/debug/x86_64-w64-mingw64/Makefile + +bin/debug/x86_64-w64-mingw64/arm-softmmu/Makefile + +bin/debug/x86_64-w64-mingw64/arm-softmmu/config-devices.mak + +# Compiled source # +################### +*.com +*.class +*.dll +*.exe +*.o +*.so + +# Packages # +############ +# it's better to unpack these files and commit the raw source +# git has its own built in compression methods +*.7z +*.dmg +*.gz +*.iso +*.jar +*.rar +*.tar +*.zip + +# Logs and databases # +###################### +*.log +*.sql +*.sqlite + +# OS generated files # +###################### +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db +.cproject +.project +### NetBeans ### +nbproject/private/ +build/ +nbbuild/ +dist/ +nbdist/ +.nb-gradle/ diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs index 4c5c4ee76c..35b2da24f5 100644 --- a/hw/arm/Makefile.objs +++ b/hw/arm/Makefile.objs @@ -11,7 +11,7 @@ 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_RASPI) += bcm2835.o 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 diff --git a/hw/arm/bcm2835.c b/hw/arm/bcm2835.c new file mode 100644 index 0000000000..e5744c1620 --- /dev/null +++ b/hw/arm/bcm2835.c @@ -0,0 +1,114 @@ +/* + * 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 "cpu.h" +#include "hw/arm/bcm2835.h" +#include "hw/arm/raspi_platform.h" +#include "hw/sysbus.h" +#include "exec/address-spaces.h" + + +/* Peripheral base address seen by the CPU */ +#define BCM2835_PERI_BASE 0x20000000 + +static void bcm2835_init(Object *obj) +{ + BCM2835State *s = BCM2835(obj); + + object_initialize(&s->cpus[0], sizeof(s->cpus[0]), "arm1176-" TYPE_ARM_CPU); + object_property_add_child(obj, "cpu", OBJECT(&s->cpus[0]), &error_abort); + + 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 bcm2835_realize(DeviceState *dev, Error **errp) +{ + BCM2835State *s = BCM2835(dev); + Object *obj; + Error *err = NULL; + + /* 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, + BCM2835_PERI_BASE, 1); + + object_property_set_bool(OBJECT(&s->cpus[0]), true, "realized", &err); + if (err) { + error_report_err(err); + exit(1); + } + + sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 0, + qdev_get_gpio_in(DEVICE(&s->cpus[0]), ARM_CPU_IRQ)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 1, + qdev_get_gpio_in(DEVICE(&s->cpus[0]), ARM_CPU_FIQ)); +} + +static Property bcm2835_props[] = { + DEFINE_PROP_UINT32("enabled-cpus", BCM2835State, enabled_cpus, BCM2835_NCPUS), + DEFINE_PROP_END_OF_LIST() +}; + +static void bcm2835_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->props = bcm2835_props; + dc->realize = bcm2835_realize; +} + +static const TypeInfo bcm2835_type_info = { + .name = TYPE_BCM2835, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(BCM2835State), + .instance_init = bcm2835_init, + .class_init = bcm2835_class_init, +}; + +static void bcm2835_register_types(void) +{ + type_register_static(&bcm2835_type_info); +} + +type_init(bcm2835_register_types) diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c index 369ef1e3bd..e0e8525eab 100644 --- a/hw/arm/bcm2835_peripherals.c +++ b/hw/arm/bcm2835_peripherals.c @@ -56,6 +56,29 @@ static void bcm2835_peripherals_init(Object *obj) object_property_add_child(obj, "aux", OBJECT(&s->aux), NULL); qdev_set_parent_bus(DEVICE(&s->aux), sysbus_get_default()); + /* System timer */ + object_initialize(&s->st, sizeof(s->st), TYPE_BCM2835_ST); + object_property_add_child(obj, "systimer", OBJECT(&s->st), NULL); + qdev_set_parent_bus(DEVICE(&s->st), sysbus_get_default()); + + /* ARM timer */ + object_initialize(&s->timer, sizeof(s->timer), TYPE_BCM2835_TIMER); + object_property_add_child(obj, "armtimer", OBJECT(&s->timer), NULL); + qdev_set_parent_bus(DEVICE(&s->timer), sysbus_get_default()); + + /* USB controller */ + object_initialize(&s->usb, sizeof(s->usb), TYPE_BCM2835_USB); + object_property_add_child(obj, "usb", OBJECT(&s->usb), NULL); + qdev_set_parent_bus(DEVICE(&s->usb), sysbus_get_default()); + + object_property_add_const_link(OBJECT(&s->usb), "dma_mr", + OBJECT(&s->gpu_bus_mr), &error_abort); + + /* MPHI - Message-based Parallel Host Interface */ + object_initialize(&s->mphi, sizeof(s->mphi), TYPE_BCM2835_MPHI); + object_property_add_child(obj, "mphi", OBJECT(&s->mphi), NULL); + qdev_set_parent_bus(DEVICE(&s->mphi), sysbus_get_default()); + /* Mailboxes */ object_initialize(&s->mboxes, sizeof(s->mboxes), TYPE_BCM2835_MBOX); object_property_add_child(obj, "mbox", OBJECT(&s->mboxes), NULL); @@ -64,6 +87,11 @@ static void bcm2835_peripherals_init(Object *obj) object_property_add_const_link(OBJECT(&s->mboxes), "mbox-mr", OBJECT(&s->mbox_mr), &error_abort); + /* Power management */ + object_initialize(&s->power, sizeof(s->power), TYPE_BCM2835_POWER); + object_property_add_child(obj, "power", OBJECT(&s->power), NULL); + qdev_set_parent_bus(DEVICE(&s->power), sysbus_get_default()); + /* Framebuffer */ object_initialize(&s->fb, sizeof(s->fb), TYPE_BCM2835_FB); object_property_add_child(obj, "fb", OBJECT(&s->fb), NULL); @@ -179,6 +207,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) sysbus_connect_irq(s->uart0, 0, qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ, INTERRUPT_UART)); + /* AUX / UART1 */ qdev_prop_set_chr(DEVICE(&s->aux), "chardev", serial_hds[1]); @@ -194,6 +223,67 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ, INTERRUPT_AUX)); + /* System timer */ + object_property_set_bool(OBJECT(&s->st), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + + memory_region_add_subregion(&s->peri_mr, ST_OFFSET, + sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->st), 0)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->st), 0, + qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ, + INTERRUPT_TIMER0)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->st), 1, + qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ, + INTERRUPT_TIMER1)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->st), 2, + qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ, + INTERRUPT_TIMER2)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->st), 3, + qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ, + INTERRUPT_TIMER3)); + + /* ARM timer */ + object_property_set_bool(OBJECT(&s->timer), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + + memory_region_add_subregion(&s->peri_mr, ARMCTRL_TIMER0_1_OFFSET, + sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->timer), 0)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->timer), 0, + qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_ARM_IRQ, + INTERRUPT_ARM_TIMER)); + + /* USB controller */ + object_property_set_bool(OBJECT(&s->usb), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + + memory_region_add_subregion(&s->peri_mr, USB_OFFSET, + sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->usb), 0)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->usb), 0, + qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ, + INTERRUPT_USB)); + + /* MPHI - Message-based Parallel Host Interface */ + object_property_set_bool(OBJECT(&s->mphi), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + + memory_region_add_subregion(&s->peri_mr, MPHI_OFFSET, + sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->mphi), 0)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->mphi), 0, + qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ, + INTERRUPT_HOSTPORT)); + /* Mailboxes */ object_property_set_bool(OBJECT(&s->mboxes), true, "realized", &err); if (err) { @@ -207,6 +297,18 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_ARM_IRQ, INTERRUPT_ARM_MAILBOX)); + /* Power management */ + object_property_set_bool(OBJECT(&s->power), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + + memory_region_add_subregion(&s->mbox_mr, MBOX_CHAN_POWER << MBOX_AS_CHAN_SHIFT, + sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->power), 0)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->power), 0, + qdev_get_gpio_in(DEVICE(&s->mboxes), MBOX_CHAN_POWER)); + /* Framebuffer */ vcram_size = (uint32_t)object_property_get_int(OBJECT(s), "vcram-size", &err); @@ -338,6 +440,8 @@ 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 = { diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c index 8c43291112..5f1bd15b24 100644 --- a/hw/arm/bcm2836.c +++ b/hw/arm/bcm2836.c @@ -27,7 +27,7 @@ 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); @@ -106,6 +106,7 @@ static void bcm2836_realize(DeviceState *dev, Error **errp) /* 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 */ diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c index 2b295f14c4..8ed2d9785d 100644 --- a/hw/arm/raspi.c +++ b/hw/arm/raspi.c @@ -4,6 +4,8 @@ * * Rasperry Pi 2 emulation Copyright (c) 2015, Microsoft * Written by Andrew Baumann + * + * Merge into QEMU root fork John Bradley April 2017 * * This code is licensed under the GNU GPLv2 and later. */ @@ -12,6 +14,7 @@ #include "qapi/error.h" #include "qemu-common.h" #include "cpu.h" +#include "hw/arm/bcm2835.h" #include "hw/arm/bcm2836.h" #include "qemu/error-report.h" #include "hw/boards.h" @@ -27,10 +30,20 @@ /* Table of Linux board IDs for different Pi versions */ static const int raspi_boardid[] = {[1] = 0xc42, [2] = 0xc43}; -typedef struct RasPiState { +/* Table of board revisions + * https://github.com/AndrewFromMelbourne/raspberry_pi_revision/blob/master/README.md + */ +static const uint32_t raspi_boardrev[] = {[1] = 0x10, [2] = 0xa21041}; + +typedef struct RasPi1State { + BCM2835State soc; + MemoryRegion ram; +} RasPi1State; + +typedef struct RasPi2State { BCM2836State soc; MemoryRegion ram; -} RasPiState; +} RasPi2State; static void write_smpboot(ARMCPU *cpu, const struct arm_boot_info *info) { @@ -113,9 +126,53 @@ static void setup_boot(MachineState *machine, int version, size_t ram_size) arm_load_kernel(ARM_CPU(first_cpu), &binfo); } +static void raspi1_init(MachineState *machine) +{ + RasPi1State *s = g_new0(RasPi1State, 1); + uint32_t vcram_size; + DriveInfo *di; + BlockBackend *blk; + BusState *bus; + DeviceState *carddev; + + object_initialize(&s->soc, sizeof(s->soc), TYPE_BCM2835); + 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, 1, machine->ram_size - vcram_size); +} static void raspi2_init(MachineState *machine) { - RasPiState *s = g_new0(RasPiState, 1); + RasPi2State *s = g_new0(RasPi2State, 1); uint32_t vcram_size; DriveInfo *di; BlockBackend *blk; @@ -158,6 +215,20 @@ static void raspi2_init(MachineState *machine) setup_boot(machine, 2, machine->ram_size - vcram_size); } + +static void raspi1_machine_init(MachineClass *mc) +{ + mc->desc = "Raspberry Pi 1"; + mc->init = raspi1_init; + mc->block_default_type = IF_SD; + mc->no_parallel = 1; + mc->no_floppy = 1; + mc->no_cdrom = 1; + mc->max_cpus = BCM2835_NCPUS; + mc->default_ram_size = 512 * 1024 * 1024; +}; +DEFINE_MACHINE("raspi1", raspi1_machine_init) + static void raspi2_machine_init(MachineClass *mc) { mc->desc = "Raspberry Pi 2"; diff --git a/hw/gpio/bcm2835_gpio.c b/hw/gpio/bcm2835_gpio.c index acc2e3cf9e..37be668d2a 100644 --- a/hw/gpio/bcm2835_gpio.c +++ b/hw/gpio/bcm2835_gpio.c @@ -19,6 +19,8 @@ #include "hw/sd/sd.h" #include "hw/gpio/bcm2835_gpio.h" + + #define GPFSEL0 0x00 #define GPFSEL1 0x04 #define GPFSEL2 0x08 @@ -53,9 +55,9 @@ static uint32_t gpfsel_get(BCM2835GpioState *s, uint8_t reg) { int i; uint32_t value = 0; - for (i = 0; i < 10; i++) { + for (i = 0; i < 10; i ++) { uint32_t index = 10 * reg + i; - if (index < sizeof(s->fsel)) { + if (index < sizeof (s->fsel)) { value |= (s->fsel[index] & 0x7) << (3 * i); } } @@ -65,9 +67,9 @@ static uint32_t gpfsel_get(BCM2835GpioState *s, uint8_t reg) static void gpfsel_set(BCM2835GpioState *s, uint8_t reg, uint32_t value) { int i; - for (i = 0; i < 10; i++) { + for (i = 0; i < 10; i ++) { uint32_t index = 10 * reg + i; - if (index < sizeof(s->fsel)) { + if (index < sizeof (s->fsel)) { int fsel = (value >> (3 * i)) & 0x7; s->fsel[index] = fsel; } @@ -75,24 +77,24 @@ static void gpfsel_set(BCM2835GpioState *s, uint8_t reg, uint32_t value) /* SD controller selection (48-53) */ if (s->sd_fsel != 0 - && (s->fsel[48] == 0) /* SD_CLK_R */ - && (s->fsel[49] == 0) /* SD_CMD_R */ - && (s->fsel[50] == 0) /* SD_DATA0_R */ - && (s->fsel[51] == 0) /* SD_DATA1_R */ - && (s->fsel[52] == 0) /* SD_DATA2_R */ - && (s->fsel[53] == 0) /* SD_DATA3_R */ - ) { + && (s->fsel[48] == 0) /* SD_CLK_R */ + && (s->fsel[49] == 0) /* SD_CMD_R */ + && (s->fsel[50] == 0) /* SD_DATA0_R */ + && (s->fsel[51] == 0) /* SD_DATA1_R */ + && (s->fsel[52] == 0) /* SD_DATA2_R */ + && (s->fsel[53] == 0) /* SD_DATA3_R */ + ) { /* SDHCI controller selected */ sdbus_reparent_card(s->sdbus_sdhost, s->sdbus_sdhci); s->sd_fsel = 0; } else if (s->sd_fsel != 4 - && (s->fsel[48] == 4) /* SD_CLK_R */ - && (s->fsel[49] == 4) /* SD_CMD_R */ - && (s->fsel[50] == 4) /* SD_DATA0_R */ - && (s->fsel[51] == 4) /* SD_DATA1_R */ - && (s->fsel[52] == 4) /* SD_DATA2_R */ - && (s->fsel[53] == 4) /* SD_DATA3_R */ - ) { + && (s->fsel[48] == 4) /* SD_CLK_R */ + && (s->fsel[49] == 4) /* SD_CMD_R */ + && (s->fsel[50] == 4) /* SD_DATA0_R */ + && (s->fsel[51] == 4) /* SD_DATA1_R */ + && (s->fsel[52] == 4) /* SD_DATA2_R */ + && (s->fsel[53] == 4) /* SD_DATA3_R */ + ) { /* SDHost controller selected */ sdbus_reparent_card(s->sdbus_sdhci, s->sdbus_sdhost); s->sd_fsel = 4; @@ -108,13 +110,13 @@ static int gpfsel_is_out(BCM2835GpioState *s, int index) } static void gpset(BCM2835GpioState *s, - uint32_t val, uint8_t start, uint8_t count, uint32_t *lev) + uint32_t val, uint8_t start, uint8_t count, uint32_t *lev) { - uint32_t changes = val & ~*lev; + uint32_t changes = val & ~ *lev; uint32_t cur = 1; int i; - for (i = 0; i < count; i++) { + for (i = 0; i < count; i ++) { if ((changes & cur) && (gpfsel_is_out(s, start + i))) { qemu_set_irq(s->out[start + i], 1); } @@ -125,132 +127,165 @@ static void gpset(BCM2835GpioState *s, } static void gpclr(BCM2835GpioState *s, - uint32_t val, uint8_t start, uint8_t count, uint32_t *lev) + uint32_t val, uint8_t start, uint8_t count, uint32_t *lev) { uint32_t changes = val & *lev; uint32_t cur = 1; int i; - for (i = 0; i < count; i++) { + for (i = 0; i < count; i ++) { if ((changes & cur) && (gpfsel_is_out(s, start + i))) { qemu_set_irq(s->out[start + i], 0); } cur <<= 1; } - *lev &= ~val; + *lev &= ~ val; } -static uint64_t bcm2835_gpio_read(void *opaque, hwaddr offset, - unsigned size) +static uint64_t bcm2835_gpio_read(void *opaque, hwaddr offset, unsigned size) { - BCM2835GpioState *s = (BCM2835GpioState *)opaque; + BCM2835GpioState *s = (BCM2835GpioState *) opaque; + + uint64_t Data; switch (offset) { - case GPFSEL0: - case GPFSEL1: - case GPFSEL2: - case GPFSEL3: - case GPFSEL4: - case GPFSEL5: - return gpfsel_get(s, offset / 4); - case GPSET0: - case GPSET1: - /* Write Only */ - return 0; - case GPCLR0: - case GPCLR1: - /* Write Only */ - return 0; - case GPLEV0: - return s->lev0; - case GPLEV1: - return s->lev1; - case GPEDS0: - case GPEDS1: - case GPREN0: - case GPREN1: - case GPFEN0: - case GPFEN1: - case GPHEN0: - case GPHEN1: - case GPLEN0: - case GPLEN1: - case GPAREN0: - case GPAREN1: - case GPAFEN0: - case GPAFEN1: - case GPPUD: - case GPPUDCLK0: - case GPPUDCLK1: - /* Not implemented */ - return 0; - default: - qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n", - __func__, offset); - break; + case GPFSEL0: + case GPFSEL1: + case GPFSEL2: + case GPFSEL3: + case GPFSEL4: + case GPFSEL5: + return gpfsel_get(s, offset / 4); + case GPSET0: + case GPSET1: + /* Write Only */ + return 0; + case GPCLR0: + case GPCLR1: + /* Write Only */ + return 0; + case GPLEV0: + if (s->panel.socket != - 1) { + if (panel_read(&s->panel, &Data)) { + s->lev0 = (uint32_t) Data; + s->lev1 = (uint32_t) (Data >> 32); + } + } + return s->lev0; + case GPLEV1: + if (s->panel.socket != - 1) { + if (panel_read(&s->panel, &Data)) { + s->lev0 = (uint32_t) Data; + s->lev1 = (uint32_t) (Data >> 32); + } + } + return s->lev1; + case GPEDS0: + case GPEDS1: + case GPREN0: + case GPREN1: + case GPFEN0: + case GPFEN1: + case GPHEN0: + case GPHEN1: + case GPLEN0: + case GPLEN1: + case GPAREN0: + case GPAREN1: + case GPAFEN0: + case GPAFEN1: + case GPPUD: + case GPPUDCLK0: + case GPPUDCLK1: + /* Not implemented */ + return 0; + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n", + __func__, offset); + break; } return 0; } static void bcm2835_gpio_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) + uint64_t value, unsigned size) { - BCM2835GpioState *s = (BCM2835GpioState *)opaque; + BCM2835GpioState *s = (BCM2835GpioState *) opaque; + uint64_t Data; + switch (offset) { - case GPFSEL0: - case GPFSEL1: - case GPFSEL2: - case GPFSEL3: - case GPFSEL4: - case GPFSEL5: - gpfsel_set(s, offset / 4, value); - break; - case GPSET0: - gpset(s, value, 0, 32, &s->lev0); - break; - case GPSET1: - gpset(s, value, 32, 22, &s->lev1); - break; - case GPCLR0: - gpclr(s, value, 0, 32, &s->lev0); - break; - case GPCLR1: - gpclr(s, value, 32, 22, &s->lev1); - break; - case GPLEV0: - case GPLEV1: - /* Read Only */ - break; - case GPEDS0: - case GPEDS1: - case GPREN0: - case GPREN1: - case GPFEN0: - case GPFEN1: - case GPHEN0: - case GPHEN1: - case GPLEN0: - case GPLEN1: - case GPAREN0: - case GPAREN1: - case GPAFEN0: - case GPAFEN1: - case GPPUD: - case GPPUDCLK0: - case GPPUDCLK1: - /* Not implemented */ - break; - default: - goto err_out; + case GPFSEL0: + case GPFSEL1: + case GPFSEL2: + case GPFSEL3: + case GPFSEL4: + case GPFSEL5: + gpfsel_set(s, offset / 4, value); + break; + case GPSET0: + gpset(s, value, 0, 32, &s->lev0); + if (s->panel.socket != - 1) { + Data = value; + senddatatopanel(&s->panel, Data, true); //John Bradley dummy GPIO Panel + } + break; + case GPSET1: + gpset(s, value, 32, 22, &s->lev1); + if (s->panel.socket != - 1) { + Data = value; + Data <<= 32; + senddatatopanel(&s->panel, Data, true); //John Bradley dummy GPIO Panel + } + break; + case GPCLR0: + gpclr(s, value, 0, 32, &s->lev0); + if (s->panel.socket != - 1) { + Data = value; + senddatatopanel(&s->panel, Data, false); //John Bradley dummy GPIO Panel + } + break; + case GPCLR1: + gpclr(s, value, 32, 22, &s->lev1); + if (s->panel.socket != - 1) { + Data = value; + Data <<= 32; + senddatatopanel(&s->panel, Data, false); //John Bradley dummy GPIO Panel + } + break; + case GPLEV0: + case GPLEV1: + /* Read Only */ + break; + case GPEDS0: + case GPEDS1: + case GPREN0: + case GPREN1: + case GPFEN0: + case GPFEN1: + case GPHEN0: + case GPHEN1: + case GPLEN0: + case GPLEN1: + case GPAREN0: + case GPAREN1: + case GPAFEN0: + case GPAFEN1: + case GPPUD: + case GPPUDCLK0: + case GPPUDCLK1: + /* Not implemented */ + break; + default: + goto err_out; } return; err_out: qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n", - __func__, offset); + __func__, offset); } static void bcm2835_gpio_reset(DeviceState *dev) @@ -258,7 +293,7 @@ static void bcm2835_gpio_reset(DeviceState *dev) BCM2835GpioState *s = BCM2835_GPIO(dev); int i; - for (i = 0; i < 6; i++) { + for (i = 0; i < 6; i ++) { gpfsel_set(s, i, 0); } @@ -272,21 +307,22 @@ static void bcm2835_gpio_reset(DeviceState *dev) } static const MemoryRegionOps bcm2835_gpio_ops = { - .read = bcm2835_gpio_read, - .write = bcm2835_gpio_write, - .endianness = DEVICE_NATIVE_ENDIAN, + .read = bcm2835_gpio_read, + .write = bcm2835_gpio_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; static const VMStateDescription vmstate_bcm2835_gpio = { - .name = "bcm2835_gpio", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT8_ARRAY(fsel, BCM2835GpioState, 54), - VMSTATE_UINT32(lev0, BCM2835GpioState), - VMSTATE_UINT32(lev1, BCM2835GpioState), - VMSTATE_UINT8(sd_fsel, BCM2835GpioState), - VMSTATE_END_OF_LIST() + .name = "bcm2835_gpio", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) + { + VMSTATE_UINT8_ARRAY(fsel, BCM2835GpioState, 54), + VMSTATE_UINT32(lev0, BCM2835GpioState), + VMSTATE_UINT32(lev1, BCM2835GpioState), + VMSTATE_UINT8(sd_fsel, BCM2835GpioState), + VMSTATE_END_OF_LIST() } }; @@ -296,13 +332,26 @@ static void bcm2835_gpio_init(Object *obj) DeviceState *dev = DEVICE(obj); SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - qbus_create_inplace(&s->sdbus, sizeof(s->sdbus), + qbus_create_inplace(&s->sdbus, sizeof (s->sdbus), TYPE_SD_BUS, DEVICE(s), "sd-bus"); memory_region_init_io(&s->iomem, obj, - &bcm2835_gpio_ops, s, "bcm2835_gpio", 0x1000); + &bcm2835_gpio_ops, s, "bcm2835_gpio", 0x1000); sysbus_init_mmio(sbd, &s->iomem); qdev_init_gpio_out(dev, s->out, 54); + + int err; + + /* Get access to the GPIO panel, program will quit on fail */ + err = panel_open(&s->panel); + if (err) { + printf("Couldn't connect to a GPIO panel\n"); //John Bradley dummy GPIO Panel + } else { + sendpincount(&s->panel, 54); //PI Has 54 Pins + sendenabledmap(&s->panel, 0x003FFFFFFFFFFFFC); //Pins 0 & 1 are I2C so disable + sendinputmap(&s->panel, 0x0000000000000000); //There are no dedicated input pins I know off + sendoutputmap(&s->panel, 0x0000800000000000); //Pin 53 is dedicated output LED + } } static void bcm2835_gpio_realize(DeviceState *dev, Error **errp) @@ -314,7 +363,7 @@ static void bcm2835_gpio_realize(DeviceState *dev, Error **errp) obj = object_property_get_link(OBJECT(dev), "sdbus-sdhci", &err); if (obj == NULL) { error_setg(errp, "%s: required sdhci link not found: %s", - __func__, error_get_pretty(err)); + __func__, error_get_pretty(err)); return; } s->sdbus_sdhci = SD_BUS(obj); @@ -322,7 +371,7 @@ static void bcm2835_gpio_realize(DeviceState *dev, Error **errp) obj = object_property_get_link(OBJECT(dev), "sdbus-sdhost", &err); if (obj == NULL) { error_setg(errp, "%s: required sdhost link not found: %s", - __func__, error_get_pretty(err)); + __func__, error_get_pretty(err)); return; } s->sdbus_sdhost = SD_BUS(obj); @@ -332,17 +381,17 @@ static void bcm2835_gpio_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - dc->vmsd = &vmstate_bcm2835_gpio; - dc->realize = &bcm2835_gpio_realize; - dc->reset = &bcm2835_gpio_reset; + dc->vmsd = & vmstate_bcm2835_gpio; + dc->realize = & bcm2835_gpio_realize; + dc->reset = & bcm2835_gpio_reset; } static const TypeInfo bcm2835_gpio_info = { - .name = TYPE_BCM2835_GPIO, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(BCM2835GpioState), - .instance_init = bcm2835_gpio_init, - .class_init = bcm2835_gpio_class_init, + .name = TYPE_BCM2835_GPIO, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof (BCM2835GpioState), + .instance_init = bcm2835_gpio_init, + .class_init = bcm2835_gpio_class_init, }; static void bcm2835_gpio_register_types(void) diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index c8b489390f..fd0cc922ee 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -41,6 +41,8 @@ obj-$(CONFIG_OMAP) += omap_l4.o obj-$(CONFIG_OMAP) += omap_sdrc.o obj-$(CONFIG_OMAP) += omap_tap.o obj-$(CONFIG_RASPI) += bcm2835_mbox.o +obj-$(CONFIG_RASPI) += bcm2835_mphi.o +obj-$(CONFIG_RASPI) += bcm2835_power.o obj-$(CONFIG_RASPI) += bcm2835_property.o obj-$(CONFIG_RASPI) += bcm2835_rng.o obj-$(CONFIG_SLAVIO) += slavio_misc.o diff --git a/hw/misc/bcm2835_mphi.c b/hw/misc/bcm2835_mphi.c new file mode 100644 index 0000000000..7681e00684 --- /dev/null +++ b/hw/misc/bcm2835_mphi.c @@ -0,0 +1,163 @@ +/* + * Raspberry Pi emulation (c) 2012 Gregory Estrade + * This code is licensed under the GNU GPLv2 and later. + */ + +#include "qemu/osdep.h" +#include "hw/misc/bcm2835_mphi.h" + +#include "qemu/log.h" +#include "qapi/error.h" + +static void bcm2835_mphi_update_irq(BCM2835MphiState *s) +{ + if (s->mphi_intstat) { + qemu_set_irq(s->irq, 1); + } else { + qemu_set_irq(s->irq, 0); + } +} + +static uint64_t bcm2835_mphi_read(void *opaque, hwaddr offset, + unsigned size) +{ + BCM2835MphiState *s = (BCM2835MphiState *)opaque; + uint32_t res = 0; + + assert(size == 4); + + switch (offset) { + case 0x00: /* mphi_base */ + res = s->mphi_base; + break; + case 0x28: /* mphi_outdda */ + res = s->mphi_outdda; + break; + case 0x2c: /* mphi_outddb */ + res = s->mphi_outddb; + break; + case 0x4c: /* mphi_ctrl */ + res = s->mphi_ctrl; + break; + case 0x50: /* mphi_intstat */ + res = s->mphi_intstat; + break; + + default: + qemu_log_mask(LOG_GUEST_ERROR, + "bcm2835_mphi_read: Bad offset %x\n", (int)offset); + res = 0; + break; + } + + return res; +} + +static void bcm2835_mphi_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + BCM2835MphiState *s = (BCM2835MphiState *)opaque; + int set_irq = 0; + + assert(size == 4); + + switch (offset) { + case 0x00: /* mphi_base */ + s->mphi_base = value; + break; + case 0x28: /* mphi_outdda */ + s->mphi_outdda = value; + break; + case 0x2c: /* mphi_outddb */ + s->mphi_outddb = value; + if (value & (1 << 29)) { + /* Enable MPHI interrupt */ + s->mphi_intstat |= (1 << 16); + set_irq = 1; + } + break; + case 0x4c: /* mphi_ctrl */ + s->mphi_ctrl &= ~(1 << 31); + s->mphi_ctrl |= value & (1 << 31); + + s->mphi_ctrl &= ~(3 << 16); + if (value & (1 << 16)) { + s->mphi_ctrl |= (3 << 16); + } + + break; + case 0x50: /* mphi_intstat */ + s->mphi_intstat &= ~value; + set_irq = 1; + break; + + default: + qemu_log_mask(LOG_GUEST_ERROR, + "bcm2835_mphi_write: Bad offset %x\n", (int)offset); + break; + } + + if (set_irq) { + bcm2835_mphi_update_irq(s); + } +} + +static const MemoryRegionOps bcm2835_mphi_ops = { + .read = bcm2835_mphi_read, + .write = bcm2835_mphi_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static const VMStateDescription vmstate_bcm2835_mphi = { + .name = TYPE_BCM2835_MPHI, + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_END_OF_LIST() + } +}; + +static void bcm2835_mphi_init(Object *obj) +{ + BCM2835MphiState *s = BCM2835_MPHI(obj); + + memory_region_init_io(&s->iomem, obj, &bcm2835_mphi_ops, s, + TYPE_BCM2835_MPHI, 0x1000); + sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem); + sysbus_init_irq(SYS_BUS_DEVICE(s), &s->irq); +} + +static void bcm2835_mphi_realize(DeviceState *dev, Error **errp) +{ + BCM2835MphiState *s = BCM2835_MPHI(dev); + + s->mphi_base = 0; + s->mphi_ctrl = 0; + s->mphi_outdda = 0; + s->mphi_outddb = 0; + s->mphi_intstat = 0; +} + +static void bcm2835_mphi_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = bcm2835_mphi_realize; + dc->vmsd = &vmstate_bcm2835_mphi; +} + +static TypeInfo bcm2835_mphi_info = { + .name = TYPE_BCM2835_MPHI, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(BCM2835MphiState), + .class_init = bcm2835_mphi_class_init, + .instance_init = bcm2835_mphi_init, +}; + +static void bcm2835_mphi_register_types(void) +{ + type_register_static(&bcm2835_mphi_info); +} + +type_init(bcm2835_mphi_register_types) diff --git a/hw/misc/bcm2835_power.c b/hw/misc/bcm2835_power.c new file mode 100644 index 0000000000..3bdb2b03da --- /dev/null +++ b/hw/misc/bcm2835_power.c @@ -0,0 +1,106 @@ +/* + * Raspberry Pi emulation (c) 2012 Gregory Estrade + * This code is licensed under the GNU GPLv2 and later. + */ + +#include "qemu/osdep.h" +#include "hw/misc/bcm2835_power.h" +#include "hw/misc/bcm2835_mbox_defs.h" + +#include "qemu/log.h" +#include "qapi/error.h" + +static uint64_t bcm2835_power_read(void *opaque, hwaddr offset, unsigned size) +{ + BCM2835PowerState *s = (BCM2835PowerState *)opaque; + uint32_t res = 0; + + switch (offset) { + case 0: + res = MBOX_CHAN_POWER; + s->pending = 0; + qemu_set_irq(s->mbox_irq, 0); + break; + case 4: + res = s->pending; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "bcm2835_power_read: Bad offset %x\n", (int)offset); + return 0; + } + return res; +} + +static void bcm2835_power_write(void *opaque, hwaddr offset, uint64_t value, + unsigned size) +{ + BCM2835PowerState *s = (BCM2835PowerState *)opaque; + switch (offset) { + case 0: + s->pending = 1; + qemu_set_irq(s->mbox_irq, 1); + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "bcm2835_power_write: Bad offset %x\n", (int)offset); + return; + } + +} + +static const MemoryRegionOps bcm2835_power_ops = { + .read = bcm2835_power_read, + .write = bcm2835_power_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static const VMStateDescription vmstate_bcm2835_power = { + .name = TYPE_BCM2835_POWER, + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_END_OF_LIST() + } +}; + +static void bcm2835_power_init(Object *obj) +{ + BCM2835PowerState *s = BCM2835_POWER(obj); + + sysbus_init_irq(SYS_BUS_DEVICE(s), &s->mbox_irq); + memory_region_init_io(&s->iomem, obj, &bcm2835_power_ops, s, + TYPE_BCM2835_POWER, 0x10); + sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem); +} + +static void bcm2835_power_realize(DeviceState *dev, Error **errp) +{ + BCM2835PowerState *s = BCM2835_POWER(dev); + + s->pending = 0; +} + +static void bcm2835_power_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = bcm2835_power_realize; + dc->vmsd = &vmstate_bcm2835_power; +} + +static TypeInfo bcm2835_power_info = { + .name = TYPE_BCM2835_POWER, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(BCM2835PowerState), + .class_init = bcm2835_power_class_init, + .instance_init = bcm2835_power_init, +}; + +static void bcm2835_power_register_types(void) +{ + type_register_static(&bcm2835_power_info); +} + +type_init(bcm2835_power_register_types) diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs index dd6f27e2a3..7beccc8747 100644 --- a/hw/timer/Makefile.objs +++ b/hw/timer/Makefile.objs @@ -29,6 +29,8 @@ obj-$(CONFIG_EXYNOS4) += exynos4210_rtc.o obj-$(CONFIG_OMAP) += omap_gptimer.o obj-$(CONFIG_OMAP) += omap_synctimer.o obj-$(CONFIG_PXA2XX) += pxa2xx_timer.o +obj-$(CONFIG_RASPI) += bcm2835_st.o +obj-$(CONFIG_RASPI) += bcm2835_timer.o obj-$(CONFIG_SH4) += sh_timer.o obj-$(CONFIG_DIGIC) += digic-timer.o obj-$(CONFIG_MIPS_CPS) += mips_gictimer.o diff --git a/hw/timer/bcm2835_st.c b/hw/timer/bcm2835_st.c new file mode 100644 index 0000000000..fb5cf5e573 --- /dev/null +++ b/hw/timer/bcm2835_st.c @@ -0,0 +1,202 @@ +/* + * Raspberry Pi emulation (c) 2012 Gregory Estrade + * This code is licensed under the GNU GPLv2 and later. + */ + +/* Based on several timers code found in various QEMU source files. */ + +#include "qemu/osdep.h" +#include "hw/timer/bcm2835_st.h" +#include "qemu/log.h" + +static void bcm2835_st_update(BCM2835StState *s) +{ + int64_t now = qemu_clock_get_us(QEMU_CLOCK_VIRTUAL); + uint32_t clo = (uint32_t)now; + uint32_t delta; + bool set = false; + int i; + + /* Calculate new "next" value and reschedule */ + for (i = 0; i < 4; i++) { + if (!(s->match & (1 << i))) { + if (!set || s->compare[i] - clo < delta) { + set = true; + s->next = s->compare[i]; + delta = s->next - clo; + } + } + } + + if (set) { + timer_mod(s->timer, now + delta); + } else { + timer_del(s->timer); + } +} + +static void bcm2835_st_tick(void *opaque) +{ + BCM2835StState *s = (BCM2835StState *)opaque; + int i; + + /* Trigger irqs for current "next" value */ + for (i = 0; i < 4; i++) { + if (!(s->match & (1 << i)) && (s->next == s->compare[i])) { + s->match |= (1 << i); + qemu_set_irq(s->irq[i], 1); + } + } + + bcm2835_st_update(s); +} + +static uint64_t bcm2835_st_read(void *opaque, hwaddr offset, + unsigned size) +{ + BCM2835StState *s = (BCM2835StState *)opaque; + uint32_t res = 0; + uint64_t now = qemu_clock_get_us(QEMU_CLOCK_VIRTUAL); + + assert(size == 4); + + switch (offset) { + case 0x00: + res = s->match; + break; + case 0x04: + res = (uint32_t)now; + /* Ugly temporary hack to get Plan9 to boot... */ + /* see http://plan9.bell-labs.com/sources/contrib/ \ + * miller/rpi/sys/src/9/bcm/clock.c */ + /* res = (now / 10000) * 10000; */ + break; + case 0x08: + res = (now >> 32); + break; + case 0x0c: + res = s->compare[0]; + break; + case 0x10: + res = s->compare[1]; + break; + case 0x14: + res = s->compare[2]; + break; + case 0x18: + res = s->compare[3]; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "bcm2835_st_read: Bad offset %x\n", (int)offset); + return 0; + } + + return res; +} + +static void bcm2835_st_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + BCM2835StState *s = (BCM2835StState *)opaque; + int i; + + assert(size == 4); + + switch (offset) { + case 0x00: + s->match &= ~value & 0x0f; + for (i = 0; i < 4; i++) { + if (value & (1 << i)) { + qemu_set_irq(s->irq[i], 0); + } + } + break; + case 0x0c: + s->compare[0] = value; + break; + case 0x10: + s->compare[1] = value; + break; + case 0x14: + s->compare[2] = value; + break; + case 0x18: + s->compare[3] = value; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "bcm2835_st_write: Bad offset %x\n", (int)offset); + return; + } + bcm2835_st_update(s); +} + +static const MemoryRegionOps bcm2835_st_ops = { + .read = bcm2835_st_read, + .write = bcm2835_st_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static const VMStateDescription vmstate_bcm2835_st = { + .name = TYPE_BCM2835_ST, + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(compare, BCM2835StState, 4), + VMSTATE_UINT32(match, BCM2835StState), + VMSTATE_END_OF_LIST() + } +}; + +static void bcm2835_st_init(Object *obj) +{ + BCM2835StState *s = BCM2835_ST(obj); + int i; + + for (i = 0; i < 4; i++) { + sysbus_init_irq(SYS_BUS_DEVICE(s), &s->irq[i]); + } + + memory_region_init_io(&s->iomem, obj, &bcm2835_st_ops, s, + TYPE_BCM2835_ST, 0x20); + sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem); +} + +static void bcm2835_st_realize(DeviceState *dev, Error **errp) +{ + BCM2835StState *s = BCM2835_ST(dev); + int i; + + for (i = 0; i < 4; i++) { + s->compare[i] = 0; + } + s->match = 0; + s->timer = timer_new_us(QEMU_CLOCK_VIRTUAL, bcm2835_st_tick, s); + + bcm2835_st_update(s); +} + +static void bcm2835_st_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = bcm2835_st_realize; + dc->vmsd = &vmstate_bcm2835_st; +} + +static TypeInfo bcm2835_st_info = { + .name = TYPE_BCM2835_ST, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(BCM2835StState), + .class_init = bcm2835_st_class_init, + .instance_init = bcm2835_st_init, +}; + +static void bcm2835_st_register_types(void) +{ + type_register_static(&bcm2835_st_info); +} + +type_init(bcm2835_st_register_types) diff --git a/hw/timer/bcm2835_timer.c b/hw/timer/bcm2835_timer.c new file mode 100644 index 0000000000..87f14f8561 --- /dev/null +++ b/hw/timer/bcm2835_timer.c @@ -0,0 +1,224 @@ +/* + * Raspberry Pi emulation (c) 2012 Gregory Estrade + * This code is licensed under the GNU GPLv2 and later. + */ + +#include "qemu/osdep.h" +#include "hw/timer/bcm2835_timer.h" +#include "qemu/main-loop.h" +#include "qemu/log.h" + +#define SYSCLOCK_FREQ (252000000) +#define APBCLOCK_FREQ (126000000) + +#define CTRL_FRC_EN (1 << 9) +#define CTRL_TIMER_EN (1 << 7) +#define CTRL_IRQ_EN (1 << 5) +#define CTRL_PS_MASK (3 << 2) +#define CTRL_PS_SHIFT 2 +#define CTRL_CNT_32 (1 << 1) +#define CTRL_FRC_PS_MASK (0xff << 16) +#define CTRL_FRC_PS_SHIFT 16 + +static void timer_tick(void *opaque) +{ + BCM2835TimerState *s = (BCM2835TimerState *)opaque; + s->raw_irq = 1; + if (s->control & CTRL_IRQ_EN) { + qemu_set_irq(s->irq, 1); + } +} +static void frc_timer_tick(void *opaque) +{ + BCM2835TimerState *s = (BCM2835TimerState *)opaque; + s->frc_value++; +} + +static uint64_t bcm2835_timer_read(void *opaque, hwaddr offset, + unsigned size) +{ + BCM2835TimerState *s = (BCM2835TimerState *)opaque; + uint32_t res = 0; + + assert(size == 4); + + switch (offset) { + case 0x0: + res = s->load; + break; + case 0x4: + res = ptimer_get_count(s->timer); + break; + case 0x8: + res = s->control; + break; + case 0xc: + res = 0x544d5241; + break; + case 0x10: + res = s->raw_irq; + break; + case 0x14: + if (s->control & CTRL_IRQ_EN) { + res = s->raw_irq; + } + break; + case 0x18: + res = s->load; + break; + case 0x1c: + res = s->prediv; + break; + case 0x20: + res = s->frc_value; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "bcm2835_timer_read: Bad offset %x\n", (int)offset); + return 0; + } + + return res; +} + +static void bcm2835_timer_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + BCM2835TimerState *s = (BCM2835TimerState *)opaque; + uint32_t freq; + + assert(size == 4); + + switch (offset) { + case 0x0: + s->load = value; + ptimer_set_limit(s->timer, s->load, 1); + break; + case 0x4: + break; + case 0x8: + if (s->control & CTRL_FRC_EN) { + ptimer_stop(s->frc_timer); + } + if (s->control & CTRL_TIMER_EN) { + ptimer_stop(s->timer); + } + s->control = value & 0x00ff03ae; + + freq = SYSCLOCK_FREQ; + ptimer_set_freq(s->frc_timer, freq); + ptimer_set_limit(s->frc_timer, + ((s->control & CTRL_FRC_PS_MASK) >> CTRL_FRC_PS_SHIFT) + 1, + s->control & CTRL_FRC_EN); + + freq = APBCLOCK_FREQ; + freq /= s->prediv + 1; + switch ((s->control & CTRL_PS_MASK) >> CTRL_PS_SHIFT) { + case 1: + freq >>= 4; + break; + case 2: + freq >>= 8; + break; + default: + break; + } + ptimer_set_freq(s->timer, freq); + ptimer_set_limit(s->timer, s->load, s->control & CTRL_TIMER_EN); + + if (s->control & CTRL_TIMER_EN) { + ptimer_run(s->timer, 0); + } + if (s->control & CTRL_FRC_EN) { + s->frc_value++; + ptimer_run(s->frc_timer, 0); + } + break; + case 0xc: + s->raw_irq = 0; + qemu_set_irq(s->irq, 0); + break; + case 0x10: + case 0x14: + break; + case 0x18: + s->load = value; + ptimer_set_limit(s->timer, s->load, 0); + break; + case 0x1c: + s->prediv = value & 0x3ff; + break; + case 0x20: + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "bcm2835_timer_write: Bad offset %x\n", (int)offset); + return; + } +} + +static const MemoryRegionOps bcm2835_timer_ops = { + .read = bcm2835_timer_read, + .write = bcm2835_timer_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static const VMStateDescription vmstate_bcm2835_timer = { + .name = TYPE_BCM2835_TIMER, + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_END_OF_LIST() + } +}; + +static void bcm2835_timer_init(Object *obj) +{ + BCM2835TimerState *s = BCM2835_TIMER(obj); + + memory_region_init_io(&s->iomem, obj, &bcm2835_timer_ops, s, + TYPE_BCM2835_TIMER, 0x100); + sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem); + sysbus_init_irq(SYS_BUS_DEVICE(s), &s->irq); +} + +static void bcm2835_timer_realize(DeviceState *dev, Error **errp) +{ + BCM2835TimerState *s = BCM2835_TIMER(dev); + QEMUBH *bh; + + s->load = 0; + s->control = 0x3e << 16; + s->raw_irq = 0; + s->prediv = 0x7d; + + bh = qemu_bh_new(timer_tick, s); + s->timer = ptimer_init(bh,PTIMER_POLICY_DEFAULT); + + bh = qemu_bh_new(frc_timer_tick, s); + s->frc_timer = ptimer_init(bh,PTIMER_POLICY_DEFAULT); +} + +static void bcm2835_timer_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = bcm2835_timer_realize; + dc->vmsd = &vmstate_bcm2835_timer; +} + +static TypeInfo bcm2835_timer_info = { + .name = TYPE_BCM2835_TIMER, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(BCM2835TimerState), + .class_init = bcm2835_timer_class_init, + .instance_init = bcm2835_timer_init, +}; + +static void bcm2835_timer_register_types(void) +{ + type_register_static(&bcm2835_timer_info); +} + +type_init(bcm2835_timer_register_types) diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs index 5958be8ce3..9ac7cb4c41 100644 --- a/hw/usb/Makefile.objs +++ b/hw/usb/Makefile.objs @@ -40,5 +40,7 @@ common-obj-$(CONFIG_USB_REDIR) += redirect.o quirks.o common-obj-y += $(patsubst %,host-%.o,$(HOST_USB)) ifeq ($(CONFIG_USB_LIBUSB),y) -common-obj-$(CONFIG_XEN) += xen-usb.o +common-obj-$(CONFIG_XEN_BACKEND) += xen-usb.o endif + +obj-$(CONFIG_RASPI) += bcm2835_usb.o diff --git a/hw/usb/bcm2835_usb.c b/hw/usb/bcm2835_usb.c new file mode 100644 index 0000000000..ed745e5591 --- /dev/null +++ b/hw/usb/bcm2835_usb.c @@ -0,0 +1,604 @@ +/* + * Raspberry Pi emulation (c) 2012-2013 Gregory Estrade + * This code is licensed under the GNU GPLv2 and later. + */ + +/* This is wrong at so many levels, but well, I'm releasing it anyway */ + +#include "qemu/osdep.h" +#include "hw/usb/bcm2835_usb.h" + +#include "qemu/log.h" +#include "qapi/error.h" + +#include "sysemu/dma.h" + +#include "bcm2835_usb_regs.h" + +/* You may have to change these parameters to get an almost-usable mouse + * support. + * The problem is that frame scheduling is all done by software, so a LOT of + * interrupts are generated, which doesn't help... */ +#define SOF_INCR 1 +#define SOF_DELAY 5000 + +static void bcm2835_usb_update_irq(BCM2835UsbState *s) +{ + int n; + + s->haint = 0; + for (n = 0; n < BCM2835_USB_HCHANS; n++) { + if (s->hchan[n].hcint & s->hchan[n].hcintmsk) { + s->haint |= (1 << n); + } + } + s->gintsts &= ~gintsts_hcintr; + if (s->haint & s->haintmsk) { + s->gintsts |= gintsts_hcintr; + } + + if ((s->hprt0 & hprt0_prtconndet) + || (s->hprt0 & hprt0_prtenchng)) { + s->gintsts |= gintsts_portintr; + } else { + s->gintsts &= ~gintsts_portintr; + } + + s->gintsts |= gintsts_nptxfempty | gintsts_ptxfempty; + + if (!(s->gahbcfg & gahbcfg_glblintrmsk)) { + qemu_set_irq(s->irq, 0); + } else { + if (s->gintsts & s->gintmsk) { + qemu_set_irq(s->irq, 1); + } else { + qemu_set_irq(s->irq, 0); + } + } +} + + +static void bcm2835_usb_sof_tick(void *opaque) +{ + BCM2835UsbState *s = (BCM2835UsbState *)opaque; + int64_t now; + + uint32_t num = (s->hfnum & 0x3fff) + SOF_INCR; + s->hfnum = (num & 0x3fff) | (0x3210 << 16); + s->gintsts |= gintsts_sofintr; + + bcm2835_usb_update_irq(s); + + now = qemu_clock_get_us(QEMU_CLOCK_VIRTUAL); + timer_mod(s->sof_timer, now + SOF_DELAY); +} + +static void channel_enable(BCM2835UsbHcState *c) +{ + USBEndpoint *ep; + USBDevice *dev; + + uint32_t epnum = (c->hcchar >> hcchar_epnum_shift) & hcchar_epnum_mask; + uint32_t devaddr = (c->hcchar >> hcchar_devaddr_shift) + & hcchar_devaddr_mask; + uint32_t xfersize = (c->hctsiz >> hctsiz_xfersize_shift) + & hctsiz_xfersize_mask; + uint32_t pid = (c->hctsiz >> hctsiz_pid_shift) & hctsiz_pid_mask; + uint32_t dma_addr = c->hcdma; /* ??? */ + int actual_length; + int qpid; + + if (!c->parent->reset_done) { + return; + } + + if (c->hcchar & hcchar_epdir) { + /* IN */ + qpid = USB_TOKEN_IN; + } else { + /* OUT/SETUP */ + if (pid == DWC_HCTSIZ_SETUP) { + qpid = USB_TOKEN_SETUP; + } else { + qpid = USB_TOKEN_OUT; + } + } + + dev = usb_find_device(&c->parent->port, devaddr); + assert(dev != NULL); + + ep = usb_ep_get(dev, qpid, epnum); + usb_packet_setup(&c->packet, qpid, ep, 0, devaddr, 0, 0); + + if (xfersize > 0) { + dma_memory_read(&c->parent->dma_as, dma_addr, c->buffer, xfersize); + + usb_packet_addbuf(&c->packet, c->buffer, xfersize); + } + usb_handle_packet(dev, &c->packet); + + if (c->packet.status == USB_RET_SUCCESS) { + if (qpid == USB_TOKEN_IN) { + actual_length = c->packet.actual_length; + + xfersize -= actual_length; + c->hctsiz &= ~(hctsiz_xfersize_mask << hctsiz_xfersize_shift); + c->hctsiz |= xfersize << hctsiz_xfersize_shift; + + dma_memory_write(&c->parent->dma_as, dma_addr, c->buffer, + actual_length); + } + + c->hcint |= hcint_xfercomp | hcint_chhltd; + bcm2835_usb_update_irq(c->parent); + } else if (c->packet.status == USB_RET_NAK) { + c->hcint |= hcint_chhltd | hcint_nak; + bcm2835_usb_update_irq(c->parent); + } else { + /* assert(0); */ + c->hcint |= hcint_chhltd | hcint_stall; + bcm2835_usb_update_irq(c->parent); + } + +} + +static uint32_t bcm2835_usb_hchan_read(BCM2835UsbState *s, int ch, + int offset) +{ + BCM2835UsbHcState *c = &s->hchan[ch]; + uint32_t res; + + switch (offset) { + case 0x0: + res = c->hcchar; + break; + case 0x4: + res = c->hcsplt; + break; + case 0x8: + res = c->hcint; + break; + case 0xc: + res = c->hcintmsk; + break; + case 0x10: + res = c->hctsiz; + break; + case 0x14: + res = c->hcdma; + break; + case 0x1c: + res = c->hcdmab; + break; + default: + res = 0; + break; + } + return res; +} +static void bcm2835_usb_hchan_write(BCM2835UsbState *s, int ch, + int offset, uint32_t value, int *pset_irq) +{ + BCM2835UsbHcState *c = &s->hchan[ch]; + + switch (offset) { + case 0x0: + c->hcchar = value; + if (value & hcchar_chdis) { + c->hcchar &= ~(hcchar_chdis | hcchar_chen); + /* TODO irq */ + } + if (value & hcchar_chen) { + channel_enable(c); + } + break; + case 0x4: + c->hcsplt = value; + break; + case 0x8: + /* Looks like a standard interrupt register */ + c->hcint &= ~value; + *pset_irq = 1; + break; + case 0xc: + c->hcintmsk = value; + break; + case 0x10: + c->hctsiz = value; + break; + case 0x14: + c->hcdma = value; + break; + case 0x1c: + c->hcdmab = value; + break; + default: + break; + } +} + +static uint64_t bcm2835_usb_read(void *opaque, hwaddr offset, + unsigned size) +{ + BCM2835UsbState *s = (BCM2835UsbState *)opaque; + uint32_t res = 0; + int i; + + assert(size == 4); + + switch (offset) { + case 0x0: + res = s->gotgctl; + break; + case 0x4: + res = s->gotgint; + break; + case 0x8: + res = s->gahbcfg; + break; + case 0xc: + res = s->gusbcfg; + break; + case 0x10: + res = s->grstctl; + break; + case 0x14: + res = s->gintsts; + /* Enforce Host mode */ + res |= gintsts_curmode; + break; + case 0x18: + res = s->gintmsk; + break; + case 0x24: + res = s->grxfsiz; + break; + case 0x28: + res = s->gnptxfsiz; + break; + case 0x2c: + res = s->gnptxsts; + break; + case 0x3c: + res = s->guid; + break; + case 0x40: + res = 0x4f54280a; + break; + case 0x44: + res = 0; + break; + case 0x48: + res = 0x228ddd50; + break; + case 0x4c: + res = 0x0ff000e8; + break; + case 0x50: + res = 0x1ff00020; + break; + case 0x5c: + res = s->gdfifocfg; + break; + case 0x100: + res = s->hptxfsiz; + break; + case 0x400: + res = s->hcfg; + break; + case 0x408: + res = s->hfnum; + break; + case 0x410: + res = s->hptxsts; + break; + case 0x414: + res = s->haint; + break; + case 0x418: + res = s->haintmsk; + break; + case 0x440: + res = s->hprt0; + res &= ~hprt0_prtconnsts; + if (s->attached) { + res |= hprt0_prtconnsts; + } + break; + case 0x800: + res = s->dcfg; + break; + + case 0xe00: + case 0x54: + case 0x58: + res = 0; + break; + + default: + if ((offset >= 0x104) && (offset < 0x104 + (15 << 2))) { + res = s->dtxfsiz[(offset - 0x104) >> 2]; + } else if ((offset >= 0x500) && (offset < 0x500 + 0x20*BCM2835_USB_HCHANS)) { + i = (offset - 0x500) >> 5; + res = bcm2835_usb_hchan_read(s, i, offset & 0x1f); + } else { + qemu_log_mask(LOG_GUEST_ERROR, + "bcm2835_usb_read: Bad offset %x\n", (int)offset); + res = 0; + } + break; + } + return res; +} + +static void bcm2835_usb_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + BCM2835UsbState *s = (BCM2835UsbState *)opaque; + + int i; + int set_irq = 0; + + assert(size == 4); + + switch (offset) { + case 0x0: + s->gotgctl = value; + break; + case 0x4: + /* Looks like a standard interrupt register */ + s->gotgint &= ~value; + break; + case 0x8: + s->gahbcfg = value; + set_irq = 1; + break; + case 0xc: + s->gusbcfg = value; + break; + case 0x10: + s->grstctl &= ~0x7c0; + s->grstctl |= value & 0x7c0; + break; + case 0x14: + s->gintsts &= ~value; + /* Enforce Host mode */ + s->gintsts |= gintsts_curmode; + set_irq = 1; + break; + case 0x18: + s->gintmsk = value; + break; + case 0x24: + s->grxfsiz = value; + break; + case 0x28: + s->gnptxfsiz = value; + break; + case 0x3c: + s->guid = value; + break; + case 0x5c: + s->gdfifocfg = value; + break; + case 0x100: + s->hptxfsiz = value; + break; + case 0x400: + s->hcfg = value; + break; + case 0x408: + /* Probably RO */ + break; + case 0x410: + /* Probably RO */ + break; + case 0x414: + /* Probably RO */ + break; + case 0x418: + s->haintmsk = value & ((1 << BCM2835_USB_HCHANS) - 1); + set_irq = 1; + break; + case 0x440: + if (!(s->hprt0 & hprt0_prtpwr) && (value & hprt0_prtpwr)) { + /* Trigger the port status change interrupt on power on */ + if (s->attached) { + s->hprt0 |= hprt0_prtconndet; + set_irq = 1; + /* Reset the device (that's probably not the right place) */ + usb_device_reset(s->port.dev); + s->reset_done = 1; + timer_mod(s->sof_timer, 0); + } + } + s->hprt0 &= ~hprt0_prtpwr; + s->hprt0 |= value & hprt0_prtpwr; + + if ((s->hprt0 & hprt0_prtres) ^ (value & hprt0_prtres)) { + s->hprt0 |= hprt0_prtenchng; + set_irq = 1; + } + s->hprt0 &= ~(hprt0_prtena | hprt0_prtres); + if (value & hprt0_prtres) { + s->hprt0 |= hprt0_prtres; + } else { + s->hprt0 |= hprt0_prtena; + } + + /* Interrupt clears */ + if (value & hprt0_prtconndet) { + s->hprt0 &= ~hprt0_prtconndet; + set_irq = 1; + } + if (value & hprt0_prtenchng) { + s->hprt0 &= ~hprt0_prtenchng; + set_irq = 1; + } + + break; + + case 0xe00: + case 0x54: + case 0x58: + break; + + default: + if ((offset >= 0x104) && (offset < 0x104 + (15 << 2))) { + s->dtxfsiz[(offset - 0x104) >> 2] = value; + } else if ((offset >= 0x500) && (offset < 0x500 + 0x20*BCM2835_USB_HCHANS)) { + i = (offset - 0x500) >> 5; + bcm2835_usb_hchan_write(s, i, offset & 0x1f, value, &set_irq); + } else { + qemu_log_mask(LOG_GUEST_ERROR, + "bcm2835_usb_write: Bad offset %x\n", (int)offset); + } + break; + } + + if (set_irq) { + bcm2835_usb_update_irq(s); + } +} + +static void bcm2835_usb_attach(USBPort *port1) +{ + BCM2835UsbState *s = port1->opaque; + s->attached = 1; +} +static void bcm2835_usb_detach(USBPort *port1) +{ +} +static void bcm2835_usb_child_detach(USBPort *port1, USBDevice *child) +{ +} +static void bcm2835_usb_wakeup(USBPort *port1) +{ +} +static void bcm2835_usb_async_complete(USBPort *port, USBPacket *packet) +{ +} + + +static const MemoryRegionOps bcm2835_usb_ops = { + .read = bcm2835_usb_read, + .write = bcm2835_usb_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static const VMStateDescription vmstate_bcm2835_usb = { + .name = TYPE_BCM2835_USB, + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_END_OF_LIST() + } +}; + +static USBPortOps bcm2835_usb_port_ops = { + .attach = bcm2835_usb_attach, + .detach = bcm2835_usb_detach, + .child_detach = bcm2835_usb_child_detach, + .wakeup = bcm2835_usb_wakeup, + .complete = bcm2835_usb_async_complete, +}; + +static USBBusOps bcm2835_usb_bus_ops = { +}; + +static void bcm2835_usb_init(Object *obj) +{ + BCM2835UsbState *s = BCM2835_USB(obj); + + memory_region_init_io(&s->iomem, obj, &bcm2835_usb_ops, s, + TYPE_BCM2835_USB, 0x20000); + sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem); + sysbus_init_irq(SYS_BUS_DEVICE(s), &s->irq); +} + +static void bcm2835_usb_realize(DeviceState *dev, Error **errp) +{ + int n; + BCM2835UsbState *s = BCM2835_USB(dev); + Error *err = NULL; + Object *obj; + + obj = object_property_get_link(OBJECT(dev), "dma_mr", &err); + if (err || obj == NULL) { + error_setg(errp, "bcm2835_usb: required dma_mr property not found"); + return; + } + + s->dma_mr = MEMORY_REGION(obj); + address_space_init(&s->dma_as, s->dma_mr, NULL); + + s->gusbcfg = 0x20402700; + s->hptxfsiz = 0x02002000; + s->hcfg = 0x00000001; + s->dcfg = 0x00000000; + s->grxfsiz = 0x00001000; + s->gnptxfsiz = 0x01001000; + for (n = 0; n < 15; n++) { + s->dtxfsiz[n] = 0x02002000; + } + s->gahbcfg = 0x0000000e; + s->grstctl = 0x80000000; + s->gotgctl = 0x001c0000; + s->gotgint = 0; + s->gintsts = 0; + s->gintmsk = 0; + s->gdfifocfg = 0x00000000; + s->hprt0 = DWC_HPRT0_PRTSPD_FULL_SPEED << hprt0_prtspd_shift; + s->gnptxsts = 0x080100; + s->hfnum = 0; + s->hptxsts = 0x080200; + s->guid = 0x2708A000; + + for (n = 0; n < BCM2835_USB_HCHANS; n++) { + s->hchan[n].parent = s; + s->hchan[n].index = n; + + s->hchan[n].hcchar = 0; + s->hchan[n].hcsplt = 0; + s->hchan[n].hcint = 0; + s->hchan[n].hcintmsk = 0; + s->hchan[n].hctsiz = 0; + s->hchan[n].hcdma = 0; + s->hchan[n].hcdmab = 0; + + usb_packet_init(&s->hchan[n].packet); + } + + s->attached = 0; + s->reset_done = 0; + + s->sof_timer = timer_new_us(QEMU_CLOCK_VIRTUAL, bcm2835_usb_sof_tick, s); + + usb_bus_new(&s->bus, sizeof(s->bus), &bcm2835_usb_bus_ops, DEVICE(s)); + usb_register_port(&s->bus, &s->port, s, 0, &bcm2835_usb_port_ops, + USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL); +} + +static void bcm2835_usb_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = bcm2835_usb_realize; + dc->vmsd = &vmstate_bcm2835_usb; +} + +static TypeInfo bcm2835_usb_info = { + .name = TYPE_BCM2835_USB, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(BCM2835UsbState), + .class_init = bcm2835_usb_class_init, + .instance_init = bcm2835_usb_init, +}; + +static void bcm2835_usb_register_types(void) +{ + type_register_static(&bcm2835_usb_info); +} + +type_init(bcm2835_usb_register_types) diff --git a/hw/usb/bcm2835_usb_regs.h b/hw/usb/bcm2835_usb_regs.h new file mode 100644 index 0000000000..76f3219b54 --- /dev/null +++ b/hw/usb/bcm2835_usb_regs.h @@ -0,0 +1,1061 @@ +#ifndef BCM2835_USB_REGS_H +#define BCM2835_USB_REGS_H + +#define __DWC_OTG_REGS_H__ +#define DWC_GLBINTRMASK 0x0001 +#define DWC_DMAENABLE 0x0020 +#define DWC_NPTXEMPTYLVL_EMPTY 0x0080 +#define DWC_NPTXEMPTYLVL_HALFEMPTY 0x0000 +#define DWC_PTXEMPTYLVL_EMPTY 0x0100 +#define DWC_PTXEMPTYLVL_HALFEMPTY 0x0000 +#define DWC_SLAVE_ONLY_ARCH 0 +#define DWC_EXT_DMA_ARCH 1 +#define DWC_INT_DMA_ARCH 2 +#define DWC_MODE_HNP_SRP_CAPABLE 0 +#define DWC_MODE_SRP_ONLY_CAPABLE 1 +#define DWC_MODE_NO_HNP_SRP_CAPABLE 2 +#define DWC_MODE_SRP_CAPABLE_DEVICE 3 +#define DWC_MODE_NO_SRP_CAPABLE_DEVICE 4 +#define DWC_MODE_SRP_CAPABLE_HOST 5 +#define DWC_MODE_NO_SRP_CAPABLE_HOST 6 + +/* union gotgctl_data */ +#define gotgctl_sesreqscs (1 << 0) +#define gotgctl_sesreq (1 << 1) +#define gotgctl_vbvalidoven (1 << 2) +#define gotgctl_vbvalidovval (1 << 3) +#define gotgctl_avalidoven (1 << 4) +#define gotgctl_avalidovval (1 << 5) +#define gotgctl_bvalidoven (1 << 6) +#define gotgctl_bvalidovval (1 << 7) +#define gotgctl_hstnegscs (1 << 8) +#define gotgctl_hnpreq (1 << 9) +#define gotgctl_hstsethnpen (1 << 10) +#define gotgctl_devhnpen (1 << 11) +#define gotgctl_reserved12_15_shift (12) +#define gotgctl_reserved12_15_mask (0xf) +#define gotgctl_conidsts (1 << 16) +#define gotgctl_dbnctime (1 << 17) +#define gotgctl_asesvld (1 << 18) +#define gotgctl_bsesvld (1 << 19) +#define gotgctl_otgver (1 << 20) +#define gotgctl_reserved1 (1 << 21) +#define gotgctl_multvalidbc_shift (22) +#define gotgctl_multvalidbc_mask (0x1f) +#define gotgctl_chirpen (1 << 27) +#define gotgctl_reserved28_31_shift (28) +#define gotgctl_reserved28_31_mask (0xf) + +/* union gotgint_data */ +#define gotgint_reserved0_1_shift (0) +#define gotgint_reserved0_1_mask (0x3) +#define gotgint_sesenddet (1 << 2) +#define gotgint_reserved3_7_shift (3) +#define gotgint_reserved3_7_mask (0x1f) +#define gotgint_sesreqsucstschng (1 << 8) +#define gotgint_hstnegsucstschng (1 << 9) +#define gotgint_reserved10_16_shift (10) +#define gotgint_reserved10_16_mask (0x7f) +#define gotgint_hstnegdet (1 << 17) +#define gotgint_adevtoutchng (1 << 18) +#define gotgint_debdone (1 << 19) +#define gotgint_mvic (1 << 20) +#define gotgint_reserved31_21_shift (21) +#define gotgint_reserved31_21_mask (0x7ff) + +/* union gahbcfg_data */ +#define gahbcfg_glblintrmsk (1 << 0) +#define DWC_GAHBCFG_GLBINT_ENABLE 1 +#define gahbcfg_hburstlen_shift (1) +#define gahbcfg_hburstlen_mask (0xf) +#define DWC_GAHBCFG_INT_DMA_BURST_SINGLE 0 +#define DWC_GAHBCFG_INT_DMA_BURST_INCR 1 +#define DWC_GAHBCFG_INT_DMA_BURST_INCR4 3 +#define DWC_GAHBCFG_INT_DMA_BURST_INCR8 5 +#define DWC_GAHBCFG_INT_DMA_BURST_INCR16 7 +#define gahbcfg_dmaenable (1 << 5) +#define DWC_GAHBCFG_DMAENABLE 1 +#define gahbcfg_reserved (1 << 6) +#define gahbcfg_nptxfemplvl_txfemplvl (1 << 7) +#define gahbcfg_ptxfemplvl (1 << 8) +#define DWC_GAHBCFG_TXFEMPTYLVL_EMPTY 1 +#define DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY 0 +#define gahbcfg_reserved9_20_shift (9) +#define gahbcfg_reserved9_20_mask (0xfff) +#define gahbcfg_remmemsupp (1 << 21) +#define gahbcfg_notialldmawrit (1 << 22) +#define gahbcfg_ahbsingle (1 << 23) +#define gahbcfg_reserved24_31_shift (24) +#define gahbcfg_reserved24_31_mask (0xff) + +/* union gusbcfg_data */ +#define gusbcfg_toutcal_shift (0) +#define gusbcfg_toutcal_mask (0x7) +#define gusbcfg_phyif (1 << 3) +#define gusbcfg_ulpi_utmi_sel (1 << 4) +#define gusbcfg_fsintf (1 << 5) +#define gusbcfg_physel (1 << 6) +#define gusbcfg_ddrsel (1 << 7) +#define gusbcfg_srpcap (1 << 8) +#define gusbcfg_hnpcap (1 << 9) +#define gusbcfg_usbtrdtim_shift (10) +#define gusbcfg_usbtrdtim_mask (0xf) +#define gusbcfg_reserved1 (1 << 14) +#define gusbcfg_phylpwrclksel (1 << 15) +#define gusbcfg_otgutmifssel (1 << 16) +#define gusbcfg_ulpi_fsls (1 << 17) +#define gusbcfg_ulpi_auto_res (1 << 18) +#define gusbcfg_ulpi_clk_sus_m (1 << 19) +#define gusbcfg_ulpi_ext_vbus_drv (1 << 20) +#define gusbcfg_ulpi_int_vbus_indicator (1 << 21) +#define gusbcfg_term_sel_dl_pulse (1 << 22) +#define gusbcfg_indicator_complement (1 << 23) +#define gusbcfg_indicator_pass_through (1 << 24) +#define gusbcfg_ulpi_int_prot_dis (1 << 25) +#define gusbcfg_ic_usb_cap (1 << 26) +#define gusbcfg_ic_traffic_pull_remove (1 << 27) +#define gusbcfg_tx_end_delay (1 << 28) +#define gusbcfg_force_host_mode (1 << 29) +#define gusbcfg_force_dev_mode (1 << 30) +#define gusbcfg_reserved31 (1 << 31) + +/* union grstctl_data */ +#define grstctl_csftrst (1 << 0) +#define grstctl_hsftrst (1 << 1) +#define grstctl_hstfrm (1 << 2) +#define grstctl_intknqflsh (1 << 3) +#define grstctl_rxfflsh (1 << 4) +#define grstctl_txfflsh (1 << 5) +#define grstctl_txfnum_shift (6) +#define grstctl_txfnum_mask (0x1f) +#define grstctl_reserved11_29_shift (11) +#define grstctl_reserved11_29_mask (0x7ffff) +#define grstctl_dmareq (1 << 30) +#define grstctl_ahbidle (1 << 31) + +/* union gintmsk_data */ +#define gintmsk_reserved0 (1 << 0) +#define gintmsk_modemismatch (1 << 1) +#define gintmsk_otgintr (1 << 2) +#define gintmsk_sofintr (1 << 3) +#define gintmsk_rxstsqlvl (1 << 4) +#define gintmsk_nptxfempty (1 << 5) +#define gintmsk_ginnakeff (1 << 6) +#define gintmsk_goutnakeff (1 << 7) +#define gintmsk_ulpickint (1 << 8) +#define gintmsk_i2cintr (1 << 9) +#define gintmsk_erlysuspend (1 << 10) +#define gintmsk_usbsuspend (1 << 11) +#define gintmsk_usbreset (1 << 12) +#define gintmsk_enumdone (1 << 13) +#define gintmsk_isooutdrop (1 << 14) +#define gintmsk_eopframe (1 << 15) +#define gintmsk_restoredone (1 << 16) +#define gintmsk_epmismatch (1 << 17) +#define gintmsk_inepintr (1 << 18) +#define gintmsk_outepintr (1 << 19) +#define gintmsk_incomplisoin (1 << 20) +#define gintmsk_incomplisoout (1 << 21) +#define gintmsk_fetsusp (1 << 22) +#define gintmsk_resetdet (1 << 23) +#define gintmsk_portintr (1 << 24) +#define gintmsk_hcintr (1 << 25) +#define gintmsk_ptxfempty (1 << 26) +#define gintmsk_lpmtranrcvd (1 << 27) +#define gintmsk_conidstschng (1 << 28) +#define gintmsk_disconnect (1 << 29) +#define gintmsk_sessreqintr (1 << 30) +#define gintmsk_wkupintr (1 << 31) + +/* union gintsts_data */ +#define DWC_SOF_INTR_MASK 0x0008 +#define DWC_HOST_MODE 1 +#define gintsts_curmode (1 << 0) +#define gintsts_modemismatch (1 << 1) +#define gintsts_otgintr (1 << 2) +#define gintsts_sofintr (1 << 3) +#define gintsts_rxstsqlvl (1 << 4) +#define gintsts_nptxfempty (1 << 5) +#define gintsts_ginnakeff (1 << 6) +#define gintsts_goutnakeff (1 << 7) +#define gintsts_ulpickint (1 << 8) +#define gintsts_i2cintr (1 << 9) +#define gintsts_erlysuspend (1 << 10) +#define gintsts_usbsuspend (1 << 11) +#define gintsts_usbreset (1 << 12) +#define gintsts_enumdone (1 << 13) +#define gintsts_isooutdrop (1 << 14) +#define gintsts_eopframe (1 << 15) +#define gintsts_restoredone (1 << 16) +#define gintsts_epmismatch (1 << 17) +#define gintsts_inepint (1 << 18) +#define gintsts_outepintr (1 << 19) +#define gintsts_incomplisoin (1 << 20) +#define gintsts_incomplisoout (1 << 21) +#define gintsts_fetsusp (1 << 22) +#define gintsts_resetdet (1 << 23) +#define gintsts_portintr (1 << 24) +#define gintsts_hcintr (1 << 25) +#define gintsts_ptxfempty (1 << 26) +#define gintsts_lpmtranrcvd (1 << 27) +#define gintsts_conidstschng (1 << 28) +#define gintsts_disconnect (1 << 29) +#define gintsts_sessreqintr (1 << 30) +#define gintsts_wkupintr (1 << 31) + +/* union device_grxsts_data */ +#define device_grxsts_epnum_shift (0) +#define device_grxsts_epnum_mask (0xf) +#define device_grxsts_bcnt_shift (4) +#define device_grxsts_bcnt_mask (0x7ff) +#define device_grxsts_dpid_shift (15) +#define device_grxsts_dpid_mask (0x3) +#define DWC_STS_DATA_UPDT 0x2 /* OUT Data Packet */ +#define DWC_STS_XFER_COMP 0x3 /* OUT Data Transfer Complete */ +#define DWC_DSTS_GOUT_NAK 0x1 /* Global OUT NAK */ +#define DWC_DSTS_SETUP_COMP 0x4 /* Setup Phase Complete */ +#define DWC_DSTS_SETUP_UPDT 0x6 /* SETUP Packet */ +#define device_grxsts_pktsts_shift (17) +#define device_grxsts_pktsts_mask (0xf) +#define device_grxsts_fn_shift (21) +#define device_grxsts_fn_mask (0xf) +#define device_grxsts_reserved25_31_shift (25) +#define device_grxsts_reserved25_31_mask (0x7f) + +/* union host_grxsts_data */ +#define host_grxsts_chnum_shift (0) +#define host_grxsts_chnum_mask (0xf) +#define host_grxsts_bcnt_shift (4) +#define host_grxsts_bcnt_mask (0x7ff) +#define host_grxsts_dpid_shift (15) +#define host_grxsts_dpid_mask (0x3) +#define host_grxsts_pktsts_shift (17) +#define host_grxsts_pktsts_mask (0xf) +#define DWC_GRXSTS_PKTSTS_IN 0x2 +#define DWC_GRXSTS_PKTSTS_IN_XFER_COMP 0x3 +#define DWC_GRXSTS_PKTSTS_DATA_TOGGLE_ERR 0x5 +#define DWC_GRXSTS_PKTSTS_CH_HALTED 0x7 +#define host_grxsts_reserved21_31_shift (21) +#define host_grxsts_reserved21_31_mask (0x7ff) + +/* union fifosize_data */ +#define fifosize_startaddr_shift (0) +#define fifosize_startaddr_mask (0xffff) +#define fifosize_depth_shift (16) +#define fifosize_depth_mask (0xffff) + +/* union gnptxsts_data */ +#define gnptxsts_nptxfspcavail_shift (0) +#define gnptxsts_nptxfspcavail_mask (0xffff) +#define gnptxsts_nptxqspcavail_shift (16) +#define gnptxsts_nptxqspcavail_mask (0xff) +#define gnptxsts_nptxqtop_terminate (1 << 24) +#define gnptxsts_nptxqtop_token_shift (25) +#define gnptxsts_nptxqtop_token_mask (0x3) +#define gnptxsts_nptxqtop_chnep_shift (27) +#define gnptxsts_nptxqtop_chnep_mask (0xf) +#define gnptxsts_reserved (1 << 31) + +/* union dtxfsts_data */ +#define dtxfsts_txfspcavail_shift (0) +#define dtxfsts_txfspcavail_mask (0xffff) +#define dtxfsts_reserved_shift (16) +#define dtxfsts_reserved_mask (0xffff) + +/* union gi2cctl_data */ +#define gi2cctl_rwdata_shift (0) +#define gi2cctl_rwdata_mask (0xff) +#define gi2cctl_regaddr_shift (8) +#define gi2cctl_regaddr_mask (0xff) +#define gi2cctl_addr_shift (16) +#define gi2cctl_addr_mask (0x7f) +#define gi2cctl_i2cen (1 << 23) +#define gi2cctl_ack (1 << 24) +#define gi2cctl_i2csuspctl (1 << 25) +#define gi2cctl_i2cdevaddr_shift (26) +#define gi2cctl_i2cdevaddr_mask (0x3) +#define gi2cctl_i2cdatse0 (1 << 28) +#define gi2cctl_reserved (1 << 29) +#define gi2cctl_rw (1 << 30) +#define gi2cctl_bsydne (1 << 31) + +/* union gpvndctl_data */ +#define gpvndctl_regdata_shift (0) +#define gpvndctl_regdata_mask (0xff) +#define gpvndctl_vctrl_shift (8) +#define gpvndctl_vctrl_mask (0xff) +#define gpvndctl_regaddr16_21_shift (16) +#define gpvndctl_regaddr16_21_mask (0x3f) +#define gpvndctl_regwr (1 << 22) +#define gpvndctl_reserved23_24_shift (23) +#define gpvndctl_reserved23_24_mask (0x3) +#define gpvndctl_newregreq (1 << 25) +#define gpvndctl_vstsbsy (1 << 26) +#define gpvndctl_vstsdone (1 << 27) +#define gpvndctl_reserved28_30_shift (28) +#define gpvndctl_reserved28_30_mask (0x7) +#define gpvndctl_disulpidrvr (1 << 31) + +/* union ggpio_data */ +#define ggpio_gpi_shift (0) +#define ggpio_gpi_mask (0xffff) +#define ggpio_gpo_shift (16) +#define ggpio_gpo_mask (0xffff) + +/* union guid_data */ +#define guid_rwdata_shift (0) +#define guid_rwdata_mask (0xffffffff) + +/* union gsnpsid_data */ +#define gsnpsid_rwdata_shift (0) +#define gsnpsid_rwdata_mask (0xffffffff) + +/* union hwcfg1_data */ +#define hwcfg1_ep_dir0_shift (0) +#define hwcfg1_ep_dir0_mask (0x3) +#define hwcfg1_ep_dir1_shift (2) +#define hwcfg1_ep_dir1_mask (0x3) +#define hwcfg1_ep_dir2_shift (4) +#define hwcfg1_ep_dir2_mask (0x3) +#define hwcfg1_ep_dir3_shift (6) +#define hwcfg1_ep_dir3_mask (0x3) +#define hwcfg1_ep_dir4_shift (8) +#define hwcfg1_ep_dir4_mask (0x3) +#define hwcfg1_ep_dir5_shift (10) +#define hwcfg1_ep_dir5_mask (0x3) +#define hwcfg1_ep_dir6_shift (12) +#define hwcfg1_ep_dir6_mask (0x3) +#define hwcfg1_ep_dir7_shift (14) +#define hwcfg1_ep_dir7_mask (0x3) +#define hwcfg1_ep_dir8_shift (16) +#define hwcfg1_ep_dir8_mask (0x3) +#define hwcfg1_ep_dir9_shift (18) +#define hwcfg1_ep_dir9_mask (0x3) +#define hwcfg1_ep_dir10_shift (20) +#define hwcfg1_ep_dir10_mask (0x3) +#define hwcfg1_ep_dir11_shift (22) +#define hwcfg1_ep_dir11_mask (0x3) +#define hwcfg1_ep_dir12_shift (24) +#define hwcfg1_ep_dir12_mask (0x3) +#define hwcfg1_ep_dir13_shift (26) +#define hwcfg1_ep_dir13_mask (0x3) +#define hwcfg1_ep_dir14_shift (28) +#define hwcfg1_ep_dir14_mask (0x3) +#define hwcfg1_ep_dir15_shift (30) +#define hwcfg1_ep_dir15_mask (0x3) + +/* union hwcfg2_data */ +#define hwcfg2_op_mode_shift (0) +#define hwcfg2_op_mode_mask (0x7) +#define DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG 0 +#define DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG 1 +#define DWC_HWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE_OTG 2 +#define DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE 3 +#define DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE 4 +#define DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST 5 +#define DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST 6 +#define hwcfg2_architecture_shift (3) +#define hwcfg2_architecture_mask (0x3) +#define hwcfg2_point2point (1 << 5) +#define hwcfg2_hs_phy_type_shift (6) +#define hwcfg2_hs_phy_type_mask (0x3) +#define DWC_HWCFG2_HS_PHY_TYPE_NOT_SUPPORTED 0 +#define DWC_HWCFG2_HS_PHY_TYPE_UTMI 1 +#define DWC_HWCFG2_HS_PHY_TYPE_ULPI 2 +#define DWC_HWCFG2_HS_PHY_TYPE_UTMI_ULPI 3 +#define hwcfg2_fs_phy_type_shift (8) +#define hwcfg2_fs_phy_type_mask (0x3) +#define hwcfg2_num_dev_ep_shift (10) +#define hwcfg2_num_dev_ep_mask (0xf) +#define hwcfg2_num_host_chan_shift (14) +#define hwcfg2_num_host_chan_mask (0xf) +#define hwcfg2_perio_ep_supported (1 << 18) +#define hwcfg2_dynamic_fifo (1 << 19) +#define hwcfg2_multi_proc_int (1 << 20) +#define hwcfg2_reserved21 (1 << 21) +#define hwcfg2_nonperio_tx_q_depth_shift (22) +#define hwcfg2_nonperio_tx_q_depth_mask (0x3) +#define hwcfg2_host_perio_tx_q_depth_shift (24) +#define hwcfg2_host_perio_tx_q_depth_mask (0x3) +#define hwcfg2_dev_token_q_depth_shift (26) +#define hwcfg2_dev_token_q_depth_mask (0x1f) +#define hwcfg2_otg_enable_ic_usb (1 << 31) + +/* union hwcfg3_data */ +#define hwcfg3_xfer_size_cntr_width_shift (0) +#define hwcfg3_xfer_size_cntr_width_mask (0xf) +#define hwcfg3_packet_size_cntr_width_shift (4) +#define hwcfg3_packet_size_cntr_width_mask (0x7) +#define hwcfg3_otg_func (1 << 7) +#define hwcfg3_i2c (1 << 8) +#define hwcfg3_vendor_ctrl_if (1 << 9) +#define hwcfg3_optional_features (1 << 10) +#define hwcfg3_synch_reset_type (1 << 11) +#define hwcfg3_adp_supp (1 << 12) +#define hwcfg3_otg_enable_hsic (1 << 13) +#define hwcfg3_bc_support (1 << 14) +#define hwcfg3_otg_lpm_en (1 << 15) +#define hwcfg3_dfifo_depth_shift (16) +#define hwcfg3_dfifo_depth_mask (0xffff) + +/* union hwcfg4_data */ +#define hwcfg4_num_dev_perio_in_ep_shift (0) +#define hwcfg4_num_dev_perio_in_ep_mask (0xf) +#define hwcfg4_power_optimiz (1 << 4) +#define hwcfg4_min_ahb_freq (1 << 5) +#define hwcfg4_hiber (1 << 6) +#define hwcfg4_xhiber (1 << 7) +#define hwcfg4_reserved_shift (8) +#define hwcfg4_reserved_mask (0x3f) +#define hwcfg4_utmi_phy_data_width_shift (14) +#define hwcfg4_utmi_phy_data_width_mask (0x3) +#define hwcfg4_num_dev_mode_ctrl_ep_shift (16) +#define hwcfg4_num_dev_mode_ctrl_ep_mask (0xf) +#define hwcfg4_iddig_filt_en (1 << 20) +#define hwcfg4_vbus_valid_filt_en (1 << 21) +#define hwcfg4_a_valid_filt_en (1 << 22) +#define hwcfg4_b_valid_filt_en (1 << 23) +#define hwcfg4_session_end_filt_en (1 << 24) +#define hwcfg4_ded_fifo_en (1 << 25) +#define hwcfg4_num_in_eps_shift (26) +#define hwcfg4_num_in_eps_mask (0xf) +#define hwcfg4_desc_dma (1 << 30) +#define hwcfg4_desc_dma_dyn (1 << 31) + +/* union glpmctl_data */ +#define glpmctl_lpm_cap_en (1 << 0) +#define glpmctl_appl_resp (1 << 1) +#define glpmctl_hird_shift (2) +#define glpmctl_hird_mask (0xf) +#define glpmctl_rem_wkup_en (1 << 6) +#define glpmctl_en_utmi_sleep (1 << 7) +#define glpmctl_hird_thres_shift (8) +#define glpmctl_hird_thres_mask (0x1f) +#define glpmctl_lpm_resp_shift (13) +#define glpmctl_lpm_resp_mask (0x3) +#define glpmctl_prt_sleep_sts (1 << 15) +#define glpmctl_sleep_state_resumeok (1 << 16) +#define glpmctl_lpm_chan_index_shift (17) +#define glpmctl_lpm_chan_index_mask (0xf) +#define glpmctl_retry_count_shift (21) +#define glpmctl_retry_count_mask (0x7) +#define glpmctl_send_lpm (1 << 24) +#define glpmctl_retry_count_sts_shift (25) +#define glpmctl_retry_count_sts_mask (0x7) +#define glpmctl_reserved28_29_shift (28) +#define glpmctl_reserved28_29_mask (0x3) +#define glpmctl_hsic_connect (1 << 30) +#define glpmctl_inv_sel_hsic (1 << 31) + +/* union adpctl_data */ +#define adpctl_prb_dschg_shift (0) +#define adpctl_prb_dschg_mask (0x3) +#define adpctl_prb_delta_shift (2) +#define adpctl_prb_delta_mask (0x3) +#define adpctl_prb_per_shift (4) +#define adpctl_prb_per_mask (0x3) +#define adpctl_rtim_shift (6) +#define adpctl_rtim_mask (0x7ff) +#define adpctl_enaprb (1 << 17) +#define adpctl_enasns (1 << 18) +#define adpctl_adpres (1 << 19) +#define adpctl_adpen (1 << 20) +#define adpctl_adp_prb_int (1 << 21) +#define adpctl_adp_sns_int (1 << 22) +#define adpctl_adp_tmout_int (1 << 23) +#define adpctl_adp_prb_int_msk (1 << 24) +#define adpctl_adp_sns_int_msk (1 << 25) +#define adpctl_adp_tmout_int_msk (1 << 26) +#define adpctl_ar_shift (27) +#define adpctl_ar_mask (0x3) +#define adpctl_reserved29_31_shift (29) +#define adpctl_reserved29_31_mask (0x7) + +/* union dcfg_data */ +#define dcfg_devspd_shift (0) +#define dcfg_devspd_mask (0x3) +#define dcfg_nzstsouthshk (1 << 2) +#define DWC_DCFG_SEND_STALL 1 +#define dcfg_ena32khzs (1 << 3) +#define dcfg_devaddr_shift (4) +#define dcfg_devaddr_mask (0x7f) +#define dcfg_perfrint_shift (11) +#define dcfg_perfrint_mask (0x3) +#define DWC_DCFG_FRAME_INTERVAL_80 0 +#define DWC_DCFG_FRAME_INTERVAL_85 1 +#define DWC_DCFG_FRAME_INTERVAL_90 2 +#define DWC_DCFG_FRAME_INTERVAL_95 3 +#define dcfg_endevoutnak (1 << 13) +#define dcfg_reserved14_17_shift (14) +#define dcfg_reserved14_17_mask (0xf) +#define dcfg_epmscnt_shift (18) +#define dcfg_epmscnt_mask (0x1f) +#define dcfg_descdma (1 << 23) +#define dcfg_perschintvl_shift (24) +#define dcfg_perschintvl_mask (0x3) +#define dcfg_resvalid_shift (26) +#define dcfg_resvalid_mask (0x3f) + +/* union dctl_data */ +#define dctl_rmtwkupsig (1 << 0) +#define dctl_sftdiscon (1 << 1) +#define dctl_gnpinnaksts (1 << 2) +#define dctl_goutnaksts (1 << 3) +#define dctl_tstctl_shift (4) +#define dctl_tstctl_mask (0x7) +#define dctl_sgnpinnak (1 << 7) +#define dctl_cgnpinnak (1 << 8) +#define dctl_sgoutnak (1 << 9) +#define dctl_cgoutnak (1 << 10) +#define dctl_pwronprgdone (1 << 11) +#define dctl_reserved (1 << 12) +#define dctl_gmc_shift (13) +#define dctl_gmc_mask (0x3) +#define dctl_ifrmnum (1 << 15) +#define dctl_nakonbble (1 << 16) +#define dctl_encontonbna (1 << 17) +#define dctl_reserved18_31_shift (18) +#define dctl_reserved18_31_mask (0x3fff) + +/* union dsts_data */ +#define dsts_suspsts (1 << 0) +#define dsts_enumspd_shift (1) +#define dsts_enumspd_mask (0x3) +#define DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ 0 +#define DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ 1 +#define DWC_DSTS_ENUMSPD_LS_PHY_6MHZ 2 +#define DWC_DSTS_ENUMSPD_FS_PHY_48MHZ 3 +#define dsts_errticerr (1 << 3) +#define dsts_reserved4_7_shift (4) +#define dsts_reserved4_7_mask (0xf) +#define dsts_soffn_shift (8) +#define dsts_soffn_mask (0x3fff) +#define dsts_reserved22_31_shift (22) +#define dsts_reserved22_31_mask (0x3ff) + +/* union diepint_data */ +#define diepint_xfercompl (1 << 0) +#define diepint_epdisabled (1 << 1) +#define diepint_ahberr (1 << 2) +#define diepint_timeout (1 << 3) +#define diepint_intktxfemp (1 << 4) +#define diepint_intknepmis (1 << 5) +#define diepint_inepnakeff (1 << 6) +#define diepint_emptyintr (1 << 7) +#define diepint_txfifoundrn (1 << 8) +#define diepint_bna (1 << 9) +#define diepint_reserved10_12_shift (10) +#define diepint_reserved10_12_mask (0x7) +#define diepint_nak (1 << 13) +#define diepint_reserved14_31_shift (14) +#define diepint_reserved14_31_mask (0x3ffff) + +/* union doepint_data */ +#define doepint_xfercompl (1 << 0) +#define doepint_epdisabled (1 << 1) +#define doepint_ahberr (1 << 2) +#define doepint_setup (1 << 3) +#define doepint_outtknepdis (1 << 4) +#define doepint_stsphsercvd (1 << 5) +#define doepint_back2backsetup (1 << 6) +#define doepint_reserved7 (1 << 7) +#define doepint_outpkterr (1 << 8) +#define doepint_bna (1 << 9) +#define doepint_reserved10 (1 << 10) +#define doepint_pktdrpsts (1 << 11) +#define doepint_babble (1 << 12) +#define doepint_nak (1 << 13) +#define doepint_nyet (1 << 14) +#define doepint_sr (1 << 15) +#define doepint_reserved16_31_shift (16) +#define doepint_reserved16_31_mask (0xffff) + +/* union daint_data */ +#define daint_in_shift (0) +#define daint_in_mask (0xffff) +#define daint_out_shift (16) +#define daint_out_mask (0xffff) +#define daint_b_inep0 (1 << 0) +#define daint_b_inep1 (1 << 1) +#define daint_b_inep2 (1 << 2) +#define daint_b_inep3 (1 << 3) +#define daint_b_inep4 (1 << 4) +#define daint_b_inep5 (1 << 5) +#define daint_b_inep6 (1 << 6) +#define daint_b_inep7 (1 << 7) +#define daint_b_inep8 (1 << 8) +#define daint_b_inep9 (1 << 9) +#define daint_b_inep10 (1 << 10) +#define daint_b_inep11 (1 << 11) +#define daint_b_inep12 (1 << 12) +#define daint_b_inep13 (1 << 13) +#define daint_b_inep14 (1 << 14) +#define daint_b_inep15 (1 << 15) +#define daint_b_outep0 (1 << 16) +#define daint_b_outep1 (1 << 17) +#define daint_b_outep2 (1 << 18) +#define daint_b_outep3 (1 << 19) +#define daint_b_outep4 (1 << 20) +#define daint_b_outep5 (1 << 21) +#define daint_b_outep6 (1 << 22) +#define daint_b_outep7 (1 << 23) +#define daint_b_outep8 (1 << 24) +#define daint_b_outep9 (1 << 25) +#define daint_b_outep10 (1 << 26) +#define daint_b_outep11 (1 << 27) +#define daint_b_outep12 (1 << 28) +#define daint_b_outep13 (1 << 29) +#define daint_b_outep14 (1 << 30) +#define daint_b_outep15 (1 << 31) + +/* union dtknq1_data */ +#define dtknq1_intknwptr_shift (0) +#define dtknq1_intknwptr_mask (0x1f) +#define dtknq1_reserved05_06_shift (5) +#define dtknq1_reserved05_06_mask (0x3) +#define dtknq1_wrap_bit (1 << 7) +#define dtknq1_epnums0_5_shift (8) +#define dtknq1_epnums0_5_mask (0xffffff) + +/* union dthrctl_data */ +#define dthrctl_non_iso_thr_en (1 << 0) +#define dthrctl_iso_thr_en (1 << 1) +#define dthrctl_tx_thr_len_shift (2) +#define dthrctl_tx_thr_len_mask (0x1ff) +#define dthrctl_ahb_thr_ratio_shift (11) +#define dthrctl_ahb_thr_ratio_mask (0x3) +#define dthrctl_reserved13_15_shift (13) +#define dthrctl_reserved13_15_mask (0x7) +#define dthrctl_rx_thr_en (1 << 16) +#define dthrctl_rx_thr_len_shift (17) +#define dthrctl_rx_thr_len_mask (0x1ff) +#define dthrctl_reserved26 (1 << 26) +#define dthrctl_arbprken (1 << 27) +#define dthrctl_reserved28_31_shift (28) +#define dthrctl_reserved28_31_mask (0xf) + +/* union depctl_data */ +#define depctl_mps_shift (0) +#define depctl_mps_mask (0x7ff) +#define DWC_DEP0CTL_MPS_64 0 +#define DWC_DEP0CTL_MPS_32 1 +#define DWC_DEP0CTL_MPS_16 2 +#define DWC_DEP0CTL_MPS_8 3 +#define depctl_nextep_shift (11) +#define depctl_nextep_mask (0xf) +#define depctl_usbactep (1 << 15) +#define depctl_dpid (1 << 16) +#define depctl_naksts (1 << 17) +#define depctl_eptype_shift (18) +#define depctl_eptype_mask (0x3) +#define depctl_snp (1 << 20) +#define depctl_stall (1 << 21) +#define depctl_txfnum_shift (22) +#define depctl_txfnum_mask (0xf) +#define depctl_cnak (1 << 26) +#define depctl_snak (1 << 27) +#define depctl_setd0pid (1 << 28) +#define depctl_setd1pid (1 << 29) +#define depctl_epdis (1 << 30) +#define depctl_epena (1 << 31) + +/* union deptsiz_data */ +#define deptsiz_xfersize_shift (0) +#define deptsiz_xfersize_mask (0x7ffff) +#define MAX_PKT_CNT 1023 +#define deptsiz_pktcnt_shift (19) +#define deptsiz_pktcnt_mask (0x3ff) +#define deptsiz_mc_shift (29) +#define deptsiz_mc_mask (0x3) +#define deptsiz_reserved (1 << 31) + +/* union deptsiz0_data */ +#define deptsiz0_xfersize_shift (0) +#define deptsiz0_xfersize_mask (0x7f) +#define deptsiz0_reserved7_18_shift (7) +#define deptsiz0_reserved7_18_mask (0xfff) +#define deptsiz0_pktcnt_shift (19) +#define deptsiz0_pktcnt_mask (0x3) +#define deptsiz0_reserved21_28_shift (21) +#define deptsiz0_reserved21_28_mask (0xff) +#define deptsiz0_supcnt_shift (29) +#define deptsiz0_supcnt_mask (0x3) +#define deptsiz0_reserved31 (1 << 31) +#define BS_HOST_READY 0x0 +#define BS_DMA_BUSY 0x1 +#define BS_DMA_DONE 0x2 +#define BS_HOST_BUSY 0x3 +#define RTS_SUCCESS 0x0 +#define RTS_BUFFLUSH 0x1 +#define RTS_RESERVED 0x2 +#define RTS_BUFERR 0x3 + +/* union dev_dma_desc_sts */ +#define dev_dma_desc_sts_bytes_shift (0) +#define dev_dma_desc_sts_bytes_mask (0xffff) +#define dev_dma_desc_sts_nak (1 << 16) +#define dev_dma_desc_sts_reserved17_22_shift (17) +#define dev_dma_desc_sts_reserved17_22_mask (0x3f) +#define dev_dma_desc_sts_mtrf (1 << 23) +#define dev_dma_desc_sts_sr (1 << 24) +#define dev_dma_desc_sts_ioc (1 << 25) +#define dev_dma_desc_sts_sp (1 << 26) +#define dev_dma_desc_sts_l (1 << 27) +#define dev_dma_desc_sts_sts_shift (28) +#define dev_dma_desc_sts_sts_mask (0x3) +#define dev_dma_desc_sts_bs_shift (30) +#define dev_dma_desc_sts_bs_mask (0x3) +#define dev_dma_desc_sts_b_rxbytes_shift (0) +#define dev_dma_desc_sts_b_rxbytes_mask (0x7ff) +#define dev_dma_desc_sts_b_reserved11 (1 << 11) +#define dev_dma_desc_sts_b_framenum_shift (12) +#define dev_dma_desc_sts_b_framenum_mask (0x7ff) +#define dev_dma_desc_sts_b_pid_shift (23) +#define dev_dma_desc_sts_b_pid_mask (0x3) +#define dev_dma_desc_sts_b_ioc (1 << 25) +#define dev_dma_desc_sts_b_sp (1 << 26) +#define dev_dma_desc_sts_b_l (1 << 27) +#define dev_dma_desc_sts_b_rxsts_shift (28) +#define dev_dma_desc_sts_b_rxsts_mask (0x3) +#define dev_dma_desc_sts_b_bs_shift (30) +#define dev_dma_desc_sts_b_bs_mask (0x3) +#define dev_dma_desc_sts_b_b_txbytes_shift (0) +#define dev_dma_desc_sts_b_b_txbytes_mask (0xfff) +#define dev_dma_desc_sts_b_b_framenum_shift (12) +#define dev_dma_desc_sts_b_b_framenum_mask (0x7ff) +#define dev_dma_desc_sts_b_b_pid_shift (23) +#define dev_dma_desc_sts_b_b_pid_mask (0x3) +#define dev_dma_desc_sts_b_b_ioc (1 << 25) +#define dev_dma_desc_sts_b_b_sp (1 << 26) +#define dev_dma_desc_sts_b_b_l (1 << 27) +#define dev_dma_desc_sts_b_b_txsts_shift (28) +#define dev_dma_desc_sts_b_b_txsts_mask (0x3) +#define dev_dma_desc_sts_b_b_bs_shift (30) +#define dev_dma_desc_sts_b_b_bs_mask (0x3) +#define DWC_DEV_GLOBAL_REG_OFFSET 0x800 +#define DWC_DEV_IN_EP_REG_OFFSET 0x900 +#define DWC_EP_REG_OFFSET 0x20 +#define DWC_DEV_OUT_EP_REG_OFFSET 0xB00 + +/* union hcfg_data */ +#define hcfg_fslspclksel_shift (0) +#define hcfg_fslspclksel_mask (0x3) +#define DWC_HCFG_30_60_MHZ 0 +#define DWC_HCFG_48_MHZ 1 +#define DWC_HCFG_6_MHZ 2 +#define hcfg_fslssupp (1 << 2) +#define hcfg_reserved3_6_shift (3) +#define hcfg_reserved3_6_mask (0xf) +#define hcfg_ena32khzs (1 << 7) +#define hcfg_resvalid_shift (8) +#define hcfg_resvalid_mask (0xff) +#define hcfg_reserved16_22_shift (16) +#define hcfg_reserved16_22_mask (0x7f) +#define hcfg_descdma (1 << 23) +#define hcfg_frlisten_shift (24) +#define hcfg_frlisten_mask (0x3) +#define hcfg_perschedena (1 << 26) +#define hcfg_reserved27_30_shift (27) +#define hcfg_reserved27_30_mask (0xf) +#define hcfg_modechtimen (1 << 31) + +/* union hfir_data */ +#define hfir_frint_shift (0) +#define hfir_frint_mask (0xffff) +#define hfir_hfirrldctrl (1 << 16) +#define hfir_reserved_shift (17) +#define hfir_reserved_mask (0x7fff) + +/* union hfnum_data */ +#define hfnum_frnum_shift (0) +#define hfnum_frnum_mask (0xffff) +#define DWC_HFNUM_MAX_FRNUM 0x3FFF +#define hfnum_frrem_shift (16) +#define hfnum_frrem_mask (0xffff) + +/* union hptxsts_data */ +#define hptxsts_ptxfspcavail_shift (0) +#define hptxsts_ptxfspcavail_mask (0xffff) +#define hptxsts_ptxqspcavail_shift (16) +#define hptxsts_ptxqspcavail_mask (0xff) +#define hptxsts_ptxqtop_terminate (1 << 24) +#define hptxsts_ptxqtop_token_shift (25) +#define hptxsts_ptxqtop_token_mask (0x3) +#define hptxsts_ptxqtop_chnum_shift (27) +#define hptxsts_ptxqtop_chnum_mask (0xf) +#define hptxsts_ptxqtop_odd (1 << 31) + +/* union hprt0_data */ +#define hprt0_prtconnsts (1 << 0) +#define hprt0_prtconndet (1 << 1) +#define hprt0_prtena (1 << 2) +#define hprt0_prtenchng (1 << 3) +#define hprt0_prtovrcurract (1 << 4) +#define hprt0_prtovrcurrchng (1 << 5) +#define hprt0_prtres (1 << 6) +#define hprt0_prtsusp (1 << 7) +#define hprt0_prtrst (1 << 8) +#define hprt0_reserved9 (1 << 9) +#define hprt0_prtlnsts_shift (10) +#define hprt0_prtlnsts_mask (0x3) +#define hprt0_prtpwr (1 << 12) +#define hprt0_prttstctl_shift (13) +#define hprt0_prttstctl_mask (0xf) +#define hprt0_prtspd_shift (17) +#define hprt0_prtspd_mask (0x3) +#define DWC_HPRT0_PRTSPD_HIGH_SPEED 0 +#define DWC_HPRT0_PRTSPD_FULL_SPEED 1 +#define DWC_HPRT0_PRTSPD_LOW_SPEED 2 +#define hprt0_reserved19_31_shift (19) +#define hprt0_reserved19_31_mask (0x1fff) + +/* union haint_data */ +#define haint_ch0 (1 << 0) +#define haint_ch1 (1 << 1) +#define haint_ch2 (1 << 2) +#define haint_ch3 (1 << 3) +#define haint_ch4 (1 << 4) +#define haint_ch5 (1 << 5) +#define haint_ch6 (1 << 6) +#define haint_ch7 (1 << 7) +#define haint_ch8 (1 << 8) +#define haint_ch9 (1 << 9) +#define haint_ch10 (1 << 10) +#define haint_ch11 (1 << 11) +#define haint_ch12 (1 << 12) +#define haint_ch13 (1 << 13) +#define haint_ch14 (1 << 14) +#define haint_ch15 (1 << 15) +#define haint_reserved_shift (16) +#define haint_reserved_mask (0xffff) +#define haint_b_chint_shift (0) +#define haint_b_chint_mask (0xffff) +#define haint_b_reserved_shift (16) +#define haint_b_reserved_mask (0xffff) + +/* union haintmsk_data */ +#define haintmsk_ch0 (1 << 0) +#define haintmsk_ch1 (1 << 1) +#define haintmsk_ch2 (1 << 2) +#define haintmsk_ch3 (1 << 3) +#define haintmsk_ch4 (1 << 4) +#define haintmsk_ch5 (1 << 5) +#define haintmsk_ch6 (1 << 6) +#define haintmsk_ch7 (1 << 7) +#define haintmsk_ch8 (1 << 8) +#define haintmsk_ch9 (1 << 9) +#define haintmsk_ch10 (1 << 10) +#define haintmsk_ch11 (1 << 11) +#define haintmsk_ch12 (1 << 12) +#define haintmsk_ch13 (1 << 13) +#define haintmsk_ch14 (1 << 14) +#define haintmsk_ch15 (1 << 15) +#define haintmsk_reserved_shift (16) +#define haintmsk_reserved_mask (0xffff) +#define haintmsk_b_chint_shift (0) +#define haintmsk_b_chint_mask (0xffff) +#define haintmsk_b_reserved_shift (16) +#define haintmsk_b_reserved_mask (0xffff) + +/* union hcchar_data */ +#define hcchar_mps_shift (0) +#define hcchar_mps_mask (0x7ff) +#define hcchar_epnum_shift (11) +#define hcchar_epnum_mask (0xf) +#define hcchar_epdir (1 << 15) +#define hcchar_reserved (1 << 16) +#define hcchar_lspddev (1 << 17) +#define hcchar_eptype_shift (18) +#define hcchar_eptype_mask (0x3) +#define hcchar_multicnt_shift (20) +#define hcchar_multicnt_mask (0x3) +#define hcchar_devaddr_shift (22) +#define hcchar_devaddr_mask (0x7f) +#define hcchar_oddfrm (1 << 29) +#define hcchar_chdis (1 << 30) +#define hcchar_chen (1 << 31) + +/* union hcsplt_data */ +#define hcsplt_prtaddr_shift (0) +#define hcsplt_prtaddr_mask (0x7f) +#define hcsplt_hubaddr_shift (7) +#define hcsplt_hubaddr_mask (0x7f) +#define hcsplt_xactpos_shift (14) +#define hcsplt_xactpos_mask (0x3) +#define DWC_HCSPLIT_XACTPOS_MID 0 +#define DWC_HCSPLIT_XACTPOS_END 1 +#define DWC_HCSPLIT_XACTPOS_BEGIN 2 +#define DWC_HCSPLIT_XACTPOS_ALL 3 +#define hcsplt_compsplt (1 << 16) +#define hcsplt_reserved_shift (17) +#define hcsplt_reserved_mask (0x3fff) +#define hcsplt_spltena (1 << 31) + +/* union hcint_data */ +#define hcint_xfercomp (1 << 0) +#define hcint_chhltd (1 << 1) +#define hcint_ahberr (1 << 2) +#define hcint_stall (1 << 3) +#define hcint_nak (1 << 4) +#define hcint_ack (1 << 5) +#define hcint_nyet (1 << 6) +#define hcint_xacterr (1 << 7) +#define hcint_bblerr (1 << 8) +#define hcint_frmovrun (1 << 9) +#define hcint_datatglerr (1 << 10) +#define hcint_bna (1 << 11) +#define hcint_xcs_xact (1 << 12) +#define hcint_frm_list_roll (1 << 13) +#define hcint_reserved14_31_shift (14) +#define hcint_reserved14_31_mask (0x3ffff) + +/* union hcintmsk_data */ +#define hcintmsk_xfercompl (1 << 0) +#define hcintmsk_chhltd (1 << 1) +#define hcintmsk_ahberr (1 << 2) +#define hcintmsk_stall (1 << 3) +#define hcintmsk_nak (1 << 4) +#define hcintmsk_ack (1 << 5) +#define hcintmsk_nyet (1 << 6) +#define hcintmsk_xacterr (1 << 7) +#define hcintmsk_bblerr (1 << 8) +#define hcintmsk_frmovrun (1 << 9) +#define hcintmsk_datatglerr (1 << 10) +#define hcintmsk_bna (1 << 11) +#define hcintmsk_xcs_xact (1 << 12) +#define hcintmsk_frm_list_roll (1 << 13) +#define hcintmsk_reserved14_31_shift (14) +#define hcintmsk_reserved14_31_mask (0x3ffff) + +/* union hctsiz_data */ +#define hctsiz_xfersize_shift (0) +#define hctsiz_xfersize_mask (0x7ffff) +#define hctsiz_pktcnt_shift (19) +#define hctsiz_pktcnt_mask (0x3ff) +#define hctsiz_pid_shift (29) +#define hctsiz_pid_mask (0x3) +#define DWC_HCTSIZ_DATA0 0 +#define DWC_HCTSIZ_DATA1 2 +#define DWC_HCTSIZ_DATA2 1 +#define DWC_HCTSIZ_MDATA 3 +#define DWC_HCTSIZ_SETUP 3 +#define hctsiz_dopng (1 << 31) +#define hctsiz_b_schinfo_shift (0) +#define hctsiz_b_schinfo_mask (0xff) +#define hctsiz_b_ntd_shift (8) +#define hctsiz_b_ntd_mask (0xff) +#define hctsiz_b_reserved16_28_shift (16) +#define hctsiz_b_reserved16_28_mask (0x1fff) +#define hctsiz_b_pid_shift (29) +#define hctsiz_b_pid_mask (0x3) +#define hctsiz_b_dopng (1 << 31) + +/* union hcdma_data */ +#define hcdma_reserved0_2_shift (0) +#define hcdma_reserved0_2_mask (0x7) +#define hcdma_ctd_shift (3) +#define hcdma_ctd_mask (0xff) +#define hcdma_dma_addr_shift (11) +#define hcdma_dma_addr_mask (0x1fffff) + +/* union host_dma_desc_sts */ +#define host_dma_desc_sts_n_bytes_shift (0) +#define host_dma_desc_sts_n_bytes_mask (0x1ffff) +#define host_dma_desc_sts_qtd_offset_shift (17) +#define host_dma_desc_sts_qtd_offset_mask (0x3f) +#define host_dma_desc_sts_a_qtd (1 << 23) +#define host_dma_desc_sts_sup (1 << 24) +#define host_dma_desc_sts_ioc (1 << 25) +#define host_dma_desc_sts_eol (1 << 26) +#define host_dma_desc_sts_reserved27 (1 << 27) +#define host_dma_desc_sts_sts_shift (28) +#define host_dma_desc_sts_sts_mask (0x3) +#define DMA_DESC_STS_PKTERR 1 +#define host_dma_desc_sts_reserved30 (1 << 30) +#define host_dma_desc_sts_a (1 << 31) +#define host_dma_desc_sts_b_n_bytes_shift (0) +#define host_dma_desc_sts_b_n_bytes_mask (0xfff) +#define host_dma_desc_sts_b_reserved12_24_shift (12) +#define host_dma_desc_sts_b_reserved12_24_mask (0x1fff) +#define host_dma_desc_sts_b_ioc (1 << 25) +#define host_dma_desc_sts_b_reserved26_27_shift (26) +#define host_dma_desc_sts_b_reserved26_27_mask (0x3) +#define host_dma_desc_sts_b_sts_shift (28) +#define host_dma_desc_sts_b_sts_mask (0x3) +#define host_dma_desc_sts_b_reserved30 (1 << 30) +#define host_dma_desc_sts_b_a (1 << 31) +#define MAX_DMA_DESC_SIZE 131071 +#define MAX_DMA_DESC_NUM_GENERIC 64 +#define MAX_DMA_DESC_NUM_HS_ISOC 256 +#define MAX_FRLIST_EN_NUM 64 +#define DWC_OTG_HOST_GLOBAL_REG_OFFSET 0x400 +#define DWC_OTG_HOST_PORT_REGS_OFFSET 0x440 +#define DWC_OTG_HOST_CHAN_REGS_OFFSET 0x500 +#define DWC_OTG_CHAN_REGS_OFFSET 0x20 + +/* union pcgcctl_data */ +#define pcgcctl_stoppclk (1 << 0) +#define pcgcctl_gatehclk (1 << 1) +#define pcgcctl_pwrclmp (1 << 2) +#define pcgcctl_rstpdwnmodule (1 << 3) +#define pcgcctl_reserved (1 << 4) +#define pcgcctl_enbl_sleep_gating (1 << 5) +#define pcgcctl_phy_in_sleep (1 << 6) +#define pcgcctl_deep_sleep (1 << 7) +#define pcgcctl_resetaftsusp (1 << 8) +#define pcgcctl_restoremode (1 << 9) +#define pcgcctl_enbl_extnd_hiber (1 << 10) +#define pcgcctl_extnd_hiber_pwrclmp (1 << 11) +#define pcgcctl_extnd_hiber_switch (1 << 12) +#define pcgcctl_ess_reg_restored (1 << 13) +#define pcgcctl_prt_clk_sel_shift (14) +#define pcgcctl_prt_clk_sel_mask (0x3) +#define pcgcctl_port_power (1 << 16) +#define pcgcctl_max_xcvrselect_shift (17) +#define pcgcctl_max_xcvrselect_mask (0x3) +#define pcgcctl_max_termsel (1 << 19) +#define pcgcctl_mac_dev_addr_shift (20) +#define pcgcctl_mac_dev_addr_mask (0x7f) +#define pcgcctl_p2hd_dev_enum_spd_shift (27) +#define pcgcctl_p2hd_dev_enum_spd_mask (0x3) +#define pcgcctl_p2hd_prt_spd_shift (29) +#define pcgcctl_p2hd_prt_spd_mask (0x3) +#define pcgcctl_if_dev_mode (1 << 31) + +/* union gdfifocfg_data */ +#define gdfifocfg_gdfifocfg_shift (0) +#define gdfifocfg_gdfifocfg_mask (0xffff) +#define gdfifocfg_epinfobase_shift (16) +#define gdfifocfg_epinfobase_mask (0xffff) + +/* union gpwrdn_data */ +#define gpwrdn_pmuintsel (1 << 0) +#define gpwrdn_pmuactv (1 << 1) +#define gpwrdn_restore (1 << 2) +#define gpwrdn_pwrdnclmp (1 << 3) +#define gpwrdn_pwrdnrstn (1 << 4) +#define gpwrdn_pwrdnswtch (1 << 5) +#define gpwrdn_dis_vbus (1 << 6) +#define gpwrdn_lnstschng (1 << 7) +#define gpwrdn_lnstchng_msk (1 << 8) +#define gpwrdn_rst_det (1 << 9) +#define gpwrdn_rst_det_msk (1 << 10) +#define gpwrdn_disconn_det (1 << 11) +#define gpwrdn_disconn_det_msk (1 << 12) +#define gpwrdn_connect_det (1 << 13) +#define gpwrdn_connect_det_msk (1 << 14) +#define gpwrdn_srp_det (1 << 15) +#define gpwrdn_srp_det_msk (1 << 16) +#define gpwrdn_sts_chngint (1 << 17) +#define gpwrdn_sts_chngint_msk (1 << 18) +#define gpwrdn_linestate_shift (19) +#define gpwrdn_linestate_mask (0x3) +#define gpwrdn_idsts (1 << 21) +#define gpwrdn_bsessvld (1 << 22) +#define gpwrdn_adp_int (1 << 23) +#define gpwrdn_mult_val_id_bc_shift (24) +#define gpwrdn_mult_val_id_bc_mask (0x1f) +#define gpwrdn_reserved29_31_shift (29) +#define gpwrdn_reserved29_31_mask (0x7) + +#endif /* BCM2835_USB_REGS_H */ diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c index 85fc81bf43..3d97b5d489 100644 --- a/hw/usb/dev-network.c +++ b/hw/usb/dev-network.c @@ -1201,7 +1201,7 @@ static void usb_net_handle_dataout(USBNetState *s, USBPacket *p) s->out_ptr += sz; if (!is_rndis(s)) { - if (p->iov.size < 64) { + /*if (p->iov.size < 64)*/ { qemu_send_packet(qemu_get_queue(s->nic), s->out_buf, s->out_ptr); s->out_ptr = 0; } diff --git a/include/hw/arm/bcm2835.h b/include/hw/arm/bcm2835.h new file mode 100644 index 0000000000..9ea8ddd572 --- /dev/null +++ b/include/hw/arm/bcm2835.h @@ -0,0 +1,37 @@ +/* + * 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 + * + * Moved to Qemu root from Old Rasp + * John Bradley April 2017 + * + * This code is licensed under the GNU GPLv2 and later. + */ + +#ifndef BCM2835_H +#define BCM2835_H + +#include "hw/arm/arm.h" +#include "hw/arm/bcm2835_peripherals.h" +#include "hw/intc/bcm2835_control.h" + +#define TYPE_BCM2835 "bcm2835" +#define BCM2835(obj) OBJECT_CHECK(BCM2835State, (obj), TYPE_BCM2835) + +#define BCM2835_NCPUS 1 + +typedef struct BCM2835State { + /*< private >*/ + DeviceState parent_obj; + /*< public >*/ + + uint32_t enabled_cpus; + ARMCPU cpus[BCM2835_NCPUS]; + + BCM2835PeripheralState peripherals; +} BCM2835State; + +#endif /* BCM2835_H */ diff --git a/include/hw/arm/bcm2835_peripherals.h b/include/hw/arm/bcm2835_peripherals.h index 122b286de7..ef28b51066 100644 --- a/include/hw/arm/bcm2835_peripherals.h +++ b/include/hw/arm/bcm2835_peripherals.h @@ -18,12 +18,17 @@ #include "hw/display/bcm2835_fb.h" #include "hw/dma/bcm2835_dma.h" #include "hw/intc/bcm2835_ic.h" +#include "hw/misc/bcm2835_mphi.h" +#include "hw/misc/bcm2835_power.h" #include "hw/misc/bcm2835_property.h" #include "hw/misc/bcm2835_rng.h" #include "hw/misc/bcm2835_mbox.h" #include "hw/sd/sdhci.h" #include "hw/sd/bcm2835_sdhost.h" #include "hw/gpio/bcm2835_gpio.h" +#include "hw/timer/bcm2835_st.h" +#include "hw/timer/bcm2835_timer.h" +#include "hw/usb/bcm2835_usb.h" #define TYPE_BCM2835_PERIPHERALS "bcm2835-peripherals" #define BCM2835_PERIPHERALS(obj) \ @@ -43,10 +48,15 @@ typedef struct BCM2835PeripheralState { BCM2835FBState fb; BCM2835DMAState dma; BCM2835ICState ic; + BCM2835MphiState mphi; + BCM2835PowerState power; BCM2835PropertyState property; BCM2835RngState rng; BCM2835MboxState mboxes; SDHCIState sdhci; + BCM2835StState st; + BCM2835TimerState timer; + BCM2835UsbState usb; BCM2835SDHostState sdhost; BCM2835GpioState gpio; } BCM2835PeripheralState; diff --git a/include/hw/gpio/bcm2835_gpio.h b/include/hw/gpio/bcm2835_gpio.h index 9f8e0c720c..73cfda6a6b 100644 --- a/include/hw/gpio/bcm2835_gpio.h +++ b/include/hw/gpio/bcm2835_gpio.h @@ -16,6 +16,8 @@ #include "hw/sd/sd.h" +#include "qemu/PanelEmu.h" + typedef struct BCM2835GpioState { SysBusDevice parent_obj; @@ -30,6 +32,9 @@ typedef struct BCM2835GpioState { uint32_t lev0, lev1; uint8_t sd_fsel; qemu_irq out[54]; + + panel_connection_t panel; + } BCM2835GpioState; #define TYPE_BCM2835_GPIO "bcm2835_gpio" diff --git a/include/hw/intc/bcm2835_control.h b/include/hw/intc/bcm2835_control.h new file mode 100644 index 0000000000..6d09b03077 --- /dev/null +++ b/include/hw/intc/bcm2835_control.h @@ -0,0 +1,53 @@ +/* + * 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 + * + * Merge into QEMU root fork John Bradley April 2017 + * + * This code is licensed under the GNU GPLv2 and later. + */ + +#ifndef BCM2835_CONTROL_H +#define BCM2835_CONTROL_H + +#include "hw/sysbus.h" + +/* 4 mailboxes per core, for 16 total */ +#define BCM2835_NCORES 1 +#define BCM2835_MBPERCORE 4 + +#define TYPE_BCM2835_CONTROL "bcm2836-control" +#define BCM2835_CONTROL(obj) \ + OBJECT_CHECK(BCM2835ControlState, (obj), TYPE_BCM2835_CONTROL) + +typedef struct BCM2835ControlState { + /*< private >*/ + SysBusDevice busdev; + /*< public >*/ + MemoryRegion iomem; + + /* mailbox state */ + uint32_t mailboxes[BCM2835_NCORES * BCM2835_MBPERCORE]; + + /* interrupt routing/control registers */ + uint8_t route_gpu_irq, route_gpu_fiq; + uint32_t timercontrol[BCM2835_NCORES]; + uint32_t mailboxcontrol[BCM2835_NCORES]; + + /* interrupt status regs (derived from input pins; not visible to user) */ + bool gpu_irq, gpu_fiq; + uint8_t timerirqs[BCM2835_NCORES]; + + /* interrupt source registers, post-routing (also input-derived; visible) */ + uint32_t irqsrc[BCM2835_NCORES]; + uint32_t fiqsrc[BCM2835_NCORES]; + + /* outputs to CPU cores */ + qemu_irq irq[BCM2835_NCORES]; + qemu_irq fiq[BCM2835_NCORES]; +} BCM2835ControlState; + +#endif diff --git a/include/hw/intc/bcm2836_control.h b/include/hw/intc/bcm2836_control.h index 613f3c4186..768b4d4930 100644 --- a/include/hw/intc/bcm2836_control.h +++ b/include/hw/intc/bcm2836_control.h @@ -5,6 +5,8 @@ * Rasperry Pi 2 emulation and refactoring Copyright (c) 2015, Microsoft * Written by Andrew Baumann * + * Merge into QEMU root fork John Bradley April 2017 + * * This code is licensed under the GNU GPLv2 and later. */ diff --git a/include/hw/misc/bcm2835_mphi.h b/include/hw/misc/bcm2835_mphi.h new file mode 100644 index 0000000000..72824a9ff5 --- /dev/null +++ b/include/hw/misc/bcm2835_mphi.h @@ -0,0 +1,28 @@ +/* + * Raspberry Pi emulation (c) 2012 Gregory Estrade + * This code is licensed under the GNU GPLv2 and later. + */ + +#ifndef BCM2835_MPHI_H +#define BCM2835_MPHI_H + +#include "hw/sysbus.h" + +#define TYPE_BCM2835_MPHI "bcm2835-mphi" +#define BCM2835_MPHI(obj) \ + OBJECT_CHECK(BCM2835MphiState, (obj), TYPE_BCM2835_MPHI) + +typedef struct { + SysBusDevice busdev; + MemoryRegion iomem; + + uint32_t mphi_base; + uint32_t mphi_ctrl; + uint32_t mphi_outdda; + uint32_t mphi_outddb; + uint32_t mphi_intstat; + + qemu_irq irq; +} BCM2835MphiState; + +#endif diff --git a/include/hw/misc/bcm2835_power.h b/include/hw/misc/bcm2835_power.h new file mode 100644 index 0000000000..a19e7f4930 --- /dev/null +++ b/include/hw/misc/bcm2835_power.h @@ -0,0 +1,22 @@ +/* + * Raspberry Pi emulation (c) 2012 Gregory Estrade + * This code is licensed under the GNU GPLv2 and later. + */ + +#ifndef BCM2835_POWER_H +#define BCM2835_POWER_H + +#include "hw/sysbus.h" + +#define TYPE_BCM2835_POWER "bcm2835-power" +#define BCM2835_POWER(obj) \ + OBJECT_CHECK(BCM2835PowerState, (obj), TYPE_BCM2835_POWER) + +typedef struct { + SysBusDevice busdev; + MemoryRegion iomem; + int pending; + qemu_irq mbox_irq; +} BCM2835PowerState; + +#endif diff --git a/include/hw/timer/bcm2835_st.h b/include/hw/timer/bcm2835_st.h new file mode 100644 index 0000000000..11dc312711 --- /dev/null +++ b/include/hw/timer/bcm2835_st.h @@ -0,0 +1,25 @@ +/* + * Raspberry Pi emulation (c) 2012 Gregory Estrade + * This code is licensed under the GNU GPLv2 and later. + */ + +#ifndef BCM2835_ST_H +#define BCM2835_ST_H + +#include "hw/sysbus.h" +#include "qemu/timer.h" + +#define TYPE_BCM2835_ST "bcm2835_st" +#define BCM2835_ST(obj) OBJECT_CHECK(BCM2835StState, (obj), TYPE_BCM2835_ST) + +typedef struct BCM2835StState { + SysBusDevice busdev; + MemoryRegion iomem; + QEMUTimer *timer; + uint32_t compare[4]; + uint32_t match; + uint32_t next; + qemu_irq irq[4]; +} BCM2835StState; + +#endif diff --git a/include/hw/timer/bcm2835_timer.h b/include/hw/timer/bcm2835_timer.h new file mode 100644 index 0000000000..e2a0a76f01 --- /dev/null +++ b/include/hw/timer/bcm2835_timer.h @@ -0,0 +1,32 @@ +/* + * Raspberry Pi emulation (c) 2012 Gregory Estrade + * This code is licensed under the GNU GPLv2 and later. + */ + +#ifndef BCM2835_TIMER_H +#define BCM2835_TIMER_H + +#include "hw/sysbus.h" +#include "hw/ptimer.h" + +#define TYPE_BCM2835_TIMER "bcm2835_timer" +#define BCM2835_TIMER(obj) \ + OBJECT_CHECK(BCM2835TimerState, (obj), TYPE_BCM2835_TIMER) + +typedef struct { + SysBusDevice busdev; + MemoryRegion iomem; + + qemu_irq irq; + + uint32_t load; + uint32_t control; + uint32_t raw_irq; + uint32_t prediv; + uint32_t frc_value; + + ptimer_state *timer; + ptimer_state *frc_timer; +} BCM2835TimerState; + +#endif diff --git a/include/hw/usb/bcm2835_usb.h b/include/hw/usb/bcm2835_usb.h new file mode 100644 index 0000000000..246123123b --- /dev/null +++ b/include/hw/usb/bcm2835_usb.h @@ -0,0 +1,78 @@ +/* + * Raspberry Pi emulation (c) 2012 Gregory Estrade + * This code is licensed under the GNU GPLv2 and later. + */ + +#ifndef BCM2835_USB_H +#define BCM2835_USB_H + +#include "hw/sysbus.h" +#include "qemu/timer.h" + +#include "hw/usb.h" + +#define BCM2835_USB_HCHANS 8 + +#define TYPE_BCM2835_USB "bcm2835_usb" +#define BCM2835_USB(obj) \ + OBJECT_CHECK(BCM2835UsbState, (obj), TYPE_BCM2835_USB) + +//typedef struct BCM2835UsbState BCM2835UsbState; + +typedef struct { + struct BCM2835UsbState_ *parent; + int index; + + uint32_t hcchar; + uint32_t hcsplt; + uint32_t hcint; + uint32_t hcintmsk; + uint32_t hctsiz; + uint32_t hcdma; + uint32_t reserved; + uint32_t hcdmab; + + USBPacket packet; + uint8_t buffer[8192]; +} BCM2835UsbHcState; + +typedef struct BCM2835UsbState_ { + SysBusDevice busdev; + MemoryRegion iomem; + MemoryRegion *dma_mr; + AddressSpace dma_as; + + USBBus bus; + USBPort port; + int attached; + int reset_done; + QEMUTimer *sof_timer; + + uint32_t gusbcfg; + uint32_t hptxfsiz; + uint32_t hcfg; + uint32_t dcfg; + uint32_t grxfsiz; + uint32_t gnptxfsiz; + uint32_t dtxfsiz[15]; + uint32_t gahbcfg; + uint32_t grstctl; + uint32_t gotgctl; + uint32_t gotgint; + uint32_t gintsts; + uint32_t gintmsk; + uint32_t gdfifocfg; + uint32_t hprt0; + uint32_t haint; + uint32_t haintmsk; + uint32_t gnptxsts; + uint32_t hfnum; + uint32_t hptxsts; + uint32_t guid; + + BCM2835UsbHcState hchan[BCM2835_USB_HCHANS]; + + qemu_irq irq; +} BCM2835UsbState; + +#endif diff --git a/include/qemu/PanelEmu.h b/include/qemu/PanelEmu.h new file mode 100644 index 0000000000..b7a15e64e7 --- /dev/null +++ b/include/qemu/PanelEmu.h @@ -0,0 +1,53 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ + +/* + * File: PanelEmu.h + * Author: John Bradley + * + * Created on 22 April 2017, 22:26 + */ + +#ifndef PANELEMU_H +#define PANELEMU_H + +#ifdef __cplusplus +extern "C" { +#endif + + +#define DRIVER_NAME "RDC-GPIO: " +#define PANEL_NAME "GPIO panel: " + + +#define DEFAULT_PORT 0xb1ff //45567 + +#define PANEL_PINS 54 + + typedef struct panel_connection { + int socket; /* socket we'll connect to the panel with */ + fd_set fds; /* list of descriptors (only the above socket */ + char last[PANEL_PINS / 8]; /* we don't want to send updates to the panel + unless something changed */ + } panel_connection_t; + + int panel_open(panel_connection_t* h); + + bool panel_read(panel_connection_t* h, uint64_t *pinS); + void senddatatopanel(panel_connection_t* h, uint64_t pinS, bool Value); + void panel_send_read_command(panel_connection_t* h); + void sendpincount(panel_connection_t* h, int Num); + void sendenabledmap(panel_connection_t* h, uint64_t pins); + void sendinputmap(panel_connection_t* h, uint64_t pins); + void sendoutputmap(panel_connection_t* h, uint64_t pins); + + +#ifdef __cplusplus +} +#endif + +#endif /* PANELEMU_H */ + diff --git a/util/Makefile.objs b/util/Makefile.objs index c6205ebf86..8316ed79ba 100644 --- a/util/Makefile.objs +++ b/util/Makefile.objs @@ -43,3 +43,4 @@ util-obj-y += qdist.o util-obj-y += qht.o util-obj-y += range.o util-obj-y += systemd.o +util-obj-y += PanelEmu.o \ No newline at end of file diff --git a/util/PanelEmu.c b/util/PanelEmu.c new file mode 100644 index 0000000000..59c87d2747 --- /dev/null +++ b/util/PanelEmu.c @@ -0,0 +1,293 @@ +/* + * Emulation for Rasp PI GPIO via Server connected to via Socket + * + */ +#include "qemu/osdep.h" + +#include <stdio.h> +#include <stdlib.h> +#include <memory.h> +#include <errno.h> +#include <string.h> +#include <sys/types.h> +#ifdef __MINGW32__ +#include <winsock2.h> +#else +#include <sys/socket.h> +#include <arpa/inet.h> +#include <netinet/in.h> +#endif + + +#include "qemu/PanelEmu.h" + +typedef enum +{ + MACHINEDESC = 0, + PINSTOPANEL = 1, + READREQ = 2, + PINCOUNT = 3, + ENABLEMAP = 4, + INPUTMAP = 5, + OUTPUTMAP = 6, + PINSTOQEMU = 7 +} PacketType; + +#define MAXPACKET 255 + +#define PACKETLEN 0 //Includes Packet Length +#define PACKETTYPE 1 + +typedef struct +{ + unsigned short int Data[MAXPACKET]; +} CommandPacket; + +/* + * Hub connections + * + */ + +int panel_open(panel_connection_t* h) +{ + int rv; +#ifdef __MINGW32__ + struct sockaddr_in remote; +#else + struct sockaddr_in remote; +#endif + + int returnval = - 1; + +#ifdef __MINGW32__ + printf("__MINGW32__\n"); +#else + printf("NOT __MINGW32__\n"); +#endif + +#ifdef __MINGW32__ + WSADATA wsadata; + if (WSAStartup(MAKEWORD(1, 1), &wsadata) == SOCKET_ERROR) { + printf("Error creating socket.\n"); + } + else +#endif + { + if ((h->socket = socket(AF_INET, SOCK_STREAM, 0)) != - 1) { +#ifdef __MINGW32__ + memset((char *)&remote, 0, sizeof(remote)); + remote.sin_family = AF_INET; + remote.sin_port = htons(DEFAULT_PORT); + remote.sin_addr.s_addr = inet_addr("127.0.0.1"); +#else + bzero((char *)&remote, sizeof(remote)); + remote.sin_family = AF_INET; + remote.sin_port = htons(DEFAULT_PORT); + remote.sin_addr.s_addr = inet_addr("127.0.0.1"); +#endif + if ((rv=connect(h->socket, (struct sockaddr *) &remote, sizeof (remote))) != - 1) { +#ifdef __MINGW32__ + char value = 1; + setsockopt(h->socket, IPPROTO_TCP, TCP_NODELAY, &value, sizeof ( value)); + +#endif + FD_ZERO(&h->fds); + + /* Set our connected socket */ + FD_SET(h->socket, &h->fds); + + printf(PANEL_NAME "Connected OK %d\n",rv); + returnval = 0; + } else { + printf(PANEL_NAME "connection Failes %d\n",rv); +#ifdef __MINGW32__ + closesocket(h->socket); +#else + close(h->socket); +#endif + h->socket = - 1; + } + } + } + return returnval; +} + +static void panel_command(panel_connection_t *h, CommandPacket *Pkt) +{ + if (send(h->socket, (char *) Pkt, Pkt->Data[PACKETLEN], 0) == - 1) { + perror(PANEL_NAME "send"); +#ifdef __MINGW32__ + closesocket(h->socket); +#else + close(h->socket); +#endif + h->socket = - 1; /* act like we never connected */ + } +} + +/* Wait for values to be read back from panel */ +bool panel_read(panel_connection_t* h, uint64_t* Data) +{ + fd_set rfds, efds; + int LengthInBuffer; + int select_res = 0; + + CommandPacket *PktPtr = (CommandPacket *) malloc(sizeof (CommandPacket)); + CommandPacket *Pkt; + bool NoError = true; + bool NewData = false; + bool NoData = false; + struct timeval timeout; + + int ReadStart = 0; + + timeout.tv_sec = 0; + timeout.tv_usec = 0; + + if (h->socket != - 1) { + rfds = h->fds; + efds = h->fds; + +// printf(PANEL_NAME "panel_read\n"); + + Pkt = PktPtr; + while (NoError&&! NoData) { + select_res = select(h->socket + 1, &rfds, NULL, &efds, &timeout); + if (select_res > 0) { + if (FD_ISSET(h->socket, &rfds)) { + /* receive more data */ + if ((LengthInBuffer = recv(h->socket, (char *) &Pkt[ReadStart], sizeof (*Pkt) - ReadStart, 0)) > 0) { + LengthInBuffer += ReadStart; + for (int i = 0; LengthInBuffer > 0; i ++) { + if (LengthInBuffer >= Pkt->Data[i + PACKETLEN]) { + if (Pkt->Data[i + PACKETTYPE] == PINSTOQEMU) { + *Data = (uint64_t) Pkt->Data[i + 2]; + *Data |= ((uint64_t) Pkt->Data[i + 3]) << 16; + *Data |= ((uint64_t) Pkt->Data[i + 4]) << 32; + *Data |= ((uint64_t) Pkt->Data[i + 5]) << 48; + + NewData = true; + } else { + printf(PANEL_NAME "Invalid data received\n"); + } + LengthInBuffer -= Pkt->Data[PACKETLEN]; + i += Pkt->Data[PACKETLEN]; // Pkt=(CommandPacket *)&(Pkt->Data[Pkt->Data[PACKETLEN]]); + } else { + ReadStart = LengthInBuffer; + for (int j = 0; j < LengthInBuffer; j ++) { + Pkt->Data[j] = Pkt->Data[i + j]; + } + printf(PANEL_NAME "Partial Packet Read"); + } + } + } else { + if (LengthInBuffer < 0) { + if (errno != EINTR) { + printf(PANEL_NAME "recv"); + NoError = FALSE; + } + } else { + printf(PANEL_NAME "closed connection\n"); + NoError = FALSE; + } + } + } + } else if (select_res == 0) { + NoData = true; + } else if (errno != EINTR) { +#ifdef __MINGW32__ + closesocket(h->socket); +#else + close(h->socket); +#endif + h->socket = - 1; /* act like we never connected */ + perror(PANEL_NAME "select error"); + NoError = FALSE; + } + } + } + + free(PktPtr); + + return NewData; +} + +void panel_send_read_command(panel_connection_t* h) +{ + CommandPacket Pkt; + + Pkt.Data[PACKETLEN] = 4; + Pkt.Data[PACKETTYPE] = READREQ; + + panel_command(h, &Pkt); +} + +/* Set a pin to a specified value */ +void senddatatopanel(panel_connection_t* h, uint64_t pin, bool val) +{ + CommandPacket Pkt; + + Pkt.Data[PACKETLEN] = (char *) &Pkt.Data[6 + 1]-(char *) &Pkt.Data[0]; + Pkt.Data[PACKETTYPE] = PINSTOPANEL; + Pkt.Data[2] = (unsigned short int) (pin & 0xFFFF); + Pkt.Data[3] = (unsigned short int) ((pin >> 16)&0xFFFF); + Pkt.Data[4] = (unsigned short int) (pin >> 32 & 0xFFFF); + Pkt.Data[5] = (unsigned short int) ((pin >> 48)&0xFFFF); + Pkt.Data[6] = val; + + panel_command(h, &Pkt); +} + +void sendpincount(panel_connection_t* h, int val) +{ + CommandPacket Pkt; + + Pkt.Data[PACKETLEN] = (char *) &Pkt.Data[2 + 1]-(char *) &Pkt.Data[0]; + Pkt.Data[PACKETTYPE] = PINCOUNT; + Pkt.Data[2] = val; + + panel_command(h, &Pkt); +} + +void sendenabledmap(panel_connection_t* h, uint64_t pin) +{ + CommandPacket Pkt; + + Pkt.Data[PACKETLEN] = (char *) &Pkt.Data[5 + 1]-(char *) &Pkt.Data[0]; + Pkt.Data[PACKETTYPE] = ENABLEMAP; + Pkt.Data[2] = (unsigned short int) (pin & 0xFFFF); + Pkt.Data[3] = (unsigned short int) ((pin >> 16)&0xFFFF); + Pkt.Data[4] = (unsigned short int) (pin >> 32 & 0xFFFF); + Pkt.Data[5] = (unsigned short int) ((pin >> 48)&0xFFFF); + + panel_command(h, &Pkt); +} + +void sendinputmap(panel_connection_t* h, uint64_t pin) +{ + CommandPacket Pkt; + + Pkt.Data[PACKETLEN] = (char *) &Pkt.Data[5 + 1]-(char *) &Pkt.Data[0]; + Pkt.Data[PACKETTYPE] = INPUTMAP; + Pkt.Data[2] = (unsigned short int) (pin & 0xFFFF); + Pkt.Data[3] = (unsigned short int) ((pin >> 16)&0xFFFF); + Pkt.Data[4] = (unsigned short int) (pin >> 32 & 0xFFFF); + Pkt.Data[5] = (unsigned short int) ((pin >> 48)&0xFFFF); + + panel_command(h, &Pkt); +} + +void sendoutputmap(panel_connection_t* h, uint64_t pin) +{ + CommandPacket Pkt; + + Pkt.Data[PACKETLEN] = (char *) &Pkt.Data[5 + 1]-(char *) &Pkt.Data[0]; + Pkt.Data[PACKETTYPE] = OUTPUTMAP; + Pkt.Data[2] = (unsigned short int) (pin & 0xFFFF); + Pkt.Data[3] = (unsigned short int) ((pin >> 16)&0xFFFF); + Pkt.Data[4] = (unsigned short int) (pin >> 32 & 0xFFFF); + Pkt.Data[5] = (unsigned short int) ((pin >> 48)&0xFFFF); + + panel_command(h, &Pkt); +} + -- 2.13.0.windows.1