+/*
+ * Copyright © 2018 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao_usb_gen.h"
+
+static uint32_t grxstsp;
+
+static inline uint8_t
+grxstsp_enum(void)
+{
+ return (grxstsp >> STM_USB_GRXSTSP_EPNUM) & STM_USB_GRXSTSP_EPNUM_MASK;
+}
+
+static inline uint8_t
+grxstsp_pktsts(void)
+{
+ return (grxstsp >> STM_USB_GRXSTSP_PKTSTS) & STM_USB_GRXSTSP_PKTSTS_MASK;
+}
+
+static inline uint16_t
+grxstsp_bcnt(void)
+{
+ return (grxstsp >> STM_USB_GRXSTSP_BCNT) & STM_USB_GRXSTSP_BCNT_MASK;
+}
+
+static void
+ao_usb_dev_ep_out_start(uint8_t ep)
+{
+ stm_usb.doep[ep].doeptsiz = ((1 << STM_USB_DOEPTSIZ_PKTCNT) |
+ (3 << STM_USB_DOEPTSIZ_STUPCNT) |
+ (24 << STM_USB_DOEPTSIZ_XFRSIZ));
+
+// stm_usb.doep[ep].doepctl |= (1 << STM_USB_DOEPCTL_EPENA);
+}
+
+static void
+ao_usb_mask_in_bits(vuint32_t *addr, uint32_t shift, uint32_t mask, uint32_t bits)
+{
+ uint32_t value;
+
+ value = *addr;
+ value &= ~(mask << shift);
+ value |= (bits << shift);
+ *addr = value;
+}
+
+static void
+ao_usb_activate_ep0(void)
+{
+ stm_usb.diep[0].diepctl = ((0 << STM_USB_DIEPCTL_TXFNUM) |
+ (0 << STM_USB_DIEPCTL_STALL) |
+ (STM_USB_DIEPCTL_EPTYP_CONTROL << STM_USB_DIEPCTL_EPTYP) |
+ (1 << STM_USB_DIEPCTL_USBAEP) |
+ (STM_USB_DIEPCTL_MPSIZ0_64 << STM_USB_DIEPCTL_MPSIZ));
+ stm_usb.doep[0].doepctl = ((0 << STM_USB_DOEPCTL_SNPM) |
+ (STM_USB_DOEPCTL_EPTYP_CONTROL << STM_USB_DOEPCTL_EPTYP) |
+ (1 << STM_USB_DOEPCTL_USBAEP) |
+ (STM_USB_DOEPCTL_MPSIZ0_64 << STM_USB_DOEPCTL_MPSIZ));
+}
+
+#if 0
+static void
+ao_usb_activate_in(int epnum)
+{
+ stm_usb.daintmsk |= (1 << (epnum + STM_USB_DAINTMSK_IEPM));
+ stm_usb.diep[epnum].diepctl = ((epnum << STM_USB_DIEPCTL_TXFNUM) |
+ (0 << STM_USB_DIEPCTL_STALL) |
+ (STM_USB_DIEPCTL_EPTYP_BULK << STM_USB_DIEPCTL_EPTYP) |
+ (1 << STM_USB_DIEPCTL_USBAEP) |
+ (64 << STM_USB_DIEPCTL_MPSIZ));
+}
+
+static void
+ao_usb_activate_out(int epnum)
+{
+ stm_usb.daintmsk |= (1 << (epnum + STM_USB_DAINTMSK_OEPM));
+ stm_usb.doep[epnum].doepctl = ((0 << STM_USB_DOEPCTL_SNPM) |
+ (STM_USB_DOEPCTL_EPTYP_BULK << STM_USB_DOEPCTL_EPTYP) |
+ (1 << STM_USB_DOEPCTL_USBAEP) |
+ (64 << STM_USB_DOEPCTL_MPSIZ));
+}
+#endif
+
+static void
+ao_usb_enum_done(void)
+{
+ /* Set turn-around delay. 6 is for high hclk (> 32MHz) */
+ ao_usb_mask_in_bits(&stm_usb.gusbcfg, STM_USB_GUSBCFG_TRDT, STM_USB_GUSBCFG_TRDT_MASK, 6);
+
+ ao_usb_activate_ep0();
+}
+
+static void
+ao_usb_flush_tx_fifo(uint32_t fifo)
+{
+ stm_usb.grstctl = ((1 << STM_USB_GRSTCTL_TXFFLSH) |
+ (fifo << STM_USB_GRSTCTL_TXFNUM));
+ while ((stm_usb.grstctl & (1 << STM_USB_GRSTCTL_TXFFLSH)) != 0)
+ ao_arch_nop();
+}
+
+static void
+ao_usb_flush_rx_fifo(void)
+{
+ stm_usb.grstctl = (1 << STM_USB_GRSTCTL_RXFFLSH);
+ while ((stm_usb.grstctl & (1 << STM_USB_GRSTCTL_RXFFLSH)) != 0)
+ ao_arch_nop();
+}
+
+/* reset and enable EP0 */
+void
+ao_usb_dev_ep0_init(void)
+{
+ uint32_t diepctl;
+
+ /* Flush TX fifo */
+ ao_usb_flush_tx_fifo(STM_USB_GRSTCTL_TXFNUM_ALL);
+
+ /* Clear interrupts */
+ for (int i = 0; i < 6; i++) {
+ stm_usb.diep[i].diepint = 0xfffffffful;
+ stm_usb.doep[i].doepint = 0xfffffffful;
+ }
+ stm_usb.daint = 0xfffffffful;
+
+ /* Enable EP0 in/out interrupts */
+ /* 2. Unmask interrupt bits */
+ stm_usb.daintmsk |= ((1 << (STM_USB_DAINTMSK_IEPM + 0)) |
+ (1 << (STM_USB_DAINTMSK_OEPM + 0)));
+
+ stm_usb.doepmsk |= ((1 << STM_USB_DOEPMSK_STUPM) |
+ (1 << STM_USB_DOEPMSK_EPDM) |
+ (1 << STM_USB_DOEPMSK_XFRCM));
+ stm_usb.diepmsk |= ((1 << STM_USB_DIEPMSK_TOM) |
+ (1 << STM_USB_DIEPMSK_XFRCM) |
+ (1 << STM_USB_DIEPMSK_EPDM));
+
+ /* 1. Set NAK bit for all OUT endpoints */
+ stm_usb.doep[0].doepctl |= (1 << STM_USB_DOEPCTL_CNAK);
+ for (int i = 1; i < 6; i++)
+ stm_usb.doep[i].doepctl |= (1 << STM_USB_DOEPCTL_SNAK);
+
+ /* 3. Setup FIFO ram allocation */
+
+ /* XXX make principled decisions here */
+ stm_usb.grxfsiz = 0x80;
+
+ stm_usb.dieptxf0 = ((0x40 << STM_USB_DIEPTXF0_TX0FD) | /* size = 256 bytes */
+ (0x80 << STM_USB_DIEPTXF0_TX0FSA)); /* start address = 0x80 */
+
+ /* 4. Program OUT endpoint 0 to receive a SETUP packet */
+
+ uint32_t doeptsiz;
+
+ doeptsiz = ((1 << STM_USB_DOEPTSIZ_PKTCNT) |
+ (0x40 << STM_USB_DOEPTSIZ_XFRSIZ) |
+ (1 << STM_USB_DOEPTSIZ_STUPCNT));
+
+ stm_usb.doep[0].doeptsiz = doeptsiz;
+
+ /* Program MPSIZ field to set maximum packet size */
+
+ diepctl = ((0 << STM_USB_DIEPCTL_EPENA ) |
+ (0 << STM_USB_DIEPCTL_EPDIS ) |
+ (0 << STM_USB_DIEPCTL_SNAK ) |
+ (0 << STM_USB_DIEPCTL_CNAK ) |
+ (0 << STM_USB_DIEPCTL_TXFNUM) |
+ (0 << STM_USB_DIEPCTL_STALL ) |
+ (STM_USB_DIEPCTL_EPTYP_CONTROL << STM_USB_DIEPCTL_EPTYP ) |
+ (0 << STM_USB_DIEPCTL_NAKSTS ) |
+ (0 << STM_USB_DIEPCTL_EONUM ) |
+ (1 << STM_USB_DIEPCTL_USBAEP ) |
+ (STM_USB_DIEPCTL_MPSIZ0_64 << STM_USB_DIEPCTL_MPSIZ));
+
+ stm_usb.diep[0].diepctl = diepctl;
+
+ uint32_t doepctl;
+
+ doepctl = ((0 << STM_USB_DOEPCTL_EPENA ) |
+ (0 << STM_USB_DOEPCTL_EPDIS ) |
+ (0 << STM_USB_DOEPCTL_SNAK ) |
+ (0 << STM_USB_DOEPCTL_CNAK ) |
+ (0 << STM_USB_DOEPCTL_STALL ) |
+ (0 << STM_USB_DOEPCTL_SNPM ) |
+ (STM_USB_DOEPCTL_EPTYP_CONTROL << STM_USB_DOEPCTL_EPTYP ) |
+ (0 << STM_USB_DOEPCTL_NAKSTS ) |
+ (1 << STM_USB_DOEPCTL_USBAEP ) |
+ (STM_USB_DOEPCTL_MPSIZ0_64 << STM_USB_DOEPCTL_MPSIZ));
+
+ stm_usb.doep[0].doepctl = doepctl;
+
+ /* Clear interrupts */
+ stm_usb.diep[0].diepint = 0xffffffff;
+ stm_usb.doep[0].doepint = 0xffffffff;
+
+ ao_usb_dev_ep_out_start(0);
+}
+
+void
+ao_usb_dev_ep0_in(const void *data, uint16_t len)
+{
+ return ao_usb_dev_ep_in(0, data, len);
+}
+
+bool
+ao_usb_dev_ep0_in_busy(void)
+{
+ return false;
+}
+
+uint16_t
+ao_usb_dev_ep0_out(void *data, uint16_t len)
+{
+ return ao_usb_dev_ep_out(0, data, len);
+}
+
+/* Queue IN bytes to EPn */
+void
+ao_usb_dev_ep_in(uint8_t ep, const void *data, uint16_t len)
+{
+ int l = len;
+
+ while (l > 0) {
+ stm_usb.dfifo[ep].fifo = *((__packed uint32_t *) data);
+ l -= 4;
+ data += 4;
+ }
+
+ /* Set the IN data size */
+ stm_usb.diep[ep].dieptsiz = ((1 << STM_USB_DIEPTSIZ_PKTCNT) |
+ (len << STM_USB_DIEPTSIZ_XFRSIZ));
+
+ /* Enable the TX empty interrupt */
+ stm_usb.diepempmsk |= (1 << ep);
+
+ /* Enable the endpoint to queue the packet for transmission */
+ stm_usb.diep[ep].diepctl |= (1 << STM_USB_DIEPCTL_EPENA);
+}
+
+bool
+ao_usb_dev_ep_in_busy(uint8_t ep)
+{
+ (void) ep;
+ return false;
+}
+
+/* Receive OUT bytes from EPn */
+uint16_t
+ao_usb_dev_ep_out(uint8_t ep, void *data, uint16_t len)
+{
+ uint16_t received;
+ int l = len;
+ uint32_t t;
+
+ if (grxstsp_enum() != ep)
+ return 0;
+
+ received = grxstsp_bcnt();
+ if (received > len)
+ received = len;
+
+ while (l >= 4) {
+ *((__packed uint32_t *) data) = stm_usb.dfifo[0].fifo;
+ l -= 4;
+ data += 4;
+ }
+
+ if (l != 0) {
+ t = stm_usb.dfifo[0].fifo;
+ memcpy(data, &t, l);
+ }
+
+ ao_usb_dev_ep_out_start(ep);
+ return received;
+}
+
+void
+ao_usb_dev_set_address(uint8_t address)
+{
+ uint32_t dcfg;
+
+ dcfg = stm_usb.dcfg;
+
+ dcfg &= ~(STM_USB_DCFG_DAD_MASK << STM_USB_DCFG_DAD);
+ dcfg |= address & STM_USB_DCFG_DAD_MASK;
+ stm_usb.dcfg = dcfg;
+}
+
+static void
+ao_usb_core_reset(void)
+{
+ /* Wait for AHB master IDLE state. */
+ while ((stm_usb.grstctl & (1 << STM_USB_GRSTCTL_AHBIDL)) == 0)
+ ao_arch_nop();
+
+
+ /* Core soft reset */
+ stm_usb.grstctl |= (1 << STM_USB_GRSTCTL_CSRST);
+
+ /* Wait for reset to complete */
+
+ while ((stm_usb.grstctl & (1 << STM_USB_GRSTCTL_CSRST)) != 0)
+ ao_arch_nop();
+}
+
+static void
+ao_usb_core_init(void)
+{
+ /* Enable embedded PHY */
+ stm_usb.gusbcfg |= (1 << STM_USB_GUSBCFG_PHYSEL);
+
+ /* Core reset */
+ ao_usb_core_reset();
+
+ /* Deactivate power down */
+ stm_usb.gccfg = (1 << STM_USB_GCCFG_PWRDWN);
+}
+
+static void
+ao_usb_delay(uint32_t ms)
+{
+ AO_TICK_TYPE now = ao_time();
+ AO_TICK_TYPE then = now + AO_MS_TO_TICKS(ms);
+
+ while ((int16_t) (then - ao_time()) > 0)
+ ao_arch_nop();
+}
+
+static void
+ao_usb_set_device_mode(void)
+{
+ uint32_t gusbcfg;
+
+ gusbcfg = stm_usb.gusbcfg;
+ gusbcfg &= ~((1 << STM_USB_GUSBCFG_FHMOD) |
+ (1 << STM_USB_GUSBCFG_FDMOD));
+ gusbcfg |= (1 << STM_USB_GUSBCFG_FDMOD);
+ stm_usb.gusbcfg = gusbcfg;
+ ao_usb_delay(50);
+}
+
+static void
+ao_usb_device_init(void)
+{
+ /* deactivate vbus sensing */
+ stm_usb.gccfg &= ~(1 << STM_USB_GCCFG_VBDEN);
+
+ /* Force device mode */
+ stm_usb.gotgctl |= ((1 << STM_USB_GOTGCTL_BVALOEN) |
+ (1 << STM_USB_GOTGCTL_BVALOVAL));
+
+ /* Restart the phy clock */
+ stm_usb.pcgcctl = 0;
+
+ /* Device mode configuration */
+ stm_usb.dcfg |= (STM_USB_DCFG_PFIVL_80 << STM_USB_DCFG_PFIVL);
+
+ /* Set full speed phy */
+ stm_usb.dcfg |= (STM_USB_DCFG_DSPD_FULL_SPEED << STM_USB_DCFG_DSPD);
+
+ /* Flush the fifos */
+ ao_usb_flush_tx_fifo(STM_USB_GRSTCTL_TXFNUM_ALL);
+ ao_usb_flush_rx_fifo();
+
+ /* Clear all pending device interrupts */
+ stm_usb.diepmsk = 0;
+ stm_usb.doepmsk = 0;
+ stm_usb.daint = 0xffffffffUL;
+ stm_usb.daintmsk = 0;
+
+ /* Reset all endpoints */
+ for (int i = 0; i < 6; i++) {
+
+ /* Reset IN endpoint */
+ if (stm_usb.diep[i].diepctl & (1 << STM_USB_DIEPCTL_EPENA))
+ stm_usb.diep[i].diepctl = ((1 << STM_USB_DIEPCTL_EPDIS) |
+ (1 << STM_USB_DIEPCTL_SNAK));
+ else
+ stm_usb.diep[i].diepctl = 0;
+ stm_usb.diep[i].dieptsiz = 0;
+ stm_usb.diep[i].diepint = 0xfffffffful;
+
+ /* Reset OUT endpoint */
+ if (stm_usb.doep[i].doepctl & (1 << STM_USB_DOEPCTL_EPENA))
+ stm_usb.doep[i].doepctl = ((1 << STM_USB_DOEPCTL_EPDIS) |
+ (1 << STM_USB_DOEPCTL_SNAK));
+ else
+ stm_usb.doep[i].doepctl = 0;
+
+ stm_usb.doep[i].doeptsiz = 0;
+ stm_usb.doep[i].doepint = 0xfffffffful;
+ }
+
+ /* Disable all interrupts */
+ stm_usb.gintmsk = 0;
+
+ /* Clear pending interrupts */
+ stm_usb.gintsts = 0xfffffffful;
+
+ /* Enable core interrupts */
+ stm_usb.gintmsk = ((1 << STM_USB_GINTMSK_WUIM ) |
+ (0 << STM_USB_GINTMSK_SRQIM ) |
+ (0 << STM_USB_GINTMSK_DISCINT ) |
+ (0 << STM_USB_GINTMSK_CIDSCHGM ) |
+ (0 << STM_USB_GINTMSK_LPMINTM ) |
+ (0 << STM_USB_GINTMSK_PTXFEM ) |
+ (0 << STM_USB_GINTMSK_HCIM) |
+ (0 << STM_USB_GINTMSK_PRTIM ) |
+ (0 << STM_USB_GINTMSK_RSTDETM ) |
+ (1 << STM_USB_GINTMSK_IISOOXFRM ) |
+ (1 << STM_USB_GINTMSK_IISOIXFRM ) |
+ (1 << STM_USB_GINTMSK_OEPINT) |
+ (1 << STM_USB_GINTMSK_IEPINT) |
+ (0 << STM_USB_GINTMSK_EOPFM ) |
+ (0 << STM_USB_GINTMSK_ISOODRPM ) |
+ (1 << STM_USB_GINTMSK_ENUMDNEM) |
+ (1 << STM_USB_GINTMSK_USBRST) |
+ (1 << STM_USB_GINTMSK_USBSUSPM ) |
+ (0 << STM_USB_GINTMSK_ESUSPM ) |
+ (0 << STM_USB_GINTMSK_GONAKEFFM ) |
+ (0 << STM_USB_GINTMSK_GINAKEFFM ) |
+ (0 << STM_USB_GINTMSK_NPTXFEM ) |
+ (0 << STM_USB_GINTMSK_RXFLVLM) |
+ (0 << STM_USB_GINTMSK_SOFM ) |
+ (0 << STM_USB_GINTMSK_OTGINT ) |
+ (0 << STM_USB_GINTMSK_MMISM));
+}
+
+static void
+ao_usb_device_connect(void)
+{
+ /* Enable pull-up/pull-down */
+ stm_usb.dctl &= ~(1 << STM_USB_DCTL_SDIS);
+ ao_usb_delay(20);
+}
+
+#if 0
+static void
+ao_usb_device_disconnect(void)
+{
+ /* Disable pull-up/pull-down */
+ stm_usb.dctl |= (1 << STM_USB_DCTL_SDIS);
+ ao_usb_delay(20);
+}
+#endif
+
+void
+ao_usb_dev_enable(void)
+{
+ ao_arch_block_interrupts();
+
+ /* Configure GPIOs */
+ ao_enable_port(&stm_gpioa);
+#if 0
+ stm_afr_set(&stm_gpioa, 8, STM_AFR_AF10); /* USB_FS_SOF */
+ stm_afr_set(&stm_gpioa, 9, STM_AFR_AF10); /* USB_FS_VBUS */
+ stm_afr_set(&stm_gpioa, 10, STM_AFR_AF10); /* USB_FS_ID */
+#endif
+ stm_afr_set(&stm_gpioa, 11, STM_AFR_AF10);
+ stm_ospeedr_set(&stm_gpioa, 11, STM_OSPEEDR_HIGH);
+ stm_pupdr_set(&stm_gpioa, 11, STM_PUPDR_NONE);
+ stm_afr_set(&stm_gpioa, 12, STM_AFR_AF10);
+ stm_ospeedr_set(&stm_gpioa, 12, STM_OSPEEDR_HIGH);
+ stm_pupdr_set(&stm_gpioa, 12, STM_PUPDR_NONE);
+
+ /* Power on USB */
+ stm_rcc.ahb2enr |= (1 << STM_RCC_AHB2ENR_OTGFSEN);
+
+ /* Route interrupts */
+ stm_nvic_set_priority(STM_ISR_OTG_FS_POS, AO_STM_NVIC_LOW_PRIORITY);
+ stm_nvic_set_enable(STM_ISR_OTG_FS_POS);
+
+ /* Core init */
+ ao_usb_core_init();
+
+ /* Set device mode */
+ ao_usb_set_device_mode();
+
+ /* Reset FIFO allocations */
+ for (int i = 1; i < 16; i++)
+ stm_usb.dieptxf[i-1] = 0x0;
+
+ ao_usb_device_init();
+
+ /* Connect */
+ ao_usb_device_connect();
+}
+
+void
+ao_usb_dev_disable(void)
+{
+ stm_usb.gusbcfg = ((1 << STM_USB_GUSBCFG_FDMOD) |
+ (0 << STM_USB_GUSBCFG_FHMOD) |
+ (6 << STM_USB_GUSBCFG_TRDT) |
+ (0 << STM_USB_GUSBCFG_HNPCAP) |
+ (0 << STM_USB_GUSBCFG_SRPCAP) |
+ (1 << STM_USB_GUSBCFG_PHYSEL) |
+ (0 << STM_USB_GUSBCFG_TOCAL));
+
+ stm_usb.gahbcfg = ((0 << STM_USB_GAHBCFG_PTXFELVL) |
+ (1 << STM_USB_GAHBCFG_TXFELVL) |
+ (0 << STM_USB_GAHBCFG_GINTMSK));
+
+ stm_usb.dctl = ((0 << STM_USB_DCTL_POPRGDNE) |
+ (1 << STM_USB_DCTL_SDIS));
+
+ stm_rcc.ahb2enr &= ~(1 << STM_RCC_AHB2ENR_OTGFSEN);
+}
+
+void
+stm_otg_fs_isr(void)
+{
+ uint32_t gintsts = stm_usb.gintsts;
+ uint8_t ep0_receive = 0;
+ uint32_t out_interrupt = 0;
+ uint32_t in_interrupt = 0;
+
+ /* Clear all received interrupts */
+ stm_usb.gintsts = gintsts;
+
+ if (gintsts & (1 << STM_USB_GINTSTS_USBRST)) {
+ ep0_receive |= AO_USB_EP0_GOT_RESET;
+ }
+
+ if (gintsts & (1 << STM_USB_GINTSTS_ENUMDNE)) {
+ ao_usb_enum_done();
+ }
+
+ if (gintsts & ((1 << STM_USB_GINTSTS_OEPINT) |
+ (1 << STM_USB_GINTSTS_IEPINT)))
+ {
+ uint32_t daint = stm_usb.daint;
+ uint32_t oepint = (daint >> STM_USB_DAINT_OEPINT) & STM_USB_DAINT_OEPINT_MASK;
+ uint32_t iepint = (daint >> STM_USB_DAINT_IEPINT) & STM_USB_DAINT_IEPINT_MASK;
+
+ for (int ep = 0; ep < 6; ep++) {
+ if (gintsts & (1 << STM_USB_GINTSTS_OEPINT)) {
+ if (oepint & (1 << ep)) {
+ uint32_t doepint = stm_usb.doep[ep].doepint;
+
+ stm_usb.doep[ep].doepint = doepint;
+ if (doepint & (1 << STM_USB_DOEPINT_XFRC)) {
+ if (ep == 0)
+ ep0_receive |= AO_USB_EP0_GOT_SETUP;
+ else
+ out_interrupt |= (1 << ep);
+ }
+ grxstsp = stm_usb.grxstsp;
+ }
+ }
+
+ if (gintsts & (1 << STM_USB_GINTSTS_IEPINT)) {
+ if (iepint & (1 << ep)) {
+ uint32_t diepint = stm_usb.diep[ep].diepint;
+
+ stm_usb.diep[ep].diepint = diepint;
+ if (diepint & (1 << STM_USB_DIEPINT_XFRC)) {
+ if (ep == 0)
+ ep0_receive |= AO_USB_EP0_GOT_TX_ACK;
+ else
+ in_interrupt |= (1 << ep);
+ }
+ }
+ }
+ }
+ } else {
+ grxstsp = 0;
+ }
+
+ if (ep0_receive)
+ ao_usb_ep0_interrupt(ep0_receive);
+
+ if (out_interrupt)
+ ao_usb_out_interrupt(out_interrupt);
+
+ if (in_interrupt)
+ ao_usb_in_interrupt(in_interrupt);
+}
+
+/*
+
+ running before plugging in at first packet
+ gotgctl = 0x04cd0000, 0x04c10000, 0x04cd0000 *************
+
+ CURMOD = 0
+ OTGVER = 0
+ BSVLD = 1 BSVLD = 0
+ ASVLD = 1 ASVLD = 0
+ DBCT = 0
+ CIDSTS = 1
+
+ gotgint = 0x00100000, 0x00100000, 0x00100000
+
+ IDCHNG = 1
+
+ gahbcfg = 0x1, 0x1, 0x00000001
+
+ TXFELVL = 0 trigger half empty
+ GINTMSK = 1 interrupts enabled
+
+ gusbcfg = 0x40001840, 0x40001440 0x40001840 *************
+
+ FDMOD = 1 force device mode
+ FHMOD = 0
+ TRDT = 6 5 6
+ HNPCAP = 0
+ SRPCAP = 0
+ PHYSEL = 1
+ TOCAL = 0
+
+ grstctl = 0x80000040, 0x80000000 0x80000400 ***********
+
+ AHBIDL = 1
+ TXFNUM = 1 TXFNUM = 0 TXFNUM = 0x20 (flush all)
+ TXFFLSH = 0
+ RXFFLSH = 0
+ FCRST = 0
+ PSRST = 0
+ CSRST = 0
+
+ gintsts = 0x0480b43a, 0x04008022 0x04888438 ***********
+
+ WKUPINT = 0 0
+ SRQINT = 0 0
+ DISCINT = 0 0
+ CIDSCHG = 0 0
+ LPMINT = 0 0
+ PTXFE = 1 PTXFE = 1 PTXFE = 1
+ HCINT = 0
+ HPRTINT = 0
+ RSTDET = 1 RSTDET = 0 RSTDET = 1
+ IPXFER = 0
+ IISOIXFR = 0
+ OEPINT = 0 OEPINT = 1
+ IEPINT = 0
+ EOPF = 1 EOPF = 1 EOPF = 1
+ ISOODRP = 0
+ ENUMDNE = 1
+ USBRST = 1
+ USBSUSP = 0
+ ESUSP = 1 ESUSP = 1
+ GONAKEFF = 0
+ GINAKEFF = 0
+ NPTXFE = 1 NPTXFE = 1 NPTXFE = 1
+ RXFLVL = 1 RXFLVL = 1
+ SOF = 1 SOF = 1
+ OTGINT = 0
+ MMIS = 1 MMIS = 1 MMIS = 0
+ CMOD = 0
+
+ gintmsk = 0xc03c3814, 0xc03c3814,
+
+ WUIM = 1
+ SRQIM = 1
+ DISCINT = 0
+ CIDSCHGM = 0
+ LPMINTM = 0
+ PTXFEM = 0
+ HCIM = 0
+ PRTIM = 0
+ RSTDETM = 0
+ IISOOXFRM = 1
+ IISOIXFRM = 1
+ OEPINT = 1
+ IEPINT = 1
+ EOPFM = 0
+ ISOODRPM = 0
+ ENUMDNEM = 1
+ USBRST = 1
+ USBSUSPM = 1
+ ESUSPM =0
+ GONAKEFFM = 0
+ GINAKEFFM = 0
+ NPTXFEM = 0
+ RXFLVLM = 1
+ SOFM = 0
+ OTGINT = 1
+ MMISM = 0
+
+ grxstsr = 0xac0080, 0x0 0x14c0080 ***************
+
+ STSPHST = 0 STSPHST = 0
+ FRMNUM = 5 FRMNUM = 10
+ PKTSTS = 6 -- SETUP data packet PKTSTS = 6 -- SETUP data packet
+ DPID = 0 DPID = 0
+ BCNT = 8 BCNT = 8
+ EPNUM = 0 EPNUM = 0
+
+ grxstsp = 0xac0080, 0x0 0x14c0080
+
+ (same)
+
+ grxfsiz = 0x80, 0x80 0x80
+
+ RXFD = 128 512 bytes
+
+ dieptxf0 = 0x00400080, 0x00400080 0x00400080
+
+ TX0FD = 64 256 bytes
+ TX0FSA = 0x80
+
+ gccfg = 0x21fff0, 0x21fff0 0x21fff0
+
+ VBDEN = 1
+ SDEN = 0
+ PDEN = 0
+ DCDEN = 0
+ BCDEN = 0
+ PWRDN = 1
+ PS2DET = 0
+ SDET = 0
+ PDET = 0
+ DCDET = 0
+
+ cid = 0x2000, 0x2000 0x2000
+
+ PRODUCT_ID = 0x2000
+
+ glpmcfg = 0x0, 0x0 0x0
+
+ ENBESL = 0
+ LPMRCNTTST = 0
+ SNDLPM = 0
+ LPMRCNT = 0
+ LPMCHIDX = 0
+ L1RSMOK = 0
+ SLPSTS = 0
+ LPMRSP = 0
+ L1DSEN = 0
+ BESLTHRS = 0
+ L1SSEN = 0
+ REMWAKE = 0
+ BESL = 0
+ LPMACK = 0
+ LPMEN = 0
+
+ dieptxf = {0x8000c0, 0x0, 0x0, 0x0, 0x0}, {0x8000c0, 0x0, 0x0, 0x0, 0x0}, {0x8000c0, 0x0, 0x0, 0x0, 0x0},
+
+ INEXPTXFD 0 = 0x80 512 bytes
+ INEXPTXSA 0 = 0xc0
+
+ dcfg = 0x82000b3, 0x8200003, 0x8200003
+
+ ERRATIM = 0
+ PFIVL = 0
+ DAD = 0xb DAD = 0x0 DAD = 0
+ NZLSOHSK = 0
+ DSPD = 3 Full speed USB 1.1
+
+ dctl = 0x0, 0x0 0x0
+
+ DSBESLRJCT = 0
+ POPRGDNE = 0
+ CGONAK = 0
+ SGONAK = 0
+ CGINAK = 0
+ SGINAK = 0
+ TCTL = 0
+ GONSTS = 0
+ GINSTS = 0
+ SDIS = 0
+ RWUSIG = 0
+
+ dsts = 0x0043ff06, 0x00000006 0x00400c06
+
+ DEVLNSTS = 1 (D+ low, D- high)
+ FNSOF = 0x3ff FNSOF = 0xc
+ EERR = 0
+ ENUMSPD = 3 Full speed ENUMSPD = 3
+ SUSPSTS = 0 SUSPSTS = 0
+
+ diepmsk = 0xb, 0x0 0xb
+
+ NAKM = 0
+ TXFURM = 0
+ INEPNEM = 0
+ INEPNMM = 0
+ ITTXFEMSK = 0
+ TOM = 1
+ EPDM = 1
+ XFRCM = 1
+
+ doepmsk = 0x2b, 0x0 0x2b
+
+ NYETMSK = 0
+ NAKMSK = 0
+ BERRM =0
+ OUTPKTERRM = 0
+ STSPHSRXM = 1
+ OTEPDM = 0
+ STUPM = 1
+ EPDM = 1
+ XFRCM = 1
+
+ daint = 0x0, 0x0 0x10000
+
+ daintmsk = 0x30003, 0x0 0x10001
+
+ OEPM = 0x3 endpoints 0 and 1 OEPM = 0x1 endpoint 0
+ IEPM = 0x3 endpoints 0 and 1 IEPM = 0x1 endpoint 0
+
+ dvbusdis = 0x17d7, 0x17d7 0x17d7
+
+ VBUSDT = 0x17d7 reset value
+
+ dvbuspulse = 0x5b8, 0x5b8 0x5b8
+
+ DVBUSP = 0x5b8 reset value
+
+ diepempmsk = 0x0, 0x0 0x0
+
+ INEPTXFEM = 0 no endpoints
+
+ diep = {{
+ diepctl = 0x28000,
+
+ EPENA = 0
+ EPDIS = 0
+ SNAK = 0
+ CNAK = 0
+ TXFNUM = 0
+ STALL = 0
+ EPTYP = 0
+ NAKSTS = 1
+ USBAEP = 1
+ MPSIZ = 0 64 bytes
+
+ diepint = 0x20c0,
+
+ NAK = 1
+ PKTDRPSTS = 0
+ TXFIFOUDRN = 0
+ TXFE = 1
+ INEPNE = 1
+ ITTXFE = 0
+ TOC = 0
+ EPDISD = 0
+ XFRC = 0
+
+ dieptsiz = 0x0,
+
+ PKTCNT = 0
+ XFRSIZ = 0
+
+ dtxfsts = 0x40,
+
+ INEPTFSAV = 0x40 256 bytes available
+
+ }, {
+ diepctl = 0x00490040,
+
+ EPENA = 0
+ EPDIS = 0
+ SODDFRM = 0
+ SD0PID = 0
+ SNAK = 0
+ CNAK = 0
+ TXFNUM = 1
+ STALL = 0
+ EPTYP = 2 bulk
+ NAKSTS = 0
+ EONUM = 1
+ USBAEP = 0
+ MPSIZ = 64 256 bytes
+
+ diepint = 0x2090,
+
+ NAK = 1
+ PKTDRPSTS = 0
+ TXFIFOUDRN = 0
+ TXFE = 1
+ INEPNE = 0
+ INPENM = 0
+ ITTXFE = 1
+ TOC = 0
+ EPDISD = 0
+ XFRC = 0
+
+ dieptsiz = 0x0,
+
+ MCNT = 0
+ PKTCNT = 0
+ XFRSIZ = 0
+
+ dtxfsts = 0x80,
+
+ INEPTFSAV = 0x80 512 bytes available
+
+ }, {
+ diepctl = 0x0,
+ pad_04 = 0x0,
+ diepint = 0x80,
+ pad_0c = 0x0,
+ dieptsiz = 0x0,
+ pad_14 = 0x43425355,
+ dtxfsts = 0x40,
+ pad_1c = 0x400000
+ }, {
+ diepctl = 0x0,
+ pad_04 = 0x0,
+ diepint = 0x80,
+ pad_0c = 0x0,
+ dieptsiz = 0x0,
+ pad_14 = 0x43425355,
+ dtxfsts = 0x40,
+ pad_1c = 0x400000
+ }, {
+ diepctl = 0x0,
+ pad_04 = 0x0,
+ diepint = 0x80,
+ pad_0c = 0x0,
+ dieptsiz = 0x0,
+ pad_14 = 0x43425355,
+ dtxfsts = 0x40,
+ pad_1c = 0x400000
+ }, {
+ diepctl = 0x0,
+ pad_04 = 0x0,
+ diepint = 0x80,
+ pad_0c = 0x0,
+ dieptsiz = 0x0,
+ pad_14 = 0x43425355,
+ dtxfsts = 0x40,
+ pad_1c = 0x400000
+ }},
+
+ doep = {{
+ doepctl = 0x80028000, 0x00008000, 0x28000
+
+ EPENA = 1 EPENA = 0 EPENA = 0
+ EPDIS = 0
+ SNAK =0
+ CNAK = 0
+ STALL = 0
+ SNPM = 0
+ EPTYP = 0
+ NAKSTS = 1 NAKSTS = 0 NAKSTS = 1
+ USPAEP = 1 USPAEP = 1
+ MPSIZ = 0 64 bytes MPSIZ = 0
+
+ doepint = 0x8010, 0x0 0x8008
+
+ NYET = 0
+ NAK = 0
+ BERR = 0
+ OUTPKTERR = 0
+ STSPHSRX = 0
+ OTEPDIS = 1
+ STUP = 0 STUP = 1
+ EPDISD = 0
+ XFRC = 0
+
+ doeptsiz = 0x38, 0x0 0x20080008
+
+ STPCNT = 0 1 packet STPCNT = 1
+ PKTCNT = 0 PKTCNT = 1
+ XFRSIZ = 0x38 56 bytes (64 - 8) XFRSIZ = 8
+
+ }, {
+ doepctl = 0x800b0040,
+
+ EPENA = 1
+ EPDIS = 0
+ SD1PID = 0
+ SD0PID = 0
+ SNAK = 0
+ CNAK = 0
+ STALL = 0
+ SNPM =0
+ EPTYP = 2 Bulk
+ NAKSTS = 1
+ EONUM = 1
+ USBAEP = 0
+ MPSIZ = 0x40 64 bytes
+
+ doepint = 0x0,
+ doeptsiz = 0x21,
+
+ RXDPID = 0
+ PKTCNT = 0
+ XFRSIZ = 0x21 33 bytes ?
+
+ }, {
+ doepctl = 0x0,
+ pad_04 = 0x0,
+ doepint = 0x0,
+ pad_0c = 0x0,
+ doeptsiz = 0x0,
+ pad_14 = 0x43425355,
+ pad_18 = 0x40,
+ pad_1c = 0x400000
+ }, {
+ doepctl = 0x0,
+ pad_04 = 0x0,
+ doepint = 0x0,
+ pad_0c = 0x0,
+ doeptsiz = 0x0,
+ pad_14 = 0x43425355,
+ pad_18 = 0x40,
+ pad_1c = 0x400000
+ }, {
+ doepctl = 0x0,
+ pad_04 = 0x0,
+ doepint = 0x0,
+ pad_0c = 0x0,
+ doeptsiz = 0x0,
+ pad_14 = 0x43425355,
+ pad_18 = 0x40,
+ pad_1c = 0x400000
+ }, {
+ doepctl = 0x0,
+ pad_04 = 0x0,
+ doepint = 0x0,
+ pad_0c = 0x0,
+ doeptsiz = 0x0,
+ pad_14 = 0x43425355,
+ pad_18 = 0x40,
+ pad_1c = 0x400000
+ }},
+
+ pcgcctl = 0x0, 0x0, 0x0
+
+ SUSP = 0
+ PHYSLEEP = 0
+ ENL1GTG = 0
+ PHYSUSP = 0
+ GATEHCLK = 0
+ STPPCLK = 0
+
+ dfifo = {{
+ fifo = 0x1000680,
+
+
+ Clock configuration:
+
+$5 = {
+ cr = 0x0f077d83,
+
+ PLLI2SRDY = 1
+ PLLI2SON = 1
+ PLLRDY = 1
+ PLLON = 1
+ CSSON = 0
+ HSEBYP = 1
+ HSERDY = 1
+ HSEON = 1
+ HSICAL = 0x7d
+ HSITRIM = 0x10
+ HSIRDY = 1
+ HSION = 1
+
+ pllcfgr = 0x27403208,
+
+ PLLR = 2
+ PLLQ = 7
+ PLLSRC = 1 HSE
+ PLLP = 0 2
+ PLLN = 0xc8 200
+ PLLM = 8
+
+ clk_pllin = 8000000 / 8 = 1000000
+ vco = 1000000 * 200 = 200000000
+ clk_pll1p = 200000000 / 2 = 100000000 (100MHz)
+ clk_pll1q = 200000000 / 7 = ???
+ clk_pll1r = 200000000 / 2 = 100000000 (100MHz)
+
+ cfgr = 0x0000100a,
+ cir = 0x00000000,
+ ahb1rstr = 0x0,
+ ahb2rstr = 0x0,
+ ahb3rstr = 0x0,
+ pad_1c = 0x0,
+ apb1rstr = 0x0,
+ apb2rstr = 0x0,
+ pad_28 = 0x0,
+ pad_2c = 0x0,
+ ahb1enr = 0x40107f,
+ ahb2enr = 0x80,
+ ahbdnr = 0x3,
+ pad_3c = 0x0,
+ apb1enr = 0x11000410,
+ apb2enr = 0xc800,
+ pad_48 = 0x0,
+ pad_4c = 0x0,
+ ahb1lpenr = 0x6390ff,
+ ahb2lpenr = 0xd0,
+ ahb3lpenr = 0x3,
+ pad_5c = 0x0,
+ apb1lpenr = 0xfffecfff,
+ apb2lpenr = 0x357f9f3,
+ pad_68 = 0x0,
+ pad_6c = 0x0,
+ bdcr = 0x8200,
+ csr = 0x1e000003,
+ pad_78 = 0x0,
+ pad_7c = 0x0,
+ sscgr = 0x0,
+ plli2scfgr = 0x44003008,
+
+ PLLI2SR = 4
+ PLLI2SQ = 4
+ PLLI2SSRC = 0 HSE (due to PLLSRC)
+ PLLI2SN = 0xc0 192
+ PLLI2SM = 8
+
+ clk_plli2sin = 8000000 / 8 = 1000000
+ vcoi2s = 1000000 * 192 = 192000000
+ ck_pl2q = 192000000 / 4 = 48000000
+ ck_pl2r = 192000000 / 4 = 48000000
+
+ pad_88 = 0x0,
+ dckcfgr = 0x0,
+
+
+ ckgatenr = 0x0,
+
+ All clock gates enabled
+
+ dckcfgr2 = 0x08000000
+
+ LPTIMER1SEL = 0 APB
+ CKSDIOSEL = 0 CK_48MHz
+ CK48MSEL = 1 PLLI2S_Q
+ I2CFMP1SEL = 0 APB
+}
+
+
+
+*/