/* * Copyright (C) 2018 Marcus Comstedt * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include static const struct Fx3UsbCallbacks *Fx3UsbUserCallbacks = NULL; static void Fx3UsbGctlCoreIsr(void) __attribute__ ((isr ("IRQ"))); static void Fx3UsbUsbCoreIsr(void) __attribute__ ((isr ("IRQ"))); static void Fx3UsbGctlPowerIsr(void) __attribute__ ((isr ("IRQ"))); static void Fx3UsbWritePhyReg(uint16_t phy_addr, uint16_t phy_val) { if (!(Fx3ReadReg32(FX3_OTG_CTRL) & FX3_OTG_CTRL_SSDEV_ENABLE)) return; Fx3WriteReg32(0xe0033024, phy_addr); Fx3WriteReg32(0xe0033024, phy_addr | (1UL << 16)); while(!(Fx3ReadReg32(0xe0033028) & (1UL << 16))) ; Fx3WriteReg32(0xe0033024, phy_addr); while((Fx3ReadReg32(0xe0033028) & (1UL << 16))) ; Fx3WriteReg32(0xe0033024, phy_val); Fx3WriteReg32(0xe0033024, phy_val | (1UL << 17)); while(!(Fx3ReadReg32(0xe0033028) & (1UL << 16))) ; Fx3WriteReg32(0xe0033024, phy_val); while((Fx3ReadReg32(0xe0033028) & (1UL << 16))) ; Fx3WriteReg32(0xe0033024, phy_val | (1UL << 19)); while(!(Fx3ReadReg32(0xe0033028) & (1UL << 16))) ; Fx3WriteReg32(0xe0033024, phy_val); while((Fx3ReadReg32(0xe0033028) & (1UL << 16))) ; } static void Fx3UsbConnectHighSpeed(void) { Fx3UsbWritePhyReg(0x1005, 0x0000); /* Force the link state machine into SS.Disabled. */ Fx3WriteReg32(FX3_LNK_LTSSM_STATE,(0UL << (6)) | (1UL << 12)); /* Change EPM config to full speed */ Fx3ClearReg32(FX3_GCTL_UIB_CORE_CLK, FX3_GCTL_UIB_CORE_CLK_CLK_EN); Fx3UtilDelayUs(5); Fx3WriteReg32(FX3_GCTL_UIB_CORE_CLK, (2UL << FX3_GCTL_UIB_CORE_CLK_PCLK_SRC_SHIFT) | (2UL << FX3_GCTL_UIB_CORE_CLK_EPMCLK_SRC_SHIFT)); Fx3SetReg32(FX3_GCTL_UIB_CORE_CLK, FX3_GCTL_UIB_CORE_CLK_CLK_EN); Fx3UtilDelayUs(5); /* Switch the EPM to USB 2.0 mode, turn off USB 3.0 PHY and remove Rx Termination. */ Fx3ClearReg32(FX3_OTG_CTRL, FX3_OTG_CTRL_SSDEV_ENABLE); Fx3UtilDelayUs(5); Fx3ClearReg32(FX3_OTG_CTRL, FX3_OTG_CTRL_SSEPM_ENABLE); Fx3ClearReg32(FX3_UIB_INTR_MASK, FX3_UIB_INTR_DEV_CTL_INT | FX3_UIB_INTR_DEV_EP_INT | FX3_UIB_INTR_LNK_INT | FX3_UIB_INTR_PROT_INT | FX3_UIB_INTR_PROT_EP_INT | FX3_UIB_INTR_EPM_URUN); *(volatile uint32_t *)(void*)(FX3_LNK_PHY_CONF) &= 0x1FFFFFFFUL; Fx3WriteReg32(FX3_LNK_PHY_MPLL_STATUS,0x910410); /* Power cycle the PHY blocks. */ Fx3ClearReg32(FX3_GCTL_CONTROL, FX3_GCTL_CONTROL_USB_POWER_EN); Fx3UtilDelayUs(5); Fx3SetReg32(FX3_GCTL_CONTROL, FX3_GCTL_CONTROL_USB_POWER_EN); Fx3UtilDelayUs(10); /* Clear USB 2.0 interrupts. */ Fx3WriteReg32(FX3_DEV_CTRL_INTR, ~0UL); Fx3WriteReg32(FX3_DEV_EP_INTR, ~0UL); Fx3WriteReg32(FX3_OTG_INTR, ~0UL); /* Clear and disable USB 3.0 interrupts. */ Fx3WriteReg32(FX3_LNK_INTR_MASK, 0UL); Fx3WriteReg32(FX3_LNK_INTR, ~0UL); Fx3WriteReg32(FX3_PROT_INTR_MASK, 0UL); Fx3WriteReg32(FX3_PROT_INTR, ~0UL); Fx3SetReg32(FX3_UIB_INTR_MASK, FX3_UIB_INTR_DEV_CTL_INT | FX3_UIB_INTR_DEV_EP_INT | FX3_UIB_INTR_LNK_INT | FX3_UIB_INTR_PROT_INT | FX3_UIB_INTR_PROT_EP_INT | FX3_UIB_INTR_EPM_URUN); /* Disable EP0-IN and EP0-OUT (USB-2). */ Fx3ClearReg32(FX3_DEV_EPI_CS+0, FX3_DEV_EPI_CS_VALID); Fx3ClearReg32(FX3_DEV_EPO_CS+0, FX3_DEV_EPO_CS_VALID); Fx3WriteReg32(FX3_EHCI_PORTSC, (1UL << 22)); Fx3WriteReg32(FX3_DEV_PWR_CS, (1UL << 2) | (1UL << 3)); /* Enable USB 2.0 PHY. */ Fx3UtilDelayUs(2); Fx3SetReg32(FX3_OTG_CTRL, (1UL << 13)); Fx3UtilDelayUs(100); Fx3WriteReg32(FX3_PHY_CONF, 0xd4a480UL); Fx3WriteReg32(FX3_PHY_CLK_AND_TEST, 0xa0000011UL); Fx3UtilDelayUs(80); Fx3ClearReg32(FX3_GCTL_UIB_CORE_CLK, FX3_GCTL_UIB_CORE_CLK_CLK_EN); Fx3UtilDelayUs(5); Fx3WriteReg32(FX3_GCTL_UIB_CORE_CLK, (2UL << FX3_GCTL_UIB_CORE_CLK_PCLK_SRC_SHIFT) | (0UL << FX3_GCTL_UIB_CORE_CLK_EPMCLK_SRC_SHIFT)); Fx3SetReg32(FX3_GCTL_UIB_CORE_CLK, FX3_GCTL_UIB_CORE_CLK_CLK_EN); Fx3UtilDelayUs(5); /* For USB 2.0 connections, enable pull-up on D+ pin. */ Fx3ClearReg32(FX3_DEV_PWR_CS, (1UL << 3)); } static void Fx3UsbConnectSuperSpeed(void) { Fx3WriteReg32(FX3_LNK_PHY_TX_TRIM, 0x0b569011UL); Fx3UsbWritePhyReg(0x1006, 0x180); Fx3UsbWritePhyReg(0x1024, 0x0080); /* Switch EPM clock to USB 3.0 mode */ Fx3ClearReg32(FX3_GCTL_UIB_CORE_CLK, FX3_GCTL_UIB_CORE_CLK_CLK_EN); Fx3UtilDelayUs(5); Fx3WriteReg32(FX3_GCTL_UIB_CORE_CLK, (1UL << FX3_GCTL_UIB_CORE_CLK_PCLK_SRC_SHIFT) | (1UL << FX3_GCTL_UIB_CORE_CLK_EPMCLK_SRC_SHIFT)); Fx3SetReg32(FX3_GCTL_UIB_CORE_CLK, FX3_GCTL_UIB_CORE_CLK_CLK_EN); Fx3UtilDelayUs(5); Fx3WriteReg32(FX3_LNK_PHY_CONF, FX3_LNK_PHY_CONF_RX_TERMINATION_ENABLE | FX3_LNK_PHY_CONF_RX_TERMINATION_OVR_VAL | FX3_LNK_PHY_CONF_RX_TERMINATION_OVR | (1UL << FX3_LNK_PHY_CONF_PHY_MODE_SHIFT)); Fx3SetReg32(FX3_OTG_CTRL, FX3_OTG_CTRL_SSEPM_ENABLE); /* Reset EPM mux */ Fx3SetReg32(FX3_IEPM_CS, FX3_IEPM_CS_EPM_MUX_RESET | FX3_IEPM_CS_EPM_FLUSH); Fx3UtilDelayUs(1); Fx3ClearReg32(FX3_IEPM_CS, FX3_IEPM_CS_EPM_MUX_RESET | FX3_IEPM_CS_EPM_FLUSH); Fx3UtilDelayUs(1); Fx3UsbWritePhyReg(0x0030, 0x00c0); Fx3UsbWritePhyReg(0x1010, 0x0080); Fx3WriteReg32(FX3_EEPM_ENDPOINT+0, (512UL << FX3_EEPM_ENDPOINT_PACKET_SIZE_SHIFT)); Fx3WriteReg32(FX3_IEPM_ENDPOINT+0, (512UL << FX3_IEPM_ENDPOINT_PACKET_SIZE_SHIFT)); } static void Fx3UsbEnablePhy(void) { Fx3WriteReg32(FX3_OTG_INTR, ~0UL); Fx3WriteReg32(FX3_LNK_INTR, ~0UL); Fx3WriteReg32(FX3_LNK_INTR_MASK, FX3_LNK_INTR_MASK_LTSSM_RESET | FX3_LNK_INTR_MASK_LTSSM_DISCONNECT | FX3_LNK_INTR_MASK_LTSSM_CONNECT | FX3_LNK_INTR_MASK_LGO_U3 | FX3_LNK_INTR_MASK_LTSSM_STATE_CHG); Fx3WriteReg32(FX3_PROT_EP_INTR_MASK, 0); Fx3WriteReg32(FX3_PROT_INTR, ~0UL); Fx3WriteReg32(FX3_PROT_INTR_MASK, FX3_PROT_INTR_MASK_STATUS_STAGE | FX3_PROT_INTR_MASK_SUTOK_EN | FX3_PROT_INTR_MASK_TIMEOUT_PORT_CFG_EN | FX3_PROT_INTR_MASK_TIMEOUT_PORT_CAP_EN | FX3_PROT_INTR_MASK_LMP_PORT_CFG_EN | FX3_PROT_INTR_MASK_LMP_PORT_CAP_EN | FX3_PROT_INTR_MASK_LMP_RCV_EN); Fx3WriteReg32(FX3_DEV_CTRL_INTR, ~0UL); Fx3WriteReg32(FX3_DEV_CTRL_INTR_MASK, FX3_DEV_CTRL_INTR_MASK_URESUME | FX3_DEV_CTRL_INTR_MASK_SUDAV | FX3_DEV_CTRL_INTR_MASK_HSGRANT | FX3_DEV_CTRL_INTR_MASK_URESET | FX3_DEV_CTRL_INTR_MASK_SUSP); Fx3WriteReg32(FX3_DEV_EP_INTR, ~0UL); Fx3WriteReg32(FX3_DEV_EP_INTR_MASK, 0); Fx3WriteReg32(FX3_UIB_INTR_MASK, FX3_UIB_INTR_MASK_PROT_INT | FX3_UIB_INTR_MASK_LNK_INT | FX3_UIB_INTR_MASK_DEV_CTL_INT); Fx3WriteReg32(FX3_VIC_INT_ENABLE, (1UL << FX3_IRQ_USB_CORE)); Fx3SetReg32(FX3_GCTL_CONTROL, FX3_GCTL_CONTROL_USB_POWER_EN); /* Setup LNK for superspeed */ Fx3WriteReg32(FX3_LNK_DEVICE_POWER_CONTROL, FX3_LNK_DEVICE_POWER_CONTROL_AUTO_U2 | FX3_LNK_DEVICE_POWER_CONTROL_AUTO_U1); Fx3WriteReg32(0xe003309c, 10000); Fx3WriteReg32(0xe0033080, 10000); Fx3WriteReg32(0xe0033084, 0x00fa004b); Fx3WriteReg32(0xe00330c4, 0x00000177); Fx3WriteReg32(0xe0033078, 0x58); Fx3WriteReg32(FX3_PROT_LMP_PORT_CAPABILITY_TIMER, 2312); Fx3WriteReg32(FX3_PROT_LMP_PORT_CONFIGURATION_TIMER, 2312); Fx3SetReg32(FX3_LNK_COMPLIANCE_PATTERN_8, FX3_LNK_COMPLIANCE_PATTERN_8_LFPS); Fx3WriteReg32(FX3_LNK_PHY_CONF, FX3_LNK_PHY_CONF_RX_TERMINATION_OVR | (1UL << FX3_LNK_PHY_CONF_PHY_MODE_SHIFT)); uint32_t old_int_enable = Fx3ReadReg32(FX3_VIC_INT_ENABLE); Fx3WriteReg32(FX3_VIC_INT_CLEAR, ~0UL); Fx3ClearReg32(FX3_GCTL_UIB_CORE_CLK, FX3_GCTL_UIB_CORE_CLK_CLK_EN); Fx3UtilDelayUs(5); Fx3WriteReg32(FX3_GCTL_UIB_CORE_CLK, (2UL << FX3_GCTL_UIB_CORE_CLK_PCLK_SRC_SHIFT) | (2UL << FX3_GCTL_UIB_CORE_CLK_EPMCLK_SRC_SHIFT)); Fx3SetReg32(FX3_GCTL_UIB_CORE_CLK, FX3_GCTL_UIB_CORE_CLK_CLK_EN); Fx3UtilDelayUs(5); Fx3WriteReg32(FX3_LNK_LTSSM_STATE, (0UL << FX3_LNK_LTSSM_STATE_LTSSM_OVERRIDE_VALUE_SHIFT) | FX3_LNK_LTSSM_STATE_LTSSM_OVERRIDE_EN); Fx3SetReg32(FX3_OTG_CTRL, FX3_OTG_CTRL_SSDEV_ENABLE); Fx3UtilDelayUs(100); Fx3SetField32(FX3_LNK_CONF, EPM_FIRST_DELAY, 15UL); Fx3SetReg32(FX3_LNK_CONF, FX3_LNK_CONF_LDN_DETECTION); Fx3WriteReg32(FX3_LNK_PHY_MPLL_STATUS, FX3_LNK_PHY_MPLL_STATUS_REF_SSP_EN | (136UL << FX3_LNK_PHY_MPLL_STATUS_SSC_REF_CLK_SEL_SHIFT) | (0UL << FX3_LNK_PHY_MPLL_STATUS_SSC_RANGE_SHIFT) | FX3_LNK_PHY_MPLL_STATUS_SSC_EN | (3UL << FX3_LNK_PHY_MPLL_STATUS_MPLL_MULTIPLIER_SHIFT)); Fx3UsbWritePhyReg(0x30, 0xc0); Fx3ClearReg32(FX3_LNK_LTSSM_STATE, FX3_LNK_LTSSM_STATE_LTSSM_OVERRIDE_EN); Fx3WriteReg32(FX3_LNK_PHY_CONF, FX3_LNK_PHY_CONF_RX_TERMINATION_ENABLE | FX3_LNK_PHY_CONF_RX_TERMINATION_OVR_VAL | FX3_LNK_PHY_CONF_RX_TERMINATION_OVR | (1UL << FX3_LNK_PHY_CONF_PHY_MODE_SHIFT)); Fx3UtilDelayUs(100); Fx3WriteReg32(FX3_GCTL_UIB_CORE_CLK, FX3_GCTL_UIB_CORE_CLK_CLK_EN | (1UL << FX3_GCTL_UIB_CORE_CLK_PCLK_SRC_SHIFT) | (1UL << FX3_GCTL_UIB_CORE_CLK_EPMCLK_SRC_SHIFT)); Fx3WriteReg32(FX3_VIC_INT_ENABLE, old_int_enable); } void Fx3UsbConnect(void) { Fx3WriteReg32(FX3_GCTL_IOPOWER_INTR, ~0UL); Fx3WriteReg32(FX3_GCTL_IOPOWER_INTR_MASK, FX3_GCTL_IOPOWER_INTR_MASK_VBUS); Fx3WriteReg32(FX3_VIC_INT_ENABLE, (1UL << FX3_IRQ_GCTL_POWER)); if (Fx3ReadReg32(FX3_GCTL_IOPOWER) & FX3_GCTL_IOPOWER_VBUS) { Fx3UartTxString("VBUS POWER!\n"); Fx3UsbEnablePhy(); } } void Fx3UsbStallEp0(Fx3UsbSpeed_t s) { Fx3UartTxString("STALL EP0!\n"); if (s == FX3_USB_SUPER_SPEED){ Fx3SetReg32(FX3_PROT_EPI_CS1+0, FX3_PROT_EPI_CS1_STALL); Fx3SetReg32(FX3_PROT_EPO_CS1+0, FX3_PROT_EPO_CS1_STALL); Fx3UtilDelayUs(1); Fx3SetReg32(FX3_PROT_CS, FX3_PROT_CS_SETUP_CLR_BUSY); } else { Fx3SetReg32(FX3_DEV_EPI_CS+0, FX3_DEV_EPI_CS_STALL); Fx3SetReg32(FX3_DEV_EPO_CS+0, FX3_DEV_EPO_CS_STALL); Fx3UtilDelayUs(1); Fx3SetReg32(FX3_DEV_CS, FX3_DEV_CS_SETUP_CLR_BUSY); } } void Fx3UsbUnstallEp0(Fx3UsbSpeed_t s) { if (s == FX3_USB_SUPER_SPEED){ Fx3ClearReg32(FX3_PROT_EPI_CS1+0, FX3_PROT_EPI_CS1_STALL); Fx3ClearReg32(FX3_PROT_EPO_CS1+0, FX3_PROT_EPO_CS1_STALL); Fx3UtilDelayUs(1); Fx3SetReg32(FX3_PROT_CS, FX3_PROT_CS_SETUP_CLR_BUSY); } else { Fx3ClearReg32(FX3_DEV_EPI_CS+0,FX3_DEV_EPI_CS_STALL); Fx3ClearReg32(FX3_DEV_EPO_CS+0,FX3_DEV_EPO_CS_STALL); Fx3UtilDelayUs(1); Fx3SetReg32(FX3_DEV_CS, FX3_DEV_CS_SETUP_CLR_BUSY); } } void Fx3UsbDmaDataOut(uint8_t ep, volatile void *buffer, uint16_t length) { uint16_t d = Fx3DmaAllocateDescriptor(); Fx3DmaSimpleTransferWrite(FX3_UIBIN_DMA_SCK(ep), d, buffer, length); Fx3DmaFreeDescriptor(d); } void Fx3UsbDmaDataIn(uint8_t ep, const volatile void *buffer, uint16_t length) { uint16_t d = Fx3DmaAllocateDescriptor(); Fx3DmaSimpleTransferRead(FX3_UIB_DMA_SCK(ep), d, buffer, length); Fx3DmaFreeDescriptor(d); } static void Fx3UsbUsbCoreIsr(void) { uint32_t req = Fx3ReadReg32(FX3_UIB_INTR) & Fx3ReadReg32(FX3_UIB_INTR_MASK); Fx3WriteReg32(FX3_UIB_INTR, req); Fx3UartTxString("Fx3UsbUsbCoreIsr\n"); if (req & FX3_UIB_INTR_PROT_INT) { Fx3UartTxString(" PROT\n"); uint32_t prot_req = Fx3ReadReg32(FX3_PROT_INTR) & Fx3ReadReg32(FX3_PROT_INTR_MASK); Fx3WriteReg32(FX3_PROT_INTR, prot_req); if (prot_req & FX3_PROT_INTR_STATUS_STAGE) { Fx3UartTxString(" STATUS_STAGE\n"); } if (prot_req & FX3_PROT_INTR_SUTOK_EV) { Fx3UartTxString(" SUTOK_EV\n"); Fx3WriteReg32(FX3_PROT_EPO_CS1 + 0, FX3_PROT_EPO_CS1_VALID); Fx3WriteReg32(FX3_PROT_EPI_CS1 + 0, FX3_PROT_EPI_CS1_VALID); Fx3DmaAbortSocket(FX3_UIB_DMA_SCK(0)); Fx3DmaAbortSocket(FX3_UIBIN_DMA_SCK(0)); Fx3SetReg32(FX3_EEPM_ENDPOINT, FX3_EEPM_ENDPOINT_SOCKET_FLUSH); Fx3UtilDelayUs(10); Fx3ClearReg32(FX3_EEPM_ENDPOINT, FX3_EEPM_ENDPOINT_SOCKET_FLUSH); uint32_t sudat0 = Fx3ReadReg32(FX3_PROT_SETUP_DAT+0); uint32_t sudat1 = Fx3ReadReg32(FX3_PROT_SETUP_DAT+4); uint8_t req_type = sudat0 >> FX3_PROT_SETUP_DAT_SETUP_REQUEST_TYPE_SHIFT; uint16_t length = sudat1 >> (FX3_PROT_SETUP_DAT_SETUP_LENGTH_SHIFT - 32); if ((req_type & FX3_USB_REQTYPE_DIR_MASK) == FX3_USB_REQTYPE_IN) /* IN transfer */ Fx3WriteReg32(FX3_DEV_EPI_XFER_CNT, length); else /* OUT transfer */ Fx3WriteReg32(FX3_DEV_EPO_XFER_CNT, length); (*Fx3UsbUserCallbacks->sutok) (req_type, sudat0 >> FX3_PROT_SETUP_DAT_SETUP_REQUEST_SHIFT, sudat0 >> FX3_PROT_SETUP_DAT_SETUP_VALUE_SHIFT, sudat1 >> (FX3_PROT_SETUP_DAT_SETUP_INDEX_SHIFT - 32), length, FX3_USB_SUPER_SPEED); } if (prot_req & FX3_PROT_INTR_TIMEOUT_PORT_CFG_EV) { Fx3UartTxString(" TIMEOUT_PORT_CFG_EV\n"); } if (prot_req & FX3_PROT_INTR_TIMEOUT_PORT_CAP_EV) { Fx3UartTxString(" TIMEOUT_PORT_CAP_EV\n"); } if (prot_req & FX3_PROT_INTR_LMP_PORT_CFG_EV) { Fx3UartTxString(" LMP_PORT_CFG_EV\n"); /* Disable timeout */ Fx3WriteReg32(FX3_PROT_LMP_PORT_CONFIGURATION_TIMER, 0x80008000UL); Fx3WriteReg32(FX3_PROT_INTR, FX3_PROT_INTR_TIMEOUT_PORT_CFG_EV); } if (prot_req & FX3_PROT_INTR_LMP_PORT_CAP_EV) { Fx3UartTxString(" LMP_PORT_CAP_EV\n"); /* Disable timeout */ Fx3WriteReg32(FX3_PROT_LMP_PORT_CAPABILITY_TIMER, 0x80008000UL); Fx3WriteReg32(FX3_PROT_INTR, FX3_PROT_INTR_TIMEOUT_PORT_CAP_EV); } if (prot_req & FX3_PROT_INTR_LMP_RCV_EV) { Fx3UartTxString(" LMP_RCV_EV\n"); } } if (req & FX3_UIB_INTR_LNK_INT) { Fx3UartTxString(" LNK\n"); uint32_t lnk_req = Fx3ReadReg32(FX3_LNK_INTR) & Fx3ReadReg32(FX3_LNK_INTR_MASK); Fx3WriteReg32(FX3_LNK_INTR, lnk_req); if (lnk_req & FX3_LNK_INTR_LTSSM_RESET) { Fx3UartTxString(" LTSSM_RESET\n"); } if (lnk_req & FX3_LNK_INTR_LTSSM_DISCONNECT) { Fx3UartTxString(" LTSSM_DISCONNECT\n"); Fx3UsbConnectHighSpeed(); } if (lnk_req & FX3_LNK_INTR_LTSSM_CONNECT) { Fx3UartTxString(" LTSSM_CONNECT\n"); Fx3UsbConnectSuperSpeed(); } if (lnk_req & FX3_LNK_INTR_LGO_U3) { Fx3UartTxString(" LGO_U3\n"); } if (lnk_req & FX3_LNK_INTR_LTSSM_STATE_CHG) { Fx3UartTxString(" LTSSM_STATE_CHG %u\n"); } } if (req & FX3_UIB_INTR_DEV_CTL_INT) { Fx3UartTxString(" DEV_CTL\n"); uint32_t dev_ctrl_req; dev_ctrl_req = Fx3ReadReg32(FX3_DEV_CTRL_INTR) & Fx3ReadReg32(FX3_DEV_CTRL_INTR_MASK); Fx3WriteReg32(FX3_DEV_CTRL_INTR, dev_ctrl_req); if (dev_ctrl_req & (1UL << 8)) { Fx3WriteReg32(FX3_DEV_CTRL_INTR, (1UL << 8)); Fx3UartTxString(" resume\n"); Fx3SetReg32(FX3_DEV_CTRL_INTR_MASK, (1UL << 8)); } if (dev_ctrl_req & (1UL << 2)) { Fx3WriteReg32(FX3_DEV_CTRL_INTR, (1UL << 2)); Fx3UartTxString(" suspend\n"); Fx3SetReg32(FX3_DEV_CTRL_INTR_MASK, (1UL << 2)); } if (dev_ctrl_req & (1UL << 3)) { Fx3WriteReg32(FX3_DEV_CTRL_INTR, (1UL << 3)); Fx3UartTxString(" reset\n"); Fx3SetReg32(FX3_DEV_CTRL_INTR_MASK, (1UL << 3)); } if (dev_ctrl_req & (1UL << 4)) { Fx3WriteReg32(FX3_DEV_CTRL_INTR, (1UL << 4)); Fx3UartTxString(" hsgrant\n"); Fx3SetReg32(FX3_DEV_CTRL_INTR_MASK, (1UL << 4)); } if (dev_ctrl_req & (1UL << 11)) { Fx3WriteReg32(FX3_DEV_CTRL_INTR, (1UL << 11)); Fx3UartTxString(" status\n"); Fx3SetReg32(FX3_DEV_CTRL_INTR_MASK, (1UL << 11)); } if (dev_ctrl_req & (1UL << 6)) { Fx3WriteReg32(FX3_DEV_CTRL_INTR, (1UL << 6)); Fx3UartTxString(" sudav\n"); Fx3WriteReg32(FX3_DEV_EPO_CS + 0, FX3_DEV_EPO_CS_VALID); Fx3WriteReg32(FX3_DEV_EPI_CS + 0, FX3_DEV_EPI_CS_VALID); Fx3DmaAbortSocket(FX3_UIB_DMA_SCK(0)); Fx3DmaAbortSocket(FX3_UIBIN_DMA_SCK(0)); Fx3SetReg32(FX3_EEPM_ENDPOINT, FX3_EEPM_ENDPOINT_SOCKET_FLUSH); Fx3UtilDelayUs(10); Fx3ClearReg32(FX3_EEPM_ENDPOINT, FX3_EEPM_ENDPOINT_SOCKET_FLUSH); uint32_t setupdat0; uint32_t setupdat1; setupdat0 = Fx3ReadReg32(FX3_DEV_SETUPDAT+0); setupdat1 = Fx3ReadReg32(FX3_DEV_SETUPDAT+4); uint8_t req_type = setupdat0 >> 0; uint16_t length = setupdat1 >> (48 - 32); if ((req_type & FX3_USB_REQTYPE_DIR_MASK) == FX3_USB_REQTYPE_IN) /* IN transfer */ Fx3WriteReg32(FX3_DEV_EPI_XFER_CNT, length); else /* OUT transfer */ Fx3WriteReg32(FX3_DEV_EPO_XFER_CNT, length); (*Fx3UsbUserCallbacks->sutok) (req_type, setupdat0 >> FX3_PROT_SETUP_DAT_SETUP_REQUEST_SHIFT, setupdat0 >> FX3_PROT_SETUP_DAT_SETUP_VALUE_SHIFT, setupdat1 >> (FX3_PROT_SETUP_DAT_SETUP_INDEX_SHIFT - 32), length, FX3_USB_HIGH_SPEED); } if (dev_ctrl_req & (1UL << 7)) { Fx3WriteReg32(FX3_DEV_CTRL_INTR, (1UL << 7)); Fx3SetReg32(FX3_DEV_CTRL_INTR_MASK, (1UL << 7)); } } Fx3WriteReg32(FX3_VIC_ADDRESS, 0); } static void Fx3UsbGctlCoreIsr(void) { uint32_t req = Fx3ReadReg32(FX3_GCTL_WAKEUP_EVENT) & Fx3ReadReg32(FX3_GCTL_WAKEUP_EN); Fx3WriteReg32(FX3_GCTL_WAKEUP_EVENT, req); Fx3UartTxString("Fx3UsbGctlCoreIsr\n"); Fx3WriteReg32(FX3_VIC_ADDRESS, 0); } static void Fx3UsbGctlPowerIsr(void) { uint32_t req = Fx3ReadReg32(FX3_GCTL_IOPOWER_INTR) & Fx3ReadReg32(FX3_GCTL_IOPOWER_INTR_MASK); Fx3WriteReg32(FX3_GCTL_IOPOWER_INTR, req); Fx3UartTxString("Fx3UsbGctlPowerIsr\n"); if (req & FX3_GCTL_IOPOWER_INTR_VBUS) { Fx3UartTxString(" VBUS\n"); } Fx3WriteReg32(FX3_VIC_ADDRESS, 0); } void Fx3UsbInit(const struct Fx3UsbCallbacks *callbacks) { Fx3UsbUserCallbacks = callbacks; /* Select bus clock */ Fx3ClearReg32(FX3_GCTL_UIB_CORE_CLK, FX3_GCTL_UIB_CORE_CLK_CLK_EN); Fx3UtilDelayUs(5); Fx3WriteReg32(FX3_GCTL_UIB_CORE_CLK, (2UL << FX3_GCTL_UIB_CORE_CLK_PCLK_SRC_SHIFT) | (2UL << FX3_GCTL_UIB_CORE_CLK_EPMCLK_SRC_SHIFT)); Fx3SetReg32(FX3_GCTL_UIB_CORE_CLK, FX3_GCTL_UIB_CORE_CLK_CLK_EN); Fx3UtilDelayUs(5); Fx3WriteReg32(FX3_GCTL_CONTROL, FX3_GCTL_CONTROL_HARD_RESET_N | FX3_GCTL_CONTROL_CPU_RESET_N | FX3_GCTL_CONTROL_BOOTROM_EN | (1UL<<27) | FX3_GCTL_CONTROL_MAIN_POWER_EN | FX3_GCTL_CONTROL_MAIN_CLOCK_EN | FX3_GCTL_CONTROL_WAKEUP_CPU_INT | FX3_GCTL_CONTROL_WAKEUP_CLK | FX3_GCTL_CONTROL_POR); /* Reset USB */ Fx3ClearReg32(FX3_UIB_POWER, FX3_UIB_POWER_RESETN); Fx3UtilDelayUs(50); Fx3SetReg32(FX3_UIB_POWER, FX3_UIB_POWER_RESETN); Fx3UtilDelayUs(100); while((Fx3ReadReg32(FX3_UIB_POWER) & FX3_UIB_POWER_ACTIVE) == 0) ; Fx3WriteReg32(FX3_OTG_CTRL, 0); Fx3WriteReg32(FX3_PHY_CLK_AND_TEST, (1UL<<31) | FX3_PHY_CLK_AND_TEST_SUSPEND_N | FX3_PHY_CLK_AND_TEST_VLOAD | FX3_PHY_CLK_AND_TEST_DATABUS16_8); Fx3SetReg32(FX3_DEV_PWR_CS, FX3_DEV_PWR_CS_DISCON); Fx3WriteReg32(FX3_GCTL_WAKEUP_EN, 0); Fx3WriteReg32(FX3_GCTL_WAKEUP_POLARITY, 0); Fx3WriteReg32(FX3_LNK_PHY_CONF, FX3_LNK_PHY_CONF_RX_TERMINATION_ENABLE | FX3_LNK_PHY_CONF_RX_TERMINATION_OVR_VAL | FX3_LNK_PHY_CONF_RX_TERMINATION_OVR | (1UL << FX3_LNK_PHY_CONF_PHY_MODE_SHIFT)); Fx3WriteReg32(FX3_LNK_ERROR_CONF, ~0UL); Fx3WriteReg32(FX3_LNK_INTR, ~0UL); Fx3WriteReg32(FX3_LNK_INTR_MASK, FX3_LNK_INTR_MASK_LTSSM_RESET | FX3_LNK_INTR_MASK_LTSSM_DISCONNECT | FX3_LNK_INTR_MASK_LTSSM_CONNECT | FX3_LNK_INTR_MASK_LGO_U3 | FX3_LNK_INTR_MASK_LTSSM_STATE_CHG); Fx3WriteReg32(FX3_PROT_EP_INTR_MASK, 0); Fx3WriteReg32(FX3_PROT_INTR, ~0UL); Fx3WriteReg32(FX3_PROT_INTR_MASK, FX3_PROT_INTR_MASK_STATUS_STAGE | FX3_PROT_INTR_MASK_SUTOK_EN | FX3_PROT_INTR_MASK_TIMEOUT_PORT_CFG_EN | FX3_PROT_INTR_MASK_TIMEOUT_PORT_CAP_EN | FX3_PROT_INTR_MASK_LMP_PORT_CFG_EN | FX3_PROT_INTR_MASK_LMP_PORT_CAP_EN | FX3_PROT_INTR_MASK_LMP_RCV_EN); Fx3WriteReg32(FX3_PHY_CONF, FX3_PHY_CONF_PREEMDEPTH | FX3_PHY_CONF_ENPRE | (1UL << FX3_PHY_CONF_FSRFTSEL_SHIFT) | (1UL << FX3_PHY_CONF_LSRFTSEL_SHIFT) | (2UL << FX3_PHY_CONF_HSTEDVSEL_SHIFT) | (4UL << FX3_PHY_CONF_FSTUNEVSEL_SHIFT) | (2UL << FX3_PHY_CONF_HSDEDVSEL_SHIFT) | (4UL << FX3_PHY_CONF_HSDRVSLOPE_SHIFT)); Fx3WriteReg32(FX3_DEV_CTRL_INTR, ~0UL); Fx3WriteReg32(FX3_DEV_CTRL_INTR_MASK, FX3_DEV_CTRL_INTR_MASK_URESUME | FX3_DEV_CTRL_INTR_MASK_SUDAV | FX3_DEV_CTRL_INTR_MASK_HSGRANT | FX3_DEV_CTRL_INTR_MASK_URESET | FX3_DEV_CTRL_INTR_MASK_SUSP); Fx3WriteReg32(FX3_DEV_EP_INTR, ~0UL); Fx3WriteReg32(FX3_DEV_EP_INTR_MASK, 0); /* USB3 EP0 valid as control */ Fx3WriteReg32(FX3_PROT_EPO_CS1+0, FX3_PROT_EPO_CS1_VALID); Fx3WriteReg32(FX3_PROT_EPI_CS1+0, FX3_PROT_EPI_CS1_VALID); Fx3WriteReg32(FX3_PROT_EPO_CS2+0, (16UL << FX3_PROT_EPO_CS2_ISOINPKS_SHIFT) | (3UL << FX3_PROT_EPO_CS2_TYPE_SHIFT)); Fx3WriteReg32(FX3_PROT_EPI_CS2+0, (16UL << FX3_PROT_EPI_CS2_ISOINPKS_SHIFT) | (3UL << FX3_PROT_EPI_CS2_TYPE_SHIFT)); /* USB2 EP0 valid as control */ Fx3WriteReg32(FX3_DEV_EPI_CS+0, FX3_DEV_EPI_CS_VALID | (0UL << FX3_DEV_EPI_CS_TYPE_SHIFT) | (64UL << FX3_DEV_EPI_CS_PAYLOAD_SHIFT)); Fx3WriteReg32(FX3_DEV_EPO_CS+0, FX3_DEV_EPO_CS_VALID | (0UL << FX3_DEV_EPO_CS_TYPE_SHIFT) | (64UL << FX3_DEV_EPO_CS_PAYLOAD_SHIFT)); /* Endpoint manager settings for EP0 */ Fx3WriteReg32(FX3_EEPM_ENDPOINT+0, (64UL << FX3_EEPM_ENDPOINT_PACKET_SIZE_SHIFT)); Fx3WriteReg32(FX3_IEPM_ENDPOINT+0, (64UL << FX3_IEPM_ENDPOINT_PACKET_SIZE_SHIFT)); /* Invalidate all other EPs */ unsigned i; for (i=1; i<16; i++) { Fx3ClearReg32(FX3_DEV_EPO_CS + (i<<2), FX3_DEV_EPO_CS_VALID); Fx3WriteReg32(FX3_PROT_EPO_CS1 + (i<<2), 0); Fx3ClearReg32(FX3_DEV_EPI_CS + (i<<2), FX3_DEV_EPI_CS_VALID); Fx3WriteReg32(FX3_PROT_EPI_CS1 + (i<<2), 0); } Fx3WriteReg32(FX3_UIB_INTR_MASK, 0); /* Configure vectored interrupt controller */ Fx3WriteReg32(FX3_VIC_VEC_ADDRESS + (FX3_IRQ_GCTL_CORE<<2), Fx3UsbGctlCoreIsr); Fx3WriteReg32(FX3_VIC_VEC_ADDRESS + (FX3_IRQ_USB_CORE<<2), Fx3UsbUsbCoreIsr); Fx3WriteReg32(FX3_VIC_VEC_ADDRESS + (FX3_IRQ_GCTL_POWER<<2), Fx3UsbGctlPowerIsr); Fx3WriteReg32(FX3_VIC_INT_CLEAR, (1UL << FX3_IRQ_GCTL_POWER) | (1UL << FX3_IRQ_USB_CORE) | (1UL << FX3_IRQ_GCTL_CORE)); } void Fx3UsbEnableInEndpoint(uint8_t ep, Fx3UsbEndpointType_t type, uint16_t pktsize) { static const uint8_t usb2_type_map[] = { [FX3_USB_EP_ISOCHRONOUS] = 1, [FX3_USB_EP_INTERRUPT] = 3, [FX3_USB_EP_BULK] = 2, [FX3_USB_EP_CONTROL] = 0, }; /* USB3 EP valid */ Fx3WriteReg32(FX3_PROT_EPI_CS1+(ep<<2), FX3_PROT_EPI_CS1_VALID); Fx3WriteReg32(FX3_PROT_EPI_CS2+(ep<<2), (16UL << FX3_PROT_EPI_CS2_ISOINPKS_SHIFT) | ((type << FX3_PROT_EPI_CS2_TYPE_SHIFT) & FX3_PROT_EPI_CS2_TYPE_MASK)); /* USB2 EP valid */ Fx3WriteReg32(FX3_DEV_EPI_CS+(ep<<2), FX3_DEV_EPI_CS_VALID | (usb2_type_map[type&3] << FX3_DEV_EPI_CS_TYPE_SHIFT) | ((pktsize << FX3_DEV_EPI_CS_PAYLOAD_SHIFT) & FX3_DEV_EPI_CS_PAYLOAD_MASK)); /* Endpoint manager settings for EP */ Fx3WriteReg32(FX3_EEPM_ENDPOINT+(ep<<2), (pktsize << FX3_EEPM_ENDPOINT_PACKET_SIZE_SHIFT) & FX3_EEPM_ENDPOINT_PACKET_SIZE_MASK); } void Fx3UsbFlushInEndpoint(uint8_t ep) { Fx3SetReg32(FX3_EEPM_ENDPOINT+(ep<<2), FX3_EEPM_ENDPOINT_SOCKET_FLUSH); Fx3UtilDelayUs(5); Fx3ClearReg32(FX3_EEPM_ENDPOINT+(ep<<2), FX3_EEPM_ENDPOINT_SOCKET_FLUSH); }