jacking/bsp/usb.c

700 lines
24 KiB
C
Raw Normal View History

2022-01-21 04:15:36 +00:00
/*
* 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 <bsp/usb.h>
#include <bsp/regaccess.h>
#include <bsp/dma.h>
#include <bsp/irq.h>
#include <bsp/util.h>
#include <bsp/uart.h>
#include <rdb/gctl.h>
#include <rdb/uib.h>
#include <rdb/uibin.h>
#include <rdb/vic.h>
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);
}