From patchwork Wed May 17 18:09:40 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Denis V. Lunev\" via" X-Patchwork-Id: 9731771 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id F24146022E for ; Wed, 17 May 2017 18:15:08 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D612C2863B for ; Wed, 17 May 2017 18:15:08 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id C5CC3287D0; Wed, 17 May 2017 18:15:08 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00,DKIM_SIGNED, FORGED_MUA_MOZILLA, FREEMAIL_REPLYTO_END_DIGIT, RCVD_IN_DNSWL_HI, T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 15C782863B for ; Wed, 17 May 2017 18:15:03 +0000 (UTC) Received: from localhost ([::1]:50246 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dB3TR-0000aL-SD for patchwork-qemu-devel@patchwork.kernel.org; Wed, 17 May 2017 14:15:01 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:57604) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dB3SL-0000UC-DP for qemu-devel@nongnu.org; Wed, 17 May 2017 14:14:01 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dB3SD-00043W-2d for qemu-devel@nongnu.org; Wed, 17 May 2017 14:13:53 -0400 Received: from sonic303-48.consmr.mail.ir2.yahoo.com ([77.238.178.229]:35319) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dB3SC-00043K-E2 for qemu-devel@nongnu.org; Wed, 17 May 2017 14:13:44 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rocketmail.com; s=s2048; t=1495044822; bh=H7q2iOPJYAMUCTCoIEuLcNq4AVXyy3I5lnoYNICczvI=; h=Date:From:Reply-To:To:Cc:Subject:References:From:Subject; b=kMUfGXHVcOfeyKuw2WlKeuYdFe5iK/J1NGz4JPHDFQT5ejnFHwHxxJfuFUfJbV+4OU7n2eTkBf8d0SgQeB3YKVVvHNXot6Sic1oAiWCdKlZrnUwPACi1OJXEYj6Saaz+M3TnHnrxEb9wS1K/2hyVO7BxfgoUm+M3WG9xPZLUov/Wwr1zyWenCKZcrT/DxseT12CZ53BusNk53uCqLgEPo8w6j94tZd90/ZTZhCSNvRhR7J5Um1zAPqvfg4qDx5+sx+1Aryh3UZOn7sAbGqVfgBjrnk8Tz0QFGT49FEesf1bMoCha7X2K4EmmyZO1H/mR3G/ZuP9bDVQyGMYN+L0dEw== X-YMail-OSG: UTBhFPAVM1mPdy5cnnEpmrRyseYRP1u33opTUK6XDszV6jNCxfN77ki5c23U.EG nP8bbyhdsLPJAPv2LbABUm3lsGj4nG6RVkxfnd1Zmla9PRGsN6w1iWr02GZe9e8ZOrrmEKOTtscs igCEnoNkXuvHOJhXEUQButdBS2aEPh4.3pvowmgP6qoHxGW4uniwjfo2VBJVDpZ66J80JgmmYqDp KuLafD8lvITCvjyNcVPi9kunwMeQPgo2Hl2C8m0n1YFw3dZLZUfp9nzWQuMqwuVRTNbcT58sGs5M i6gTKTyat6VsfIJfiST9ndhUBH0IfkmvY8qU4MdhiSKXnUCAG5iZJsMdx.qK36EXcpQl9sUE.XLj IpYjRNX_dnnkanHoHFynlOQC4R_VA.KaDtXAQbqcQKWKAZ7G.TLT0B5f2VIOrOOsryNRgS8vrU.J _ELnoj7xbRBDfQil881EgFb0jCeb7slVBp8zrD1nK5DjuL1e.Qa4_YcNqwfwQNFsk.KHdFkX.xFp zq7rJ9KtUvaTmzP8i0TrHOyU246hrStIDzg_BbrK1c5IRCNbmkUI90Ju1pHU- Received: from sonic.gate.mail.ne1.yahoo.com by sonic303.consmr.mail.ir2.yahoo.com with HTTP; Wed, 17 May 2017 18:13:42 +0000 Date: Wed, 17 May 2017 18:09:40 +0000 (UTC) To: "qemu-devel@nongnu.org" Message-ID: <684185116.2952708.1495044580181@mail.yahoo.com> MIME-Version: 1.0 References: <684185116.2952708.1495044580181.ref@mail.yahoo.com> X-Mailer: WebService/1.1.9552 YahooMailNeo Mozilla/5.0 (Windows NT 10.0; WOW64; rv:53.0) Gecko/20100101 Firefox/53.0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x [fuzzy] X-Received-From: 77.238.178.229 Subject: [Qemu-devel] Add Markus Armbrusters code for Broadcom Perhiperals for ARM. X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: John Bradley via Qemu-devel From: "Denis V. Lunev\" via" Reply-To: John Bradley Cc: John Bradley , Laurent Vivier , Peter Maydell , Geert Martin Ijewski , Markus Armbruster , Alistair Francis , "qemu-arm@nongnu.org" , =?UTF-8?Q?Philippe_Mathieu-Daud=C3=A9?= Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP Also available at https://www.dropbox.com/s/gwuquw0kirstw7a/0001-Add-Markus-Armbrusters-code-for-Broadcom-Perhiperals.patch?dl=0 Following suggestions split my original patch up. This the largest monolithic chunk is additional BCM device support from Markus Armbruster. From 0b39a04030d5a2cea4fcd2159d365580ca155b78 Mon Sep 17 00:00:00 2001 From: John Bradley Date: Wed, 17 May 2017 18:57:21 +0100 Subject: [PATCH] Add Markus Armbrusters code for Broadcom Perhiperals for ARM. Signed-off-by: John Bradley --- hw/arm/Makefile.objs | 2 +- hw/arm/bcm2835.c | 114 ++++ hw/arm/bcm2835_peripherals.c | 104 ++++ 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 ++++++++++++++++++++++++++++++++++ include/hw/arm/bcm2835.h | 37 ++ include/hw/arm/bcm2835_peripherals.h | 10 + include/hw/intc/bcm2835_control.h | 53 ++ 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 +++ 20 files changed, 2871 insertions(+), 2 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 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/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/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/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/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