first commit for chrg
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2024, ArtInChip Technology Co., Ltd
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <aic_core.h>
|
||||
#include <aic_hal.h>
|
||||
#include <hal_syscfg.h>
|
||||
#include "usbd_core.h"
|
||||
#include "usb_dc_aic_reg.h"
|
||||
|
||||
extern irqreturn_t USBD_IRQHandler(int irq, void * data);
|
||||
|
||||
uint32_t usbd_clk;
|
||||
static unsigned char dma_sync_buffer[CACHE_LINE_SIZE] __attribute__((aligned(CACHE_LINE_SIZE)));
|
||||
|
||||
void usb_dc_sync_dma(void)
|
||||
{
|
||||
asm volatile("sw t0, (%0)" : : "r"(dma_sync_buffer));
|
||||
csi_dcache_clean_range((phy_addr_t)(ptr_t)dma_sync_buffer, CACHE_LINE_SIZE);
|
||||
}
|
||||
|
||||
void usb_dc_low_level_init(void)
|
||||
{
|
||||
/* set usb0 phy switch: Host/Device */
|
||||
#if defined(AIC_USING_USB0_DEVICE) || defined(AIC_USING_USB0_OTG)
|
||||
hal_syscfg_usb_phy0_sw_host(0);
|
||||
#endif
|
||||
/* set pin-mux */
|
||||
|
||||
/* enable clock */
|
||||
hal_clk_enable(CONFIG_USB_AIC_DC_PHY_CLK);
|
||||
hal_clk_enable(CONFIG_USB_AIC_DC_CLK);
|
||||
aicos_udelay(300);
|
||||
hal_reset_assert(CONFIG_USB_AIC_DC_PHY_RESET);
|
||||
hal_reset_assert(CONFIG_USB_AIC_DC_RESET);
|
||||
aicos_udelay(300);
|
||||
hal_reset_deassert(CONFIG_USB_AIC_DC_PHY_RESET);
|
||||
hal_reset_deassert(CONFIG_USB_AIC_DC_RESET);
|
||||
aicos_udelay(300);
|
||||
|
||||
usbd_clk = hal_clk_get_freq(CONFIG_USB_AIC_DC_CLK);
|
||||
|
||||
/* register interrupt callback */
|
||||
aicos_request_irq(CONFIG_USB_AIC_DC_IRQ_NUM, USBD_IRQHandler,
|
||||
0, "usb_device", NULL);
|
||||
aicos_irq_enable(CONFIG_USB_AIC_DC_IRQ_NUM);
|
||||
}
|
||||
|
||||
void usb_dc_low_level_deinit(void)
|
||||
{
|
||||
aicos_irq_disable(CONFIG_USB_AIC_DC_IRQ_NUM);
|
||||
|
||||
hal_reset_assert(CONFIG_USB_AIC_DC_PHY_RESET);
|
||||
hal_reset_assert(CONFIG_USB_AIC_DC_RESET);
|
||||
hal_clk_disable(CONFIG_USB_AIC_DC_PHY_CLK);
|
||||
hal_clk_disable(CONFIG_USB_AIC_DC_CLK);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,312 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2024, Artinchip Technology Co., Ltd
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __USB_DC_AIC_REG_H__
|
||||
#define __USB_DC_AIC_REG_H__
|
||||
|
||||
#define __IO volatile /*!< Defines 'read / write' permissions */
|
||||
|
||||
typedef struct {
|
||||
__IO uint32_t ahbbasic; /* 0x0000: AHBBASIC */
|
||||
__IO uint32_t usbdevinit; /* 0x0004: USBDEVINIT */
|
||||
__IO uint32_t usbphyif; /* 0x0008: USBPHYIF */
|
||||
__IO uint32_t usbulpiphy; /* 0x000C: USBULPIPHY */
|
||||
__IO uint32_t usbintsts; /* 0x0010: USBINTSTS */
|
||||
__IO uint32_t usbintmsk; /* 0x0014: USBINTMSK */
|
||||
__IO uint32_t rxfifosiz; /* 0x0018: RXFIFOSIZ */
|
||||
__IO uint32_t rxfifosts_pop; /* 0x001C: RXFIFOSTS pop */
|
||||
__IO uint32_t nptxfifosiz; /* 0x0020: NPTXFIFOSIZ */
|
||||
__IO uint32_t nptxfifosts; /* 0x0024: NPTXFIFOSTS */
|
||||
__IO uint32_t txfifosiz[2]; /* 0x0028 - 0x002C: TXFIFOSIZ() */
|
||||
__IO uint32_t rxfifosts_dbg; /* 0x0030: RXFIFOSTS_DBG */
|
||||
uint8_t res0[0x1cc];
|
||||
__IO uint32_t usbdevconf; /* 0x0200: USBDEVCONF */
|
||||
__IO uint32_t usbdevfunc; /* 0x0204: USBDEVFUNC */
|
||||
__IO uint32_t usblinests; /* 0x0208: USBLINESTS */
|
||||
__IO uint32_t inepintmsk; /* 0x020C: INEPINTMSK */
|
||||
__IO uint32_t outepintmsk; /* 0x0210: OUTEPINTMSK */
|
||||
__IO uint32_t usbepint; /* 0x0214: USBEPINT */
|
||||
__IO uint32_t usbepintmsk; /* 0x0218: USBEPINTMSK */
|
||||
uint8_t res1[4];
|
||||
__IO uint32_t inepcfg[5]; /* 0x0220 - 0x0230: INEPCFG() */
|
||||
uint8_t res2[0xc];
|
||||
__IO uint32_t outepcfg[5]; /* 0x0240 - 0x0250: OUTEPCFG() */
|
||||
uint8_t res3[0xc];
|
||||
__IO uint32_t inepint[5]; /* 0x0260 - 0x0270: INEPINT() */
|
||||
uint8_t res4[0xc];
|
||||
__IO uint32_t outepint[5]; /* 0x0280 - 0x0290: OUTEPINT() */
|
||||
uint8_t res5[0xc];
|
||||
__IO uint32_t ineptsfsiz[5]; /* 0x02A0 - 0x02B0: INEPTSFSIZ() */
|
||||
uint8_t res6[0xc];
|
||||
__IO uint32_t outeptsfsiz[5]; /* 0x02C0 - 0x02D0: OUTEPTSFSIZ() */
|
||||
uint8_t res7[0x2c];
|
||||
__IO uint32_t inepdmaaddr[5]; /* 0x0300 - 0x0310: INEPDMAADDR() */
|
||||
uint8_t res8[0xc];
|
||||
__IO uint32_t outepdmaaddr[5]; /* 0x0320 - 0x0330: OUTEPDMAADDR() */
|
||||
uint8_t res9[0xc];
|
||||
__IO uint32_t ineptxsts[5]; /* 0x0340 - 0x0350: INEPTXSTS() */
|
||||
uint8_t res10[0xc];
|
||||
__IO uint32_t dtknqr1; /* 0x0360: DTKNQR1 */
|
||||
__IO uint32_t dtknqr2; /* 0x0364: DTKNQR2 */
|
||||
__IO uint32_t dtknqr3; /* 0x0368: DTKNQR3 */
|
||||
__IO uint32_t dtknqr4; /* 0x036C: DTKNQR4 */
|
||||
}AIC_UDC_RegDef;
|
||||
|
||||
/*===================================================================== */
|
||||
/*definitions related to CSR setting */
|
||||
|
||||
/* AHBBASIC */
|
||||
#define AHBBASIC_NOTI_ALL_DMA_WRIT (1 << 8)
|
||||
#define AHBBASIC_REM_MEM_SUPP (1 << 7)
|
||||
#define AHBBASIC_INV_DESC_ENDIANNESS (1 << 6)
|
||||
#define AHBBASIC_AHB_SINGLE (1 << 5)
|
||||
#define AHBBASIC_TXENDDELAY (1 << 3)
|
||||
#define AHBBASIC_AHBIDLE (1 << 2)
|
||||
#define AHBBASIC_DMAREQ (1 << 1)
|
||||
|
||||
/* USBDEVINIT */
|
||||
#define USBDEVINIT_HBSTLEN_MASK (0xf << 12)
|
||||
#define USBDEVINIT_HBSTLEN_SHIFT 12
|
||||
#define USBDEVINIT_HBSTLEN_SINGLE 0
|
||||
#define USBDEVINIT_HBSTLEN_INCR 1
|
||||
#define USBDEVINIT_HBSTLEN_INCR4 3
|
||||
#define USBDEVINIT_HBSTLEN_INCR8 5
|
||||
#define USBDEVINIT_HBSTLEN_INCR16 7
|
||||
#define USBDEVINIT_DMA_EN (1 << 11)
|
||||
#define USBDEVINIT_NP_TXF_EMP_LVL (1 << 10)
|
||||
#define USBDEVINIT_GLBL_INTR_EN (1 << 9)
|
||||
#define USBDEVINIT_CTRL_MASK (USBDEVINIT_NP_TXF_EMP_LVL | \
|
||||
USBDEVINIT_DMA_EN | \
|
||||
USBDEVINIT_GLBL_INTR_EN)
|
||||
#define USBDEVINIT_IN_TKNQ_FLSH (1 << 8)
|
||||
#define USBDEVINIT_TXFNUM_MASK (0x1f << 3)
|
||||
#define USBDEVINIT_TXFNUM_SHIFT 3
|
||||
#define USBDEVINIT_TXFNUM_LIMIT 0x1f
|
||||
#define USBDEVINIT_TXFNUM(_x) ((_x) << 3)
|
||||
#define USBDEVINIT_TXFFLSH (1 << 2)
|
||||
#define USBDEVINIT_RXFFLSH (1 << 1)
|
||||
#define USBDEVINIT_CSFTRST (1 << 0)
|
||||
|
||||
/* USBPHYIF */
|
||||
#define USBPHYIF_ULPI_CLK_SUSP_M (1 << 19)
|
||||
#define USBPHYIF_ULPI_AUTO_RES (1 << 18)
|
||||
#define USBPHYIF_PHY_LP_CLK_SEL (1 << 15)
|
||||
#define USBPHYIF_USBTRDTIM_MASK (0xf << 10)
|
||||
#define USBPHYIF_USBTRDTIM_SHIFT 10
|
||||
#ifndef USBPHYIF_HS_TRDT_VALUE
|
||||
#define USBPHYIF_HS_TRDT_VALUE 9U
|
||||
#endif /* USBD_HS_TRDT_VALUE */
|
||||
#ifndef USBPHYIF_FS_TRDT_VALUE
|
||||
#define USBPHYIF_FS_TRDT_VALUE 5U
|
||||
#define USBPHYIF_DEFAULT_TRDT_VALUE 9U
|
||||
#endif /* USBD_HS_TRDT_VALUE */
|
||||
#define USBPHYIF_DDRSEL (1 << 7)
|
||||
#define USBPHYIF_ULPI_UTMI_SEL (1 << 4)
|
||||
#define USBPHYIF_PHYIF16 (1 << 3)
|
||||
#define USBPHYIF_PHYIF8 (0 << 3)
|
||||
#define USBPHYIF_TOUTCAL_MASK (0x7 << 0)
|
||||
#define USBPHYIF_TOUTCAL_SHIFT 0
|
||||
#define USBPHYIF_TOUTCAL_LIMIT 0x7
|
||||
#define USBPHYIF_TOUTCAL(_x) ((_x) << 0)
|
||||
|
||||
/* USBINTSTS/USBINTMSK interrupt register */
|
||||
#define INT_RESUME (1u << 31)
|
||||
#define INT_INCOMP_ISO_OUT_INT (0x1 << 21)
|
||||
#define INT_INCOMP_ISO_IN_INT (0x1 << 20)
|
||||
#define INT_OUT_EP (0x1 << 19)
|
||||
#define INT_IN_EP (0x1 << 18)
|
||||
#define INT_ENUMDONE (0x1 << 13)
|
||||
#define INT_RESET (0x1 << 12)
|
||||
#define INT_SUSPEND (0x1 << 11)
|
||||
#define INT_EARLY_SUSPEND (0x1 << 10)
|
||||
#define INT_GOUTNAKEFF (0x1 << 7)
|
||||
#define INT_GINNAKEFF (0x1 << 6)
|
||||
#define INT_NP_TX_FIFO_EMPTY (0x1 << 5)
|
||||
#define INT_RX_FIFO_NOT_EMPTY (0x1 << 4)
|
||||
#define INT_SOF (0x1 << 3)
|
||||
|
||||
#define FULL_SPEED_CONTROL_PKT_SIZE 8
|
||||
#define FULL_SPEED_BULK_PKT_SIZE 64
|
||||
|
||||
#define HIGH_SPEED_CONTROL_PKT_SIZE 64
|
||||
#define HIGH_SPEED_BULK_PKT_SIZE 512
|
||||
|
||||
#define RX_FIFO_SIZE (1024)
|
||||
#define NPTX_FIFO_SIZE (1024)
|
||||
#define PTX_FIFO_SIZE (384)
|
||||
|
||||
/* fifo size configure */
|
||||
#define EPS_NUM 5
|
||||
#define PERIOD_IN_EP_NUM 2
|
||||
#define TOTAL_FIFO_SIZE 0x3f6
|
||||
#ifdef LPKG_CHERRYUSB_DEVICE_VIDEO_DVP_TEMPLATE
|
||||
/* video_dvp_template must use 2K Bytes period_tx_fifo */
|
||||
#define AIC_RX_FIFO_SIZE 0x99
|
||||
#define AIC_NP_TX_FIFO_SIZE 0x100
|
||||
#define AIC_PERIOD_TX_FIFO1_SIZE 0x200
|
||||
#define AIC_PERIOD_TX_FIFO2_SIZE 0x0
|
||||
#else
|
||||
/* default configuration */
|
||||
#define AIC_RX_FIFO_SIZE 0x119
|
||||
#define AIC_NP_TX_FIFO_SIZE 0x100
|
||||
#define AIC_PERIOD_TX_FIFO1_SIZE 0x100
|
||||
#define AIC_PERIOD_TX_FIFO2_SIZE 0xDD
|
||||
#endif
|
||||
|
||||
#define DEPCTL_TXFNUM_0 (0x0 << 22)
|
||||
#define DEPCTL_TXFNUM_1 (0x1 << 22)
|
||||
#define DEPCTL_TXFNUM_2 (0x2 << 22)
|
||||
#define DEPCTL_TXFNUM_3 (0x3 << 22)
|
||||
#define DEPCTL_TXFNUM_4 (0x4 << 22)
|
||||
|
||||
/* RXFIFOSTS */
|
||||
#define RXFIFOSTS_EPNUM_MASK (0xFU << 0)
|
||||
#define RXFIFOSTS_BCNT_MASK (0x7FFU << 4)
|
||||
#define RXFIFOSTS_DPID_MASK (0x3U << 15)
|
||||
#define RXFIFOSTS_PKTSTS_SHIFT (17)
|
||||
#define RXFIFOSTS_PKTSTS_MASK (0xFU << RXFIFOSTS_PKTSTS_SHIFT)
|
||||
#define PKTSTS_GLOBAL_OUT_NAK (0x1 << RXFIFOSTS_PKTSTS_SHIFT)
|
||||
#define PKTSTS_OUT_DATA_PKT_REC (0x2 << RXFIFOSTS_PKTSTS_SHIFT)
|
||||
#define PKTSTS_OUT_TRANSFER_COMP (0x3 << RXFIFOSTS_PKTSTS_SHIFT)
|
||||
#define PKTSTS_SETUP_TRANSACTION_COMP (0x4 << RXFIFOSTS_PKTSTS_SHIFT)
|
||||
#define PKTSTS_SETUP_DATA_PKT_REC (0x6 << RXFIFOSTS_PKTSTS_SHIFT)
|
||||
#define RXFIFOSTS_FN_MASK (0xFU << 21)
|
||||
|
||||
/* USBDEVCONF */
|
||||
#define DEV_SPEED_HIGH_SPEED_20 (0x0 << 0)
|
||||
#define DEV_SPEED_FULL_SPEED_20 (0x1 << 0)
|
||||
#define DEV_SPEED_LOW_SPEED_11 (0x2 << 0)
|
||||
#define DEV_SPEED_FULL_SPEED_11 (0x3 << 0)
|
||||
#define EP_MISS_CNT(x) (x << 18)
|
||||
#define DEVICE_ADDRESS_MASK (0x7F << 4)
|
||||
#define DEVICE_ADDRESS(x) (x << 4)
|
||||
#define PERIOD_FRAME_INTERVAL_80 (0 << 11)
|
||||
#define PERIOD_FRAME_INTERVAL_85 (1 << 11)
|
||||
#define PERIOD_FRAME_INTERVAL_90 (2 << 11)
|
||||
#define PERIOD_FRAME_INTERVAL_95 (3 << 11)
|
||||
|
||||
/* USBDEVFUNC */
|
||||
#define NORMAL_OPERATION (0x1 << 0)
|
||||
#define SOFT_DISCONNECT (0x1 << 1)
|
||||
#define USBDEVFUNC_SERVICE_INTERVAL_SUPPORTED (1 << 19)
|
||||
#define USBDEVFUNC_PWRONPRGDONE (1 << 11)
|
||||
#define USBDEVFUNC_CGOUTNAK (1 << 10)
|
||||
#define USBDEVFUNC_SGOUTNAK (1 << 9)
|
||||
#define USBDEVFUNC_CGNPINNAK (1 << 8)
|
||||
#define USBDEVFUNC_SGNPINNAK (1 << 7)
|
||||
#define USBDEVFUNC_TSTCTL_MASK (0x7 << 4)
|
||||
#define USBDEVFUNC_TSTCTL_SHIFT (4)
|
||||
#define USBDEVFUNC_GOUTNAKSTS (1 << 3)
|
||||
#define USBDEVFUNC_GNPINNAKSTS (1 << 2)
|
||||
#define USBDEVFUNC_SFTDISCON (1 << 1)
|
||||
#define USBDEVFUNC_RMTWKUPSIG (1 << 0)
|
||||
|
||||
/* USBLINESTS: Enumeration speed */
|
||||
#define USB_ENUM_SPEED_SHIFT 1
|
||||
#define USB_ENUM_SPEED_MASK (0x3 << USB_ENUM_SPEED_SHIFT)
|
||||
#define USB_ENUM_SPEED_HIGH 0
|
||||
#define USB_ENUM_SPEED_FULL 1
|
||||
#define USB_HIGH_30_60MHZ (0x0 << USB_ENUM_SPEED_SHIFT)
|
||||
#define USB_FULL_30_60MHZ (0x1 << USB_ENUM_SPEED_SHIFT)
|
||||
#define USB_LOW_6MHZ (0x2 << USB_ENUM_SPEED_SHIFT)
|
||||
#define USB_FULL_48MHZ (0x3 << USB_ENUM_SPEED_SHIFT)
|
||||
|
||||
/* USBEPINT endpoint interrupt register */
|
||||
#define DAINT_OUT_BIT (16)
|
||||
#define DAINT_IN_MASK (0xFFFF)
|
||||
#define DAINT_OUT_MASK (0xFFFFU << DAINT_OUT_BIT)
|
||||
|
||||
/* INEPCFG()/OUTEPCFG()
|
||||
* devicecontrol IN/OUT endpoint 0 control register
|
||||
*/
|
||||
#define DEPCTL_EPENA (1u << 31)
|
||||
#define DEPCTL_EPDIS (0x1 << 30)
|
||||
#define DEPCTL_SETD1PID (0x1 << 29)
|
||||
#define DEPCTL_SETD0PID (0x1 << 28)
|
||||
#define DEPCTL_SNAK (0x1 << 27)
|
||||
#define DEPCTL_CNAK (0x1 << 26)
|
||||
#define DEPCTL_TXFIFONUM_SHIFT 22
|
||||
#define DEPCTL_TXFIFONUM_MASK (0xF << 22)
|
||||
#define DEPCTL_STALL (0x1 << 21)
|
||||
#define DEPCTL_TYPE_BIT (18)
|
||||
#define DEPCTL_TYPE_MASK (0x3 << 18)
|
||||
#define DEPCTL_CTRL_TYPE (0x0 << 18)
|
||||
#define DEPCTL_ISO_TYPE (0x1 << 18)
|
||||
#define DEPCTL_BULK_TYPE (0x2 << 18)
|
||||
#define DEPCTL_INTR_TYPE (0x3 << 18)
|
||||
#define DEPCTL_USBACTEP (0x1 << 15)
|
||||
#define DEPCTL_NEXT_EP_BIT (11)
|
||||
#define DEPCTL_NEXT_EP_MASK (0xFU << DEPCTL_NEXT_EP_BIT)
|
||||
#define DEPCTL_MPS_BIT (0)
|
||||
#define DEPCTL_MPS_MASK (0x7FF)
|
||||
|
||||
#define DEPCTL0_MPS_64 (0x0 << 0)
|
||||
#define DEPCTL0_MPS_32 (0x1 << 0)
|
||||
#define DEPCTL0_MPS_16 (0x2 << 0)
|
||||
#define DEPCTL0_MPS_8 (0x3 << 0)
|
||||
#define DEPCTL_MPS_BULK_512 (512 << 0)
|
||||
#define DEPCTL_MPS_INT_MPS_16 (16 << 0)
|
||||
|
||||
#define DIEPCTL0_NEXT_EP_BIT (11)
|
||||
|
||||
/* INEPINT/OUTEPINT device IN/OUT endpoint interrupt register */
|
||||
#define CTRL_OUT_EP_SETUP_RCVD (0x1 << 15)
|
||||
#define TXFIFO_EMP_INT (0x1 << 7)
|
||||
#define INEP_NAKEFF (0x1 << 6)
|
||||
#define BACK2BACK_SETUP_RECEIVED (0x1 << 6)
|
||||
#define CTRL_OUT_EP_STATUS_PHASE_RCVD (0x1 << 5)
|
||||
#define INTKNEPMIS (0x1 << 5)
|
||||
#define INTKN_TXFEMP (0x1 << 4)
|
||||
#define NON_ISO_IN_EP_TIMEOUT (0x1 << 3)
|
||||
#define CTRL_OUT_EP_SETUP_PHASE_DONE (0x1 << 3)
|
||||
#define AHB_ERROR (0x1 << 2)
|
||||
#define EPDISBLD (0x1 << 1)
|
||||
#define TRANSFER_DONE (0x1 << 0)
|
||||
|
||||
/* Masks definitions */
|
||||
#define GINTMSK_INIT (INT_OUT_EP | INT_IN_EP | INT_RESUME | INT_ENUMDONE\
|
||||
| INT_RESET | INT_SUSPEND)
|
||||
#define DOEPMSK_INIT (CTRL_OUT_EP_SETUP_PHASE_DONE |\
|
||||
AHB_ERROR | TRANSFER_DONE)
|
||||
#define DIEPMSK_INIT (NON_ISO_IN_EP_TIMEOUT | AHB_ERROR | TRANSFER_DONE)
|
||||
#define GAHBCFG_INIT (USBDEVINIT_DMA_EN | USBDEVINIT_GLBL_INTR_EN\
|
||||
| (USBDEVINIT_HBSTLEN_INCR4 <<\
|
||||
USBDEVINIT_HBSTLEN_SHIFT))
|
||||
|
||||
/* INEPTSFSIZ/OUTEPTSFSIZ */
|
||||
#define DXEPTSIZ_MULCNT_SHIFT 29
|
||||
#define DXEPTSIZ_MULCNT_MASK (0x3U << DXEPTSIZ_MULCNT_SHIFT)
|
||||
#define DXEPTSIZ_PKT_CNT_SHIFT 19
|
||||
#define DXEPTSIZ_PKT_CNT_MASK (0x3FFU << DXEPTSIZ_PKT_CNT_SHIFT)
|
||||
#define DXEPTSIZ_XFER_SIZE_SHIFT 0
|
||||
#define DXEPTSIZ_XFER_SIZE_MASK (0x7FFFFU << DXEPTSIZ_XFER_SIZE_SHIFT)
|
||||
|
||||
/* Device Endpoint X Transfer Size Register INEPTSFSIZ() */
|
||||
#define DIEPT_SIZ_PKT_CNT(x) (x << 19)
|
||||
#define DIEPT_SIZ_XFER_SIZE(x) (x << 0)
|
||||
|
||||
/* Device OUT Endpoint X Transfer Size Register OUTEPTSFSIZ() */
|
||||
#define DOEPT_SIZ_PKT_CNT(x) (x << 19)
|
||||
#define DOEPT_SIZ_XFER_SIZE(x) (x << 0)
|
||||
#define DOEPT_SIZ_XFER_SIZE_MAX_EP0 (0x7F << 0)
|
||||
#define DOEPT_SIZ_XFER_SIZE_MAX_EP (0x7FFF << 0)
|
||||
|
||||
/* Device Endpoint-N Control Register INEPCFG()/OUTEPCFG() */
|
||||
#define DIEPCTL_TX_FIFO_NUM(x) (x << 22)
|
||||
#define DIEPCTL_TX_FIFO_NUM_MASK (~DIEPCTL_TX_FIFO_NUM(0xF))
|
||||
|
||||
/* Device ALL Endpoints Interrupt Register (USBEPINT) */
|
||||
#define DAINT_IN_EP_INT(x) (x << 0)
|
||||
#define DAINT_OUT_EP_INT(x) (x << 16)
|
||||
|
||||
#define AIC_EP_FIFO_BASE 0x1000UL
|
||||
#define AIC_EP_FIFO_SIZE 0x1000UL
|
||||
|
||||
/* In EPn Txfifo Status (INEPTXSTS) */
|
||||
#define INEPTXSTS_IN_EP_TXFIFO_STS (0xFFFFU << 0)
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,5 @@
|
||||
# Note
|
||||
|
||||
## Support Chip List
|
||||
|
||||
- BL616/BL808
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,14 @@
|
||||
# Note
|
||||
|
||||
## Support Chip List
|
||||
|
||||
### NXP
|
||||
|
||||
Modify USB_NOCACHE_RAM_SECTION
|
||||
|
||||
```
|
||||
#define USB_NOCACHE_RAM_SECTION __attribute__((section(".NonCacheable")))
|
||||
```
|
||||
|
||||
- IMRT10XX/IMRT11XX (chipidea + EHCI)
|
||||
- MCXN9XX/MCXN236 (chipidea + EHCI)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,729 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2024 HPMicro
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2024, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usbd_core.h"
|
||||
#include "usb_chipidea_reg.h"
|
||||
|
||||
#define USB_OTG_DEV ((CHIPIDEA_TypeDef *)g_usbdev_bus[busid].reg_base)
|
||||
|
||||
#define CHIPIDEA_BITSMASK(val, offset) ((uint32_t)(val) << (offset))
|
||||
#define QTD_COUNT_EACH_ENDPOINT (8U)
|
||||
|
||||
#ifndef CONFIG_USBDEV_EP_NUM
|
||||
#define CONFIG_USBDEV_EP_NUM 8
|
||||
#endif
|
||||
|
||||
/* ENDPTCTRL */
|
||||
enum {
|
||||
ENDPTCTRL_STALL = CHIPIDEA_BITSMASK(1, 0),
|
||||
ENDPTCTRL_TYPE = CHIPIDEA_BITSMASK(3, 2),
|
||||
ENDPTCTRL_TOGGLE_INHIBIT = CHIPIDEA_BITSMASK(1, 5),
|
||||
ENDPTCTRL_TOGGLE_RESET = CHIPIDEA_BITSMASK(1, 6),
|
||||
ENDPTCTRL_ENABLE = CHIPIDEA_BITSMASK(1, 7),
|
||||
};
|
||||
|
||||
/* USBSTS, USBINTR */
|
||||
enum {
|
||||
intr_usb = CHIPIDEA_BITSMASK(1, 0),
|
||||
intr_error = CHIPIDEA_BITSMASK(1, 1),
|
||||
intr_port_change = CHIPIDEA_BITSMASK(1, 2),
|
||||
intr_reset = CHIPIDEA_BITSMASK(1, 6),
|
||||
intr_sof = CHIPIDEA_BITSMASK(1, 7),
|
||||
intr_suspend = CHIPIDEA_BITSMASK(1, 8),
|
||||
intr_nak = CHIPIDEA_BITSMASK(1, 16)
|
||||
};
|
||||
|
||||
/* Queue Transfer Descriptor */
|
||||
typedef struct {
|
||||
/* Word 0: Next QTD Pointer */
|
||||
volatile uint32_t next; /* Next link pointer This field contains the physical memory address of the next dTD to be processed */
|
||||
|
||||
/* Word 1: qTQ Token */
|
||||
volatile uint32_t : 3;
|
||||
volatile uint32_t xact_err : 1;
|
||||
volatile uint32_t : 1;
|
||||
volatile uint32_t buffer_err : 1;
|
||||
volatile uint32_t halted : 1;
|
||||
volatile uint32_t active : 1;
|
||||
volatile uint32_t : 2;
|
||||
volatile uint32_t iso_mult_override : 2; /* This field can be used for transmit ISOs to override the MULT field in the dQH. This field must be zero for all packet types that are not transmit-ISO. */
|
||||
volatile uint32_t : 3;
|
||||
volatile uint32_t int_on_complete : 1;
|
||||
volatile uint32_t total_bytes : 15;
|
||||
volatile uint32_t : 0;
|
||||
|
||||
/* Word 2-6: Buffer Page Pointer List, Each element in the list is a 4K page aligned, physical memory address. The lower 12 bits in each pointer are reserved (except for the first one) as each memory pointer must reference the start of a 4K page */
|
||||
volatile uint32_t buffer[5];
|
||||
|
||||
/*------------- DCD Area -------------*/
|
||||
volatile uint16_t expected_bytes;
|
||||
volatile uint8_t reserved[2];
|
||||
} dcd_qtd_t;
|
||||
|
||||
/* Queue Head */
|
||||
typedef struct {
|
||||
/* Word 0: Capabilities and Characteristics */
|
||||
|
||||
volatile uint32_t : 15; /* Number of packets executed per transaction descriptor 00 - Execute N transactions as demonstrated by the USB variable length protocol where N is computed using Max_packet_length and the Total_bytes field in the dTD. 01 - Execute one transaction 10 - Execute two transactions 11 - Execute three transactions Remark: Non-isochronous endpoints must set MULT = 00. Remark: Isochronous endpoints must set MULT = 01, 10, or 11 as needed. */
|
||||
volatile uint32_t int_on_setup : 1; /* Interrupt on setup This bit is used on control type endpoints to indicate if USBINT is set in response to a setup being received. */
|
||||
volatile uint32_t max_packet_size : 11; /* This directly corresponds to the maximum packet size of the associated endpoint (wMaxPacketSize) */
|
||||
volatile uint32_t : 2;
|
||||
volatile uint32_t zero_length_termination : 1; /* This bit is used for non-isochronous endpoints to indicate when a zero-length packet is received to terminate transfers in case the total transfer length is “multiple”. 0 - Enable zero-length packet to terminate transfers equal to a multiple of Max_packet_length (default). 1 - Disable zero-length packet on transfers that are equal in length to a multiple Max_packet_length. */
|
||||
volatile uint32_t iso_mult : 2;
|
||||
volatile uint32_t : 0;
|
||||
|
||||
/* Word 1: Current qTD Pointer */
|
||||
volatile uint32_t qtd_addr;
|
||||
|
||||
/* Word 2-9: Transfer Overlay */
|
||||
volatile dcd_qtd_t qtd_overlay;
|
||||
|
||||
/* Word 10-11: Setup request (control OUT only) */
|
||||
volatile struct usb_setup_packet setup_request;
|
||||
|
||||
/*--------------------------------------------------------------------
|
||||
* Due to the fact QHD is 64 bytes aligned but occupies only 48 bytes
|
||||
* thus there are 16 bytes padding free that we can make use of.
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
volatile uint8_t reserved[16];
|
||||
} dcd_qhd_t;
|
||||
|
||||
typedef struct {
|
||||
dcd_qhd_t qhd[CONFIG_USBDEV_EP_NUM * 2];
|
||||
dcd_qtd_t qtd[CONFIG_USBDEV_EP_NUM * 2 * QTD_COUNT_EACH_ENDPOINT];
|
||||
} dcd_data_t;
|
||||
|
||||
/* Endpoint state */
|
||||
struct chipidea_ep_state {
|
||||
uint16_t ep_mps; /* Endpoint max packet size */
|
||||
uint8_t ep_type; /* Endpoint type */
|
||||
uint8_t ep_stalled; /* Endpoint stall flag */
|
||||
uint8_t ep_enable; /* Endpoint enable */
|
||||
uint8_t *xfer_buf;
|
||||
uint32_t xfer_len;
|
||||
uint32_t actual_xfer_len;
|
||||
};
|
||||
|
||||
/* Driver state */
|
||||
struct chipidea_udc {
|
||||
dcd_data_t *dcd_data;
|
||||
bool is_suspend;
|
||||
struct chipidea_ep_state in_ep[CONFIG_USBDEV_EP_NUM]; /*!< IN endpoint parameters*/
|
||||
struct chipidea_ep_state out_ep[CONFIG_USBDEV_EP_NUM]; /*!< OUT endpoint parameters */
|
||||
} g_chipidea_udc[CONFIG_USBDEV_MAX_BUS];
|
||||
|
||||
static USB_NOCACHE_RAM_SECTION __attribute__((aligned(2048))) dcd_data_t _dcd_data0;
|
||||
#if CONFIG_USBDEV_MAX_BUS == 2
|
||||
static USB_NOCACHE_RAM_SECTION __attribute__((aligned(2048))) dcd_data_t _dcd_data1;
|
||||
#endif
|
||||
|
||||
static dcd_data_t *g_dcd_data[CONFIG_USBDEV_MAX_BUS] = {
|
||||
&_dcd_data0,
|
||||
#if CONFIG_USBDEV_MAX_BUS == 2
|
||||
&_dcd_data1
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Index to bit position in register */
|
||||
static inline uint8_t ep_idx2bit(uint8_t ep_idx)
|
||||
{
|
||||
return ep_idx / 2 + ((ep_idx % 2) ? 16 : 0);
|
||||
}
|
||||
|
||||
static void __chipidea_bus_reset(CHIPIDEA_TypeDef *ptr)
|
||||
{
|
||||
/* The reset value for all endpoint types is the control endpoint. If one endpoint
|
||||
* direction is enabled and the paired endpoint of opposite direction is disabled, then the
|
||||
* endpoint type of the unused direction must be changed from the control type to any other
|
||||
* type (e.g. bulk). Leaving an un-configured endpoint control will cause undefined behavior
|
||||
* for the data PID tracking on the active endpoint.
|
||||
*/
|
||||
|
||||
for (uint32_t i = 1; i < CONFIG_USBDEV_EP_NUM; i++) {
|
||||
ptr->ENDPTCTRL[i] = USB_ENDPTCTRL_TXT_SET(USB_ENDPOINT_TYPE_BULK) | USB_ENDPTCTRL_RXT_SET(USB_ENDPOINT_TYPE_BULK);
|
||||
}
|
||||
|
||||
/* Clear All Registers */
|
||||
ptr->ENDPTNAK = ptr->ENDPTNAK;
|
||||
ptr->ENDPTNAKEN = 0;
|
||||
ptr->USBSTS = ptr->USBSTS;
|
||||
ptr->ENDPTSETUPSTAT = ptr->ENDPTSETUPSTAT;
|
||||
ptr->ENDPTCOMPLETE = ptr->ENDPTCOMPLETE;
|
||||
|
||||
while (ptr->ENDPTPRIME) {
|
||||
}
|
||||
ptr->ENDPTFLUSH = 0xFFFFFFFF;
|
||||
while (ptr->ENDPTFLUSH) {
|
||||
}
|
||||
}
|
||||
|
||||
static void chipidea_init(CHIPIDEA_TypeDef *ptr)
|
||||
{
|
||||
/* Reset controller */
|
||||
ptr->USBCMD |= USB_USBCMD_RST_MASK;
|
||||
while (USB_USBCMD_RST_GET(ptr->USBCMD)) {
|
||||
}
|
||||
|
||||
/* Set mode to device, must be set immediately after reset */
|
||||
ptr->USBMODE &= ~USB_USBMODE_CM_MASK;
|
||||
ptr->USBMODE |= USB_USBMODE_CM_SET(2);
|
||||
|
||||
/* Disable setup lockout, please refer to "Control Endpoint Operation" section in RM. */
|
||||
ptr->USBMODE &= ~USB_USBMODE_SLOM_MASK;
|
||||
|
||||
/* Set the endian */
|
||||
ptr->USBMODE &= ~USB_USBMODE_ES_MASK;
|
||||
|
||||
/* Set parallel interface signal */
|
||||
ptr->PORTSC1 &= ~USB_PORTSC1_STS_MASK;
|
||||
|
||||
/* Set parallel transceiver width */
|
||||
ptr->PORTSC1 &= ~USB_PORTSC1_PTW_MASK;
|
||||
|
||||
/* Set usb forced to full speed mode */
|
||||
//ptr->PORTSC1 |= USB_PORTSC1_PFSC_MASK;
|
||||
|
||||
/* Not use interrupt threshold. */
|
||||
ptr->USBCMD &= ~USB_USBCMD_ITC_MASK;
|
||||
|
||||
/* Enable VBUS discharge */
|
||||
ptr->OTGSC |= USB_OTGSC_VD_MASK;
|
||||
}
|
||||
|
||||
static void chipidea_deinit(CHIPIDEA_TypeDef *ptr)
|
||||
{
|
||||
/* Stop */
|
||||
ptr->USBCMD &= ~USB_USBCMD_RS_MASK;
|
||||
|
||||
/* Reset controller */
|
||||
ptr->USBCMD |= USB_USBCMD_RST_MASK;
|
||||
while (USB_USBCMD_RST_GET(ptr->USBCMD)) {
|
||||
}
|
||||
|
||||
/* Reset endpoint list address register */
|
||||
ptr->ENDPTLISTADDR = 0;
|
||||
|
||||
/* Reset status register */
|
||||
ptr->USBSTS = ptr->USBSTS;
|
||||
|
||||
/* Reset interrupt enable register */
|
||||
ptr->USBINTR = 0;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
* Endpoint API
|
||||
*---------------------------------------------------------------------
|
||||
*/
|
||||
static void __chipidea_edpt_open(CHIPIDEA_TypeDef *ptr, uint8_t ep_addr, uint8_t ep_type)
|
||||
{
|
||||
uint8_t const epnum = ep_addr & 0x0f;
|
||||
uint8_t const dir = (ep_addr & 0x80) >> 7;
|
||||
|
||||
/* Enable EP Control */
|
||||
uint32_t temp = ptr->ENDPTCTRL[epnum];
|
||||
temp &= ~((0x03 << 2) << (dir ? 16 : 0));
|
||||
temp |= ((ep_type << 2) | ENDPTCTRL_ENABLE | ENDPTCTRL_TOGGLE_RESET) << (dir ? 16 : 0);
|
||||
ptr->ENDPTCTRL[epnum] = temp;
|
||||
}
|
||||
|
||||
static void chipidea_edpt_xfer(CHIPIDEA_TypeDef *ptr, uint8_t ep_idx)
|
||||
{
|
||||
uint32_t offset = ep_idx / 2 + ((ep_idx % 2) ? 16 : 0);
|
||||
|
||||
/* Start transfer */
|
||||
ptr->ENDPTPRIME = 1 << offset;
|
||||
}
|
||||
|
||||
static void chipidea_edpt_stall(CHIPIDEA_TypeDef *ptr, uint8_t ep_addr)
|
||||
{
|
||||
uint8_t const epnum = ep_addr & 0x0f;
|
||||
uint8_t const dir = (ep_addr & 0x80) >> 7;
|
||||
|
||||
ptr->ENDPTCTRL[epnum] |= ENDPTCTRL_STALL << (dir ? 16 : 0);
|
||||
}
|
||||
|
||||
static void chipidea_edpt_clear_stall(CHIPIDEA_TypeDef *ptr, uint8_t ep_addr)
|
||||
{
|
||||
uint8_t const epnum = ep_addr & 0x0f;
|
||||
uint8_t const dir = (ep_addr & 0x80) >> 7;
|
||||
|
||||
/* data toggle also need to be reset */
|
||||
ptr->ENDPTCTRL[epnum] |= ENDPTCTRL_TOGGLE_RESET << (dir ? 16 : 0);
|
||||
ptr->ENDPTCTRL[epnum] &= ~(ENDPTCTRL_STALL << (dir ? 16 : 0));
|
||||
}
|
||||
|
||||
static bool chipidea_edpt_check_stall(CHIPIDEA_TypeDef *ptr, uint8_t ep_addr)
|
||||
{
|
||||
uint8_t const epnum = ep_addr & 0x0f;
|
||||
uint8_t const dir = (ep_addr & 0x80) >> 7;
|
||||
|
||||
return (ptr->ENDPTCTRL[epnum] & (ENDPTCTRL_STALL << (dir ? 16 : 0))) ? true : false;
|
||||
}
|
||||
|
||||
static void chipidea_edpt_close(CHIPIDEA_TypeDef *ptr, uint8_t ep_addr)
|
||||
{
|
||||
uint8_t const epnum = ep_addr & 0x0f;
|
||||
uint8_t const dir = (ep_addr & 0x80) >> 7;
|
||||
|
||||
uint32_t primebit = CHIPIDEA_BITSMASK(1, epnum) << (dir ? 16 : 0);
|
||||
|
||||
/* Flush the endpoint to stop a transfer. */
|
||||
do {
|
||||
/* Set the corresponding bit(s) in the ENDPTFLUSH register */
|
||||
ptr->ENDPTFLUSH |= primebit;
|
||||
|
||||
/* Wait until all bits in the ENDPTFLUSH register are cleared. */
|
||||
while (0U != (ptr->ENDPTFLUSH & primebit)) {
|
||||
}
|
||||
/*
|
||||
* Read the ENDPTSTAT register to ensure that for all endpoints
|
||||
* commanded to be flushed, that the corresponding bits
|
||||
* are now cleared.
|
||||
*/
|
||||
} while (0U != (ptr->ENDPTSTAT & primebit));
|
||||
|
||||
/* Disable the endpoint */
|
||||
ptr->ENDPTCTRL[epnum] &= ~((ENDPTCTRL_TYPE | ENDPTCTRL_ENABLE | ENDPTCTRL_STALL) << (dir ? 16 : 0));
|
||||
ptr->ENDPTCTRL[epnum] |= (USB_ENDPOINT_TYPE_BULK << 2) << (dir ? 16 : 0);
|
||||
}
|
||||
|
||||
/* Initialize qtd */
|
||||
static void usb_qtd_init(dcd_qtd_t *p_qtd, void *data_ptr, uint16_t total_bytes)
|
||||
{
|
||||
memset(p_qtd, 0, sizeof(dcd_qtd_t));
|
||||
|
||||
p_qtd->next = 1;
|
||||
p_qtd->active = 1;
|
||||
p_qtd->total_bytes = p_qtd->expected_bytes = total_bytes;
|
||||
|
||||
if (data_ptr != NULL) {
|
||||
p_qtd->buffer[0] = (uint32_t)data_ptr;
|
||||
for (uint8_t i = 1; i < 5; i++) {
|
||||
p_qtd->buffer[i] = ((p_qtd->buffer[i - 1]) & 0xFFFFF000UL) + 4096U;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static dcd_qhd_t *chipidea_qhd_get(uint8_t busid, uint8_t ep_idx)
|
||||
{
|
||||
dcd_data_t *dcd_data;
|
||||
|
||||
dcd_data = g_chipidea_udc[busid].dcd_data;
|
||||
return &dcd_data->qhd[ep_idx];
|
||||
}
|
||||
|
||||
static dcd_qtd_t *chipidea_qtd_get(uint8_t busid, uint8_t ep_idx)
|
||||
{
|
||||
dcd_data_t *dcd_data;
|
||||
|
||||
dcd_data = g_chipidea_udc[busid].dcd_data;
|
||||
return &dcd_data->qtd[ep_idx * QTD_COUNT_EACH_ENDPOINT];
|
||||
}
|
||||
|
||||
static void chipidea_bus_reset(uint8_t busid, uint16_t ep0_max_packet_size)
|
||||
{
|
||||
dcd_data_t *dcd_data;
|
||||
|
||||
dcd_data = g_chipidea_udc[busid].dcd_data;
|
||||
__chipidea_bus_reset(USB_OTG_DEV);
|
||||
|
||||
/* Queue Head & Queue TD */
|
||||
memset(dcd_data, 0, sizeof(dcd_data_t));
|
||||
|
||||
/* Set up Control Endpoints (0 OUT, 1 IN) */
|
||||
dcd_data->qhd[0].zero_length_termination = dcd_data->qhd[1].zero_length_termination = 1;
|
||||
dcd_data->qhd[0].max_packet_size = dcd_data->qhd[1].max_packet_size = ep0_max_packet_size;
|
||||
dcd_data->qhd[0].qtd_overlay.next = dcd_data->qhd[1].qtd_overlay.next = 1;
|
||||
|
||||
/* OUT only */
|
||||
dcd_data->qhd[0].int_on_setup = 1;
|
||||
}
|
||||
|
||||
static void chipidea_edpt_open(uint8_t busid, uint8_t ep_addr, uint8_t ep_type, uint16_t ep_mps)
|
||||
{
|
||||
uint8_t const epnum = ep_addr & 0x0f;
|
||||
uint8_t const dir = (ep_addr & 0x80) >> 7;
|
||||
uint8_t const ep_idx = 2 * epnum + dir;
|
||||
dcd_data_t *dcd_data;
|
||||
dcd_qhd_t *p_qhd;
|
||||
|
||||
/* Prepare Queue Head */
|
||||
dcd_data = g_chipidea_udc[busid].dcd_data;
|
||||
p_qhd = &dcd_data->qhd[ep_idx];
|
||||
memset(p_qhd, 0, sizeof(dcd_qhd_t));
|
||||
|
||||
p_qhd->zero_length_termination = 1;
|
||||
p_qhd->max_packet_size = ep_mps & 0x7FFu;
|
||||
p_qhd->qtd_overlay.next = 1;
|
||||
if (ep_type == USB_ENDPOINT_TYPE_ISOCHRONOUS) {
|
||||
p_qhd->iso_mult = ((ep_mps >> 11u) & 0x3u) + 1u;
|
||||
}
|
||||
|
||||
__chipidea_edpt_open(USB_OTG_DEV, ep_addr, ep_type);
|
||||
}
|
||||
|
||||
static bool chipidea_start_xfer(uint8_t busid, uint8_t ep_addr, uint8_t *buffer, uint32_t total_bytes)
|
||||
{
|
||||
uint8_t const epnum = ep_addr & 0x0f;
|
||||
uint8_t const dir = (ep_addr & 0x80) >> 7;
|
||||
uint8_t const ep_idx = 2 * epnum + dir;
|
||||
uint8_t qtd_num;
|
||||
uint8_t i;
|
||||
uint32_t xfer_len;
|
||||
dcd_qhd_t *p_qhd;
|
||||
dcd_qtd_t *p_qtd;
|
||||
dcd_qtd_t *first_p_qtd = NULL;
|
||||
dcd_qtd_t *prev_p_qtd = NULL;
|
||||
dcd_data_t *dcd_data;
|
||||
|
||||
dcd_data = g_chipidea_udc[busid].dcd_data;
|
||||
|
||||
if (epnum == 0) {
|
||||
/* follows UM Setup packet handling using setup lockout mechanism
|
||||
* wait until ENDPTSETUPSTAT before priming data/status in response TODO add time out
|
||||
*/
|
||||
while (USB_OTG_DEV->ENDPTSETUPSTAT & CHIPIDEA_BITSMASK(1, 0)) {
|
||||
}
|
||||
}
|
||||
|
||||
qtd_num = (total_bytes + 0x3fff) / 0x4000;
|
||||
if (qtd_num > QTD_COUNT_EACH_ENDPOINT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (buffer != NULL) {
|
||||
buffer = (uint8_t *)buffer;
|
||||
}
|
||||
p_qhd = &dcd_data->qhd[ep_idx];
|
||||
i = 0;
|
||||
do {
|
||||
p_qtd = &dcd_data->qtd[ep_idx * QTD_COUNT_EACH_ENDPOINT + i];
|
||||
i++;
|
||||
|
||||
if (total_bytes > 0x4000) {
|
||||
xfer_len = 0x4000;
|
||||
total_bytes -= 0x4000;
|
||||
} else {
|
||||
xfer_len = total_bytes;
|
||||
total_bytes = 0;
|
||||
}
|
||||
|
||||
usb_qtd_init(p_qtd, (void *)buffer, xfer_len);
|
||||
if (total_bytes == 0) {
|
||||
p_qtd->int_on_complete = true;
|
||||
}
|
||||
buffer += xfer_len;
|
||||
|
||||
if (prev_p_qtd) {
|
||||
prev_p_qtd->next = (uint32_t)p_qtd;
|
||||
} else {
|
||||
first_p_qtd = p_qtd;
|
||||
}
|
||||
prev_p_qtd = p_qtd;
|
||||
} while (total_bytes > 0);
|
||||
|
||||
p_qhd->qtd_overlay.next = (uint32_t)first_p_qtd; /* link qtd to qhd */
|
||||
|
||||
chipidea_edpt_xfer(USB_OTG_DEV, ep_idx);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
__WEAK void usb_dc_low_level_init(uint8_t busid)
|
||||
{
|
||||
}
|
||||
|
||||
__WEAK void usb_dc_low_level_deinit(uint8_t busid)
|
||||
{
|
||||
}
|
||||
|
||||
int usb_dc_init(uint8_t busid)
|
||||
{
|
||||
uint32_t int_mask;
|
||||
int_mask = (USB_USBINTR_UE_MASK | USB_USBINTR_UEE_MASK | USB_USBINTR_SLE_MASK |
|
||||
USB_USBINTR_PCE_MASK | USB_USBINTR_URE_MASK);
|
||||
|
||||
usb_dc_low_level_init(busid);
|
||||
|
||||
memset(&g_chipidea_udc[busid], 0, sizeof(struct chipidea_udc));
|
||||
g_chipidea_udc[busid].dcd_data = g_dcd_data[busid];
|
||||
memset(g_chipidea_udc[busid].dcd_data, 0, sizeof(dcd_data_t));
|
||||
|
||||
chipidea_init(USB_OTG_DEV);
|
||||
|
||||
/* Set endpoint list address */
|
||||
USB_OTG_DEV->ENDPTLISTADDR = ((uint32_t)g_chipidea_udc[busid].dcd_data->qhd) & USB_ENDPTLISTADDR_EPBASE_MASK;
|
||||
|
||||
/* Clear status */
|
||||
USB_OTG_DEV->USBSTS = USB_OTG_DEV->USBSTS;
|
||||
|
||||
#ifdef CONFIG_USBDEV_SOF_ENABLE
|
||||
int_mask |= USB_USBINTR_SRE_MASK;
|
||||
#endif
|
||||
|
||||
/* Enable interrupt mask */
|
||||
USB_OTG_DEV->USBINTR |= int_mask;
|
||||
|
||||
/* Connect by enabling internal pull-up resistor on D+/D- */
|
||||
USB_OTG_DEV->USBCMD |= USB_USBCMD_RS_MASK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_dc_deinit(uint8_t busid)
|
||||
{
|
||||
chipidea_deinit(USB_OTG_DEV);
|
||||
|
||||
for (uint32_t i = 0; i < CONFIG_USBDEV_EP_NUM; i++) {
|
||||
chipidea_edpt_close(USB_OTG_DEV, (i | 0x80));
|
||||
chipidea_edpt_close(USB_OTG_DEV, (i | 0x00));
|
||||
}
|
||||
|
||||
usb_dc_low_level_deinit(busid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_set_address(uint8_t busid, const uint8_t addr)
|
||||
{
|
||||
USB_OTG_DEV->DEVICEADDR = USB_DEVICEADDR_USBADR_SET(addr) | USB_DEVICEADDR_USBADRA_MASK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_set_remote_wakeup(uint8_t busid)
|
||||
{
|
||||
if (!USB_PORTSC1_SUSP_GET(USB_OTG_DEV->PORTSC1)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
USB_OTG_DEV->PORTSC1 |= USB_PORTSC1_FPR_MASK;
|
||||
while (USB_OTG_DEV->PORTSC1 & USB_PORTSC1_FPR_MASK) {
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t usbd_get_port_speed(uint8_t busid)
|
||||
{
|
||||
uint8_t speed;
|
||||
|
||||
speed = USB_PORTSC1_PSPD_GET(USB_OTG_DEV->PORTSC1);
|
||||
|
||||
if (speed == 0x00) {
|
||||
return USB_SPEED_FULL;
|
||||
}
|
||||
if (speed == 0x01) {
|
||||
return USB_SPEED_LOW;
|
||||
}
|
||||
if (speed == 0x02) {
|
||||
return USB_SPEED_HIGH;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_open(uint8_t busid, const struct usb_endpoint_descriptor *ep)
|
||||
{
|
||||
uint8_t ep_idx = USB_EP_GET_IDX(ep->bEndpointAddress);
|
||||
|
||||
USB_ASSERT_MSG(ep_idx < CONFIG_USBDEV_EP_NUM, "Ep addr %02x overflow", ep->bEndpointAddress);
|
||||
|
||||
chipidea_edpt_open(busid, ep->bEndpointAddress, USB_GET_ENDPOINT_TYPE(ep->bmAttributes), ep->wMaxPacketSize);
|
||||
|
||||
if (USB_EP_DIR_IS_OUT(ep->bEndpointAddress)) {
|
||||
g_chipidea_udc[busid].out_ep[ep_idx].ep_mps = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
|
||||
g_chipidea_udc[busid].out_ep[ep_idx].ep_type = USB_GET_ENDPOINT_TYPE(ep->bmAttributes);
|
||||
g_chipidea_udc[busid].out_ep[ep_idx].ep_enable = true;
|
||||
} else {
|
||||
g_chipidea_udc[busid].in_ep[ep_idx].ep_mps = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
|
||||
g_chipidea_udc[busid].in_ep[ep_idx].ep_type = USB_GET_ENDPOINT_TYPE(ep->bmAttributes);
|
||||
g_chipidea_udc[busid].in_ep[ep_idx].ep_enable = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_close(uint8_t busid, const uint8_t ep)
|
||||
{
|
||||
uint8_t ep_idx = USB_EP_GET_IDX(ep);
|
||||
|
||||
if (USB_EP_DIR_IS_OUT(ep)) {
|
||||
g_chipidea_udc[busid].out_ep[ep_idx].ep_enable = false;
|
||||
} else {
|
||||
g_chipidea_udc[busid].in_ep[ep_idx].ep_enable = false;
|
||||
}
|
||||
|
||||
chipidea_edpt_close(USB_OTG_DEV, ep);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_set_stall(uint8_t busid, const uint8_t ep)
|
||||
{
|
||||
chipidea_edpt_stall(USB_OTG_DEV, ep);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_clear_stall(uint8_t busid, const uint8_t ep)
|
||||
{
|
||||
chipidea_edpt_clear_stall(USB_OTG_DEV, ep);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_is_stalled(uint8_t busid, const uint8_t ep, uint8_t *stalled)
|
||||
{
|
||||
*stalled = chipidea_edpt_check_stall(USB_OTG_DEV, ep);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_start_write(uint8_t busid, const uint8_t ep, const uint8_t *data, uint32_t data_len)
|
||||
{
|
||||
uint8_t ep_idx = USB_EP_GET_IDX(ep);
|
||||
|
||||
if (!data && data_len) {
|
||||
return -1;
|
||||
}
|
||||
if (!g_chipidea_udc[busid].in_ep[ep_idx].ep_enable) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
g_chipidea_udc[busid].in_ep[ep_idx].xfer_buf = (uint8_t *)data;
|
||||
g_chipidea_udc[busid].in_ep[ep_idx].xfer_len = data_len;
|
||||
g_chipidea_udc[busid].in_ep[ep_idx].actual_xfer_len = 0;
|
||||
|
||||
chipidea_start_xfer(busid, ep, (uint8_t *)data, data_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_start_read(uint8_t busid, const uint8_t ep, uint8_t *data, uint32_t data_len)
|
||||
{
|
||||
uint8_t ep_idx = USB_EP_GET_IDX(ep);
|
||||
|
||||
if (!data && data_len) {
|
||||
return -1;
|
||||
}
|
||||
if (!g_chipidea_udc[busid].out_ep[ep_idx].ep_enable) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
g_chipidea_udc[busid].out_ep[ep_idx].xfer_buf = (uint8_t *)data;
|
||||
g_chipidea_udc[busid].out_ep[ep_idx].xfer_len = data_len;
|
||||
g_chipidea_udc[busid].out_ep[ep_idx].actual_xfer_len = 0;
|
||||
|
||||
chipidea_start_xfer(busid, ep, data, data_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void USBD_IRQHandler(uint8_t busid)
|
||||
{
|
||||
uint32_t int_status;
|
||||
uint32_t transfer_len;
|
||||
bool ep_cb_req;
|
||||
|
||||
/* Acknowledge handled interrupt */
|
||||
int_status = USB_OTG_DEV->USBSTS;
|
||||
int_status &= USB_OTG_DEV->USBINTR;
|
||||
USB_OTG_DEV->USBSTS = int_status;
|
||||
|
||||
if (int_status & intr_error) {
|
||||
USB_LOG_ERR("usbd intr error!\r\n");
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USBDEV_SOF_ENABLE
|
||||
if (int_status & intr_sof) {
|
||||
usbd_event_sof_handler(busid);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (int_status & intr_reset) {
|
||||
g_chipidea_udc[busid].is_suspend = false;
|
||||
memset(g_chipidea_udc[busid].in_ep, 0, sizeof(struct chipidea_ep_state) * CONFIG_USBDEV_EP_NUM);
|
||||
memset(g_chipidea_udc[busid].out_ep, 0, sizeof(struct chipidea_ep_state) * CONFIG_USBDEV_EP_NUM);
|
||||
usbd_event_reset_handler(busid);
|
||||
chipidea_bus_reset(busid, 64);
|
||||
}
|
||||
|
||||
if (int_status & intr_suspend) {
|
||||
if (USB_PORTSC1_SUSP_GET(USB_OTG_DEV->PORTSC1)) {
|
||||
/* Note: Host may delay more than 3 ms before and/or after bus reset before doing enumeration. */
|
||||
if (USB_DEVICEADDR_USBADR_GET(USB_OTG_DEV->DEVICEADDR)) {
|
||||
g_chipidea_udc[busid].is_suspend = true;
|
||||
usbd_event_suspend_handler(busid);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
}
|
||||
|
||||
if (int_status & intr_port_change) {
|
||||
if (!USB_PORTSC1_CCS_GET(USB_OTG_DEV->PORTSC1)) {
|
||||
usbd_event_disconnect_handler(busid);
|
||||
} else {
|
||||
if (g_chipidea_udc[busid].is_suspend) {
|
||||
g_chipidea_udc[busid].is_suspend = false;
|
||||
usbd_event_resume_handler(busid);
|
||||
}
|
||||
usbd_event_connect_handler(busid);
|
||||
}
|
||||
}
|
||||
|
||||
if (int_status & intr_usb) {
|
||||
uint32_t const edpt_complete = USB_OTG_DEV->ENDPTCOMPLETE;
|
||||
uint32_t edpt_setup_status = USB_OTG_DEV->ENDPTSETUPSTAT;
|
||||
|
||||
if (edpt_complete) {
|
||||
USB_OTG_DEV->ENDPTCOMPLETE = edpt_complete;
|
||||
for (uint8_t ep_idx = 0; ep_idx < (CONFIG_USBDEV_EP_NUM * 2); ep_idx++) {
|
||||
if (edpt_complete & (1 << ep_idx2bit(ep_idx))) {
|
||||
transfer_len = 0;
|
||||
ep_cb_req = true;
|
||||
|
||||
/* Failed QTD also get ENDPTCOMPLETE set */
|
||||
dcd_qtd_t *p_qtd = chipidea_qtd_get(busid, ep_idx);
|
||||
while (1) {
|
||||
if (p_qtd->halted || p_qtd->xact_err || p_qtd->buffer_err) {
|
||||
USB_LOG_ERR("usbd transfer error!\r\n");
|
||||
ep_cb_req = false;
|
||||
break;
|
||||
} else if (p_qtd->active) {
|
||||
ep_cb_req = false;
|
||||
break;
|
||||
} else {
|
||||
transfer_len += p_qtd->expected_bytes - p_qtd->total_bytes;
|
||||
}
|
||||
|
||||
if (p_qtd->next == 1) {
|
||||
break;
|
||||
} else {
|
||||
p_qtd = (dcd_qtd_t *)p_qtd->next;
|
||||
}
|
||||
}
|
||||
|
||||
if (ep_cb_req) {
|
||||
uint8_t const ep_addr = (ep_idx / 2) | ((ep_idx & 0x01) ? 0x80 : 0);
|
||||
if (ep_addr & 0x80) {
|
||||
usbd_event_ep_in_complete_handler(busid, ep_addr, transfer_len);
|
||||
} else {
|
||||
usbd_event_ep_out_complete_handler(busid, ep_addr, transfer_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (edpt_setup_status) {
|
||||
/*------------- Set up Received -------------*/
|
||||
USB_OTG_DEV->ENDPTSETUPSTAT = edpt_setup_status;
|
||||
dcd_qhd_t *qhd0 = chipidea_qhd_get(busid, 0);
|
||||
usbd_event_ep0_setup_complete_handler(busid, (uint8_t *)&qhd0->setup_request);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
# Note
|
||||
|
||||
Please note that host must support dma mode.
|
||||
|
||||
## Support Chip List
|
||||
|
||||
### STM32
|
||||
|
||||
**有且仅有 PB14/PB15 引脚支持 host 模式, 部分 F7/H7 可能 PA11/PA12 也支持**。
|
||||
|
||||
- STM32F105xc、STM32F107xc
|
||||
- STM32F205xx、STM32F207xx、STM32F215xx、STM32F217xx
|
||||
- STM32F401xc、STM32F401xe、STM32F405xx、STM32F407xx、STM32F411xe、STM32F412cx、STM32F412rx、STM32F412vx、STM32F412zx、STM32F413xx、STM32F415xx、STM32F417xx、STM32F423xx、STM32F423xx、STM32F429xx、STM32F437xx、STM32F439xx、STM32F446xx、STM32F469xx、STM32F479xx
|
||||
- STM32F7xx
|
||||
- STM32H7xx
|
||||
- STM32L4xx
|
||||
- STM32U5xx
|
||||
|
||||
### AT32
|
||||
|
||||
**有且仅有 AT32F405xx PB14/PB15引脚支持 host 模式**。
|
||||
|
||||
- AT32F402xx、AT32F405xx、AT32F415xx、AT32F423xx、AT32F425xx、AT32F435xx、AT32F437xx
|
||||
|
||||
### GD32
|
||||
|
||||
**由于无法读取 DWC2 配置信息,并且有部分寄存器是非标准的,因此暂时无法支持 GD 系列**。
|
||||
|
||||
- GD32F30X_CL
|
||||
- GD32F405、GD32F407
|
||||
- GD32F350、GD32F450
|
||||
|
||||
### HC32
|
||||
|
||||
- HC32F4A0
|
||||
|
||||
### Espressif
|
||||
|
||||
- ESP32S2、ESP32S3、ESP32P4
|
||||
|
||||
### Sophgo
|
||||
|
||||
- CV18xx
|
||||
|
||||
### Kendryte
|
||||
|
||||
- K230
|
||||
|
||||
### Nationstech
|
||||
|
||||
- N32H4X
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,367 @@
|
||||
/*
|
||||
* Copyright (c) 2025, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef __USB_DWC2_PARAM_H__
|
||||
#define __USB_DWC2_PARAM_H__
|
||||
|
||||
/* Maximum number of Endpoints/HostChannels */
|
||||
#define MAX_EPS_CHANNELS 16
|
||||
|
||||
#define HSOTG_REG(x) (x)
|
||||
|
||||
#define dwc2_readl(addr) \
|
||||
(*(volatile uint32_t *)(addr))
|
||||
|
||||
#define GUID_OFFSET HSOTG_REG(0x003C)
|
||||
|
||||
#define GSNPSID_OFFSET HSOTG_REG(0x0040)
|
||||
#define GSNPSID_ID_MASK (0xFFFF0000UL)
|
||||
|
||||
#define GHWCFG1_OFFSET HSOTG_REG(0x0044)
|
||||
|
||||
#define GHWCFG2_OFFSET HSOTG_REG(0x0048)
|
||||
#define GHWCFG2_OTG_ENABLE_IC_USB (0x01UL << 31U)
|
||||
#define GHWCFG2_DEV_TOKEN_Q_DEPTH_MASK (0x1FUL << 26U)
|
||||
#define GHWCFG2_DEV_TOKEN_Q_DEPTH_SHIFT (26U)
|
||||
#define GHWCFG2_HOST_PERIO_TX_Q_DEPTH_MASK (0x03UL << 24U)
|
||||
#define GHWCFG2_HOST_PERIO_TX_Q_DEPTH_SHIFT (24U)
|
||||
#define GHWCFG2_NONPERIO_TX_Q_DEPTH_MASK (0x03UL << 22U)
|
||||
#define GHWCFG2_NONPERIO_TX_Q_DEPTH_SHIFT (22U)
|
||||
#define GHWCFG2_MULTI_PROC_INT (0x01UL << 20U)
|
||||
#define GHWCFG2_DYNAMIC_FIFO (0x01UL << 19U)
|
||||
#define GHWCFG2_PERIO_EP_SUPPORTED (0x01UL << 18U)
|
||||
#define GHWCFG2_NUM_HOST_CHAN_MASK (0x0FUL << 14U)
|
||||
#define GHWCFG2_NUM_HOST_CHAN_SHIFT (14U)
|
||||
#define GHWCFG2_NUM_DEV_EP_MASK (0x0FUL << 10U)
|
||||
#define GHWCFG2_NUM_DEV_EP_SHIFT (10U)
|
||||
#define GHWCFG2_FS_PHY_TYPE_MASK (0x03UL << 8U)
|
||||
#define GHWCFG2_FS_PHY_TYPE_SHIFT (8U)
|
||||
#define GHWCFG2_FS_PHY_TYPE_NOT_SUPPORTED (0x00UL)
|
||||
#define GHWCFG2_FS_PHY_TYPE_DEDICATED (0x01UL)
|
||||
#define GHWCFG2_FS_PHY_TYPE_SHARED_UTMI (0x02UL)
|
||||
#define GHWCFG2_FS_PHY_TYPE_SHARED_ULPI (0x03UL)
|
||||
#define GHWCFG2_HS_PHY_TYPE_MASK (0x03UL << 6U)
|
||||
#define GHWCFG2_HS_PHY_TYPE_SHIFT (6U)
|
||||
#define GHWCFG2_HS_PHY_TYPE_NOT_SUPPORTED (0x00UL)
|
||||
#define GHWCFG2_HS_PHY_TYPE_UTMI (0x01UL)
|
||||
#define GHWCFG2_HS_PHY_TYPE_ULPI (0x02UL)
|
||||
#define GHWCFG2_HS_PHY_TYPE_UTMI_ULPI (0x03UL)
|
||||
#define GHWCFG2_POINT2POINT (0x01UL << 5U)
|
||||
#define GHWCFG2_ARCHITECTURE_MASK (0x03UL << 3U)
|
||||
#define GHWCFG2_ARCHITECTURE_SHIFT (3U)
|
||||
#define GHWCFG2_SLAVE_ONLY_ARCH (0x00UL)
|
||||
#define GHWCFG2_EXT_DMA_ARCH (0x01UL)
|
||||
#define GHWCFG2_INT_DMA_ARCH (0x02UL)
|
||||
#define GHWCFG2_OP_MODE_MASK (0x07UL << 0U)
|
||||
#define GHWCFG2_OP_MODE_SHIFT (0U)
|
||||
#define GHWCFG2_OP_MODE_HNP_SRP_CAPABLE (0x00UL)
|
||||
#define GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE (0x01UL)
|
||||
#define GHWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE (0x02UL)
|
||||
#define GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE (0x03UL)
|
||||
#define GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE (0x04UL)
|
||||
#define GHWCFG2_OP_MODE_SRP_CAPABLE_HOST (0x05UL)
|
||||
#define GHWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST (0x06UL)
|
||||
#define GHWCFG2_OP_MODE_UNDEFINED (0x07UL)
|
||||
|
||||
#define GHWCFG3_OFFSET HSOTG_REG(0x004C)
|
||||
#define GHWCFG3_DFIFO_DEPTH_MASK (0xFFFFUL << 16U)
|
||||
#define GHWCFG3_DFIFO_DEPTH_SHIFT (16U)
|
||||
#define GHWCFG3_OTG_LPM_EN (0x0001UL << 15U)
|
||||
#define GHWCFG3_BC_SUPPORT (0x0001UL << 14U)
|
||||
#define GHWCFG3_OTG_ENABLE_HSIC (0x0001UL << 13U)
|
||||
#define GHWCFG3_ADP_SUPP (0x0001UL << 12U)
|
||||
#define GHWCFG3_SYNCH_RESET_TYPE (0x0001UL << 11U)
|
||||
#define GHWCFG3_OPTIONAL_FEATURES (0x0001UL << 10U)
|
||||
#define GHWCFG3_VENDOR_CTRL_IF (0x0001UL << 9U)
|
||||
#define GHWCFG3_I2C (0x0001UL << 8U)
|
||||
#define GHWCFG3_OTG_FUNC (0x0001UL << 7U)
|
||||
#define GHWCFG3_PACKET_SIZE_CNTR_WIDTH_MASK (0x0007UL << 4U)
|
||||
#define GHWCFG3_PACKET_SIZE_CNTR_WIDTH_SHIFT (4U)
|
||||
#define GHWCFG3_XFER_SIZE_CNTR_WIDTH_MASK (0x000FUL << 0U)
|
||||
#define GHWCFG3_XFER_SIZE_CNTR_WIDTH_SHIFT (0U)
|
||||
|
||||
#define GHWCFG4_OFFSET HSOTG_REG(0x0050)
|
||||
#define GHWCFG4_DESC_DMA_DYN (0x1UL << 31U)
|
||||
#define GHWCFG4_DESC_DMA (0x1UL << 30U)
|
||||
#define GHWCFG4_NUM_IN_EPS_MASK (0xFUL << 26U)
|
||||
#define GHWCFG4_NUM_IN_EPS_SHIFT (26U)
|
||||
#define GHWCFG4_DED_FIFO_EN (0x1UL << 25U)
|
||||
#define GHWCFG4_DED_FIFO_SHIFT (25U)
|
||||
#define GHWCFG4_SESSION_END_FILT_EN (0x1UL << 24U)
|
||||
#define GHWCFG4_B_VALID_FILT_EN (0x1UL << 23U)
|
||||
#define GHWCFG4_A_VALID_FILT_EN (0x1UL << 22U)
|
||||
#define GHWCFG4_VBUS_VALID_FILT_EN (0x1UL << 21U)
|
||||
#define GHWCFG4_IDDIG_FILT_EN (0x1UL << 20U)
|
||||
#define GHWCFG4_NUM_DEV_MODE_CTRL_EP_MASK (0xFUL << 16U)
|
||||
#define GHWCFG4_NUM_DEV_MODE_CTRL_EP_SHIFT (16U)
|
||||
#define GHWCFG4_UTMI_PHY_DATA_WIDTH_MASK (0x3UL << 14U)
|
||||
#define GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT (14U)
|
||||
#define GHWCFG4_UTMI_PHY_DATA_WIDTH_8 (0x0UL)
|
||||
#define GHWCFG4_UTMI_PHY_DATA_WIDTH_16 (0x1UL)
|
||||
#define GHWCFG4_UTMI_PHY_DATA_WIDTH_8_OR_16 (0x2UL)
|
||||
#define GHWCFG4_ACG_SUPPORTED (0x1UL << 12U)
|
||||
#define GHWCFG4_IPG_ISOC_SUPPORTED (0x1UL << 11U)
|
||||
#define GHWCFG4_SERVICE_INTERVAL_SUPPORTED (0x1UL << 10U)
|
||||
#define GHWCFG4_XHIBER (0x1UL << 7U)
|
||||
#define GHWCFG4_HIBER (0x1UL << 6U)
|
||||
#define GHWCFG4_MIN_AHB_FREQ (0x1UL << 5U)
|
||||
#define GHWCFG4_POWER_OPTIMIZ (0x1UL << 4U)
|
||||
#define GHWCFG4_NUM_DEV_PERIO_IN_EP_MASK (0xFUL << 0U)
|
||||
#define GHWCFG4_NUM_DEV_PERIO_IN_EP_SHIFT (0U)
|
||||
|
||||
/**
|
||||
* struct dwc2_hw_params - Autodetected parameters.
|
||||
*
|
||||
* These parameters are the various parameters read from hardware
|
||||
* registers during initialization. They typically contain the best
|
||||
* supported or maximum value that can be configured in the
|
||||
* corresponding dwc2_core_params value.
|
||||
*
|
||||
* The values that are not in dwc2_core_params are documented below.
|
||||
*
|
||||
* @snpsid: Value from SNPSID register
|
||||
* @dev_ep_dirs: Direction of device endpoints (GHWCFG1)
|
||||
*
|
||||
* @op_mode: Mode of Operation
|
||||
* 0 - HNP- and SRP-Capable OTG (Host & Device)
|
||||
* 1 - SRP-Capable OTG (Host & Device)
|
||||
* 2 - Non-HNP and Non-SRP Capable OTG (Host & Device)
|
||||
* 3 - SRP-Capable Device
|
||||
* 4 - Non-OTG Device
|
||||
* 5 - SRP-Capable Host
|
||||
* 6 - Non-OTG Host
|
||||
* @arch: Architecture
|
||||
* 0 - Slave only
|
||||
* 1 - External DMA
|
||||
* 2 - Internal DMA
|
||||
* @enable_dynamic_fifo: 0 - Use coreConsultant-specified FIFO size parameters
|
||||
* 1 - Allow dynamic FIFO sizing (default, if available)
|
||||
* @host_channels: The number of host channel registers to use
|
||||
* 1 to 16
|
||||
* @hs_phy_type: High-speed PHY interface type
|
||||
* 0 - High-speed interface not supported
|
||||
* 1 - UTMI+
|
||||
* 2 - ULPI
|
||||
* 3 - UTMI+ and ULPI
|
||||
* @fs_phy_type: Full-speed PHY interface type
|
||||
* 0 - Full speed interface not supported
|
||||
* 1 - Dedicated full speed interface
|
||||
* 2 - FS pins shared with UTMI+ pins
|
||||
* 3 - FS pins shared with ULPI pins
|
||||
* @num_dev_ep: Number of device endpoints available
|
||||
* @nperio_tx_q_depth:
|
||||
* Non-Periodic Request Queue Depth
|
||||
* 2, 4 or 8
|
||||
* @dev_token_q_depth: Device Mode IN Token Sequence Learning Queue
|
||||
* Depth
|
||||
* 0 to 30
|
||||
* @host_perio_tx_q_depth:
|
||||
* Host Mode Periodic Request Queue Depth
|
||||
* 2, 4 or 8
|
||||
*
|
||||
* @max_transfer_size: The maximum transfer size supported, in bytes
|
||||
* 2047 to 65,535
|
||||
* Actual maximum value is autodetected and also
|
||||
* the default.
|
||||
* @max_packet_count: The maximum number of packets in a transfer
|
||||
* 15 to 511
|
||||
* Actual maximum value is autodetected and also
|
||||
* the default.
|
||||
* @i2c_enable: Specifies whether to use the I2Cinterface for a full
|
||||
* speed PHY. This parameter is only applicable if phy_type
|
||||
* is FS.
|
||||
* 0 - No (default)
|
||||
* 1 - Yes
|
||||
* @total_fifo_size: Total internal RAM for FIFOs (bytes)
|
||||
* @lpm_mode: For enabling Link Power Management in the controller
|
||||
* 0 - Disable
|
||||
* 1 - Enable
|
||||
*
|
||||
* @en_multiple_tx_fifo: Specifies whether dedicated per-endpoint transmit FIFOs
|
||||
* are enabled for non-periodic IN endpoints in device
|
||||
* mode.
|
||||
* @num_dev_in_eps: Number of device IN endpoints available
|
||||
* @num_dev_perio_in_ep: Number of device periodic IN endpoints
|
||||
* available
|
||||
* @dma_desc_enable: When DMA mode is enabled, specifies whether to use
|
||||
* address DMA mode or descriptor DMA mode for accessing
|
||||
* the data FIFOs. The driver will automatically detect the
|
||||
* value for this if none is specified.
|
||||
* 0 - Address DMA
|
||||
* 1 - Descriptor DMA (default, if available)
|
||||
|
||||
* @power_optimized: Are power optimizations enabled?
|
||||
* @hibernation: Is hibernation enabled?
|
||||
* @utmi_phy_data_width: UTMI+ PHY data width
|
||||
* 0 - 8 bits
|
||||
* 1 - 16 bits
|
||||
* 2 - 8 or 16 bits
|
||||
|
||||
* @acg_enable: For enabling Active Clock Gating in the controller
|
||||
* 0 - Disable
|
||||
* 1 - Enable
|
||||
* @ipg_isoc_en: This feature indicates that the controller supports
|
||||
* the worst-case scenario of Rx followed by Rx
|
||||
* Interpacket Gap (IPG) (32 bitTimes) as per the utmi
|
||||
* specification for any token following ISOC OUT token.
|
||||
* 0 - Don't support
|
||||
* 1 - Support
|
||||
* @service_interval_mode: For enabling service interval based scheduling in the
|
||||
* controller.
|
||||
* 0 - Disable
|
||||
* 1 - Enable
|
||||
*/
|
||||
struct dwc2_hw_params {
|
||||
uint32_t snpsid;
|
||||
uint32_t dev_ep_dirs;
|
||||
|
||||
unsigned op_mode : 3;
|
||||
unsigned arch : 2;
|
||||
unsigned enable_dynamic_fifo : 1;
|
||||
unsigned host_channels : 5;
|
||||
unsigned hs_phy_type : 2;
|
||||
unsigned fs_phy_type : 2;
|
||||
unsigned num_dev_ep : 4;
|
||||
unsigned nperio_tx_q_depth : 3;
|
||||
unsigned host_perio_tx_q_depth : 3;
|
||||
unsigned dev_token_q_depth : 5;
|
||||
|
||||
unsigned max_transfer_size : 26;
|
||||
unsigned max_packet_count : 11;
|
||||
unsigned i2c_enable : 1;
|
||||
unsigned total_fifo_size : 16;
|
||||
unsigned lpm_mode : 1;
|
||||
|
||||
unsigned en_multiple_tx_fifo : 1;
|
||||
unsigned num_dev_in_eps : 4;
|
||||
unsigned num_dev_perio_in_ep : 4;
|
||||
unsigned dma_desc_enable : 1;
|
||||
unsigned power_optimized : 1;
|
||||
unsigned hibernation : 1;
|
||||
unsigned utmi_phy_data_width : 2;
|
||||
unsigned acg_enable : 1;
|
||||
unsigned ipg_isoc_en : 1;
|
||||
unsigned service_interval_mode : 1;
|
||||
};
|
||||
|
||||
#define DWC2_PHY_TYPE_PARAM_FS 0
|
||||
#define DWC2_PHY_TYPE_PARAM_UTMI 1
|
||||
#define DWC2_PHY_TYPE_PARAM_ULPI 2
|
||||
|
||||
struct dwc2_user_params {
|
||||
uint8_t phy_type;
|
||||
uint8_t phy_utmi_width;
|
||||
|
||||
bool device_dma_enable;
|
||||
bool device_dma_desc_enable;
|
||||
/* (5 * number of control endpoints + 8) + ((largest USB packet used / 4) + 1 for
|
||||
* status information) + (2 * number of OUT endpoints) + 1 for Global NAK
|
||||
*/
|
||||
uint16_t device_rx_fifo_size;
|
||||
/* IN Endpoints Max packet Size / 4 */
|
||||
uint16_t device_tx_fifo_size[MAX_EPS_CHANNELS];
|
||||
|
||||
bool host_dma_desc_enable;
|
||||
/*
|
||||
* (largest USB packet used / 4) + 1 for status information + 1 transfer complete +
|
||||
* 1 location each for Bulk/Control endpoint for handling NAK/NYET scenario
|
||||
*/
|
||||
uint16_t host_rx_fifo_size;
|
||||
/* largest non-periodic USB packet used / 4 */
|
||||
uint16_t host_nperio_tx_fifo_size;
|
||||
/* largest periodic USB packet used / 4 */
|
||||
uint16_t host_perio_tx_fifo_size;
|
||||
|
||||
uint32_t device_gccfg;
|
||||
uint32_t host_gccfg;
|
||||
|
||||
bool b_session_valid_override;
|
||||
uint32_t total_fifo_size;
|
||||
};
|
||||
|
||||
struct usb_dwc2_user_fifo_config {
|
||||
/* (5 * number of control endpoints + 8) + ((largest USB packet used / 4) + 1 for
|
||||
* status information) + (2 * number of OUT endpoints) + 1 for Global NAK
|
||||
*/
|
||||
uint16_t device_rx_fifo_size;
|
||||
/* IN Endpoints Max packet Size / 4 */
|
||||
uint16_t device_tx_fifo_size[MAX_EPS_CHANNELS];
|
||||
};
|
||||
|
||||
static inline void dwc2_get_hwparams(uint32_t reg_base, struct dwc2_hw_params *hw)
|
||||
{
|
||||
unsigned int width;
|
||||
uint32_t snpsid, hwcfg1, hwcfg2, hwcfg3, hwcfg4;
|
||||
|
||||
snpsid = dwc2_readl(reg_base + GSNPSID_OFFSET);
|
||||
|
||||
hwcfg1 = dwc2_readl(reg_base + GHWCFG1_OFFSET);
|
||||
hwcfg2 = dwc2_readl(reg_base + GHWCFG2_OFFSET);
|
||||
hwcfg3 = dwc2_readl(reg_base + GHWCFG3_OFFSET);
|
||||
hwcfg4 = dwc2_readl(reg_base + GHWCFG4_OFFSET);
|
||||
|
||||
/* snpsid */
|
||||
hw->snpsid = snpsid;
|
||||
|
||||
/* hwcfg1 */
|
||||
hw->dev_ep_dirs = hwcfg1;
|
||||
|
||||
/* hwcfg2 */
|
||||
hw->op_mode = (hwcfg2 & GHWCFG2_OP_MODE_MASK) >>
|
||||
GHWCFG2_OP_MODE_SHIFT;
|
||||
hw->arch = (hwcfg2 & GHWCFG2_ARCHITECTURE_MASK) >>
|
||||
GHWCFG2_ARCHITECTURE_SHIFT;
|
||||
hw->enable_dynamic_fifo = !!(hwcfg2 & GHWCFG2_DYNAMIC_FIFO);
|
||||
hw->host_channels = 1 + ((hwcfg2 & GHWCFG2_NUM_HOST_CHAN_MASK) >>
|
||||
GHWCFG2_NUM_HOST_CHAN_SHIFT);
|
||||
hw->hs_phy_type = (hwcfg2 & GHWCFG2_HS_PHY_TYPE_MASK) >>
|
||||
GHWCFG2_HS_PHY_TYPE_SHIFT;
|
||||
hw->fs_phy_type = (hwcfg2 & GHWCFG2_FS_PHY_TYPE_MASK) >>
|
||||
GHWCFG2_FS_PHY_TYPE_SHIFT;
|
||||
hw->num_dev_ep = (hwcfg2 & GHWCFG2_NUM_DEV_EP_MASK) >>
|
||||
GHWCFG2_NUM_DEV_EP_SHIFT;
|
||||
hw->nperio_tx_q_depth =
|
||||
(hwcfg2 & GHWCFG2_NONPERIO_TX_Q_DEPTH_MASK) >>
|
||||
GHWCFG2_NONPERIO_TX_Q_DEPTH_SHIFT << 1;
|
||||
hw->host_perio_tx_q_depth =
|
||||
(hwcfg2 & GHWCFG2_HOST_PERIO_TX_Q_DEPTH_MASK) >>
|
||||
GHWCFG2_HOST_PERIO_TX_Q_DEPTH_SHIFT << 1;
|
||||
hw->dev_token_q_depth =
|
||||
(hwcfg2 & GHWCFG2_DEV_TOKEN_Q_DEPTH_MASK) >>
|
||||
GHWCFG2_DEV_TOKEN_Q_DEPTH_SHIFT;
|
||||
|
||||
/* hwcfg3 */
|
||||
width = (hwcfg3 & GHWCFG3_XFER_SIZE_CNTR_WIDTH_MASK) >>
|
||||
GHWCFG3_XFER_SIZE_CNTR_WIDTH_SHIFT;
|
||||
hw->max_transfer_size = (1 << (width + 11)) - 1;
|
||||
width = (hwcfg3 & GHWCFG3_PACKET_SIZE_CNTR_WIDTH_MASK) >>
|
||||
GHWCFG3_PACKET_SIZE_CNTR_WIDTH_SHIFT;
|
||||
hw->max_packet_count = (1 << (width + 4)) - 1;
|
||||
hw->i2c_enable = !!(hwcfg3 & GHWCFG3_I2C);
|
||||
hw->total_fifo_size = (hwcfg3 & GHWCFG3_DFIFO_DEPTH_MASK) >>
|
||||
GHWCFG3_DFIFO_DEPTH_SHIFT;
|
||||
hw->lpm_mode = !!(hwcfg3 & GHWCFG3_OTG_LPM_EN);
|
||||
|
||||
/* hwcfg4 */
|
||||
hw->en_multiple_tx_fifo = !!(hwcfg4 & GHWCFG4_DED_FIFO_EN);
|
||||
hw->num_dev_perio_in_ep = (hwcfg4 & GHWCFG4_NUM_DEV_PERIO_IN_EP_MASK) >>
|
||||
GHWCFG4_NUM_DEV_PERIO_IN_EP_SHIFT;
|
||||
hw->num_dev_in_eps = (hwcfg4 & GHWCFG4_NUM_IN_EPS_MASK) >>
|
||||
GHWCFG4_NUM_IN_EPS_SHIFT;
|
||||
hw->dma_desc_enable = !!(hwcfg4 & GHWCFG4_DESC_DMA);
|
||||
hw->power_optimized = !!(hwcfg4 & GHWCFG4_POWER_OPTIMIZ);
|
||||
hw->hibernation = !!(hwcfg4 & GHWCFG4_HIBER);
|
||||
hw->utmi_phy_data_width = (hwcfg4 & GHWCFG4_UTMI_PHY_DATA_WIDTH_MASK) >>
|
||||
GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT;
|
||||
hw->acg_enable = !!(hwcfg4 & GHWCFG4_ACG_SUPPORTED);
|
||||
hw->ipg_isoc_en = !!(hwcfg4 & GHWCFG4_IPG_ISOC_SUPPORTED);
|
||||
hw->service_interval_mode = !!(hwcfg4 &
|
||||
GHWCFG4_SERVICE_INTERVAL_SUPPORTED);
|
||||
}
|
||||
|
||||
void dwc2_get_user_params(uint32_t reg_base, struct dwc2_user_params *params);
|
||||
void dwc2_get_user_fifo_config(uint32_t reg_base, struct usb_dwc2_user_fifo_config *config);
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (c) 2024, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usbd_core.h"
|
||||
#include "usbh_core.h"
|
||||
#include "usb_dwc2_param.h"
|
||||
|
||||
extern unsigned int system_core_clock;
|
||||
|
||||
uint32_t SystemCoreClock;
|
||||
|
||||
const struct dwc2_user_params param_pa11_pa12 = {
|
||||
.phy_type = DWC2_PHY_TYPE_PARAM_FS,
|
||||
.device_dma_enable = false,
|
||||
.device_dma_desc_enable = false,
|
||||
.device_rx_fifo_size = (320 - 16 - 16 - 16 - 16),
|
||||
.device_tx_fifo_size = {
|
||||
[0] = 16, // 64 byte
|
||||
[1] = 16, // 64 byte
|
||||
[2] = 16, // 64 byte
|
||||
[3] = 16, // 64 byte
|
||||
[4] = 0,
|
||||
[5] = 0,
|
||||
[6] = 0,
|
||||
[7] = 0,
|
||||
[8] = 0,
|
||||
[9] = 0,
|
||||
[10] = 0,
|
||||
[11] = 0,
|
||||
[12] = 0,
|
||||
[13] = 0,
|
||||
[14] = 0,
|
||||
[15] = 0 },
|
||||
#ifdef AT32F415xx
|
||||
.device_gccfg = ((1 << 16) | (1 << 18) | (1 << 19) | (1 << 21)),
|
||||
#else
|
||||
.device_gccfg = ((1 << 16) | (1 << 21)),
|
||||
#endif
|
||||
.total_fifo_size = 320 // 1280 byte
|
||||
};
|
||||
|
||||
#if __has_include("at32f402_405.h")
|
||||
#include "at32f402_405.h"
|
||||
|
||||
const struct dwc2_user_params param_pb14_pb15 = {
|
||||
.phy_type = DWC2_PHY_TYPE_PARAM_UTMI,
|
||||
.device_dma_enable = true,
|
||||
.device_dma_desc_enable = false,
|
||||
.device_rx_fifo_size = (1008 - 16 - 256 - 128 - 128 - 128 - 128),
|
||||
.device_tx_fifo_size = {
|
||||
[0] = 16, // 64 byte
|
||||
[1] = 256, // 1024 byte
|
||||
[2] = 128, // 512 byte
|
||||
[3] = 128, // 512 byte
|
||||
[4] = 128, // 512 byte
|
||||
[5] = 128, // 512 byte
|
||||
[6] = 0,
|
||||
[7] = 0,
|
||||
[8] = 0,
|
||||
[9] = 0,
|
||||
[10] = 0,
|
||||
[11] = 0,
|
||||
[12] = 0,
|
||||
[13] = 0,
|
||||
[14] = 0,
|
||||
[15] = 0 },
|
||||
|
||||
.host_dma_desc_enable = false,
|
||||
.host_rx_fifo_size = 624,
|
||||
.host_nperio_tx_fifo_size = 128, // 512 byte
|
||||
.host_perio_tx_fifo_size = 256, // 1024 byte
|
||||
|
||||
.device_gccfg = ((1 << 16) | (1 << 21)),
|
||||
.host_gccfg = ((1 << 16) | (1 << 21))
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_USB_DWC2_CUSTOM_PARAM
|
||||
void dwc2_get_user_params(uint32_t reg_base, struct dwc2_user_params *params)
|
||||
{
|
||||
SystemCoreClock = system_core_clock;
|
||||
|
||||
#if __has_include("at32f402_405.h")
|
||||
if (reg_base == OTGHS_BASE) {
|
||||
memcpy(params, ¶m_pb14_pb15, sizeof(struct dwc2_user_params));
|
||||
} else {
|
||||
memcpy(params, ¶m_pa11_pa12, sizeof(struct dwc2_user_params));
|
||||
}
|
||||
#else
|
||||
memcpy(params, ¶m_pa11_pa12, sizeof(struct dwc2_user_params));
|
||||
#endif
|
||||
#ifdef CONFIG_USB_DWC2_CUSTOM_FIFO
|
||||
struct usb_dwc2_user_fifo_config s_dwc2_fifo_config;
|
||||
|
||||
dwc2_get_user_fifo_config(reg_base, &s_dwc2_fifo_config);
|
||||
|
||||
params->device_rx_fifo_size = s_dwc2_fifo_config.device_rx_fifo_size;
|
||||
for (uint8_t i = 0; i < MAX_EPS_CHANNELS; i++) {
|
||||
params->device_tx_fifo_size[i] = s_dwc2_fifo_config.device_tx_fifo_size[i];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
void usbd_dwc2_delay_ms(uint8_t ms)
|
||||
{
|
||||
uint32_t count = SystemCoreClock / 1000 * ms;
|
||||
while (count--) {
|
||||
__asm volatile("nop");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,291 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_idf_version.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "esp_private/usb_phy.h"
|
||||
#include "soc/periph_defs.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "usbd_core.h"
|
||||
#include "usbh_core.h"
|
||||
#include "usb_dwc2_param.h"
|
||||
|
||||
#define GET_USB_INDEX(reg_base) 0
|
||||
#define GET_USB_INTR_SOURCE(reg_base) ETS_USB_INTR_SOURCE
|
||||
#define GET_USB_PHY_TARGET(reg_base) USB_PHY_TARGET_INT
|
||||
#define GET_USB_PHY_SPEED(reg_base) USB_PHY_SPEED_UNDEFINED
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32S2
|
||||
#define DEFAULT_CPU_FREQ_MHZ CONFIG_ESP32S2_DEFAULT_CPU_FREQ_MHZ
|
||||
#define DEFAULT_USB_INTR_SOURCE ETS_USB_INTR_SOURCE
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||
#define DEFAULT_CPU_FREQ_MHZ CONFIG_ESP32S3_DEFAULT_CPU_FREQ_MHZ
|
||||
#define DEFAULT_USB_INTR_SOURCE ETS_USB_INTR_SOURCE
|
||||
#elif CONFIG_IDF_TARGET_ESP32P4
|
||||
#undef GET_USB_INDEX
|
||||
#define GET_USB_INDEX(reg_base) ((reg_base) == (void*)ESP_USB_HS0_BASE ? 0 : 1)
|
||||
#define DEFAULT_CPU_FREQ_MHZ CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ
|
||||
#define DEFAULT_USB_INTR_SOURCE ETS_USB_OTG_INTR_SOURCE
|
||||
#define USB_FS_INTR_SOURCE ETS_USB_OTG11_CH0_INTR_SOURCE
|
||||
#undef GET_USB_INTR_SOURCE
|
||||
#define GET_USB_INTR_SOURCE(reg_base) ((reg_base) == (void*)ESP_USB_HS0_BASE ? DEFAULT_USB_INTR_SOURCE : USB_FS_INTR_SOURCE)
|
||||
#undef GET_USB_PHY_TARGET
|
||||
#define GET_USB_PHY_TARGET(reg_base) ((reg_base) == (void*)ESP_USB_HS0_BASE ? USB_PHY_TARGET_UTMI : USB_PHY_TARGET_INT)
|
||||
#undef GET_USB_PHY_SPEED
|
||||
#define GET_USB_PHY_SPEED(reg_base) ((reg_base) == (void*)ESP_USB_HS0_BASE ? USB_PHY_SPEED_HIGH : USB_PHY_SPEED_FULL)
|
||||
#else
|
||||
#define DEFAULT_CPU_FREQ_MHZ 160
|
||||
#endif
|
||||
|
||||
uint32_t SystemCoreClock = (DEFAULT_CPU_FREQ_MHZ * 1000 * 1000);
|
||||
static usb_phy_handle_t s_phy_handle[SOC_USB_OTG_PERIPH_NUM] = {NULL};
|
||||
static intr_handle_t s_interrupt_handle[SOC_USB_OTG_PERIPH_NUM] = {NULL};
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
|
||||
const struct dwc2_user_params param_fs = {
|
||||
.phy_type = DWC2_PHY_TYPE_PARAM_FS,
|
||||
.device_dma_enable = true,
|
||||
.device_dma_desc_enable = false,
|
||||
.device_rx_fifo_size = (200 - 16 * 7),
|
||||
.device_tx_fifo_size = {
|
||||
[0] = 16, // 64 byte
|
||||
[1] = 16, // 64 byte
|
||||
[2] = 16, // 64 byte
|
||||
[3] = 16, // 64 byte
|
||||
[4] = 16, // 64 byte
|
||||
[5] = 16, // 64 byte
|
||||
[6] = 16, // 64 byte
|
||||
[7] = 0,
|
||||
[8] = 0,
|
||||
[9] = 0,
|
||||
[10] = 0,
|
||||
[11] = 0,
|
||||
[12] = 0,
|
||||
[13] = 0,
|
||||
[14] = 0,
|
||||
[15] = 0 },
|
||||
|
||||
.host_dma_desc_enable = false,
|
||||
.host_rx_fifo_size = 80,
|
||||
.host_nperio_tx_fifo_size = 60, // 240 byte
|
||||
.host_perio_tx_fifo_size = 60, // 240 byte
|
||||
};
|
||||
#elif CONFIG_IDF_TARGET_ESP32P4
|
||||
const struct dwc2_user_params param_fs = {
|
||||
.phy_type = DWC2_PHY_TYPE_PARAM_FS,
|
||||
.device_dma_enable = true,
|
||||
.device_dma_desc_enable = false,
|
||||
.device_rx_fifo_size = (200 - 16 * 7),
|
||||
.device_tx_fifo_size = {
|
||||
[0] = 16, // 64 byte
|
||||
[1] = 16, // 64 byte
|
||||
[2] = 16, // 64 byte
|
||||
[3] = 16, // 64 byte
|
||||
[4] = 16, // 64 byte
|
||||
[5] = 16, // 64 byte
|
||||
[6] = 16, // 64 byte
|
||||
[7] = 0,
|
||||
[8] = 0,
|
||||
[9] = 0,
|
||||
[10] = 0,
|
||||
[11] = 0,
|
||||
[12] = 0,
|
||||
[13] = 0,
|
||||
[14] = 0,
|
||||
[15] = 0 },
|
||||
|
||||
.host_dma_desc_enable = false,
|
||||
.host_rx_fifo_size = (200 - 60 - 60),
|
||||
.host_nperio_tx_fifo_size = 60, // 240 byte
|
||||
.host_perio_tx_fifo_size = 60, // 240 byte
|
||||
};
|
||||
|
||||
const struct dwc2_user_params param_hs = {
|
||||
.phy_type = DWC2_PHY_TYPE_PARAM_UTMI,
|
||||
.device_dma_enable = true,
|
||||
.device_dma_desc_enable = false,
|
||||
.device_rx_fifo_size = (896 - 16 - 128 - 128 - 128 - 128 - 16 - 16),
|
||||
.device_tx_fifo_size = {
|
||||
[0] = 16, // 64 byte
|
||||
[1] = 128, // 512 byte
|
||||
[2] = 128, // 512 byte
|
||||
[3] = 128, // 512 byte
|
||||
[4] = 128, // 512 byte
|
||||
[5] = 16, // 64 byte
|
||||
[6] = 16, // 64 byte
|
||||
[7] = 0,
|
||||
[8] = 0,
|
||||
[9] = 0,
|
||||
[10] = 0,
|
||||
[11] = 0,
|
||||
[12] = 0,
|
||||
[13] = 0,
|
||||
[14] = 0,
|
||||
[15] = 0 },
|
||||
|
||||
.host_dma_desc_enable = false,
|
||||
.host_rx_fifo_size = (896 - 128 - 128),
|
||||
.host_nperio_tx_fifo_size = 128, // 512 byte
|
||||
.host_perio_tx_fifo_size = 128, // 512 byte
|
||||
};
|
||||
#endif
|
||||
|
||||
static void usb_dc_interrupt_cb(void *arg_pv)
|
||||
{
|
||||
extern void USBD_IRQHandler(uint8_t busid);
|
||||
uint8_t busid = (uintptr_t)arg_pv;
|
||||
USBD_IRQHandler(busid);
|
||||
}
|
||||
|
||||
void usb_dc_low_level_init(uint8_t busid)
|
||||
{
|
||||
esp_err_t ret;
|
||||
void *reg_base = (void*)g_usbdev_bus[busid].reg_base;
|
||||
(void)reg_base;
|
||||
usb_phy_config_t phy_config = {
|
||||
.controller = USB_PHY_CTRL_OTG,
|
||||
.otg_mode = USB_OTG_MODE_DEVICE,
|
||||
};
|
||||
phy_config.target = GET_USB_PHY_TARGET(reg_base);
|
||||
phy_config.otg_speed = GET_USB_PHY_SPEED(reg_base);
|
||||
|
||||
ret = usb_new_phy(&phy_config, &s_phy_handle[GET_USB_INDEX(reg_base)]);
|
||||
if (ret != ESP_OK) {
|
||||
USB_LOG_ERR("USB Phy Init Failed!\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
uintptr_t arg = busid;
|
||||
// TODO: Check when to enable interrupt
|
||||
ret = esp_intr_alloc(GET_USB_INTR_SOURCE(reg_base), ESP_INTR_FLAG_LOWMED, usb_dc_interrupt_cb, (void *)arg, &s_interrupt_handle[GET_USB_INDEX(reg_base)]);
|
||||
if (ret != ESP_OK) {
|
||||
USB_LOG_ERR("USB Interrupt Init Failed!\r\n");
|
||||
return;
|
||||
}
|
||||
USB_LOG_INFO("cherryusb, version: " CHERRYUSB_VERSION_STR "\r\n");
|
||||
}
|
||||
|
||||
void usb_dc_low_level_deinit(uint8_t busid)
|
||||
{
|
||||
void *reg_base = (void*)g_usbdev_bus[busid].reg_base;
|
||||
(void)reg_base;
|
||||
if (s_interrupt_handle[GET_USB_INDEX(reg_base)]) {
|
||||
esp_intr_free(s_interrupt_handle[GET_USB_INDEX(reg_base)]);
|
||||
s_interrupt_handle[GET_USB_INDEX(reg_base)] = NULL;
|
||||
}
|
||||
if (s_phy_handle[GET_USB_INDEX(reg_base)]) {
|
||||
usb_del_phy(s_phy_handle[GET_USB_INDEX(reg_base)]);
|
||||
s_phy_handle[GET_USB_INDEX(reg_base)] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void usb_hc_interrupt_cb(void *arg_pv)
|
||||
{
|
||||
extern void USBH_IRQHandler(uint8_t busid);
|
||||
uint8_t busid = (uintptr_t)arg_pv;
|
||||
USBH_IRQHandler(busid);
|
||||
}
|
||||
|
||||
void usb_hc_low_level_init(struct usbh_bus *bus)
|
||||
{
|
||||
void *reg_base = (void*)bus->hcd.reg_base;
|
||||
(void)reg_base;
|
||||
// Host Library defaults to internal PHY
|
||||
usb_phy_config_t phy_config = {
|
||||
.controller = USB_PHY_CTRL_OTG,
|
||||
.otg_mode = USB_OTG_MODE_HOST,
|
||||
.otg_speed = USB_PHY_SPEED_UNDEFINED, // In Host mode, the speed is determined by the connected device
|
||||
.ext_io_conf = NULL,
|
||||
.otg_io_conf = NULL,
|
||||
};
|
||||
phy_config.target = GET_USB_PHY_TARGET(reg_base);
|
||||
|
||||
esp_err_t ret = usb_new_phy(&phy_config, &s_phy_handle[GET_USB_INDEX(reg_base)]);
|
||||
if (ret != ESP_OK) {
|
||||
USB_LOG_ERR("USB Phy Init Failed!\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
uintptr_t arg = bus->busid;
|
||||
// TODO: Check when to enable interrupt
|
||||
ret = esp_intr_alloc(GET_USB_INTR_SOURCE(reg_base), ESP_INTR_FLAG_LOWMED, usb_hc_interrupt_cb, (void*)(arg), &s_interrupt_handle[GET_USB_INDEX(reg_base)]);
|
||||
if (ret != ESP_OK) {
|
||||
USB_LOG_ERR("USB Interrupt Init Failed!\r\n");
|
||||
return;
|
||||
}
|
||||
USB_LOG_INFO("cherryusb, version: " CHERRYUSB_VERSION_STR "\r\n");
|
||||
}
|
||||
|
||||
void usb_hc_low_level_deinit(struct usbh_bus *bus)
|
||||
{
|
||||
void *reg_base = (void*)bus->hcd.reg_base;
|
||||
(void)reg_base;
|
||||
if (s_interrupt_handle[GET_USB_INDEX(reg_base)]) {
|
||||
esp_intr_free(s_interrupt_handle[GET_USB_INDEX(reg_base)]);
|
||||
s_interrupt_handle[GET_USB_INDEX(reg_base)] = NULL;
|
||||
}
|
||||
if (s_phy_handle[GET_USB_INDEX(reg_base)]) {
|
||||
usb_del_phy(s_phy_handle[GET_USB_INDEX(reg_base)]);
|
||||
s_phy_handle[GET_USB_INDEX(reg_base)] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void dwc2_get_user_params(uint32_t reg_base, struct dwc2_user_params *params)
|
||||
{
|
||||
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
|
||||
memcpy(params, ¶m_fs, sizeof(struct dwc2_user_params));
|
||||
#elif CONFIG_IDF_TARGET_ESP32P4
|
||||
if (reg_base == ESP_USB_HS0_BASE) {
|
||||
memcpy(params, ¶m_hs, sizeof(struct dwc2_user_params));
|
||||
} else {
|
||||
memcpy(params, ¶m_fs, sizeof(struct dwc2_user_params));
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_USB_DWC2_CUSTOM_FIFO
|
||||
struct usb_dwc2_user_fifo_config s_dwc2_fifo_config;
|
||||
|
||||
dwc2_get_user_fifo_config(reg_base, &s_dwc2_fifo_config);
|
||||
|
||||
params->device_rx_fifo_size = s_dwc2_fifo_config.device_rx_fifo_size;
|
||||
for (uint8_t i = 0; i < MAX_EPS_CHANNELS; i++)
|
||||
{
|
||||
params->device_tx_fifo_size[i] = s_dwc2_fifo_config.device_tx_fifo_size[i];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void usbd_dwc2_delay_ms(uint8_t ms)
|
||||
{
|
||||
vTaskDelay(pdMS_TO_TICKS(ms));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_DCACHE_ENABLE
|
||||
#include "esp_cache.h"
|
||||
|
||||
void usb_dcache_clean(uintptr_t addr, size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
return;
|
||||
|
||||
esp_cache_msync((void *)addr, size, ESP_CACHE_MSYNC_FLAG_TYPE_DATA | ESP_CACHE_MSYNC_FLAG_DIR_C2M);
|
||||
}
|
||||
|
||||
void usb_dcache_invalidate(uintptr_t addr, size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
return;
|
||||
|
||||
esp_cache_msync((void *)addr, size, ESP_CACHE_MSYNC_FLAG_TYPE_DATA | ESP_CACHE_MSYNC_FLAG_DIR_M2C);
|
||||
}
|
||||
|
||||
void usb_dcache_flush(uintptr_t addr, size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
return;
|
||||
|
||||
esp_cache_msync((void *)addr, size, ESP_CACHE_MSYNC_FLAG_TYPE_DATA | ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_DIR_M2C);
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2024, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usb_config.h"
|
||||
#include "stdint.h"
|
||||
#include "usb_dwc2_reg.h"
|
||||
|
||||
#if 1
|
||||
#error you need to modify some usb register values then use this chip
|
||||
#endif
|
||||
|
||||
#if CONFIG_USBDEV_EP_NUM != 4 && CONFIG_USBDEV_EP_NUM != 6
|
||||
#error "gd32 only has 4 endpoints for pa11/pa12 and 6 endpoints for pb14/pb15"
|
||||
#endif
|
||||
|
||||
/* you can find this config in function:usb_core_init, file:drv_usb_core.c, for example:
|
||||
*
|
||||
* usb_regs->gr->GCCFG |= GCCFG_PWRON | GCCFG_VBUSACEN | GCCFG_VBUSBCEN;
|
||||
*
|
||||
*/
|
||||
|
||||
uint32_t usbd_get_dwc2_gccfg_conf(uint32_t reg_base)
|
||||
{
|
||||
#ifdef CONFIG_USB_HS
|
||||
return 0;
|
||||
#else
|
||||
return ((1 << 16) | (1 << 18) | (1 << 19) | (1 << 21));
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t usbh_get_dwc2_gccfg_conf(uint32_t reg_base)
|
||||
{
|
||||
#ifdef CONFIG_USB_HS
|
||||
return 0;
|
||||
#else
|
||||
return ((1 << 16) | (1 << 18) | (1 << 19) | (1 << 21));
|
||||
#endif
|
||||
}
|
||||
|
||||
extern uint32_t SystemCoreClock;
|
||||
|
||||
void usbd_dwc2_delay_ms(uint8_t ms)
|
||||
{
|
||||
uint32_t count = SystemCoreClock / 1000 * ms;
|
||||
while (count--) {
|
||||
__asm volatile("nop");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2024, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usb_config.h"
|
||||
#include "usb_dwc2_reg.h"
|
||||
|
||||
/* When using [GPIO_SetFunc(USBF_VBUS_PORT, USBF_VBUS_PIN, USBF_VBUS_FUNC);], there is no need to configure GOTGCTL */
|
||||
|
||||
#define USB_OTG_GLB ((DWC2_GlobalTypeDef *)(reg_base))
|
||||
|
||||
uint32_t usbd_get_dwc2_gccfg_conf(uint32_t reg_base)
|
||||
{
|
||||
|
||||
USB_OTG_GLB->GOTGCTL |= USB_OTG_GOTGCTL_BVALOEN;
|
||||
USB_OTG_GLB->GOTGCTL |= USB_OTG_GOTGCTL_BVALOVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t usbh_get_dwc2_gccfg_conf(uint32_t reg_base)
|
||||
{
|
||||
USB_OTG_GLB->GOTGCTL &= ~USB_OTG_GOTGCTL_BVALOEN;
|
||||
USB_OTG_GLB->GOTGCTL &= ~USB_OTG_GOTGCTL_BVALOVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern uint32_t SystemCoreClock;
|
||||
|
||||
void usbd_dwc2_delay_ms(uint8_t ms)
|
||||
{
|
||||
uint32_t count = SystemCoreClock / 1000 * ms;
|
||||
while (count--) {
|
||||
__asm volatile("nop");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
/* Copyright (c) 2023, Canaan Bright Sight Co., Ltd
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rthw.h>
|
||||
#include "usbd_core.h"
|
||||
#include "usbh_core.h"
|
||||
#include "usb_dwc2_param.h"
|
||||
|
||||
#include <riscv_io.h>
|
||||
#include "sysctl_rst.h"
|
||||
#include "ioremap.h"
|
||||
#include "mmu.h"
|
||||
#include "cache.h"
|
||||
|
||||
extern rt_mmu_info mmu_info;
|
||||
|
||||
#if defined(ENABLE_CHERRY_USB) || defined(PKG_USING_CHERRYUSB) || defined(RT_USING_CHERRYUSB)
|
||||
#define DEFAULT_USB_HCLK_FREQ_MHZ 200
|
||||
|
||||
uint32_t SystemCoreClock = (DEFAULT_USB_HCLK_FREQ_MHZ * 1000 * 1000);
|
||||
|
||||
const uintptr_t usb_dev_addr[2] = { 0x91500000UL, 0x91540000UL };
|
||||
|
||||
#define USB_IDPULLUP0 (1 << 4)
|
||||
#define USB_DMPULLDOWN0 (1 << 8)
|
||||
#define USB_DPPULLDOWN0 (1 << 9)
|
||||
|
||||
const struct dwc2_user_params param_common = {
|
||||
.phy_type = DWC2_PHY_TYPE_PARAM_UTMI,
|
||||
#ifdef CONFIG_USB_DWC2_DMA_ENABLE
|
||||
.device_dma_enable = true,
|
||||
#else
|
||||
.device_dma_enable = false,
|
||||
#endif
|
||||
.device_dma_desc_enable = false,
|
||||
.device_rx_fifo_size = (3016 - 16 - 256 * 8),
|
||||
.device_tx_fifo_size = {
|
||||
[0] = 16, // 64 byte
|
||||
[1] = 512, // 1024 byte, double buffer
|
||||
[2] = 256, // 1024 byte
|
||||
[3] = 512, // 1024 byte, double buffer
|
||||
[4] = 256, // 1024 byte
|
||||
[5] = 256, // 1024 byte
|
||||
[6] = 256, // 1024 byte
|
||||
[7] = 0,
|
||||
[8] = 0,
|
||||
[9] = 0,
|
||||
[10] = 0,
|
||||
[11] = 0,
|
||||
[12] = 0,
|
||||
[13] = 0,
|
||||
[14] = 0,
|
||||
[15] = 0 },
|
||||
|
||||
.host_dma_desc_enable = false,
|
||||
.host_rx_fifo_size = 3016 - 128 * 2 - 256 * 2,
|
||||
.host_nperio_tx_fifo_size = 128 * 2, // 512 byte, double buffer
|
||||
.host_perio_tx_fifo_size = 256 * 2, // 1024 byte, double buffer
|
||||
|
||||
.device_gccfg = 0,
|
||||
.host_gccfg = 0
|
||||
};
|
||||
|
||||
#ifndef CONFIG_USB_DWC2_CUSTOM_PARAM
|
||||
void dwc2_get_user_params(uint32_t reg_base, struct dwc2_user_params *params)
|
||||
{
|
||||
memcpy(params, ¶m_common, sizeof(struct dwc2_user_params));
|
||||
#ifdef CONFIG_USB_DWC2_CUSTOM_FIFO
|
||||
struct usb_dwc2_user_fifo_config s_dwc2_fifo_config;
|
||||
|
||||
dwc2_get_user_fifo_config(reg_base, &s_dwc2_fifo_config);
|
||||
|
||||
params->device_rx_fifo_size = s_dwc2_fifo_config.device_rx_fifo_size;
|
||||
for (uint8_t i = 0; i < MAX_EPS_CHANNELS; i++) {
|
||||
params->device_tx_fifo_size[i] = s_dwc2_fifo_config.device_tx_fifo_size[i];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
// USB Host
|
||||
#if defined(ENABLE_CHERRY_USB_HOST) || defined(PKG_CHERRYUSB_HOST) || defined(RT_CHERRYUSB_HOST)
|
||||
static void usb_hc_interrupt_cb(int irq, void *arg_pv)
|
||||
{
|
||||
USBH_IRQHandler((uint8_t)(uintptr_t)arg_pv);
|
||||
}
|
||||
|
||||
void usb_hc_low_level_init(struct usbh_bus *bus)
|
||||
{
|
||||
uint32_t *hs_reg;
|
||||
uint32_t usb_ctl3;
|
||||
|
||||
if ((uintptr_t)rt_hw_mmu_v2p(&mmu_info, (void *)bus->hcd.reg_base) == usb_dev_addr[0]) {
|
||||
if (!sysctl_reset(SYSCTL_RESET_USB0)) {
|
||||
USB_LOG_ERR("reset usb0 fail\n");
|
||||
}
|
||||
|
||||
hs_reg = (uint32_t *)rt_ioremap((void *)(0x91585000 + 0x7C), 0x1000);
|
||||
usb_ctl3 = *hs_reg | USB_IDPULLUP0;
|
||||
|
||||
*hs_reg = usb_ctl3 | (USB_DMPULLDOWN0 | USB_DPPULLDOWN0);
|
||||
|
||||
rt_iounmap(hs_reg);
|
||||
|
||||
rt_hw_interrupt_install(173, usb_hc_interrupt_cb, (void *)(uintptr_t)bus->hcd.hcd_id, "usbh0");
|
||||
rt_hw_interrupt_umask(173);
|
||||
|
||||
} else {
|
||||
if (!sysctl_reset(SYSCTL_RESET_USB1)) {
|
||||
USB_LOG_ERR("reset usb1 fail\n");
|
||||
}
|
||||
|
||||
hs_reg = (uint32_t *)rt_ioremap((void *)(0x91585000 + 0x9C), 0x1000);
|
||||
usb_ctl3 = *hs_reg | USB_IDPULLUP0;
|
||||
|
||||
*hs_reg = usb_ctl3 | (USB_DMPULLDOWN0 | USB_DPPULLDOWN0);
|
||||
|
||||
rt_iounmap(hs_reg);
|
||||
|
||||
rt_hw_interrupt_install(174, usb_hc_interrupt_cb, (void *)(uintptr_t)bus->hcd.hcd_id, "usbh1");
|
||||
rt_hw_interrupt_umask(174);
|
||||
}
|
||||
}
|
||||
|
||||
void usb_hc_low_level_deinit(struct usbh_bus *bus)
|
||||
{
|
||||
if ((uintptr_t)rt_hw_mmu_v2p(&mmu_info, (void *)bus->hcd.reg_base) == usb_dev_addr[0]) {
|
||||
rt_hw_interrupt_mask(173);
|
||||
} else {
|
||||
rt_hw_interrupt_mask(174);
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_CHERRY_USB_HOST
|
||||
|
||||
// USB Device
|
||||
#if defined(ENABLE_CHERRY_USB_DEVICE) || defined(PKG_CHERRYUSB_DEVICE) || defined(RT_CHERRYUSB_DEVICE)
|
||||
static void usb_dc_interrupt_cb(int irq, void *arg_pv)
|
||||
{
|
||||
USBD_IRQHandler((uint8_t)(uintptr_t)arg_pv);
|
||||
}
|
||||
|
||||
void usb_dc_low_level_init(uint8_t busid)
|
||||
{
|
||||
if ((uintptr_t)rt_hw_mmu_v2p(&mmu_info, (void *)g_usbdev_bus[busid].reg_base) == usb_dev_addr[0]) {
|
||||
if (!sysctl_reset(SYSCTL_RESET_USB0)) {
|
||||
USB_LOG_ERR("reset usb0 fail\n");
|
||||
}
|
||||
|
||||
uint32_t *hs_reg = (uint32_t *)rt_ioremap((void *)(0x91585000 + 0x7C), 0x1000);
|
||||
*hs_reg = 0x37;
|
||||
rt_iounmap(hs_reg);
|
||||
|
||||
rt_hw_interrupt_install(173, usb_dc_interrupt_cb, (void *)(uintptr_t)busid, "usbd0");
|
||||
rt_hw_interrupt_umask(173);
|
||||
} else {
|
||||
if (!sysctl_reset(SYSCTL_RESET_USB1)) {
|
||||
USB_LOG_ERR("reset usb1 fail\n");
|
||||
}
|
||||
|
||||
uint32_t *hs_reg = (uint32_t *)rt_ioremap((void *)(0x91585000 + 0x9C), 0x1000);
|
||||
*hs_reg = 0x37;
|
||||
rt_iounmap(hs_reg);
|
||||
|
||||
rt_hw_interrupt_install(174, usb_dc_interrupt_cb, (void *)(uintptr_t)busid, "usbd1");
|
||||
rt_hw_interrupt_umask(174);
|
||||
}
|
||||
}
|
||||
|
||||
void usb_dc_low_level_deinit(uint8_t busid)
|
||||
{
|
||||
if ((uintptr_t)rt_hw_mmu_v2p(&mmu_info, (void *)g_usbdev_bus[busid].reg_base) == usb_dev_addr[0]) {
|
||||
rt_hw_interrupt_mask(173);
|
||||
} else {
|
||||
rt_hw_interrupt_mask(174);
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_CHERRY_USB_DEVICE
|
||||
|
||||
void usbd_dwc2_delay_ms(uint8_t ms)
|
||||
{
|
||||
rt_thread_mdelay(ms);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_DCACHE_ENABLE
|
||||
void usb_dcache_clean(uintptr_t addr, size_t size)
|
||||
{
|
||||
rt_hw_cpu_dcache_clean((void *)addr, size);
|
||||
}
|
||||
|
||||
void usb_dcache_invalidate(uintptr_t addr, size_t size)
|
||||
{
|
||||
rt_hw_cpu_dcache_invalidate((void *)addr, size);
|
||||
}
|
||||
|
||||
void usb_dcache_flush(uintptr_t addr, size_t size)
|
||||
{
|
||||
rt_hw_cpu_dcache_clean_flush((void *)addr, size);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // ENABLE_CHERRY_USB
|
||||
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* Copyright (c) 2025, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usbd_core.h"
|
||||
#include "usbh_core.h"
|
||||
|
||||
__WEAK void USBD_IRQHandler(uint8_t busid)
|
||||
{
|
||||
}
|
||||
|
||||
__WEAK void USBH_IRQHandler(uint8_t busid)
|
||||
{
|
||||
}
|
||||
|
||||
#if defined(N32H473) || defined(N32H474) || defined(N32H475) || defined(N32H482) || defined(N32H487)
|
||||
#include "n32h47x_48x_rcc.h"
|
||||
#include "n32h47x_48x_gpio.h"
|
||||
#include "n32h47x_48x_exti.h"
|
||||
#include "misc.h"
|
||||
|
||||
typedef void (*usb_dwc2_irq)(uint8_t busid);
|
||||
|
||||
static usb_dwc2_irq g_usb_dwc2_irq;
|
||||
static volatile uint8_t g_usb_dwc2_busid = 0;
|
||||
|
||||
static void usbhs_common_init(void)
|
||||
{
|
||||
RCC_EnableAHB1PeriphClk(RCC_AHB_PERIPHEN_GPIOA | RCC_AHB_PERIPHEN_GPIOB, ENABLE);
|
||||
RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_AFIO, ENABLE);
|
||||
/* PLL= 240MHz */
|
||||
#if (HSE_VALUE == 8000000)
|
||||
/* Select PLL clock as USBHS clock source , clock 15 divisions = 16M */
|
||||
RCC_ConfigUSBPLLPresClk(RCC_USBPLLCLK_SRC_PLL, RCC_USBPLLCLK_DIV15);
|
||||
|
||||
/* Select the corresponding bandwidth and frequency*/
|
||||
RCC_ConfigUSBHSBandwidth(RCC_USBHS_BW_16M);
|
||||
|
||||
/* Select USBHS clock source frequency */
|
||||
RCC_ConfigUSBHSFrequency(RCC_USBHS_FREQ_16_OR_32M);
|
||||
|
||||
/* Select PLL as USBHS clock */
|
||||
RCC_ConfigUSBHSClk(RCC_USBHS_CLKSRC_PLLPRES);
|
||||
#else //HSE 16M
|
||||
RCC_ConfigUSBHSBandwidth(RCC_USBHS_BW_16M);
|
||||
RCC_ConfigUSBHSFrequency(RCC_USBHS_FREQ_16_OR_32M);
|
||||
RCC_ConfigUSBHSClk(RCC_USBHS_CLKSRC_HSE);
|
||||
#endif
|
||||
/* Reset the USBHS phy clock*/
|
||||
RCC_EnableAHBPeriphReset(RCC_AHBPRST_USBHSPHYRST);
|
||||
/* Enables the USBHS peripheral clock*/
|
||||
RCC_EnableAHBPeriphClk(RCC_AHB_PERIPHEN_USBHS, ENABLE);
|
||||
|
||||
NVIC_InitType NVIC_InitStructure;
|
||||
// EXTI_InitType EXTI_InitStructure;
|
||||
|
||||
// NVIC_InitStructure.NVIC_IRQChannel = USB_HS_WKUP_IRQn;
|
||||
// NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
|
||||
// NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
|
||||
// NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
|
||||
// NVIC_Init(&NVIC_InitStructure);
|
||||
|
||||
NVIC_InitStructure.NVIC_IRQChannel = USB_HS_IRQn;
|
||||
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
|
||||
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
|
||||
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
|
||||
NVIC_Init(&NVIC_InitStructure);
|
||||
|
||||
/* Configure the EXTI line 23 connected internally to the USBHS IP */
|
||||
// EXTI_ClrITPendBit(EXTI_LINE23);
|
||||
// EXTI_InitStructure.EXTI_Line = EXTI_LINE23;
|
||||
// EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
|
||||
// EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
|
||||
// EXTI_InitStructure.EXTI_LineCmd = ENABLE;
|
||||
// EXTI_InitPeripheral(&EXTI_InitStructure);
|
||||
}
|
||||
|
||||
static void usbhs_gpio_init(void)
|
||||
{
|
||||
GPIO_InitType GPIO_InitStructure;
|
||||
|
||||
RCC_EnableAHB1PeriphClk(RCC_AHB_PERIPHEN_GPIOA | RCC_AHB_PERIPHEN_GPIOB | RCC_AHB_PERIPHEN_GPIOE, ENABLE);
|
||||
RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_AFIO, ENABLE);
|
||||
GPIO_ConfigPinRemap(0, 0, GPIO_RMP_SWJ_SWD);
|
||||
|
||||
GPIO_InitStruct(&GPIO_InitStructure);
|
||||
#ifdef USBHS_HOST
|
||||
GPIO_InitStructure.Pin = GPIO_PIN_1;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_MODE_OUTPUT_PP;
|
||||
GPIO_InitPeripheral(GPIOE, &GPIO_InitStructure);
|
||||
GPIO_ResetBits(GPIOE, GPIO_PIN_1);
|
||||
|
||||
GPIO_InitStructure.Pin = GPIO_PIN_3;
|
||||
GPIO_InitPeripheral(GPIOB, &GPIO_InitStructure);
|
||||
GPIO_ResetBits(GPIOB, GPIO_PIN_3);
|
||||
#endif
|
||||
// VBUS
|
||||
// GPIO_InitStructure.Pin = GPIO_PIN_13;
|
||||
// GPIO_InitStructure.GPIO_Mode = GPIO_MODE_INPUT;
|
||||
// GPIO_InitPeripheral(GPIOB, &GPIO_InitStructure);
|
||||
|
||||
// // SOF
|
||||
// GPIO_InitStructure.Pin = GPIO_PIN_4;
|
||||
// GPIO_InitStructure.GPIO_Mode = GPIO_MODE_AF_PP;
|
||||
// GPIO_InitStructure.GPIO_Alternate = 8; // SOF
|
||||
// GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
|
||||
|
||||
// // ID
|
||||
// GPIO_InitStructure.Pin = GPIO_PIN_12;
|
||||
// GPIO_InitStructure.GPIO_Mode = GPIO_MODE_AF_PP;
|
||||
// GPIO_InitStructure.GPIO_Alternate = 14; // ID
|
||||
// GPIO_InitPeripheral(GPIOB, &GPIO_InitStructure);
|
||||
}
|
||||
|
||||
void usb_dc_low_level_init(uint8_t busid)
|
||||
{
|
||||
g_usb_dwc2_irq = USBD_IRQHandler;
|
||||
g_usb_dwc2_busid = busid;
|
||||
|
||||
usbhs_common_init();
|
||||
|
||||
RCC->USBHSCTRL2 |= (uint32_t)0x01 << 19;
|
||||
RCC->USBHSCTRL1 |= (uint32_t)0x01 << 31;
|
||||
}
|
||||
|
||||
void usb_dc_low_level_deinit(uint8_t busid)
|
||||
{
|
||||
NVIC_InitType NVIC_InitStructure;
|
||||
|
||||
NVIC_InitStructure.NVIC_IRQChannel = USB_HS_IRQn;
|
||||
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
|
||||
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
|
||||
NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE;
|
||||
NVIC_Init(&NVIC_InitStructure);
|
||||
|
||||
RCC_EnableAHBPeriphReset(RCC_AHBPRST_USBHSPHYRST);
|
||||
/* Enables the USBHS peripheral clock*/
|
||||
RCC_EnableAHBPeriphClk(RCC_AHB_PERIPHEN_USBHS, DISABLE);
|
||||
}
|
||||
|
||||
void usb_hc_low_level_init(struct usbh_bus *bus)
|
||||
{
|
||||
g_usb_dwc2_irq = USBH_IRQHandler;
|
||||
g_usb_dwc2_busid = 0;
|
||||
|
||||
usbhs_common_init();
|
||||
|
||||
RCC->USBHSCTRL2 &= ~(uint32_t)0x01 << 19;
|
||||
RCC->USBHSCTRL1 |= (uint32_t)0x01 << 31;
|
||||
}
|
||||
|
||||
void usb_hc_low_level_deinit(struct usbh_bus *bus)
|
||||
{
|
||||
NVIC_InitType NVIC_InitStructure;
|
||||
|
||||
NVIC_InitStructure.NVIC_IRQChannel = USB_HS_IRQn;
|
||||
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
|
||||
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
|
||||
NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE;
|
||||
NVIC_Init(&NVIC_InitStructure);
|
||||
|
||||
RCC_EnableAHBPeriphReset(RCC_AHBPRST_USBHSPHYRST);
|
||||
/* Enables the USBHS peripheral clock*/
|
||||
RCC_EnableAHBPeriphClk(RCC_AHB_PERIPHEN_USBHS, DISABLE);
|
||||
}
|
||||
|
||||
uint32_t usbd_get_dwc2_gccfg_conf(uint32_t reg_base)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t usbh_get_dwc2_gccfg_conf(uint32_t reg_base)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void USB_HS_IRQHandler(void)
|
||||
{
|
||||
g_usb_dwc2_irq(g_usb_dwc2_busid);
|
||||
}
|
||||
|
||||
extern uint32_t SystemCoreClock;
|
||||
|
||||
void usbd_dwc2_delay_ms(uint8_t ms)
|
||||
{
|
||||
uint32_t count = SystemCoreClock / 1000 * ms;
|
||||
while (count--) {
|
||||
__asm volatile("nop");
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,750 @@
|
||||
/*
|
||||
* Copyright (c) 2024, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usbd_core.h"
|
||||
#include "usbh_core.h"
|
||||
#include "usb_dwc2_param.h"
|
||||
|
||||
#ifndef CONFIG_USB_DWC2_CUSTOM_PARAM
|
||||
|
||||
#if __has_include("stm32f1xx_hal.h")
|
||||
#include "stm32f1xx_hal.h"
|
||||
|
||||
const struct dwc2_user_params param_pa11_pa12 = {
|
||||
.phy_type = DWC2_PHY_TYPE_PARAM_FS,
|
||||
.device_dma_enable = false,
|
||||
.device_dma_desc_enable = false,
|
||||
.device_rx_fifo_size = (320 - 16 - 16 - 16 - 16),
|
||||
.device_tx_fifo_size = {
|
||||
[0] = 16, // 64 byte
|
||||
[1] = 16, // 64 byte
|
||||
[2] = 16, // 64 byte
|
||||
[3] = 16, // 64 byte
|
||||
[4] = 0,
|
||||
[5] = 0,
|
||||
[6] = 0,
|
||||
[7] = 0,
|
||||
[8] = 0,
|
||||
[9] = 0,
|
||||
[10] = 0,
|
||||
[11] = 0,
|
||||
[12] = 0,
|
||||
[13] = 0,
|
||||
[14] = 0,
|
||||
[15] = 0 },
|
||||
|
||||
.device_gccfg = ((1 << 16) | (1 << 21)), // fs: USB_OTG_GCCFG_PWRDWN | USB_OTG_GCCFG_NOVBUSSENS
|
||||
.total_fifo_size = 320 // 1280 byte
|
||||
};
|
||||
|
||||
const struct dwc2_user_params param_pb14_pb15 = { 0 }; // do not support
|
||||
#if defined(HAL_HCD_MODULE_ENABLED)
|
||||
#error "HAL_HCD_MODULE_ENABLED is not supported for STM32F1xx, please use HAL_PCD_MODULE_ENABLED"
|
||||
#endif
|
||||
#elif __has_include("stm32f2xx_hal.h")
|
||||
#include "stm32f2xx_hal.h"
|
||||
|
||||
const struct dwc2_user_params param_pa11_pa12 = {
|
||||
.phy_type = DWC2_PHY_TYPE_PARAM_FS,
|
||||
.device_dma_enable = false,
|
||||
.device_dma_desc_enable = false,
|
||||
.device_rx_fifo_size = (320 - 16 - 16 - 16 - 16),
|
||||
.device_tx_fifo_size = {
|
||||
[0] = 16, // 64 byte
|
||||
[1] = 16, // 64 byte
|
||||
[2] = 16, // 64 byte
|
||||
[3] = 16, // 64 byte
|
||||
[4] = 0,
|
||||
[5] = 0,
|
||||
[6] = 0,
|
||||
[7] = 0,
|
||||
[8] = 0,
|
||||
[9] = 0,
|
||||
[10] = 0,
|
||||
[11] = 0,
|
||||
[12] = 0,
|
||||
[13] = 0,
|
||||
[14] = 0,
|
||||
[15] = 0 },
|
||||
|
||||
.device_gccfg = ((1 << 16) | (1 << 21)), // fs: USB_OTG_GCCFG_PWRDWN | USB_OTG_GCCFG_NOVBUSSENS
|
||||
.total_fifo_size = 320 // 1280 byte
|
||||
};
|
||||
|
||||
const struct dwc2_user_params param_pb14_pb15 = {
|
||||
#ifdef CONFIG_USB_HS
|
||||
.phy_type = DWC2_PHY_TYPE_PARAM_UTMI,
|
||||
#else
|
||||
.phy_type = DWC2_PHY_TYPE_PARAM_FS,
|
||||
#endif
|
||||
#ifdef CONFIG_USB_DWC2_DMA_ENABLE
|
||||
.device_dma_enable = true,
|
||||
#else
|
||||
.device_dma_enable = false,
|
||||
#endif
|
||||
.device_dma_desc_enable = false,
|
||||
.device_rx_fifo_size = (1012 - 16 - 256 - 128 - 128 - 128 - 128),
|
||||
.device_tx_fifo_size = {
|
||||
[0] = 16, // 64 byte
|
||||
[1] = 256, // 1024 byte
|
||||
[2] = 128, // 512 byte
|
||||
[3] = 128, // 512 byte
|
||||
[4] = 128, // 512 byte
|
||||
[5] = 128, // 512 byte
|
||||
[6] = 0,
|
||||
[7] = 0,
|
||||
[8] = 0,
|
||||
[9] = 0,
|
||||
[10] = 0,
|
||||
[11] = 0,
|
||||
[12] = 0,
|
||||
[13] = 0,
|
||||
[14] = 0,
|
||||
[15] = 0 },
|
||||
|
||||
.host_dma_desc_enable = false,
|
||||
.host_rx_fifo_size = 628,
|
||||
.host_nperio_tx_fifo_size = 128, // 512 byte
|
||||
.host_perio_tx_fifo_size = 256, // 1024 byte
|
||||
|
||||
#ifdef CONFIG_USB_HS
|
||||
.device_gccfg = 0,
|
||||
.host_gccfg = 0,
|
||||
#else
|
||||
.device_gccfg = ((1 << 16) | (1 << 21)), // fs: USB_OTG_GCCFG_PWRDWN | USB_OTG_GCCFG_NOVBUSSENS hs:0
|
||||
.host_gccfg = ((1 << 16) | (1 << 21)) // fs: USB_OTG_GCCFG_PWRDWN | USB_OTG_GCCFG_NOVBUSSENS hs:0
|
||||
#endif
|
||||
};
|
||||
#elif __has_include("stm32f4xx_hal.h")
|
||||
#include "stm32f4xx_hal.h"
|
||||
|
||||
const struct dwc2_user_params param_pa11_pa12 = {
|
||||
.phy_type = DWC2_PHY_TYPE_PARAM_FS,
|
||||
.device_dma_enable = false,
|
||||
.device_dma_desc_enable = false,
|
||||
.device_rx_fifo_size = (320 - 16 - 16 - 16 - 16),
|
||||
.device_tx_fifo_size = {
|
||||
[0] = 16, // 64 byte
|
||||
[1] = 16, // 64 byte
|
||||
[2] = 16, // 64 byte
|
||||
[3] = 16, // 64 byte
|
||||
[4] = 0,
|
||||
[5] = 0,
|
||||
[6] = 0,
|
||||
[7] = 0,
|
||||
[8] = 0,
|
||||
[9] = 0,
|
||||
[10] = 0,
|
||||
[11] = 0,
|
||||
[12] = 0,
|
||||
[13] = 0,
|
||||
[14] = 0,
|
||||
[15] = 0 },
|
||||
|
||||
#if defined(STM32F446xx) || defined(STM32F469xx) || defined(STM32F479xx) || \
|
||||
defined(STM32F412Zx) || defined(STM32F412Vx) || defined(STM32F412Rx) || defined(STM32F412Cx) || defined(STM32F413xx) || \
|
||||
defined(STM32F423xx)
|
||||
.device_gccfg = (1 << 16), // fs: USB_OTG_GCCFG_PWRDWN
|
||||
.b_session_valid_override = true,
|
||||
#else
|
||||
.device_gccfg = ((1 << 16) | (1 << 21)), // fs: USB_OTG_GCCFG_PWRDWN | USB_OTG_GCCFG_NOVBUSSENS
|
||||
#endif
|
||||
.total_fifo_size = 320 // 1280 byte
|
||||
};
|
||||
|
||||
const struct dwc2_user_params param_pb14_pb15 = {
|
||||
#ifdef CONFIG_USB_HS
|
||||
.phy_type = DWC2_PHY_TYPE_PARAM_UTMI,
|
||||
#else
|
||||
.phy_type = DWC2_PHY_TYPE_PARAM_FS,
|
||||
#endif
|
||||
#ifdef CONFIG_USB_DWC2_DMA_ENABLE
|
||||
.device_dma_enable = true,
|
||||
#else
|
||||
.device_dma_enable = false,
|
||||
#endif
|
||||
.device_dma_desc_enable = false,
|
||||
.device_rx_fifo_size = (1006 - 16 - 256 - 128 - 128 - 128 - 128), // 1006/1012
|
||||
.device_tx_fifo_size = {
|
||||
[0] = 16, // 64 byte
|
||||
[1] = 256, // 1024 byte
|
||||
[2] = 128, // 512 byte
|
||||
[3] = 128, // 512 byte
|
||||
[4] = 128, // 512 byte
|
||||
[5] = 128, // 512 byte
|
||||
[6] = 0,
|
||||
[7] = 0,
|
||||
[8] = 0,
|
||||
[9] = 0,
|
||||
[10] = 0,
|
||||
[11] = 0,
|
||||
[12] = 0,
|
||||
[13] = 0,
|
||||
[14] = 0,
|
||||
[15] = 0 },
|
||||
|
||||
.host_dma_desc_enable = false,
|
||||
.host_rx_fifo_size = 622,
|
||||
.host_nperio_tx_fifo_size = 128, // 512 byte
|
||||
.host_perio_tx_fifo_size = 256, // 1024 byte
|
||||
#ifdef CONFIG_USB_HS
|
||||
.device_gccfg = 0,
|
||||
.host_gccfg = 0,
|
||||
#else
|
||||
#if defined(STM32F446xx) || defined(STM32F469xx) || defined(STM32F479xx) || \
|
||||
defined(STM32F412Zx) || defined(STM32F412Vx) || defined(STM32F412Rx) || defined(STM32F412Cx) || defined(STM32F413xx) || \
|
||||
defined(STM32F423xx)
|
||||
.device_gccfg = (1 << 16), // fs: USB_OTG_GCCFG_PWRDWN
|
||||
.host_gccfg = (1 << 16), // fs: USB_OTG_GCCFG_PWRDWN
|
||||
.b_session_valid_override = true,
|
||||
#else
|
||||
.device_gccfg = ((1 << 16) | (1 << 21)), // fs: USB_OTG_GCCFG_PWRDWN | USB_OTG_GCCFG_NOVBUSSENS hs:0
|
||||
.host_gccfg = ((1 << 16) | (1 << 21)) // fs: USB_OTG_GCCFG_PWRDWN | USB_OTG_GCCFG_NOVBUSSENS hs:0
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
#elif __has_include("stm32f7xx_hal.h")
|
||||
#include "stm32f7xx_hal.h"
|
||||
|
||||
const struct dwc2_user_params param_pa11_pa12 = {
|
||||
.phy_type = DWC2_PHY_TYPE_PARAM_FS,
|
||||
.device_dma_enable = false,
|
||||
.device_dma_desc_enable = false,
|
||||
.device_rx_fifo_size = (320 - 16 - 16 - 16 - 16),
|
||||
.device_tx_fifo_size = {
|
||||
[0] = 16, // 64 byte
|
||||
[1] = 16, // 64 byte
|
||||
[2] = 16, // 64 byte
|
||||
[3] = 16, // 64 byte
|
||||
[4] = 0,
|
||||
[5] = 0,
|
||||
[6] = 0,
|
||||
[7] = 0,
|
||||
[8] = 0,
|
||||
[9] = 0,
|
||||
[10] = 0,
|
||||
[11] = 0,
|
||||
[12] = 0,
|
||||
[13] = 0,
|
||||
[14] = 0,
|
||||
[15] = 0 },
|
||||
|
||||
.device_gccfg = (1 << 16), // fs: USB_OTG_GCCFG_PWRDWN
|
||||
.host_gccfg = (1 << 16), // fs: USB_OTG_GCCFG_PWRDWN
|
||||
|
||||
.b_session_valid_override = true,
|
||||
.total_fifo_size = 320 // 1280 byte
|
||||
};
|
||||
|
||||
const struct dwc2_user_params param_pb14_pb15 = {
|
||||
#if defined(STM32F722xx) || defined(STM32F723xx) || defined(STM32F730xx) || defined(STM32F732xx) || defined(STM32F733xx)
|
||||
.phy_type = DWC2_PHY_TYPE_PARAM_UTMI,
|
||||
#else
|
||||
.phy_type = DWC2_PHY_TYPE_PARAM_FS,
|
||||
#endif
|
||||
#ifdef CONFIG_USB_DWC2_DMA_ENABLE
|
||||
.device_dma_enable = true,
|
||||
#else
|
||||
.device_dma_enable = false,
|
||||
#endif
|
||||
.device_dma_desc_enable = false,
|
||||
.device_rx_fifo_size = (1006 - 16 - 256 - 128 - 128 - 128 - 128),
|
||||
.device_tx_fifo_size = {
|
||||
[0] = 16, // 64 byte
|
||||
[1] = 256, // 1024 byte
|
||||
[2] = 128, // 512 byte
|
||||
[3] = 128, // 512 byte
|
||||
[4] = 128, // 512 byte
|
||||
[5] = 128, // 512 byte
|
||||
[6] = 0,
|
||||
[7] = 0,
|
||||
[8] = 0,
|
||||
[9] = 0,
|
||||
[10] = 0,
|
||||
[11] = 0,
|
||||
[12] = 0,
|
||||
[13] = 0,
|
||||
[14] = 0,
|
||||
[15] = 0 },
|
||||
|
||||
.host_dma_desc_enable = false,
|
||||
.host_rx_fifo_size = 622,
|
||||
.host_nperio_tx_fifo_size = 128, // 512 byte
|
||||
.host_perio_tx_fifo_size = 256, // 1024 byte
|
||||
#if defined(STM32F722xx) || defined(STM32F723xx) || defined(STM32F730xx) || defined(STM32F732xx) || defined(STM32F733xx)
|
||||
.device_gccfg = (1 << 23), // USB_OTG_GCCFG_PHYHSEN
|
||||
.host_gccfg = (1 << 23), // USB_OTG_GCCFG_PHYHSEN
|
||||
#else
|
||||
#ifdef CONFIG_USB_HS
|
||||
.device_gccfg = 0,
|
||||
.host_gccfg = 0,
|
||||
#else
|
||||
.device_gccfg = (1 << 16), // fs: USB_OTG_GCCFG_PWRDWN hs:0
|
||||
.host_gccfg = (1 << 16), // fs: USB_OTG_GCCFG_PWRDWN hs:0
|
||||
#endif
|
||||
#endif
|
||||
.b_session_valid_override = true
|
||||
};
|
||||
#elif __has_include("stm32h7xx_hal.h")
|
||||
#include "stm32h7xx_hal.h"
|
||||
|
||||
const struct dwc2_user_params param_pa11_pa12 = {
|
||||
.phy_type = DWC2_PHY_TYPE_PARAM_FS, // DWC2_PHY_TYPE_PARAM_UTMI
|
||||
#ifdef CONFIG_USB_DWC2_DMA_ENABLE
|
||||
.device_dma_enable = true,
|
||||
#else
|
||||
.device_dma_enable = false,
|
||||
#endif
|
||||
.device_dma_desc_enable = false,
|
||||
.device_rx_fifo_size = (952 - 16 - 256 - 128 - 128 - 128 - 128),
|
||||
.device_tx_fifo_size = {
|
||||
[0] = 16, // 64 byte
|
||||
[1] = 256, // 1024 byte
|
||||
[2] = 128, // 512 byte
|
||||
[3] = 128, // 512 byte
|
||||
[4] = 128, // 512 byte
|
||||
[5] = 128, // 512 byte
|
||||
[6] = 0,
|
||||
[7] = 0,
|
||||
[8] = 0,
|
||||
[9] = 0,
|
||||
[10] = 0,
|
||||
[11] = 0,
|
||||
[12] = 0,
|
||||
[13] = 0,
|
||||
[14] = 0,
|
||||
[15] = 0 },
|
||||
|
||||
.host_dma_desc_enable = false,
|
||||
.host_rx_fifo_size = 568,
|
||||
.host_nperio_tx_fifo_size = 128, // 512 byte
|
||||
.host_perio_tx_fifo_size = 256, // 1024 byte
|
||||
|
||||
.device_gccfg = (1 << 16), // fs: USB_OTG_GCCFG_PWRDWN hs:0
|
||||
.host_gccfg = (1 << 16), // fs: USB_OTG_GCCFG_PWRDWN hs:0
|
||||
|
||||
.b_session_valid_override = true
|
||||
};
|
||||
|
||||
const struct dwc2_user_params param_pb14_pb15 = {
|
||||
#ifdef CONFIG_USB_HS
|
||||
.phy_type = DWC2_PHY_TYPE_PARAM_UTMI,
|
||||
#else
|
||||
.phy_type = DWC2_PHY_TYPE_PARAM_FS,
|
||||
#endif
|
||||
#ifdef CONFIG_USB_DWC2_DMA_ENABLE
|
||||
.device_dma_enable = true,
|
||||
#else
|
||||
.device_dma_enable = false,
|
||||
#endif
|
||||
.device_dma_desc_enable = false,
|
||||
.device_rx_fifo_size = (952 - 16 - 256 - 128 - 128 - 128 - 128),
|
||||
.device_tx_fifo_size = {
|
||||
[0] = 16, // 64 byte
|
||||
[1] = 256, // 1024 byte
|
||||
[2] = 128, // 512 byte
|
||||
[3] = 128, // 512 byte
|
||||
[4] = 128, // 512 byte
|
||||
[5] = 128, // 512 byte
|
||||
[6] = 0,
|
||||
[7] = 0,
|
||||
[8] = 0,
|
||||
[9] = 0,
|
||||
[10] = 0,
|
||||
[11] = 0,
|
||||
[12] = 0,
|
||||
[13] = 0,
|
||||
[14] = 0,
|
||||
[15] = 0 },
|
||||
|
||||
.host_dma_desc_enable = false,
|
||||
.host_rx_fifo_size = 568,
|
||||
.host_nperio_tx_fifo_size = 128, // 512 byte
|
||||
.host_perio_tx_fifo_size = 256, // 1024 byte
|
||||
|
||||
#ifdef CONFIG_USB_HS
|
||||
.device_gccfg = 0,
|
||||
.host_gccfg = 0,
|
||||
#else
|
||||
.device_gccfg = (1 << 16), // fs: USB_OTG_GCCFG_PWRDWN hs:0
|
||||
.host_gccfg = (1 << 16), // fs: USB_OTG_GCCFG_PWRDWN hs:0
|
||||
#endif
|
||||
.b_session_valid_override = true
|
||||
};
|
||||
#elif __has_include("stm32h7rsxx_hal.h")
|
||||
#include "stm32h7rsxx_hal.h"
|
||||
|
||||
const struct dwc2_user_params param_pa11_pa12 = {
|
||||
.phy_type = DWC2_PHY_TYPE_PARAM_FS,
|
||||
.device_dma_enable = false,
|
||||
.device_dma_desc_enable = false,
|
||||
.device_rx_fifo_size = (320 - 16 - 16 - 16 - 16),
|
||||
.device_tx_fifo_size = {
|
||||
[0] = 16, // 64 byte
|
||||
[1] = 16, // 64 byte
|
||||
[2] = 16, // 64 byte
|
||||
[3] = 16, // 64 byte
|
||||
[4] = 0,
|
||||
[5] = 0,
|
||||
[6] = 0,
|
||||
[7] = 0,
|
||||
[8] = 0,
|
||||
[9] = 0,
|
||||
[10] = 0,
|
||||
[11] = 0,
|
||||
[12] = 0,
|
||||
[13] = 0,
|
||||
[14] = 0,
|
||||
[15] = 0 },
|
||||
|
||||
.device_gccfg = (1 << 16), // fs: USB_OTG_GCCFG_PWRDWN
|
||||
.b_session_valid_override = true,
|
||||
.total_fifo_size = 320 // 1280 byte
|
||||
};
|
||||
|
||||
const struct dwc2_user_params param_pb14_pb15 = {
|
||||
.phy_type = DWC2_PHY_TYPE_PARAM_UTMI,
|
||||
#ifdef CONFIG_USB_DWC2_DMA_ENABLE
|
||||
.device_dma_enable = true,
|
||||
#else
|
||||
.device_dma_enable = false,
|
||||
#endif
|
||||
.device_dma_desc_enable = false,
|
||||
.device_rx_fifo_size = (952 - 16 - 256 - 128 - 128 - 128 - 128),
|
||||
.device_tx_fifo_size = {
|
||||
[0] = 16, // 64 byte
|
||||
[1] = 256, // 1024 byte
|
||||
[2] = 128, // 512 byte
|
||||
[3] = 128, // 512 byte
|
||||
[4] = 128, // 512 byte
|
||||
[5] = 128, // 512 byte
|
||||
[6] = 0,
|
||||
[7] = 0,
|
||||
[8] = 0,
|
||||
[9] = 0,
|
||||
[10] = 0,
|
||||
[11] = 0,
|
||||
[12] = 0,
|
||||
[13] = 0,
|
||||
[14] = 0,
|
||||
[15] = 0 },
|
||||
|
||||
.host_dma_desc_enable = false,
|
||||
.host_rx_fifo_size = 568,
|
||||
.host_nperio_tx_fifo_size = 128, // 512 byte
|
||||
.host_perio_tx_fifo_size = 256, // 1024 byte
|
||||
|
||||
.device_gccfg = ((1 << 23) | (1 << 24)), // hs: USB_OTG_GCCFG_VBVALEXTOEN | USB_OTG_GCCFG_VBVALOVAL
|
||||
.host_gccfg = (1 << 25) // hs: USB_OTG_GCCFG_PULLDOWNEN
|
||||
};
|
||||
#elif __has_include("stm32l4xx_hal.h")
|
||||
#include "stm32l4xx_hal.h"
|
||||
|
||||
const struct dwc2_user_params param_pa11_pa12 = {
|
||||
.phy_type = DWC2_PHY_TYPE_PARAM_FS,
|
||||
.device_dma_enable = false,
|
||||
.device_dma_desc_enable = false,
|
||||
.device_rx_fifo_size = (320 - 16 - 16 - 16 - 16),
|
||||
.device_tx_fifo_size = {
|
||||
[0] = 16, // 64 byte
|
||||
[1] = 16, // 64 byte
|
||||
[2] = 16, // 64 byte
|
||||
[3] = 16, // 64 byte
|
||||
[4] = 0,
|
||||
[5] = 0,
|
||||
[6] = 0,
|
||||
[7] = 0,
|
||||
[8] = 0,
|
||||
[9] = 0,
|
||||
[10] = 0,
|
||||
[11] = 0,
|
||||
[12] = 0,
|
||||
[13] = 0,
|
||||
[14] = 0,
|
||||
[15] = 0 },
|
||||
|
||||
.device_gccfg = (1 << 16),
|
||||
.b_session_valid_override = true,
|
||||
.total_fifo_size = 320 // 1280 byte
|
||||
};
|
||||
|
||||
const struct dwc2_user_params param_pb14_pb15 = { 0 }; // do not support
|
||||
#if defined(HAL_HCD_MODULE_ENABLED)
|
||||
#error "HAL_HCD_MODULE_ENABLED is not supported for STM32L4xx, please use HAL_PCD_MODULE_ENABLED"
|
||||
#endif
|
||||
#elif __has_include("stm32u5xx_hal.h")
|
||||
#include "stm32u5xx_hal.h"
|
||||
|
||||
const struct dwc2_user_params param_pa11_pa12 = {
|
||||
.phy_type = DWC2_PHY_TYPE_PARAM_FS,
|
||||
.device_dma_enable = false,
|
||||
.device_dma_desc_enable = false,
|
||||
.device_rx_fifo_size = (320 - 16 - 16 - 16 - 16),
|
||||
.device_tx_fifo_size = {
|
||||
[0] = 16, // 64 byte
|
||||
[1] = 16, // 64 byte
|
||||
[2] = 16, // 64 byte
|
||||
[3] = 16, // 64 byte
|
||||
[4] = 0,
|
||||
[5] = 0,
|
||||
[6] = 0,
|
||||
[7] = 0,
|
||||
[8] = 0,
|
||||
[9] = 0,
|
||||
[10] = 0,
|
||||
[11] = 0,
|
||||
[12] = 0,
|
||||
[13] = 0,
|
||||
[14] = 0,
|
||||
[15] = 0 },
|
||||
|
||||
.device_gccfg = (1 << 16),
|
||||
.b_session_valid_override = true,
|
||||
.total_fifo_size = 320 // 1280 byte
|
||||
};
|
||||
|
||||
#if defined(STM32U595xx) || defined(STM32U5A5xx) || defined(STM32U599xx) || defined(STM32U5A9xx) || \
|
||||
defined(STM32U5F7xx) || defined(STM32U5G7xx) || defined(STM32U5F9xx) || defined(STM32U5G9xx)
|
||||
const struct dwc2_user_params param_pb14_pb15 = {
|
||||
.phy_type = DWC2_PHY_TYPE_PARAM_UTMI,
|
||||
#ifdef CONFIG_USB_DWC2_DMA_ENABLE
|
||||
.device_dma_enable = true,
|
||||
#else
|
||||
.device_dma_enable = false,
|
||||
#endif
|
||||
.device_dma_desc_enable = false,
|
||||
.device_rx_fifo_size = (952 - 16 - 256 - 128 - 128 - 128 - 128),
|
||||
.device_tx_fifo_size = {
|
||||
[0] = 16, // 64 byte
|
||||
[1] = 256, // 1024 byte
|
||||
[2] = 128, // 512 byte
|
||||
[3] = 128, // 512 byte
|
||||
[4] = 128, // 512 byte
|
||||
[5] = 128, // 512 byte
|
||||
[6] = 0,
|
||||
[7] = 0,
|
||||
[8] = 0,
|
||||
[9] = 0,
|
||||
[10] = 0,
|
||||
[11] = 0,
|
||||
[12] = 0,
|
||||
[13] = 0,
|
||||
[14] = 0,
|
||||
[15] = 0 },
|
||||
|
||||
.host_dma_desc_enable = false,
|
||||
.host_rx_fifo_size = 568,
|
||||
.host_nperio_tx_fifo_size = 128, // 512 byte
|
||||
.host_perio_tx_fifo_size = 256, // 1024 byte
|
||||
|
||||
.device_gccfg = ((1 << 23) | (1 << 24)), // hs: USB_OTG_GCCFG_VBVALEXTOEN | USB_OTG_GCCFG_VBVALOVAL
|
||||
.host_gccfg = (1 << 25) // hs: USB_OTG_GCCFG_PULLDOWNEN
|
||||
};
|
||||
#else
|
||||
const struct dwc2_user_params param_pb14_pb15 = { 0 }; // do not support
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // CONFIG_USB_DWC2_CUSTOM_PARAM
|
||||
|
||||
#if !defined(HAL_HCD_MODULE_ENABLED) && !defined(HAL_PCD_MODULE_ENABLED)
|
||||
#error please define HAL_HCD_MODULE_ENABLED or HAL_PCD_MODULE_ENABLED in stm32xxx_hal_conf.h
|
||||
#endif
|
||||
|
||||
typedef void (*usb_dwc2_irq)(uint8_t busid);
|
||||
|
||||
struct dwc2_instance {
|
||||
USB_OTG_GlobalTypeDef *Instance;
|
||||
};
|
||||
|
||||
static usb_dwc2_irq g_usb_dwc2_irq[2];
|
||||
static uint8_t g_usb_dwc2_busid[2] = { 0, 0 };
|
||||
static struct dwc2_instance g_dwc2_instance;
|
||||
|
||||
#if defined(STM32F722xx) || defined(STM32F723xx) || defined(STM32F730xx) || defined(STM32F732xx) || defined(STM32F733xx)
|
||||
/**
|
||||
* @brief Enables control of a High Speed USB PHY
|
||||
* Init the low level hardware : GPIO, CLOCK, NVIC...
|
||||
* @param USBx Selected device
|
||||
* @retval HAL status
|
||||
*/
|
||||
static int usb_hsphy_init(uint32_t hse_value)
|
||||
{
|
||||
__IO uint32_t count = 0U;
|
||||
|
||||
/* Enable LDO */
|
||||
USB_HS_PHYC->USB_HS_PHYC_LDO |= USB_HS_PHYC_LDO_ENABLE;
|
||||
|
||||
/* wait for LDO Ready */
|
||||
while ((USB_HS_PHYC->USB_HS_PHYC_LDO & USB_HS_PHYC_LDO_STATUS) == 0U) {
|
||||
count++;
|
||||
|
||||
if (count > 200000U) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Controls PHY frequency operation selection */
|
||||
if (hse_value == 12000000U) /* HSE = 12MHz */
|
||||
{
|
||||
USB_HS_PHYC->USB_HS_PHYC_PLL = (0x0U << 1);
|
||||
} else if (hse_value == 12500000U) /* HSE = 12.5MHz */
|
||||
{
|
||||
USB_HS_PHYC->USB_HS_PHYC_PLL = (0x2U << 1);
|
||||
} else if (hse_value == 16000000U) /* HSE = 16MHz */
|
||||
{
|
||||
USB_HS_PHYC->USB_HS_PHYC_PLL = (0x3U << 1);
|
||||
} else if (hse_value == 24000000U) /* HSE = 24MHz */
|
||||
{
|
||||
USB_HS_PHYC->USB_HS_PHYC_PLL = (0x4U << 1);
|
||||
} else if (hse_value == 25000000U) /* HSE = 25MHz */
|
||||
{
|
||||
USB_HS_PHYC->USB_HS_PHYC_PLL = (0x5U << 1);
|
||||
} else if (hse_value == 32000000U) /* HSE = 32MHz */
|
||||
{
|
||||
USB_HS_PHYC->USB_HS_PHYC_PLL = (0x7U << 1);
|
||||
} else {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
/* Control the tuning interface of the High Speed PHY */
|
||||
USB_HS_PHYC->USB_HS_PHYC_TUNE |= USB_HS_PHYC_TUNE_VALUE;
|
||||
|
||||
/* Enable PLL internal PHY */
|
||||
USB_HS_PHYC->USB_HS_PHYC_PLL |= USB_HS_PHYC_PLL_PLLEN;
|
||||
|
||||
/* 2ms Delay required to get internal phy clock stable */
|
||||
HAL_Delay(2U);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAL_PCD_MODULE_ENABLED
|
||||
void usb_dc_low_level_init(uint8_t busid)
|
||||
{
|
||||
if (g_usbdev_bus[busid].reg_base == 0x40040000UL) { // USB_OTG_HS_PERIPH_BASE
|
||||
g_usb_dwc2_busid[1] = busid;
|
||||
g_usb_dwc2_irq[1] = USBD_IRQHandler;
|
||||
} else {
|
||||
g_usb_dwc2_busid[0] = busid;
|
||||
g_usb_dwc2_irq[0] = USBD_IRQHandler;
|
||||
}
|
||||
|
||||
g_dwc2_instance.Instance = (USB_OTG_GlobalTypeDef *)g_usbdev_bus[busid].reg_base;
|
||||
HAL_PCD_MspInit((PCD_HandleTypeDef *)&g_dwc2_instance);
|
||||
|
||||
#if defined(STM32F722xx) || defined(STM32F723xx) || defined(STM32F730xx) || defined(STM32F732xx) || defined(STM32F733xx)
|
||||
usb_hsphy_init(25000000U);
|
||||
#endif
|
||||
}
|
||||
|
||||
void usb_dc_low_level_deinit(uint8_t busid)
|
||||
{
|
||||
if (g_usbdev_bus[busid].reg_base == 0x40040000UL) { // USB_OTG_HS_PERIPH_BASE
|
||||
g_usb_dwc2_busid[1] = 0;
|
||||
g_usb_dwc2_irq[1] = NULL;
|
||||
} else {
|
||||
g_usb_dwc2_busid[0] = 0;
|
||||
g_usb_dwc2_irq[0] = NULL;
|
||||
}
|
||||
|
||||
g_dwc2_instance.Instance = (USB_OTG_GlobalTypeDef *)g_usbdev_bus[busid].reg_base;
|
||||
HAL_PCD_MspDeInit((PCD_HandleTypeDef *)&g_dwc2_instance);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAL_HCD_MODULE_ENABLED
|
||||
void usb_hc_low_level_init(struct usbh_bus *bus)
|
||||
{
|
||||
if (bus->hcd.reg_base == 0x40040000UL) { // USB_OTG_HS_PERIPH_BASE
|
||||
g_usb_dwc2_busid[1] = bus->hcd.hcd_id;
|
||||
g_usb_dwc2_irq[1] = USBH_IRQHandler;
|
||||
} else {
|
||||
g_usb_dwc2_busid[0] = bus->hcd.hcd_id;
|
||||
g_usb_dwc2_irq[0] = USBH_IRQHandler;
|
||||
}
|
||||
|
||||
g_dwc2_instance.Instance = (USB_OTG_GlobalTypeDef *)bus->hcd.reg_base;
|
||||
HAL_HCD_MspInit((HCD_HandleTypeDef *)&g_dwc2_instance);
|
||||
|
||||
#if defined(STM32F722xx) || defined(STM32F723xx) || defined(STM32F730xx) || defined(STM32F732xx) || defined(STM32F733xx)
|
||||
usb_hsphy_init(25000000U);
|
||||
#endif
|
||||
}
|
||||
|
||||
void usb_hc_low_level_deinit(struct usbh_bus *bus)
|
||||
{
|
||||
if (bus->hcd.reg_base == 0x40040000UL) { // USB_OTG_HS_PERIPH_BASE
|
||||
g_usb_dwc2_busid[1] = 0;
|
||||
g_usb_dwc2_irq[1] = NULL;
|
||||
} else {
|
||||
g_usb_dwc2_busid[0] = 0;
|
||||
g_usb_dwc2_irq[0] = NULL;
|
||||
}
|
||||
|
||||
g_dwc2_instance.Instance = (USB_OTG_GlobalTypeDef *)bus->hcd.reg_base;
|
||||
HAL_HCD_MspDeInit((HCD_HandleTypeDef *)&g_dwc2_instance);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_USB_DWC2_CUSTOM_PARAM
|
||||
void dwc2_get_user_params(uint32_t reg_base, struct dwc2_user_params *params)
|
||||
{
|
||||
if (reg_base == 0x40040000UL) { // USB_OTG_HS_PERIPH_BASE
|
||||
memcpy(params, ¶m_pb14_pb15, sizeof(struct dwc2_user_params));
|
||||
} else {
|
||||
memcpy(params, ¶m_pa11_pa12, sizeof(struct dwc2_user_params));
|
||||
}
|
||||
#ifdef CONFIG_USB_DWC2_CUSTOM_FIFO
|
||||
struct usb_dwc2_user_fifo_config s_dwc2_fifo_config;
|
||||
|
||||
dwc2_get_user_fifo_config(reg_base, &s_dwc2_fifo_config);
|
||||
|
||||
params->device_rx_fifo_size = s_dwc2_fifo_config.device_rx_fifo_size;
|
||||
for (uint8_t i = 0; i < MAX_EPS_CHANNELS; i++)
|
||||
{
|
||||
params->device_tx_fifo_size[i] = s_dwc2_fifo_config.device_tx_fifo_size[i];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
extern uint32_t SystemCoreClock;
|
||||
|
||||
void usbd_dwc2_delay_ms(uint8_t ms)
|
||||
{
|
||||
uint32_t count = SystemCoreClock / 1000 * ms;
|
||||
while (count--) {
|
||||
__asm volatile("nop");
|
||||
}
|
||||
}
|
||||
|
||||
void OTG_FS_IRQHandler(void)
|
||||
{
|
||||
g_usb_dwc2_irq[0](g_usb_dwc2_busid[0]);
|
||||
}
|
||||
|
||||
void OTG_HS_IRQHandler(void)
|
||||
{
|
||||
g_usb_dwc2_irq[1](g_usb_dwc2_busid[1]);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_DCACHE_ENABLE
|
||||
void usb_dcache_clean(uintptr_t addr, size_t size)
|
||||
{
|
||||
SCB_CleanDCache_by_Addr((void *)addr, size);
|
||||
}
|
||||
|
||||
void usb_dcache_invalidate(uintptr_t addr, size_t size)
|
||||
{
|
||||
SCB_InvalidateDCache_by_Addr((void *)addr, size);
|
||||
}
|
||||
|
||||
void usb_dcache_flush(uintptr_t addr, size_t size)
|
||||
{
|
||||
SCB_CleanInvalidateDCache_by_Addr((void *)addr, size);
|
||||
}
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,38 @@
|
||||
# Note
|
||||
|
||||
## Support Chip List
|
||||
|
||||
### BouffaloLab
|
||||
|
||||
- BouffaloLab BL616/BL808 (bouffalolab + EHCI)
|
||||
|
||||
### HPMicro
|
||||
|
||||
- HPM all series (hpmicro + EHCI)
|
||||
|
||||
### AllwinnerTech
|
||||
|
||||
- F133/T113
|
||||
|
||||
### Nuvoton
|
||||
|
||||
- Nuvoton all series
|
||||
|
||||
### Artinchip
|
||||
|
||||
- d13x, d21x
|
||||
|
||||
### NXP
|
||||
|
||||
Modify USB_NOCACHE_RAM_SECTION
|
||||
|
||||
```
|
||||
#define USB_NOCACHE_RAM_SECTION __attribute__((section(".NonCacheable")))
|
||||
```
|
||||
|
||||
- IMRT10XX/IMRT11XX (chipidea + EHCI)
|
||||
- MCXN9XX/MCXN236 (chipidea + EHCI)
|
||||
|
||||
### Intel
|
||||
|
||||
- Intel 6 Series Chipset and Intel C200 Series Chipset
|
||||
@@ -0,0 +1,393 @@
|
||||
/****************************************************************************
|
||||
* include/nuttx/usb/ehci.h
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
/*
|
||||
* Copyright 2022 sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef __INCLUDE_NUTTX_USB_EHCI_H
|
||||
#define __INCLUDE_NUTTX_USB_EHCI_H
|
||||
|
||||
#define EHCI_FULL_SPEED (0) /* Full-Speed (12Mbs) */
|
||||
#define EHCI_LOW_SPEED (1) /* Low-Speed (1.5Mbs) */
|
||||
#define EHCI_HIGH_SPEED (2) /* High-Speed (480 Mb/s) */
|
||||
|
||||
/* Host Controller Capability Register Bit Definitions **********************/
|
||||
|
||||
/* Structural Parameters. Paragraph 2.2.3 */
|
||||
|
||||
#define EHCI_HCSPARAMS_NPORTS_SHIFT (0) /* Bit 0-3: Number of physical downstream ports */
|
||||
#define EHCI_HCSPARAMS_NPORTS_MASK (15 << EHCI_HCSPARAMS_NPORTS_SHIFT)
|
||||
#define EHCI_HCSPARAMS_PPC (1 << 4) /* Bit 4: Port Power Control */
|
||||
#define EHCI_HCSPARAMS_PRR (1 << 7) /* Bit 7: Port Routing Rules */
|
||||
#define EHCI_HCSPARAMS_NPCC_SHIFT (8) /* Bit 8-11: Number of Ports per Companion Controller */
|
||||
#define EHCI_HCSPARAMS_NPCC_MASK (15 << EHCI_HCSPARAMS_NPCC_SHIFT)
|
||||
#define EHCI_HCSPARAMS_NCC_SHIFT (12) /* Bit 12-15: Number of Companion Controllers */
|
||||
#define EHCI_HCSPARAMS_NCC_MASK (15 << EHCI_HCSPARAMS_NCC_SHIFT)
|
||||
#define EHCI_HCSPARAMS_PIND (1 << 16) /* Bit 16: Port Indicators */
|
||||
#define EHCI_HCSPARAMS_DBGPORT_SHIFT (20) /* Bit 20-23: Debug Port Number */
|
||||
#define EHCI_HCSPARAMS_DBGPORT_MASK (15 << EHCI_HCSPARAMS_DBGPORT_SHIFT)
|
||||
|
||||
/* Capability Parameters. Paragraph 2.2.4 */
|
||||
|
||||
#define EHCI_HCCPARAMS_64BIT (1 << 0) /* Bit 0: 64-bit Addressing Capability */
|
||||
#define EHCI_HCCPARAMS_PFLF (1 << 1) /* Bit 1: Programmable Frame List Flag */
|
||||
#define EHCI_HCCPARAMS_ASPC (1 << 2) /* Bit 2: Asynchronous Schedule Park Capability */
|
||||
#define EHCI_HCCPARAMS_IST_SHIFT (4) /* Bits 4-7: Isochronous Scheduling Threshold */
|
||||
#define EHCI_HCCPARAMS_IST_MASK (15 << EHCI_HCCPARAMS_IST_SHIFT)
|
||||
#define EHCI_HCCPARAMS_EECP_SHIFT (8) /* Bits 8-15: EHCI Extended Capabilities Pointer */
|
||||
#define EHCI_HCCPARAMS_EECP_MASK (0xff << EHCI_HCCPARAMS_EECP_SHIFT)
|
||||
|
||||
/* Host Controller Operational Register Bit Definitions *********************/
|
||||
|
||||
/* USB Command. Paragraph 2.3.1 */
|
||||
|
||||
#define EHCI_USBCMD_RUN (1 << 0) /* Bit 0: Run/Stop */
|
||||
#define EHCI_USBCMD_HCRESET (1 << 1) /* Bit 1: Host Controller Reset */
|
||||
#define EHCI_USBCMD_FLSIZE_SHIFT (2) /* Bits 2-3: Frame List Size */
|
||||
#define EHCI_USBCMD_FLSIZE_MASK (3 << EHCI_USBCMD_FLSIZE_SHIFT)
|
||||
#define EHCI_USBCMD_FLSIZE_1024 (0 << EHCI_USBCMD_FLSIZE_SHIFT) /* 1024 elements (4096 bytes) */
|
||||
#define EHCI_USBCMD_FLSIZE_512 (1 << EHCI_USBCMD_FLSIZE_SHIFT) /* 512 elements (2048 bytes) */
|
||||
#define EHCI_USBCMD_FLSIZE_256 (2 << EHCI_USBCMD_FLSIZE_SHIFT) /* 256 elements (1024 bytes) */
|
||||
#define EHCI_USBCMD_PSEN (1 << 4) /* Bit 4: Periodic Schedule Enable */
|
||||
#define EHCI_USBCMD_ASEN (1 << 5) /* Bit 5: Asynchronous Schedule Enable */
|
||||
#define EHCI_USBCMD_IAAD (1 << 6) /* Bit 6: Interrupt on Async Advance Doorbell */
|
||||
#define EHCI_USBCMD_LRESET (1 << 7) /* Bit 7: Light Host Controller Reset */
|
||||
#define EHCI_USBCMD_ASYNC_PARKCNT_SHIFT (8) /* Bits 8-9: Asynchronous Schedule Park Mode Count */
|
||||
#define EHCI_USBCMD_ASYNC_PARKCNT_MASK (3 << EHCI_USBCMD_ASYNC_PARKCNT_SHIFT)
|
||||
#define EHCI_USBCMD_ASYNC_PARK (1 << 11) /* Bit 11: Asynchronous Schedule Park Mode Enable */
|
||||
#define EHCI_USBCMD_ITHRE_SHIFT (16) /* Bits 16-23: Interrupt Threshold Control */
|
||||
#define EHCI_USBCMD_ITHRE_MASK (0xff << EHCI_USBCMD_ITHRE_SHIFT)
|
||||
#define EHCI_USBCMD_ITHRE_1MF (0x01 << EHCI_USBCMD_ITHRE_SHIFT) /* 1 micro-frame */
|
||||
#define EHCI_USBCMD_ITHRE_2MF (0x02 << EHCI_USBCMD_ITHRE_SHIFT) /* 2 micro-frames */
|
||||
#define EHCI_USBCMD_ITHRE_4MF (0x04 << EHCI_USBCMD_ITHRE_SHIFT) /* 4 micro-frames */
|
||||
#define EHCI_USBCMD_ITHRE_8MF (0x08 << EHCI_USBCMD_ITHRE_SHIFT) /* 8 micro-frames (default, 1 ms) */
|
||||
#define EHCI_USBCMD_ITHRE_16MF (0x10 << EHCI_USBCMD_ITHRE_SHIFT) /* 16 micro-frames (2 ms) */
|
||||
#define EHCI_USBCMD_ITHRE_32MF (0x20 << EHCI_USBCMD_ITHRE_SHIFT) /* 32 micro-frames (4 ms) */
|
||||
#define EHCI_USBCMD_ITHRE_64MF (0x40 << EHCI_USBCMD_ITHRE_SHIFT) /* 64 micro-frames (8 ms) */
|
||||
|
||||
/* USB Status. Paragraph 2.3.2 */
|
||||
|
||||
#define EHCI_USBSTS_INT (1 << 0) /* Bit 0: USB Interrupt */
|
||||
#define EHCI_USBSTS_ERR (1 << 1) /* Bit 1: USB Error Interrupt */
|
||||
#define EHCI_USBSTS_PCD (1 << 2) /* Bit 2: Port Change Detect */
|
||||
#define EHCI_USBSTS_FLR (1 << 3) /* Bit 3: Frame List Rollover */
|
||||
#define EHCI_USBSTS_FATAL (1 << 4) /* Bit 4: Host System Error */
|
||||
#define EHCI_USBSTS_IAA (1 << 5) /* Bit 5: Interrupt on Async Advance */
|
||||
#define EHCI_USBSTS_HALTED (1 << 12) /* Bit 12: HC Halted */
|
||||
#define EHCI_USBSTS_RECLAM (1 << 13) /* Bit 13: Reclamation */
|
||||
#define EHCI_USBSTS_PSS (1 << 14) /* Bit 14: Periodic Schedule Status */
|
||||
#define EHCI_USBSTS_ASS (1 << 15) /* Bit 15: Asynchronous Schedule Status */
|
||||
/* Bits 16-31: Reserved */
|
||||
|
||||
/* USB Interrupt Enable. Paragraph 2.3.3 */
|
||||
|
||||
#define EHCI_USBIE_INT (1 << 0) /* Bit 0: USB Interrupt */
|
||||
#define EHCI_USBIE_ERR (1 << 1) /* Bit 1: USB Error Interrupt */
|
||||
#define EHCI_USBIE_PCD (1 << 2) /* Bit 2: Port Change Detect */
|
||||
#define EHCI_USBIE_FLROLL (1 << 3) /* Bit 3: Frame List Rollover */
|
||||
#define EHCI_USBIE_FATAL (1 << 4) /* Bit 4: Host System Error */
|
||||
#define EHCI_USBIE_IAA (1 << 5) /* Bit 5: Interrupt on Async Advance */
|
||||
#define EHCI_USBIE_ALLINTS (0x3f) /* Bits 0-5: All interrupts */
|
||||
|
||||
/* USB Frame Index. Paragraph 2.3.4 */
|
||||
|
||||
#define EHCI_FRINDEX_MASK (0x3fff) /* Bits 0-13: Frame index */
|
||||
|
||||
/* 4G Segment Selector.
|
||||
* Paragraph 2.3.5, Bits[64:32] of data structure addresses
|
||||
*/
|
||||
|
||||
/* Frame List Base Address. Paragraph 2.3.6 */
|
||||
#define EHCI_PERIODICLISTBASE_MASK (0xfffff000) /* Bits 12-31: Base Address (Low) */
|
||||
|
||||
/* Next Asynchronous List Address. Paragraph 2.3.7 */
|
||||
|
||||
#define EHCI_ASYNCLISTADDR_MASK (0xffffffe0) /* Bits 5-31: Link Pointer Low (LPL) */
|
||||
|
||||
/* Configured Flag Register. Paragraph 2.3.8 */
|
||||
|
||||
#define EHCI_CONFIGFLAG (1 << 0) /* Bit 0: Configure Flag */
|
||||
|
||||
/* Port Status/Control, Port 1-n. Paragraph 2.3.9 */
|
||||
|
||||
#define EHCI_PORTSC_CCS (1 << 0) /* Bit 0: Current Connect Status */
|
||||
#define EHCI_PORTSC_CSC (1 << 1) /* Bit 1: Connect Status Change */
|
||||
#define EHCI_PORTSC_PE (1 << 2) /* Bit 2: Port Enable */
|
||||
#define EHCI_PORTSC_PEC (1 << 3) /* Bit 3: Port Enable/Disable Change */
|
||||
#define EHCI_PORTSC_OCA (1 << 4) /* Bit 4: Over-current Active */
|
||||
#define EHCI_PORTSC_OCC (1 << 5) /* Bit 5: Over-current Change */
|
||||
#define EHCI_PORTSC_RESUME (1 << 6) /* Bit 6: Force Port Resume */
|
||||
#define EHCI_PORTSC_SUSPEND (1 << 7) /* Bit 7: Suspend */
|
||||
#define EHCI_PORTSC_RESET (1 << 8) /* Bit 8: Port Reset */
|
||||
#define EHCI_PORTSC_LSTATUS_SHIFT (10) /* Bits 10-11: Line Status */
|
||||
#define EHCI_PORTSC_LSTATUS_MASK (3 << EHCI_PORTSC_LSTATUS_SHIFT)
|
||||
#define EHCI_PORTSC_LSTATUS_SE0 (0 << EHCI_PORTSC_LSTATUS_SHIFT) /* SE0 Not Low-speed device, perform EHCI reset */
|
||||
#define EHCI_PORTSC_LSTATUS_KSTATE (1 << EHCI_PORTSC_LSTATUS_SHIFT) /* K-state Low-speed device, release ownership of port */
|
||||
#define EHCI_PORTSC_LSTATUS_JSTATE (2 << EHCI_PORTSC_LSTATUS_SHIFT) /* J-state Not Low-speed device, perform EHCI reset */
|
||||
#define EHCI_PORTSC_PP (1 << 12) /* Bit 12: Port Power */
|
||||
#define EHCI_PORTSC_OWNER (1 << 13) /* Bit 13: Port Owner */
|
||||
#define EHCI_PORTSC_PIC_SHIFT (14) /* Bits 14-15: Port Indicator Control */
|
||||
#define EHCI_PORTSC_PIC_MASK (3 << EHCI_PORTSC_PIC_SHIFT)
|
||||
#define EHCI_PORTSC_PIC_OFF (0 << EHCI_PORTSC_PIC_SHIFT) /* Port indicators are off */
|
||||
#define EHCI_PORTSC_PIC_AMBER (1 << EHCI_PORTSC_PIC_SHIFT) /* Amber */
|
||||
#define EHCI_PORTSC_PIC_GREEN (2 << EHCI_PORTSC_PIC_SHIFT) /* Green */
|
||||
#define EHCI_PORTSC_PTC_SHIFT (16) /* Bits 16-19: Port Test Control */
|
||||
#define EHCI_PORTSC_PTC_MASK (15 << EHCI_PORTSC_PTC_SHIFT)
|
||||
#define EHCI_PORTSC_PTC_DISABLED (0 << EHCI_PORTSC_PTC_SHIFT) /* Test mode not enabled */
|
||||
#define EHCI_PORTSC_PTC_JSTATE (1 << EHCI_PORTSC_PTC_SHIFT) /* Test J_STATE */
|
||||
#define EHCI_PORTSC_PTC_KSTATE (2 << EHCI_PORTSC_PTC_SHIFT) /* Test K_STATE */
|
||||
#define EHCI_PORTSC_PTC_SE0NAK (3 << EHCI_PORTSC_PTC_SHIFT) /* Test SE0_NAK */
|
||||
#define EHCI_PORTSC_PTC_PACKET (4 << EHCI_PORTSC_PTC_SHIFT) /* Test Packet */
|
||||
#define EHCI_PORTSC_PTC_ENABLE (5 << EHCI_PORTSC_PTC_SHIFT) /* Test FORCE_ENABLE */
|
||||
#define EHCI_PORTSC_WKCCNTE (1 << 20) /* Bit 20: Wake on Connect Enable */
|
||||
#define EHCI_PORTSC_WKDSCNNTE (1 << 21) /* Bit 21: Wake on Disconnect Enable */
|
||||
#define EHCI_PORTSC_WKOCE (1 << 22) /* Bit 22: Wake on Over-current Enable */
|
||||
/* Bits 23-31: Reserved */
|
||||
|
||||
#define EHCI_PORTSC_ALLINTS (EHCI_PORTSC_CSC | EHCI_PORTSC_PEC | \
|
||||
EHCI_PORTSC_OCC | EHCI_PORTSC_RESUME)
|
||||
|
||||
/* Queue Head. Paragraph 3.6 */
|
||||
|
||||
/* Queue Head Horizontal Link Pointer: Queue Head DWord 0. Table 3-19 */
|
||||
|
||||
#define QH_HLP_END 0x1
|
||||
|
||||
#define QH_HLP_ITD(x) (((uint32_t)(x) & ~0x1F) | 0x0) /* Isochronous Transfer Descriptor */
|
||||
#define QH_HLP_QH(x) (((uint32_t)(x) & ~0x1F) | 0x2) /* Queue Head */
|
||||
#define QH_HLP_SITD(x) (((uint32_t)(x) & ~0x1F) | 0x4) /* Split Transaction Isochronous Transfer Descriptor */
|
||||
#define QH_HLP_FSTN(x) (((uint32_t)(x) & ~0x1F) | 0x6) /* Frame Span Traversal Node */
|
||||
|
||||
/* Endpoint Characteristics: Queue Head DWord 1. Table 3-19 */
|
||||
|
||||
#define QH_EPCHAR_DEVADDR_SHIFT (0) /* Bitx 0-6: Device Address */
|
||||
#define QH_EPCHAR_DEVADDR_MASK (0x7f << QH_EPCHAR_DEVADDR_SHIFT)
|
||||
#define QH_EPCHAR_I (1 << 7) /* Bit 7: Inactivate on Next Transaction */
|
||||
#define QH_EPCHAR_ENDPT_SHIFT (8) /* Bitx 8-11: Endpoint Number */
|
||||
#define QH_EPCHAR_ENDPT_MASK (15 << QH_EPCHAR_ENDPT_SHIFT)
|
||||
#define QH_EPCHAR_EPS_SHIFT (12) /* Bitx 12-13: Endpoint Speed */
|
||||
#define QH_EPCHAR_EPS_MASK (3 << QH_EPCHAR_EPS_SHIFT)
|
||||
#define QH_EPCHAR_EPS_FULL (0 << QH_EPCHAR_EPS_SHIFT) /* Full-Speed (12Mbs) */
|
||||
#define QH_EPCHAR_EPS_LOW (1 << QH_EPCHAR_EPS_SHIFT) /* Low-Speed (1.5Mbs) */
|
||||
#define QH_EPCHAR_EPS_HIGH (2 << QH_EPCHAR_EPS_SHIFT) /* High-Speed (480 Mb/s) */
|
||||
#define QH_EPCHAR_DTC (1 << 14) /* Bit 14: Data Toggle Control */
|
||||
#define QH_EPCHAR_H (1 << 15) /* Bit 15: Head of Reclamation List Flag */
|
||||
#define QH_EPCHAR_MAXPKT_SHIFT (16) /* Bitx 16-26: Maximum Packet Length */
|
||||
#define QH_EPCHAR_MAXPKT_MASK (0x7ff << QH_EPCHAR_MAXPKT_SHIFT)
|
||||
#define QH_EPCHAR_C (1 << 27) /* Bit 27: Control Endpoint Flag */
|
||||
#define QH_EPCHAR_RL_SHIFT (28) /* Bitx 28-31: Nak Count Reload */
|
||||
#define QH_EPCHAR_RL_MASK (15 << QH_EPCHAR_RL_SHIFT)
|
||||
|
||||
/* Endpoint Capabilities: Queue Head DWord 2. Table 3-20 */
|
||||
|
||||
#define QH_EPCAPS_SSMASK_SHIFT (0) /* Bitx 0-7: Interrupt Schedule Mask (Frame S-mask) */
|
||||
#define QH_EPCAPS_SSMASK_MASK (0xff << QH_EPCAPS_SSMASK_SHIFT)
|
||||
#define QH_EPCAPS_SSMASK(n) ((n) << QH_EPCAPS_SSMASK_SHIFT)
|
||||
#define QH_EPCAPS_SCMASK_SHIFT (8) /* Bitx 8-15: Split Completion Mask (Frame C-Mask) */
|
||||
#define QH_EPCAPS_SCMASK_MASK (0xff << QH_EPCAPS_SCMASK_SHIFT)
|
||||
#define QH_EPCAPS_SCMASK(n) ((n) << QH_EPCAPS_SCMASK_SHIFT)
|
||||
#define QH_EPCAPS_HUBADDR_SHIFT (16) /* Bitx 16-22: Hub Address */
|
||||
#define QH_EPCAPS_HUBADDR_MASK (0x7f << QH_EPCAPS_HUBADDR_SHIFT)
|
||||
#define QH_EPCAPS_HUBADDR(n) ((n) << QH_EPCAPS_HUBADDR_SHIFT)
|
||||
#define QH_EPCAPS_PORT_SHIFT (23) /* Bit 23-29: Port Number */
|
||||
#define QH_EPCAPS_PORT_MASK (0x7f << QH_EPCAPS_PORT_SHIFT)
|
||||
#define QH_EPCAPS_PORT(n) ((n) << QH_EPCAPS_PORT_SHIFT)
|
||||
#define QH_EPCAPS_MULT_SHIFT (30) /* Bit 30-31: High-Bandwidth Pipe Multiplier */
|
||||
#define QH_EPCAPS_MULT_MASK (3 << QH_EPCAPS_MULT_SHIFT)
|
||||
#define QH_EPCAPS_MULT(n) ((n) << QH_EPCAPS_MULT_SHIFT)
|
||||
|
||||
/* qTD Token. Paragraph 3.5.3 */
|
||||
|
||||
#define QTD_LIST_END 1
|
||||
|
||||
#define QTD_TOKEN_STATUS_SHIFT (0) /* Bits 0-7: Status */
|
||||
#define QTD_TOKEN_STATUS_MASK (0xff << QTD_TOKEN_STATUS_SHIFT)
|
||||
#define QTD_TOKEN_STATUS_PINGSTATE (1 << 0) /* Bit 0 Ping State */
|
||||
#define QTD_TOKEN_STATUS_ERR (1 << 0) /* Bit 0 Error */
|
||||
#define QTD_TOKEN_STATUS_SPLITXSTATE (1 << 1) /* Bit 1 Split Transaction State */
|
||||
#define QTD_TOKEN_STATUS_MMF (1 << 2) /* Bit 2 Missed Micro-Frame */
|
||||
#define QTD_TOKEN_STATUS_XACTERR (1 << 3) /* Bit 3 Transaction Error */
|
||||
#define QTD_TOKEN_STATUS_BABBLE (1 << 4) /* Bit 4 Babble Detected */
|
||||
#define QTD_TOKEN_STATUS_DBERR (1 << 5) /* Bit 5 Data Buffer Error */
|
||||
#define QTD_TOKEN_STATUS_HALTED (1 << 6) /* Bit 6 Halted */
|
||||
#define QTD_TOKEN_STATUS_ACTIVE (1 << 7) /* Bit 7 Active */
|
||||
#define QTD_TOKEN_STATUS_ERRORS (0x78 << QTD_TOKEN_STATUS_SHIFT)
|
||||
#define QTD_TOKEN_PID_SHIFT (8) /* Bits 8-9: PID Code */
|
||||
#define QTD_TOKEN_PID_MASK (3 << QTD_TOKEN_PID_SHIFT)
|
||||
#define QTD_TOKEN_PID_OUT (0 << QTD_TOKEN_PID_SHIFT) /* OUT Token generates token (E1H) */
|
||||
#define QTD_TOKEN_PID_IN (1 << QTD_TOKEN_PID_SHIFT) /* IN Token generates token (69H) */
|
||||
#define QTD_TOKEN_PID_SETUP (2 << QTD_TOKEN_PID_SHIFT) /* SETUP Token generates token (2DH) */
|
||||
#define QTD_TOKEN_CERR_SHIFT (10) /* Bits 10-11: Error Counter */
|
||||
#define QTD_TOKEN_CERR_MASK (3 << QTD_TOKEN_CERR_SHIFT)
|
||||
#define QTD_TOKEN_CPAGE_SHIFT (12) /* Bits 12-14: Current Page */
|
||||
#define QTD_TOKEN_CPAGE_MASK (7 << QTD_TOKEN_CPAGE_SHIFT)
|
||||
#define QTD_TOKEN_IOC (1 << 15) /* Bit 15: Interrupt On Complete */
|
||||
#define QTD_TOKEN_NBYTES_SHIFT (16) /* Bits 16-30: Total Bytes to Transfer */
|
||||
#define QTD_TOKEN_NBYTES_MASK (0x7fff << QTD_TOKEN_NBYTES_SHIFT)
|
||||
#define QTD_TOKEN_TOGGLE (1 << 31) /* Bit 31: Data Toggle */
|
||||
|
||||
/* Isochronous (High-Speed) Transfer Descriptor (iTD). Paragraph 3.3 */
|
||||
|
||||
/* iTD Next Link Pointer. Paragraph 3.3.1 */
|
||||
|
||||
#define ITD_NLP_ITD(x) (((uint32_t)(x) & ~0x1F) | 0x0)
|
||||
#define ITD_NLP_QH(x) (((uint32_t)(x) & ~0x1F) | 0x2)
|
||||
#define ITD_NLP_SITD(x) (((uint32_t)(x) & ~0x1F) | 0x4)
|
||||
#define ITD_NLP_FSTN(x) (((uint32_t)(x) & ~0x1F) | 0x6)
|
||||
|
||||
/* iTD Transaction Status and Control List. Paragraph 3.3.2 */
|
||||
#define ITD_TSCL_XOFFS_SHIFT (0) /* Bits 0-11: Transaction X offset */
|
||||
#define ITD_TSCL_XOFFS_MASK (0xfff << ITD_TSCL_XOFFS_SHIFT)
|
||||
#define ITD_TSCL_PG_SHIFT (12) /* Bits 12-14: Page select */
|
||||
#define ITD_TSCL_PG_MASK (7 << ITD_TSCL_PG_SHIFT)
|
||||
#define ITD_TSCL_IOC (1 << 15) /* Bit 15: Interrupt On Comp */
|
||||
#define ITD_TSCL_LENGTH_SHIFT (16) /* Bits 16-27: Transaction length */
|
||||
#define ITD_TSCL_LENGTH_MASK (0xfff << ITD_TSCL_LENGTH_SHIFT)
|
||||
#define ITD_TSCL_STATUS_SHIFT (28) /* Bits 28-31: Transaction status */
|
||||
#define ITD_TSCL_STATUS_MASK (15 << ITD_TSCL_STATUS_SHIFT)
|
||||
#define ITD_TSCL_STATUS_XACTERR (1 << 28) /* Bit 28: Transaction error */
|
||||
#define ITD_TSCL_STATUS_BABBLE (1 << 29) /* Bit 29: Babble Detected */
|
||||
#define ITD_TSCL_STATUS_DBERROR (1 << 30) /* Bit 30: Data Buffer Error */
|
||||
#define ITD_TSCL_STATUS_ACTIVE (1 << 31) /* Bit 31: Active error */
|
||||
|
||||
/* iTD Buffer Page Pointer List. Paragraph 3.3.4 */
|
||||
|
||||
/* iTD Buffer Pointer Page 0. Table 3-4 */
|
||||
|
||||
#define ITD_BUFPTR0_DEVADDR_SHIFT (0) /* Bits 0-6: Device Address */
|
||||
#define ITD_BUFPTR0_DEVADDR_MASK (0x7f << ITD_BUFPTR0_DEVADDR_SHIFT)
|
||||
#define ITD_BUFPTR0_ENDPT_SHIFT (8) /* Bits 8-11: Endpoint Number */
|
||||
#define ITD_BUFPTR0_ENDPT_MASK (15 << ITD_BUFPTR0_ENDPT_SHIFT)
|
||||
|
||||
/* iTD Buffer Pointer Page 1. Table 3-5 */
|
||||
|
||||
#define ITD_BUFPTR1_MAXPKT_SHIFT (0) /* Bits 0-10: Maximum Packet Size */
|
||||
#define ITD_BUFPTR1_MAXPKT_MASK (0x7ff << ITD_BUFPTR1_MAXPKT_SHIFT)
|
||||
#define ITD_BUFPTR1_DIRIN (1 << 11) /* Bit 11: Direction 1=IN */
|
||||
#define ITD_BUFPTR1_DIROUT (0) /* Bit 11: Direction 0=OUT */
|
||||
|
||||
/* iTD Buffer Pointer Page 2. Table 3-6 */
|
||||
|
||||
#define ITD_BUFPTR2_MULTI_SHIFT (0) /* Bits 0-1: Multi */
|
||||
#define ITD_BUFPTR2_MULTI_MASK (3 << ITD_BUFPTR2_MULTI_SHIFT)
|
||||
#define ITD_BUFPTR2_MULTI_1 (1 << ITD_BUFPTR2_MULTI_SHIFT) /* One transaction per micro-frame */
|
||||
#define ITD_BUFPTR2_MULTI_2 (2 << ITD_BUFPTR2_MULTI_SHIFT) /* Two transactions per micro-frame */
|
||||
#define ITD_BUFPTR2_MULTI_3 (3 << ITD_BUFPTR2_MULTI_SHIFT) /* Three transactions per micro-frame */
|
||||
|
||||
/* Registers ****************************************************************/
|
||||
|
||||
/* Host Controller Capability Registers.
|
||||
* This register block must be positioned at a well known address.
|
||||
*/
|
||||
|
||||
struct ehci_hccr {
|
||||
volatile uint8_t caplength; /* 0x00: Capability Register Length */
|
||||
volatile uint8_t reserved; /* 0x01: reserved */
|
||||
volatile uint16_t hciversion; /* 0x02: Interface Version Number */
|
||||
volatile uint32_t hcsparams; /* 0x04: Structural Parameters */
|
||||
volatile uint32_t hccparams; /* 0x08: Capability Parameters */
|
||||
volatile uint8_t hcspportroute[8]; /* 0x0c: Companion Port Route Description */
|
||||
};
|
||||
|
||||
/* Host Controller Operational Registers.
|
||||
* This register block is positioned at an offset of 'caplength' from the
|
||||
* beginning of the Host Controller Capability Registers.
|
||||
*/
|
||||
|
||||
struct ehci_hcor {
|
||||
volatile uint32_t usbcmd; /* 0x00: USB Command */
|
||||
volatile uint32_t usbsts; /* 0x04: USB Status */
|
||||
volatile uint32_t usbintr; /* 0x08: USB Interrupt Enable */
|
||||
volatile uint32_t frindex; /* 0x0c: USB Frame Index */
|
||||
volatile uint32_t ctrldssegment; /* 0x10: 4G Segment Selector */
|
||||
volatile uint32_t periodiclistbase; /* 0x14: Frame List Base Address */
|
||||
volatile uint32_t asynclistaddr; /* 0x18: Next Asynchronous List Address */
|
||||
#ifndef CONFIG_USB_EHCI_HCOR_RESERVED_DISABLE
|
||||
uint32_t reserved[9];
|
||||
#endif
|
||||
volatile uint32_t configflag; /* 0x40: Configured Flag Register */
|
||||
volatile uint32_t portsc[15]; /* 0x44: Port Status/Control */
|
||||
};
|
||||
|
||||
/* USB2 Debug Port Register Interface.
|
||||
* This register block is normally found via the PCI capabalities.
|
||||
* In non-PCI implementions, you need apriori information about the
|
||||
* location of these registers.
|
||||
*/
|
||||
|
||||
struct ehci_debug {
|
||||
uint32_t psc; /* 0x00: Debug Port Control/Status Register */
|
||||
uint32_t pids; /* 0x04: Debug USB PIDs Register */
|
||||
uint32_t data[2]; /* 0x08: Debug Data buffer Registers */
|
||||
uint32_t addr; /* 0x10: Device Address Register */
|
||||
};
|
||||
|
||||
/* Data Structures **********************************************************/
|
||||
|
||||
/* Queue Element Transfer Descriptor (qTD). Paragraph 3.5 */
|
||||
|
||||
struct ehci_qtd {
|
||||
uint32_t next_qtd; /* 0x00-0x03: Next qTD Pointer */
|
||||
uint32_t alt_next_qtd; /* 0x04-0x07: Alternate Next qTD Pointer */
|
||||
uint32_t token; /* 0x08-0x0b: qTD Token */
|
||||
uint32_t bpl[5]; /* 0x0c-0x1c: Buffer Page Pointer List */
|
||||
};
|
||||
|
||||
#define SIZEOF_EHCI_QTD (32) /* 8*sizeof(uint32_t) */
|
||||
|
||||
/* Queue Head. Paragraph 3.6 */
|
||||
|
||||
struct ehci_qh {
|
||||
uint32_t hlp; /* 0x00-0x03: Queue Head Horizontal Link Pointer */
|
||||
uint32_t epchar; /* 0x04-0x07: Endpoint Characteristics */
|
||||
uint32_t epcap; /* 0x08-0x0b: Endpoint Capabilities */
|
||||
uint32_t curr_qtd; /* 0x0c-0x0f: Current qTD Pointer */
|
||||
struct ehci_qtd overlay; /* 0x10-0x2c: Transfer overlay */
|
||||
};
|
||||
|
||||
#define SIZEOF_EHCI_QH (48) /* 4*sizeof(uint32_t) + 32 */
|
||||
|
||||
/* Isochronous (High-Speed) Transfer Descriptor (iTD).
|
||||
* Paragraph 3.3. Must be aligned to 32-byte boundaries.
|
||||
*/
|
||||
|
||||
struct ehci_itd {
|
||||
uint32_t nlp; /* 0x00-0x03: Next link pointer */
|
||||
uint32_t tscl[8]; /* 0x04-0x23: Transaction Status and Control List */
|
||||
uint32_t bpl[7]; /* 0x24-0x3c: Buffer Page Pointer List */
|
||||
};
|
||||
|
||||
#define SIZEOF_EHCI_ITD (64) /* 16*sizeof(uint32_t) */
|
||||
|
||||
/* Split Transaction Isochronous Transfer Descriptor (siTD). Paragraph 3.4 */
|
||||
|
||||
struct ehci_sitd {
|
||||
uint32_t nlp; /* 0x00-0x03: Next link pointer */
|
||||
uint32_t epchar; /* 0x04-0x07: Endpoint and Transaction Translator Characteristics */
|
||||
uint32_t mfsc; /* 0x08-0x0b: Micro-frame Schedule Control */
|
||||
uint32_t tsc; /* 0x0c-0x0f: Transfer Status and Control */
|
||||
uint32_t bpl[2]; /* 0x10-0x17: Buffer Pointer List */
|
||||
uint32_t blp; /* 0x18-0x1b: Back link pointer */
|
||||
};
|
||||
|
||||
#define SIZEOF_EHCI_SITD (28) /* 7*sizeof(uint32_t) */
|
||||
|
||||
#endif /* __INCLUDE_NUTTX_USB_EHCI_H */
|
||||
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Artinchip Technology Co., Ltd
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <aic_core.h>
|
||||
#include <aic_hal.h>
|
||||
#include <hal_syscfg.h>
|
||||
#include "usbh_core.h"
|
||||
#include "usb_hc_ehci.h"
|
||||
#include "usb_hc_ohci.h"
|
||||
|
||||
#if !defined(CONFIG_USB_EHCI_CONFIGFLAG)
|
||||
#error "aic ehci must define CONFIG_USB_EHCI_CONFIGFLAG"
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_USB_EHCI_WITH_OHCI)
|
||||
#error "aic must define CONFIG_USB_EHCI_WITH_OHCI for ls/fs device"
|
||||
#endif
|
||||
|
||||
#if CONFIG_USB_OHCI_HCOR_OFFSET != 0x400
|
||||
#error "aic CONFIG_USB_OHCI_HCOR_OFFSET must be 0x400"
|
||||
#endif
|
||||
|
||||
extern void USBH_IRQHandler(uint8_t busid);
|
||||
|
||||
static void aic_ehci_isr(int vector, void *arg)
|
||||
{
|
||||
struct usbh_bus *bus = (struct usbh_bus *)arg;
|
||||
extern void USBH_IRQHandler(uint8_t busid);
|
||||
USBH_IRQHandler(bus->hcd.hcd_id);
|
||||
}
|
||||
|
||||
static void aic_ohci_isr(int vector, void *arg)
|
||||
{
|
||||
struct usbh_bus *bus = (struct usbh_bus *)arg;
|
||||
extern void OHCI_IRQHandler(uint8_t busid);
|
||||
OHCI_IRQHandler(bus->hcd.hcd_id);
|
||||
}
|
||||
|
||||
typedef struct aic_ehci_config {
|
||||
uint32_t base_addr;
|
||||
uint32_t clk_id;
|
||||
uint32_t rst_id;
|
||||
uint32_t phy_clk_id;
|
||||
uint32_t phy_rst_id;
|
||||
uint32_t irq_num;
|
||||
}aic_ehci_config_t;
|
||||
|
||||
aic_ehci_config_t config[] = {
|
||||
#ifdef AIC_USING_USB0_HOST
|
||||
{
|
||||
USB_HOST0_BASE,
|
||||
CLK_USBH0,
|
||||
RESET_USBH0,
|
||||
CLK_USB_PHY0,
|
||||
RESET_USBPHY0,
|
||||
USB_HOST0_EHCI_IRQn
|
||||
},
|
||||
#else
|
||||
{
|
||||
0xFFFFFFFF,
|
||||
0xFFFFFFFF,
|
||||
0xFFFFFFFF,
|
||||
0xFFFFFFFF,
|
||||
0xFFFFFFFF,
|
||||
0xFFFFFFFF
|
||||
},
|
||||
#endif
|
||||
#ifdef AIC_USING_USB1_HOST
|
||||
{
|
||||
USB_HOST1_BASE,
|
||||
CLK_USBH1,
|
||||
RESET_USBH1,
|
||||
CLK_USB_PHY1,
|
||||
RESET_USBPHY1,
|
||||
USB_HOST1_EHCI_IRQn
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
void usb_hc_low_level_init(struct usbh_bus *bus)
|
||||
{
|
||||
uint32_t val;
|
||||
int i = 0;
|
||||
|
||||
for (i=0; i<sizeof(config)/sizeof(aic_ehci_config_t); i++) {
|
||||
if (bus->hcd.reg_base == config[i].base_addr)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == sizeof(config)/sizeof(aic_ehci_config_t))
|
||||
return;
|
||||
|
||||
/* set usb0 phy switch: Host/Device */
|
||||
if (i == 0)
|
||||
syscfg_usb_phy0_sw_host(1);
|
||||
|
||||
/* enable clock */
|
||||
hal_clk_enable(config[i].phy_clk_id);
|
||||
hal_clk_enable(config[i].clk_id);
|
||||
aicos_udelay(300);
|
||||
hal_reset_assert(config[i].phy_rst_id);
|
||||
hal_reset_assert(config[i].rst_id);
|
||||
aicos_udelay(300);
|
||||
hal_reset_deassert(config[i].phy_rst_id);
|
||||
hal_reset_deassert(config[i].rst_id);
|
||||
aicos_udelay(300);
|
||||
|
||||
/* set phy type: UTMI/ULPI */
|
||||
val = readl((volatile void *)(unsigned long)(config[i].base_addr+0x800));
|
||||
#ifdef FPGA_BOARD_ARTINCHIP
|
||||
/* fpga phy type = ULPI */
|
||||
writel((val & ~0x1U), (volatile void *)(unsigned long)(config[i].base_addr+0x800));
|
||||
#else
|
||||
/* board phy type = UTMI */
|
||||
writel((val | 0x1), (volatile void *)(unsigned long)(config[i].base_addr+0x800));
|
||||
#endif
|
||||
|
||||
/* Set AHB2STBUS_INSREG01
|
||||
Set EHCI packet buffer IN/OUT threshold (in DWORDs)
|
||||
Must increase the OUT threshold to avoid underrun. (FIFO size - 4)
|
||||
*/
|
||||
writel((32 | (127 << 16)), (volatile void *)(unsigned long)(config[i].base_addr+0x94));
|
||||
|
||||
/* register interrupt callback */
|
||||
aicos_request_irq(config[i].irq_num, (irq_handler_t)aic_ehci_isr,
|
||||
0, "usb_host_ehci", bus);
|
||||
aicos_request_irq(config[i].irq_num + 1, (irq_handler_t)aic_ohci_isr,
|
||||
0, "usb_host_ohci", bus);
|
||||
aicos_irq_enable(config[i].irq_num);
|
||||
aicos_irq_enable(config[i].irq_num + 1);
|
||||
}
|
||||
|
||||
uint8_t usbh_get_port_speed(struct usbh_bus *bus, const uint8_t port)
|
||||
{
|
||||
return USB_SPEED_HIGH;
|
||||
}
|
||||
|
||||
void usb_ehci_dcache_clean(uintptr_t addr, uint32_t len)
|
||||
{
|
||||
aicos_dcache_clean_range((size_t *)addr, len);
|
||||
}
|
||||
|
||||
void usb_ehci_dcache_invalidate(uintptr_t addr, uint32_t len)
|
||||
{
|
||||
aicos_dcache_invalid_range((size_t *)addr, len);
|
||||
}
|
||||
|
||||
void usb_ehci_dcache_clean_invalidate(uintptr_t addr, uint32_t len)
|
||||
{
|
||||
aicos_dcache_clean_invalid_range((size_t *)addr, len);
|
||||
}
|
||||
|
||||
int __usbh_init(void)
|
||||
{
|
||||
#if defined(AIC_USING_USB0_HOST) || defined(AIC_USING_USB1_HOST)
|
||||
int bus_id = 0;
|
||||
#endif
|
||||
|
||||
#ifdef AIC_USING_USB0_HOST
|
||||
usbh_initialize(bus_id, USB_HOST0_BASE);
|
||||
bus_id++;
|
||||
#endif
|
||||
|
||||
#ifdef AIC_USING_USB1_HOST
|
||||
usbh_initialize(bus_id, USB_HOST1_BASE);
|
||||
bus_id++;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(KERNEL_RTTHREAD)
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
INIT_ENV_EXPORT(__usbh_init);
|
||||
#endif
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright (c) 2024, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "bflb_core.h"
|
||||
#include "bflb_l1c.h"
|
||||
#include "usbh_core.h"
|
||||
#include "hardware/usb_v2_reg.h"
|
||||
|
||||
#ifndef CONFIG_USB_EHCI_HCOR_RESERVED_DISABLE
|
||||
#error "usb host must enable CONFIG_USB_EHCI_HCOR_RESERVED_DISABLE"
|
||||
#endif
|
||||
|
||||
#define BLFB_USB_BASE ((uint32_t)0x20072000)
|
||||
#define BFLB_PDS_BASE ((uint32_t)0x2000e000)
|
||||
|
||||
#define PDS_USB_CTL_OFFSET (0x500) /* usb_ctl */
|
||||
#define PDS_USB_PHY_CTRL_OFFSET (0x504) /* usb_phy_ctrl */
|
||||
|
||||
/* 0x500 : usb_ctl */
|
||||
#define PDS_REG_USB_SW_RST_N (1 << 0U)
|
||||
#define PDS_REG_USB_EXT_SUSP_N (1 << 1U)
|
||||
#define PDS_REG_USB_WAKEUP (1 << 2U)
|
||||
#define PDS_REG_USB_L1_WAKEUP (1 << 3U)
|
||||
#define PDS_REG_USB_DRVBUS_POL (1 << 4U)
|
||||
#define PDS_REG_USB_IDDIG (1 << 5U)
|
||||
|
||||
/* 0x504 : usb_phy_ctrl */
|
||||
#define PDS_REG_USB_PHY_PONRST (1 << 0U)
|
||||
#define PDS_REG_USB_PHY_OSCOUTEN (1 << 1U)
|
||||
#define PDS_REG_USB_PHY_XTLSEL_SHIFT (2U)
|
||||
#define PDS_REG_USB_PHY_XTLSEL_MASK (0x3 << PDS_REG_USB_PHY_XTLSEL_SHIFT)
|
||||
#define PDS_REG_USB_PHY_OUTCLKSEL (1 << 4U)
|
||||
#define PDS_REG_USB_PHY_PLLALIV (1 << 5U)
|
||||
#define PDS_REG_PU_USB20_PSW (1 << 6U)
|
||||
|
||||
#define USB_SOF_TIMER_MASK_AFTER_RESET_HS (0x44C)
|
||||
#define USB_SOF_TIMER_MASK_AFTER_RESET_FS (0x2710)
|
||||
|
||||
extern void USBH_IRQHandler(uint8_t busid);
|
||||
|
||||
void USBH_IRQ(int irq, void *arg) {
|
||||
USBH_IRQHandler(0);
|
||||
}
|
||||
|
||||
static void bflb_usb_phy_init(void)
|
||||
{
|
||||
uint32_t regval;
|
||||
|
||||
/* USB_PHY_CTRL[3:2] reg_usb_phy_xtlsel=0 */
|
||||
/* 2000e504 = 0x40; #100; USB_PHY_CTRL[6] reg_pu_usb20_psw=1 (VCC33A) */
|
||||
/* 2000e504 = 0x41; #500; USB_PHY_CTRL[0] reg_usb_phy_ponrst=1 */
|
||||
/* 2000e500 = 0x20; #100; USB_CTL[0] reg_usb_sw_rst_n=0 */
|
||||
/* 2000e500 = 0x22; #500; USB_CTL[1] reg_usb_ext_susp_n=1 */
|
||||
/* 2000e500 = 0x23; #100; USB_CTL[0] reg_usb_sw_rst_n=1 */
|
||||
/* #1.2ms; wait UCLK */
|
||||
/* wait(soc616_b0.usb_uclk); */
|
||||
|
||||
regval = getreg32(BFLB_PDS_BASE + PDS_USB_PHY_CTRL_OFFSET);
|
||||
regval &= ~PDS_REG_USB_PHY_XTLSEL_MASK;
|
||||
putreg32(regval, BFLB_PDS_BASE + PDS_USB_PHY_CTRL_OFFSET);
|
||||
|
||||
regval = getreg32(BFLB_PDS_BASE + PDS_USB_PHY_CTRL_OFFSET);
|
||||
regval |= PDS_REG_PU_USB20_PSW;
|
||||
putreg32(regval, BFLB_PDS_BASE + PDS_USB_PHY_CTRL_OFFSET);
|
||||
|
||||
regval = getreg32(BFLB_PDS_BASE + PDS_USB_PHY_CTRL_OFFSET);
|
||||
regval |= PDS_REG_USB_PHY_PONRST;
|
||||
putreg32(regval, BFLB_PDS_BASE + PDS_USB_PHY_CTRL_OFFSET);
|
||||
|
||||
/* greater than 5T */
|
||||
bflb_mtimer_delay_us(1);
|
||||
|
||||
regval = getreg32(BFLB_PDS_BASE + PDS_USB_CTL_OFFSET);
|
||||
regval &= ~PDS_REG_USB_SW_RST_N;
|
||||
putreg32(regval, BFLB_PDS_BASE + PDS_USB_CTL_OFFSET);
|
||||
|
||||
/* greater than 5T */
|
||||
bflb_mtimer_delay_us(1);
|
||||
|
||||
regval = getreg32(BFLB_PDS_BASE + PDS_USB_CTL_OFFSET);
|
||||
regval |= PDS_REG_USB_EXT_SUSP_N;
|
||||
putreg32(regval, BFLB_PDS_BASE + PDS_USB_CTL_OFFSET);
|
||||
|
||||
/* wait UCLK 1.2ms */
|
||||
bflb_mtimer_delay_ms(3);
|
||||
|
||||
regval = getreg32(BFLB_PDS_BASE + PDS_USB_CTL_OFFSET);
|
||||
regval |= PDS_REG_USB_SW_RST_N;
|
||||
putreg32(regval, BFLB_PDS_BASE + PDS_USB_CTL_OFFSET);
|
||||
|
||||
bflb_mtimer_delay_ms(2);
|
||||
}
|
||||
|
||||
void usb_hc_low_level_init(struct usbh_bus *bus)
|
||||
{
|
||||
uint32_t regval;
|
||||
|
||||
bflb_usb_phy_init();
|
||||
|
||||
bflb_irq_attach(37, USBH_IRQ, NULL);
|
||||
bflb_irq_enable(37);
|
||||
|
||||
/* enable device-A for host */
|
||||
regval = getreg32(BFLB_PDS_BASE + PDS_USB_CTL_OFFSET);
|
||||
regval &= ~PDS_REG_USB_IDDIG;
|
||||
putreg32(regval, BFLB_PDS_BASE + PDS_USB_CTL_OFFSET);
|
||||
|
||||
regval = getreg32(BLFB_USB_BASE + USB_OTG_CSR_OFFSET);
|
||||
regval |= USB_A_BUS_DROP_HOV;
|
||||
regval &= ~USB_A_BUS_REQ_HOV;
|
||||
putreg32(regval, BLFB_USB_BASE + USB_OTG_CSR_OFFSET);
|
||||
|
||||
bflb_mtimer_delay_ms(10);
|
||||
|
||||
/* enable vbus and bus control */
|
||||
regval = getreg32(BLFB_USB_BASE + USB_OTG_CSR_OFFSET);
|
||||
regval &= ~USB_A_BUS_DROP_HOV;
|
||||
regval |= USB_A_BUS_REQ_HOV;
|
||||
putreg32(regval, BLFB_USB_BASE + USB_OTG_CSR_OFFSET);
|
||||
|
||||
regval = getreg32(BLFB_USB_BASE + USB_GLB_INT_OFFSET);
|
||||
regval |= USB_MDEV_INT;
|
||||
regval |= USB_MOTG_INT;
|
||||
regval &= ~USB_MHC_INT;
|
||||
putreg32(regval, BLFB_USB_BASE + USB_GLB_INT_OFFSET);
|
||||
}
|
||||
|
||||
uint8_t usbh_get_port_speed(struct usbh_bus *bus, const uint8_t port)
|
||||
{
|
||||
uint8_t speed = 3;
|
||||
|
||||
speed = (getreg32(BLFB_USB_BASE + USB_OTG_CSR_OFFSET) & USB_SPD_TYP_HOV_POV_MASK) >> USB_SPD_TYP_HOV_POV_SHIFT;
|
||||
|
||||
if (speed == 0) {
|
||||
return USB_SPEED_FULL;
|
||||
} else if (speed == 1) {
|
||||
return USB_SPEED_LOW;
|
||||
} else if (speed == 2) {
|
||||
return USB_SPEED_HIGH;
|
||||
}
|
||||
return USB_SPEED_HIGH;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_DCACHE_ENABLE
|
||||
void usb_dcache_clean(uintptr_t addr, size_t size)
|
||||
{
|
||||
bflb_l1c_dcache_clean_range((void *)addr, size);
|
||||
}
|
||||
|
||||
void usb_dcache_invalidate(uintptr_t addr, size_t size)
|
||||
{
|
||||
bflb_l1c_dcache_invalidate_range((void *)addr, size);
|
||||
}
|
||||
|
||||
void usb_dcache_flush(uintptr_t addr, size_t size)
|
||||
{
|
||||
bflb_l1c_dcache_clean_invalidate_range((void *)addr, size);
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,55 @@
|
||||
#ifdef __rtems__
|
||||
|
||||
#include <rtems.h>
|
||||
#include <rtems/pci.h>
|
||||
#include <bsp/irq.h>
|
||||
#include "usbh_core.h"
|
||||
|
||||
uint32_t echi_base;
|
||||
static int ehci_bus;
|
||||
static int ehci_slot;
|
||||
static int ehci_function;
|
||||
static int ehci_vector;
|
||||
|
||||
extern void USBH_IRQHandler(uint8_t busid);
|
||||
|
||||
void ehci_pci_scan(int bus, int slot, int fun, int vector)
|
||||
{
|
||||
ehci_bus = bus;
|
||||
ehci_slot = slot;
|
||||
ehci_function = fun;
|
||||
ehci_vector = vector;
|
||||
pci_read_config_dword(bus, slot, fun, PCI_BASE_ADDRESS_0, &echi_base);
|
||||
}
|
||||
void usb_hc_low_level_init(struct usbh_bus *bus)
|
||||
{
|
||||
//set software own ehci
|
||||
uint32_t legacy_val;
|
||||
pci_write_config_dword(ehci_bus, ehci_slot, ehci_function, 0x68, 1 << 24);
|
||||
pci_read_config_dword(ehci_bus, ehci_slot, ehci_function, 0x68, &legacy_val);
|
||||
if ((legacy_val & 0x01010000) == 0x01000000)
|
||||
printf("OS owned echi\n");
|
||||
else
|
||||
printf("BIOS owned echi\n");
|
||||
|
||||
rtems_status_code sc;
|
||||
sc = rtems_interrupt_handler_install(
|
||||
ehci_vector,
|
||||
"USBirq",
|
||||
RTEMS_INTERRUPT_SHARED,
|
||||
USBH_IRQHandler,
|
||||
(void *)0);
|
||||
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
printf("USB install isr falied,%s\n", rtems_status_text(sc));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t usbh_get_port_speed(struct usbh_bus *bus, const uint8_t port)
|
||||
{
|
||||
printf("USB_SPEED_HIGH present\n");
|
||||
return USB_SPEED_HIGH;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,117 @@
|
||||
/**************************************************************************/ /**
|
||||
*
|
||||
* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-8-8 Wayne First version
|
||||
*
|
||||
******************************************************************************/
|
||||
#include "rtthread.h"
|
||||
|
||||
#include "NuMicro.h"
|
||||
#include "rthw.h"
|
||||
#include "drv_sys.h"
|
||||
|
||||
#define LOG_TAG "drv.cherry"
|
||||
#define DBG_ENABLE
|
||||
#define DBG_SECTION_NAME LOG_TAG
|
||||
#define DBG_LEVEL DBG_LOG
|
||||
#define DBG_COLOR
|
||||
#include <rtdbg.h>
|
||||
|
||||
#if defined(PKG_CHERRYUSB_HOST)
|
||||
|
||||
#include "usbh_core.h"
|
||||
|
||||
static void nu_echi_isr(int vector, void *param)
|
||||
{
|
||||
uint8_t busid = (uint8_t)param;
|
||||
extern void USBH_IRQHandler(uint8_t busid);
|
||||
USBH_IRQHandler(busid);
|
||||
}
|
||||
|
||||
static void nu_ochi_isr(int vector, void *param)
|
||||
{
|
||||
}
|
||||
|
||||
void usb_hc_low_level_init(struct usbh_bus *bus)
|
||||
{
|
||||
int timeout = 100;
|
||||
|
||||
if (bus->hcd.reg_base == HSUSBH0_BASE) {
|
||||
/* Enable USBH clock */
|
||||
CLK_EnableModuleClock(HUSBH0_MODULE);
|
||||
SYS_ResetModule(HSUSBH0_RST);
|
||||
|
||||
/* Clock engine clock Configuration */
|
||||
SYS->USBPMISCR &= ~(SYS_USBPMISCR_PHY0POR_Msk | SYS_USBPMISCR_PHY0COMN_Msk);
|
||||
rt_thread_mdelay(20);
|
||||
SYS->USBPMISCR |= SYS_USBPMISCR_PHY0SUSPEND_Msk | SYS_USBPMISCR_PHY0COMN_Msk;
|
||||
|
||||
/* set UHOVRCURH(SYS_MISCFCR0[12]) 1 => USBH Host over-current detect is high-active */
|
||||
/* 0 => USBH Host over-current detect is low-active */
|
||||
//SYS->MISCFCR0 |= SYS_MISCFCR0_UHOVRCURH_Msk;
|
||||
SYS->MISCFCR0 &= ~SYS_MISCFCR0_UHOVRCURH_Msk;
|
||||
while (1) {
|
||||
rt_thread_mdelay(1);
|
||||
if (SYS->USBPMISCR & SYS_USBPMISCR_PHY0HSTCKSTB_Msk)
|
||||
break; /* both USB PHY0 and PHY1 clock 60MHz UTMI clock stable */
|
||||
|
||||
timeout--;
|
||||
if (timeout == 0) {
|
||||
rt_kprintf("USB PHY reset failed. USBPMISCR = 0x%08x\n", SYS->USBPMISCR);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Register interrupt service routine. */
|
||||
rt_hw_interrupt_install(HSUSBH0_IRQn, nu_echi_isr, (void *)bus->hcd.hcd_id, "ehci0");
|
||||
|
||||
/* Enable interrupt */
|
||||
rt_hw_interrupt_umask(HSUSBH0_IRQn);
|
||||
} else if (bus->hcd.reg_base == HSUSBH1_BASE) {
|
||||
/* Enable USBH clock */
|
||||
CLK_EnableModuleClock(HUSBH1_MODULE);
|
||||
SYS_ResetModule(HSUSBH1_RST);
|
||||
|
||||
/* Clock engine clock Configuration */
|
||||
SYS->USBPMISCR &= ~(SYS_USBPMISCR_PHY1POR_Msk | SYS_USBPMISCR_PHY1COMN_Msk);
|
||||
rt_thread_mdelay(20);
|
||||
SYS->USBPMISCR |= SYS_USBPMISCR_PHY1SUSPEND_Msk | SYS_USBPMISCR_PHY1COMN_Msk;
|
||||
|
||||
/* set UHOVRCURH(SYS_MISCFCR0[12]) 1 => USBH Host over-current detect is high-active */
|
||||
/* 0 => USBH Host over-current detect is low-active */
|
||||
//SYS->MISCFCR0 |= SYS_MISCFCR0_UHOVRCURH_Msk;
|
||||
SYS->MISCFCR0 &= ~SYS_MISCFCR0_UHOVRCURH_Msk;
|
||||
while (1) {
|
||||
rt_thread_mdelay(1);
|
||||
if (SYS->USBPMISCR & SYS_USBPMISCR_PHY1HSTCKSTB_Msk)
|
||||
break; /* both USB PHY0 and PHY1 clock 60MHz UTMI clock stable */
|
||||
|
||||
timeout--;
|
||||
if (timeout == 0) {
|
||||
rt_kprintf("USB PHY reset failed. USBPMISCR = 0x%08x\n", SYS->USBPMISCR);
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* Register interrupt service routine. */
|
||||
rt_hw_interrupt_install(HSUSBH1_IRQn, nu_echi_isr, (void *)bus->hcd.hcd_id, "ehci1");
|
||||
|
||||
/* Enable interrupt */
|
||||
rt_hw_interrupt_umask(HSUSBH1_IRQn);
|
||||
}
|
||||
}
|
||||
|
||||
void usb_hc_low_level2_init(struct usbh_bus *bus)
|
||||
{
|
||||
}
|
||||
|
||||
uint8_t usbh_get_port_speed(struct usbh_bus *bus, const uint8_t port)
|
||||
{
|
||||
return USB_SPEED_HIGH;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,62 @@
|
||||
/**************************************************************************/ /**
|
||||
*
|
||||
* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-8-8 Wayne First version
|
||||
*
|
||||
******************************************************************************/
|
||||
#include "rtthread.h"
|
||||
|
||||
#include "NuMicro.h"
|
||||
#include "rthw.h"
|
||||
#include "drv_sys.h"
|
||||
|
||||
#define LOG_TAG "drv.cherry"
|
||||
#define DBG_ENABLE
|
||||
#define DBG_SECTION_NAME LOG_TAG
|
||||
#define DBG_LEVEL DBG_LOG
|
||||
#define DBG_COLOR
|
||||
#include <rtdbg.h>
|
||||
|
||||
#if defined(PKG_CHERRYUSB_HOST)
|
||||
#include "usbh_core.h"
|
||||
|
||||
static void nu_ehci_isr(int vector, void *param)
|
||||
{
|
||||
extern void USBH_IRQHandler(uint8_t busid);
|
||||
USBH_IRQHandler(0);
|
||||
}
|
||||
|
||||
void usb_hc_low_level_init(struct usbh_bus *bus)
|
||||
{
|
||||
LOG_D("%s %d", __FUNCTION__, __LINE__);
|
||||
|
||||
rt_hw_interrupt_mask(IRQ_EHCI);
|
||||
|
||||
/* Enable USBH clock */
|
||||
nu_sys_ipclk_enable(USBHCKEN);
|
||||
nu_sys_ip_reset(USBHRST);
|
||||
|
||||
outpw(0xB0015000 + 0xC4, 0x160); //HSUSBH->USBPCR0 = 0x160; /* enable PHY 0 */
|
||||
outpw(0xB0015000 + 0xC8, 0x520); //HSUSBH->USBPCR1 = 0x520; /* enable PHY 1 */
|
||||
|
||||
//USBH->HcMiscControl |= USBH_HcMiscControl_OCAL_Msk; /* Over-current active low */
|
||||
//outpw(0xB0017000 + 0x204, inpw(0xB0017000 + 0x204) | (0x1ul << 3));
|
||||
|
||||
//USBH->HcMiscControl &= ~USBH_HcMiscControl_OCAL_Msk; /* Over-current active high */
|
||||
outpw(0xB0017000 + 0x204, inpw(0xB0017000 + 0x204) & (~(0x1ul << 3)));
|
||||
|
||||
rt_hw_interrupt_install(IRQ_EHCI, nu_ehci_isr, NULL, "ehci-1");
|
||||
rt_hw_interrupt_set_priority(IRQ_EHCI, IRQ_LEVEL_1);
|
||||
rt_hw_interrupt_umask(IRQ_EHCI);
|
||||
}
|
||||
|
||||
uint8_t usbh_get_port_speed(struct usbh_bus *bus, const uint8_t port)
|
||||
{
|
||||
return USB_SPEED_HIGH;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
* Copyright (c) 2025, YC113
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usbh_core.h"
|
||||
#include "usb_hc_ehci.h"
|
||||
|
||||
#ifdef CONFIG_USB_EHCI_WITH_OHCI
|
||||
#include "usb_hc_ohci.h"
|
||||
#endif
|
||||
|
||||
#include "interrupt.h"
|
||||
#include "drv_reg_base.h"
|
||||
#include "drv_clock.h"
|
||||
|
||||
#if CONFIG_USBHOST_MAX_BUS != 2
|
||||
#error "t113 has 2 usb host controller"
|
||||
#endif
|
||||
|
||||
#if CONFIG_USB_OHCI_HCOR_OFFSET != 0x400
|
||||
#error "t113 CONFIG_USB_OHCI_HCOR_OFFSET must be 0x400"
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_USB_EHCI_HCOR_RESERVED_DISABLE)
|
||||
#error "t113 usb ehci register need reserved"
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_USB_EHCI_CONFIGFLAG)
|
||||
#error "t113 usb ehci has configflag register"
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_USB_EHCI_ISO)
|
||||
#error "t113 usb ehci no iso register"
|
||||
#endif
|
||||
|
||||
void usb_select_phyTohci(void)
|
||||
{
|
||||
*(volatile rt_uint32_t *)(USB0_OTG_BASE_ADDR + 0x420) &= ~(1 << 0);
|
||||
}
|
||||
|
||||
void usb_gate_open(rt_uint8_t busid)
|
||||
{
|
||||
rt_uint32_t addr;
|
||||
|
||||
addr = (rt_uint32_t)&CCU->usb0_clk + busid * 4;
|
||||
|
||||
if(busid == 0) {
|
||||
/* otg gate open*/
|
||||
CCU->usb_bgr |= 1 << 8;
|
||||
|
||||
/* otg bus reset */
|
||||
CCU->usb_bgr &= ~(1 << 24);
|
||||
sdelay(10);
|
||||
CCU->usb_bgr |= (1 << 24);
|
||||
sdelay(10);
|
||||
}
|
||||
|
||||
/* ehci gate open */
|
||||
CCU->usb_bgr |= (1 << 4) << busid;
|
||||
|
||||
/* ehci bus reset */
|
||||
CCU->usb_bgr &= ~((1 << 20) << busid);
|
||||
sdelay(10);
|
||||
CCU->usb_bgr |= (1 << 20) << busid;
|
||||
sdelay(10);
|
||||
|
||||
/* ohci gate open */
|
||||
CCU->usb_bgr |= 1 << busid;
|
||||
|
||||
/* ohci bus reset */
|
||||
CCU->usb_bgr &= ~((1 << 16) << busid);
|
||||
sdelay(10);
|
||||
CCU->usb_bgr |= (1 << 16) << busid;
|
||||
sdelay(10);
|
||||
|
||||
sdelay(10);
|
||||
|
||||
/* clock enable */
|
||||
*(volatile rt_uint32_t *)addr &= ~(3 << 24);
|
||||
*(volatile rt_uint32_t *)addr |= (1 << 31) | (1 << 24);
|
||||
|
||||
/* reset phy */
|
||||
*(volatile rt_uint32_t *)addr &= ~(1 << 30);
|
||||
sdelay(10);
|
||||
*(volatile rt_uint32_t *)addr |= 1 << 30;
|
||||
sdelay(10);
|
||||
|
||||
/* otg phy select */
|
||||
if(busid == 0) usb_select_phyTohci();
|
||||
|
||||
USB_LOG_DBG("usb%d gate : %X, clock : %X\n", busid, CCU->usb_bgr, *(volatile rt_uint32_t *)addr);
|
||||
}
|
||||
|
||||
void usb_clean_siddp(struct usbh_bus *bus)
|
||||
{
|
||||
*(volatile rt_uint32_t *)(bus->hcd.reg_base + 0x810) &= ~(1 << 3);
|
||||
}
|
||||
|
||||
void usb_hci_set_passby(struct usbh_bus *bus)
|
||||
{
|
||||
/* AHB Master interface INCR16 enable */
|
||||
/* AHB Master interface INCR8 enable */
|
||||
/* AHB Master interface burst type INCR4 enable */
|
||||
/* AHB Master interface INCRX align enable */
|
||||
/* ULPI bypass enable */
|
||||
*(volatile rt_uint32_t *)(bus->hcd.reg_base + 0x800) |= (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 0);
|
||||
}
|
||||
|
||||
void t113_ehci_isr(int vector, void *arg)
|
||||
{
|
||||
rt_interrupt_enter();
|
||||
|
||||
struct usbh_bus *bus = (struct usbh_bus *)arg;
|
||||
|
||||
USB_LOG_DBG("t113_ehci_isr");
|
||||
|
||||
extern void USBH_IRQHandler(uint8_t busid);
|
||||
USBH_IRQHandler(bus->hcd.hcd_id);
|
||||
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_EHCI_WITH_OHCI
|
||||
|
||||
void t113_ohci_isr(int vector, void *arg)
|
||||
{
|
||||
rt_interrupt_enter();
|
||||
|
||||
struct usbh_bus *bus = (struct usbh_bus *)arg;
|
||||
|
||||
USB_LOG_DBG("t113_ohci_isr");
|
||||
|
||||
extern void OHCI_IRQHandler(uint8_t busid);
|
||||
OHCI_IRQHandler(bus->hcd.hcd_id);
|
||||
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void usb_hc_low_level_init(struct usbh_bus *bus)
|
||||
{
|
||||
int vector;
|
||||
RT_ASSERT(bus->busid <= 1);
|
||||
|
||||
usb_gate_open(bus->busid);
|
||||
usb_clean_siddp(bus);
|
||||
usb_hci_set_passby(bus);
|
||||
|
||||
/* register EHCI interrupt callback */
|
||||
vector = T113_IRQ_USB0_EHCI + (bus->busid > 0 ? 3 : 0);
|
||||
rt_hw_interrupt_install(vector, t113_ehci_isr, bus, RT_NULL);
|
||||
rt_hw_interrupt_umask(vector);
|
||||
|
||||
/* register OHCI interrupt callback */
|
||||
#ifdef CONFIG_USB_EHCI_WITH_OHCI
|
||||
rt_hw_interrupt_install(vector + 1, t113_ohci_isr, bus, RT_NULL);
|
||||
rt_hw_interrupt_set_priority(vector, 11 << 4);
|
||||
rt_hw_interrupt_umask(vector + 1);
|
||||
#endif
|
||||
|
||||
USB_LOG_DBG("usb%d vector : %d, phy : %X\n", bus->busid, vector, *(volatile rt_uint32_t *)(bus->hcd.reg_base + 0x810));
|
||||
USB_LOG_DBG("usb%d hc low level init success\n", bus->busid);
|
||||
}
|
||||
|
||||
uint8_t usbh_get_port_speed(struct usbh_bus *bus, const uint8_t port)
|
||||
{
|
||||
/* Defined by individual manufacturers */
|
||||
uint32_t regval;
|
||||
|
||||
regval = EHCI_HCOR->portsc[port - 1];
|
||||
if ((regval & EHCI_PORTSC_LSTATUS_MASK) == EHCI_PORTSC_LSTATUS_KSTATE)
|
||||
return USB_SPEED_LOW;
|
||||
|
||||
if (regval & EHCI_PORTSC_PE)
|
||||
return USB_SPEED_HIGH;
|
||||
else
|
||||
return USB_SPEED_FULL;
|
||||
}
|
||||
|
||||
int __usbh_init(void)
|
||||
{
|
||||
#ifdef T113_USING_USB0_HOST
|
||||
/* USB0 MSC test OK */
|
||||
usbh_initialize(0, USB0_BASE_ADDR);
|
||||
#endif
|
||||
|
||||
#ifdef T113_USING_USB1_HOST
|
||||
/* USB1 MSC test OK */
|
||||
usbh_initialize(1, USB1_BASE_ADDR);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef PKG_CHERRYUSB_HOST
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
INIT_ENV_EXPORT(__usbh_init);
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (c) 2022, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef _USB_EHCI_PRIV_H
|
||||
#define _USB_EHCI_PRIV_H
|
||||
|
||||
#include "usbh_core.h"
|
||||
#include "usbh_hub.h"
|
||||
#include "usb_ehci_reg.h"
|
||||
|
||||
#define EHCI_HCCR ((struct ehci_hccr *)(uintptr_t)(bus->hcd.reg_base + CONFIG_USB_EHCI_HCCR_OFFSET))
|
||||
#define EHCI_HCOR ((struct ehci_hcor *)(uintptr_t)(bus->hcd.reg_base + CONFIG_USB_EHCI_HCCR_OFFSET + g_ehci_hcd[bus->hcd.hcd_id].hcor_offset))
|
||||
|
||||
#define EHCI_PTR2ADDR(x) ((uint32_t)(uintptr_t)(x) & ~0x1F)
|
||||
#define EHCI_ADDR2QH(x) ((struct ehci_qh_hw *)(uintptr_t)((uint32_t)(x) & ~0x1F))
|
||||
#define EHCI_ADDR2QTD(x) ((struct ehci_qtd_hw *)(uintptr_t)((uint32_t)(x) & ~0x1F))
|
||||
#define EHCI_ADDR2ITD(x) ((struct ehci_itd_hw *)(uintptr_t)((uint32_t)(x) & ~0x1F))
|
||||
|
||||
#ifndef CONFIG_USB_EHCI_QH_NUM
|
||||
#define CONFIG_USB_EHCI_QH_NUM 10
|
||||
#endif
|
||||
#ifndef CONFIG_USB_EHCI_QTD_NUM
|
||||
#define CONFIG_USB_EHCI_QTD_NUM (CONFIG_USB_EHCI_QH_NUM * 3)
|
||||
#endif
|
||||
#ifndef CONFIG_USB_EHCI_ITD_NUM
|
||||
#define CONFIG_USB_EHCI_ITD_NUM 5
|
||||
#endif
|
||||
#ifndef CONFIG_USB_EHCI_ISO_NUM
|
||||
#define CONFIG_USB_EHCI_ISO_NUM 4
|
||||
#endif
|
||||
|
||||
#if CONFIG_USB_ALIGN_SIZE <= 32
|
||||
#define CONFIG_USB_EHCI_ALIGN_SIZE 32
|
||||
#elif CONFIG_USB_ALIGN_SIZE <= 64
|
||||
#define CONFIG_USB_EHCI_ALIGN_SIZE 64
|
||||
#else
|
||||
#error "CONFIG_USB_ALIGN_SIZE must be 32 or 64"
|
||||
#endif
|
||||
|
||||
#if CONFIG_USB_EHCI_QTD_NUM < 9
|
||||
#error CONFIG_USB_EHCI_QTD_NUM is too small, recommand CONFIG_USB_EHCI_QH_NUM * 3
|
||||
#endif
|
||||
|
||||
struct ehci_qtd_hw {
|
||||
struct ehci_qtd hw;
|
||||
#if defined(CONFIG_USB_EHCI_DESC_DCACHE_ENABLE) && (CONFIG_USB_ALIGN_SIZE == 64)
|
||||
uint8_t pad[32];
|
||||
#endif
|
||||
bool inuse;
|
||||
struct usbh_urb *urb;
|
||||
uintptr_t bufaddr;
|
||||
uint32_t length;
|
||||
} __attribute__((aligned(CONFIG_USB_EHCI_ALIGN_SIZE)));
|
||||
|
||||
struct ehci_qh_hw {
|
||||
struct ehci_qh hw;
|
||||
#if defined(CONFIG_USB_EHCI_DESC_DCACHE_ENABLE)
|
||||
uint16_t pad[16];
|
||||
#endif
|
||||
bool inuse;
|
||||
uint32_t first_qtd;
|
||||
struct usbh_urb *urb;
|
||||
usb_osal_sem_t waitsem;
|
||||
uint8_t remove_in_iaad;
|
||||
} __attribute__((aligned(CONFIG_USB_EHCI_ALIGN_SIZE)));
|
||||
|
||||
struct ehci_itd_hw {
|
||||
struct ehci_itd hw;
|
||||
struct usbh_urb *urb;
|
||||
uint16_t start_frame;
|
||||
uint8_t mf_unmask;
|
||||
uint8_t mf_valid;
|
||||
uint32_t pkt_idx[8];
|
||||
bool dir_in;
|
||||
} __attribute__((aligned(CONFIG_USB_EHCI_ALIGN_SIZE)));
|
||||
|
||||
struct ehci_iso_hw {
|
||||
struct ehci_itd_hw itd_pool[CONFIG_USB_EHCI_ITD_NUM];
|
||||
uint32_t itd_num;
|
||||
};
|
||||
|
||||
struct ehci_hcd {
|
||||
bool ehci_iso_used[CONFIG_USB_EHCI_ISO_NUM];
|
||||
bool ppc; /* Port Power Control */
|
||||
bool has_tt; /* if use tt instead of Companion Controller */
|
||||
uint8_t n_cc; /* Number of Companion Controller */
|
||||
uint8_t n_pcc; /* Number of ports supported per companion host controller */
|
||||
uint8_t n_ports;
|
||||
uint8_t hcor_offset;
|
||||
};
|
||||
|
||||
extern struct ehci_hcd g_ehci_hcd[CONFIG_USBHOST_MAX_BUS];
|
||||
extern uint32_t g_framelist[CONFIG_USBHOST_MAX_BUS][USB_ALIGN_UP(CONFIG_USB_EHCI_FRAME_LIST_SIZE, 1024)];
|
||||
extern uint8_t usbh_get_port_speed(struct usbh_bus *bus, const uint8_t port);
|
||||
|
||||
int ehci_iso_urb_init(struct usbh_bus *bus, struct usbh_urb *urb);
|
||||
void ehci_kill_iso_urb(struct usbh_bus *bus, struct usbh_urb *urb);
|
||||
void ehci_scan_isochronous_list(struct usbh_bus *bus);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,30 @@
|
||||
# Note
|
||||
|
||||
## Support Chip List
|
||||
|
||||
## STM32
|
||||
|
||||
- STM32F042x6、STM32F048xx、STM32F070x6、STM32F070xb、STM32F072xb、STM32F078xx
|
||||
- STM32F102x6、STM32F102xb、STM32F103x6、STM32F103xb、STM32F103xe、STM32F103xg
|
||||
- STM32F302x8、STM32F302xc、STM32F302xe、STM32F373xc
|
||||
- STM32g431xx、STM32g441xx、STM32g471xx、STM32g483xx、STM32g484xx、STM32gbk1cb
|
||||
- STM32l052xx、STM32l053xx、STM32l062xx、STM32l063xx、STM32l072xx、STM32l073xx、STM32l082xx、STM32l083xx
|
||||
- STM32l100xb、STM32l100xba、STM32l100xc、STM32l151xb、STM32l151xba、STM32l151xc、STM32l151xca、STM32l151xd、STM32l151xdx、STM32l151xe、STM32l152xb、STM32l152xba、STM32l152xc、STM32l152xa、STM32l152xd、STM32l152xdx、STM32l152xe、STM32l162xc、STM32l162xca、STM32l162xd、STM32l162xdx、STM32l162xe
|
||||
- STM32l412xx、STM32l422xx、STM32l432xx、STM32l433xx、STM32l442xx、STM32l452xx、STM32l462xx
|
||||
- STM32wb5mxx、STM32wb35xx、STM32wb55xx
|
||||
|
||||
## AT32
|
||||
|
||||
- AT32F403xx、AT32F407xx、AT32F413xx
|
||||
|
||||
## APM32
|
||||
|
||||
- APM32f10x
|
||||
|
||||
## GD32
|
||||
|
||||
- GD32F10X
|
||||
|
||||
## CH32
|
||||
|
||||
- CH32F10x、CH32V10x
|
||||
@@ -0,0 +1,562 @@
|
||||
/*
|
||||
* Copyright (c) 2022, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usbd_core.h"
|
||||
|
||||
#if (CONFIG_USB_DBG_LEVEL >= USB_DBG_LOG)
|
||||
#error "fsdev cannot enable USB_DBG_LOG"
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_USBDEV_FSDEV_PMA_ACCESS
|
||||
#error "please define CONFIG_USBDEV_FSDEV_PMA_ACCESS in usb_config.h"
|
||||
#endif
|
||||
|
||||
#define PMA_ACCESS CONFIG_USBDEV_FSDEV_PMA_ACCESS
|
||||
#include "usb_fsdev_reg.h"
|
||||
|
||||
#ifndef CONFIG_USB_FSDEV_RAM_SIZE
|
||||
#define CONFIG_USB_FSDEV_RAM_SIZE 512
|
||||
#endif
|
||||
|
||||
#undef CONFIG_USBDEV_EP_NUM
|
||||
#define CONFIG_USBDEV_EP_NUM 8
|
||||
|
||||
#define USB ((USB_TypeDef *)g_usbdev_bus[0].reg_base)
|
||||
|
||||
#define USB_BTABLE_SIZE (8 * CONFIG_USBDEV_EP_NUM)
|
||||
|
||||
static void fsdev_write_pma(USB_TypeDef *USBx, uint8_t *pbUsrBuf, uint16_t wPMABufAddr, uint16_t wNBytes);
|
||||
static void fsdev_read_pma(USB_TypeDef *USBx, uint8_t *pbUsrBuf, uint16_t wPMABufAddr, uint16_t wNBytes);
|
||||
|
||||
/* Endpoint state */
|
||||
struct fsdev_ep_state {
|
||||
uint16_t ep_mps; /* Endpoint max packet size */
|
||||
uint8_t ep_type; /* Endpoint type */
|
||||
uint8_t ep_stalled; /* Endpoint stall flag */
|
||||
uint8_t ep_enable; /* Endpoint enable */
|
||||
uint16_t ep_pma_buf_len; /* Previously allocated buffer size */
|
||||
uint16_t ep_pma_addr; /* ep pmd allocated addr */
|
||||
uint8_t *xfer_buf;
|
||||
uint32_t xfer_len;
|
||||
uint32_t actual_xfer_len;
|
||||
};
|
||||
|
||||
/* Driver state */
|
||||
struct fsdev_udc {
|
||||
struct usb_setup_packet setup;
|
||||
volatile uint8_t dev_addr; /*!< USB Address */
|
||||
volatile uint32_t pma_offset; /*!< pma offset */
|
||||
struct fsdev_ep_state in_ep[CONFIG_USBDEV_EP_NUM]; /*!< IN endpoint parameters*/
|
||||
struct fsdev_ep_state out_ep[CONFIG_USBDEV_EP_NUM]; /*!< OUT endpoint parameters */
|
||||
} g_fsdev_udc;
|
||||
|
||||
__WEAK void usb_dc_low_level_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
__WEAK void usb_dc_low_level_deinit(void)
|
||||
{
|
||||
}
|
||||
|
||||
int usb_dc_init(uint8_t busid)
|
||||
{
|
||||
usb_dc_low_level_init();
|
||||
|
||||
/* Init Device */
|
||||
/* CNTR_FRES = 1 */
|
||||
USB->CNTR = (uint16_t)USB_CNTR_FRES;
|
||||
|
||||
/* CNTR_FRES = 0 */
|
||||
USB->CNTR = 0U;
|
||||
|
||||
/* Clear pending interrupts */
|
||||
USB->ISTR = 0U;
|
||||
|
||||
/*Set Btable Address*/
|
||||
USB->BTABLE = BTABLE_ADDRESS;
|
||||
|
||||
uint32_t winterruptmask;
|
||||
|
||||
/* Set winterruptmask variable */
|
||||
winterruptmask = USB_CNTR_CTRM | USB_CNTR_WKUPM |
|
||||
USB_CNTR_SUSPM | USB_CNTR_ERRM |
|
||||
USB_CNTR_ESOFM | USB_CNTR_RESETM;
|
||||
|
||||
#ifdef CONFIG_USBDEV_SOF_ENABLE
|
||||
winterruptmask |= USB_CNTR_SOFM;
|
||||
#endif
|
||||
|
||||
/* Set interrupt mask */
|
||||
USB->CNTR = (uint16_t)winterruptmask;
|
||||
|
||||
/* Enabling DP Pull-UP bit to Connect internal PU resistor on USB DP line */
|
||||
USB->BCDR |= (uint16_t)USB_BCDR_DPPU;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_dc_deinit(uint8_t busid)
|
||||
{
|
||||
/* disable all interrupts and force USB reset */
|
||||
USB->CNTR = (uint16_t)USB_CNTR_FRES;
|
||||
|
||||
/* clear interrupt status register */
|
||||
USB->ISTR = 0U;
|
||||
|
||||
/* switch-off device */
|
||||
USB->CNTR = (uint16_t)(USB_CNTR_FRES | USB_CNTR_PDWN);
|
||||
|
||||
usb_dc_low_level_deinit();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_set_address(uint8_t busid, const uint8_t addr)
|
||||
{
|
||||
if (addr == 0U) {
|
||||
/* set device address and enable function */
|
||||
USB->DADDR = (uint16_t)USB_DADDR_EF;
|
||||
}
|
||||
|
||||
g_fsdev_udc.dev_addr = addr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_set_remote_wakeup(uint8_t busid)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t usbd_get_port_speed(uint8_t busid)
|
||||
{
|
||||
return USB_SPEED_FULL;
|
||||
}
|
||||
|
||||
int usbd_ep_open(uint8_t busid, const struct usb_endpoint_descriptor *ep)
|
||||
{
|
||||
uint8_t ep_idx = USB_EP_GET_IDX(ep->bEndpointAddress);
|
||||
|
||||
USB_ASSERT_MSG(ep_idx < CONFIG_USBDEV_EP_NUM, "Ep addr %02x overflow", ep->bEndpointAddress);
|
||||
USB_ASSERT_MSG(USB_GET_ENDPOINT_TYPE(ep->bmAttributes) != USB_ENDPOINT_TYPE_ISOCHRONOUS, "iso endpoint not support in fsdev");
|
||||
|
||||
uint16_t wEpRegVal;
|
||||
|
||||
/* initialize Endpoint */
|
||||
switch (USB_GET_ENDPOINT_TYPE(ep->bmAttributes)) {
|
||||
case USB_ENDPOINT_TYPE_CONTROL:
|
||||
wEpRegVal = USB_EP_CONTROL;
|
||||
break;
|
||||
|
||||
case USB_ENDPOINT_TYPE_BULK:
|
||||
wEpRegVal = USB_EP_BULK;
|
||||
break;
|
||||
|
||||
case USB_ENDPOINT_TYPE_INTERRUPT:
|
||||
wEpRegVal = USB_EP_INTERRUPT;
|
||||
break;
|
||||
|
||||
case USB_ENDPOINT_TYPE_ISOCHRONOUS:
|
||||
wEpRegVal = USB_EP_ISOCHRONOUS;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
PCD_SET_EPTYPE(USB, ep_idx, wEpRegVal);
|
||||
|
||||
PCD_SET_EP_ADDRESS(USB, ep_idx, ep_idx);
|
||||
if (USB_EP_DIR_IS_OUT(ep->bEndpointAddress)) {
|
||||
g_fsdev_udc.out_ep[ep_idx].ep_mps = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
|
||||
g_fsdev_udc.out_ep[ep_idx].ep_type = USB_GET_ENDPOINT_TYPE(ep->bmAttributes);
|
||||
g_fsdev_udc.out_ep[ep_idx].ep_enable = true;
|
||||
if (g_fsdev_udc.out_ep[ep_idx].ep_mps > g_fsdev_udc.out_ep[ep_idx].ep_pma_buf_len) {
|
||||
USB_ASSERT_MSG((g_fsdev_udc.pma_offset + g_fsdev_udc.out_ep[ep_idx].ep_mps) <= CONFIG_USB_FSDEV_RAM_SIZE,
|
||||
"Ep pma %02x overflow", ep->bEndpointAddress);
|
||||
|
||||
g_fsdev_udc.out_ep[ep_idx].ep_pma_buf_len = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
|
||||
g_fsdev_udc.out_ep[ep_idx].ep_pma_addr = g_fsdev_udc.pma_offset;
|
||||
/*Set the endpoint Receive buffer address */
|
||||
PCD_SET_EP_RX_ADDRESS(USB, ep_idx, g_fsdev_udc.pma_offset);
|
||||
g_fsdev_udc.pma_offset += USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
|
||||
}
|
||||
/*Set the endpoint Receive buffer counter*/
|
||||
PCD_SET_EP_RX_CNT(USB, ep_idx, USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize));
|
||||
PCD_CLEAR_RX_DTOG(USB, ep_idx);
|
||||
} else {
|
||||
g_fsdev_udc.in_ep[ep_idx].ep_mps = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
|
||||
g_fsdev_udc.in_ep[ep_idx].ep_type = USB_GET_ENDPOINT_TYPE(ep->bmAttributes);
|
||||
g_fsdev_udc.in_ep[ep_idx].ep_enable = true;
|
||||
if (g_fsdev_udc.in_ep[ep_idx].ep_mps > g_fsdev_udc.in_ep[ep_idx].ep_pma_buf_len) {
|
||||
USB_ASSERT_MSG((g_fsdev_udc.pma_offset + g_fsdev_udc.in_ep[ep_idx].ep_mps) <= CONFIG_USB_FSDEV_RAM_SIZE,
|
||||
"Ep pma %02x overflow", ep->bEndpointAddress);
|
||||
|
||||
g_fsdev_udc.in_ep[ep_idx].ep_pma_buf_len = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
|
||||
g_fsdev_udc.in_ep[ep_idx].ep_pma_addr = g_fsdev_udc.pma_offset;
|
||||
/*Set the endpoint Transmit buffer address */
|
||||
PCD_SET_EP_TX_ADDRESS(USB, ep_idx, g_fsdev_udc.pma_offset);
|
||||
g_fsdev_udc.pma_offset += USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
|
||||
}
|
||||
|
||||
PCD_CLEAR_TX_DTOG(USB, ep_idx);
|
||||
if (USB_GET_ENDPOINT_TYPE(ep->bmAttributes) != USB_ENDPOINT_TYPE_ISOCHRONOUS) {
|
||||
/* Configure NAK status for the Endpoint */
|
||||
PCD_SET_EP_TX_STATUS(USB, ep_idx, USB_EP_TX_NAK);
|
||||
} else {
|
||||
/* Configure TX Endpoint to disabled state */
|
||||
PCD_SET_EP_TX_STATUS(USB, ep_idx, USB_EP_TX_DIS);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_close(uint8_t busid, const uint8_t ep)
|
||||
{
|
||||
uint8_t ep_idx = USB_EP_GET_IDX(ep);
|
||||
|
||||
if (USB_EP_DIR_IS_OUT(ep)) {
|
||||
PCD_CLEAR_RX_DTOG(USB, ep_idx);
|
||||
|
||||
/* Configure DISABLE status for the Endpoint*/
|
||||
PCD_SET_EP_RX_STATUS(USB, ep_idx, USB_EP_RX_DIS);
|
||||
} else {
|
||||
PCD_CLEAR_TX_DTOG(USB, ep_idx);
|
||||
|
||||
/* Configure DISABLE status for the Endpoint*/
|
||||
PCD_SET_EP_TX_STATUS(USB, ep_idx, USB_EP_TX_DIS);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_set_stall(uint8_t busid, const uint8_t ep)
|
||||
{
|
||||
uint8_t ep_idx = USB_EP_GET_IDX(ep);
|
||||
|
||||
if (USB_EP_DIR_IS_OUT(ep)) {
|
||||
PCD_SET_EP_RX_STATUS(USB, ep_idx, USB_EP_RX_STALL);
|
||||
} else {
|
||||
PCD_SET_EP_TX_STATUS(USB, ep_idx, USB_EP_TX_STALL);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_clear_stall(uint8_t busid, const uint8_t ep)
|
||||
{
|
||||
uint8_t ep_idx = USB_EP_GET_IDX(ep);
|
||||
|
||||
if (USB_EP_DIR_IS_OUT(ep)) {
|
||||
PCD_CLEAR_RX_DTOG(USB, ep_idx);
|
||||
/* Configure VALID status for the Endpoint */
|
||||
PCD_SET_EP_RX_STATUS(USB, ep_idx, USB_EP_RX_VALID);
|
||||
} else {
|
||||
PCD_CLEAR_TX_DTOG(USB, ep_idx);
|
||||
|
||||
if (g_fsdev_udc.in_ep[ep_idx].ep_type != USB_ENDPOINT_TYPE_ISOCHRONOUS) {
|
||||
/* Configure NAK status for the Endpoint */
|
||||
PCD_SET_EP_TX_STATUS(USB, ep_idx, USB_EP_TX_NAK);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_is_stalled(uint8_t busid, const uint8_t ep, uint8_t *stalled)
|
||||
{
|
||||
uint8_t ep_idx = USB_EP_GET_IDX(ep);
|
||||
|
||||
if (USB_EP_DIR_IS_OUT(ep)) {
|
||||
if (PCD_GET_EP_RX_STATUS(USB, ep_idx) & USB_EP_RX_STALL) {
|
||||
*stalled = 1;
|
||||
} else {
|
||||
*stalled = 0;
|
||||
}
|
||||
} else {
|
||||
if (PCD_GET_EP_TX_STATUS(USB, ep_idx) & USB_EP_TX_STALL) {
|
||||
*stalled = 1;
|
||||
} else {
|
||||
*stalled = 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_start_write(uint8_t busid, const uint8_t ep, const uint8_t *data, uint32_t data_len)
|
||||
{
|
||||
uint8_t ep_idx = USB_EP_GET_IDX(ep);
|
||||
|
||||
if (!data && data_len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!g_fsdev_udc.in_ep[ep_idx].ep_enable) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
g_fsdev_udc.in_ep[ep_idx].xfer_buf = (uint8_t *)data;
|
||||
g_fsdev_udc.in_ep[ep_idx].xfer_len = data_len;
|
||||
g_fsdev_udc.in_ep[ep_idx].actual_xfer_len = 0;
|
||||
|
||||
data_len = MIN(data_len, g_fsdev_udc.in_ep[ep_idx].ep_mps);
|
||||
|
||||
fsdev_write_pma(USB, (uint8_t *)data, g_fsdev_udc.in_ep[ep_idx].ep_pma_addr, (uint16_t)data_len);
|
||||
PCD_SET_EP_TX_CNT(USB, ep_idx, (uint16_t)data_len);
|
||||
PCD_SET_EP_TX_STATUS(USB, ep_idx, USB_EP_TX_VALID);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_start_read(uint8_t busid, const uint8_t ep, uint8_t *data, uint32_t data_len)
|
||||
{
|
||||
uint8_t ep_idx = USB_EP_GET_IDX(ep);
|
||||
|
||||
if (!data && data_len) {
|
||||
return -1;
|
||||
}
|
||||
if (!g_fsdev_udc.out_ep[ep_idx].ep_enable) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
g_fsdev_udc.out_ep[ep_idx].xfer_buf = data;
|
||||
g_fsdev_udc.out_ep[ep_idx].xfer_len = data_len;
|
||||
g_fsdev_udc.out_ep[ep_idx].actual_xfer_len = 0;
|
||||
|
||||
PCD_SET_EP_RX_STATUS(USB, ep_idx, USB_EP_RX_VALID);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void USBD_IRQHandler(uint8_t busid)
|
||||
{
|
||||
uint16_t wIstr, wEPVal;
|
||||
uint8_t ep_idx;
|
||||
uint8_t read_count;
|
||||
uint16_t write_count;
|
||||
uint16_t store_ep[8];
|
||||
|
||||
wIstr = USB->ISTR;
|
||||
if (wIstr & USB_ISTR_CTR) {
|
||||
while ((USB->ISTR & USB_ISTR_CTR) != 0U) {
|
||||
wIstr = USB->ISTR;
|
||||
|
||||
/* extract highest priority endpoint number */
|
||||
ep_idx = (uint8_t)(wIstr & USB_ISTR_EP_ID);
|
||||
|
||||
if (ep_idx == 0U) {
|
||||
if ((wIstr & USB_ISTR_DIR) == 0U) {
|
||||
PCD_CLEAR_TX_EP_CTR(USB, ep_idx);
|
||||
|
||||
write_count = PCD_GET_EP_TX_CNT(USB, ep_idx);
|
||||
|
||||
g_fsdev_udc.in_ep[ep_idx].xfer_buf += write_count;
|
||||
g_fsdev_udc.in_ep[ep_idx].xfer_len -= write_count;
|
||||
g_fsdev_udc.in_ep[ep_idx].actual_xfer_len += write_count;
|
||||
|
||||
usbd_event_ep_in_complete_handler(0, ep_idx | 0x80, g_fsdev_udc.in_ep[ep_idx].actual_xfer_len);
|
||||
|
||||
if (g_fsdev_udc.setup.wLength == 0) {
|
||||
/* In status, start reading setup */
|
||||
usbd_ep_start_read(0, 0x00, NULL, 0);
|
||||
} else if (g_fsdev_udc.setup.wLength && ((g_fsdev_udc.setup.bmRequestType & USB_REQUEST_DIR_MASK) == USB_REQUEST_DIR_OUT)) {
|
||||
/* In status, start reading setup */
|
||||
usbd_ep_start_read(0, 0x00, NULL, 0);
|
||||
}
|
||||
|
||||
if ((g_fsdev_udc.dev_addr > 0U) && (write_count == 0U)) {
|
||||
USB->DADDR = ((uint16_t)g_fsdev_udc.dev_addr | USB_DADDR_EF);
|
||||
g_fsdev_udc.dev_addr = 0U;
|
||||
}
|
||||
|
||||
} else {
|
||||
wEPVal = PCD_GET_ENDPOINT(USB, ep_idx);
|
||||
|
||||
if ((wEPVal & USB_EP_SETUP) != 0U) {
|
||||
PCD_CLEAR_RX_EP_CTR(USB, ep_idx);
|
||||
|
||||
read_count = PCD_GET_EP_RX_CNT(USB, ep_idx);
|
||||
fsdev_read_pma(USB, (uint8_t *)&g_fsdev_udc.setup, g_fsdev_udc.out_ep[ep_idx].ep_pma_addr, (uint16_t)read_count);
|
||||
|
||||
usbd_event_ep0_setup_complete_handler(0, (uint8_t *)&g_fsdev_udc.setup);
|
||||
|
||||
} else if ((wEPVal & USB_EP_CTR_RX) != 0U) {
|
||||
PCD_CLEAR_RX_EP_CTR(USB, ep_idx);
|
||||
|
||||
read_count = PCD_GET_EP_RX_CNT(USB, ep_idx);
|
||||
|
||||
fsdev_read_pma(USB, g_fsdev_udc.out_ep[ep_idx].xfer_buf, g_fsdev_udc.out_ep[ep_idx].ep_pma_addr, (uint16_t)read_count);
|
||||
|
||||
g_fsdev_udc.out_ep[ep_idx].xfer_buf += read_count;
|
||||
g_fsdev_udc.out_ep[ep_idx].xfer_len -= read_count;
|
||||
g_fsdev_udc.out_ep[ep_idx].actual_xfer_len += read_count;
|
||||
|
||||
usbd_event_ep_out_complete_handler(0, ep_idx, g_fsdev_udc.out_ep[ep_idx].actual_xfer_len);
|
||||
|
||||
if (read_count == 0) {
|
||||
/* Out status, start reading setup */
|
||||
usbd_ep_start_read(0, 0x00, NULL, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
wEPVal = PCD_GET_ENDPOINT(USB, ep_idx);
|
||||
|
||||
if ((wEPVal & USB_EP_CTR_RX) != 0U) {
|
||||
PCD_CLEAR_RX_EP_CTR(USB, ep_idx);
|
||||
read_count = PCD_GET_EP_RX_CNT(USB, ep_idx);
|
||||
fsdev_read_pma(USB, g_fsdev_udc.out_ep[ep_idx].xfer_buf, g_fsdev_udc.out_ep[ep_idx].ep_pma_addr, (uint16_t)read_count);
|
||||
g_fsdev_udc.out_ep[ep_idx].xfer_buf += read_count;
|
||||
g_fsdev_udc.out_ep[ep_idx].xfer_len -= read_count;
|
||||
g_fsdev_udc.out_ep[ep_idx].actual_xfer_len += read_count;
|
||||
|
||||
if ((read_count < g_fsdev_udc.out_ep[ep_idx].ep_mps) ||
|
||||
(g_fsdev_udc.out_ep[ep_idx].xfer_len == 0)) {
|
||||
usbd_event_ep_out_complete_handler(0, ep_idx, g_fsdev_udc.out_ep[ep_idx].actual_xfer_len);
|
||||
} else {
|
||||
PCD_SET_EP_RX_STATUS(USB, ep_idx, USB_EP_RX_VALID);
|
||||
}
|
||||
}
|
||||
|
||||
if ((wEPVal & USB_EP_CTR_TX) != 0U) {
|
||||
PCD_CLEAR_TX_EP_CTR(USB, ep_idx);
|
||||
write_count = PCD_GET_EP_TX_CNT(USB, ep_idx);
|
||||
|
||||
g_fsdev_udc.in_ep[ep_idx].xfer_buf += write_count;
|
||||
g_fsdev_udc.in_ep[ep_idx].xfer_len -= write_count;
|
||||
g_fsdev_udc.in_ep[ep_idx].actual_xfer_len += write_count;
|
||||
|
||||
if (g_fsdev_udc.in_ep[ep_idx].xfer_len == 0) {
|
||||
usbd_event_ep_in_complete_handler(0, ep_idx | 0x80, g_fsdev_udc.in_ep[ep_idx].actual_xfer_len);
|
||||
} else {
|
||||
write_count = MIN(g_fsdev_udc.in_ep[ep_idx].xfer_len, g_fsdev_udc.in_ep[ep_idx].ep_mps);
|
||||
fsdev_write_pma(USB, g_fsdev_udc.in_ep[ep_idx].xfer_buf, g_fsdev_udc.in_ep[ep_idx].ep_pma_addr, (uint16_t)write_count);
|
||||
PCD_SET_EP_TX_CNT(USB, ep_idx, write_count);
|
||||
PCD_SET_EP_TX_STATUS(USB, ep_idx, USB_EP_TX_VALID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (wIstr & USB_ISTR_RESET) {
|
||||
memset(&g_fsdev_udc, 0, sizeof(struct fsdev_udc));
|
||||
g_fsdev_udc.pma_offset = USB_BTABLE_SIZE;
|
||||
usbd_event_reset_handler(0);
|
||||
/* start reading setup packet */
|
||||
PCD_SET_EP_RX_STATUS(USB, 0, USB_EP_RX_VALID);
|
||||
USB->ISTR &= (uint16_t)(~USB_ISTR_RESET);
|
||||
}
|
||||
if (wIstr & USB_ISTR_PMAOVR) {
|
||||
USB->ISTR &= (uint16_t)(~USB_ISTR_PMAOVR);
|
||||
}
|
||||
if (wIstr & USB_ISTR_ERR) {
|
||||
USB->ISTR &= (uint16_t)(~USB_ISTR_ERR);
|
||||
}
|
||||
if (wIstr & USB_ISTR_WKUP) {
|
||||
USB->CNTR &= (uint16_t) ~(USB_CNTR_LP_MODE);
|
||||
USB->CNTR &= (uint16_t) ~(USB_CNTR_FSUSP);
|
||||
|
||||
USB->ISTR &= (uint16_t)(~USB_ISTR_WKUP);
|
||||
}
|
||||
if (wIstr & USB_ISTR_SUSP) {
|
||||
/* WA: To Clear Wakeup flag if raised with suspend signal */
|
||||
|
||||
/* Store Endpoint register */
|
||||
for (uint8_t i = 0U; i < 8U; i++) {
|
||||
store_ep[i] = PCD_GET_ENDPOINT(USB, i);
|
||||
}
|
||||
|
||||
/* FORCE RESET */
|
||||
USB->CNTR |= (uint16_t)(USB_CNTR_FRES);
|
||||
|
||||
/* CLEAR RESET */
|
||||
USB->CNTR &= (uint16_t)(~USB_CNTR_FRES);
|
||||
|
||||
/* wait for reset flag in ISTR */
|
||||
while ((USB->ISTR & USB_ISTR_RESET) == 0U) {
|
||||
}
|
||||
|
||||
/* Clear Reset Flag */
|
||||
USB->ISTR &= (uint16_t)(~USB_ISTR_RESET);
|
||||
/* Restore Registre */
|
||||
for (uint8_t i = 0U; i < 8U; i++) {
|
||||
PCD_SET_ENDPOINT(USB, i, store_ep[i]);
|
||||
}
|
||||
|
||||
/* Force low-power mode in the macrocell */
|
||||
USB->CNTR |= (uint16_t)USB_CNTR_FSUSP;
|
||||
|
||||
/* clear of the ISTR bit must be done after setting of CNTR_FSUSP */
|
||||
USB->ISTR &= (uint16_t)(~USB_ISTR_SUSP);
|
||||
|
||||
USB->CNTR |= (uint16_t)USB_CNTR_LP_MODE;
|
||||
}
|
||||
#ifdef CONFIG_USBDEV_SOF_ENABLE
|
||||
if (wIstr & USB_ISTR_SOF) {
|
||||
USB->ISTR &= (uint16_t)(~USB_ISTR_SOF);
|
||||
usbd_event_sof_handler(0);
|
||||
}
|
||||
#endif
|
||||
if (wIstr & USB_ISTR_ESOF) {
|
||||
USB->ISTR &= (uint16_t)(~USB_ISTR_ESOF);
|
||||
}
|
||||
}
|
||||
|
||||
static void fsdev_write_pma(USB_TypeDef *USBx, uint8_t *pbUsrBuf, uint16_t wPMABufAddr, uint16_t wNBytes)
|
||||
{
|
||||
uint32_t n = ((uint32_t)wNBytes + 1U) >> 1;
|
||||
uint32_t BaseAddr = (uint32_t)USBx;
|
||||
uint32_t i, temp1, temp2;
|
||||
__IO uint16_t *pdwVal;
|
||||
uint8_t *pBuf = pbUsrBuf;
|
||||
|
||||
pdwVal = (__IO uint16_t *)(BaseAddr + 0x400U + ((uint32_t)wPMABufAddr * PMA_ACCESS));
|
||||
|
||||
for (i = n; i != 0U; i--) {
|
||||
temp1 = *pBuf;
|
||||
pBuf++;
|
||||
temp2 = temp1 | ((uint16_t)((uint16_t)*pBuf << 8));
|
||||
*pdwVal = (uint16_t)temp2;
|
||||
pdwVal++;
|
||||
|
||||
#if PMA_ACCESS > 1U
|
||||
pdwVal++;
|
||||
#endif
|
||||
|
||||
pBuf++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Copy data from packet memory area (PMA) to user memory buffer
|
||||
* @param USBx USB peripheral instance register address.
|
||||
* @param pbUsrBuf pointer to user memory area.
|
||||
* @param wPMABufAddr address into PMA.
|
||||
* @param wNBytes no. of bytes to be copied.
|
||||
* @retval None
|
||||
*/
|
||||
static void fsdev_read_pma(USB_TypeDef *USBx, uint8_t *pbUsrBuf, uint16_t wPMABufAddr, uint16_t wNBytes)
|
||||
{
|
||||
uint32_t n = (uint32_t)wNBytes >> 1;
|
||||
uint32_t BaseAddr = (uint32_t)USBx;
|
||||
uint32_t i, temp;
|
||||
__IO uint16_t *pdwVal;
|
||||
uint8_t *pBuf = pbUsrBuf;
|
||||
|
||||
pdwVal = (__IO uint16_t *)(BaseAddr + 0x400U + ((uint32_t)wPMABufAddr * PMA_ACCESS));
|
||||
|
||||
for (i = n; i != 0U; i--) {
|
||||
temp = *(__IO uint16_t *)pdwVal;
|
||||
pdwVal++;
|
||||
*pBuf = (uint8_t)((temp >> 0) & 0xFFU);
|
||||
pBuf++;
|
||||
*pBuf = (uint8_t)((temp >> 8) & 0xFFU);
|
||||
pBuf++;
|
||||
|
||||
#if PMA_ACCESS > 1U
|
||||
pdwVal++;
|
||||
#endif
|
||||
}
|
||||
|
||||
if ((wNBytes % 2U) != 0U) {
|
||||
temp = *pdwVal;
|
||||
*pBuf = (uint8_t)((temp >> 0) & 0xFFU);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2025, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usbd_core.h"
|
||||
|
||||
#if __has_include("stm32f0xx_hal.h")
|
||||
#include "stm32f0xx_hal.h"
|
||||
#elif __has_include("stm32f1xx_hal.h")
|
||||
#include "stm32f1xx_hal.h"
|
||||
#elif __has_include("stm32f3xx_hal.h")
|
||||
#include "stm32f3xx_hal.h"
|
||||
#elif __has_include("stm32g0xx_hal.h")
|
||||
#include "stm32g0xx_hal.h"
|
||||
#elif __has_include("stm32g4xx_hal.h")
|
||||
#include "stm32g4xx_hal.h"
|
||||
#elif __has_include("stm32l0xx_hal.h")
|
||||
#include "stm32l0xx_hal.h"
|
||||
#elif __has_include("stm32l1xx_hal.h")
|
||||
#include "stm32l1xx_hal.h"
|
||||
#elif __has_include("stm32l4xx_hal.h")
|
||||
#include "stm32l4xx_hal.h"
|
||||
#elif __has_include("stm32l5xx_hal.h")
|
||||
#include "stm32l5xx_hal.h"
|
||||
#endif
|
||||
|
||||
#if !defined(HAL_PCD_MODULE_ENABLED)
|
||||
#error please define HAL_PCD_MODULE_ENABLED in stm32xxx_hal_conf.h
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_USBDEV_FSDEV_PMA_ACCESS
|
||||
#error "please define CONFIG_USBDEV_FSDEV_PMA_ACCESS in usb_config.h"
|
||||
#endif
|
||||
|
||||
#if CONFIG_USBDEV_FSDEV_PMA_ACCESS != PMA_ACCESS
|
||||
#error "CONFIG_USBDEV_FSDEV_PMA_ACCESS must be equal PMA_ACCESS"
|
||||
#endif
|
||||
|
||||
struct fsdev_instance {
|
||||
USB_TypeDef *Instance;
|
||||
};
|
||||
|
||||
static struct fsdev_instance g_fsdev_instance;
|
||||
|
||||
void usb_dc_low_level_init(uint8_t busid)
|
||||
{
|
||||
g_fsdev_instance.Instance = (USB_TypeDef *)g_usbdev_bus[busid].reg_base;
|
||||
HAL_PCD_MspInit((PCD_HandleTypeDef *)&g_fsdev_instance);
|
||||
}
|
||||
|
||||
void usb_dc_low_level_deinit(uint8_t busid)
|
||||
{
|
||||
g_fsdev_instance.Instance = (USB_TypeDef *)g_usbdev_bus[busid].reg_base;
|
||||
HAL_PCD_MspDeInit((PCD_HandleTypeDef *)&g_fsdev_instance);
|
||||
}
|
||||
|
||||
void USB_IRQHandler(void)
|
||||
{
|
||||
USBD_IRQHandler(0);
|
||||
}
|
||||
|
||||
void USB_LP_IRQHandler(void)
|
||||
{
|
||||
USBD_IRQHandler(0);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
# Note
|
||||
|
||||
## Support Chip List
|
||||
|
||||
- HPM all series (HPMicro + EHCI)
|
||||
@@ -0,0 +1,379 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2025 HPMicro
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
#include "usbd_core.h"
|
||||
#include "hpm_usb_device.h"
|
||||
#include "usb_glue_hpm.h"
|
||||
|
||||
#define USB_NUM_BIDIR_ENDPOINTS USB_SOC_DCD_MAX_ENDPOINT_COUNT
|
||||
|
||||
/* USBSTS, USBINTR */
|
||||
enum {
|
||||
intr_usb = USB_USBINTR_UE_MASK,
|
||||
intr_error = USB_USBINTR_UEE_MASK,
|
||||
intr_port_change = USB_USBINTR_PCE_MASK,
|
||||
intr_reset = USB_USBINTR_URE_MASK,
|
||||
intr_sof = USB_USBINTR_SRE_MASK,
|
||||
intr_suspend = USB_USBINTR_SLE_MASK,
|
||||
intr_nak = USB_USBINTR_NAKE_MASK,
|
||||
};
|
||||
|
||||
/* Endpoint state */
|
||||
struct hpm_ep_state {
|
||||
uint16_t ep_mps; /* Endpoint max packet size */
|
||||
uint8_t ep_type; /* Endpoint type */
|
||||
uint8_t ep_stalled; /* Endpoint stall flag */
|
||||
uint8_t ep_enable; /* Endpoint enable */
|
||||
uint8_t *xfer_buf;
|
||||
uint32_t xfer_len;
|
||||
uint32_t actual_xfer_len;
|
||||
};
|
||||
|
||||
/*---------------------------------------------------------------------*
|
||||
* Variable Definitions
|
||||
*---------------------------------------------------------------------*/
|
||||
/* Driver state */
|
||||
struct hpm_udc {
|
||||
usb_device_handle_t *handle;
|
||||
bool is_suspend;
|
||||
struct hpm_ep_state in_ep[USB_NUM_BIDIR_ENDPOINTS]; /*!< IN endpoint parameters*/
|
||||
struct hpm_ep_state out_ep[USB_NUM_BIDIR_ENDPOINTS]; /*!< OUT endpoint parameters */
|
||||
} g_hpm_udc[CONFIG_USBDEV_MAX_BUS];
|
||||
|
||||
static USB_NOCACHE_RAM_SECTION ATTR_ALIGN(USB_SOC_DCD_DATA_RAM_ADDRESS_ALIGNMENT)
|
||||
uint8_t _dcd_data[CONFIG_USBDEV_MAX_BUS][HPM_ALIGN_UP(sizeof(dcd_data_t), USB_SOC_DCD_DATA_RAM_ADDRESS_ALIGNMENT)];
|
||||
static USB_NOCACHE_RAM_SECTION usb_device_handle_t usb_device_handle[CONFIG_USBDEV_MAX_BUS];
|
||||
|
||||
/* Index to bit position in register */
|
||||
static inline uint8_t ep_idx2bit(uint8_t ep_idx)
|
||||
{
|
||||
return ep_idx / 2 + ((ep_idx % 2) ? 16 : 0);
|
||||
}
|
||||
|
||||
static void usb_dc_isr_connect(uint8_t busid)
|
||||
{
|
||||
if (g_usbdev_bus[busid].reg_base == HPM_USB0_BASE) {
|
||||
g_usb_hpm_busid[0] = busid;
|
||||
g_usb_hpm_irq[0] = USBD_IRQHandler;
|
||||
|
||||
hpm_usb_isr_enable(HPM_USB0_BASE);
|
||||
} else {
|
||||
#ifdef HPM_USB1_BASE
|
||||
g_usb_hpm_busid[1] = busid;
|
||||
g_usb_hpm_irq[1] = USBD_IRQHandler;
|
||||
|
||||
hpm_usb_isr_enable(HPM_USB1_BASE);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static void usb_dc_isr_disconnect(uint8_t busid)
|
||||
{
|
||||
if (g_usbdev_bus[busid].reg_base == HPM_USB0_BASE) {
|
||||
hpm_usb_isr_disable(HPM_USB0_BASE);
|
||||
|
||||
g_usb_hpm_busid[0] = 0;
|
||||
g_usb_hpm_irq[0] = NULL;
|
||||
} else {
|
||||
#ifdef HPM_USB1_BASE
|
||||
hpm_usb_isr_disable(HPM_USB1_BASE);
|
||||
|
||||
g_usb_hpm_busid[1] = 0;
|
||||
g_usb_hpm_irq[1] = NULL;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
int usb_dc_init(uint8_t busid)
|
||||
{
|
||||
memset(&g_hpm_udc[busid], 0, sizeof(struct hpm_udc));
|
||||
g_hpm_udc[busid].handle = &usb_device_handle[busid];
|
||||
g_hpm_udc[busid].handle->regs = (USB_Type *)g_usbdev_bus[busid].reg_base;
|
||||
g_hpm_udc[busid].handle->dcd_data = (dcd_data_t *)&_dcd_data[busid][0];
|
||||
|
||||
uint32_t int_mask;
|
||||
int_mask = (intr_usb | intr_error |intr_port_change | intr_reset | intr_suspend);
|
||||
|
||||
#ifdef CONFIG_USBDEV_SOF_ENABLE
|
||||
int_mask |= intr_sof;
|
||||
#endif
|
||||
|
||||
usb_device_init(g_hpm_udc[busid].handle, int_mask);
|
||||
|
||||
usb_dc_isr_connect(busid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_dc_deinit(uint8_t busid)
|
||||
{
|
||||
usb_dc_isr_disconnect(busid);
|
||||
|
||||
usb_device_deinit(g_hpm_udc[busid].handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_set_address(uint8_t busid, const uint8_t addr)
|
||||
{
|
||||
usb_device_handle_t *handle = g_hpm_udc[busid].handle;
|
||||
usb_dcd_set_address(handle->regs, addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_set_remote_wakeup(uint8_t busid)
|
||||
{
|
||||
USB_Type *ptr;
|
||||
|
||||
ptr = g_hpm_udc[busid].handle->regs;
|
||||
|
||||
if (!usb_get_suspend_status(ptr)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
usb_force_port_resume(ptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void usbd_execute_test_mode(uint8_t busid, uint8_t test_mode)
|
||||
{
|
||||
usb_set_port_test_mode(g_hpm_udc[busid].handle->regs, test_mode);
|
||||
}
|
||||
|
||||
uint8_t usbd_get_port_speed(uint8_t busid)
|
||||
{
|
||||
uint8_t speed;
|
||||
|
||||
speed = usb_get_port_speed(g_hpm_udc[busid].handle->regs);
|
||||
|
||||
if (speed == 0x00) {
|
||||
return USB_SPEED_FULL;
|
||||
}
|
||||
if (speed == 0x01) {
|
||||
return USB_SPEED_LOW;
|
||||
}
|
||||
if (speed == 0x02) {
|
||||
return USB_SPEED_HIGH;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_open(uint8_t busid, const struct usb_endpoint_descriptor *ep)
|
||||
{
|
||||
usb_endpoint_config_t tmp_ep_cfg;
|
||||
usb_device_handle_t *handle = g_hpm_udc[busid].handle;
|
||||
uint8_t ep_idx = USB_EP_GET_IDX(ep->bEndpointAddress);
|
||||
|
||||
tmp_ep_cfg.xfer = USB_GET_ENDPOINT_TYPE(ep->bmAttributes);
|
||||
tmp_ep_cfg.ep_addr = ep->bEndpointAddress;
|
||||
tmp_ep_cfg.max_packet_size = ep->wMaxPacketSize;
|
||||
|
||||
usb_device_edpt_open(handle, &tmp_ep_cfg);
|
||||
|
||||
if (USB_EP_DIR_IS_OUT(ep->bEndpointAddress)) {
|
||||
g_hpm_udc[busid].out_ep[ep_idx].ep_mps = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
|
||||
g_hpm_udc[busid].out_ep[ep_idx].ep_type = USB_GET_ENDPOINT_TYPE(ep->bmAttributes);
|
||||
g_hpm_udc[busid].out_ep[ep_idx].ep_enable = true;
|
||||
} else {
|
||||
g_hpm_udc[busid].in_ep[ep_idx].ep_mps = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
|
||||
g_hpm_udc[busid].in_ep[ep_idx].ep_type = USB_GET_ENDPOINT_TYPE(ep->bmAttributes);
|
||||
g_hpm_udc[busid].in_ep[ep_idx].ep_enable = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_close(uint8_t busid, const uint8_t ep)
|
||||
{
|
||||
usb_device_handle_t *handle = g_hpm_udc[busid].handle;
|
||||
uint8_t ep_idx = USB_EP_GET_IDX(ep);
|
||||
|
||||
if (USB_EP_DIR_IS_OUT(ep)) {
|
||||
g_hpm_udc[busid].out_ep[ep_idx].ep_enable = false;
|
||||
} else {
|
||||
g_hpm_udc[busid].in_ep[ep_idx].ep_enable = false;
|
||||
}
|
||||
|
||||
usb_device_edpt_close(handle, ep);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_set_stall(uint8_t busid, const uint8_t ep)
|
||||
{
|
||||
usb_device_handle_t *handle = g_hpm_udc[busid].handle;
|
||||
|
||||
usb_device_edpt_stall(handle, ep);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_clear_stall(uint8_t busid, const uint8_t ep)
|
||||
{
|
||||
usb_device_handle_t *handle = g_hpm_udc[busid].handle;
|
||||
|
||||
usb_device_edpt_clear_stall(handle, ep);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_is_stalled(uint8_t busid, const uint8_t ep, uint8_t *stalled)
|
||||
{
|
||||
usb_device_handle_t *handle = g_hpm_udc[busid].handle;
|
||||
|
||||
*stalled = usb_device_edpt_check_stall(handle, ep);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_start_write(uint8_t busid, const uint8_t ep, const uint8_t *data, uint32_t data_len)
|
||||
{
|
||||
uint8_t ep_idx = USB_EP_GET_IDX(ep);
|
||||
usb_device_handle_t *handle = g_hpm_udc[busid].handle;
|
||||
|
||||
if (!data && data_len) {
|
||||
return -1;
|
||||
}
|
||||
if (!g_hpm_udc[busid].in_ep[ep_idx].ep_enable) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
g_hpm_udc[busid].in_ep[ep_idx].xfer_buf = (uint8_t *)data;
|
||||
g_hpm_udc[busid].in_ep[ep_idx].xfer_len = data_len;
|
||||
g_hpm_udc[busid].in_ep[ep_idx].actual_xfer_len = 0;
|
||||
|
||||
usb_device_edpt_xfer(handle, ep, (uint8_t *)data, data_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_start_read(uint8_t busid, const uint8_t ep, uint8_t *data, uint32_t data_len)
|
||||
{
|
||||
uint8_t ep_idx = USB_EP_GET_IDX(ep);
|
||||
usb_device_handle_t *handle = g_hpm_udc[busid].handle;
|
||||
|
||||
if (!data && data_len) {
|
||||
return -1;
|
||||
}
|
||||
if (!g_hpm_udc[busid].out_ep[ep_idx].ep_enable) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
g_hpm_udc[busid].out_ep[ep_idx].xfer_buf = (uint8_t *)data;
|
||||
g_hpm_udc[busid].out_ep[ep_idx].xfer_len = data_len;
|
||||
g_hpm_udc[busid].out_ep[ep_idx].actual_xfer_len = 0;
|
||||
|
||||
usb_device_edpt_xfer(handle, ep, data, data_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void USBD_IRQHandler(uint8_t busid)
|
||||
{
|
||||
uint32_t int_status;
|
||||
usb_device_handle_t *handle = g_hpm_udc[busid].handle;
|
||||
uint32_t transfer_len;
|
||||
bool ep_cb_req;
|
||||
|
||||
/* Acknowledge handled interrupt */
|
||||
int_status = usb_device_status_flags(handle);
|
||||
int_status &= usb_device_interrupts(handle);
|
||||
usb_device_clear_status_flags(handle, int_status);
|
||||
|
||||
if (int_status & intr_error) {
|
||||
USB_LOG_ERR("usbd intr error!\r\n");
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USBDEV_SOF_ENABLE
|
||||
if (int_status & intr_sof) {
|
||||
usbd_event_sof_handler(busid);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (int_status & intr_reset) {
|
||||
g_hpm_udc[busid].is_suspend = false;
|
||||
memset(g_hpm_udc[busid].in_ep, 0, sizeof(struct hpm_ep_state) * USB_NUM_BIDIR_ENDPOINTS);
|
||||
memset(g_hpm_udc[busid].out_ep, 0, sizeof(struct hpm_ep_state) * USB_NUM_BIDIR_ENDPOINTS);
|
||||
usbd_event_reset_handler(busid);
|
||||
usb_device_bus_reset(handle, 64);
|
||||
}
|
||||
|
||||
if (int_status & intr_suspend) {
|
||||
if (usb_device_get_suspend_status(handle)) {
|
||||
/* Note: Host may delay more than 3 ms before and/or after bus reset before doing enumeration. */
|
||||
if (usb_device_get_address(handle)) {
|
||||
g_hpm_udc[busid].is_suspend = true;
|
||||
usbd_event_suspend_handler(busid);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
}
|
||||
|
||||
if (int_status & intr_port_change) {
|
||||
if (!usb_device_get_port_ccs(handle)) {
|
||||
usbd_event_disconnect_handler(busid);
|
||||
} else {
|
||||
if (g_hpm_udc[busid].is_suspend) {
|
||||
g_hpm_udc[busid].is_suspend = false;
|
||||
usbd_event_resume_handler(busid);
|
||||
}
|
||||
usbd_event_connect_handler(busid);
|
||||
}
|
||||
}
|
||||
|
||||
if (int_status & intr_usb) {
|
||||
uint32_t const edpt_complete = usb_device_get_edpt_complete_status(handle);
|
||||
uint32_t const edpt_setup_status = usb_device_get_setup_status(handle);
|
||||
|
||||
if (edpt_complete) {
|
||||
usb_device_clear_edpt_complete_status(handle, edpt_complete);
|
||||
for (uint8_t ep_idx = 0; ep_idx < USB_SOS_DCD_MAX_QHD_COUNT; ep_idx++) {
|
||||
if (edpt_complete & (1 << ep_idx2bit(ep_idx))) {
|
||||
transfer_len = 0;
|
||||
ep_cb_req = true;
|
||||
|
||||
/* Failed QTD also get ENDPTCOMPLETE set */
|
||||
dcd_qhd_t *p_qhd = usb_device_qhd_get(handle, ep_idx);
|
||||
dcd_qtd_t *p_qtd = p_qhd->attached_qtd;
|
||||
while (1) {
|
||||
if (p_qtd->halted || p_qtd->xact_err || p_qtd->buffer_err) {
|
||||
USB_LOG_ERR("usbd transfer error!\r\n");
|
||||
ep_cb_req = false;
|
||||
break;
|
||||
} else if (p_qtd->active) {
|
||||
ep_cb_req = false;
|
||||
break;
|
||||
} else {
|
||||
transfer_len += p_qtd->expected_bytes - p_qtd->total_bytes;
|
||||
p_qtd->in_use = false;
|
||||
}
|
||||
|
||||
if (p_qtd->next == USB_SOC_DCD_QTD_NEXT_INVALID) {
|
||||
break;
|
||||
} else {
|
||||
p_qtd = (dcd_qtd_t *)p_qtd->next;
|
||||
}
|
||||
}
|
||||
|
||||
if (ep_cb_req) {
|
||||
uint8_t const ep_addr = (ep_idx / 2) | ((ep_idx & 0x01) ? 0x80 : 0);
|
||||
if (ep_addr & 0x80) {
|
||||
usbd_event_ep_in_complete_handler(busid, ep_addr, transfer_len);
|
||||
} else {
|
||||
usbd_event_ep_out_complete_handler(busid, ep_addr, transfer_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (edpt_setup_status) {
|
||||
/*------------- Set up Received -------------*/
|
||||
usb_device_clear_setup_status(handle, edpt_setup_status);
|
||||
dcd_qhd_t *qhd0 = usb_device_qhd_get(handle, 0);
|
||||
usbd_event_ep0_setup_complete_handler(busid, (uint8_t *)&qhd0->setup_request);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2025 HPMicro
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
#include "hpm_common.h"
|
||||
#include "hpm_soc.h"
|
||||
#include "hpm_l1c_drv.h"
|
||||
#include "usb_config.h"
|
||||
|
||||
void (*g_usb_hpm_irq[2])(uint8_t busid);
|
||||
uint8_t g_usb_hpm_busid[2];
|
||||
|
||||
ATTR_WEAK void hpm_usb_isr_enable(uint32_t base)
|
||||
{
|
||||
if (base == HPM_USB0_BASE) {
|
||||
intc_m_enable_irq(IRQn_USB0);
|
||||
} else {
|
||||
#ifdef HPM_USB1_BASE
|
||||
intc_m_enable_irq(IRQn_USB1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
ATTR_WEAK void hpm_usb_isr_disable(uint32_t base)
|
||||
{
|
||||
if (base == HPM_USB0_BASE) {
|
||||
intc_m_disable_irq(IRQn_USB0);
|
||||
} else {
|
||||
#ifdef HPM_USB1_BASE
|
||||
intc_m_disable_irq(IRQn_USB1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef CONFIG_CHERRYUSB_CUSTOM_IRQ_HANDLER
|
||||
SDK_DECLARE_EXT_ISR_M(IRQn_USB0, hpm_isr_usb0)
|
||||
#endif
|
||||
void hpm_isr_usb0(void)
|
||||
{
|
||||
g_usb_hpm_irq[0](g_usb_hpm_busid[0]);
|
||||
}
|
||||
|
||||
#ifdef HPM_USB1_BASE
|
||||
#ifndef CONFIG_CHERRYUSB_CUSTOM_IRQ_HANDLER
|
||||
SDK_DECLARE_EXT_ISR_M(IRQn_USB1, hpm_isr_usb1)
|
||||
#endif
|
||||
void hpm_isr_usb1(void)
|
||||
{
|
||||
g_usb_hpm_irq[1](g_usb_hpm_busid[1]);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_DCACHE_ENABLE
|
||||
void usb_dcache_clean(uintptr_t addr, size_t size)
|
||||
{
|
||||
l1c_dc_writeback(addr, size);
|
||||
}
|
||||
|
||||
void usb_dcache_invalidate(uintptr_t addr, size_t size)
|
||||
{
|
||||
l1c_dc_invalidate(addr, size);
|
||||
}
|
||||
|
||||
void usb_dcache_flush(uintptr_t addr, size_t size)
|
||||
{
|
||||
l1c_dc_flush(addr, size);
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2025 HPMicro
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _HPM_USB_GLUE_HPM_H_
|
||||
#define _HPM_USB_GLUE_HPM_H_
|
||||
|
||||
extern void (*g_usb_hpm_irq[2])(uint8_t busid);
|
||||
extern uint8_t g_usb_hpm_busid[2];
|
||||
|
||||
void hpm_usb_isr_enable(uint32_t base);
|
||||
void hpm_usb_isr_disable(uint32_t base);
|
||||
void hpm_isr_usb0(void);
|
||||
void hpm_isr_usb1(void);
|
||||
|
||||
#endif /* _HPM_USB_GLUE_HPM_H_ */
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2025 HPMicro
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
#include "usbh_core.h"
|
||||
#include "hpm_common.h"
|
||||
#include "hpm_soc.h"
|
||||
#include "hpm_usb_drv.h"
|
||||
#include "usb_glue_hpm.h"
|
||||
|
||||
#if !defined(CONFIG_USB_EHCI_HPMICRO) || !CONFIG_USB_EHCI_HPMICRO
|
||||
#error "hpm ehci must set CONFIG_USB_EHCI_HPMICRO=1"
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_USB_EHCI_HCCR_OFFSET) || CONFIG_USB_EHCI_HCCR_OFFSET != 0x100
|
||||
#error "hpm ehci must config CONFIG_USB_EHCI_HCCR_OFFSET to 0x100"
|
||||
#endif
|
||||
|
||||
extern void (*g_usb_hpm_irq[2])(uint8_t busid);
|
||||
extern uint8_t g_usb_hpm_busid[2];
|
||||
|
||||
static void usb_host_mode_init(USB_Type *ptr)
|
||||
{
|
||||
/* Set mode to host, must be set immediately after reset */
|
||||
ptr->USBMODE &= ~USB_USBMODE_CM_MASK;
|
||||
ptr->USBMODE |= USB_USBMODE_CM_SET(3);
|
||||
|
||||
/* Set the endian */
|
||||
ptr->USBMODE &= ~USB_USBMODE_ES_MASK;
|
||||
|
||||
/* Set parallel interface signal */
|
||||
ptr->PORTSC1 &= ~USB_PORTSC1_STS_MASK;
|
||||
|
||||
/* Set parallel transceiver width */
|
||||
ptr->PORTSC1 &= ~USB_PORTSC1_PTW_MASK;
|
||||
|
||||
#ifdef CONFIG_USB_HOST_FORCE_FULL_SPEED
|
||||
/* Set usb forced to full speed mode */
|
||||
ptr->PORTSC1 |= USB_PORTSC1_PFSC_MASK;
|
||||
#endif
|
||||
|
||||
/* Not use interrupt threshold. */
|
||||
ptr->USBCMD &= ~USB_USBCMD_ITC_MASK;
|
||||
}
|
||||
|
||||
void usb_hc_low_level_init(struct usbh_bus *bus)
|
||||
{
|
||||
usb_phy_init((USB_Type *)(bus->hcd.reg_base), true);
|
||||
}
|
||||
|
||||
void usb_hc_low_level2_init(struct usbh_bus *bus)
|
||||
{
|
||||
usb_host_mode_init((USB_Type *)(bus->hcd.reg_base));
|
||||
|
||||
if (bus->hcd.reg_base == HPM_USB0_BASE) {
|
||||
g_usb_hpm_busid[0] = bus->hcd.hcd_id;
|
||||
g_usb_hpm_irq[0] = USBH_IRQHandler;
|
||||
|
||||
hpm_usb_isr_enable(HPM_USB0_BASE);
|
||||
} else {
|
||||
#ifdef HPM_USB1_BASE
|
||||
g_usb_hpm_busid[1] = bus->hcd.hcd_id;
|
||||
g_usb_hpm_irq[1] = USBH_IRQHandler;
|
||||
|
||||
hpm_usb_isr_enable(HPM_USB1_BASE);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void usb_hc_low_level_deinit(struct usbh_bus *bus)
|
||||
{
|
||||
usb_phy_deinit((USB_Type *)(bus->hcd.reg_base));
|
||||
|
||||
if (bus->hcd.reg_base == HPM_USB0_BASE) {
|
||||
hpm_usb_isr_disable(HPM_USB0_BASE);
|
||||
|
||||
g_usb_hpm_busid[0] = 0;
|
||||
g_usb_hpm_irq[0] = NULL;
|
||||
} else {
|
||||
#ifdef HPM_USB1_BASE
|
||||
hpm_usb_isr_disable(HPM_USB1_BASE);
|
||||
|
||||
g_usb_hpm_busid[1] = 0;
|
||||
g_usb_hpm_irq[1] = NULL;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t usbh_get_port_speed(struct usbh_bus *bus, const uint8_t port)
|
||||
{
|
||||
(void)port;
|
||||
uint8_t speed;
|
||||
|
||||
speed = usb_get_port_speed((USB_Type *)(bus->hcd.reg_base));
|
||||
|
||||
if (speed == 0x00) {
|
||||
return USB_SPEED_FULL;
|
||||
}
|
||||
if (speed == 0x01) {
|
||||
return USB_SPEED_LOW;
|
||||
}
|
||||
if (speed == 0x02) {
|
||||
return USB_SPEED_HIGH;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
# Note
|
||||
|
||||
## Support Chip List
|
||||
|
||||
### NXP
|
||||
|
||||
Modify USB_NOCACHE_RAM_SECTION
|
||||
|
||||
```
|
||||
#define USB_NOCACHE_RAM_SECTION __attribute__((section(".NonCacheable")))
|
||||
```
|
||||
|
||||
- MCXC444/MCXA153/MCXA156 (device only)
|
||||
- MCXN947
|
||||
|
||||
### MM32
|
||||
|
||||
- MM32F3/MM32F5
|
||||
@@ -0,0 +1,463 @@
|
||||
/*
|
||||
* Copyright (c) 2024, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usbd_core.h"
|
||||
#include "usb_kinetis_reg.h"
|
||||
|
||||
#undef CONFIG_USBDEV_EP_NUM
|
||||
#define CONFIG_USBDEV_EP_NUM 16
|
||||
|
||||
#define USB_OTG_DEV ((KINETIS_TypeDef *)g_usbdev_bus[busid].reg_base)
|
||||
|
||||
/* Endpoint state */
|
||||
struct kinetis_ep_state {
|
||||
uint16_t ep_mps; /* Endpoint max packet size */
|
||||
uint8_t ep_type; /* Endpoint type */
|
||||
uint8_t ep_stalled; /* Endpoint stall flag */
|
||||
uint8_t ep_enable; /* Endpoint enable */
|
||||
bool ep_odd; /* Endpoint odd */
|
||||
uint8_t *xfer_buf;
|
||||
uint32_t xfer_len;
|
||||
uint32_t actual_xfer_len;
|
||||
};
|
||||
|
||||
/* Driver state */
|
||||
struct kinetis_udc {
|
||||
uint8_t dev_addr;
|
||||
struct kinetis_ep_state in_ep[CONFIG_USBDEV_EP_NUM]; /*!< IN endpoint parameters*/
|
||||
struct kinetis_ep_state out_ep[CONFIG_USBDEV_EP_NUM]; /*!< OUT endpoint parameters */
|
||||
} g_kinetis_udc[CONFIG_USBDEV_MAX_BUS];
|
||||
|
||||
USB_NOCACHE_RAM_SECTION __attribute__((aligned(512))) kinetis_bd_table_t g_kinetis_bdt[CONFIG_USBDEV_MAX_BUS];
|
||||
USB_NOCACHE_RAM_SECTION __attribute__((aligned(32))) uint8_t setup_packet[CONFIG_USBDEV_MAX_BUS][8];
|
||||
|
||||
static int kinetis_start_transfer(uint8_t busid, uint8_t ep, uint8_t *buffer, uint16_t buflen)
|
||||
{
|
||||
uint8_t ep_idx = USB_EP_GET_IDX(ep);
|
||||
uint8_t dir;
|
||||
uint8_t odd;
|
||||
uint16_t ep_mps;
|
||||
kinetis_bd_t *bd;
|
||||
kinetis_bd_t *next;
|
||||
|
||||
if (USB_EP_DIR_IS_OUT(ep)) {
|
||||
dir = 0;
|
||||
odd = g_kinetis_udc[busid].out_ep[ep_idx].ep_odd;
|
||||
ep_mps = g_kinetis_udc[busid].out_ep[ep_idx].ep_mps;
|
||||
} else {
|
||||
dir = 1;
|
||||
odd = g_kinetis_udc[busid].in_ep[ep_idx].ep_odd;
|
||||
ep_mps = g_kinetis_udc[busid].in_ep[ep_idx].ep_mps;
|
||||
}
|
||||
|
||||
bd = &g_kinetis_bdt[busid].table[ep_idx][dir][odd];
|
||||
|
||||
if (bd->own) {
|
||||
USB_LOG_INFO("ep%02x is busy\r\n", ep);
|
||||
return -1;
|
||||
}
|
||||
|
||||
bd->bc = buflen >= ep_mps ? ep_mps : buflen;
|
||||
bd->addr = (uint32_t)buffer;
|
||||
bd->own = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void kinetis_read_setup(uint8_t busid)
|
||||
{
|
||||
uint8_t out_odd = g_kinetis_udc[busid].out_ep[0].ep_odd;
|
||||
uint8_t in_odd = g_kinetis_udc[busid].in_ep[0].ep_odd;
|
||||
|
||||
if (g_kinetis_bdt[busid].table[0][0][out_odd].own) {
|
||||
USB_LOG_INFO("ep0 is busy\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
g_kinetis_bdt[busid].table[0][0][out_odd].data = 0;
|
||||
g_kinetis_bdt[busid].table[0][0][out_odd ^ 1].data = 1;
|
||||
g_kinetis_bdt[busid].table[0][1][in_odd].data = 1;
|
||||
g_kinetis_bdt[busid].table[0][1][in_odd ^ 1].data = 0;
|
||||
|
||||
kinetis_start_transfer(busid, USB_CONTROL_OUT_EP0, setup_packet[busid], 8);
|
||||
}
|
||||
|
||||
__WEAK void usb_dc_low_level_init(uint8_t busid)
|
||||
{
|
||||
}
|
||||
|
||||
__WEAK void usb_dc_low_level_deinit(uint8_t busid)
|
||||
{
|
||||
}
|
||||
|
||||
int usb_dc_init(uint8_t busid)
|
||||
{
|
||||
usb_dc_low_level_init(busid);
|
||||
|
||||
memset(&g_kinetis_udc[busid], 0, sizeof(g_kinetis_udc[busid]));
|
||||
|
||||
USB_OTG_DEV->BDTPAGE1 = (uint8_t)((uintptr_t)&g_kinetis_bdt[busid] >> 8);
|
||||
USB_OTG_DEV->BDTPAGE2 = (uint8_t)((uintptr_t)&g_kinetis_bdt[busid] >> 16);
|
||||
USB_OTG_DEV->BDTPAGE3 = (uint8_t)((uintptr_t)&g_kinetis_bdt[busid] >> 24);
|
||||
|
||||
USB_OTG_DEV->INTEN = USB_INTEN_USBRSTEN_MASK | USB_INTEN_TOKDNEEN_MASK |
|
||||
USB_INTEN_SLEEPEN_MASK | USB_INTEN_RESUMEEN_MASK |
|
||||
USB_INTEN_ERROREN_MASK;
|
||||
|
||||
#ifdef CONFIG_USBDEV_SOF_ENABLE
|
||||
USB_OTG_DEV->INTEN |= USB_INTEN_SOFTOKEN_MASK;
|
||||
#endif
|
||||
|
||||
USB_OTG_DEV->CTL |= USB_CTL_USBENSOFEN_MASK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_dc_deinit(uint8_t busid)
|
||||
{
|
||||
USB_OTG_DEV->INTEN = 0;
|
||||
USB_OTG_DEV->CTL &= ~USB_CTL_USBENSOFEN_MASK;
|
||||
|
||||
memset(&g_kinetis_udc[busid], 0, sizeof(g_kinetis_udc[busid]));
|
||||
|
||||
USB_OTG_DEV->BDTPAGE1 = (uint8_t)((uintptr_t)&g_kinetis_bdt[busid] >> 8);
|
||||
USB_OTG_DEV->BDTPAGE2 = (uint8_t)((uintptr_t)&g_kinetis_bdt[busid] >> 16);
|
||||
USB_OTG_DEV->BDTPAGE3 = (uint8_t)((uintptr_t)&g_kinetis_bdt[busid] >> 24);
|
||||
|
||||
usb_dc_low_level_deinit(busid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_set_address(uint8_t busid, const uint8_t addr)
|
||||
{
|
||||
g_kinetis_udc[busid].dev_addr = addr;
|
||||
|
||||
if (addr == 0) {
|
||||
USB_OTG_DEV->ADDR = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_set_remote_wakeup(uint8_t busid)
|
||||
{
|
||||
USB_OTG_DEV->CTL |= USB_CTL_RESUME_MASK;
|
||||
|
||||
usbd_kinetis_delay_ms(10);
|
||||
|
||||
USB_OTG_DEV->CTL &= ~USB_CTL_RESUME_MASK;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t usbd_get_port_speed(uint8_t busid)
|
||||
{
|
||||
return USB_SPEED_FULL;
|
||||
}
|
||||
|
||||
int usbd_ep_open(uint8_t busid, const struct usb_endpoint_descriptor *ep)
|
||||
{
|
||||
uint8_t ep_idx = USB_EP_GET_IDX(ep->bEndpointAddress);
|
||||
uint8_t odd;
|
||||
uint8_t dir;
|
||||
kinetis_bd_t *bd;
|
||||
uint8_t regval;
|
||||
|
||||
/* Must not exceed max endpoint number */
|
||||
USB_ASSERT_MSG(ep_idx < CONFIG_USBDEV_EP_NUM, "Ep addr %02x overflow", ep->bEndpointAddress);
|
||||
|
||||
if (USB_EP_DIR_IS_OUT(ep->bEndpointAddress)) {
|
||||
g_kinetis_udc[busid].out_ep[ep_idx].ep_mps = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
|
||||
g_kinetis_udc[busid].out_ep[ep_idx].ep_type = USB_GET_ENDPOINT_TYPE(ep->bmAttributes);
|
||||
g_kinetis_udc[busid].out_ep[ep_idx].ep_enable = true;
|
||||
|
||||
dir = 0;
|
||||
odd = g_kinetis_udc[busid].out_ep[ep_idx].ep_odd;
|
||||
} else {
|
||||
g_kinetis_udc[busid].in_ep[ep_idx].ep_mps = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
|
||||
g_kinetis_udc[busid].in_ep[ep_idx].ep_type = USB_GET_ENDPOINT_TYPE(ep->bmAttributes);
|
||||
g_kinetis_udc[busid].in_ep[ep_idx].ep_enable = true;
|
||||
|
||||
dir = 1;
|
||||
odd = g_kinetis_udc[busid].in_ep[ep_idx].ep_odd;
|
||||
}
|
||||
|
||||
if (ep_idx != 0) {
|
||||
regval = USB_ENDPT_EPCTLDIS_MASK;
|
||||
regval |= (USB_GET_ENDPOINT_TYPE(ep->bmAttributes) != USB_ENDPOINT_TYPE_ISOCHRONOUS) ? USB_ENDPT_EPHSHK_MASK : 0;
|
||||
regval |= dir ? USB_ENDPT_EPTXEN_MASK : USB_ENDPT_EPRXEN_MASK;
|
||||
USB_OTG_DEV->ENDPOINT[ep_idx].ENDPT |= regval;
|
||||
|
||||
if (USB_GET_ENDPOINT_TYPE(ep->bmAttributes) != USB_ENDPOINT_TYPE_ISOCHRONOUS) {
|
||||
bd = &g_kinetis_bdt[busid].table[ep_idx][dir][odd];
|
||||
bd->dts = 1;
|
||||
bd->data = 0;
|
||||
|
||||
bd = &g_kinetis_bdt[busid].table[ep_idx][dir][odd ^ 1];
|
||||
bd->dts = 1;
|
||||
bd->data = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_close(uint8_t busid, const uint8_t ep)
|
||||
{
|
||||
uint8_t ep_idx = USB_EP_GET_IDX(ep);
|
||||
uint8_t dir;
|
||||
kinetis_bd_t *bd;
|
||||
|
||||
if (USB_EP_DIR_IS_OUT(ep)) {
|
||||
g_kinetis_udc[busid].out_ep[ep_idx].ep_enable = false;
|
||||
dir = 0;
|
||||
} else {
|
||||
g_kinetis_udc[busid].in_ep[ep_idx].ep_enable = false;
|
||||
dir = 1;
|
||||
}
|
||||
|
||||
bd = &g_kinetis_bdt[busid].table[ep_idx][dir][0];
|
||||
bd->head = 0;
|
||||
|
||||
bd = &g_kinetis_bdt[busid].table[ep_idx][dir][1];
|
||||
bd->head = 0;
|
||||
|
||||
USB_OTG_DEV->ENDPOINT[ep_idx].ENDPT &= ~(dir ? USB_ENDPT_EPTXEN_MASK : USB_ENDPT_EPRXEN_MASK);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_set_stall(uint8_t busid, const uint8_t ep)
|
||||
{
|
||||
uint8_t ep_idx = USB_EP_GET_IDX(ep);
|
||||
kinetis_bd_t *bd;
|
||||
uint8_t odd;
|
||||
uint8_t dir;
|
||||
|
||||
if (0 == ep_idx) {
|
||||
USB_OTG_DEV->ENDPOINT[ep_idx].ENDPT |= USB_ENDPT_EPSTALL_MASK;
|
||||
|
||||
if (ep_idx == 0) {
|
||||
kinetis_read_setup(busid);
|
||||
}
|
||||
} else {
|
||||
if (USB_EP_DIR_IS_OUT(ep)) {
|
||||
dir = 0;
|
||||
odd = g_kinetis_udc[busid].out_ep[ep_idx].ep_odd;
|
||||
} else {
|
||||
dir = 1;
|
||||
odd = g_kinetis_udc[busid].in_ep[ep_idx].ep_odd;
|
||||
}
|
||||
|
||||
bd = &g_kinetis_bdt[busid].table[ep_idx][dir][odd];
|
||||
|
||||
bd->bdt_stall = 1;
|
||||
bd->own = 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_clear_stall(uint8_t busid, const uint8_t ep)
|
||||
{
|
||||
uint8_t ep_idx = USB_EP_GET_IDX(ep);
|
||||
kinetis_bd_t *bd;
|
||||
uint8_t odd;
|
||||
uint8_t dir;
|
||||
|
||||
if (USB_EP_DIR_IS_OUT(ep)) {
|
||||
dir = 0;
|
||||
odd = g_kinetis_udc[busid].out_ep[ep_idx].ep_odd;
|
||||
} else {
|
||||
dir = 1;
|
||||
odd = g_kinetis_udc[busid].in_ep[ep_idx].ep_odd;
|
||||
}
|
||||
|
||||
bd = &g_kinetis_bdt[busid].table[ep_idx][dir][odd];
|
||||
|
||||
bd->own = 0;
|
||||
bd->bdt_stall = 0;
|
||||
bd->data = 0;
|
||||
|
||||
bd = &g_kinetis_bdt[busid].table[ep_idx][dir][odd ^ 1];
|
||||
bd->data = 1;
|
||||
|
||||
uint8_t regval = USB_OTG_DEV->ENDPOINT[ep_idx].ENDPT;
|
||||
if (regval & USB_ENDPT_EPSTALL_MASK) {
|
||||
USB_OTG_DEV->ENDPOINT[ep_idx].ENDPT = regval & ~USB_ENDPT_EPSTALL_MASK;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_is_stalled(uint8_t busid, const uint8_t ep, uint8_t *stalled)
|
||||
{
|
||||
uint8_t ep_idx = USB_EP_GET_IDX(ep);
|
||||
|
||||
uint8_t regval = USB_OTG_DEV->ENDPOINT[ep_idx].ENDPT;
|
||||
if (regval & USB_ENDPT_EPSTALL_MASK) {
|
||||
*stalled = 1;
|
||||
} else {
|
||||
*stalled = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_start_write(uint8_t busid, const uint8_t ep, const uint8_t *data,
|
||||
uint32_t data_len)
|
||||
{
|
||||
uint8_t ep_idx = USB_EP_GET_IDX(ep);
|
||||
|
||||
if (!data && data_len) {
|
||||
return -1;
|
||||
}
|
||||
if (!g_kinetis_udc[busid].in_ep[ep_idx].ep_enable) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
g_kinetis_udc[busid].in_ep[ep_idx].xfer_buf = (uint8_t *)data;
|
||||
g_kinetis_udc[busid].in_ep[ep_idx].xfer_len = data_len;
|
||||
g_kinetis_udc[busid].in_ep[ep_idx].actual_xfer_len = 0;
|
||||
|
||||
return kinetis_start_transfer(busid, ep, (uint8_t *)data, MIN(data_len, g_kinetis_udc[busid].in_ep[ep_idx].ep_mps));
|
||||
}
|
||||
|
||||
int usbd_ep_start_read(uint8_t busid, const uint8_t ep, uint8_t *data,
|
||||
uint32_t data_len)
|
||||
{
|
||||
uint8_t ep_idx = USB_EP_GET_IDX(ep);
|
||||
|
||||
if (!data && data_len) {
|
||||
return -1;
|
||||
}
|
||||
if (!g_kinetis_udc[busid].out_ep[ep_idx].ep_enable) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
g_kinetis_udc[busid].out_ep[ep_idx].xfer_buf = (uint8_t *)data;
|
||||
g_kinetis_udc[busid].out_ep[ep_idx].xfer_len = data_len;
|
||||
g_kinetis_udc[busid].out_ep[ep_idx].actual_xfer_len = 0;
|
||||
|
||||
return kinetis_start_transfer(busid, ep, (uint8_t *)data, MIN(data_len, g_kinetis_udc[busid].out_ep[ep_idx].ep_mps));
|
||||
}
|
||||
|
||||
void USBD_IRQHandler(uint8_t busid)
|
||||
{
|
||||
uint8_t s;
|
||||
uint8_t pid;
|
||||
uint8_t ep_idx;
|
||||
uint8_t dir;
|
||||
uint8_t odd;
|
||||
uint16_t bc;
|
||||
uint8_t is = USB_OTG_DEV->ISTAT;
|
||||
uint8_t mask = USB_OTG_DEV->INTEN;
|
||||
kinetis_bd_t *bd;
|
||||
|
||||
USB_OTG_DEV->ISTAT = is & ~mask;
|
||||
is &= mask;
|
||||
|
||||
if (is & USB_ISTAT_ERROR_MASK) {
|
||||
uint32_t es = USB_OTG_DEV->ERRSTAT;
|
||||
USB_OTG_DEV->ERRSTAT = es;
|
||||
USB_OTG_DEV->ISTAT = is;
|
||||
}
|
||||
|
||||
if (is & USB_ISTAT_USBRST_MASK) {
|
||||
USB_OTG_DEV->ISTAT = is;
|
||||
USB_OTG_DEV->CTL |= USB_CTL_ODDRST_MASK;
|
||||
USB_OTG_DEV->ADDR = 0;
|
||||
|
||||
USB_OTG_DEV->ENDPOINT[0].ENDPT = USB_ENDPT_EPHSHK_MASK | USB_ENDPT_EPRXEN_MASK | USB_ENDPT_EPTXEN_MASK;
|
||||
for (uint8_t i = 1; i < 16; i++) {
|
||||
USB_OTG_DEV->ENDPOINT[i].ENDPT = 0;
|
||||
}
|
||||
|
||||
memset(&g_kinetis_bdt[busid], 0, sizeof(g_kinetis_bdt[busid]));
|
||||
memset(g_kinetis_udc[busid].in_ep, 0, sizeof(struct kinetis_ep_state) * CONFIG_USBDEV_EP_NUM);
|
||||
memset(g_kinetis_udc[busid].out_ep, 0, sizeof(struct kinetis_ep_state) * CONFIG_USBDEV_EP_NUM);
|
||||
usbd_event_reset_handler(busid);
|
||||
|
||||
kinetis_read_setup(busid);
|
||||
|
||||
USB_OTG_DEV->CTL &= ~USB_CTL_ODDRST_MASK;
|
||||
}
|
||||
|
||||
if (is & USB_ISTAT_SLEEP_MASK) {
|
||||
USB_OTG_DEV->ISTAT = USB_ISTAT_SLEEP_MASK;
|
||||
}
|
||||
|
||||
if (is & USB_ISTAT_RESUME_MASK) {
|
||||
USB_OTG_DEV->ISTAT = USB_ISTAT_RESUME_MASK;
|
||||
}
|
||||
#ifdef CONFIG_USBDEV_SOF_ENABLE
|
||||
if (is & USB_ISTAT_SOFTOK_MASK) {
|
||||
USB_OTG_DEV->ISTAT = USB_ISTAT_SOFTOK_MASK;
|
||||
usbd_event_sof_handler(busid);
|
||||
}
|
||||
#endif
|
||||
if (is & USB_ISTAT_STALL_MASK) {
|
||||
USB_OTG_DEV->ISTAT = USB_ISTAT_STALL_MASK;
|
||||
}
|
||||
|
||||
if (is & USB_ISTAT_TOKDNE_MASK) {
|
||||
s = USB_OTG_DEV->STAT;
|
||||
USB_OTG_DEV->ISTAT = USB_ISTAT_TOKDNE_MASK; /* must be cleared after get STAT */
|
||||
|
||||
ep_idx = (s & USB_STAT_ENDP_MASK) >> USB_STAT_ENDP_SHIFT;
|
||||
dir = (s & USB_STAT_TX_MASK) >> USB_STAT_TX_SHIFT;
|
||||
odd = (s & USB_STAT_ODD_MASK) >> USB_STAT_ODD_SHIFT;
|
||||
|
||||
bd = &g_kinetis_bdt[busid].table[ep_idx][dir][odd];
|
||||
|
||||
pid = bd->tok_pid;
|
||||
bc = bd->bc;
|
||||
|
||||
bd->bdt_stall = 0;
|
||||
bd->dts = 1;
|
||||
bd->ninc = 0;
|
||||
bd->keep = 0;
|
||||
|
||||
if (dir) {
|
||||
g_kinetis_udc[busid].in_ep[ep_idx].ep_odd = odd ^ 1;
|
||||
} else {
|
||||
g_kinetis_udc[busid].out_ep[ep_idx].ep_odd = odd ^ 1;
|
||||
}
|
||||
|
||||
if (pid == USB_TOKEN_PID_SETUP) {
|
||||
USB_OTG_DEV->CTL &= ~USB_CTL_TXSUSPENDTOKENBUSY_MASK;
|
||||
usbd_event_ep0_setup_complete_handler(busid, (uint8_t *)bd->addr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (dir) {
|
||||
g_kinetis_udc[busid].in_ep[ep_idx].xfer_buf += bc;
|
||||
g_kinetis_udc[busid].in_ep[ep_idx].xfer_len -= bc;
|
||||
g_kinetis_udc[busid].in_ep[ep_idx].actual_xfer_len += bc;
|
||||
|
||||
if (g_kinetis_udc[busid].in_ep[ep_idx].xfer_len == 0) {
|
||||
usbd_event_ep_in_complete_handler(busid, ep_idx | 0x80, g_kinetis_udc[busid].in_ep[ep_idx].actual_xfer_len);
|
||||
} else {
|
||||
kinetis_start_transfer(busid, ep_idx | 0x80, g_kinetis_udc[busid].in_ep[ep_idx].xfer_buf,
|
||||
MIN(g_kinetis_udc[busid].in_ep[ep_idx].xfer_len, g_kinetis_udc[busid].in_ep[ep_idx].ep_mps));
|
||||
}
|
||||
} else {
|
||||
g_kinetis_udc[busid].out_ep[ep_idx].xfer_buf += bc;
|
||||
g_kinetis_udc[busid].out_ep[ep_idx].xfer_len -= bc;
|
||||
g_kinetis_udc[busid].out_ep[ep_idx].actual_xfer_len += bc;
|
||||
|
||||
if ((bc < g_kinetis_udc[busid].out_ep[ep_idx].ep_mps) || (g_kinetis_udc[busid].out_ep[ep_idx].xfer_len == 0)) {
|
||||
usbd_event_ep_out_complete_handler(busid, ep_idx, g_kinetis_udc[busid].out_ep[ep_idx].actual_xfer_len);
|
||||
} else {
|
||||
kinetis_start_transfer(busid, ep_idx, g_kinetis_udc[busid].out_ep[ep_idx].xfer_buf,
|
||||
MIN(g_kinetis_udc[busid].out_ep[ep_idx].xfer_len, g_kinetis_udc[busid].out_ep[ep_idx].ep_mps));
|
||||
}
|
||||
}
|
||||
|
||||
if ((bc == 0) && (ep_idx == 0)) {
|
||||
if ((g_kinetis_udc[busid].dev_addr > 0) && dir) {
|
||||
USB_OTG_DEV->ADDR = g_kinetis_udc[busid].dev_addr;
|
||||
g_kinetis_udc[busid].dev_addr = 0;
|
||||
}
|
||||
|
||||
kinetis_read_setup(busid);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) 2024, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usbd_core.h"
|
||||
#include "fsl_common.h"
|
||||
#include "usb_kinetis_reg.h"
|
||||
|
||||
#define USB_OTG_DEV ((KINETIS_MCX_TypeDef *)g_usbdev_bus[busid].reg_base)
|
||||
|
||||
#if defined(MCXC444_H_)
|
||||
#define USBD_IRQ USB0_IRQHandler
|
||||
void USB_ClockInit(void)
|
||||
{
|
||||
SystemCoreClockUpdate();
|
||||
CLOCK_EnableUsbfs0Clock(kCLOCK_UsbSrcIrc48M, 48000000U);
|
||||
}
|
||||
#elif defined(MCXA153_H_)
|
||||
#define USBD_IRQ USB0_IRQHandler
|
||||
void USB_ClockInit(void)
|
||||
{
|
||||
RESET_PeripheralReset(kUSB0_RST_SHIFT_RSTn);
|
||||
CLOCK_EnableUsbfsClock();
|
||||
}
|
||||
#elif defined(MCXN947_CM33_CORE0_H_)
|
||||
#define USBD_IRQ USB0_FS_IRQHandler
|
||||
void USB_ClockInit(void)
|
||||
{
|
||||
CLOCK_AttachClk(kCLK_48M_to_USB0);
|
||||
CLOCK_EnableClock(kCLOCK_Usb0Ram);
|
||||
CLOCK_EnableClock(kCLOCK_Usb0Fs);
|
||||
CLOCK_EnableUsbfsClock();
|
||||
}
|
||||
#elif defined(MCXA156_H_)
|
||||
#define USBD_IRQ USB0_IRQHandler
|
||||
void USB_ClockInit(void)
|
||||
{
|
||||
RESET_PeripheralReset(kUSB0_RST_SHIFT_RSTn);
|
||||
CLOCK_EnableUsbfsClock();
|
||||
}
|
||||
#else
|
||||
#error "Unsupported MCU with Kinetis IP"
|
||||
#endif
|
||||
|
||||
void USBD_IRQ(void)
|
||||
{
|
||||
extern void USBD_IRQHandler(uint8_t busid);
|
||||
USBD_IRQHandler(0);
|
||||
}
|
||||
|
||||
void usb_dc_low_level_init(uint8_t busid)
|
||||
{
|
||||
USB_ClockInit();
|
||||
|
||||
uint8_t irqNumber;
|
||||
|
||||
uint8_t usbDeviceKhciIrq[] = USB_IRQS;
|
||||
irqNumber = usbDeviceKhciIrq[0];
|
||||
|
||||
/* Install isr, set priority, and enable IRQ. */
|
||||
NVIC_SetPriority((IRQn_Type)irqNumber, 3);
|
||||
EnableIRQ((IRQn_Type)irqNumber);
|
||||
|
||||
USB_OTG_DEV->USBTRC0 |= USB_USBTRC0_USBRESET_MASK;
|
||||
while (USB_OTG_DEV->USBTRC0 & USB_USBTRC0_USBRESET_MASK);
|
||||
|
||||
USB_OTG_DEV->USBTRC0 |= USB_USBTRC0_VREGIN_STS(1); /* software must set this bit to 1 */
|
||||
USB_OTG_DEV->USBCTRL = 0;
|
||||
USB_OTG_DEV->CONTROL |= USB_CONTROL_DPPULLUPNONOTG_MASK;
|
||||
}
|
||||
|
||||
void usb_dc_low_level_deinit(uint8_t busid)
|
||||
{
|
||||
USB_OTG_DEV->CONTROL &= ~USB_CONTROL_DPPULLUPNONOTG_MASK;
|
||||
#if defined(MCXN947_CM33_CORE0_H_)
|
||||
DisableIRQ((IRQn_Type)USB0_FS_IRQn);
|
||||
#else
|
||||
DisableIRQ((IRQn_Type)USB0_IRQn);
|
||||
#endif
|
||||
}
|
||||
|
||||
void usbd_kinetis_delay_ms(uint8_t ms)
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mm32_device.h"
|
||||
#include "hal_rcc.h"
|
||||
#include "usbd_core.h"
|
||||
|
||||
void usb_dc_low_level_init(uint8_t busid)
|
||||
{
|
||||
/* Select USBCLK source */
|
||||
// RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_Div1);
|
||||
RCC->CFGR &= ~(0x3 << 22);
|
||||
RCC->CFGR |= (0x1 << 22);
|
||||
|
||||
/* Enable USB clock */
|
||||
RCC->AHB2ENR |= 0x1 << 7;
|
||||
|
||||
#define USB_DEVICE_INTERRUPT_PRIORITY (7U)
|
||||
NVIC_SetPriority((IRQn_Type)USB_OTGFS_IRQn, USB_DEVICE_INTERRUPT_PRIORITY);
|
||||
NVIC_EnableIRQ(USB_OTGFS_IRQn);
|
||||
}
|
||||
|
||||
void usb_dc_low_level_deinit(uint8_t busid)
|
||||
{
|
||||
RCC->AHB2ENR &= ~(0x1 << 7);
|
||||
}
|
||||
|
||||
void USB_OTGFS_IRQHandler(void)
|
||||
{
|
||||
USBD_IRQHandler(0);
|
||||
}
|
||||
|
||||
void usbd_kinetis_delay_ms(uint8_t ms)
|
||||
{
|
||||
//delay_ms(ms);
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
TODO
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,23 @@
|
||||
# Note
|
||||
|
||||
## Support Chip List
|
||||
|
||||
### Eastsoft
|
||||
|
||||
- ES32F3xx
|
||||
|
||||
### TI
|
||||
|
||||
- MSP432E4x
|
||||
|
||||
### Bekencorp
|
||||
|
||||
- BK7256/BK7258
|
||||
|
||||
### AllwinnerTech
|
||||
|
||||
- F1Cxxx, F2Cxxx
|
||||
|
||||
### SIFLI
|
||||
|
||||
- SF325X
|
||||
@@ -0,0 +1,898 @@
|
||||
/*
|
||||
* Copyright (c) 2022, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usbd_core.h"
|
||||
#include "usb_musb_reg.h"
|
||||
|
||||
#define HWREG(x) \
|
||||
(*((volatile uint32_t *)(x)))
|
||||
#define HWREGH(x) \
|
||||
(*((volatile uint16_t *)(x)))
|
||||
#define HWREGB(x) \
|
||||
(*((volatile uint8_t *)(x)))
|
||||
|
||||
#define USB_BASE (g_usbdev_bus[0].reg_base)
|
||||
|
||||
#if defined(CONFIG_USB_MUSB_SUNXI)
|
||||
#define MUSB_FADDR_OFFSET 0x98
|
||||
#define MUSB_POWER_OFFSET 0x40
|
||||
#define MUSB_TXIS_OFFSET 0x44
|
||||
#define MUSB_RXIS_OFFSET 0x46
|
||||
#define MUSB_TXIE_OFFSET 0x48
|
||||
#define MUSB_RXIE_OFFSET 0x4A
|
||||
#define MUSB_IS_OFFSET 0x4C
|
||||
#define MUSB_IE_OFFSET 0x50
|
||||
#define MUSB_EPIDX_OFFSET 0x42
|
||||
|
||||
#define MUSB_IND_TXMAP_OFFSET 0x80
|
||||
#define MUSB_IND_TXCSRL_OFFSET 0x82
|
||||
#define MUSB_IND_TXCSRH_OFFSET 0x83
|
||||
#define MUSB_IND_RXMAP_OFFSET 0x84
|
||||
#define MUSB_IND_RXCSRL_OFFSET 0x86
|
||||
#define MUSB_IND_RXCSRH_OFFSET 0x87
|
||||
#define MUSB_IND_RXCOUNT_OFFSET 0x88
|
||||
#define MUSB_IND_TXTYPE_OFFSET 0x8C
|
||||
#define MUSB_IND_TXINTERVAL_OFFSET 0x8D
|
||||
#define MUSB_IND_RXTYPE_OFFSET 0x8E
|
||||
#define MUSB_IND_RXINTERVAL_OFFSET 0x8F
|
||||
|
||||
#define MUSB_FIFO_OFFSET 0x00
|
||||
|
||||
#define MUSB_DEVCTL_OFFSET 0x41
|
||||
|
||||
#define MUSB_TXFIFOSZ_OFFSET 0x90
|
||||
#define MUSB_RXFIFOSZ_OFFSET 0x94
|
||||
#define MUSB_TXFIFOADD_OFFSET 0x92
|
||||
#define MUSB_RXFIFOADD_OFFSET 0x96
|
||||
|
||||
#define MUSB_TXFUNCADDR0_OFFSET 0x98
|
||||
#define MUSB_TXHUBADDR0_OFFSET 0x9A
|
||||
#define MUSB_TXHUBPORT0_OFFSET 0x9B
|
||||
#define MUSB_TXFUNCADDRx_OFFSET 0x98
|
||||
#define MUSB_TXHUBADDRx_OFFSET 0x9A
|
||||
#define MUSB_TXHUBPORTx_OFFSET 0x9B
|
||||
#define MUSB_RXFUNCADDRx_OFFSET 0x9C
|
||||
#define MUSB_RXHUBADDRx_OFFSET 0x9E
|
||||
#define MUSB_RXHUBPORTx_OFFSET 0x9F
|
||||
|
||||
#define USB_TXMAP_BASE(ep_idx) (USB_BASE + MUSB_IND_TXMAP_OFFSET)
|
||||
#define USB_TXCSRL_BASE(ep_idx) (USB_BASE + MUSB_IND_TXCSRL_OFFSET)
|
||||
#define USB_TXCSRH_BASE(ep_idx) (USB_BASE + MUSB_IND_TXCSRH_OFFSET)
|
||||
#define USB_RXMAP_BASE(ep_idx) (USB_BASE + MUSB_IND_RXMAP_OFFSET)
|
||||
#define USB_RXCSRL_BASE(ep_idx) (USB_BASE + MUSB_IND_RXCSRL_OFFSET)
|
||||
#define USB_RXCSRH_BASE(ep_idx) (USB_BASE + MUSB_IND_RXCSRH_OFFSET)
|
||||
#define USB_RXCOUNT_BASE(ep_idx) (USB_BASE + MUSB_IND_RXCOUNT_OFFSET)
|
||||
#define USB_TXTYPE_BASE(ep_idx) (USB_BASE + MUSB_IND_TXTYPE_OFFSET)
|
||||
#define USB_TXINTERVAL_BASE(ep_idx) (USB_BASE + MUSB_IND_TXINTERVAL_OFFSET)
|
||||
#define USB_RXTYPE_BASE(ep_idx) (USB_BASE + MUSB_IND_RXTYPE_OFFSET)
|
||||
#define USB_RXINTERVAL_BASE(ep_idx) (USB_BASE + MUSB_IND_RXINTERVAL_OFFSET)
|
||||
|
||||
#define USB_TXADDR_BASE(ep_idx) (USB_BASE + MUSB_TXFUNCADDRx_OFFSET)
|
||||
#define USB_TXHUBADDR_BASE(ep_idx) (USB_BASE + MUSB_TXHUBADDRx_OFFSET)
|
||||
#define USB_TXHUBPORT_BASE(ep_idx) (USB_BASE + MUSB_TXHUBPORTx_OFFSET)
|
||||
#define USB_RXADDR_BASE(ep_idx) (USB_BASE + MUSB_RXFUNCADDRx_OFFSET)
|
||||
#define USB_RXHUBADDR_BASE(ep_idx) (USB_BASE + MUSB_RXHUBADDRx_OFFSET)
|
||||
#define USB_RXHUBPORT_BASE(ep_idx) (USB_BASE + MUSB_RXHUBPORTx_OFFSET)
|
||||
|
||||
#elif defined(CONFIG_USB_MUSB_CUSTOM)
|
||||
#include "musb_custom.h"
|
||||
#else
|
||||
#define MUSB_FADDR_OFFSET 0x00
|
||||
#define MUSB_POWER_OFFSET 0x01
|
||||
#define MUSB_TXIS_OFFSET 0x02
|
||||
#define MUSB_RXIS_OFFSET 0x04
|
||||
#define MUSB_TXIE_OFFSET 0x06
|
||||
#define MUSB_RXIE_OFFSET 0x08
|
||||
#define MUSB_IS_OFFSET 0x0A
|
||||
#define MUSB_IE_OFFSET 0x0B
|
||||
|
||||
#define MUSB_EPIDX_OFFSET 0x0E
|
||||
|
||||
#define MUSB_IND_TXMAP_OFFSET 0x10
|
||||
#define MUSB_IND_TXCSRL_OFFSET 0x12
|
||||
#define MUSB_IND_TXCSRH_OFFSET 0x13
|
||||
#define MUSB_IND_RXMAP_OFFSET 0x14
|
||||
#define MUSB_IND_RXCSRL_OFFSET 0x16
|
||||
#define MUSB_IND_RXCSRH_OFFSET 0x17
|
||||
#define MUSB_IND_RXCOUNT_OFFSET 0x18
|
||||
#define MUSB_IND_TXTYPE_OFFSET 0x1A
|
||||
#define MUSB_IND_TXINTERVAL_OFFSET 0x1B
|
||||
#define MUSB_IND_RXTYPE_OFFSET 0x1C
|
||||
#define MUSB_IND_RXINTERVAL_OFFSET 0x1D
|
||||
|
||||
#define MUSB_FIFO_OFFSET 0x20
|
||||
|
||||
#define MUSB_DEVCTL_OFFSET 0x60
|
||||
|
||||
#define MUSB_TXFIFOSZ_OFFSET 0x62
|
||||
#define MUSB_RXFIFOSZ_OFFSET 0x63
|
||||
#define MUSB_TXFIFOADD_OFFSET 0x64
|
||||
#define MUSB_RXFIFOADD_OFFSET 0x66
|
||||
|
||||
#define MUSB_TXFUNCADDR0_OFFSET 0x80
|
||||
#define MUSB_TXHUBADDR0_OFFSET 0x82
|
||||
#define MUSB_TXHUBPORT0_OFFSET 0x83
|
||||
#define MUSB_TXFUNCADDRx_OFFSET 0x88
|
||||
#define MUSB_TXHUBADDRx_OFFSET 0x8A
|
||||
#define MUSB_TXHUBPORTx_OFFSET 0x8B
|
||||
#define MUSB_RXFUNCADDRx_OFFSET 0x8C
|
||||
#define MUSB_RXHUBADDRx_OFFSET 0x8E
|
||||
#define MUSB_RXHUBPORTx_OFFSET 0x8F
|
||||
|
||||
#define MUSB_TXMAP0_OFFSET 0x100
|
||||
|
||||
// do not use EPIDX
|
||||
#define USB_TXMAP_BASE(ep_idx) (USB_BASE + MUSB_TXMAP0_OFFSET + 0x10 * ep_idx)
|
||||
#define USB_TXCSRL_BASE(ep_idx) (USB_BASE + MUSB_TXMAP0_OFFSET + 0x10 * ep_idx + 2)
|
||||
#define USB_TXCSRH_BASE(ep_idx) (USB_BASE + MUSB_TXMAP0_OFFSET + 0x10 * ep_idx + 3)
|
||||
#define USB_RXMAP_BASE(ep_idx) (USB_BASE + MUSB_TXMAP0_OFFSET + 0x10 * ep_idx + 4)
|
||||
#define USB_RXCSRL_BASE(ep_idx) (USB_BASE + MUSB_TXMAP0_OFFSET + 0x10 * ep_idx + 6)
|
||||
#define USB_RXCSRH_BASE(ep_idx) (USB_BASE + MUSB_TXMAP0_OFFSET + 0x10 * ep_idx + 7)
|
||||
#define USB_RXCOUNT_BASE(ep_idx) (USB_BASE + MUSB_TXMAP0_OFFSET + 0x10 * ep_idx + 8)
|
||||
#define USB_TXTYPE_BASE(ep_idx) (USB_BASE + MUSB_TXMAP0_OFFSET + 0x10 * ep_idx + 0x0A)
|
||||
#define USB_TXINTERVAL_BASE(ep_idx) (USB_BASE + MUSB_TXMAP0_OFFSET + 0x10 * ep_idx + 0x0B)
|
||||
#define USB_RXTYPE_BASE(ep_idx) (USB_BASE + MUSB_TXMAP0_OFFSET + 0x10 * ep_idx + 0x0C)
|
||||
#define USB_RXINTERVAL_BASE(ep_idx) (USB_BASE + MUSB_TXMAP0_OFFSET + 0x10 * ep_idx + 0x0D)
|
||||
|
||||
#define USB_TXADDR_BASE(ep_idx) (USB_BASE + MUSB_TXFUNCADDR0_OFFSET + 0x8 * ep_idx)
|
||||
#define USB_TXHUBADDR_BASE(ep_idx) (USB_BASE + MUSB_TXFUNCADDR0_OFFSET + 0x8 * ep_idx + 2)
|
||||
#define USB_TXHUBPORT_BASE(ep_idx) (USB_BASE + MUSB_TXFUNCADDR0_OFFSET + 0x8 * ep_idx + 3)
|
||||
#define USB_RXADDR_BASE(ep_idx) (USB_BASE + MUSB_TXFUNCADDR0_OFFSET + 0x8 * ep_idx + 4)
|
||||
#define USB_RXHUBADDR_BASE(ep_idx) (USB_BASE + MUSB_TXFUNCADDR0_OFFSET + 0x8 * ep_idx + 6)
|
||||
#define USB_RXHUBPORT_BASE(ep_idx) (USB_BASE + MUSB_TXFUNCADDR0_OFFSET + 0x8 * ep_idx + 7)
|
||||
#endif
|
||||
|
||||
#define USB_FIFO_BASE(ep_idx) (USB_BASE + MUSB_FIFO_OFFSET + 0x4 * ep_idx)
|
||||
|
||||
typedef enum {
|
||||
USB_EP0_STATE_SETUP = 0x0, /**< SETUP DATA */
|
||||
USB_EP0_STATE_IN_DATA = 0x1, /**< IN DATA */
|
||||
USB_EP0_STATE_OUT_DATA = 0x3, /**< OUT DATA */
|
||||
USB_EP0_STATE_IN_STATUS = 0x4, /**< IN status */
|
||||
USB_EP0_STATE_OUT_STATUS = 0x5, /**< OUT status */
|
||||
USB_EP0_STATE_IN_ZLP = 0x6, /**< OUT status */
|
||||
USB_EP0_STATE_STALL = 0x7, /**< STALL status */
|
||||
} ep0_state_t;
|
||||
|
||||
/* Endpoint state */
|
||||
struct musb_ep_state {
|
||||
uint16_t ep_mps; /* Endpoint max packet size */
|
||||
uint8_t ep_type; /* Endpoint type */
|
||||
uint8_t ep_stalled; /* Endpoint stall flag */
|
||||
uint8_t ep_enable; /* Endpoint enable */
|
||||
uint8_t *xfer_buf;
|
||||
uint32_t xfer_len;
|
||||
uint32_t actual_xfer_len;
|
||||
};
|
||||
|
||||
/* Driver state */
|
||||
struct musb_udc {
|
||||
volatile uint8_t dev_addr;
|
||||
__attribute__((aligned(32))) struct usb_setup_packet setup;
|
||||
struct musb_ep_state in_ep[CONFIG_USB_MUSB_EP_NUM]; /*!< IN endpoint parameters*/
|
||||
struct musb_ep_state out_ep[CONFIG_USB_MUSB_EP_NUM]; /*!< OUT endpoint parameters */
|
||||
} g_musb_udc;
|
||||
|
||||
static volatile uint8_t usb_ep0_state = USB_EP0_STATE_SETUP;
|
||||
|
||||
/* get current active ep */
|
||||
static uint8_t musb_get_active_ep(void)
|
||||
{
|
||||
return HWREGB(USB_BASE + MUSB_EPIDX_OFFSET);
|
||||
}
|
||||
|
||||
/* set the active ep */
|
||||
static void musb_set_active_ep(uint8_t ep_index)
|
||||
{
|
||||
HWREGB(USB_BASE + MUSB_EPIDX_OFFSET) = ep_index;
|
||||
}
|
||||
|
||||
static void musb_write_packet(uint8_t ep_idx, uint8_t *buffer, uint16_t len)
|
||||
{
|
||||
uint32_t *buf32;
|
||||
uint8_t *buf8;
|
||||
uint32_t count32;
|
||||
uint32_t count8;
|
||||
int i;
|
||||
|
||||
if ((uint32_t)buffer & 0x03) {
|
||||
buf8 = buffer;
|
||||
for (i = 0; i < len; i++) {
|
||||
HWREGB(USB_FIFO_BASE(ep_idx)) = *buf8++;
|
||||
}
|
||||
} else {
|
||||
count32 = len >> 2;
|
||||
count8 = len & 0x03;
|
||||
|
||||
buf32 = (uint32_t *)buffer;
|
||||
|
||||
while (count32--) {
|
||||
HWREG(USB_FIFO_BASE(ep_idx)) = *buf32++;
|
||||
}
|
||||
|
||||
buf8 = (uint8_t *)buf32;
|
||||
|
||||
while (count8--) {
|
||||
HWREGB(USB_FIFO_BASE(ep_idx)) = *buf8++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void musb_read_packet(uint8_t ep_idx, uint8_t *buffer, uint16_t len)
|
||||
{
|
||||
uint32_t *buf32;
|
||||
uint8_t *buf8;
|
||||
uint32_t count32;
|
||||
uint32_t count8;
|
||||
int i;
|
||||
|
||||
if ((uint32_t)buffer & 0x03) {
|
||||
buf8 = buffer;
|
||||
for (i = 0; i < len; i++) {
|
||||
*buf8++ = HWREGB(USB_FIFO_BASE(ep_idx));
|
||||
}
|
||||
} else {
|
||||
count32 = len >> 2;
|
||||
count8 = len & 0x03;
|
||||
|
||||
buf32 = (uint32_t *)buffer;
|
||||
|
||||
while (count32--) {
|
||||
*buf32++ = HWREG(USB_FIFO_BASE(ep_idx));
|
||||
}
|
||||
|
||||
buf8 = (uint8_t *)buf32;
|
||||
|
||||
while (count8--) {
|
||||
*buf8++ = HWREGB(USB_FIFO_BASE(ep_idx));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t musb_get_fifo_size(uint16_t mps, uint16_t *used)
|
||||
{
|
||||
uint32_t size;
|
||||
|
||||
for (uint8_t i = USB_TXFIFOSZ_SIZE_8; i <= USB_TXFIFOSZ_SIZE_2048; i++) {
|
||||
size = (8 << i);
|
||||
if (mps <= size) {
|
||||
*used = size;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
*used = 0;
|
||||
return USB_TXFIFOSZ_SIZE_8;
|
||||
}
|
||||
|
||||
static uint32_t usbd_musb_fifo_config(struct musb_fifo_cfg *cfg, uint32_t offset)
|
||||
{
|
||||
uint16_t fifo_used;
|
||||
uint8_t c_size;
|
||||
uint16_t c_off;
|
||||
|
||||
c_off = offset >> 3;
|
||||
c_size = musb_get_fifo_size(cfg->maxpacket, &fifo_used);
|
||||
|
||||
musb_set_active_ep(cfg->ep_num);
|
||||
|
||||
switch (cfg->style) {
|
||||
case FIFO_TX:
|
||||
HWREGB(USB_BASE + MUSB_TXFIFOSZ_OFFSET) = c_size & 0x0f;
|
||||
HWREGH(USB_BASE + MUSB_TXFIFOADD_OFFSET) = c_off;
|
||||
break;
|
||||
case FIFO_RX:
|
||||
HWREGB(USB_BASE + MUSB_RXFIFOSZ_OFFSET) = c_size & 0x0f;
|
||||
HWREGH(USB_BASE + MUSB_RXFIFOADD_OFFSET) = c_off;
|
||||
break;
|
||||
case FIFO_TXRX:
|
||||
HWREGB(USB_BASE + MUSB_TXFIFOSZ_OFFSET) = c_size & 0x0f;
|
||||
HWREGH(USB_BASE + MUSB_TXFIFOADD_OFFSET) = c_off;
|
||||
HWREGB(USB_BASE + MUSB_RXFIFOSZ_OFFSET) = c_size & 0x0f;
|
||||
HWREGH(USB_BASE + MUSB_RXFIFOADD_OFFSET) = c_off;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return (offset + fifo_used);
|
||||
}
|
||||
|
||||
__WEAK void usb_dc_low_level_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
__WEAK void usb_dc_low_level_deinit(void)
|
||||
{
|
||||
}
|
||||
|
||||
int usb_dc_init(uint8_t busid)
|
||||
{
|
||||
uint16_t offset = 0;
|
||||
uint8_t cfg_num;
|
||||
struct musb_fifo_cfg *cfg;
|
||||
|
||||
usb_dc_low_level_init();
|
||||
|
||||
#ifdef CONFIG_USB_HS
|
||||
HWREGB(USB_BASE + MUSB_POWER_OFFSET) |= USB_POWER_HSENAB;
|
||||
#else
|
||||
HWREGB(USB_BASE + MUSB_POWER_OFFSET) &= ~USB_POWER_HSENAB;
|
||||
#endif
|
||||
|
||||
musb_set_active_ep(0);
|
||||
HWREGB(USB_BASE + MUSB_FADDR_OFFSET) = 0;
|
||||
|
||||
HWREGB(USB_BASE + MUSB_DEVCTL_OFFSET) |= USB_DEVCTL_SESSION;
|
||||
|
||||
cfg_num = usbd_get_musb_fifo_cfg(&cfg);
|
||||
|
||||
for (uint8_t i = 0; i < cfg_num; i++) {
|
||||
offset = usbd_musb_fifo_config(&cfg[i], offset);
|
||||
}
|
||||
|
||||
USB_ASSERT_MSG(offset <= usb_get_musb_ram_size(), "Your fifo config is overflow, please check");
|
||||
|
||||
/* Enable USB interrupts */
|
||||
HWREGB(USB_BASE + MUSB_IE_OFFSET) = USB_IE_RESET | USB_IE_SUSPND | USB_IE_RESUME;
|
||||
HWREGH(USB_BASE + MUSB_TXIE_OFFSET) = USB_TXIE_EP0;
|
||||
HWREGH(USB_BASE + MUSB_RXIE_OFFSET) = 0;
|
||||
|
||||
#ifdef CONFIG_USBDEV_SOF_ENABLE
|
||||
HWREGB(USB_BASE + MUSB_IE_OFFSET) |= USB_IE_SOF;
|
||||
#endif
|
||||
|
||||
HWREGB(USB_BASE + MUSB_POWER_OFFSET) |= USB_POWER_SOFTCONN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_dc_deinit(uint8_t busid)
|
||||
{
|
||||
HWREGB(USB_BASE + MUSB_IE_OFFSET) = 0;
|
||||
HWREGH(USB_BASE + MUSB_TXIE_OFFSET) = 0;
|
||||
HWREGH(USB_BASE + MUSB_RXIE_OFFSET) = 0;
|
||||
|
||||
HWREGB(USB_BASE + MUSB_POWER_OFFSET) &= ~USB_POWER_SOFTCONN;
|
||||
|
||||
usb_dc_low_level_deinit();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_set_address(uint8_t busid, const uint8_t addr)
|
||||
{
|
||||
if (addr == 0) {
|
||||
HWREGB(USB_BASE + MUSB_FADDR_OFFSET) = 0;
|
||||
}
|
||||
|
||||
g_musb_udc.dev_addr = addr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_set_remote_wakeup(uint8_t busid)
|
||||
{
|
||||
HWREGB(USB_BASE + MUSB_POWER_OFFSET) |= USB_POWER_RESUME;
|
||||
usbd_musb_delay_ms(10);
|
||||
HWREGB(USB_BASE + MUSB_POWER_OFFSET) &= ~USB_POWER_RESUME;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t usbd_get_port_speed(uint8_t busid)
|
||||
{
|
||||
uint8_t speed = USB_SPEED_UNKNOWN;
|
||||
|
||||
if (HWREGB(USB_BASE + MUSB_POWER_OFFSET) & USB_POWER_HSMODE)
|
||||
speed = USB_SPEED_HIGH;
|
||||
else if (HWREGB(USB_BASE + MUSB_DEVCTL_OFFSET) & USB_DEVCTL_FSDEV)
|
||||
speed = USB_SPEED_FULL;
|
||||
else if (HWREGB(USB_BASE + MUSB_DEVCTL_OFFSET) & USB_DEVCTL_LSDEV)
|
||||
speed = USB_SPEED_LOW;
|
||||
|
||||
return speed;
|
||||
}
|
||||
|
||||
int usbd_ep_open(uint8_t busid, const struct usb_endpoint_descriptor *ep)
|
||||
{
|
||||
uint8_t ep_idx = USB_EP_GET_IDX(ep->bEndpointAddress);
|
||||
uint8_t old_ep_idx;
|
||||
uint32_t ui32Flags = 0;
|
||||
uint16_t ui32Register = 0;
|
||||
|
||||
if (ep_idx == 0) {
|
||||
g_musb_udc.out_ep[0].ep_mps = USB_CTRL_EP_MPS;
|
||||
g_musb_udc.out_ep[0].ep_type = 0x00;
|
||||
g_musb_udc.out_ep[0].ep_enable = true;
|
||||
g_musb_udc.in_ep[0].ep_mps = USB_CTRL_EP_MPS;
|
||||
g_musb_udc.in_ep[0].ep_type = 0x00;
|
||||
g_musb_udc.in_ep[0].ep_enable = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
USB_ASSERT_MSG(ep_idx < CONFIG_USB_MUSB_EP_NUM, "Ep addr %02x overflow", ep->bEndpointAddress);
|
||||
|
||||
old_ep_idx = musb_get_active_ep();
|
||||
musb_set_active_ep(ep_idx);
|
||||
|
||||
if (USB_EP_DIR_IS_OUT(ep->bEndpointAddress)) {
|
||||
g_musb_udc.out_ep[ep_idx].ep_mps = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
|
||||
g_musb_udc.out_ep[ep_idx].ep_type = USB_GET_ENDPOINT_TYPE(ep->bmAttributes);
|
||||
g_musb_udc.out_ep[ep_idx].ep_enable = true;
|
||||
|
||||
#ifndef CONFIG_USB_MUSB_SIFLI
|
||||
USB_ASSERT_MSG((8 << HWREGB(USB_BASE + MUSB_RXFIFOSZ_OFFSET)) >= g_musb_udc.out_ep[ep_idx].ep_mps,
|
||||
"Ep %02x fifo is overflow", ep->bEndpointAddress);
|
||||
#endif
|
||||
|
||||
HWREGH(USB_RXMAP_BASE(ep_idx)) = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
|
||||
|
||||
//
|
||||
// Allow auto clearing of RxPktRdy when packet of size max packet
|
||||
// has been unloaded from the FIFO.
|
||||
//
|
||||
if (ui32Flags & USB_EP_AUTO_CLEAR) {
|
||||
ui32Register = USB_RXCSRH1_AUTOCL;
|
||||
}
|
||||
//
|
||||
// Configure the DMA mode.
|
||||
//
|
||||
if (ui32Flags & USB_EP_DMA_MODE_1) {
|
||||
ui32Register |= USB_RXCSRH1_DMAEN | USB_RXCSRH1_DMAMOD;
|
||||
} else if (ui32Flags & USB_EP_DMA_MODE_0) {
|
||||
ui32Register |= USB_RXCSRH1_DMAEN;
|
||||
}
|
||||
//
|
||||
// If requested, disable NYET responses for high-speed bulk and
|
||||
// interrupt endpoints.
|
||||
//
|
||||
if (ui32Flags & USB_EP_DIS_NYET) {
|
||||
ui32Register |= USB_RXCSRH1_DISNYET;
|
||||
}
|
||||
|
||||
//
|
||||
// Enable isochronous mode if requested.
|
||||
//
|
||||
if (USB_GET_ENDPOINT_TYPE(ep->bmAttributes) == 0x01) {
|
||||
ui32Register |= USB_RXCSRH1_ISO;
|
||||
}
|
||||
|
||||
HWREGB(USB_RXCSRH_BASE(ep_idx)) = ui32Register;
|
||||
|
||||
// Reset the Data toggle to zero.
|
||||
if (HWREGB(USB_RXCSRL_BASE(ep_idx)) & USB_RXCSRL1_RXRDY)
|
||||
HWREGB(USB_RXCSRL_BASE(ep_idx)) = (USB_RXCSRL1_CLRDT | USB_RXCSRL1_FLUSH);
|
||||
else
|
||||
HWREGB(USB_RXCSRL_BASE(ep_idx)) = USB_RXCSRL1_CLRDT;
|
||||
|
||||
HWREGB(USB_TXCSRH_BASE(ep_idx)) &= ~USB_TXCSRH1_MODE;
|
||||
} else {
|
||||
g_musb_udc.in_ep[ep_idx].ep_mps = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
|
||||
g_musb_udc.in_ep[ep_idx].ep_type = USB_GET_ENDPOINT_TYPE(ep->bmAttributes);
|
||||
g_musb_udc.in_ep[ep_idx].ep_enable = true;
|
||||
|
||||
#ifndef CONFIG_USB_MUSB_SIFLI
|
||||
USB_ASSERT_MSG((8 << HWREGB(USB_BASE + MUSB_TXFIFOSZ_OFFSET)) >= g_musb_udc.in_ep[ep_idx].ep_mps,
|
||||
"Ep %02x fifo is overflow", ep->bEndpointAddress);
|
||||
#endif
|
||||
|
||||
HWREGH(USB_TXMAP_BASE(ep_idx)) = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
|
||||
|
||||
//
|
||||
// Allow auto setting of TxPktRdy when max packet size has been loaded
|
||||
// into the FIFO.
|
||||
//
|
||||
if (ui32Flags & USB_EP_AUTO_SET) {
|
||||
ui32Register |= USB_TXCSRH1_AUTOSET;
|
||||
}
|
||||
|
||||
//
|
||||
// Configure the DMA mode.
|
||||
//
|
||||
if (ui32Flags & USB_EP_DMA_MODE_1) {
|
||||
ui32Register |= USB_TXCSRH1_DMAEN | USB_TXCSRH1_DMAMOD;
|
||||
} else if (ui32Flags & USB_EP_DMA_MODE_0) {
|
||||
ui32Register |= USB_TXCSRH1_DMAEN;
|
||||
}
|
||||
|
||||
//
|
||||
// Enable isochronous mode if requested.
|
||||
//
|
||||
if (USB_GET_ENDPOINT_TYPE(ep->bmAttributes) == 0x01) {
|
||||
ui32Register |= USB_TXCSRH1_ISO;
|
||||
}
|
||||
|
||||
HWREGB(USB_TXCSRH_BASE(ep_idx)) = ui32Register | USB_TXCSRH1_MODE;
|
||||
|
||||
// Reset the Data toggle to zero.
|
||||
if (HWREGB(USB_TXCSRL_BASE(ep_idx)) & USB_TXCSRL1_TXRDY)
|
||||
HWREGB(USB_TXCSRL_BASE(ep_idx)) = (USB_TXCSRL1_CLRDT | USB_TXCSRL1_FLUSH);
|
||||
else
|
||||
HWREGB(USB_TXCSRL_BASE(ep_idx)) = USB_TXCSRL1_CLRDT;
|
||||
}
|
||||
|
||||
musb_set_active_ep(old_ep_idx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_close(uint8_t busid, const uint8_t ep)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_set_stall(uint8_t busid, const uint8_t ep)
|
||||
{
|
||||
uint8_t ep_idx = USB_EP_GET_IDX(ep);
|
||||
uint8_t old_ep_idx;
|
||||
|
||||
old_ep_idx = musb_get_active_ep();
|
||||
musb_set_active_ep(ep_idx);
|
||||
|
||||
if (USB_EP_DIR_IS_OUT(ep)) {
|
||||
if (ep_idx == 0x00) {
|
||||
usb_ep0_state = USB_EP0_STATE_STALL;
|
||||
HWREGB(USB_TXCSRL_BASE(ep_idx)) |= (USB_CSRL0_STALL | USB_CSRL0_RXRDYC);
|
||||
} else {
|
||||
HWREGB(USB_RXCSRL_BASE(ep_idx)) |= USB_RXCSRL1_STALL;
|
||||
}
|
||||
} else {
|
||||
if (ep_idx == 0x00) {
|
||||
usb_ep0_state = USB_EP0_STATE_STALL;
|
||||
HWREGB(USB_TXCSRL_BASE(ep_idx)) |= (USB_CSRL0_STALL | USB_CSRL0_RXRDYC);
|
||||
} else {
|
||||
HWREGB(USB_TXCSRL_BASE(ep_idx)) |= USB_TXCSRL1_STALL;
|
||||
}
|
||||
}
|
||||
|
||||
musb_set_active_ep(old_ep_idx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_clear_stall(uint8_t busid, const uint8_t ep)
|
||||
{
|
||||
uint8_t ep_idx = USB_EP_GET_IDX(ep);
|
||||
uint8_t old_ep_idx;
|
||||
|
||||
old_ep_idx = musb_get_active_ep();
|
||||
musb_set_active_ep(ep_idx);
|
||||
|
||||
if (USB_EP_DIR_IS_OUT(ep)) {
|
||||
if (ep_idx == 0x00) {
|
||||
HWREGB(USB_TXCSRL_BASE(ep_idx)) &= ~USB_CSRL0_STALLED;
|
||||
} else {
|
||||
// Clear the stall on an OUT endpoint.
|
||||
HWREGB(USB_RXCSRL_BASE(ep_idx)) &= ~(USB_RXCSRL1_STALL | USB_RXCSRL1_STALLED);
|
||||
// Reset the data toggle.
|
||||
HWREGB(USB_RXCSRL_BASE(ep_idx)) |= USB_RXCSRL1_CLRDT;
|
||||
}
|
||||
} else {
|
||||
if (ep_idx == 0x00) {
|
||||
HWREGB(USB_TXCSRL_BASE(ep_idx)) &= ~USB_CSRL0_STALLED;
|
||||
} else {
|
||||
// Clear the stall on an IN endpoint.
|
||||
HWREGB(USB_TXCSRL_BASE(ep_idx)) &= ~(USB_TXCSRL1_STALL | USB_TXCSRL1_STALLED);
|
||||
// Reset the data toggle.
|
||||
HWREGB(USB_TXCSRL_BASE(ep_idx)) |= USB_TXCSRL1_CLRDT;
|
||||
}
|
||||
}
|
||||
|
||||
musb_set_active_ep(old_ep_idx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_is_stalled(uint8_t busid, const uint8_t ep, uint8_t *stalled)
|
||||
{
|
||||
uint8_t ep_idx = USB_EP_GET_IDX(ep);
|
||||
uint8_t old_ep_idx;
|
||||
|
||||
old_ep_idx = musb_get_active_ep();
|
||||
musb_set_active_ep(ep_idx);
|
||||
|
||||
if (USB_EP_DIR_IS_OUT(ep)) {
|
||||
if (HWREGB(USB_RXCSRL_BASE(ep_idx)) & USB_RXCSRL1_STALL) {
|
||||
*stalled = 1;
|
||||
} else {
|
||||
*stalled = 0;
|
||||
}
|
||||
} else {
|
||||
if (HWREGB(USB_TXCSRL_BASE(ep_idx)) & USB_TXCSRL1_STALL) {
|
||||
*stalled = 1;
|
||||
} else {
|
||||
*stalled = 0;
|
||||
}
|
||||
}
|
||||
musb_set_active_ep(old_ep_idx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_start_write(uint8_t busid, const uint8_t ep, const uint8_t *data, uint32_t data_len)
|
||||
{
|
||||
uint8_t ep_idx = USB_EP_GET_IDX(ep);
|
||||
uint8_t old_ep_idx;
|
||||
|
||||
if (!data && data_len) {
|
||||
return -1;
|
||||
}
|
||||
if (!g_musb_udc.in_ep[ep_idx].ep_enable) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
old_ep_idx = musb_get_active_ep();
|
||||
musb_set_active_ep(ep_idx);
|
||||
|
||||
if (HWREGB(USB_TXCSRL_BASE(ep_idx)) & USB_TXCSRL1_TXRDY) {
|
||||
musb_set_active_ep(old_ep_idx);
|
||||
return -3;
|
||||
}
|
||||
|
||||
g_musb_udc.in_ep[ep_idx].xfer_buf = (uint8_t *)data;
|
||||
g_musb_udc.in_ep[ep_idx].xfer_len = data_len;
|
||||
g_musb_udc.in_ep[ep_idx].actual_xfer_len = 0;
|
||||
|
||||
if (data_len == 0) {
|
||||
if (ep_idx == 0x00) {
|
||||
if (g_musb_udc.setup.wLength == 0) {
|
||||
usb_ep0_state = USB_EP0_STATE_IN_STATUS;
|
||||
} else {
|
||||
usb_ep0_state = USB_EP0_STATE_IN_ZLP;
|
||||
}
|
||||
HWREGB(USB_TXCSRL_BASE(ep_idx)) = (USB_CSRL0_TXRDY | USB_CSRL0_DATAEND);
|
||||
} else {
|
||||
HWREGB(USB_TXCSRL_BASE(ep_idx)) = USB_TXCSRL1_TXRDY;
|
||||
HWREGH(USB_BASE + MUSB_TXIE_OFFSET) |= (1 << ep_idx);
|
||||
}
|
||||
musb_set_active_ep(old_ep_idx);
|
||||
return 0;
|
||||
}
|
||||
data_len = MIN(data_len, g_musb_udc.in_ep[ep_idx].ep_mps);
|
||||
|
||||
musb_write_packet(ep_idx, (uint8_t *)data, data_len);
|
||||
HWREGH(USB_BASE + MUSB_TXIE_OFFSET) |= (1 << ep_idx);
|
||||
|
||||
if (ep_idx == 0x00) {
|
||||
usb_ep0_state = USB_EP0_STATE_IN_DATA;
|
||||
if (data_len < g_musb_udc.in_ep[ep_idx].ep_mps) {
|
||||
HWREGB(USB_TXCSRL_BASE(ep_idx)) = (USB_CSRL0_TXRDY | USB_CSRL0_DATAEND);
|
||||
} else {
|
||||
HWREGB(USB_TXCSRL_BASE(ep_idx)) = USB_CSRL0_TXRDY;
|
||||
}
|
||||
} else {
|
||||
HWREGB(USB_TXCSRL_BASE(ep_idx)) = USB_TXCSRL1_TXRDY;
|
||||
}
|
||||
|
||||
musb_set_active_ep(old_ep_idx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_start_read(uint8_t busid, const uint8_t ep, uint8_t *data, uint32_t data_len)
|
||||
{
|
||||
uint8_t ep_idx = USB_EP_GET_IDX(ep);
|
||||
uint8_t old_ep_idx;
|
||||
|
||||
if (!data && data_len) {
|
||||
return -1;
|
||||
}
|
||||
if (!g_musb_udc.out_ep[ep_idx].ep_enable) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
old_ep_idx = musb_get_active_ep();
|
||||
musb_set_active_ep(ep_idx);
|
||||
|
||||
g_musb_udc.out_ep[ep_idx].xfer_buf = data;
|
||||
g_musb_udc.out_ep[ep_idx].xfer_len = data_len;
|
||||
g_musb_udc.out_ep[ep_idx].actual_xfer_len = 0;
|
||||
|
||||
if (data_len == 0) {
|
||||
if (ep_idx == 0) {
|
||||
usb_ep0_state = USB_EP0_STATE_SETUP;
|
||||
}
|
||||
musb_set_active_ep(old_ep_idx);
|
||||
return 0;
|
||||
}
|
||||
if (ep_idx == 0) {
|
||||
usb_ep0_state = USB_EP0_STATE_OUT_DATA;
|
||||
} else {
|
||||
HWREGH(USB_BASE + MUSB_RXIE_OFFSET) |= (1 << ep_idx);
|
||||
}
|
||||
musb_set_active_ep(old_ep_idx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void handle_ep0(void)
|
||||
{
|
||||
uint8_t ep_idx = 0; // EP0 index is always 0
|
||||
uint8_t ep0_status = HWREGB(USB_TXCSRL_BASE(ep_idx));
|
||||
uint16_t read_count;
|
||||
|
||||
if (ep0_status & USB_CSRL0_STALLED) {
|
||||
HWREGB(USB_TXCSRL_BASE(ep_idx)) &= ~USB_CSRL0_STALLED;
|
||||
usb_ep0_state = USB_EP0_STATE_SETUP;
|
||||
return;
|
||||
}
|
||||
|
||||
if (ep0_status & USB_CSRL0_SETEND) {
|
||||
HWREGB(USB_TXCSRL_BASE(ep_idx)) = USB_CSRL0_SETENDC;
|
||||
}
|
||||
|
||||
if (g_musb_udc.dev_addr > 0) {
|
||||
HWREGB(USB_BASE + MUSB_FADDR_OFFSET) = g_musb_udc.dev_addr;
|
||||
g_musb_udc.dev_addr = 0;
|
||||
}
|
||||
|
||||
switch (usb_ep0_state) {
|
||||
case USB_EP0_STATE_SETUP:
|
||||
if (ep0_status & USB_CSRL0_RXRDY) {
|
||||
read_count = HWREGH(USB_RXCOUNT_BASE(ep_idx));
|
||||
|
||||
if (read_count != 8) {
|
||||
return;
|
||||
}
|
||||
|
||||
musb_read_packet(0, (uint8_t *)&g_musb_udc.setup, 8);
|
||||
if (g_musb_udc.setup.wLength) {
|
||||
HWREGB(USB_TXCSRL_BASE(ep_idx)) = USB_CSRL0_RXRDYC;
|
||||
} else {
|
||||
HWREGB(USB_TXCSRL_BASE(ep_idx)) = (USB_CSRL0_RXRDYC | USB_CSRL0_DATAEND);
|
||||
}
|
||||
|
||||
usbd_event_ep0_setup_complete_handler(0, (uint8_t *)&g_musb_udc.setup);
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_EP0_STATE_IN_DATA:
|
||||
if (g_musb_udc.in_ep[0].xfer_len > g_musb_udc.in_ep[0].ep_mps) {
|
||||
g_musb_udc.in_ep[0].actual_xfer_len += g_musb_udc.in_ep[0].ep_mps;
|
||||
g_musb_udc.in_ep[0].xfer_len -= g_musb_udc.in_ep[0].ep_mps;
|
||||
} else {
|
||||
g_musb_udc.in_ep[0].actual_xfer_len += g_musb_udc.in_ep[0].xfer_len;
|
||||
g_musb_udc.in_ep[0].xfer_len = 0;
|
||||
}
|
||||
|
||||
usbd_event_ep_in_complete_handler(0, 0x80, g_musb_udc.in_ep[0].actual_xfer_len);
|
||||
|
||||
break;
|
||||
case USB_EP0_STATE_OUT_DATA:
|
||||
if (ep0_status & USB_CSRL0_RXRDY) {
|
||||
read_count = HWREGH(USB_RXCOUNT_BASE(ep_idx));
|
||||
|
||||
musb_read_packet(0, g_musb_udc.out_ep[0].xfer_buf, read_count);
|
||||
g_musb_udc.out_ep[0].xfer_buf += read_count;
|
||||
g_musb_udc.out_ep[0].actual_xfer_len += read_count;
|
||||
|
||||
if (read_count < g_musb_udc.out_ep[0].ep_mps) {
|
||||
usbd_event_ep_out_complete_handler(0, 0x00, g_musb_udc.out_ep[0].actual_xfer_len);
|
||||
HWREGB(USB_TXCSRL_BASE(ep_idx)) = (USB_CSRL0_RXRDYC | USB_CSRL0_DATAEND);
|
||||
usb_ep0_state = USB_EP0_STATE_IN_STATUS;
|
||||
} else {
|
||||
HWREGB(USB_TXCSRL_BASE(ep_idx)) = USB_CSRL0_RXRDYC;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case USB_EP0_STATE_IN_STATUS:
|
||||
case USB_EP0_STATE_IN_ZLP:
|
||||
usb_ep0_state = USB_EP0_STATE_SETUP;
|
||||
usbd_event_ep_in_complete_handler(0, 0x80, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void USBD_IRQHandler(uint8_t busid)
|
||||
{
|
||||
uint32_t is;
|
||||
uint32_t txis;
|
||||
uint32_t rxis;
|
||||
uint8_t old_ep_idx;
|
||||
uint8_t ep_idx;
|
||||
uint16_t write_count, read_count;
|
||||
|
||||
if (HWREGB(USB_BASE + MUSB_DEVCTL_OFFSET) & USB_DEVCTL_HOST) {
|
||||
return;
|
||||
}
|
||||
|
||||
is = HWREGB(USB_BASE + MUSB_IS_OFFSET);
|
||||
txis = HWREGH(USB_BASE + MUSB_TXIS_OFFSET);
|
||||
rxis = HWREGH(USB_BASE + MUSB_RXIS_OFFSET);
|
||||
|
||||
HWREGB(USB_BASE + MUSB_IS_OFFSET) = is;
|
||||
|
||||
old_ep_idx = musb_get_active_ep();
|
||||
|
||||
/* Receive a reset signal from the USB bus */
|
||||
if (is & USB_IS_RESET) {
|
||||
memset(&g_musb_udc, 0, sizeof(struct musb_udc));
|
||||
usbd_event_reset_handler(0);
|
||||
HWREGH(USB_BASE + MUSB_TXIE_OFFSET) = USB_TXIE_EP0;
|
||||
HWREGH(USB_BASE + MUSB_RXIE_OFFSET) = 0;
|
||||
|
||||
usb_ep0_state = USB_EP0_STATE_SETUP;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USBDEV_SOF_ENABLE
|
||||
if (is & USB_IS_SOF) {
|
||||
usbd_event_sof_handler(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (is & USB_IS_RESUME) {
|
||||
usbd_event_resume_handler(0);
|
||||
}
|
||||
|
||||
if (is & USB_IS_SUSPEND) {
|
||||
usbd_event_suspend_handler(0);
|
||||
}
|
||||
|
||||
txis &= HWREGH(USB_BASE + MUSB_TXIE_OFFSET);
|
||||
/* Handle EP0 interrupt */
|
||||
if (txis & USB_TXIE_EP0) {
|
||||
HWREGH(USB_BASE + MUSB_TXIS_OFFSET) = USB_TXIE_EP0;
|
||||
musb_set_active_ep(0);
|
||||
handle_ep0();
|
||||
txis &= ~USB_TXIE_EP0;
|
||||
}
|
||||
|
||||
ep_idx = 1;
|
||||
while (txis) {
|
||||
if (txis & (1 << ep_idx)) {
|
||||
musb_set_active_ep(ep_idx);
|
||||
HWREGH(USB_BASE + MUSB_TXIS_OFFSET) = (1 << ep_idx);
|
||||
if (HWREGB(USB_TXCSRL_BASE(ep_idx)) & USB_TXCSRL1_UNDRN) {
|
||||
HWREGB(USB_TXCSRL_BASE(ep_idx)) &= ~USB_TXCSRL1_UNDRN;
|
||||
}
|
||||
|
||||
if (g_musb_udc.in_ep[ep_idx].xfer_len > g_musb_udc.in_ep[ep_idx].ep_mps) {
|
||||
g_musb_udc.in_ep[ep_idx].xfer_buf += g_musb_udc.in_ep[ep_idx].ep_mps;
|
||||
g_musb_udc.in_ep[ep_idx].actual_xfer_len += g_musb_udc.in_ep[ep_idx].ep_mps;
|
||||
g_musb_udc.in_ep[ep_idx].xfer_len -= g_musb_udc.in_ep[ep_idx].ep_mps;
|
||||
} else {
|
||||
g_musb_udc.in_ep[ep_idx].xfer_buf += g_musb_udc.in_ep[ep_idx].xfer_len;
|
||||
g_musb_udc.in_ep[ep_idx].actual_xfer_len += g_musb_udc.in_ep[ep_idx].xfer_len;
|
||||
g_musb_udc.in_ep[ep_idx].xfer_len = 0;
|
||||
}
|
||||
|
||||
if (g_musb_udc.in_ep[ep_idx].xfer_len == 0) {
|
||||
HWREGH(USB_BASE + MUSB_TXIE_OFFSET) &= ~(1 << ep_idx);
|
||||
usbd_event_ep_in_complete_handler(0, ep_idx | 0x80, g_musb_udc.in_ep[ep_idx].actual_xfer_len);
|
||||
} else {
|
||||
write_count = MIN(g_musb_udc.in_ep[ep_idx].xfer_len, g_musb_udc.in_ep[ep_idx].ep_mps);
|
||||
|
||||
musb_write_packet(ep_idx, g_musb_udc.in_ep[ep_idx].xfer_buf, write_count);
|
||||
HWREGB(USB_TXCSRL_BASE(ep_idx)) = USB_TXCSRL1_TXRDY;
|
||||
}
|
||||
|
||||
txis &= ~(1 << ep_idx);
|
||||
}
|
||||
ep_idx++;
|
||||
}
|
||||
|
||||
rxis &= HWREGH(USB_BASE + MUSB_RXIE_OFFSET);
|
||||
ep_idx = 1;
|
||||
while (rxis) {
|
||||
if (rxis & (1 << ep_idx)) {
|
||||
musb_set_active_ep(ep_idx);
|
||||
HWREGH(USB_BASE + MUSB_RXIS_OFFSET) = (1 << ep_idx);
|
||||
if (HWREGB(USB_RXCSRL_BASE(ep_idx)) & USB_RXCSRL1_RXRDY) {
|
||||
read_count = HWREGH(USB_RXCOUNT_BASE(ep_idx));
|
||||
|
||||
musb_read_packet(ep_idx, g_musb_udc.out_ep[ep_idx].xfer_buf, read_count);
|
||||
HWREGB(USB_RXCSRL_BASE(ep_idx)) &= ~(USB_RXCSRL1_RXRDY);
|
||||
|
||||
g_musb_udc.out_ep[ep_idx].xfer_buf += read_count;
|
||||
g_musb_udc.out_ep[ep_idx].actual_xfer_len += read_count;
|
||||
g_musb_udc.out_ep[ep_idx].xfer_len -= read_count;
|
||||
|
||||
if ((read_count < g_musb_udc.out_ep[ep_idx].ep_mps) || (g_musb_udc.out_ep[ep_idx].xfer_len == 0)) {
|
||||
HWREGH(USB_BASE + MUSB_RXIE_OFFSET) &= ~(1 << ep_idx);
|
||||
usbd_event_ep_out_complete_handler(0, ep_idx, g_musb_udc.out_ep[ep_idx].actual_xfer_len);
|
||||
} else {
|
||||
}
|
||||
}
|
||||
|
||||
rxis &= ~(1 << ep_idx);
|
||||
}
|
||||
ep_idx++;
|
||||
}
|
||||
|
||||
musb_set_active_ep(old_ep_idx);
|
||||
}
|
||||
@@ -0,0 +1,326 @@
|
||||
/*
|
||||
* Copyright (c) 2024, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "sys_driver.h"
|
||||
#include "gpio_driver.h"
|
||||
#include <driver/gpio.h>
|
||||
#include <driver/gpio_types.h>
|
||||
#include <driver/int.h>
|
||||
#include "bk_misc.h"
|
||||
#include "usbd_core.h"
|
||||
#include "usbh_core.h"
|
||||
#include "usb_musb_reg.h"
|
||||
|
||||
#define USB_BASE_ADDR SOC_USB_REG_BASE
|
||||
|
||||
#if (CONFIG_SOC_BK7271)
|
||||
#define REG_AHB2_USB_OTG_CFG (*((volatile unsigned char *)(USB_BASE_ADDR + 0x80)))
|
||||
#define REG_AHB2_USB_DMA_ENDP (*((volatile unsigned char *)(USB_BASE_ADDR + 0x84)))
|
||||
#define REG_AHB2_USB_VTH (*((volatile unsigned char *)(USB_BASE_ADDR + 0x88)))
|
||||
#define REG_AHB2_USB_GEN (*((volatile unsigned char *)(USB_BASE_ADDR + 0x8C)))
|
||||
#define REG_AHB2_USB_STAT (*((volatile unsigned char *)(USB_BASE_ADDR + 0x90)))
|
||||
#define REG_AHB2_USB_INT (*((volatile unsigned char *)(USB_BASE_ADDR + 0x94)))
|
||||
#define REG_AHB2_USB_RESET (*((volatile unsigned char *)(USB_BASE_ADDR + 0x98)))
|
||||
#define REG_AHB2_USB_DEV_CFG (*((volatile unsigned char *)(USB_BASE_ADDR + 0x9C)))
|
||||
#elif (CONFIG_SOC_BK7256XX)
|
||||
#define REG_AHB2_USB_OTG_CFG (*((volatile unsigned char *)(USB_BASE_ADDR + 0x280)))
|
||||
#define REG_AHB2_USB_DMA_ENDP (*((volatile unsigned char *)(USB_BASE_ADDR + 0x284)))
|
||||
#define REG_AHB2_USB_VTH (*((volatile unsigned char *)(USB_BASE_ADDR + 0x288)))
|
||||
#define REG_AHB2_USB_GEN (*((volatile unsigned char *)(USB_BASE_ADDR + 0x28C)))
|
||||
#define REG_AHB2_USB_STAT (*((volatile unsigned char *)(USB_BASE_ADDR + 0x290)))
|
||||
#define REG_AHB2_USB_INT (*((volatile unsigned char *)(USB_BASE_ADDR + 0x294)))
|
||||
#define REG_AHB2_USB_RESET (*((volatile unsigned char *)(USB_BASE_ADDR + 0x298)))
|
||||
#define REG_AHB2_USB_DEV_CFG (*((volatile unsigned char *)(USB_BASE_ADDR + 0x29C)))
|
||||
#elif (CONFIG_SOC_BK7236XX) || (CONFIG_SOC_BK7239XX) || (CONFIG_SOC_BK7286XX)
|
||||
#define REG_AHB2_USB_DEVICE_ID (*((volatile unsigned char *)(USB_BASE_ADDR + 0x280)))
|
||||
#define REG_AHB2_USB_VERSION_ID (*((volatile unsigned char *)(USB_BASE_ADDR + 0x284)))
|
||||
#define REG_AHB2_USB_GLOBAL_CTRL (*((volatile unsigned char *)(USB_BASE_ADDR + 0x288)))
|
||||
#define REG_AHB2_USB_DEVICE_STATUS (*((volatile unsigned char *)(USB_BASE_ADDR + 0x28c)))
|
||||
#define REG_AHB2_USB_OTG_CFG (*((volatile unsigned char *)(USB_BASE_ADDR + 0x290)))
|
||||
#define REG_AHB2_USB_DMA_ENDP (*((volatile unsigned char *)(USB_BASE_ADDR + 0x294)))
|
||||
#define REG_AHB2_USB_VTH (*((volatile unsigned char *)(USB_BASE_ADDR + 0x298)))
|
||||
#define REG_AHB2_USB_GEN (*((volatile unsigned char *)(USB_BASE_ADDR + 0x29C)))
|
||||
#define REG_AHB2_USB_STAT (*((volatile unsigned char *)(USB_BASE_ADDR + 0x2A0)))
|
||||
#define REG_AHB2_USB_INT (*((volatile unsigned char *)(USB_BASE_ADDR + 0x2A4)))
|
||||
#define REG_AHB2_USB_RESET (*((volatile unsigned char *)(USB_BASE_ADDR + 0x2A8)))
|
||||
#define REG_AHB2_USB_DEV_CFG (*((volatile unsigned char *)(USB_BASE_ADDR + 0x2AC)))
|
||||
|
||||
#define REG_USB_USR_700 (*((volatile unsigned long *)(USB_BASE_ADDR + 0x700)))
|
||||
#define REG_USB_USR_704 (*((volatile unsigned long *)(USB_BASE_ADDR + 0x704)))
|
||||
#define REG_USB_USR_708 (*((volatile unsigned long *)(USB_BASE_ADDR + 0x708)))
|
||||
#define REG_USB_USR_70C (*((volatile unsigned long *)(USB_BASE_ADDR + 0x70C)))
|
||||
#define REG_USB_USR_710 (*((volatile unsigned long *)(USB_BASE_ADDR + 0x710)))
|
||||
#define REG_USB_USR_714 (*((volatile unsigned long *)(USB_BASE_ADDR + 0x714)))
|
||||
#define REG_USB_PHY_00 (*((volatile unsigned long *)(USB_BASE_ADDR + 0x400)))
|
||||
#define REG_USB_PHY_01 (*((volatile unsigned long *)(USB_BASE_ADDR + 0x404)))
|
||||
#endif
|
||||
|
||||
#define USB_DP_CAPABILITY_VALUE (0xF)
|
||||
#define USB_DN_CAPABILITY_VALUE (0xF)
|
||||
|
||||
#define NANENG_PHY_FC_REG01 (0x01 * 4)
|
||||
#define NANENG_PHY_FC_REG02 (0x02 * 4)
|
||||
#define NANENG_PHY_FC_REG03 (0x03 * 4)
|
||||
#define NANENG_PHY_FC_REG04 (0x04 * 4)
|
||||
#define NANENG_PHY_FC_REG05 (0x05 * 4)
|
||||
#define NANENG_PHY_FC_REG06 (0x06 * 4)
|
||||
#define NANENG_PHY_FC_REG07 (0x07 * 4)
|
||||
#define NANENG_PHY_FC_REG08 (0x08 * 4)
|
||||
#define NANENG_PHY_FC_REG09 (0x09 * 4)
|
||||
#define NANENG_PHY_FC_REG0A (0x0A * 4)
|
||||
#define NANENG_PHY_FC_REG0B (0x0B * 4)
|
||||
#define NANENG_PHY_FC_REG0C (0x0C * 4)
|
||||
#define NANENG_PHY_FC_REG0D (0x0D * 4)
|
||||
#define NANENG_PHY_FC_REG0E (0x0E * 4)
|
||||
#define NANENG_PHY_FC_REG0F (0x0F * 4)
|
||||
#define NANENG_PHY_FC_REG0F_BYTE 0x0F
|
||||
|
||||
#define NANENG_PHY_FC_REG10 (0x10 * 4)
|
||||
#define NANENG_PHY_FC_REG11 (0x11 * 4)
|
||||
#define NANENG_PHY_FC_REG12 (0x12 * 4)
|
||||
#define NANENG_PHY_FC_REG13 (0x13 * 4)
|
||||
#define NANENG_PHY_FC_REG14 (0x14 * 4)
|
||||
#define NANENG_PHY_FC_REG15 (0x15 * 4)
|
||||
#define NANENG_PHY_FC_REG16 (0x16 * 4)
|
||||
#define NANENG_PHY_FC_REG17 (0x17 * 4)
|
||||
#define NANENG_PHY_FC_REG18 (0x18 * 4)
|
||||
#define NANENG_PHY_FC_REG19 (0x19 * 4)
|
||||
#define NANENG_PHY_FC_REG1A (0x1A * 4)
|
||||
#define NANENG_PHY_FC_REG1B (0x1B * 4)
|
||||
#define NANENG_PHY_FC_REG1C (0x1C * 4)
|
||||
#define NANENG_PHY_FC_REG1D (0x1D * 4)
|
||||
#define NANENG_PHY_FC_REG1E (0x1E * 4)
|
||||
#define NANENG_PHY_FC_REG1F (0x1F * 4)
|
||||
|
||||
#if CONFIG_USB_MUSB_EP_NUM != 8
|
||||
#error beken chips only support 8 endpoints
|
||||
#endif
|
||||
|
||||
#if CONFIG_USB_MUSB_PIPE_NUM != 8
|
||||
#error beken chips only support 8 pipes
|
||||
#endif
|
||||
|
||||
// clang-format off
|
||||
static struct musb_fifo_cfg musb_device_table[] = {
|
||||
{ .ep_num = 0, .style = FIFO_TXRX, .maxpacket = 64, },
|
||||
{ .ep_num = 1, .style = FIFO_TX, .maxpacket = 1024, },
|
||||
{ .ep_num = 1, .style = FIFO_RX, .maxpacket = 1024, },
|
||||
{ .ep_num = 2, .style = FIFO_TX, .maxpacket = 512, },
|
||||
{ .ep_num = 2, .style = FIFO_RX, .maxpacket = 512, },
|
||||
{ .ep_num = 3, .style = FIFO_TX, .maxpacket = 512, },
|
||||
{ .ep_num = 3, .style = FIFO_RX, .maxpacket = 512, },
|
||||
{ .ep_num = 4, .style = FIFO_TX, .maxpacket = 512, },
|
||||
{ .ep_num = 4, .style = FIFO_RX, .maxpacket = 512, },
|
||||
{ .ep_num = 5, .style = FIFO_TX, .maxpacket = 512, },
|
||||
{ .ep_num = 5, .style = FIFO_RX, .maxpacket = 512, },
|
||||
{ .ep_num = 6, .style = FIFO_TXRX, .maxpacket = 512, },
|
||||
{ .ep_num = 7, .style = FIFO_TXRX, .maxpacket = 512, }
|
||||
};
|
||||
|
||||
static struct musb_fifo_cfg musb_host_table[] = {
|
||||
{ .ep_num = 0, .style = FIFO_TXRX, .maxpacket = 64, },
|
||||
{ .ep_num = 1, .style = FIFO_TX, .maxpacket = 1024, },
|
||||
{ .ep_num = 1, .style = FIFO_RX, .maxpacket = 1024, },
|
||||
{ .ep_num = 2, .style = FIFO_TX, .maxpacket = 512, },
|
||||
{ .ep_num = 2, .style = FIFO_RX, .maxpacket = 512, },
|
||||
{ .ep_num = 3, .style = FIFO_TX, .maxpacket = 512, },
|
||||
{ .ep_num = 3, .style = FIFO_RX, .maxpacket = 512, },
|
||||
{ .ep_num = 4, .style = FIFO_TX, .maxpacket = 512, },
|
||||
{ .ep_num = 4, .style = FIFO_RX, .maxpacket = 512, },
|
||||
{ .ep_num = 5, .style = FIFO_TX, .maxpacket = 512, },
|
||||
{ .ep_num = 5, .style = FIFO_RX, .maxpacket = 512, },
|
||||
{ .ep_num = 6, .style = FIFO_TXRX, .maxpacket = 512, },
|
||||
{ .ep_num = 7, .style = FIFO_TXRX, .maxpacket = 512, }
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
uint8_t usbd_get_musb_fifo_cfg(struct musb_fifo_cfg **cfg)
|
||||
{
|
||||
*cfg = musb_device_table;
|
||||
return sizeof(musb_device_table) / sizeof(musb_device_table[0]);
|
||||
}
|
||||
|
||||
uint8_t usbh_get_musb_fifo_cfg(struct musb_fifo_cfg **cfg)
|
||||
{
|
||||
*cfg = musb_host_table;
|
||||
return sizeof(musb_host_table) / sizeof(musb_host_table[0]);
|
||||
}
|
||||
|
||||
uint32_t usb_get_musb_ram_size(void)
|
||||
{
|
||||
return 8192;
|
||||
}
|
||||
|
||||
extern void USBD_IRQHandler(uint8_t busid);
|
||||
|
||||
void USBD_IRQ(void)
|
||||
{
|
||||
USBD_IRQHandler(0);
|
||||
}
|
||||
|
||||
static void bk_analog_layer_usb_sys_related_ops(uint32_t usb_mode, bool ops)
|
||||
{
|
||||
extern void delay(INT32 num);
|
||||
|
||||
#if 0
|
||||
sys_drv_usb_analog_phy_en(ops, NULL);
|
||||
sys_drv_usb_analog_speed_en(ops, NULL);
|
||||
sys_drv_usb_analog_ckmcu_en(ops, NULL);
|
||||
#endif
|
||||
if (ops) {
|
||||
sys_drv_usb_clock_ctrl(true, NULL);
|
||||
delay(100);
|
||||
#if 0
|
||||
sys_drv_usb_analog_deepsleep_en(false);
|
||||
#endif
|
||||
sys_drv_usb_analog_dp_capability(USB_DP_CAPABILITY_VALUE);
|
||||
sys_drv_usb_analog_dn_capability(USB_DN_CAPABILITY_VALUE);
|
||||
if (!sys_hal_psram_ldo_status()) {
|
||||
sys_drv_psram_ldo_enable(1);
|
||||
}
|
||||
sys_drv_usb_analog_phy_en(1, NULL);
|
||||
|
||||
if (usb_mode == 0) {
|
||||
REG_USB_USR_708 = 0x0;
|
||||
REG_USB_USR_710 &= ~(0x1 << 7);
|
||||
delay(100);
|
||||
|
||||
REG_USB_USR_710 |= (0x1 << 15);
|
||||
//REG_USB_USR_710 |= (0x1<<14);
|
||||
REG_USB_USR_710 |= (0x1 << 16);
|
||||
REG_USB_USR_710 |= (0x1 << 17);
|
||||
REG_USB_USR_710 |= (0x1 << 18);
|
||||
REG_USB_USR_710 |= (0x1 << 19);
|
||||
REG_USB_USR_710 &= ~(0x1 << 20);
|
||||
REG_USB_USR_710 |= (0x1 << 21);
|
||||
REG_USB_USR_710 |= (0x0 << 0);
|
||||
REG_USB_USR_710 |= (0x1 << 5);
|
||||
REG_USB_USR_710 |= (0x1 << 6);
|
||||
REG_USB_USR_710 |= (0x1 << 9);
|
||||
REG_USB_USR_710 |= (0x1 << 10);
|
||||
REG_USB_USR_710 |= (0x1 << 1);
|
||||
|
||||
REG_USB_USR_710 |= (0x1 << 7);
|
||||
REG_USB_USR_708 = 0x1;
|
||||
#if 0
|
||||
REG_USB_PHY_00 = 0x08;
|
||||
REG_USB_PHY_01 = 0x02;
|
||||
REG_USB_USR_710 |= (0x1<< 8);
|
||||
while(1){
|
||||
reg = REG_USB_USR_70C;
|
||||
if(reg & 0x100){
|
||||
USB_DRIVER_LOGI("SelfTest Fin!\r\n");
|
||||
USB_DRIVER_LOGI("test end!\r\n");
|
||||
break;
|
||||
} else {
|
||||
USB_DRIVER_LOGI("70c_reg:0x%x\r\n", reg);
|
||||
delay(10000);
|
||||
}
|
||||
}
|
||||
REG_USB_PHY_00 &= ~0x08;
|
||||
REG_USB_PHY_01 &= ~0x02;
|
||||
REG_USB_USR_710 &= ~(0x1<< 8);
|
||||
#endif
|
||||
} else {
|
||||
REG_USB_USR_710 |= (0x1 << 15);
|
||||
REG_USB_USR_710 |= (0x1 << 14);
|
||||
REG_USB_USR_710 |= (0x1 << 16);
|
||||
REG_USB_USR_710 |= (0x1 << 17);
|
||||
REG_USB_USR_710 |= (0x1 << 18);
|
||||
REG_USB_USR_710 |= (0x1 << 19);
|
||||
REG_USB_USR_710 &= ~(0x1 << 20);
|
||||
REG_USB_USR_710 |= (0x1 << 21);
|
||||
REG_USB_USR_710 |= (0x0 << 0);
|
||||
REG_USB_USR_710 |= (0x1 << 5);
|
||||
REG_USB_USR_710 |= (0x1 << 6);
|
||||
REG_USB_USR_710 |= (0x1 << 9);
|
||||
REG_USB_USR_710 |= (0x1 << 10);
|
||||
REG_USB_USR_710 |= (0x1 << 7);
|
||||
|
||||
REG_USB_USR_708 = 0x1;
|
||||
}
|
||||
} else {
|
||||
sys_drv_usb_analog_phy_en(0, NULL);
|
||||
sys_drv_usb_clock_ctrl(false, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void usb_dc_low_level_init(void)
|
||||
{
|
||||
#if CONFIG_SYS_CPU0
|
||||
bk_pm_module_vote_sleep_ctrl(PM_SLEEP_MODULE_NAME_USB_1, 0x0, 0x0);
|
||||
#endif
|
||||
bk_analog_layer_usb_sys_related_ops(1, true);
|
||||
bk_gpio_set_output_high(CONFIG_USB_VBAT_CONTROL_GPIO_ID);
|
||||
|
||||
bk_pm_module_vote_cpu_freq(PM_DEV_ID_USB_1, PM_CPU_FRQ_120M);
|
||||
|
||||
sys_hal_usb_analog_phy_en(true);
|
||||
|
||||
sys_drv_usb_clock_ctrl(true, NULL);
|
||||
sys_drv_int_enable(USB_INTERRUPT_CTRL_BIT);
|
||||
|
||||
bk_int_isr_register(INT_SRC_USB, USBD_IRQ, NULL);
|
||||
bk_int_set_priority(INT_SRC_USB, 2);
|
||||
}
|
||||
|
||||
void usb_dc_low_level_deinit(void)
|
||||
{
|
||||
bk_pm_module_vote_cpu_freq(PM_DEV_ID_USB_1, PM_CPU_FRQ_DEFAULT);
|
||||
sys_hal_usb_analog_phy_en(false);
|
||||
sys_drv_usb_clock_ctrl(false, NULL);
|
||||
sys_drv_int_disable(USB_INTERRUPT_CTRL_BIT);
|
||||
bk_int_isr_unregister(INT_SRC_USB);
|
||||
bk_analog_layer_usb_sys_related_ops(1, false);
|
||||
sys_drv_dev_clk_pwr_up(CLK_PWR_ID_USB_1, CLK_PWR_CTRL_PWR_DOWN);
|
||||
}
|
||||
|
||||
void usbd_musb_delay_ms(uint8_t ms)
|
||||
{
|
||||
/* implement later */
|
||||
}
|
||||
|
||||
extern void USBH_IRQHandler(uint8_t busid);
|
||||
|
||||
void USBH_IRQ(void)
|
||||
{
|
||||
USBH_IRQHandler(0);
|
||||
}
|
||||
|
||||
#define NANENG_PHY_CFG 1
|
||||
#define USB_PHY_BASE (SOC_USB_REG_BASE + 0x400)
|
||||
|
||||
#define HWREG(x) \
|
||||
(*((volatile uint32_t *)(x)))
|
||||
#define HWREGH(x) \
|
||||
(*((volatile uint16_t *)(x)))
|
||||
#define HWREGB(x) \
|
||||
(*((volatile uint8_t *)(x)))
|
||||
|
||||
void usb_hc_low_level_init(struct usbh_bus *bus)
|
||||
{
|
||||
#if CONFIG_SYS_CPU0
|
||||
bk_pm_module_vote_sleep_ctrl(PM_SLEEP_MODULE_NAME_USB_1, 0x0, 0x0);
|
||||
#endif
|
||||
bk_analog_layer_usb_sys_related_ops(0, true);
|
||||
bk_gpio_set_output_high(CONFIG_USB_VBAT_CONTROL_GPIO_ID);
|
||||
|
||||
#if NANENG_PHY_CFG
|
||||
//NANENG_PHY_CFG_HSRX_TEST
|
||||
HWREGB(USB_PHY_BASE + NANENG_PHY_FC_REG0F) |= (0x1 << 4);
|
||||
//disconnect value 640mv
|
||||
HWREGB(USB_PHY_BASE + NANENG_PHY_FC_REG0B) = 0x7C;
|
||||
#endif
|
||||
bk_int_isr_register(INT_SRC_USB, USBH_IRQ, NULL);
|
||||
sys_drv_int_enable(USB_INTERRUPT_CTRL_BIT);
|
||||
}
|
||||
|
||||
void usb_hc_low_level_deinit(struct usbh_bus *bus)
|
||||
{
|
||||
sys_drv_int_disable(USB_INTERRUPT_CTRL_BIT);
|
||||
bk_int_isr_unregister(INT_SRC_USB);
|
||||
sys_drv_dev_clk_pwr_up(CLK_PWR_ID_USB_1, CLK_PWR_CTRL_PWR_DOWN);
|
||||
bk_analog_layer_usb_sys_related_ops(0, false);
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2024, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usb_config.h"
|
||||
#include "stdint.h"
|
||||
#include "usb_musb_reg.h"
|
||||
|
||||
#if CONFIG_USB_MUSB_EP_NUM != 6
|
||||
#error es32 chips only support 6 endpoints
|
||||
#endif
|
||||
|
||||
#if CONFIG_USB_MUSB_PIPE_NUM != 6
|
||||
#error es32 chips only support 6 pipes
|
||||
#endif
|
||||
|
||||
// clang-format off
|
||||
static struct musb_fifo_cfg musb_device_table[] = {
|
||||
{ .ep_num = 0, .style = FIFO_TXRX, .maxpacket = 64, },
|
||||
{ .ep_num = 1, .style = FIFO_TXRX, .maxpacket = 1024, },
|
||||
{ .ep_num = 2, .style = FIFO_TXRX, .maxpacket = 512, },
|
||||
{ .ep_num = 3, .style = FIFO_TXRX, .maxpacket = 512, },
|
||||
{ .ep_num = 4, .style = FIFO_TXRX, .maxpacket = 512, },
|
||||
{ .ep_num = 5, .style = FIFO_TXRX, .maxpacket = 512, },
|
||||
};
|
||||
|
||||
static struct musb_fifo_cfg musb_host_table[] = {
|
||||
{ .ep_num = 0, .style = FIFO_TXRX, .maxpacket = 64, },
|
||||
{ .ep_num = 1, .style = FIFO_TXRX, .maxpacket = 1024, },
|
||||
{ .ep_num = 2, .style = FIFO_TXRX, .maxpacket = 512, },
|
||||
{ .ep_num = 3, .style = FIFO_TXRX, .maxpacket = 512, },
|
||||
{ .ep_num = 4, .style = FIFO_TXRX, .maxpacket = 512, },
|
||||
{ .ep_num = 5, .style = FIFO_TXRX, .maxpacket = 512, },
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
uint8_t usbd_get_musb_fifo_cfg(struct musb_fifo_cfg **cfg)
|
||||
{
|
||||
*cfg = musb_device_table;
|
||||
return sizeof(musb_device_table) / sizeof(musb_device_table[0]);
|
||||
}
|
||||
|
||||
uint8_t usbh_get_musb_fifo_cfg(struct musb_fifo_cfg **cfg)
|
||||
{
|
||||
*cfg = musb_host_table;
|
||||
return sizeof(musb_host_table) / sizeof(musb_host_table[0]);
|
||||
}
|
||||
|
||||
uint32_t usb_get_musb_ram_size(void)
|
||||
{
|
||||
return 4096;
|
||||
}
|
||||
|
||||
void usbd_musb_delay_ms(uint8_t ms)
|
||||
{
|
||||
/* implement later */
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright (c) 2025, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usbd_core.h"
|
||||
#include "usbh_core.h"
|
||||
#include "usb_musb_reg.h"
|
||||
|
||||
#undef USB_POWER_SOFTCONN
|
||||
#undef USB_DEVCTL_FSDEV
|
||||
#undef USB_DEVCTL_LSDEV
|
||||
#undef USB_DEVCTL_SESSION
|
||||
#undef USB_POWER_HSENAB
|
||||
#undef USB_POWER_HSMODE
|
||||
#undef USB_POWER_RESET
|
||||
#undef USB_POWER_RESUME
|
||||
|
||||
#ifndef CONFIG_USB_MUSB_SIFLI
|
||||
#error must define CONFIG_USB_MUSB_SIFLI when use sunxi chips
|
||||
#endif
|
||||
|
||||
#include "bf0_hal.h"
|
||||
|
||||
uint8_t usbd_get_musb_fifo_cfg(struct musb_fifo_cfg **cfg)
|
||||
{
|
||||
*cfg = NULL; // No FIFO configuration for this implementation, readonly
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t usbh_get_musb_fifo_cfg(struct musb_fifo_cfg **cfg)
|
||||
{
|
||||
*cfg = NULL; // No FIFO configuration for this implementation, readonly
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t usb_get_musb_ram_size(void)
|
||||
{
|
||||
return 0xFFFF; // No specific RAM size for this implementation
|
||||
}
|
||||
|
||||
void usbd_musb_delay_ms(uint8_t ms)
|
||||
{
|
||||
/* implement later */
|
||||
}
|
||||
|
||||
#ifdef PKG_CHERRYUSB_DEVICE
|
||||
void usb_dc_low_level_init(uint8_t busid)
|
||||
{
|
||||
HAL_RCC_EnableModule(RCC_MOD_USBC);
|
||||
|
||||
#ifdef SOC_SF32LB58X
|
||||
//hwp_usbc->utmicfg12 = hwp_usbc->utmicfg12 | 0x3; //set xo_clk_sel
|
||||
hwp_usbc->ldo25 = hwp_usbc->ldo25 | 0xa; //set psw_en and ldo25_en
|
||||
HAL_Delay(1);
|
||||
hwp_usbc->swcntl3 = 0x1; //set utmi_en for USB2.0
|
||||
hwp_usbc->usbcfg = hwp_usbc->usbcfg | 0x40; //enable usb PLL.
|
||||
#elif defined(SOC_SF32LB56X) || defined(SOC_SF32LB52X)
|
||||
hwp_hpsys_cfg->USBCR |= HPSYS_CFG_USBCR_DM_PD | HPSYS_CFG_USBCR_DP_EN | HPSYS_CFG_USBCR_USB_EN;
|
||||
#elif defined(SOC_SF32LB55X)
|
||||
hwp_hpsys_cfg->USBCR |= HPSYS_CFG_USBCR_DM_PD | HPSYS_CFG_USBCR_USB_EN;
|
||||
#endif
|
||||
#ifndef SOC_SF32LB55X
|
||||
hwp_usbc->usbcfg |= (USB_USBCFG_AVALID | USB_USBCFG_AVALID_DR);
|
||||
hwp_usbc->dpbrxdisl = 0xFE;
|
||||
hwp_usbc->dpbtxdisl = 0xFE;
|
||||
#endif
|
||||
NVIC_EnableIRQ(USBC_IRQn);
|
||||
__HAL_SYSCFG_Enable_USB();
|
||||
}
|
||||
|
||||
void usb_dc_low_level_deinit(uint8_t busid)
|
||||
{
|
||||
NVIC_DisableIRQ(USBC_IRQn);
|
||||
#ifdef SOC_SF32LB58X
|
||||
hwp_usbc->usbcfg &= ~0x40; // Disable usb PLL.
|
||||
hwp_usbc->swcntl3 = 0x0;
|
||||
hwp_usbc->ldo25 &= ~0xa; // Disable psw_en and ldo25_en
|
||||
#elif defined(SOC_SF32LB56X) || defined(SOC_SF32LB52X)
|
||||
hwp_hpsys_cfg->USBCR &= ~(HPSYS_CFG_USBCR_DM_PD | HPSYS_CFG_USBCR_DP_EN | HPSYS_CFG_USBCR_USB_EN);
|
||||
#elif defined(SOC_SF32LB55X)
|
||||
hwp_hpsys_cfg->USBCR &= ~(HPSYS_CFG_USBCR_DM_PD | HPSYS_CFG_USBCR_USB_EN);
|
||||
#endif
|
||||
/* reset USB to make DP change to PULLDOWN state */
|
||||
hwp_hpsys_rcc->RSTR2 |= HPSYS_RCC_RSTR2_USBC;
|
||||
HAL_Delay_us(100);
|
||||
hwp_hpsys_rcc->RSTR2 &= ~HPSYS_RCC_RSTR2_USBC;
|
||||
HAL_RCC_DisableModule(RCC_MOD_USBC);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PKG_CHERRYUSB_HOST
|
||||
void usb_hc_low_level_init(struct usbh_bus *bus)
|
||||
{
|
||||
HAL_RCC_EnableModule(RCC_MOD_USBC);
|
||||
|
||||
#ifdef SOC_SF32LB58X
|
||||
//hwp_usbc->utmicfg12 = hwp_usbc->utmicfg12 | 0x3; //set xo_clk_sel
|
||||
hwp_usbc->ldo25 = hwp_usbc->ldo25 | 0xa; //set psw_en and ldo25_en
|
||||
HAL_Delay(1);
|
||||
hwp_usbc->swcntl3 = 0x1; //set utmi_en for USB2.0
|
||||
hwp_usbc->usbcfg = hwp_usbc->usbcfg | 0x40; //enable usb PLL.
|
||||
#elif defined(SOC_SF32LB56X) || defined(SOC_SF32LB52X)
|
||||
hwp_hpsys_cfg->USBCR |= HPSYS_CFG_USBCR_DM_PD | HPSYS_CFG_USBCR_DP_EN | HPSYS_CFG_USBCR_USB_EN;
|
||||
#elif defined(SOC_SF32LB55X)
|
||||
hwp_hpsys_cfg->USBCR |= HPSYS_CFG_USBCR_DM_PD | HPSYS_CFG_USBCR_USB_EN;
|
||||
#endif
|
||||
#ifndef SOC_SF32LB55X
|
||||
hwp_usbc->usbcfg |= (USB_USBCFG_AVALID | USB_USBCFG_AVALID_DR);
|
||||
hwp_usbc->dpbrxdisl = 0xFE;
|
||||
hwp_usbc->dpbtxdisl = 0xFE;
|
||||
#endif
|
||||
__HAL_SYSCFG_Enable_USB();
|
||||
hwp_usbc->usbcfg &= 0xEF;
|
||||
hwp_usbc->dbgl = 0x80;
|
||||
|
||||
NVIC_EnableIRQ(USBC_IRQn);
|
||||
}
|
||||
|
||||
void usb_hc_low_level_deinit(struct usbh_bus *bus)
|
||||
{
|
||||
NVIC_DisableIRQ(USBC_IRQn);
|
||||
#ifdef SOC_SF32LB58X
|
||||
hwp_usbc->usbcfg &= ~0x40; // Disable usb PLL.
|
||||
hwp_usbc->swcntl3 = 0x0;
|
||||
hwp_usbc->ldo25 &= ~0xa; // Disable psw_en and ldo25_en
|
||||
#elif defined(SOC_SF32LB56X) || defined(SOC_SF32LB52X)
|
||||
hwp_hpsys_cfg->USBCR &= ~(HPSYS_CFG_USBCR_DM_PD | HPSYS_CFG_USBCR_DP_EN | HPSYS_CFG_USBCR_USB_EN);
|
||||
#elif defined(SOC_SF32LB55X)
|
||||
hwp_hpsys_cfg->USBCR &= ~(HPSYS_CFG_USBCR_DM_PD | HPSYS_CFG_USBCR_USB_EN);
|
||||
#endif
|
||||
/* reset USB to make DP change to PULLDOWN state */
|
||||
hwp_hpsys_rcc->RSTR2 |= HPSYS_RCC_RSTR2_USBC;
|
||||
HAL_Delay_us(100);
|
||||
hwp_hpsys_rcc->RSTR2 &= ~HPSYS_RCC_RSTR2_USBC;
|
||||
HAL_RCC_DisableModule(RCC_MOD_USBC);
|
||||
}
|
||||
|
||||
void musb_reset_prev(void)
|
||||
{
|
||||
#if defined(SF32LB58X)
|
||||
hwp_usbc->rsvd0 = 0xc; //58
|
||||
#endif
|
||||
}
|
||||
|
||||
void musb_reset_post(void)
|
||||
{
|
||||
#if defined(SF32LB58X)
|
||||
hwp_usbc->rsvd0 = 0x0; //58
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
void USBC_IRQHandler(void)
|
||||
{
|
||||
#ifdef PKG_CHERRYUSB_DEVICE
|
||||
USBD_IRQHandler(0);
|
||||
#endif
|
||||
#ifdef PKG_CHERRYUSB_HOST
|
||||
USBH_IRQHandler(0);
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) 2024, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usb_config.h"
|
||||
#include "stdint.h"
|
||||
#include "usb_musb_reg.h"
|
||||
|
||||
#ifndef CONFIG_USB_MUSB_SUNXI
|
||||
#error must define CONFIG_USB_MUSB_SUNXI when use sunxi chips
|
||||
#endif
|
||||
|
||||
#if CONFIG_USB_MUSB_EP_NUM != 4
|
||||
#error sunxi chips only support 4 endpoints
|
||||
#endif
|
||||
|
||||
#if CONFIG_USB_MUSB_PIPE_NUM != 4
|
||||
#error sunxi chips only support 4 pipes
|
||||
#endif
|
||||
|
||||
// clang-format off
|
||||
static struct musb_fifo_cfg musb_device_table[] = {
|
||||
{ .ep_num = 0, .style = FIFO_TXRX, .maxpacket = 64, },
|
||||
{ .ep_num = 1, .style = FIFO_TX, .maxpacket = 1024, },
|
||||
{ .ep_num = 1, .style = FIFO_RX, .maxpacket = 1024, },
|
||||
{ .ep_num = 2, .style = FIFO_TX, .maxpacket = 512, },
|
||||
{ .ep_num = 2, .style = FIFO_RX, .maxpacket = 512, },
|
||||
{ .ep_num = 3, .style = FIFO_TX, .maxpacket = 512, },
|
||||
{ .ep_num = 3, .style = FIFO_RX, .maxpacket = 512, },
|
||||
};
|
||||
|
||||
static struct musb_fifo_cfg musb_host_table[] = {
|
||||
{ .ep_num = 0, .style = FIFO_TXRX, .maxpacket = 64, },
|
||||
{ .ep_num = 1, .style = FIFO_TX, .maxpacket = 1024, },
|
||||
{ .ep_num = 1, .style = FIFO_RX, .maxpacket = 1024, },
|
||||
{ .ep_num = 2, .style = FIFO_TX, .maxpacket = 512, },
|
||||
{ .ep_num = 2, .style = FIFO_RX, .maxpacket = 512, },
|
||||
{ .ep_num = 3, .style = FIFO_TX, .maxpacket = 512, },
|
||||
{ .ep_num = 3, .style = FIFO_RX, .maxpacket = 512, },
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
uint8_t usbd_get_musb_fifo_cfg(struct musb_fifo_cfg **cfg)
|
||||
{
|
||||
*cfg = musb_device_table;
|
||||
return sizeof(musb_device_table) / sizeof(musb_device_table[0]);
|
||||
}
|
||||
|
||||
uint8_t usbh_get_musb_fifo_cfg(struct musb_fifo_cfg **cfg)
|
||||
{
|
||||
*cfg = musb_host_table;
|
||||
return sizeof(musb_host_table) / sizeof(musb_host_table[0]);
|
||||
}
|
||||
|
||||
uint32_t usb_get_musb_ram_size(void)
|
||||
{
|
||||
return 8192;
|
||||
}
|
||||
|
||||
void usbd_musb_delay_ms(uint8_t ms)
|
||||
{
|
||||
/* implement later */
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,9 @@
|
||||
# Note
|
||||
|
||||
## Support Chip List
|
||||
|
||||
- NRF5x
|
||||
|
||||
## Before Use
|
||||
|
||||
- Your should implement `usb_dc_low_level_pre_init`,`usb_dc_low_level_post_init`,`usb_dc_low_level_deinit`.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,17 @@
|
||||
# Note
|
||||
|
||||
## Support Chip List
|
||||
|
||||
### MCX
|
||||
|
||||
Modify USB_NOCACHE_RAM_SECTION
|
||||
|
||||
```
|
||||
#define USB_NOCACHE_RAM_SECTION __attribute__((section(".NonCacheable")))
|
||||
```
|
||||
|
||||
- MCXN9XX/MCXN236 (chipidea + EHCI)
|
||||
|
||||
### IMRT
|
||||
|
||||
- IMRT10XX/IMRT11XX (chipidea + EHCI)
|
||||
@@ -0,0 +1,449 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ~ 2025, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usbd_core.h"
|
||||
#include "usbh_core.h"
|
||||
#include "fsl_common.h"
|
||||
#include "fsl_cache.h"
|
||||
#include "usb_chipidea_reg.h"
|
||||
|
||||
__WEAK void USBD_IRQHandler(uint8_t busid)
|
||||
{
|
||||
}
|
||||
|
||||
__WEAK void USBH_IRQHandler(uint8_t busid)
|
||||
{
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_USB_EHCI_NXP)
|
||||
#error "mcx ehci must config CONFIG_USB_EHCI_NXP"
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_USB_EHCI_HCCR_OFFSET) || CONFIG_USB_EHCI_HCCR_OFFSET != 0x100
|
||||
#error "mcx ehci must config CONFIG_USB_EHCI_HCCR_OFFSET to 0x100"
|
||||
#endif
|
||||
|
||||
#define USB_DEVICE_CONFIG_EHCI 1
|
||||
|
||||
/*! @brief USB controller ID */
|
||||
typedef enum _usb_controller_index {
|
||||
kUSB_ControllerKhci0 = 0U, /*!< KHCI 0U */
|
||||
kUSB_ControllerKhci1 = 1U, /*!< KHCI 1U, Currently, there are no platforms which have two KHCI IPs, this is reserved
|
||||
to be used in the future. */
|
||||
kUSB_ControllerEhci0 = 2U, /*!< EHCI 0U */
|
||||
kUSB_ControllerEhci1 = 3U, /*!< EHCI 1U, Currently, there are no platforms which have two EHCI IPs, this is reserved
|
||||
to be used in the future. */
|
||||
|
||||
kUSB_ControllerLpcIp3511Fs0 = 4U, /*!< LPC USB IP3511 FS controller 0 */
|
||||
kUSB_ControllerLpcIp3511Fs1 = 5U, /*!< LPC USB IP3511 FS controller 1, there are no platforms which have two IP3511
|
||||
IPs, this is reserved to be used in the future. */
|
||||
|
||||
kUSB_ControllerLpcIp3511Hs0 = 6U, /*!< LPC USB IP3511 HS controller 0 */
|
||||
kUSB_ControllerLpcIp3511Hs1 = 7U, /*!< LPC USB IP3511 HS controller 1, there are no platforms which have two IP3511
|
||||
IPs, this is reserved to be used in the future. */
|
||||
|
||||
kUSB_ControllerOhci0 = 8U, /*!< OHCI 0U */
|
||||
kUSB_ControllerOhci1 = 9U, /*!< OHCI 1U, Currently, there are no platforms which have two OHCI IPs, this is reserved
|
||||
to be used in the future. */
|
||||
|
||||
kUSB_ControllerIp3516Hs0 = 10U, /*!< IP3516HS 0U */
|
||||
kUSB_ControllerIp3516Hs1 = 11U, /*!< IP3516HS 1U, Currently, there are no platforms which have two IP3516HS IPs,
|
||||
this is reserved to be used in the future. */
|
||||
kUSB_ControllerDwc30 = 12U, /*!< DWC3 0U */
|
||||
kUSB_ControllerDwc31 = 13U, /*!< DWC3 1U Currently, there are no platforms which have two Dwc IPs, this is reserved
|
||||
to be used in the future.*/
|
||||
} usb_controller_index_t;
|
||||
|
||||
/* USB PHY condfiguration */
|
||||
#define BOARD_USB_PHY_D_CAL (0x04U)
|
||||
#define BOARD_USB_PHY_TXCAL45DP (0x07U)
|
||||
#define BOARD_USB_PHY_TXCAL45DM (0x07U)
|
||||
#define BOARD_XTAL0_CLK_HZ 24000000U /*!< Board xtal0 frequency in Hz */
|
||||
|
||||
typedef struct _usb_phy_config_struct {
|
||||
uint8_t D_CAL; /* Decode to trim the nominal 17.78mA current source */
|
||||
uint8_t TXCAL45DP; /* Decode to trim the nominal 45-Ohm series termination resistance to the USB_DP output pin */
|
||||
uint8_t TXCAL45DM; /* Decode to trim the nominal 45-Ohm series termination resistance to the USB_DM output pin */
|
||||
} usb_phy_config_struct_t;
|
||||
|
||||
void *USB_EhciPhyGetBase(uint8_t controllerId)
|
||||
{
|
||||
void *usbPhyBase = NULL;
|
||||
#if ((defined FSL_FEATURE_SOC_USBPHY_COUNT) && (FSL_FEATURE_SOC_USBPHY_COUNT > 0U))
|
||||
#if defined(USBPHY_STACK_BASE_ADDRS)
|
||||
uint32_t usbphy_base[] = USBPHY_STACK_BASE_ADDRS;
|
||||
#else
|
||||
uint32_t usbphy_base[] = USBPHY_BASE_ADDRS;
|
||||
#endif
|
||||
uint32_t *temp;
|
||||
if (controllerId < (uint8_t)kUSB_ControllerEhci0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((controllerId == (uint8_t)kUSB_ControllerEhci0) || (controllerId == (uint8_t)kUSB_ControllerEhci1)) {
|
||||
controllerId = controllerId - (uint8_t)kUSB_ControllerEhci0;
|
||||
} else if ((controllerId == (uint8_t)kUSB_ControllerLpcIp3511Hs0) ||
|
||||
(controllerId == (uint8_t)kUSB_ControllerLpcIp3511Hs1)) {
|
||||
controllerId = controllerId - (uint8_t)kUSB_ControllerLpcIp3511Hs0;
|
||||
} else if ((controllerId == (uint8_t)kUSB_ControllerIp3516Hs0) || (controllerId == (uint8_t)kUSB_ControllerIp3516Hs1)) {
|
||||
controllerId = controllerId - (uint8_t)kUSB_ControllerIp3516Hs0;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (controllerId < (sizeof(usbphy_base) / sizeof(usbphy_base[0]))) {
|
||||
temp = (uint32_t *)usbphy_base[controllerId];
|
||||
usbPhyBase = (void *)temp;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
return usbPhyBase;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief ehci phy initialization.
|
||||
*
|
||||
* This function initialize ehci phy IP.
|
||||
*
|
||||
* @param[in] controllerId ehci controller id, please reference to #usb_controller_index_t.
|
||||
* @param[in] freq the external input clock.
|
||||
* for example: if the external input clock is 16M, the parameter freq should be 16000000.
|
||||
*
|
||||
* @retval 0 cancel successfully.
|
||||
* @retval -1 the freq value is incorrect.
|
||||
*/
|
||||
uint32_t USB_EhciPhyInit(uint8_t controllerId, uint32_t freq, usb_phy_config_struct_t *phyConfig)
|
||||
{
|
||||
#if ((defined FSL_FEATURE_SOC_USBPHY_COUNT) && (FSL_FEATURE_SOC_USBPHY_COUNT > 0U))
|
||||
USBPHY_Type *usbPhyBase;
|
||||
|
||||
usbPhyBase = (USBPHY_Type *)USB_EhciPhyGetBase(controllerId);
|
||||
if (NULL == usbPhyBase) {
|
||||
return (uint8_t)-1;
|
||||
}
|
||||
|
||||
#if ((defined FSL_FEATURE_SOC_ANATOP_COUNT) && (FSL_FEATURE_SOC_ANATOP_COUNT > 0U))
|
||||
ANATOP->HW_ANADIG_REG_3P0.RW =
|
||||
(ANATOP->HW_ANADIG_REG_3P0.RW &
|
||||
(~(ANATOP_HW_ANADIG_REG_3P0_OUTPUT_TRG(0x1F) | ANATOP_HW_ANADIG_REG_3P0_ENABLE_ILIMIT_MASK))) |
|
||||
ANATOP_HW_ANADIG_REG_3P0_OUTPUT_TRG(0x17) | ANATOP_HW_ANADIG_REG_3P0_ENABLE_LINREG_MASK;
|
||||
ANATOP->HW_ANADIG_USB2_CHRG_DETECT.SET =
|
||||
ANATOP_HW_ANADIG_USB2_CHRG_DETECT_CHK_CHRG_B_MASK | ANATOP_HW_ANADIG_USB2_CHRG_DETECT_EN_B_MASK;
|
||||
#endif
|
||||
|
||||
#if (defined USB_ANALOG)
|
||||
USB_ANALOG->INSTANCE[controllerId - (uint8_t)kUSB_ControllerEhci0].CHRG_DETECT_SET =
|
||||
USB_ANALOG_CHRG_DETECT_CHK_CHRG_B(1) | USB_ANALOG_CHRG_DETECT_EN_B(1);
|
||||
#endif
|
||||
|
||||
#if ((!(defined FSL_FEATURE_SOC_CCM_ANALOG_COUNT)) && (!(defined FSL_FEATURE_SOC_ANATOP_COUNT)))
|
||||
|
||||
usbPhyBase->TRIM_OVERRIDE_EN = 0x001fU; /* override IFR value */
|
||||
#endif
|
||||
usbPhyBase->CTRL |= USBPHY_CTRL_SET_ENUTMILEVEL2_MASK; /* support LS device. */
|
||||
usbPhyBase->CTRL |= USBPHY_CTRL_SET_ENUTMILEVEL3_MASK; /* support external FS Hub with LS device connected. */
|
||||
/* PWD register provides overall control of the PHY power state */
|
||||
usbPhyBase->PWD = 0U;
|
||||
if (((uint8_t)kUSB_ControllerIp3516Hs0 == controllerId) || ((uint8_t)kUSB_ControllerIp3516Hs1 == controllerId) ||
|
||||
((uint8_t)kUSB_ControllerLpcIp3511Hs0 == controllerId) ||
|
||||
((uint8_t)kUSB_ControllerLpcIp3511Hs1 == controllerId)) {
|
||||
usbPhyBase->CTRL_SET = USBPHY_CTRL_SET_ENAUTOCLR_CLKGATE_MASK;
|
||||
usbPhyBase->CTRL_SET = USBPHY_CTRL_SET_ENAUTOCLR_PHY_PWD_MASK;
|
||||
}
|
||||
if (NULL != phyConfig) {
|
||||
/* Decode to trim the nominal 17.78mA current source for the High Speed TX drivers on USB_DP and USB_DM. */
|
||||
usbPhyBase->TX =
|
||||
((usbPhyBase->TX & (~(USBPHY_TX_D_CAL_MASK | USBPHY_TX_TXCAL45DM_MASK | USBPHY_TX_TXCAL45DP_MASK))) |
|
||||
(USBPHY_TX_D_CAL(phyConfig->D_CAL) | USBPHY_TX_TXCAL45DP(phyConfig->TXCAL45DP) |
|
||||
USBPHY_TX_TXCAL45DM(phyConfig->TXCAL45DM)));
|
||||
}
|
||||
#endif
|
||||
|
||||
return (uint8_t)0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief ehci phy initialization for suspend and resume.
|
||||
*
|
||||
* This function initialize ehci phy IP for suspend and resume.
|
||||
*
|
||||
* @param[in] controllerId ehci controller id, please reference to #usb_controller_index_t.
|
||||
* @param[in] freq the external input clock.
|
||||
* for example: if the external input clock is 16M, the parameter freq should be 16000000.
|
||||
*
|
||||
* @retval 0 cancel successfully.
|
||||
* @retval -1 the freq value is incorrect.
|
||||
*/
|
||||
uint32_t USB_EhciLowPowerPhyInit(uint8_t controllerId, uint32_t freq, usb_phy_config_struct_t *phyConfig)
|
||||
{
|
||||
#if ((defined FSL_FEATURE_SOC_USBPHY_COUNT) && (FSL_FEATURE_SOC_USBPHY_COUNT > 0U))
|
||||
USBPHY_Type *usbPhyBase;
|
||||
|
||||
usbPhyBase = (USBPHY_Type *)USB_EhciPhyGetBase(controllerId);
|
||||
if (NULL == usbPhyBase) {
|
||||
return (uint8_t)-1;
|
||||
}
|
||||
|
||||
#if ((!(defined FSL_FEATURE_SOC_CCM_ANALOG_COUNT)) && (!(defined FSL_FEATURE_SOC_ANATOP_COUNT)))
|
||||
usbPhyBase->TRIM_OVERRIDE_EN = 0x001fU; /* override IFR value */
|
||||
#endif
|
||||
|
||||
#if ((defined USBPHY_CTRL_AUTORESUME_EN_MASK) && (USBPHY_CTRL_AUTORESUME_EN_MASK > 0U))
|
||||
usbPhyBase->CTRL_CLR |= USBPHY_CTRL_AUTORESUME_EN_MASK;
|
||||
#else
|
||||
usbPhyBase->CTRL |= USBPHY_CTRL_ENAUTO_PWRON_PLL_MASK;
|
||||
#endif
|
||||
usbPhyBase->CTRL |= USBPHY_CTRL_ENAUTOCLR_CLKGATE_MASK | USBPHY_CTRL_ENAUTOCLR_PHY_PWD_MASK;
|
||||
usbPhyBase->CTRL |= USBPHY_CTRL_SET_ENUTMILEVEL2_MASK; /* support LS device. */
|
||||
usbPhyBase->CTRL |= USBPHY_CTRL_SET_ENUTMILEVEL3_MASK; /* support external FS Hub with LS device connected. */
|
||||
/* PWD register provides overall control of the PHY power state */
|
||||
usbPhyBase->PWD = 0U;
|
||||
#if (defined USBPHY_ANACTRL_PFD_CLKGATE_MASK)
|
||||
/* now the 480MHz USB clock is up, then configure fractional divider after PLL with PFD
|
||||
* pfd clock = 480MHz*18/N, where N=18~35
|
||||
* Please note that USB1PFDCLK has to be less than 180MHz for RUN or HSRUN mode
|
||||
*/
|
||||
usbPhyBase->ANACTRL |= USBPHY_ANACTRL_PFD_FRAC(24); /* N=24 */
|
||||
usbPhyBase->ANACTRL |= USBPHY_ANACTRL_PFD_CLK_SEL(1); /* div by 4 */
|
||||
|
||||
usbPhyBase->ANACTRL &= ~USBPHY_ANACTRL_DEV_PULLDOWN_MASK;
|
||||
usbPhyBase->ANACTRL &= ~USBPHY_ANACTRL_PFD_CLKGATE_MASK;
|
||||
while (0U == (usbPhyBase->ANACTRL & USBPHY_ANACTRL_PFD_STABLE_MASK)) {
|
||||
}
|
||||
#endif
|
||||
if (NULL != phyConfig) {
|
||||
/* Decode to trim the nominal 17.78mA current source for the High Speed TX drivers on USB_DP and USB_DM. */
|
||||
usbPhyBase->TX =
|
||||
((usbPhyBase->TX & (~(USBPHY_TX_D_CAL_MASK | USBPHY_TX_TXCAL45DM_MASK | USBPHY_TX_TXCAL45DP_MASK))) |
|
||||
(USBPHY_TX_D_CAL(phyConfig->D_CAL) | USBPHY_TX_TXCAL45DP(phyConfig->TXCAL45DP) |
|
||||
USBPHY_TX_TXCAL45DM(phyConfig->TXCAL45DM)));
|
||||
}
|
||||
#endif
|
||||
|
||||
return (uint8_t)0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief ehci phy de-initialization.
|
||||
*
|
||||
* This function de-initialize ehci phy IP.
|
||||
*
|
||||
* @param[in] controllerId ehci controller id, please reference to #usb_controller_index_t.
|
||||
*/
|
||||
void USB_EhciPhyDeinit(uint8_t controllerId)
|
||||
{
|
||||
#if ((defined FSL_FEATURE_SOC_USBPHY_COUNT) && (FSL_FEATURE_SOC_USBPHY_COUNT > 0U))
|
||||
USBPHY_Type *usbPhyBase;
|
||||
|
||||
usbPhyBase = (USBPHY_Type *)USB_EhciPhyGetBase(controllerId);
|
||||
if (NULL == usbPhyBase) {
|
||||
return;
|
||||
}
|
||||
#if ((!(defined FSL_FEATURE_SOC_CCM_ANALOG_COUNT)) && (!(defined FSL_FEATURE_SOC_ANATOP_COUNT)))
|
||||
usbPhyBase->PLL_SIC &= ~USBPHY_PLL_SIC_PLL_POWER_MASK; /* power down PLL */
|
||||
usbPhyBase->PLL_SIC &= ~USBPHY_PLL_SIC_PLL_EN_USB_CLKS_MASK; /* disable USB clock output from USB PHY PLL */
|
||||
#endif
|
||||
usbPhyBase->CTRL |= USBPHY_CTRL_CLKGATE_MASK; /* set to 1U to gate clocks */
|
||||
#endif
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief ehci phy disconnect detection enable or disable.
|
||||
*
|
||||
* This function enable/disable host ehci disconnect detection.
|
||||
*
|
||||
* @param[in] controllerId ehci controller id, please reference to #usb_controller_index_t.
|
||||
* @param[in] enable
|
||||
* 1U - enable;
|
||||
* 0U - disable;
|
||||
*/
|
||||
void USB_EhcihostPhyDisconnectDetectCmd(uint8_t controllerId, uint8_t enable)
|
||||
{
|
||||
#if ((defined FSL_FEATURE_SOC_USBPHY_COUNT) && (FSL_FEATURE_SOC_USBPHY_COUNT > 0U))
|
||||
USBPHY_Type *usbPhyBase;
|
||||
|
||||
usbPhyBase = (USBPHY_Type *)USB_EhciPhyGetBase(controllerId);
|
||||
if (NULL == usbPhyBase) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (0U != enable) {
|
||||
usbPhyBase->CTRL |= USBPHY_CTRL_ENHOSTDISCONDETECT_MASK;
|
||||
} else {
|
||||
usbPhyBase->CTRL &= (~USBPHY_CTRL_ENHOSTDISCONDETECT_MASK);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if ((defined FSL_FEATURE_SOC_USBPHY_COUNT) && (FSL_FEATURE_SOC_USBPHY_COUNT > 0U))
|
||||
#if ((defined FSL_FEATURE_USBHSD_HAS_EXIT_HS_ISSUE) && (FSL_FEATURE_USBHSD_HAS_EXIT_HS_ISSUE > 0U))
|
||||
void USB_PhyDeviceForceEnterFSMode(uint8_t controllerId, uint8_t enable)
|
||||
{
|
||||
USBPHY_Type *usbPhyBase;
|
||||
|
||||
usbPhyBase = (USBPHY_Type *)USB_EhciPhyGetBase(controllerId);
|
||||
if (NULL == usbPhyBase) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (0U != enable) {
|
||||
uint32_t delay = 1000000;
|
||||
usbPhyBase->DEBUG0_CLR = USBPHY_DEBUG0_CLKGATE_MASK;
|
||||
while ((0U != (usbPhyBase->USB1_VBUS_DET_STAT & USBPHY_USB1_VBUS_DET_STAT_VBUS_VALID_3V_MASK)) && (0U != delay)) {
|
||||
delay--;
|
||||
}
|
||||
usbPhyBase->USB1_LOOPBACK_SET = USBPHY_USB1_LOOPBACK_UTMI_TESTSTART_MASK;
|
||||
} else {
|
||||
usbPhyBase->DEBUG0_CLR = USBPHY_DEBUG0_CLKGATE_MASK;
|
||||
usbPhyBase->USB1_LOOPBACK_CLR = USBPHY_USB1_LOOPBACK_UTMI_TESTSTART_MASK;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void USB_ClockInit(void)
|
||||
{
|
||||
usb_phy_config_struct_t phyConfig = {
|
||||
BOARD_USB_PHY_D_CAL,
|
||||
BOARD_USB_PHY_TXCAL45DP,
|
||||
BOARD_USB_PHY_TXCAL45DM,
|
||||
};
|
||||
|
||||
SPC0->ACTIVE_VDELAY = 0x0500;
|
||||
/* Change the power DCDC to 1.8v (By deafult, DCDC is 1.8V), CORELDO to 1.1v (By deafult, CORELDO is 1.0V) */
|
||||
SPC0->ACTIVE_CFG &= ~SPC_ACTIVE_CFG_CORELDO_VDD_DS_MASK;
|
||||
SPC0->ACTIVE_CFG |= SPC_ACTIVE_CFG_DCDC_VDD_LVL(0x3) | SPC_ACTIVE_CFG_CORELDO_VDD_LVL(0x3) |
|
||||
SPC_ACTIVE_CFG_SYSLDO_VDD_DS_MASK | SPC_ACTIVE_CFG_DCDC_VDD_DS(0x2u);
|
||||
/* Wait until it is done */
|
||||
while (SPC0->SC & SPC_SC_BUSY_MASK)
|
||||
;
|
||||
if (0u == (SCG0->LDOCSR & SCG_LDOCSR_LDOEN_MASK)) {
|
||||
SCG0->TRIM_LOCK = 0x5a5a0001U;
|
||||
SCG0->LDOCSR |= SCG_LDOCSR_LDOEN_MASK;
|
||||
/* wait LDO ready */
|
||||
while (0U == (SCG0->LDOCSR & SCG_LDOCSR_VOUT_OK_MASK))
|
||||
;
|
||||
}
|
||||
SYSCON->AHBCLKCTRLSET[2] |= SYSCON_AHBCLKCTRL2_USB_HS_MASK | SYSCON_AHBCLKCTRL2_USB_HS_PHY_MASK;
|
||||
SCG0->SOSCCFG &= ~(SCG_SOSCCFG_RANGE_MASK | SCG_SOSCCFG_EREFS_MASK);
|
||||
/* xtal = 20 ~ 30MHz */
|
||||
SCG0->SOSCCFG = (1U << SCG_SOSCCFG_RANGE_SHIFT) | (1U << SCG_SOSCCFG_EREFS_SHIFT);
|
||||
SCG0->SOSCCSR |= SCG_SOSCCSR_SOSCEN_MASK;
|
||||
while (1) {
|
||||
if (SCG0->SOSCCSR & SCG_SOSCCSR_SOSCVLD_MASK) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
SYSCON->CLOCK_CTRL |= SYSCON_CLOCK_CTRL_CLKIN_ENA_MASK | SYSCON_CLOCK_CTRL_CLKIN_ENA_FM_USBH_LPT_MASK;
|
||||
CLOCK_EnableClock(kCLOCK_UsbHs);
|
||||
CLOCK_EnableClock(kCLOCK_UsbHsPhy);
|
||||
CLOCK_EnableUsbhsPhyPllClock(kCLOCK_Usbphy480M, 24000000U);
|
||||
CLOCK_EnableUsbhsClock();
|
||||
USB_EhciPhyInit(kUSB_ControllerEhci0, BOARD_XTAL0_CLK_HZ, &phyConfig);
|
||||
}
|
||||
|
||||
void (*g_usb_nxp_irq)(uint8_t busid);
|
||||
|
||||
void usb_dc_low_level_init(uint8_t busid)
|
||||
{
|
||||
USB_ClockInit();
|
||||
|
||||
g_usb_nxp_irq = USBD_IRQHandler;
|
||||
|
||||
/* Install isr, set priority, and enable IRQ. */
|
||||
NVIC_SetPriority((IRQn_Type)USB1_HS_IRQn, 3);
|
||||
EnableIRQ((IRQn_Type)USB1_HS_IRQn);
|
||||
}
|
||||
|
||||
void usb_dc_low_level_deinit(uint8_t busid)
|
||||
{
|
||||
DisableIRQ((IRQn_Type)USB1_HS_IRQn);
|
||||
}
|
||||
|
||||
static void usb_host_mode_init(CHIPIDEA_TypeDef *ptr)
|
||||
{
|
||||
/* Set mode to host, must be set immediately after reset */
|
||||
ptr->USBMODE &= ~USB_USBMODE_CM_MASK;
|
||||
ptr->USBMODE |= USB_USBMODE_CM_SET(3);
|
||||
|
||||
/* Set the endian */
|
||||
ptr->USBMODE &= ~USB_USBMODE_ES_MASK;
|
||||
|
||||
/* Set parallel interface signal */
|
||||
ptr->PORTSC1 &= ~USB_PORTSC1_STS_MASK;
|
||||
|
||||
/* Set parallel transceiver width */
|
||||
ptr->PORTSC1 &= ~USB_PORTSC1_PTW_MASK;
|
||||
|
||||
/* Not use interrupt threshold. */
|
||||
ptr->USBCMD &= ~USB_USBCMD_ITC_MASK;
|
||||
}
|
||||
|
||||
void usb_hc_low_level_init(struct usbh_bus *bus)
|
||||
{
|
||||
USB_ClockInit();
|
||||
|
||||
g_usb_nxp_irq = USBH_IRQHandler;
|
||||
|
||||
/* Install isr, set priority, and enable IRQ. */
|
||||
NVIC_SetPriority((IRQn_Type)USB1_HS_IRQn, 3);
|
||||
EnableIRQ((IRQn_Type)USB1_HS_IRQn);
|
||||
}
|
||||
|
||||
void usb_hc_low_level2_init(struct usbh_bus *bus)
|
||||
{
|
||||
usb_host_mode_init((CHIPIDEA_TypeDef *)(bus->hcd.reg_base));
|
||||
}
|
||||
|
||||
void usb_hc_low_level_deinit(struct usbh_bus *bus)
|
||||
{
|
||||
DisableIRQ((IRQn_Type)USB1_HS_IRQn);
|
||||
}
|
||||
|
||||
uint8_t usbh_get_port_speed(struct usbh_bus *bus, const uint8_t port)
|
||||
{
|
||||
(void)port;
|
||||
uint8_t speed;
|
||||
|
||||
CHIPIDEA_TypeDef *ptr = (CHIPIDEA_TypeDef *)bus->hcd.reg_base;
|
||||
|
||||
speed = USB_PORTSC1_PSPD_GET(ptr->PORTSC1);
|
||||
|
||||
if (speed == 0x00) {
|
||||
return USB_SPEED_FULL;
|
||||
}
|
||||
if (speed == 0x01) {
|
||||
return USB_SPEED_LOW;
|
||||
}
|
||||
if (speed == 0x02) {
|
||||
USB_EhcihostPhyDisconnectDetectCmd(kUSB_ControllerEhci0, 1);
|
||||
return USB_SPEED_HIGH;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void USB1_HS_IRQHandler(void)
|
||||
{
|
||||
g_usb_nxp_irq(0);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_DCACHE_ENABLE
|
||||
void usb_dcache_clean(uintptr_t addr, size_t size)
|
||||
{
|
||||
DCACHE_CleanByRange(addr, size);
|
||||
}
|
||||
|
||||
void usb_dcache_invalidate(uintptr_t addr, size_t size)
|
||||
{
|
||||
DCACHE_InvalidateByRange(addr, size);
|
||||
}
|
||||
|
||||
void usb_dcache_flush(uintptr_t addr, size_t size)
|
||||
{
|
||||
DCACHE_CleanInvalidateByRange(addr, size);
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,23 @@
|
||||
# Note
|
||||
|
||||
This OHCI is a companion controller of EHCI. But you can use OHCI only without CONFIG_USB_EHCI_WITH_OHCI definition.
|
||||
|
||||
**And you need to pay for using OHCI driver**.
|
||||
|
||||
## Support Chip List
|
||||
|
||||
### AllwinnerTech
|
||||
|
||||
- F133(EHCI + OHCI)
|
||||
|
||||
### Nuvoton
|
||||
|
||||
- Nuvoton all series(EHCI + OHCI, OHCI only)
|
||||
|
||||
### Artinchip
|
||||
|
||||
- d13x, d21x(EHCI + OHCI)
|
||||
|
||||
### NXP
|
||||
|
||||
- LPC4X/LPC5X(OHCI only)
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2024, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "fsl_device_registers.h"
|
||||
#include "fsl_power.h"
|
||||
#include "usbh_core.h"
|
||||
|
||||
#if defined(CONFIG_USB_EHCI_WITH_OHCI)
|
||||
#error "lpc does not have ehci"
|
||||
#endif
|
||||
|
||||
void usb_hc_low_level_init(struct usbh_bus *bus)
|
||||
{
|
||||
#if ((defined FSL_FEATURE_SOC_SYSMPU_COUNT) && (FSL_FEATURE_SOC_SYSMPU_COUNT))
|
||||
SYSMPU_Enable(SYSMPU, 0);
|
||||
#endif /* FSL_FEATURE_SOC_SYSMPU_COUNT */
|
||||
|
||||
NVIC_ClearPendingIRQ(USB0_IRQn);
|
||||
NVIC_ClearPendingIRQ(USB0_NEEDCLK_IRQn);
|
||||
|
||||
POWER_DisablePD(kPDRUNCFG_PD_USB0_PHY); /*< Turn on USB0 Phy */
|
||||
|
||||
RESET_PeripheralReset(kUSB0D_RST_SHIFT_RSTn);
|
||||
RESET_PeripheralReset(kUSB0HSL_RST_SHIFT_RSTn);
|
||||
RESET_PeripheralReset(kUSB0HMR_RST_SHIFT_RSTn);
|
||||
|
||||
CLOCK_EnableUsbfs0HostClock(kCLOCK_UsbfsSrcPll1, 48000000U);
|
||||
|
||||
NVIC_SetPriority(USB0_IRQn, 3);
|
||||
EnableIRQ(USB0_IRQn);
|
||||
}
|
||||
|
||||
|
||||
void usb_hc_low_level_deinit(struct usbh_bus *bus)
|
||||
{
|
||||
DisableIRQ(USB0_IRQn);
|
||||
}
|
||||
|
||||
void USB0_IRQHandler(void)
|
||||
{
|
||||
extern void USBH_IRQHandler(uint8_t busid);
|
||||
USBH_IRQHandler(0);
|
||||
}
|
||||
@@ -0,0 +1,353 @@
|
||||
/*
|
||||
* Copyright (c) 2024, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usb_hc_ohci.h"
|
||||
|
||||
/* Frame Interval / Periodic Start.
|
||||
*
|
||||
* At 12Mbps, there are 12000 bit time in each 1Msec frame.
|
||||
*/
|
||||
|
||||
#define OHCI_FMINTERVAL_FI (12000 - 1)
|
||||
#define OHCI_FMINTERVAL_FSMPS ((6 * (OHCI_FMINTERVAL_FI - 210)) / 7)
|
||||
#define DEFAULT_FMINTERVAL ((OHCI_FMINTERVAL_FSMPS << OHCI_FMINT_FSMPS_SHIFT) | OHCI_FMINTERVAL_FI)
|
||||
#define DEFAULT_PERSTART ((OHCI_FMINTERVAL_FI * 9) / 10)
|
||||
|
||||
struct ohci_hcd g_ohci_hcd[CONFIG_USBHOST_MAX_BUS];
|
||||
|
||||
USB_NOCACHE_RAM_SECTION struct ohci_ed_hw g_ohci_ed_pool[CONFIG_USBHOST_MAX_BUS][CONFIG_USB_OHCI_ED_NUM];
|
||||
USB_NOCACHE_RAM_SECTION struct ohci_hcca ohci_hcca[CONFIG_USBHOST_MAX_BUS];
|
||||
|
||||
int ohci_init(struct usbh_bus *bus)
|
||||
{
|
||||
volatile uint32_t timeout = 0;
|
||||
uint32_t regval;
|
||||
struct ohci_ed_hw *ed;
|
||||
|
||||
memset(&g_ohci_hcd[bus->hcd.hcd_id], 0, sizeof(struct ohci_hcd));
|
||||
memset(g_ohci_ed_pool[bus->hcd.hcd_id], 0, sizeof(struct ohci_ed_hw) * CONFIG_USB_OHCI_ED_NUM);
|
||||
|
||||
for (uint32_t i = 0; i < 32; i++) {
|
||||
ohci_hcca[bus->hcd.hcd_id].inttbl[i] = 0;
|
||||
}
|
||||
|
||||
for (uint8_t index = 0; index < CONFIG_USB_OHCI_ED_NUM; index++) {
|
||||
ed = &g_ohci_ed_pool[bus->hcd.hcd_id][index];
|
||||
if ((uint32_t)&ed->hw % 32) {
|
||||
USB_LOG_ERR("struct ohci_ed_hw is not align 32\r\n");
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
for (uint8_t i = 0; i < CONFIG_USB_OHCI_TD_NUM; i++) {
|
||||
if ((uint32_t)&ed->td_pool[i] % 32) {
|
||||
USB_LOG_ERR("struct ohci_td_hw is not align 32\r\n");
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (uint8_t index = 0; index < CONFIG_USB_OHCI_ED_NUM; index++) {
|
||||
ed = &g_ohci_ed_pool[bus->hcd.hcd_id][index];
|
||||
ed->waitsem = usb_osal_sem_create(0);
|
||||
}
|
||||
|
||||
USB_LOG_INFO("OHCI hcrevision:0x%02x\r\n", (unsigned int)OHCI_HCOR->hcrevision);
|
||||
|
||||
OHCI_HCOR->hcintdis = OHCI_INT_MIE;
|
||||
OHCI_HCOR->hccontrol = 0;
|
||||
|
||||
OHCI_HCOR->hccmdsts = OHCI_CMDST_HCR;
|
||||
while (OHCI_HCOR->hccmdsts & OHCI_CMDST_HCR) {
|
||||
usb_osal_msleep(1);
|
||||
timeout++;
|
||||
if (timeout > 100) {
|
||||
return -USB_ERR_TIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
OHCI_HCOR->hcfminterval = DEFAULT_FMINTERVAL;
|
||||
OHCI_HCOR->hcperiodicstart = DEFAULT_PERSTART;
|
||||
OHCI_HCOR->hclsthreshold = 0x628;
|
||||
|
||||
OHCI_HCOR->hccontrolheaded = 0;
|
||||
OHCI_HCOR->hcbulkheaded = 0;
|
||||
OHCI_HCOR->hchcca = (uintptr_t)&ohci_hcca[bus->hcd.hcd_id];
|
||||
|
||||
/* Clear pending interrupts */
|
||||
regval = OHCI_HCOR->hcintsts;
|
||||
OHCI_HCOR->hcintsts = regval;
|
||||
|
||||
/* Put HC in operational state */
|
||||
regval = OHCI_HCOR->hccontrol;
|
||||
regval &= ~OHCI_CTRL_CBSR;
|
||||
regval &= ~OHCI_CTRL_HCFS_MASK;
|
||||
regval |= OHCI_CTRL_HCFS_OPER;
|
||||
regval |= OHCI_CTRL_CBSR;
|
||||
regval |= OHCI_CTRL_CLE;
|
||||
OHCI_HCOR->hccontrol = regval;
|
||||
|
||||
g_ohci_hcd[bus->hcd.hcd_id].n_ports = OHCI_HCOR->hcrhdescriptora & OHCI_RHDESCA_NDP_MASK;
|
||||
USB_LOG_INFO("OHCI n_ports:%d\r\n", g_ohci_hcd[bus->hcd.hcd_id].n_ports);
|
||||
|
||||
OHCI_HCOR->hcrhdescriptora &= ~OHCI_RHDESCA_PSM;
|
||||
OHCI_HCOR->hcrhdescriptora &= ~OHCI_RHDESCA_NPS;
|
||||
|
||||
/* Set global power in HcRhStatus */
|
||||
OHCI_HCOR->hcrhsts = OHCI_RHSTATUS_SGP;
|
||||
usb_osal_msleep(20);
|
||||
|
||||
/* Enable OHCI interrupts */
|
||||
OHCI_HCOR->hcinten = OHCI_INT_WDH | OHCI_INT_RHSC | OHCI_INT_MIE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ohci_deinit(struct usbh_bus *bus)
|
||||
{
|
||||
uint32_t regval;
|
||||
struct ohci_ed_hw *ed;
|
||||
|
||||
/* Disable OHCI interrupts */
|
||||
OHCI_HCOR->hcintdis = OHCI_INT_WDH | OHCI_INT_RHSC | OHCI_INT_MIE;
|
||||
|
||||
/* Clear pending interrupts */
|
||||
regval = OHCI_HCOR->hcintsts;
|
||||
OHCI_HCOR->hcintsts = regval;
|
||||
|
||||
OHCI_HCOR->hcrhsts &= ~OHCI_RHSTATUS_SGP;
|
||||
|
||||
regval = OHCI_HCOR->hccontrol;
|
||||
regval &= ~OHCI_CTRL_HCFS_MASK;
|
||||
regval |= OHCI_CTRL_HCFS_SUSPEND;
|
||||
OHCI_HCOR->hccontrol = regval;
|
||||
|
||||
for (uint8_t index = 0; index < CONFIG_USB_OHCI_ED_NUM; index++) {
|
||||
ed = &g_ohci_ed_pool[bus->hcd.hcd_id][index];
|
||||
usb_osal_sem_delete(ed->waitsem);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t ohci_get_frame_number(struct usbh_bus *bus)
|
||||
{
|
||||
return OHCI_HCOR->hcfmnumber;
|
||||
}
|
||||
|
||||
int ohci_roothub_control(struct usbh_bus *bus, struct usb_setup_packet *setup, uint8_t *buf)
|
||||
{
|
||||
uint8_t nports;
|
||||
uint8_t port;
|
||||
uint32_t temp;
|
||||
|
||||
nports = g_ohci_hcd[bus->hcd.hcd_id].n_ports;
|
||||
|
||||
port = setup->wIndex;
|
||||
if (setup->bmRequestType & USB_REQUEST_RECIPIENT_DEVICE) {
|
||||
switch (setup->bRequest) {
|
||||
case HUB_REQUEST_CLEAR_FEATURE:
|
||||
switch (setup->wValue) {
|
||||
case HUB_FEATURE_HUB_C_LOCALPOWER:
|
||||
break;
|
||||
case HUB_FEATURE_HUB_C_OVERCURRENT:
|
||||
break;
|
||||
default:
|
||||
return -USB_ERR_NOTSUPP;
|
||||
}
|
||||
break;
|
||||
case HUB_REQUEST_SET_FEATURE:
|
||||
switch (setup->wValue) {
|
||||
case HUB_FEATURE_HUB_C_LOCALPOWER:
|
||||
break;
|
||||
case HUB_FEATURE_HUB_C_OVERCURRENT:
|
||||
break;
|
||||
default:
|
||||
return -USB_ERR_NOTSUPP;
|
||||
}
|
||||
break;
|
||||
case HUB_REQUEST_GET_DESCRIPTOR:
|
||||
break;
|
||||
case HUB_REQUEST_GET_STATUS:
|
||||
memset(buf, 0, 4);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (setup->bmRequestType & USB_REQUEST_RECIPIENT_OTHER) {
|
||||
switch (setup->bRequest) {
|
||||
case HUB_REQUEST_CLEAR_FEATURE:
|
||||
if (!port || port > nports) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
|
||||
switch (setup->wValue) {
|
||||
case HUB_PORT_FEATURE_ENABLE:
|
||||
temp = OHCI_RHPORTST_CCS;
|
||||
break;
|
||||
case HUB_PORT_FEATURE_SUSPEND:
|
||||
temp = OHCI_HCOR->hccontrol;
|
||||
temp &= ~OHCI_CTRL_HCFS_MASK;
|
||||
temp |= OHCI_CTRL_HCFS_RESUME;
|
||||
OHCI_HCOR->hccontrol = temp;
|
||||
|
||||
usb_osal_msleep(20);
|
||||
|
||||
temp = OHCI_HCOR->hccontrol;
|
||||
temp &= ~OHCI_CTRL_HCFS_MASK;
|
||||
temp |= OHCI_CTRL_HCFS_OPER;
|
||||
OHCI_HCOR->hccontrol = temp;
|
||||
|
||||
temp = OHCI_RHPORTST_POCI;
|
||||
break;
|
||||
case HUB_PORT_FEATURE_C_SUSPEND:
|
||||
temp = OHCI_RHPORTST_PSSC;
|
||||
break;
|
||||
case HUB_PORT_FEATURE_POWER:
|
||||
OHCI_HCOR->hcrhsts = OHCI_RHSTATUS_CGP;
|
||||
temp = OHCI_RHPORTST_LSDA;
|
||||
break;
|
||||
case HUB_PORT_FEATURE_C_CONNECTION:
|
||||
temp = OHCI_RHPORTST_CSC;
|
||||
break;
|
||||
case HUB_PORT_FEATURE_C_ENABLE:
|
||||
temp = OHCI_RHPORTST_PESC;
|
||||
break;
|
||||
case HUB_PORT_FEATURE_C_OVER_CURREN:
|
||||
temp = OHCI_RHPORTST_OCIC;
|
||||
break;
|
||||
case HUB_PORT_FEATURE_C_RESET:
|
||||
temp = OHCI_RHPORTST_PRSC;
|
||||
break;
|
||||
default:
|
||||
return -USB_ERR_NOTSUPP;
|
||||
}
|
||||
OHCI_HCOR->hcrhportsts[port - 1] = temp;
|
||||
break;
|
||||
case HUB_REQUEST_SET_FEATURE:
|
||||
if (!port || port > nports) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
|
||||
switch (setup->wValue) {
|
||||
case HUB_PORT_FEATURE_SUSPEND:
|
||||
temp = OHCI_HCOR->hccontrol;
|
||||
temp &= ~OHCI_CTRL_HCFS_MASK;
|
||||
temp |= OHCI_CTRL_HCFS_SUSPEND;
|
||||
OHCI_HCOR->hccontrol = temp;
|
||||
|
||||
break;
|
||||
case HUB_PORT_FEATURE_POWER:
|
||||
OHCI_HCOR->hcrhsts = OHCI_RHSTATUS_SGP;
|
||||
break;
|
||||
case HUB_PORT_FEATURE_RESET:
|
||||
OHCI_HCOR->hcrhportsts[port - 1] = OHCI_RHPORTST_PRS;
|
||||
|
||||
while (OHCI_HCOR->hcrhportsts[port - 1] & OHCI_RHPORTST_PRS) {
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return -USB_ERR_NOTSUPP;
|
||||
}
|
||||
break;
|
||||
case HUB_REQUEST_GET_STATUS:
|
||||
if (!port || port > nports) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
temp = OHCI_HCOR->hcrhportsts[port - 1];
|
||||
memcpy(buf, &temp, 4);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ohci_submit_urb(struct usbh_urb *urb)
|
||||
{
|
||||
return -USB_ERR_NOTSUPP;
|
||||
}
|
||||
|
||||
int ohci_kill_urb(struct usbh_urb *urb)
|
||||
{
|
||||
return -USB_ERR_NOTSUPP;
|
||||
}
|
||||
|
||||
void OHCI_IRQHandler(uint8_t busid)
|
||||
{
|
||||
uint32_t usbsts;
|
||||
struct usbh_bus *bus;
|
||||
|
||||
bus = &g_usbhost_bus[busid];
|
||||
|
||||
usbsts = OHCI_HCOR->hcintsts & OHCI_HCOR->hcinten;
|
||||
|
||||
if (usbsts & OHCI_INT_RHSC) {
|
||||
OHCI_HCOR->hcintsts = OHCI_INT_RHSC;
|
||||
for (int port = 0; port < CONFIG_USBHOST_MAX_RHPORTS; port++) {
|
||||
uint32_t portsc = OHCI_HCOR->hcrhportsts[port];
|
||||
|
||||
if (portsc & OHCI_RHPORTST_CSC) {
|
||||
if (OHCI_HCOR->hcrhsts & OHCI_RHSTATUS_DRWE) {
|
||||
/* If DRWE is set, Connect Status Change indicates a remote wake-up event */
|
||||
} else {
|
||||
if (portsc & OHCI_RHPORTST_CCS) {
|
||||
} else {
|
||||
}
|
||||
bus->hcd.roothub.int_buffer[0] |= (1 << (port + 1));
|
||||
usbh_hub_thread_wakeup(&bus->hcd.roothub);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (usbsts & OHCI_INT_WDH) {
|
||||
OHCI_HCOR->hcintsts = OHCI_INT_WDH;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef CONFIG_USB_EHCI_WITH_OHCI
|
||||
__WEAK void usb_hc_low_level_init(struct usbh_bus *bus)
|
||||
{
|
||||
(void)bus;
|
||||
}
|
||||
|
||||
__WEAK void usb_hc_low_level_deinit(struct usbh_bus *bus)
|
||||
{
|
||||
(void)bus;
|
||||
}
|
||||
|
||||
int usb_hc_init(struct usbh_bus *bus)
|
||||
{
|
||||
usb_hc_low_level_init(bus);
|
||||
return ohci_init(bus);
|
||||
}
|
||||
|
||||
int usb_hc_deinit(struct usbh_bus *bus)
|
||||
{
|
||||
ohci_deinit(bus);
|
||||
usb_hc_low_level_deinit(bus);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbh_roothub_control(struct usbh_bus *bus, struct usb_setup_packet *setup, uint8_t *buf)
|
||||
{
|
||||
return ohci_roothub_control(bus, setup, buf);
|
||||
}
|
||||
|
||||
int usbh_submit_urb(struct usbh_urb *urb)
|
||||
{
|
||||
return ohci_submit_urb(urb);
|
||||
}
|
||||
|
||||
int usbh_kill_urb(struct usbh_urb *urb)
|
||||
{
|
||||
return ohci_kill_urb(urb);
|
||||
}
|
||||
|
||||
void USBH_IRQHandler(uint8_t busid)
|
||||
{
|
||||
OHCI_IRQHandler(busid);
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2024, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef _USB_OHCI_PRIV_H
|
||||
#define _USB_OHCI_PRIV_H
|
||||
|
||||
#include "usbh_core.h"
|
||||
#include "usbh_hub.h"
|
||||
#include "usb_ohci_reg.h"
|
||||
|
||||
#define OHCI_HCOR ((struct ohci_hcor *)(uintptr_t)(bus->hcd.reg_base + CONFIG_USB_OHCI_HCOR_OFFSET))
|
||||
|
||||
#define OHCI_PTR2ADDR(x) ((uint32_t)(uintptr_t)(x) & ~0x0F)
|
||||
#define OHCI_ADDR2ED(x) ((struct ohci_ed_hw *)(uintptr_t)((uint32_t)(x) & ~0x0F))
|
||||
#define OHCI_ADDR2TD(x) ((struct ohci_td_hw *)(uintptr_t)((uint32_t)(x) & ~0x0F))
|
||||
|
||||
#ifndef CONFIG_USB_OHCI_ED_NUM
|
||||
#define CONFIG_USB_OHCI_ED_NUM 10
|
||||
#endif
|
||||
#ifndef CONFIG_USB_OHCI_TD_NUM
|
||||
#define CONFIG_USB_OHCI_TD_NUM 3
|
||||
#endif
|
||||
|
||||
#if CONFIG_USB_ALIGN_SIZE <= 32
|
||||
#define CONFIG_USB_OHCI_ALIGN_SIZE 32
|
||||
#elif CONFIG_USB_ALIGN_SIZE <= 64
|
||||
#define CONFIG_USB_OHCI_ALIGN_SIZE 64
|
||||
#else
|
||||
#error "CONFIG_USB_ALIGN_SIZE must be 32 or 64"
|
||||
#endif
|
||||
|
||||
struct ohci_ed_hw;
|
||||
struct ohci_td_hw {
|
||||
struct ohci_gtd hw;
|
||||
#if defined(CONFIG_USB_OHCI_DESC_DCACHE_ENABLE) && (CONFIG_USB_ALIGN_SIZE == 32)
|
||||
uint8_t pad[16];
|
||||
#elif defined(CONFIG_USB_OHCI_DESC_DCACHE_ENABLE) && (CONFIG_USB_ALIGN_SIZE == 64)
|
||||
uint8_t pad[48];
|
||||
#endif
|
||||
struct usbh_urb *urb;
|
||||
bool dir_in;
|
||||
uint32_t buf_start;
|
||||
uint32_t length;
|
||||
} __attribute__((aligned(CONFIG_USB_OHCI_ALIGN_SIZE))); /* min is 16bytes, we use CONFIG_USB_OHCI_ALIGN_SIZE for cacheline */
|
||||
|
||||
struct ohci_ed_hw {
|
||||
struct ohci_ed hw;
|
||||
#if defined(CONFIG_USB_OHCI_DESC_DCACHE_ENABLE) && (CONFIG_USB_ALIGN_SIZE == 32)
|
||||
uint8_t pad[16];
|
||||
#elif defined(CONFIG_USB_OHCI_DESC_DCACHE_ENABLE) && (CONFIG_USB_ALIGN_SIZE == 64)
|
||||
uint8_t pad[48];
|
||||
#endif
|
||||
struct ohci_td_hw td_pool[CONFIG_USB_OHCI_TD_NUM];
|
||||
uint32_t td_count;
|
||||
uint8_t ed_type;
|
||||
usb_osal_sem_t waitsem;
|
||||
} __attribute__((aligned(CONFIG_USB_OHCI_ALIGN_SIZE))); /* min is 16bytes, we use CONFIG_USB_OHCI_ALIGN_SIZE for cacheline */
|
||||
|
||||
struct ohci_hcd {
|
||||
bool ohci_ed_used[CONFIG_USB_OHCI_ED_NUM];
|
||||
uint8_t n_ports;
|
||||
};
|
||||
|
||||
int ohci_init(struct usbh_bus *bus);
|
||||
int ohci_deinit(struct usbh_bus *bus);
|
||||
uint16_t ohci_get_frame_number(struct usbh_bus *bus);
|
||||
int ohci_roothub_control(struct usbh_bus *bus, struct usb_setup_packet *setup, uint8_t *buf);
|
||||
int ohci_submit_urb(struct usbh_urb *urb);
|
||||
int ohci_kill_urb(struct usbh_urb *urb);
|
||||
|
||||
void OHCI_IRQHandler(uint8_t busid);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,484 @@
|
||||
/****************************************************************************
|
||||
* include/nuttx/usb/ohci.h
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __INCLUDE_NUTTX_USB_OHCI_H
|
||||
#define __INCLUDE_NUTTX_USB_OHCI_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* Register offsets *********************************************************/
|
||||
|
||||
/* Control and status registers (section 7.1) */
|
||||
|
||||
#define OHCI_HCIREV_OFFSET 0x0000 /* HcRevision: Version of HCI specification */
|
||||
#define OHCI_CTRL_OFFSET 0x0004 /* HcControl: HC control */
|
||||
#define OHCI_CMDST_OFFSET 0x0008 /* HcCommandStatus: HC command status */
|
||||
#define OHCI_INTST_OFFSET 0x000c /* HcInterruptStatus: HC interrupt status */
|
||||
#define OHCI_INTEN_OFFSET 0x0010 /* HcInterruptEnable: HC interrupt enable */
|
||||
#define OHCI_INTDIS_OFFSET 0x0014 /* HcInterruptDisable: HC interrupt disable */
|
||||
|
||||
/* Memory pointer registers (section 7.2) */
|
||||
|
||||
#define OHCI_HCCA_OFFSET 0x0018 /* HcHCCA: HC communication area */
|
||||
#define OHCI_PERED_OFFSET 0x001c /* HcPeriodCurrentED: Current isoc or int endpoint desc */
|
||||
#define OHCI_CTRLHEADED_OFFSET 0x0020 /* HcControlHeadED: First EP desc in the control list */
|
||||
#define OHCI_CTRLED_OFFSET 0x0024 /* HcControlCurrentED: Current EP desc in the control list */
|
||||
#define OHCI_BULKHEADED_OFFSET 0x0028 /* HcBulkHeadED: First EP desc in the bulk list */
|
||||
#define OHCI_BULKED_OFFSET 0x002c /* HcBulkCurrentED: Current EP desc in the bulk list */
|
||||
#define OHCI_DONEHEAD_OFFSET 0x0030 /* HcDoneHead: Last transfer desc added to DONE queue */
|
||||
|
||||
/* Frame counter registers (section 7.3) */
|
||||
|
||||
#define OHCI_FMINT_OFFSET 0x0034 /* HcFmInterval: Bit time interval that would not cause overrun */
|
||||
#define OHCI_FMREM_OFFSET 0x0038 /* HcFmRemaining: Bit time remaining in current frame */
|
||||
#define OHCI_FMNO_OFFSET 0x003c /* HcFmNumber: Frame number counter */
|
||||
#define OHCI_PERSTART_OFFSET 0x0040 /* HcPeriodicStart: Time to start processing periodic list */
|
||||
|
||||
/* Root hub registers (section 7.4) */
|
||||
|
||||
#define OHCI_LSTHRES_OFFSET 0x0044 /* HcLSThreshold: Commit to transfer threshold */
|
||||
#define OHCI_RHDESCA_OFFSET 0x0048 /* HcRhDescriptorA: Describes root hub (part A) */
|
||||
#define OHCI_RHDESCB_OFFSET 0x004c /* HcRhDescriptorB: Describes root hub (part B) */
|
||||
#define OHCI_RHSTATUS_OFFSET 0x0050 /* HcRhStatus: Root hub status */
|
||||
|
||||
#define OHCI_MAX_RHPORT 15 /* Maximum number of OHCI root hub ports */
|
||||
|
||||
#define OHCI_RHPORTST_OFFSET(n) (0x0054 + (((n) - 1) << 2))
|
||||
#define OHCI_RHPORTST1_OFFSET 0x0054 /* HcRhPort1Status: Root hub port status 1 */
|
||||
#define OHCI_RHPORTST2_OFFSET 0x0058 /* HcRhPort2Status: Root hub port status 2 */
|
||||
#define OHCI_RHPORTST3_OFFSET 0x005c /* HcRhPort3Status: Root hub port status 3 */
|
||||
#define OHCI_RHPORTST4_OFFSET 0x0060 /* HcRhPort4Status: Root hub port status 4 */
|
||||
#define OHCI_RHPORTST5_OFFSET 0x0064 /* HcRhPort5Status: Root hub port status 5 */
|
||||
#define OHCI_RHPORTST6_OFFSET 0x0068 /* HcRhPort6Status: Root hub port status 6 */
|
||||
#define OHCI_RHPORTST7_OFFSET 0x006c /* HcRhPort7Status: Root hub port status 7 */
|
||||
#define OHCI_RHPORTST8_OFFSET 0x0070 /* HcRhPort8Status: Root hub port status 8 */
|
||||
#define OHCI_RHPORTST9_OFFSET 0x0074 /* HcRhPort9Status: Root hub port status 9 */
|
||||
#define OHCI_RHPORTST10_OFFSET 0x0078 /* HcRhPort10Status: Root hub port status 10 */
|
||||
#define OHCI_RHPORTST11_OFFSET 0x007c /* HcRhPort11Status: Root hub port status 11 */
|
||||
#define OHCI_RHPORTST12_OFFSET 0x0080 /* HcRhPort12Status: Root hub port status 12 */
|
||||
#define OHCI_RHPORTST13_OFFSET 0x0084 /* HcRhPort13Status: Root hub port status 13 */
|
||||
#define OHCI_RHPORTST14_OFFSET 0x0088 /* HcRhPort14Status: Root hub port status 14 */
|
||||
#define OHCI_RHPORTST15_OFFSET 0x008c /* HcRhPort15Status: Root hub port status 15 */
|
||||
|
||||
/* Register bit definitions *************************************************/
|
||||
|
||||
/* HcRevision: Version of HCI specification (7.1.1) */
|
||||
|
||||
#define OHCI_HCIREV_SHIFT (0) /* Bits 0-7: HCI spec version (BCD) */
|
||||
#define OHCI_HCIREV_MASK (0xff << OHCI_HCIREV_SHIFT)
|
||||
|
||||
/* HcControl: HC control (7.1.2) */
|
||||
|
||||
#define OHCI_CTRL_CBSR (3 << 0) /* Bit 0: Control/bulk service ratio */
|
||||
#define OHCI_CTRL_PLE (1 << 2) /* Bit 2: Periodic list enable */
|
||||
#define OHCI_CTRL_IE (1 << 3) /* Bit 3: Isochronous enable */
|
||||
#define OHCI_CTRL_CLE (1 << 4) /* Bit 4: Control list enable */
|
||||
#define OHCI_CTRL_BLE (1 << 5) /* Bit 5: Bulk list enable */
|
||||
#define OHCI_CTRL_HCFS_SHIFT (6) /* Bits 6-7: Host controller functional state */
|
||||
#define OHCI_CTRL_HCFS_MASK (3 << OHCI_CTRL_HCFS_SHIFT)
|
||||
# define OHCI_CTRL_HCFS_RESET (0 << OHCI_CTRL_HCFS_SHIFT)
|
||||
# define OHCI_CTRL_HCFS_RESUME (1 << OHCI_CTRL_HCFS_SHIFT)
|
||||
# define OHCI_CTRL_HCFS_OPER (2 << OHCI_CTRL_HCFS_SHIFT)
|
||||
# define OHCI_CTRL_HCFS_SUSPEND (3 << OHCI_CTRL_HCFS_SHIFT)
|
||||
#define OHCI_CTRL_IR (1 << 8) /* Bit 8: Interrupt routing */
|
||||
#define OHCI_CTRL_RWC (1 << 9) /* Bit 9: Remote wakeup connected */
|
||||
#define OHCI_CTRL_RWE (1 << 10) /* Bit 10: Remote wakeup enable */
|
||||
/* Bits 11-31: Reserved */
|
||||
|
||||
/* HcCommandStatus: HC command status (7.1.3) */
|
||||
|
||||
#define OHCI_CMDST_HCR (1 << 0) /* Bit 0: Host controller reset */
|
||||
#define OHCI_CMDST_CLF (1 << 1) /* Bit 1: Control list filled */
|
||||
#define OHCI_CMDST_BLF (1 << 2) /* Bit 2: Bulk list filled */
|
||||
#define OHCI_CMDST_OCR (1 << 3) /* Bit 3: Ownership change request */
|
||||
/* Bits 4-15: Reserved */
|
||||
#define OHCI_CMDST_SOC (3 << 16) /* Bit 16: Scheduling overrun count */
|
||||
/* Bits 17-31: Reserved */
|
||||
|
||||
/* HcInterruptStatus: HC interrupt status (7.1.4),
|
||||
* HcInterruptEnable: HC interrupt enable (7.1.5), and
|
||||
* HcInterruptDisable: HC interrupt disable (7.1.6)
|
||||
*/
|
||||
|
||||
#define OHCI_INT_SO (1 << 0) /* Bit 0: Scheduling overrun */
|
||||
#define OHCI_INT_WDH (1 << 1) /* Bit 1: Writeback done head */
|
||||
#define OHCI_INT_SF (1 << 2) /* Bit 2: Start of frame */
|
||||
#define OHCI_INT_RD (1 << 3) /* Bit 3: Resume detected */
|
||||
#define OHCI_INT_UE (1 << 4) /* Bit 4: Unrecoverable error */
|
||||
#define OHCI_INT_FNO (1 << 5) /* Bit 5: Frame number overflow */
|
||||
#define OHCI_INT_RHSC (1 << 6) /* Bit 6: Root hub status change */
|
||||
/* Bits 7-29: Reserved */
|
||||
#define OHCI_INT_OC (1 << 30) /* Bit 30: Ownership change */
|
||||
#define OHCI_INT_MIE (1 << 31) /* Bit 31: Master interrupt enable
|
||||
* (Enable/disable only) */
|
||||
|
||||
/* HcHCCA: HC communication area (7.2.1):
|
||||
*
|
||||
* 32-bits aligned to 256 byte boundary.
|
||||
*/
|
||||
|
||||
/* HcPeriodCurrentED: Current isoc or int endpoint desc (7.2.2),
|
||||
* HcControlHeadED: First EP desc in the control list (7.2.3),
|
||||
* HcControlCurrentED: Current EP desc in the control list (7.2.4),
|
||||
* HcBulkHeadED: First EP desc in the bulk list (7.2.5),
|
||||
* HcBulkCurrentED: Current EP desc in the bulk list (7.2.6), and
|
||||
* HcDoneHead: Last transfer desc added to DONE queue (7.2.7):
|
||||
*
|
||||
* All 32-bits aligned to an 8-byte boundary
|
||||
*/
|
||||
|
||||
/* HcFmInterval: Bit time interval that would not cause overrun (7.3.1) */
|
||||
|
||||
#define OHCI_FMINT_FI_SHIFT (0) /* Bits 0-13: Frame interval */
|
||||
#define OHCI_FMINT_FI_MASK (0x3fff << OHCI_FMINT_FI_SHIFT)
|
||||
/* Bits 14-15: Reserved */
|
||||
#define OHCI_FMINT_FSMPS_SHIFT (16) /* Bits 16-30: FS largest packet data */
|
||||
#define OHCI_FMINT_FSMPS_MASK (0x7fff << OHCI_FMINT_FSMPS_SHIFT)
|
||||
#define OHCI_FMINT_FIT (1 << 31) /* Bit 31: Frame interval toggle */
|
||||
|
||||
/* HcFmRemaining: Bit time remaining in current frame (7.3.2) */
|
||||
|
||||
#define OHCI_FMREM_FR_SHIFT (0) /* Bits 0-13: Frame remaining */
|
||||
#define OHCI_FMREM_FR_MASK (0x3fff << OHCI_FMREM_FR_SHIFT)
|
||||
/* Bits 16-30: Reserved */
|
||||
#define OHCI_FMINT_FRT (1 << 31) /* Bit 31: Frame remaining toggle */
|
||||
|
||||
/* HcFmNumber: Frame number counter (7.3.3) */
|
||||
|
||||
#define OHCI_FMNO_FI_SHIFT (0) /* Bits 0-15: Frame number */
|
||||
#define OHCI_FMNO_FI_MASK (0xffff << OHCI_FMINT_FI_SHIFT)
|
||||
/* Bits 16-31: Reserved */
|
||||
|
||||
/* HcPeriodicStart: Time to start processing periodic list (7.3.4) */
|
||||
|
||||
#define OHCI_PERSTART_SHIFT (0) /* Bits 0-13: Periodic start */
|
||||
#define OHCI_PERSTART_MASK (0x3fff << OHCI_PERSTART_SHIFT)
|
||||
/* Bits 14-31: Reserved */
|
||||
|
||||
/* HcLSThreshold: Commit to transfer threshold (7.3.5) */
|
||||
|
||||
#define OHCI_LSTHRES_SHIFT (0) /* Bits 0-11: LS threshold */
|
||||
#define OHCI_LSTHRES_MASK (0x0fff << OHCI_PERSTART_SHIFT)
|
||||
/* Bits 12-31: Reserved */
|
||||
|
||||
/* HcRhDescriptorN: Describes root hub (part A) (7.4.1) */
|
||||
|
||||
#define OHCI_RHDESCA_NDP_SHIFT (0) /* Bits 0-7: Number downstream ports */
|
||||
#define OHCI_RHDESCA_NDP_MASK (0xff << OHCI_RHDESCA_NDP_SHIFT)
|
||||
#define OHCI_RHDESCA_PSM (1 << 8) /* Bit 8: Power switching mode */
|
||||
#define OHCI_RHDESCA_NPS (1 << 9) /* Bit 9: No power switching */
|
||||
#define OHCI_RHDESCA_DT (1 << 10) /* Bit 10: Device type */
|
||||
#define OHCI_RHDESCA_OCPM (1 << 11) /* Bit 11: Over current protection mode */
|
||||
#define OHCI_RHDESCA_NOCP (1 << 12) /* Bit 12: No over current protection */
|
||||
/* Bits 13-23: Reserved */
|
||||
#define OHCI_RHDESCA_POTPGT_SHIFT (24) /* Bits 24-31: Power on to power good time */
|
||||
#define OHCI_RHDESCA_POTPGT_MASK (0xff << OHCI_RHDESCA_POTPGT_SHIFT)
|
||||
|
||||
/* HcRhDescriptorB: Describes root hub (part B) (7.4.2) */
|
||||
|
||||
#define OHCI_RHDESCB_DR_SHIFT (0) /* Bits 0-15: Device removable */
|
||||
#define OHCI_RHDESCB_DR_MASK (0xffff << OHCI_RHDESCB_DR_SHIFT)
|
||||
# define OHCI_RHDESCB_ATTACHED(n) (1 << (OHCI_RHDESCB_DR_SHIFT+(n)))
|
||||
#define OHCI_RHDESCB_PPCM_SHIFT (16) /* Bits 16-31: Port power control mask */
|
||||
#define OHCI_RHDESCB_PPCM_MASK (0xffff << OHCI_RHDESCB_PPCM_SHIFT)
|
||||
# define OHCI_RHDESCB_POWERED(n) (1 << (OHCI_RHDESCB_DR_SHIFT+(n)))
|
||||
|
||||
/* HcRhStatus: Root hub status (7.4.3) */
|
||||
|
||||
#define OHCI_RHSTATUS_LPS (1 << 0) /* Bit 0: Local power status (read)*/
|
||||
#define OHCI_RHSTATUS_CGP (1 << 0) /* Bit 0: Clear global power (write)*/
|
||||
#define OHCI_RHSTATUS_OCI (1 << 1) /* Bit 1: Over current indicator */
|
||||
/* Bits 2-14: Reserved */
|
||||
#define OHCI_RHSTATUS_DRWE (1 << 15) /* Bit 15: Device remote wakeup enable */
|
||||
#define OHCI_RHSTATUS_LPSC (1 << 16) /* Bit 16: Local power status change (read) */
|
||||
#define OHCI_RHSTATUS_SGP (1 << 16) /* Bit 16: Set global power (write) */
|
||||
#define OHCI_RHSTATUS_OCIC (1 << 17) /* Bit 17: Overcurrent indicator change */
|
||||
/* Bits 18-30: Reserved */
|
||||
#define OHCI_RHSTATUS_CRWE (1 << 31) /* Bit 31: Clear remote wakeup enable */
|
||||
|
||||
/* HcRhPortStatus: Root hub port status (7.4.4) */
|
||||
|
||||
#define OHCI_RHPORTST_CCS (1 << 0) /* Bit 0: Current connect status */
|
||||
#define OHCI_RHPORTST_PES (1 << 1) /* Bit 1: Port enable status */
|
||||
#define OHCI_RHPORTST_PSS (1 << 2) /* Bit 2: Port suspend status */
|
||||
#define OHCI_RHPORTST_POCI (1 << 3) /* Bit 3: Port over current indicator */
|
||||
#define OHCI_RHPORTST_PRS (1 << 4) /* Bit 4: Port reset status */
|
||||
/* Bits 5-7: Reserved */
|
||||
#define OHCI_RHPORTST_PPS (1 << 8) /* Bit 8: Port power status */
|
||||
#define OHCI_RHPORTST_LSDA (1 << 9) /* Bit 9: Low speed device attached */
|
||||
/* Bits 10-15: Reserved */
|
||||
#define OHCI_RHPORTST_CSC (1 << 16) /* Bit 16: Connect status change */
|
||||
#define OHCI_RHPORTST_PESC (1 << 17) /* Bit 17: Port enable status change */
|
||||
#define OHCI_RHPORTST_PSSC (1 << 18) /* Bit 18: Port suspend status change */
|
||||
#define OHCI_RHPORTST_OCIC (1 << 19) /* Bit 19: Port over current indicator change */
|
||||
#define OHCI_RHPORTST_PRSC (1 << 20) /* Bit 20: Port reset status change */
|
||||
/* Bits 21-31: Reserved */
|
||||
|
||||
/* Transfer Descriptors *****************************************************/
|
||||
|
||||
/* Endpoint Descriptor Offsets (4.2.1) */
|
||||
|
||||
#define ED_CONTROL_OFFSET (0x00) /* ED status/control bits */
|
||||
#define ED_TAILP_OFFSET (0x04) /* TD Queue Tail Pointer (TailP) */
|
||||
#define ED_HEADP_OFFSET (0x08) /* TD Queue Head Pointer (HeadP) */
|
||||
#define ED_NEXTED_OFFSET (0x0c) /* Next Endpoint Descriptor (NextED) */
|
||||
|
||||
/* Endpoint Descriptor Bit Definitions (4.2.2) */
|
||||
|
||||
#define ED_CONTROL_FA_SHIFT (0) /* Bits 0-6: Function Address */
|
||||
#define ED_CONTROL_FA_MASK (0x7f << ED_CONTROL_FA_SHIFT)
|
||||
#define ED_CONTROL_EN_SHIFT (7) /* Bits 7-10: Endpoint number */
|
||||
#define ED_CONTROL_EN_MASK (15 << ED_CONTROL_EN_SHIFT)
|
||||
#define ED_CONTROL_D_SHIFT (11) /* Bits 11-12: Direction */
|
||||
#define ED_CONTROL_D_MASK (3 << ED_CONTROL_D_SHIFT)
|
||||
# define ED_CONTROL_D_TD1 (0 << ED_CONTROL_D_SHIFT) /* Get direction from TD */
|
||||
# define ED_CONTROL_D_OUT (1 << ED_CONTROL_D_SHIFT) /* OUT */
|
||||
# define ED_CONTROL_D_IN (2 << ED_CONTROL_D_SHIFT) /* IN */
|
||||
# define ED_CONTROL_D_TD2 (3 << ED_CONTROL_D_SHIFT) /* Get direction from TD */
|
||||
|
||||
#define ED_CONTROL_SPPED_LOW (1 << 13) /* Bit 13: Speed (low) */
|
||||
#define ED_CONTROL_SKIP (1 << 14) /* Bit 14: Skip */
|
||||
#define ED_CONTROL_FORMAT_ISO (1 << 15) /* Bit 15: Format (isochronous) */
|
||||
#define ED_CONTROL_MPS_SHIFT (16) /* Bits 16-26: Maximum packet size */
|
||||
#define ED_CONTROL_MPS_MASK (0x7ff << ED_CONTROL_MPS_SHIFT)
|
||||
|
||||
#define ED_HEADP_ADDR_SHIFT (0)
|
||||
#define ED_HEADP_ADDR_MASK 0xfffffff0
|
||||
#define ED_HEADP_H (1 << 0) /* Bit 0: Halted */
|
||||
#define ED_HEADP_C (1 << 1) /* Bit 1: Toggle carry */
|
||||
|
||||
/* General Transfer Descriptor Offsets (4.3.1) */
|
||||
|
||||
#define GTD_STATUS_OFFSET (0x00) /* TD status bits */
|
||||
#define GTD_CBP_OFFSET (0x04) /* Current Buffer Pointer (CBP) */
|
||||
#define GTD_NEXTTD_OFFSET (0x08) /* Next TD (NextTD) */
|
||||
#define GTD_BE_OFFSET (0x0c) /* Buffer End (BE) */
|
||||
|
||||
/* General Transfer Descriptor Bit Definitions */
|
||||
|
||||
/* Bits 0-17: Reserved */
|
||||
|
||||
#define GTD_STATUS_R (1 << 18) /* Bit 18: Buffer rounding */
|
||||
#define GTD_STATUS_DP_SHIFT (19) /* Bits 19-20: Direction/PID */
|
||||
#define GTD_STATUS_DP_MASK (3 << GTD_STATUS_DP_SHIFT)
|
||||
# define GTD_STATUS_DP_SETUP (0 << GTD_STATUS_DP_SHIFT) /* To endpoint */
|
||||
# define GTD_STATUS_DP_OUT (1 << GTD_STATUS_DP_SHIFT) /* To endpoint */
|
||||
# define GTD_STATUS_DP_IN (2 << GTD_STATUS_DP_SHIFT) /* From endpoint */
|
||||
|
||||
#define GTD_STATUS_DI_SHIFT (21) /* Bits 21-23: Delay input */
|
||||
#define GTD_STATUS_DI_MASK (7 << GTD_STATUS_DI_SHIFT)
|
||||
#define GTD_STATUS_T_SHIFT (24) /* Bits 24-25: Data Toggle */
|
||||
#define GTD_STATUS_T_MASK (3 << GTD_STATUS_T_SHIFT)
|
||||
# define GTD_STATUS_T_TOGGLE (0 << GTD_STATUS_T_SHIFT)
|
||||
# define GTD_STATUS_T_DATA0 (2 << GTD_STATUS_T_SHIFT)
|
||||
# define GTD_STATUS_T_DATA1 (3 << GTD_STATUS_T_SHIFT)
|
||||
#define GTD_STATUS_EC_SHIFT (26) /* Bits 26-27: Error count */
|
||||
#define GTD_STATUS_EC_MASK (3 << GTD_STATUS_EC_SHIFT)
|
||||
#define GTD_STATUS_CC_SHIFT (28) /* Bits 28-31: Condition code */
|
||||
#define GTD_STATUS_CC_MASK (15 << GTD_STATUS_CC_SHIFT)
|
||||
|
||||
/* Isochronous Transfer Descriptor Offsets (4.3.2) */
|
||||
|
||||
#define ITD_STATUS_OFFSET (0x00) /* TD status bits */
|
||||
#define ITD_BP0_OFFSET (0x04) /* Buffer page 0 (BP0) */
|
||||
#define ITD_NEXTTD_OFFSET (0x08) /* Next TD (NextTD) */
|
||||
#define ITD_BE_OFFSET (0x0c) /* Buffer End (BE) */
|
||||
|
||||
#define ITD_NPSW (8)
|
||||
#define ITD_PSW0_OFFSET (0x10) /* Offset0/PSW0 */
|
||||
#define ITD_PSW1_OFFSET (0x12) /* Offset1/PSW1 */
|
||||
#define ITD_PSW2_OFFSET (0x14) /* Offset2/PSW2 */
|
||||
#define ITD_PSW3_OFFSET (0x16) /* Offset3/PSW3 */
|
||||
#define ITD_PSW4_OFFSET (0x18) /* Offset4/PSW4 */
|
||||
#define ITD_PSW5_OFFSET (0x1a) /* Offset5/PSW5 */
|
||||
#define ITD_PSW6_OFFSET (0x1c) /* Offset6/PSW6 */
|
||||
#define ITD_PSW7_OFFSET (0x1e) /* Offset7/PSW7 */
|
||||
|
||||
/* Condition codes (Table 4-7) */
|
||||
|
||||
#define TD_CC_NOERROR 0x00
|
||||
#define TD_CC_CRC 0x01
|
||||
#define TD_CC_BITSTUFFING 0x02
|
||||
#define TD_CC_DATATOGGLEMISMATCH 0x03
|
||||
#define TD_CC_STALL 0x04
|
||||
#define TD_CC_DEVNOTRESPONDING 0x05
|
||||
#define TD_CC_PIDCHECKFAILURE 0x06
|
||||
#define TD_CC_UNEXPECTEDPID 0x07
|
||||
#define TD_CC_DATAOVERRUN 0x08
|
||||
#define TD_CC_DATAUNDERRUN 0x09
|
||||
#define TD_CC_BUFFEROVERRUN 0x0c
|
||||
#define TD_CC_BUFFERUNDERRUN 0x0d
|
||||
#define TD_CC_NOTACCESSED 0x0f
|
||||
|
||||
#define TD_CC_USER 0x10 /* For use by OHCI drivers */
|
||||
|
||||
/* Host Controller Communications Area Format (4.4.1) ***********************/
|
||||
|
||||
/* HccaInterruptTable: 32x32-bit pointers to interrupt EDs */
|
||||
|
||||
#define HCCA_INTTBL_OFFSET (0x00)
|
||||
#define HCCA_INTTBL_WSIZE (32)
|
||||
#define HCCA_INTTBL_BSIZE (HCCA_INTTBL_WSIZE * 4)
|
||||
|
||||
/* HccaFrameNumber: Current frame number */
|
||||
|
||||
#define HCCA_FMNO_OFFSET (0x80)
|
||||
#define HCCA_FMNO_BSIZE (2)
|
||||
|
||||
/* HccaPad1: Zero when frame no. updated */
|
||||
|
||||
#define HCCA_PAD1_OFFSET (0x82)
|
||||
#define HCCA_PAD1_BSIZE (2)
|
||||
|
||||
/* HccaDoneHead: When the HC reaches the end of a frame and its deferred
|
||||
* interrupt register is 0, it writes the current value of its HcDoneHead to
|
||||
* this location and generates an interrupt.
|
||||
*
|
||||
* The LSB of HCCADoneHead may be set to 1 to indicate that an unmasked
|
||||
* HcInterruptStatus was set when HccaDoneHead was written.
|
||||
*/
|
||||
|
||||
#define HCCA_DONEHEAD_OFFSET (0x84)
|
||||
#define HCCA_DONEHEAD_BSIZE (4)
|
||||
|
||||
#define HCCA_DONEHEAD_MASK 0xfffffffe
|
||||
#define HCCA_DONEHEAD_INTSTA (1 << 0)
|
||||
|
||||
/* 0x88: 116 bytes reserved */
|
||||
|
||||
#define HCCA_RESERVED_OFFSET (0x88)
|
||||
#define HCCA_RESERVED_BSIZE (116)
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
|
||||
struct ohci_hcor
|
||||
{
|
||||
volatile uint32_t hcrevision; /* 0x00 */
|
||||
volatile uint32_t hccontrol; /* 0x04 */
|
||||
volatile uint32_t hccmdsts; /* 0x08 */
|
||||
volatile uint32_t hcintsts; /* 0x0c */
|
||||
volatile uint32_t hcinten; /* 0x10 */
|
||||
volatile uint32_t hcintdis; /* 0x14 */
|
||||
volatile uint32_t hchcca; /* 0x18 */
|
||||
volatile uint32_t hcperiodcurrented; /* 0x1c */
|
||||
volatile uint32_t hccontrolheaded; /* 0x20 */
|
||||
volatile uint32_t hccontrolcurrented; /* 0x24 */
|
||||
volatile uint32_t hcbulkheaded; /* 0x28 */
|
||||
volatile uint32_t hcbulkcurrented; /* 0x2c */
|
||||
volatile uint32_t hcdonehead; /* 0x30 */
|
||||
volatile uint32_t hcfminterval; /* 0x34 */
|
||||
volatile uint32_t hcfmremaining; /* 0x38 */
|
||||
volatile uint32_t hcfmnumber; /* 0x3c */
|
||||
volatile uint32_t hcperiodicstart; /* 0x40 */
|
||||
volatile uint32_t hclsthreshold; /* 0x44 */
|
||||
volatile uint32_t hcrhdescriptora; /* 0x48 */
|
||||
volatile uint32_t hcrhdescriptorb; /* 0x4c */
|
||||
volatile uint32_t hcrhsts; /* 0x50 */
|
||||
volatile uint32_t hcrhportsts[15]; /* 0x54 */
|
||||
};
|
||||
|
||||
/* Endpoint Descriptor Offsets (4.2.1) */
|
||||
|
||||
struct ohci_ed
|
||||
{
|
||||
volatile uint32_t ctrl; /* ED status/control bits */
|
||||
volatile uint32_t tailp; /* TD Queue Tail Pointer (TailP) */
|
||||
volatile uint32_t headp; /* TD Queue Head Pointer (HeadP) */
|
||||
volatile uint32_t nexted; /* Next Endpoint Descriptor (NextED) */
|
||||
};
|
||||
|
||||
/* General Transfer Descriptor (4.3.1) */
|
||||
|
||||
struct ohci_gtd
|
||||
{
|
||||
volatile uint32_t ctrl; /* TD status/control bits */
|
||||
volatile uint32_t cbp; /* Current Buffer Pointer (CBP) */
|
||||
volatile uint32_t nexttd; /* Next TD (NextTD) */
|
||||
volatile uint32_t be; /* Buffer End (BE) */
|
||||
};
|
||||
|
||||
/* Isochronous Transfer Descriptor Offsets (4.3.2) */
|
||||
|
||||
struct ohci_itd
|
||||
{
|
||||
volatile uint32_t ctrl; /* TD status/control bits */
|
||||
volatile uint32_t bp0; /* Buffer page 0 (BP0 */
|
||||
volatile uint32_t nexttd; /* Next TD (NextTD) */
|
||||
volatile uint32_t be; /* Buffer End (BE) */
|
||||
volatile uint16_t psw[ITD_NPSW]; /* Offset/PSW */
|
||||
};
|
||||
|
||||
/* Host Controller Communications Area Format (4.4.1) */
|
||||
|
||||
struct ohci_hcca
|
||||
{
|
||||
/* HccaInterruptTable: 32x32-bit pointers to interrupt EDs */
|
||||
|
||||
volatile uint32_t inttbl[HCCA_INTTBL_WSIZE];
|
||||
|
||||
/* HccaFrameNumber: Current frame number and
|
||||
* HccaPad1: Zero when frame no. updated
|
||||
*/
|
||||
|
||||
volatile uint16_t fmno;
|
||||
volatile uint16_t pad1;
|
||||
|
||||
/* HccaDoneHead: When the HC reaches the end of a frame and its deferred
|
||||
* interrupt register is 0, it writes the current value of its HcDoneHead
|
||||
* to this location and generates an interrupt.
|
||||
*/
|
||||
|
||||
volatile uint32_t donehead;
|
||||
volatile uint8_t reserved[HCCA_RESERVED_BSIZE];
|
||||
volatile uint32_t extra;
|
||||
} __attribute__((aligned(256)));
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define EXTERN extern "C"
|
||||
extern "C"
|
||||
{
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
#undef EXTERN
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __INCLUDE_NUTTX_USB_OHCI_H */
|
||||
@@ -0,0 +1,66 @@
|
||||
# USB 2.0 OTG 控制器 (PUSB2)
|
||||
|
||||
- Phytium PI 和 Phyium E2000 系列开发板提供了兼容 USB2.0 的 OTG 接口
|
||||
- 相关的使用例程可以在 Phytium PI(飞腾派)和 E2000 D/Q Demo 板上运行,例程包括
|
||||
|
||||
---------------------------------------------
|
||||
|
||||
- Host 模式
|
||||
|
||||
- - 1. [FreeRTOS 上作为主机使用键盘/鼠标/U盘](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk/tree/master/example/peripheral/usb/pusb2_host/README.md)
|
||||
- - 5. [RT-Thread 上作为主机识别键盘/鼠标/U盘](https://github.com/RT-Thread/rt-thread/blob/master/bsp/phytium/doc/use_cherryusb.md)
|
||||
|
||||
---------------------------------------------
|
||||
|
||||
- Device 模式
|
||||
|
||||
- - 1. [裸机上模拟为一个 U 盘](https://gitee.com/phytium_embedded/phytium-standalone-sdk/tree/master/example/peripherals/usb/pusb2_device/README.md)
|
||||
- - 2. [裸机上模拟为一个虚拟串口](https://gitee.com/phytium_embedded/phytium-standalone-sdk/tree/master/example/peripherals/usb/pusb2_device/README.md)
|
||||
- - 3. [FreeRTOS 上模拟为一个 U 盘](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk/tree/master/example/peripheral/usb/pusb2_device/README.md)
|
||||
- - 4. [FreeRTOS 上模拟为虚拟串口](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk/tree/master/example/peripheral/usb/pusb2_device/README.md)
|
||||
- - 5. [RT-Thread 上模拟为一个 U 盘](https://github.com/RT-Thread/rt-thread/blob/master/bsp/phytium/doc/use_cherryusb.md)
|
||||
|
||||
---------------------------------------------
|
||||
|
||||
- PUSB2 的驱动功能以静态库的方式提供,
|
||||
- - libpusb2_hc_a64.a : AARCH64 主机模式驱动库
|
||||
- - libpusb2_dc_a64.a : AARCH64 从机模式驱动库
|
||||
- - libpusb2_hc_a32_hardfp.a :AARCH32 主机模式驱动库,使用硬浮点
|
||||
- - libpusb2_hc_a32_softfp.a :AARCH32 主机模式驱动库,使用软浮点
|
||||
- - libpusb2_dc_a32_hardfp.a :AARCH32 从机模式驱动库,使用硬浮点
|
||||
- - libpusb2_dc_a32_softfp.a :AARCH32 从机模式驱动库,使用软浮点
|
||||
|
||||
需要获取源代码请联系 `opensource_embedded@phytium.com.cn` 获取
|
||||
|
||||
# USB 2.0 OTG Controller (PUSB2)
|
||||
|
||||
- Phytium PI and the Phytium E2000 series development boards offer OTG interfaces compatible with USB 2.0.
|
||||
- Relevant usage examples can be run on the Phytium PI and E2000 D/Q Demo boards, including:
|
||||
|
||||
---------------------------------------------
|
||||
|
||||
- Host Mode
|
||||
|
||||
- 1. [Using a keyboard/mouse/USB flash drive as a host on FreeRTOS](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk/tree/master/example/peripheral/usb/pusb2_host/README.md)
|
||||
- 5. [Recognizing a keyboard/mouse/USB flash drive as a host on RT-Thread](https://github.com/RT-Thread/rt-thread/blob/master/bsp/phytium/doc/use_cherryusb.md)
|
||||
|
||||
---------------------------------------------
|
||||
|
||||
- Device Mode
|
||||
- 1. [Simulating as a USB flash drive on a standalone system](https://gitee.com/phytium_embedded/phytium-standalone-sdk/tree/master/example/peripherals/usb/pusb2_device/README.md)
|
||||
- 2. [Simulating as a virtual serial port on a standalone system](https://gitee.com/phytium_embedded/phytium-standalone-sdk/tree/master/example/peripherals/usb/pusb2_device/README.md)
|
||||
- 3. [Simulating as a USB flash drive on FreeRTOS](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk/tree/master/example/peripheral/usb/pusb2_device/README.md)
|
||||
- 4. [Simulating as a virtual serial port on FreeRTOS](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk/tree/master/example/peripheral/usb/pusb2_device/README.md)
|
||||
- 5. [Simulating as a USB flash drive on RT-Thread](https://github.com/RT-Thread/rt-thread/blob/master/bsp/phytium/doc/use_cherryusb.md)
|
||||
|
||||
---------------------------------------------
|
||||
|
||||
- The driver functionality of PUSB2 is provided as static libraries:
|
||||
- - `libpusb2_hc_a64.a` : Host mode driver library for AARCH64
|
||||
- - `libpusb2_dc_a64.a` : Device mode driver library for AARCH64
|
||||
- - `libpusb2_hc_a32_hardfp.a` : Host mode driver library for AARCH32, using hard floating point
|
||||
- - `libpusb2_hc_a32_softfp.a` : Host mode driver library for AARCH32, using soft floating point
|
||||
- - `libpusb2_dc_a32_hardfp.a` : Device mode driver library for AARCH32, using hard floating point
|
||||
- - `libpusb2_dc_a32_softfp.a` : Device mode driver library for AARCH32, using soft floating point
|
||||
|
||||
- To obtain the source code, please contact `opensource_embedded@phytium.com.cn`.
|
||||
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,266 @@
|
||||
/*
|
||||
* Copyright : (C) 2024 Phytium Information Technology, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Modify History:
|
||||
* Ver Who Date Changes
|
||||
* ----- ------ -------- --------------------------------------
|
||||
* 1.0 zhugengyu 2024/6/26 first commit
|
||||
*/
|
||||
#ifndef CHERRYUSB_CONFIG_H
|
||||
#define CHERRYUSB_CONFIG_H
|
||||
|
||||
#include "rtconfig.h"
|
||||
#include <rtthread.h>
|
||||
|
||||
/* ================ USB common Configuration ================ */
|
||||
|
||||
#define CONFIG_USB_PRINTF(...) rt_kprintf(__VA_ARGS__)
|
||||
|
||||
void *usb_sys_mem_malloc(size_t size);
|
||||
void usb_sys_mem_free(void *ptr);
|
||||
void *usb_sys_malloc_align(size_t align, size_t size);
|
||||
|
||||
#define usb_malloc(size) usb_sys_mem_malloc(size)
|
||||
#define usb_free(ptr) usb_sys_mem_free(ptr)
|
||||
#define usb_align(align, size) usb_sys_malloc_align(align, size)
|
||||
|
||||
unsigned long usb_hc_get_register_base(uint32_t id);
|
||||
unsigned long usb_dc_get_register_base(uint32_t id);
|
||||
|
||||
#define CONFIG_USB_DBG_LEVEL USB_DBG_ERROR
|
||||
|
||||
/* Enable print with color */
|
||||
#define CONFIG_USB_PRINTF_COLOR_ENABLE
|
||||
|
||||
/* data align size when use dma */
|
||||
#ifndef CONFIG_USB_ALIGN_SIZE
|
||||
#define CONFIG_USB_ALIGN_SIZE 4
|
||||
#endif
|
||||
|
||||
/* attribute data into no cache ram */
|
||||
#define USB_NOCACHE_RAM_SECTION __attribute__((section(".noncacheable")))
|
||||
|
||||
/* ================= USB Device Stack Configuration ================ */
|
||||
|
||||
/* Ep0 in and out transfer buffer */
|
||||
#ifndef CONFIG_USBDEV_REQUEST_BUFFER_LEN
|
||||
#define CONFIG_USBDEV_REQUEST_BUFFER_LEN 512
|
||||
#endif
|
||||
|
||||
/* Setup packet log for debug */
|
||||
// #define CONFIG_USBDEV_SETUP_LOG_PRINT
|
||||
|
||||
/* Send ep0 in data from user buffer instead of copying into ep0 reqdata
|
||||
* Please note that user buffer must be aligned with CONFIG_USB_ALIGN_SIZE
|
||||
*/
|
||||
// #define CONFIG_USBDEV_EP0_INDATA_NO_COPY
|
||||
|
||||
/* Check if the input descriptor is correct */
|
||||
// #define CONFIG_USBDEV_DESC_CHECK
|
||||
|
||||
/* Enable test mode */
|
||||
// #define CONFIG_USBDEV_TEST_MODE
|
||||
|
||||
#ifndef CONFIG_USBDEV_MSC_MAX_LUN
|
||||
#define CONFIG_USBDEV_MSC_MAX_LUN 1
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_USBDEV_MSC_MAX_BUFSIZE
|
||||
#define CONFIG_USBDEV_MSC_MAX_BUFSIZE 4096
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_USBDEV_MSC_MANUFACTURER_STRING
|
||||
#define CONFIG_USBDEV_MSC_MANUFACTURER_STRING ""
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_USBDEV_MSC_PRODUCT_STRING
|
||||
#define CONFIG_USBDEV_MSC_PRODUCT_STRING ""
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_USBDEV_MSC_VERSION_STRING
|
||||
#define CONFIG_USBDEV_MSC_VERSION_STRING "0.01"
|
||||
#endif
|
||||
|
||||
// #define CONFIG_USBDEV_MSC_THREAD
|
||||
|
||||
#ifndef CONFIG_USBDEV_MSC_PRIO
|
||||
#define CONFIG_USBDEV_MSC_PRIO 4
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_USBDEV_MSC_STACKSIZE
|
||||
#define CONFIG_USBDEV_MSC_STACKSIZE 8192
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE
|
||||
#define CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE 156
|
||||
#endif
|
||||
|
||||
/* rndis transfer buffer size, must be a multiple of (1536 + 44)*/
|
||||
#ifndef CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE
|
||||
#define CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE 1580
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_USBDEV_RNDIS_VENDOR_ID
|
||||
#define CONFIG_USBDEV_RNDIS_VENDOR_ID 0x0000ffff
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_USBDEV_RNDIS_VENDOR_DESC
|
||||
#define CONFIG_USBDEV_RNDIS_VENDOR_DESC "CherryUSB"
|
||||
#endif
|
||||
|
||||
#define CONFIG_USBDEV_RNDIS_USING_LWIP
|
||||
|
||||
/* ================ USB HOST Stack Configuration ================== */
|
||||
|
||||
#define CONFIG_USBHOST_MAX_RHPORTS 1
|
||||
#define CONFIG_USBHOST_MAX_EXTHUBS 0
|
||||
#define CONFIG_USBHOST_MAX_EHPORTS 8
|
||||
#define CONFIG_USBHOST_MAX_INTERFACES 8
|
||||
#define CONFIG_USBHOST_MAX_INTF_ALTSETTINGS 8
|
||||
#define CONFIG_USBHOST_MAX_ENDPOINTS 8
|
||||
|
||||
#define CONFIG_USBHOST_MAX_CDC_ACM_CLASS 4
|
||||
#define CONFIG_USBHOST_MAX_HID_CLASS 4
|
||||
#define CONFIG_USBHOST_MAX_MSC_CLASS 2
|
||||
#define CONFIG_USBHOST_MAX_AUDIO_CLASS 1
|
||||
#define CONFIG_USBHOST_MAX_VIDEO_CLASS 1
|
||||
|
||||
#define CONFIG_USBHOST_DEV_NAMELEN 16
|
||||
|
||||
#ifndef CONFIG_USBHOST_PSC_PRIO
|
||||
#define CONFIG_USBHOST_PSC_PRIO 0
|
||||
#endif
|
||||
#ifndef CONFIG_USBHOST_PSC_STACKSIZE
|
||||
#define CONFIG_USBHOST_PSC_STACKSIZE 8192
|
||||
#endif
|
||||
|
||||
//#define CONFIG_USBHOST_GET_STRING_DESC
|
||||
|
||||
// #define CONFIG_USBHOST_MSOS_ENABLE
|
||||
#ifndef CONFIG_USBHOST_MSOS_VENDOR_CODE
|
||||
#define CONFIG_USBHOST_MSOS_VENDOR_CODE 0x00
|
||||
#endif
|
||||
|
||||
/* Ep0 max transfer buffer */
|
||||
#ifndef CONFIG_USBHOST_REQUEST_BUFFER_LEN
|
||||
#define CONFIG_USBHOST_REQUEST_BUFFER_LEN 512
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT
|
||||
#define CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT 500
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_USBHOST_MSC_TIMEOUT
|
||||
#define CONFIG_USBHOST_MSC_TIMEOUT 5000
|
||||
#endif
|
||||
|
||||
/* This parameter affects usb performance, and depends on (TCP_WND)tcp eceive windows size,
|
||||
* you can change to 2K ~ 16K and must be larger than TCP RX windows size in order to avoid being overflow.
|
||||
*/
|
||||
#ifndef CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE
|
||||
#define CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE (2048)
|
||||
#endif
|
||||
|
||||
/* Because lwip do not support multi pbuf at a time, so increasing this variable has no performance improvement */
|
||||
#ifndef CONFIG_USBHOST_RNDIS_ETH_MAX_TX_SIZE
|
||||
#define CONFIG_USBHOST_RNDIS_ETH_MAX_TX_SIZE (2048)
|
||||
#endif
|
||||
|
||||
/* This parameter affects usb performance, and depends on (TCP_WND)tcp eceive windows size,
|
||||
* you can change to 2K ~ 16K and must be larger than TCP RX windows size in order to avoid being overflow.
|
||||
*/
|
||||
#ifndef CONFIG_USBHOST_CDC_NCM_ETH_MAX_RX_SIZE
|
||||
#define CONFIG_USBHOST_CDC_NCM_ETH_MAX_RX_SIZE (2048)
|
||||
#endif
|
||||
/* Because lwip do not support multi pbuf at a time, so increasing this variable has no performance improvement */
|
||||
#ifndef CONFIG_USBHOST_CDC_NCM_ETH_MAX_TX_SIZE
|
||||
#define CONFIG_USBHOST_CDC_NCM_ETH_MAX_TX_SIZE (2048)
|
||||
#endif
|
||||
|
||||
/* This parameter affects usb performance, and depends on (TCP_WND)tcp eceive windows size,
|
||||
* you can change to 2K ~ 16K and must be larger than TCP RX windows size in order to avoid being overflow.
|
||||
*/
|
||||
#ifndef CONFIG_USBHOST_ASIX_ETH_MAX_RX_SIZE
|
||||
#define CONFIG_USBHOST_ASIX_ETH_MAX_RX_SIZE (2048)
|
||||
#endif
|
||||
/* Because lwip do not support multi pbuf at a time, so increasing this variable has no performance improvement */
|
||||
#ifndef CONFIG_USBHOST_ASIX_ETH_MAX_TX_SIZE
|
||||
#define CONFIG_USBHOST_ASIX_ETH_MAX_TX_SIZE (2048)
|
||||
#endif
|
||||
|
||||
/* This parameter affects usb performance, and depends on (TCP_WND)tcp eceive windows size,
|
||||
* you can change to 2K ~ 16K and must be larger than TCP RX windows size in order to avoid being overflow.
|
||||
*/
|
||||
#ifndef CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE
|
||||
#define CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE (2048)
|
||||
#endif
|
||||
/* Because lwip do not support multi pbuf at a time, so increasing this variable has no performance improvement */
|
||||
#ifndef CONFIG_USBHOST_RTL8152_ETH_MAX_TX_SIZE
|
||||
#define CONFIG_USBHOST_RTL8152_ETH_MAX_TX_SIZE (2048)
|
||||
#endif
|
||||
|
||||
#define CONFIG_USBHOST_BLUETOOTH_HCI_H4
|
||||
// #define CONFIG_USBHOST_BLUETOOTH_HCI_LOG
|
||||
|
||||
#ifndef CONFIG_USBHOST_BLUETOOTH_TX_SIZE
|
||||
#define CONFIG_USBHOST_BLUETOOTH_TX_SIZE 2048
|
||||
#endif
|
||||
#ifndef CONFIG_USBHOST_BLUETOOTH_RX_SIZE
|
||||
#define CONFIG_USBHOST_BLUETOOTH_RX_SIZE 2048
|
||||
#endif
|
||||
|
||||
/* ================ USB Device Port Configuration ================*/
|
||||
|
||||
#ifndef CONFIG_USBDEV_MAX_BUS
|
||||
#define CONFIG_USBDEV_MAX_BUS 1 // for now, bus num must be 1 except hpm ip
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_USBDEV_EP_NUM
|
||||
#define CONFIG_USBDEV_EP_NUM 8
|
||||
#endif
|
||||
|
||||
/* ---------------- FSDEV Configuration ---------------- */
|
||||
//#define CONFIG_USBDEV_FSDEV_PMA_ACCESS 2 // maybe 1 or 2, many chips may have a difference
|
||||
|
||||
/* ---------------- DWC2 Configuration ---------------- */
|
||||
/* (5 * number of control endpoints + 8) + ((largest USB packet used / 4) + 1 for
|
||||
* status information) + (2 * number of OUT endpoints) + 1 for Global NAK
|
||||
*/
|
||||
// #define CONFIG_USB_DWC2_RXALL_FIFO_SIZE (1024 / 4)
|
||||
/* IN Endpoints Max packet Size / 4 */
|
||||
// #define CONFIG_USB_DWC2_TX0_FIFO_SIZE (64 / 4)
|
||||
// #define CONFIG_USB_DWC2_TX1_FIFO_SIZE (512 / 4)
|
||||
// #define CONFIG_USB_DWC2_TX2_FIFO_SIZE (64 / 4)
|
||||
// #define CONFIG_USB_DWC2_TX3_FIFO_SIZE (64 / 4)
|
||||
// #define CONFIG_USB_DWC2_TX4_FIFO_SIZE (0 / 4)
|
||||
// #define CONFIG_USB_DWC2_TX5_FIFO_SIZE (0 / 4)
|
||||
// #define CONFIG_USB_DWC2_TX6_FIFO_SIZE (0 / 4)
|
||||
// #define CONFIG_USB_DWC2_TX7_FIFO_SIZE (0 / 4)
|
||||
// #define CONFIG_USB_DWC2_TX8_FIFO_SIZE (0 / 4)
|
||||
|
||||
/* ---------------- MUSB Configuration ---------------- */
|
||||
// #define CONFIG_USB_MUSB_SUNXI
|
||||
|
||||
/* ================ USB Host Port Configuration ==================*/
|
||||
#ifndef CONFIG_INPUT_MOUSE_WHEEL
|
||||
#define CONFIG_INPUT_MOUSE_WHEEL
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_USBHOST_MAX_BUS
|
||||
#define CONFIG_USBHOST_MAX_BUS 3
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_USBHOST_PIPE_NUM
|
||||
#define CONFIG_USBHOST_PIPE_NUM 10
|
||||
#endif
|
||||
|
||||
/* ---------------- XHCI Configuration ---------------- */
|
||||
#define CONFIG_USB_XHCI_HCCR_OFFSET (0x0)
|
||||
|
||||
/* ---------------- PUSB2 Configuration ---------------- */
|
||||
#define CONFIG_USB_PUSB2_BUS_NUM 3U
|
||||
#define CONFIG_USB_PUSB2_BUS_ID 0U
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright : (C) 2024 Phytium Information Technology, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Modify History:
|
||||
* Ver Who Date Changes
|
||||
* ----- ------ -------- --------------------------------------
|
||||
* 1.0 zhugengyu 2024/6/26 first commit
|
||||
*/
|
||||
#include "rtthread.h"
|
||||
#include "interrupt.h"
|
||||
|
||||
#include "fparameters.h"
|
||||
|
||||
#include "usbd_core.h"
|
||||
|
||||
void USBD_IRQHandler(uint8_t busid);
|
||||
|
||||
void usb_assert(const char *filename, int linenum)
|
||||
{
|
||||
rt_assert_handler("", filename, linenum);
|
||||
}
|
||||
|
||||
static void usb_dc_pusb2_interrupt_handler(int irqno, void *param)
|
||||
{
|
||||
USBD_IRQHandler(CONFIG_USB_PUSB2_BUS_ID);
|
||||
}
|
||||
|
||||
static void usb_dc_setup_pusb2_interrupt(uint32_t id)
|
||||
{
|
||||
uint32_t irq_num = FUSB2_0_VHUB_IRQ_NUM;
|
||||
|
||||
rt_hw_interrupt_set_priority(irq_num, 0U);
|
||||
rt_hw_interrupt_install(irq_num, usb_dc_pusb2_interrupt_handler, NULL, "pusb2-dc");
|
||||
rt_hw_interrupt_umask(irq_num);
|
||||
}
|
||||
|
||||
static void usb_dc_revoke_pusb2_interrupt(uint32_t id)
|
||||
{
|
||||
uint32_t irq_num = FUSB2_0_VHUB_IRQ_NUM;
|
||||
|
||||
rt_hw_interrupt_mask(irq_num);
|
||||
}
|
||||
|
||||
unsigned long usb_dc_get_register_base(uint32_t id)
|
||||
{
|
||||
USB_ASSERT(id == FUSB2_ID_VHUB_0);
|
||||
return FUSB2_0_VHUB_BASE_ADDR;
|
||||
}
|
||||
|
||||
void usb_dc_low_level_init()
|
||||
{
|
||||
usb_dc_setup_pusb2_interrupt(CONFIG_USB_PUSB2_BUS_ID);
|
||||
}
|
||||
|
||||
void usb_dc_low_level_deinit(void)
|
||||
{
|
||||
usb_dc_revoke_pusb2_interrupt(CONFIG_USB_PUSB2_BUS_ID);
|
||||
}
|
||||
|
||||
void *usb_sys_mem_malloc(size_t size)
|
||||
{
|
||||
void *buf = rt_malloc(size);
|
||||
|
||||
if (buf) {
|
||||
rt_memset(buf, 0, size);
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
void usb_sys_mem_free(void *ptr)
|
||||
{
|
||||
if (ptr) {
|
||||
rt_free(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void *usb_sys_malloc_align(size_t align, size_t size)
|
||||
{
|
||||
void *buf = rt_malloc_align(size, align);
|
||||
|
||||
if (buf) {
|
||||
rt_memset(buf, 0, size);
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
int usbd_set_remote_wakeup(uint8_t busid)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright : (C) 2024 Phytium Information Technology, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Modify History:
|
||||
* Ver Who Date Changes
|
||||
* ----- ------ -------- --------------------------------------
|
||||
* 1.0 zhugengyu 2024/6/26 first commit
|
||||
*/
|
||||
#include "rtthread.h"
|
||||
#include "interrupt.h"
|
||||
|
||||
#include "fparameters.h"
|
||||
|
||||
#include "usbh_core.h"
|
||||
|
||||
static const uint32_t irq_nums[] = {
|
||||
FUSB2_0_VHUB_IRQ_NUM, FUSB2_1_IRQ_NUM, FUSB2_2_IRQ_NUM
|
||||
};
|
||||
|
||||
void USBH_IRQHandler(uint8_t busid);
|
||||
|
||||
void usb_assert(const char *filename, int linenum)
|
||||
{
|
||||
rt_assert_handler("", filename, linenum);
|
||||
}
|
||||
|
||||
static void usb_hc_pusb2_interrupt_handler(int irqno, void *param)
|
||||
{
|
||||
if (irqno == FUSB2_0_VHUB_IRQ_NUM) {
|
||||
USBH_IRQHandler(FUSB2_ID_VHUB_0);
|
||||
} else if (irqno == FUSB2_1_IRQ_NUM) {
|
||||
USBH_IRQHandler(FUSB2_ID_1);
|
||||
} else if (irqno == FUSB2_2_IRQ_NUM) {
|
||||
USBH_IRQHandler(FUSB2_ID_2);
|
||||
}
|
||||
}
|
||||
|
||||
static void usb_hc_setup_pusb2_interrupt(uint32_t id)
|
||||
{
|
||||
uint32_t irq_num = irq_nums[id];
|
||||
|
||||
rt_hw_interrupt_set_priority(irq_num, 0U);
|
||||
rt_hw_interrupt_install(irq_num, usb_hc_pusb2_interrupt_handler, NULL, "pusb2-hc");
|
||||
rt_hw_interrupt_umask(irq_num);
|
||||
|
||||
USB_LOG_DBG("Enable irq-%d\n", irq_num);
|
||||
}
|
||||
|
||||
static void usb_hc_revoke_pusb2_interrupt(uint32_t id)
|
||||
{
|
||||
uint32_t irq_num = irq_nums[id];
|
||||
|
||||
rt_hw_interrupt_mask(irq_num);
|
||||
}
|
||||
|
||||
unsigned long usb_hc_get_register_base(uint32_t id)
|
||||
{
|
||||
if (id == FUSB2_ID_VHUB_0) {
|
||||
return FUSB2_0_VHUB_BASE_ADDR;
|
||||
} else if (id == FUSB2_ID_1) {
|
||||
return FUSB2_1_BASE_ADDR;
|
||||
} else if (id == FUSB2_ID_2) {
|
||||
return FUSB2_2_BASE_ADDR;
|
||||
} else {
|
||||
USB_ASSERT(0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void usb_hc_low_level_init(struct usbh_bus *bus)
|
||||
{
|
||||
usb_hc_setup_pusb2_interrupt(bus->busid);
|
||||
}
|
||||
|
||||
void usb_hc_low_level_deinit(struct usbh_bus *bus)
|
||||
{
|
||||
usb_hc_revoke_pusb2_interrupt(bus->busid);
|
||||
}
|
||||
|
||||
void *usb_sys_mem_malloc(size_t size)
|
||||
{
|
||||
void *buf = rt_malloc(size);
|
||||
|
||||
if (buf) {
|
||||
rt_memset(buf, 0, size);
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
void usb_sys_mem_free(void *ptr)
|
||||
{
|
||||
if (ptr) {
|
||||
rt_free(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void *usb_sys_malloc_align(size_t align, size_t size)
|
||||
{
|
||||
void *buf = rt_malloc_align(size, align);
|
||||
|
||||
if (buf) {
|
||||
rt_memset(buf, 0, size);
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
# Note
|
||||
|
||||
## Support Chip List
|
||||
|
||||
- RP2040/RP2350
|
||||
@@ -0,0 +1,595 @@
|
||||
/*
|
||||
* Copyright (c) 2022, HaiMianBBao
|
||||
* Copyright (c) 2025, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usbd_core.h"
|
||||
#include "hardware/resets.h"
|
||||
#include "hardware/irq.h"
|
||||
#include "hardware/structs/usb.h"
|
||||
#if CHERRYUSB_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX
|
||||
#include "pico/fix/rp2040_usb_device_enumeration.h"
|
||||
#endif
|
||||
|
||||
#define usb_hw_set hw_set_alias(usb_hw)
|
||||
#define usb_hw_clear hw_clear_alias(usb_hw)
|
||||
|
||||
#ifndef FORCE_VBUS_DETECT
|
||||
#define FORCE_VBUS_DETECT 1
|
||||
#endif
|
||||
|
||||
/* Endpoint state */
|
||||
struct rp2040_ep_state {
|
||||
uint16_t ep_mps; /* Endpoint max packet size */
|
||||
uint8_t ep_type; /* Endpoint type */
|
||||
uint8_t ep_stalled; /* Endpoint stall flag */
|
||||
uint8_t ep_enable; /* Endpoint enable */
|
||||
uint8_t ep_addr; /* Endpoint address */
|
||||
uint8_t *xfer_buf;
|
||||
uint32_t xfer_len;
|
||||
uint32_t actual_xfer_len;
|
||||
|
||||
volatile uint32_t *endpoint_control; /*!< Endpoint control register */
|
||||
volatile uint32_t *buffer_control; /*!< Buffer control register */
|
||||
uint8_t *data_buffer; /*!< Buffer pointer in usb dpram */
|
||||
uint8_t next_pid; /*!< Toggle after each packet (unless replying to a SETUP) */
|
||||
};
|
||||
|
||||
/* Driver state */
|
||||
struct rp2040_udc {
|
||||
volatile uint8_t dev_addr;
|
||||
struct rp2040_ep_state in_ep[USB_NUM_ENDPOINTS]; /*!< IN endpoint parameters*/
|
||||
struct rp2040_ep_state out_ep[USB_NUM_ENDPOINTS]; /*!< OUT endpoint parameters */
|
||||
struct usb_setup_packet setup; /*!< Setup package that may be used in interrupt processing (outside the protocol stack) */
|
||||
} g_rp2040_udc;
|
||||
|
||||
void rp2040_usbd_irq(void);
|
||||
|
||||
/**
|
||||
* @brief Take a buffer pointer located in the USB RAM and return as an offset of the RAM.
|
||||
*
|
||||
* @param buf
|
||||
* @return uint32_t
|
||||
*/
|
||||
static inline uint32_t usb_buffer_offset(volatile uint8_t *buf)
|
||||
{
|
||||
return (uint32_t)buf ^ (uint32_t)usb_dpram;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set up the endpoint control register for an endpoint (if applicable. Not valid for EP0).
|
||||
*
|
||||
* @param ep
|
||||
*/
|
||||
void usb_setup_endpoint(const struct rp2040_ep_state *ep)
|
||||
{
|
||||
// EP0 doesn't have one so return if that is the case
|
||||
if (!ep->endpoint_control) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the data buffer as an offset of the USB controller's DPRAM
|
||||
uint32_t dpram_offset = usb_buffer_offset(ep->data_buffer);
|
||||
uint32_t reg = EP_CTRL_ENABLE_BITS |
|
||||
EP_CTRL_INTERRUPT_PER_BUFFER |
|
||||
(ep->ep_type << EP_CTRL_BUFFER_TYPE_LSB) |
|
||||
dpram_offset;
|
||||
*ep->endpoint_control = reg;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Starts a transfer on a given endpoint.
|
||||
*
|
||||
* @param ep, the endpoint configuration.
|
||||
* @param buf, the data buffer to send. Only applicable if the endpoint is TX
|
||||
* @param len, the length of the data in buf (this example limits max len to one packet - 64 bytes)
|
||||
*/
|
||||
static void usb_start_transfer(struct rp2040_ep_state *ep, uint8_t *buf, uint16_t len)
|
||||
{
|
||||
/*!< Prepare buffer control register value */
|
||||
uint32_t val = len | USB_BUF_CTRL_AVAIL;
|
||||
|
||||
if (len < ep->ep_mps) {
|
||||
val |= USB_BUF_CTRL_LAST;
|
||||
}
|
||||
|
||||
if (USB_EP_DIR_IS_IN(ep->ep_addr)) {
|
||||
/*!< Need to copy the data from the user buffer to the usb memory */
|
||||
if (buf != NULL) {
|
||||
memcpy((void *)ep->data_buffer, (void *)buf, len);
|
||||
}
|
||||
/*!< Mark as full */
|
||||
val |= USB_BUF_CTRL_FULL;
|
||||
}
|
||||
|
||||
/*!< Set pid and flip for next transfer */
|
||||
val |= ep->next_pid ? USB_BUF_CTRL_DATA1_PID : USB_BUF_CTRL_DATA0_PID;
|
||||
ep->next_pid ^= 1u;
|
||||
|
||||
*ep->buffer_control = val;
|
||||
}
|
||||
|
||||
int usb_dc_init(uint8_t busid)
|
||||
{
|
||||
uint8_t *next_buffer_ptr;
|
||||
|
||||
memset(&g_rp2040_udc, 0, sizeof(struct rp2040_udc));
|
||||
|
||||
g_rp2040_udc.in_ep[0].endpoint_control = NULL;
|
||||
g_rp2040_udc.in_ep[0].data_buffer = &usb_dpram->ep0_buf_a[0];
|
||||
g_rp2040_udc.out_ep[0].endpoint_control = NULL;
|
||||
g_rp2040_udc.out_ep[0].data_buffer = &usb_dpram->ep0_buf_a[0];
|
||||
|
||||
for (uint32_t i = 0; i < USB_NUM_ENDPOINTS; i++) {
|
||||
g_rp2040_udc.in_ep[i].buffer_control = &usb_dpram->ep_buf_ctrl[i].in;
|
||||
g_rp2040_udc.out_ep[i].buffer_control = &usb_dpram->ep_buf_ctrl[i].out;
|
||||
|
||||
if (i != 0) {
|
||||
g_rp2040_udc.in_ep[i].endpoint_control = &usb_dpram->ep_ctrl[i - 1].in;
|
||||
g_rp2040_udc.out_ep[i].endpoint_control = &usb_dpram->ep_ctrl[i - 1].out;
|
||||
}
|
||||
}
|
||||
|
||||
next_buffer_ptr = &usb_dpram->epx_data[0];
|
||||
|
||||
for (uint32_t i = 1; i < USB_NUM_ENDPOINTS; i++) {
|
||||
g_rp2040_udc.in_ep[i].data_buffer = next_buffer_ptr;
|
||||
if (i == 1) {
|
||||
next_buffer_ptr += 1024; /* for iso video */
|
||||
} else {
|
||||
next_buffer_ptr += 64;
|
||||
}
|
||||
|
||||
g_rp2040_udc.out_ep[i].data_buffer = next_buffer_ptr;
|
||||
next_buffer_ptr += 64;
|
||||
}
|
||||
|
||||
// Remove shared irq if it was previously added so as not to fill up shared irq slots
|
||||
irq_remove_handler(USBCTRL_IRQ, rp2040_usbd_irq);
|
||||
|
||||
irq_add_shared_handler(USBCTRL_IRQ, rp2040_usbd_irq, PICO_SHARED_IRQ_HANDLER_HIGHEST_ORDER_PRIORITY);
|
||||
|
||||
// Reset usb controller
|
||||
reset_unreset_block_num_wait_blocking(RESET_USBCTRL);
|
||||
|
||||
/*!< Clear any previous state just in case */
|
||||
memset(usb_hw, 0, sizeof(*usb_hw));
|
||||
memset(usb_dpram, 0, sizeof(*usb_dpram));
|
||||
|
||||
/*!< Mux the controller to the onboard usb phy */
|
||||
usb_hw->muxing = USB_USB_MUXING_TO_PHY_BITS | USB_USB_MUXING_SOFTCON_BITS;
|
||||
|
||||
#if FORCE_VBUS_DETECT
|
||||
// Force VBUS detect so the device thinks it is plugged into a host
|
||||
usb_hw->pwr = USB_USB_PWR_VBUS_DETECT_BITS | USB_USB_PWR_VBUS_DETECT_OVERRIDE_EN_BITS;
|
||||
#endif
|
||||
|
||||
// Enable the USB controller in device mode.
|
||||
usb_hw->main_ctrl = USB_MAIN_CTRL_CONTROLLER_EN_BITS;
|
||||
|
||||
// Enable an interrupt per EP0 transaction
|
||||
usb_hw->sie_ctrl = USB_SIE_CTRL_EP0_INT_1BUF_BITS; // <2>
|
||||
|
||||
// Enable interrupts for when a buffer is done, when the bus is reset,
|
||||
// and when a setup packet is received
|
||||
usb_hw->inte = USB_INTS_BUFF_STATUS_BITS | USB_INTS_BUS_RESET_BITS | USB_INTS_SETUP_REQ_BITS |
|
||||
USB_INTS_DEV_SUSPEND_BITS | USB_INTS_DEV_RESUME_FROM_HOST_BITS |
|
||||
(FORCE_VBUS_DETECT ? 0 : USB_INTS_DEV_CONN_DIS_BITS);
|
||||
|
||||
#ifdef CONFIG_USBDEV_SOF_ENABLE
|
||||
usb_hw->inte |= USB_INTS_DEV_SOF_BITS;
|
||||
#endif
|
||||
|
||||
// Enable USB interrupt at processor
|
||||
irq_set_enabled(USBCTRL_IRQ, true);
|
||||
|
||||
usb_hw_set->sie_ctrl = USB_SIE_CTRL_PULLUP_EN_BITS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_dc_deinit(uint8_t busid)
|
||||
{
|
||||
irq_set_enabled(USBCTRL_IRQ, false);
|
||||
// Remove shared irq if it was previously added so as not to fill up shared irq slots
|
||||
irq_remove_handler(USBCTRL_IRQ, rp2040_usbd_irq);
|
||||
|
||||
usb_hw_clear->sie_ctrl = USB_SIE_CTRL_PULLUP_EN_BITS;
|
||||
memset(&g_rp2040_udc, 0, sizeof(struct rp2040_udc));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_set_address(uint8_t busid, const uint8_t addr)
|
||||
{
|
||||
g_rp2040_udc.dev_addr = addr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_set_remote_wakeup(uint8_t busid)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t usbd_get_port_speed(uint8_t busid)
|
||||
{
|
||||
return USB_SPEED_FULL;
|
||||
}
|
||||
|
||||
int usbd_ep_open(uint8_t busid, const struct usb_endpoint_descriptor *ep)
|
||||
{
|
||||
uint8_t ep_idx = USB_EP_GET_IDX(ep->bEndpointAddress);
|
||||
|
||||
if (USB_EP_DIR_IS_OUT(ep->bEndpointAddress)) {
|
||||
g_rp2040_udc.out_ep[ep_idx].ep_mps = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
|
||||
g_rp2040_udc.out_ep[ep_idx].ep_type = USB_GET_ENDPOINT_TYPE(ep->bmAttributes);
|
||||
g_rp2040_udc.out_ep[ep_idx].ep_addr = ep->bEndpointAddress;
|
||||
g_rp2040_udc.out_ep[ep_idx].ep_enable = true;
|
||||
/*!< Clear control reg */
|
||||
*(g_rp2040_udc.out_ep[ep_idx].buffer_control) = 0;
|
||||
|
||||
usb_setup_endpoint(&g_rp2040_udc.out_ep[ep_idx]);
|
||||
} else {
|
||||
g_rp2040_udc.in_ep[ep_idx].ep_mps = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
|
||||
g_rp2040_udc.in_ep[ep_idx].ep_type = USB_GET_ENDPOINT_TYPE(ep->bmAttributes);
|
||||
g_rp2040_udc.in_ep[ep_idx].ep_addr = ep->bEndpointAddress;
|
||||
g_rp2040_udc.in_ep[ep_idx].ep_enable = true;
|
||||
/*!< Clear control reg */
|
||||
*(g_rp2040_udc.in_ep[ep_idx].buffer_control) = 0;
|
||||
|
||||
usb_setup_endpoint(&g_rp2040_udc.in_ep[ep_idx]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_close(uint8_t busid, const uint8_t ep)
|
||||
{
|
||||
if (USB_EP_DIR_IS_IN(ep)) {
|
||||
} else if (USB_EP_DIR_IS_OUT(ep)) {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_set_stall(uint8_t busid, const uint8_t ep)
|
||||
{
|
||||
if (USB_EP_GET_IDX(ep) == 0) {
|
||||
/**
|
||||
* A stall on EP0 has to be armed so it can be cleared on the next setup packet
|
||||
*/
|
||||
usb_hw_set->ep_stall_arm = (USB_EP_DIR_IS_IN(ep)) ? USB_EP_STALL_ARM_EP0_IN_BITS : USB_EP_STALL_ARM_EP0_OUT_BITS;
|
||||
}
|
||||
|
||||
if (USB_EP_DIR_IS_OUT(ep)) {
|
||||
*(g_rp2040_udc.out_ep[USB_EP_GET_IDX(ep)].buffer_control) = USB_BUF_CTRL_STALL;
|
||||
} else {
|
||||
*(g_rp2040_udc.in_ep[USB_EP_GET_IDX(ep)].buffer_control) = USB_BUF_CTRL_STALL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_clear_stall(uint8_t busid, const uint8_t ep)
|
||||
{
|
||||
uint8_t ep_idx = USB_EP_GET_IDX(ep);
|
||||
|
||||
if (ep_idx != 0) {
|
||||
if (USB_EP_DIR_IS_OUT(ep)) {
|
||||
g_rp2040_udc.out_ep[USB_EP_GET_IDX(ep)].next_pid = 0;
|
||||
*(g_rp2040_udc.out_ep[USB_EP_GET_IDX(ep)].buffer_control) = ~USB_BUF_CTRL_STALL;
|
||||
} else {
|
||||
g_rp2040_udc.in_ep[USB_EP_GET_IDX(ep)].next_pid = 0;
|
||||
*(g_rp2040_udc.in_ep[USB_EP_GET_IDX(ep)].buffer_control) = ~USB_BUF_CTRL_STALL;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_is_stalled(uint8_t busid, const uint8_t ep, uint8_t *stalled)
|
||||
{
|
||||
if (USB_EP_DIR_IS_OUT(ep)) {
|
||||
if (*(g_rp2040_udc.out_ep[USB_EP_GET_IDX(ep)].buffer_control) & USB_BUF_CTRL_STALL) {
|
||||
*stalled = 1;
|
||||
} else {
|
||||
*stalled = 0;
|
||||
}
|
||||
} else {
|
||||
if (*(g_rp2040_udc.in_ep[USB_EP_GET_IDX(ep)].buffer_control) & USB_BUF_CTRL_STALL) {
|
||||
*stalled = 1;
|
||||
} else {
|
||||
*stalled = 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_start_write(uint8_t busid, const uint8_t ep, const uint8_t *data, uint32_t data_len)
|
||||
{
|
||||
uint8_t ep_idx = USB_EP_GET_IDX(ep);
|
||||
|
||||
if (!data && data_len) {
|
||||
return -1;
|
||||
}
|
||||
if (!g_rp2040_udc.in_ep[ep_idx].ep_enable) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
g_rp2040_udc.in_ep[ep_idx].xfer_buf = (uint8_t *)data;
|
||||
g_rp2040_udc.in_ep[ep_idx].xfer_len = data_len;
|
||||
g_rp2040_udc.in_ep[ep_idx].actual_xfer_len = 0;
|
||||
|
||||
if (data_len == 0) {
|
||||
usb_start_transfer(&g_rp2040_udc.in_ep[ep_idx], NULL, 0);
|
||||
} else {
|
||||
data_len = MIN(data_len, g_rp2040_udc.in_ep[ep_idx].ep_mps);
|
||||
usb_start_transfer(&g_rp2040_udc.in_ep[ep_idx], g_rp2040_udc.in_ep[ep_idx].xfer_buf, data_len);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_start_read(uint8_t busid, const uint8_t ep, uint8_t *data, uint32_t data_len)
|
||||
{
|
||||
uint8_t ep_idx = USB_EP_GET_IDX(ep);
|
||||
|
||||
if (!data && data_len) {
|
||||
return -1;
|
||||
}
|
||||
if (!g_rp2040_udc.out_ep[ep_idx].ep_enable) {
|
||||
return -2;
|
||||
}
|
||||
g_rp2040_udc.out_ep[ep_idx].xfer_buf = (uint8_t *)data;
|
||||
g_rp2040_udc.out_ep[ep_idx].xfer_len = data_len;
|
||||
g_rp2040_udc.out_ep[ep_idx].actual_xfer_len = 0;
|
||||
|
||||
if (data_len == 0) {
|
||||
usb_start_transfer(&g_rp2040_udc.out_ep[ep_idx], NULL, 0);
|
||||
} else {
|
||||
/*!< Not zlp */
|
||||
data_len = MIN(data_len, g_rp2040_udc.out_ep[ep_idx].ep_mps);
|
||||
usb_start_transfer(&g_rp2040_udc.out_ep[ep_idx], g_rp2040_udc.out_ep[ep_idx].xfer_buf, data_len);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Notify an endpoint that a transfer has completed.
|
||||
*
|
||||
* @param ep, the endpoint to notify.
|
||||
*/
|
||||
static void usb_handle_ep_buff_done(struct rp2040_ep_state *ep)
|
||||
{
|
||||
uint32_t buffer_control = *ep->buffer_control;
|
||||
/*!< Get the transfer length for this endpoint */
|
||||
uint16_t read_count = buffer_control & USB_BUF_CTRL_LEN_MASK;
|
||||
/*!< Call that endpoints buffer done handler */
|
||||
if (ep->ep_addr == 0x80) {
|
||||
/*!< EP0 In */
|
||||
/**
|
||||
* Determine the current setup direction
|
||||
*/
|
||||
switch (g_rp2040_udc.setup.bmRequestType >> USB_REQUEST_DIR_SHIFT) {
|
||||
case 1:
|
||||
/*!< Get */
|
||||
if (g_rp2040_udc.in_ep[0].xfer_len > g_rp2040_udc.in_ep[0].ep_mps) {
|
||||
g_rp2040_udc.in_ep[0].xfer_len -= g_rp2040_udc.in_ep[0].ep_mps;
|
||||
g_rp2040_udc.in_ep[0].actual_xfer_len += g_rp2040_udc.in_ep[0].ep_mps;
|
||||
usbd_event_ep_in_complete_handler(0, 0 | 0x80, g_rp2040_udc.in_ep[0].actual_xfer_len);
|
||||
} else {
|
||||
g_rp2040_udc.in_ep[0].actual_xfer_len += g_rp2040_udc.in_ep[0].xfer_len;
|
||||
g_rp2040_udc.in_ep[0].xfer_len = 0;
|
||||
/**
|
||||
* EP0 In complete and host will send a out token to get 0 length packet
|
||||
* In the next usbd_event_ep_in_complete_handler, stack will start read 0 length packet
|
||||
* and host must send data1 packet.We resest the ep0 next_pid = 1 in setup interrupt head.
|
||||
*/
|
||||
usbd_event_ep_in_complete_handler(0, 0 | 0x80, g_rp2040_udc.in_ep[0].actual_xfer_len);
|
||||
}
|
||||
break;
|
||||
case 0:
|
||||
/*!< Set */
|
||||
if (g_rp2040_udc.dev_addr > 0) {
|
||||
usb_hw->dev_addr_ctrl = g_rp2040_udc.dev_addr;
|
||||
g_rp2040_udc.dev_addr = 0;
|
||||
} else {
|
||||
/*!< Normal status stage // Setup out...out in */
|
||||
/**
|
||||
* Perpar for next setup
|
||||
*/
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
} else if (ep->ep_addr == 0x00) {
|
||||
/*!< EP0 Out */
|
||||
memcpy(g_rp2040_udc.out_ep[0].xfer_buf, g_rp2040_udc.out_ep[0].data_buffer, read_count);
|
||||
if (read_count == 0) {
|
||||
/*!< Normal status stage // Setup in...in out */
|
||||
/**
|
||||
* Perpar for next setup
|
||||
*/
|
||||
}
|
||||
|
||||
g_rp2040_udc.out_ep[0].actual_xfer_len += read_count;
|
||||
g_rp2040_udc.out_ep[0].xfer_len -= read_count;
|
||||
|
||||
usbd_event_ep_out_complete_handler(0, 0x00, g_rp2040_udc.out_ep[0].actual_xfer_len);
|
||||
} else {
|
||||
/*!< Others ep */
|
||||
uint16_t data_len = 0;
|
||||
if (USB_EP_DIR_IS_OUT(ep->ep_addr)) {
|
||||
/*!< flip the pid */
|
||||
memcpy(g_rp2040_udc.out_ep[(ep->ep_addr) & 0x0f].xfer_buf, g_rp2040_udc.out_ep[(ep->ep_addr) & 0x0f].data_buffer, read_count);
|
||||
g_rp2040_udc.out_ep[(ep->ep_addr) & 0x0f].xfer_buf += read_count;
|
||||
g_rp2040_udc.out_ep[(ep->ep_addr) & 0x0f].actual_xfer_len += read_count;
|
||||
g_rp2040_udc.out_ep[(ep->ep_addr) & 0x0f].xfer_len -= read_count;
|
||||
|
||||
if (read_count < g_rp2040_udc.out_ep[(ep->ep_addr) & 0x0f].ep_mps || g_rp2040_udc.out_ep[(ep->ep_addr) & 0x0f].xfer_len == 0) {
|
||||
/*!< Out complete */
|
||||
usbd_event_ep_out_complete_handler(0, ep->ep_addr, g_rp2040_udc.out_ep[(ep->ep_addr) & 0x0f].actual_xfer_len);
|
||||
} else {
|
||||
/*!< Need read again */
|
||||
data_len = MIN(g_rp2040_udc.out_ep[(ep->ep_addr) & 0x0f].xfer_len, g_rp2040_udc.out_ep[(ep->ep_addr) & 0x0f].ep_mps);
|
||||
usb_start_transfer(&g_rp2040_udc.out_ep[(ep->ep_addr) & 0x0f], NULL, data_len);
|
||||
}
|
||||
} else {
|
||||
if (g_rp2040_udc.in_ep[(ep->ep_addr) & 0x0f].xfer_len > g_rp2040_udc.in_ep[(ep->ep_addr) & 0x0f].ep_mps) {
|
||||
/*!< Need tx again */
|
||||
g_rp2040_udc.in_ep[(ep->ep_addr) & 0x0f].xfer_len -= g_rp2040_udc.in_ep[(ep->ep_addr) & 0x0f].ep_mps;
|
||||
g_rp2040_udc.in_ep[(ep->ep_addr) & 0x0f].xfer_buf += g_rp2040_udc.in_ep[(ep->ep_addr) & 0x0f].ep_mps;
|
||||
g_rp2040_udc.in_ep[(ep->ep_addr) & 0x0f].actual_xfer_len += g_rp2040_udc.in_ep[(ep->ep_addr) & 0x0f].ep_mps;
|
||||
data_len = MIN(g_rp2040_udc.in_ep[(ep->ep_addr) & 0x0f].xfer_len, g_rp2040_udc.in_ep[(ep->ep_addr) & 0x0f].ep_mps);
|
||||
usb_start_transfer(&g_rp2040_udc.in_ep[(ep->ep_addr) & 0x0f], g_rp2040_udc.in_ep[(ep->ep_addr) & 0x0f].xfer_buf, data_len);
|
||||
} else {
|
||||
/*!< In complete */
|
||||
g_rp2040_udc.in_ep[(ep->ep_addr) & 0x0f].actual_xfer_len += g_rp2040_udc.in_ep[(ep->ep_addr) & 0x0f].xfer_len;
|
||||
g_rp2040_udc.in_ep[(ep->ep_addr) & 0x0f].xfer_len = 0;
|
||||
usbd_event_ep_in_complete_handler(0, ep->ep_addr, g_rp2040_udc.in_ep[(ep->ep_addr) & 0x0f].actual_xfer_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Find the endpoint configuration for a specified endpoint number and
|
||||
* direction and notify it that a transfer has completed.
|
||||
*
|
||||
* @param ep_num
|
||||
* @param in
|
||||
*/
|
||||
static void usb_handle_buff_done(uint8_t ep_num, bool in)
|
||||
{
|
||||
uint8_t ep_addr = ep_num | (in ? USB_EP_DIR_IN : 0);
|
||||
if (USB_EP_DIR_IS_OUT(ep_addr)) {
|
||||
usb_handle_ep_buff_done(&g_rp2040_udc.out_ep[ep_num]);
|
||||
} else {
|
||||
usb_handle_ep_buff_done(&g_rp2040_udc.in_ep[ep_num]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handle a "buffer status" irq. This means that one or more
|
||||
* buffers have been sent / received. Notify each endpoint where this
|
||||
* is the case.
|
||||
*/
|
||||
static void usb_handle_buff_status(void)
|
||||
{
|
||||
uint32_t remaining_buffers = usb_hw->buf_status;
|
||||
|
||||
uint32_t bit = 1u;
|
||||
for (uint8_t i = 0; remaining_buffers && i < USB_NUM_ENDPOINTS * 2; i++) {
|
||||
if (remaining_buffers & bit) {
|
||||
/*!< clear this in advance */
|
||||
usb_hw_clear->buf_status = bit;
|
||||
/*!< IN transfer for even i, OUT transfer for odd i */
|
||||
usb_handle_buff_done(i >> 1u, !(i & 1u));
|
||||
remaining_buffers &= ~bit;
|
||||
}
|
||||
bit <<= 1u;
|
||||
}
|
||||
}
|
||||
|
||||
void USBD_IRQHandler(uint8_t busid)
|
||||
{
|
||||
uint32_t const status = usb_hw->ints;
|
||||
uint32_t handled = 0;
|
||||
|
||||
if (status & USB_INTS_BUFF_STATUS_BITS) {
|
||||
handled |= USB_INTS_BUFF_STATUS_BITS;
|
||||
usb_handle_buff_status();
|
||||
}
|
||||
|
||||
if (status & USB_INTS_SETUP_REQ_BITS) {
|
||||
handled |= USB_INTS_SETUP_REQ_BITS;
|
||||
memcpy((uint8_t *)&g_rp2040_udc.setup, (uint8_t const *)&usb_dpram->setup_packet, 8);
|
||||
/**
|
||||
* reset pid to both 1 (data and ack)
|
||||
*/
|
||||
g_rp2040_udc.in_ep[0].next_pid = 1;
|
||||
g_rp2040_udc.out_ep[0].next_pid = 1;
|
||||
usbd_event_ep0_setup_complete_handler(0, (uint8_t *)&g_rp2040_udc.setup);
|
||||
usb_hw_clear->sie_status = USB_SIE_STATUS_SETUP_REC_BITS;
|
||||
}
|
||||
|
||||
#if FORCE_VBUS_DETECT == 0
|
||||
/**
|
||||
* Since we force VBUS detect On, device will always think it is connected and
|
||||
* couldn't distinguish between disconnect and suspend
|
||||
*/
|
||||
if (status & USB_INTS_DEV_CONN_DIS_BITS) {
|
||||
handled |= USB_INTS_DEV_CONN_DIS_BITS;
|
||||
if (usb_hw->sie_status & USB_SIE_STATUS_CONNECTED_BITS) {
|
||||
/*!< Connected: nothing to do */
|
||||
usbd_event_connect_handler(0);
|
||||
} else {
|
||||
/*!< Disconnected */
|
||||
usbd_event_disconnect_handler(0);
|
||||
}
|
||||
usb_hw_clear->sie_status = USB_SIE_STATUS_CONNECTED_BITS;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* SE0 for 2.5 us or more (will last at least 10ms)
|
||||
*/
|
||||
if (status & USB_INTS_BUS_RESET_BITS) {
|
||||
handled |= USB_INTS_BUS_RESET_BITS;
|
||||
usb_hw_clear->sie_status = USB_SIE_STATUS_BUS_RESET_BITS;
|
||||
|
||||
usb_hw->dev_addr_ctrl = 0;
|
||||
|
||||
for (uint8_t i = 0; i < USB_NUM_ENDPOINTS - 1; i++) {
|
||||
/*!< Start at ep1 */
|
||||
usb_dpram->ep_ctrl[i].in = 0;
|
||||
usb_dpram->ep_ctrl[i].out = 0;
|
||||
}
|
||||
|
||||
usbd_event_reset_handler(0);
|
||||
|
||||
#if CHERRYUSB_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX
|
||||
/**
|
||||
* Only run enumeration walk-around if pull up is enabled
|
||||
*/
|
||||
if (usb_hw->sie_ctrl & USB_SIE_CTRL_PULLUP_EN_BITS)
|
||||
rp2040_usb_device_enumeration_fix();
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Note from pico datasheet 4.1.2.6.4 (v1.2)
|
||||
* If you enable the suspend interrupt, it is likely you will see a suspend interrupt when
|
||||
* the device is first connected but the bus is idle. The bus can be idle for a few ms before
|
||||
* the host begins sending start of frame packets. You will also see a suspend interrupt
|
||||
* when the device is disconnected if you do not have a VBUS detect circuit connected. This is
|
||||
* because without VBUS detection, it is impossible to tell the difference between
|
||||
* being disconnected and suspended.
|
||||
*/
|
||||
if (status & USB_INTS_DEV_SUSPEND_BITS) {
|
||||
handled |= USB_INTS_DEV_SUSPEND_BITS;
|
||||
/*!< Suspend */
|
||||
usb_hw_clear->sie_status = USB_SIE_STATUS_SUSPENDED_BITS;
|
||||
usbd_event_suspend_handler(0);
|
||||
}
|
||||
|
||||
if (status & USB_INTS_DEV_RESUME_FROM_HOST_BITS) {
|
||||
handled |= USB_INTS_DEV_RESUME_FROM_HOST_BITS;
|
||||
/*!< Resume */
|
||||
usb_hw_clear->sie_status = USB_SIE_STATUS_RESUME_BITS;
|
||||
usbd_event_resume_handler(0);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USBDEV_SOF_ENABLE
|
||||
if (status & USB_INTS_DEV_SOF_BITS) {
|
||||
handled |= USB_INTS_DEV_SOF_BITS;
|
||||
usbd_event_sof_handler(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (status ^ handled) {
|
||||
USB_LOG_INFO("Unhandled IRQ 0x%x\n", (uint32_t)(status ^ handled));
|
||||
}
|
||||
}
|
||||
|
||||
void rp2040_usbd_irq(void)
|
||||
{
|
||||
USBD_IRQHandler(0);
|
||||
}
|
||||
@@ -0,0 +1,829 @@
|
||||
/*
|
||||
* Copyright (c) 2025, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usbh_core.h"
|
||||
#include "usbh_hub.h"
|
||||
#include "hardware/resets.h"
|
||||
#include "hardware/irq.h"
|
||||
#include "hardware/structs/usb.h"
|
||||
|
||||
#define usb_hw_set hw_set_alias(usb_hw)
|
||||
#define usb_hw_clear hw_clear_alias(usb_hw)
|
||||
|
||||
#define SIE_CTRL_COMMON (USB_SIE_CTRL_SOF_EN_BITS | \
|
||||
USB_SIE_CTRL_KEEP_ALIVE_EN_BITS | \
|
||||
USB_SIE_CTRL_PULLDOWN_EN_BITS | \
|
||||
USB_SIE_CTRL_EP0_INT_1BUF_BITS)
|
||||
|
||||
typedef enum {
|
||||
USB_EP0_STATE_SETUP = 0x0, /**< SETUP DATA */
|
||||
USB_EP0_STATE_IN_DATA, /**< IN DATA */
|
||||
USB_EP0_STATE_IN_STATUS, /**< IN status*/
|
||||
USB_EP0_STATE_OUT_DATA, /**< OUT DATA */
|
||||
USB_EP0_STATE_OUT_STATUS, /**< OUT status */
|
||||
} ep0_state_t;
|
||||
|
||||
struct rp2040_pipe {
|
||||
uint8_t chidx;
|
||||
bool inuse;
|
||||
volatile uint8_t ep0_state;
|
||||
volatile uint32_t *endpoint_control; /*!< Endpoint control register */
|
||||
volatile uint32_t *buffer_control; /*!< Buffer control register */
|
||||
uint8_t *data_buffer; /*!< Buffer pointer in usb dpram */
|
||||
uint32_t buffer_size; /*!< Buffer size */
|
||||
usb_osal_sem_t waitsem;
|
||||
struct usbh_urb *urb;
|
||||
};
|
||||
|
||||
struct rp2040_hcd {
|
||||
volatile bool port_csc;
|
||||
volatile bool port_pec;
|
||||
volatile bool port_pe;
|
||||
usb_osal_mutex_t ep0_mutex;
|
||||
struct rp2040_pipe pipe_pool[1 + USB_HOST_INTERRUPT_ENDPOINTS];
|
||||
} g_rp2040_hcd[CONFIG_USBHOST_MAX_BUS];
|
||||
|
||||
void rp2040_usbh_irq(void);
|
||||
|
||||
static int rp2040_pipe_alloc(struct usbh_bus *bus)
|
||||
{
|
||||
size_t flags;
|
||||
int chidx;
|
||||
|
||||
flags = usb_osal_enter_critical_section();
|
||||
for (chidx = 1; chidx <= USB_HOST_INTERRUPT_ENDPOINTS; chidx++) {
|
||||
if (!g_rp2040_hcd[bus->hcd.hcd_id].pipe_pool[chidx].inuse) {
|
||||
g_rp2040_hcd[bus->hcd.hcd_id].pipe_pool[chidx].inuse = true;
|
||||
usb_osal_leave_critical_section(flags);
|
||||
return chidx;
|
||||
}
|
||||
}
|
||||
usb_osal_leave_critical_section(flags);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void rp2040_pipe_free(struct rp2040_pipe *pipe)
|
||||
{
|
||||
size_t flags;
|
||||
|
||||
flags = usb_osal_enter_critical_section();
|
||||
if (pipe->urb) {
|
||||
pipe->urb->hcpriv = NULL;
|
||||
pipe->urb = NULL;
|
||||
}
|
||||
pipe->inuse = false;
|
||||
usb_osal_leave_critical_section(flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Take a buffer pointer located in the USB RAM and return as an offset of the RAM.
|
||||
*
|
||||
* @param buf
|
||||
* @return uint32_t
|
||||
*/
|
||||
static inline uint32_t usb_buffer_offset(volatile uint8_t *buf)
|
||||
{
|
||||
return (uint32_t)buf ^ (uint32_t)usbh_dpram;
|
||||
}
|
||||
|
||||
static inline uint8_t usbh_get_port_speed(void)
|
||||
{
|
||||
return (usb_hw->sie_status & USB_SIE_STATUS_SPEED_BITS) >> USB_SIE_STATUS_SPEED_LSB;
|
||||
}
|
||||
|
||||
static inline void rp2040_init_endpoint(struct usbh_bus *bus,
|
||||
uint8_t chidx,
|
||||
uint8_t dev_addr,
|
||||
uint8_t ep_addr,
|
||||
uint8_t ep_type,
|
||||
uint8_t ep_interval,
|
||||
uint8_t speed)
|
||||
{
|
||||
struct rp2040_pipe *pipe;
|
||||
uint32_t regval;
|
||||
|
||||
pipe = &g_rp2040_hcd[bus->hcd.hcd_id].pipe_pool[chidx];
|
||||
|
||||
// Get the data buffer as an offset of the USB controller's DPRAM
|
||||
uint32_t dpram_offset = usb_buffer_offset(pipe->data_buffer);
|
||||
regval = EP_CTRL_ENABLE_BITS |
|
||||
EP_CTRL_INTERRUPT_PER_BUFFER |
|
||||
(ep_type << EP_CTRL_BUFFER_TYPE_LSB) |
|
||||
dpram_offset;
|
||||
|
||||
if (ep_interval) {
|
||||
regval |= (uint32_t)((ep_interval - 1) << EP_CTRL_HOST_INTERRUPT_INTERVAL_LSB);
|
||||
}
|
||||
|
||||
*pipe->endpoint_control = regval;
|
||||
|
||||
if (chidx != 0) {
|
||||
regval = (uint32_t)(dev_addr | ((ep_addr & 0x0f) << USB_ADDR_ENDP1_ENDPOINT_LSB));
|
||||
|
||||
if (!(ep_addr & 0x80)) {
|
||||
regval |= USB_ADDR_ENDP1_INTEP_DIR_BITS;
|
||||
}
|
||||
|
||||
// ls device plugged to hub
|
||||
if ((usbh_get_port_speed() == USB_SPEED_FULL) && (speed == USB_SPEED_LOW)) {
|
||||
regval |= USB_ADDR_ENDP1_INTEP_PREAMBLE_BITS;
|
||||
}
|
||||
|
||||
usb_hw->int_ep_addr_ctrl[(chidx - 1)] = regval;
|
||||
|
||||
// Finally, enable interrupt that endpoint
|
||||
usb_hw_set->int_ep_ctrl = 1 << chidx;
|
||||
} else {
|
||||
usb_hw->dev_addr_ctrl = dev_addr;
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint32_t usb_buf_ctrl_fill(struct usbh_bus *bus, uint8_t chidx, uint8_t ep_addr, uint8_t buf_id)
|
||||
{
|
||||
struct rp2040_pipe *pipe;
|
||||
struct usbh_urb *urb;
|
||||
uint32_t len;
|
||||
uint32_t buf_ctrl;
|
||||
|
||||
pipe = &g_rp2040_hcd[bus->hcd.hcd_id].pipe_pool[chidx];
|
||||
urb = pipe->urb;
|
||||
|
||||
len = MIN(urb->transfer_buffer_length, USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize));
|
||||
urb->transfer_buffer_length -= len;
|
||||
|
||||
buf_ctrl = len | USB_BUF_CTRL_AVAIL;
|
||||
buf_ctrl |= urb->data_toggle ? USB_BUF_CTRL_DATA1_PID : USB_BUF_CTRL_DATA0_PID;
|
||||
|
||||
if (USB_EP_DIR_IS_OUT(ep_addr)) {
|
||||
/*!< Need to copy the data from the user buffer to the usb memory */
|
||||
if (urb->transfer_buffer != NULL) {
|
||||
memcpy((void *)pipe->data_buffer + buf_id * 64, (void *)urb->transfer_buffer, len);
|
||||
urb->transfer_buffer += len;
|
||||
}
|
||||
/*!< Mark as full */
|
||||
buf_ctrl |= USB_BUF_CTRL_FULL;
|
||||
}
|
||||
|
||||
if (USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes) != USB_ENDPOINT_TYPE_ISOCHRONOUS) {
|
||||
if (urb->transfer_buffer_length == 0) {
|
||||
buf_ctrl |= USB_BUF_CTRL_LAST;
|
||||
}
|
||||
} else {
|
||||
//TODO: handle isochronous transfer
|
||||
}
|
||||
|
||||
if (buf_id)
|
||||
buf_ctrl = buf_ctrl << 16;
|
||||
|
||||
return buf_ctrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Starts a transfer on a given endpoint.
|
||||
*
|
||||
* @param ep, the endpoint configuration.
|
||||
* @param buf, the data buffer to send. Only applicable if the endpoint is TX
|
||||
* @param len, the length of the data in buf (this example limits max len to one packet - 64 bytes)
|
||||
*/
|
||||
static void usb_start_transfer(struct usbh_bus *bus, uint8_t chidx, uint8_t ep_addr)
|
||||
{
|
||||
struct rp2040_pipe *pipe;
|
||||
struct usbh_urb *urb;
|
||||
uint32_t buf_ctrl;
|
||||
uint32_t ep_ctrl;
|
||||
|
||||
pipe = &g_rp2040_hcd[bus->hcd.hcd_id].pipe_pool[chidx];
|
||||
urb = pipe->urb;
|
||||
|
||||
ep_ctrl = *pipe->endpoint_control;
|
||||
buf_ctrl = usb_buf_ctrl_fill(bus, chidx, ep_addr, 0);
|
||||
|
||||
if (urb->transfer_buffer_length && (ep_addr & 0x0f) == 0x00) {
|
||||
urb->data_toggle ^= 1;
|
||||
buf_ctrl |= usb_buf_ctrl_fill(bus, chidx, ep_addr, 1);
|
||||
|
||||
// Set endpoint control double buffered bit if needed
|
||||
ep_ctrl &= ~EP_CTRL_INTERRUPT_PER_BUFFER;
|
||||
ep_ctrl |= EP_CTRL_DOUBLE_BUFFERED_BITS | EP_CTRL_INTERRUPT_PER_DOUBLE_BUFFER;
|
||||
} else {
|
||||
// Single buffered since 1 is enough
|
||||
ep_ctrl &= ~(EP_CTRL_DOUBLE_BUFFERED_BITS | EP_CTRL_INTERRUPT_PER_DOUBLE_BUFFER);
|
||||
ep_ctrl |= EP_CTRL_INTERRUPT_PER_BUFFER;
|
||||
}
|
||||
*pipe->endpoint_control = ep_ctrl;
|
||||
*pipe->buffer_control = buf_ctrl;
|
||||
}
|
||||
|
||||
static inline void rp2040_control_transfer_start(bool dir_in, bool isetup, uint8_t speed)
|
||||
{
|
||||
uint32_t regval;
|
||||
|
||||
regval = SIE_CTRL_COMMON | USB_SIE_CTRL_START_TRANS_BITS;
|
||||
|
||||
if ((usbh_get_port_speed() == USB_SPEED_FULL) && (speed == USB_SPEED_LOW)) {
|
||||
regval |= USB_SIE_CTRL_PREAMBLE_EN_BITS;
|
||||
}
|
||||
|
||||
if (isetup) {
|
||||
regval |= USB_SIE_CTRL_SEND_SETUP_BITS;
|
||||
} else {
|
||||
if (dir_in) {
|
||||
regval |= USB_SIE_CTRL_RECEIVE_DATA_BITS;
|
||||
} else {
|
||||
regval |= USB_SIE_CTRL_SEND_DATA_BITS;
|
||||
}
|
||||
}
|
||||
|
||||
usb_hw->sie_ctrl = regval & ~USB_SIE_CTRL_START_TRANS_BITS;
|
||||
busy_wait_at_least_cycles(12);
|
||||
usb_hw->sie_ctrl = regval;
|
||||
}
|
||||
|
||||
static void rp2040_control_urb_init(struct usbh_bus *bus, uint8_t chidx, struct usbh_urb *urb, struct usb_setup_packet *setup, uint8_t *buffer, uint32_t buflen)
|
||||
{
|
||||
struct rp2040_pipe *pipe;
|
||||
|
||||
pipe = &g_rp2040_hcd[bus->hcd.hcd_id].pipe_pool[chidx];
|
||||
|
||||
if (pipe->ep0_state == USB_EP0_STATE_SETUP) /* fill setup */
|
||||
{
|
||||
pipe->urb->data_toggle = 1;
|
||||
memcpy((uint8_t *)usbh_dpram->setup_packet, (uint8_t *)setup, 8);
|
||||
rp2040_init_endpoint(bus, chidx, urb->hport->dev_addr, 0x00, USB_ENDPOINT_TYPE_CONTROL, 0, urb->hport->speed);
|
||||
rp2040_control_transfer_start(false, true, urb->hport->speed);
|
||||
} else if (pipe->ep0_state == USB_EP0_STATE_IN_DATA) /* fill in data */
|
||||
{
|
||||
rp2040_init_endpoint(bus, chidx, urb->hport->dev_addr, 0x80, USB_ENDPOINT_TYPE_CONTROL, 0, urb->hport->speed);
|
||||
usb_start_transfer(bus, chidx, 0x80);
|
||||
rp2040_control_transfer_start(true, false, urb->hport->speed);
|
||||
} else if (pipe->ep0_state == USB_EP0_STATE_OUT_DATA) /* fill out data */
|
||||
{
|
||||
rp2040_init_endpoint(bus, chidx, urb->hport->dev_addr, 0x00, USB_ENDPOINT_TYPE_CONTROL, 0, urb->hport->speed);
|
||||
usb_start_transfer(bus, chidx, 0x00);
|
||||
rp2040_control_transfer_start(false, false, urb->hport->speed);
|
||||
} else if (pipe->ep0_state == USB_EP0_STATE_IN_STATUS) /* fill in status */
|
||||
{
|
||||
urb->data_toggle = 1;
|
||||
rp2040_init_endpoint(bus, chidx, urb->hport->dev_addr, 0x80, USB_ENDPOINT_TYPE_CONTROL, 0, urb->hport->speed);
|
||||
usb_start_transfer(bus, chidx, 0x80);
|
||||
rp2040_control_transfer_start(true, false, urb->hport->speed);
|
||||
} else if (pipe->ep0_state == USB_EP0_STATE_OUT_STATUS) /* fill out status */
|
||||
{
|
||||
urb->data_toggle = 1;
|
||||
rp2040_init_endpoint(bus, chidx, urb->hport->dev_addr, 0x00, USB_ENDPOINT_TYPE_CONTROL, 0, urb->hport->speed);
|
||||
usb_start_transfer(bus, chidx, 0x00);
|
||||
rp2040_control_transfer_start(false, false, urb->hport->speed);
|
||||
}
|
||||
}
|
||||
|
||||
static void rp2040_bulk_int_urb_init(struct usbh_bus *bus, uint8_t chidx, struct usbh_urb *urb, uint8_t *buffer, uint32_t buflen)
|
||||
{
|
||||
rp2040_init_endpoint(bus, chidx, urb->hport->dev_addr, urb->ep->bEndpointAddress, USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes), urb->ep->bInterval, urb->hport->speed);
|
||||
usb_start_transfer(bus, chidx, urb->ep->bEndpointAddress);
|
||||
}
|
||||
|
||||
int usb_hc_init(struct usbh_bus *bus)
|
||||
{
|
||||
uint8_t *next_buffer_ptr;
|
||||
|
||||
memset(&g_rp2040_hcd[bus->hcd.hcd_id], 0, sizeof(struct rp2040_hcd));
|
||||
|
||||
for (uint8_t i = 0; i <= USB_HOST_INTERRUPT_ENDPOINTS; i++) {
|
||||
g_rp2040_hcd[bus->hcd.hcd_id].pipe_pool[i].waitsem = usb_osal_sem_create(0);
|
||||
if (g_rp2040_hcd[bus->hcd.hcd_id].pipe_pool[i].waitsem == NULL) {
|
||||
USB_LOG_ERR("Failed to create waitsem\r\n");
|
||||
return -USB_ERR_NOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
g_rp2040_hcd[bus->hcd.hcd_id].ep0_mutex = usb_osal_mutex_create();
|
||||
if (g_rp2040_hcd[bus->hcd.hcd_id].ep0_mutex == NULL) {
|
||||
USB_LOG_ERR("Failed to create ep0_mutex\r\n");
|
||||
return -USB_ERR_NOMEM;
|
||||
}
|
||||
|
||||
g_rp2040_hcd[bus->hcd.hcd_id].pipe_pool[0].endpoint_control = &usbh_dpram->epx_ctrl;
|
||||
g_rp2040_hcd[bus->hcd.hcd_id].pipe_pool[0].buffer_control = &usbh_dpram->epx_buf_ctrl;
|
||||
g_rp2040_hcd[bus->hcd.hcd_id].pipe_pool[0].data_buffer = &usbh_dpram->epx_data[0];
|
||||
g_rp2040_hcd[bus->hcd.hcd_id].pipe_pool[0].buffer_size = (64 * 2);
|
||||
|
||||
next_buffer_ptr = &usb_dpram->epx_data[64 * 2];
|
||||
|
||||
for (uint8_t i = 1; i <= USB_HOST_INTERRUPT_ENDPOINTS; i++) {
|
||||
g_rp2040_hcd[bus->hcd.hcd_id].pipe_pool[i].chidx = i;
|
||||
g_rp2040_hcd[bus->hcd.hcd_id].pipe_pool[i].endpoint_control = &usbh_dpram->int_ep_ctrl[i - 1].ctrl;
|
||||
g_rp2040_hcd[bus->hcd.hcd_id].pipe_pool[i].buffer_control = &usbh_dpram->int_ep_buffer_ctrl[i - 1].ctrl;
|
||||
g_rp2040_hcd[bus->hcd.hcd_id].pipe_pool[i].data_buffer = next_buffer_ptr;
|
||||
g_rp2040_hcd[bus->hcd.hcd_id].pipe_pool[i].buffer_size = (64 * 2);
|
||||
next_buffer_ptr += (64 * 2);
|
||||
}
|
||||
|
||||
// Reset usb controller
|
||||
reset_unreset_block_num_wait_blocking(RESET_USBCTRL);
|
||||
|
||||
// Remove shared irq if it was previously added so as not to fill up shared irq slots
|
||||
irq_remove_handler(USBCTRL_IRQ, rp2040_usbh_irq);
|
||||
|
||||
irq_add_shared_handler(USBCTRL_IRQ, rp2040_usbh_irq, PICO_SHARED_IRQ_HANDLER_HIGHEST_ORDER_PRIORITY);
|
||||
|
||||
/*!< Clear any previous state just in case */
|
||||
memset(usb_hw, 0, sizeof(*usb_hw));
|
||||
memset(usbh_dpram, 0, sizeof(*usbh_dpram));
|
||||
|
||||
/*!< Mux the controller to the onboard usb phy */
|
||||
usb_hw->muxing = USB_USB_MUXING_TO_PHY_BITS | USB_USB_MUXING_SOFTCON_BITS;
|
||||
|
||||
// Force VBUS detect so the device thinks it is plugged into a host
|
||||
usb_hw->pwr = USB_USB_PWR_VBUS_DETECT_BITS | USB_USB_PWR_VBUS_DETECT_OVERRIDE_EN_BITS;
|
||||
|
||||
// Enable the USB controller in device mode.
|
||||
usb_hw->main_ctrl = USB_MAIN_CTRL_CONTROLLER_EN_BITS | USB_MAIN_CTRL_HOST_NDEVICE_BITS;
|
||||
|
||||
usb_hw->sie_ctrl = SIE_CTRL_COMMON;
|
||||
|
||||
// Enable USB interrupt at processor
|
||||
irq_set_enabled(USBCTRL_IRQ, true);
|
||||
|
||||
usb_hw->inte = USB_INTE_BUFF_STATUS_BITS |
|
||||
USB_INTE_HOST_CONN_DIS_BITS |
|
||||
USB_INTE_STALL_BITS |
|
||||
USB_INTE_TRANS_COMPLETE_BITS |
|
||||
USB_INTE_ERROR_RX_TIMEOUT_BITS |
|
||||
USB_INTE_ERROR_DATA_SEQ_BITS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_hc_deinit(struct usbh_bus *bus)
|
||||
{
|
||||
// Enable USB interrupt at processor
|
||||
irq_set_enabled(USBCTRL_IRQ, false);
|
||||
|
||||
// Remove shared irq if it was previously added so as not to fill up shared irq slots
|
||||
irq_remove_handler(USBCTRL_IRQ, rp2040_usbh_irq);
|
||||
|
||||
for (uint8_t i = 0; i <= USB_HOST_INTERRUPT_ENDPOINTS; i++) {
|
||||
usb_osal_sem_delete(g_rp2040_hcd[bus->hcd.hcd_id].pipe_pool[i].waitsem);
|
||||
}
|
||||
|
||||
usb_osal_mutex_delete(g_rp2040_hcd[bus->hcd.hcd_id].ep0_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t usbh_get_frame_number(struct usbh_bus *bus)
|
||||
{
|
||||
return usb_hw->sof_rd;
|
||||
}
|
||||
|
||||
int usbh_roothub_control(struct usbh_bus *bus, struct usb_setup_packet *setup, uint8_t *buf)
|
||||
{
|
||||
uint8_t nports;
|
||||
uint8_t port;
|
||||
uint32_t status;
|
||||
|
||||
nports = CONFIG_USBHOST_MAX_RHPORTS;
|
||||
port = setup->wIndex;
|
||||
if (setup->bmRequestType & USB_REQUEST_RECIPIENT_DEVICE) {
|
||||
switch (setup->bRequest) {
|
||||
case HUB_REQUEST_CLEAR_FEATURE:
|
||||
switch (setup->wValue) {
|
||||
case HUB_FEATURE_HUB_C_LOCALPOWER:
|
||||
break;
|
||||
case HUB_FEATURE_HUB_C_OVERCURRENT:
|
||||
break;
|
||||
default:
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
break;
|
||||
case HUB_REQUEST_SET_FEATURE:
|
||||
switch (setup->wValue) {
|
||||
case HUB_FEATURE_HUB_C_LOCALPOWER:
|
||||
break;
|
||||
case HUB_FEATURE_HUB_C_OVERCURRENT:
|
||||
break;
|
||||
default:
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
break;
|
||||
case HUB_REQUEST_GET_DESCRIPTOR:
|
||||
break;
|
||||
case HUB_REQUEST_GET_STATUS:
|
||||
memset(buf, 0, 4);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (setup->bmRequestType & USB_REQUEST_RECIPIENT_OTHER) {
|
||||
switch (setup->bRequest) {
|
||||
case HUB_REQUEST_CLEAR_FEATURE:
|
||||
if (!port || port > nports) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
|
||||
switch (setup->wValue) {
|
||||
case HUB_PORT_FEATURE_ENABLE:
|
||||
break;
|
||||
case HUB_PORT_FEATURE_SUSPEND:
|
||||
case HUB_PORT_FEATURE_C_SUSPEND:
|
||||
break;
|
||||
case HUB_PORT_FEATURE_POWER:
|
||||
break;
|
||||
case HUB_PORT_FEATURE_C_CONNECTION:
|
||||
g_rp2040_hcd[bus->hcd.hcd_id].port_csc = 0;
|
||||
break;
|
||||
case HUB_PORT_FEATURE_C_ENABLE:
|
||||
g_rp2040_hcd[bus->hcd.hcd_id].port_pec = 0;
|
||||
break;
|
||||
case HUB_PORT_FEATURE_C_OVER_CURREN:
|
||||
break;
|
||||
case HUB_PORT_FEATURE_C_RESET:
|
||||
break;
|
||||
default:
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
break;
|
||||
case HUB_REQUEST_SET_FEATURE:
|
||||
if (!port || port > nports) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
|
||||
switch (setup->wValue) {
|
||||
case HUB_PORT_FEATURE_SUSPEND:
|
||||
break;
|
||||
case HUB_PORT_FEATURE_POWER:
|
||||
break;
|
||||
case HUB_PORT_FEATURE_RESET:
|
||||
break;
|
||||
|
||||
default:
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
break;
|
||||
case HUB_REQUEST_GET_STATUS:
|
||||
if (!port || port > nports) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
|
||||
status = 0;
|
||||
if (g_rp2040_hcd[bus->hcd.hcd_id].port_csc) {
|
||||
status |= (1 << HUB_PORT_FEATURE_C_CONNECTION);
|
||||
}
|
||||
if (g_rp2040_hcd[bus->hcd.hcd_id].port_pec) {
|
||||
status |= (1 << HUB_PORT_FEATURE_C_ENABLE);
|
||||
}
|
||||
|
||||
if (g_rp2040_hcd[bus->hcd.hcd_id].port_pe) {
|
||||
status |= (1 << HUB_PORT_FEATURE_CONNECTION);
|
||||
status |= (1 << HUB_PORT_FEATURE_ENABLE);
|
||||
if (usbh_get_port_speed() == USB_SPEED_LOW) {
|
||||
status |= (1 << HUB_PORT_FEATURE_LOWSPEED);
|
||||
}
|
||||
}
|
||||
|
||||
status |= (1 << HUB_PORT_FEATURE_POWER);
|
||||
memcpy(buf, &status, 4);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbh_submit_urb(struct usbh_urb *urb)
|
||||
{
|
||||
struct rp2040_pipe *pipe;
|
||||
struct usbh_bus *bus;
|
||||
int chidx;
|
||||
size_t flags;
|
||||
int ret = 0;
|
||||
|
||||
if (!urb || !urb->hport || !urb->ep || !urb->hport->bus) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
|
||||
if (!urb->hport->connected || !(usb_hw->sie_status & USB_SIE_STATUS_SPEED_BITS)) {
|
||||
return -USB_ERR_NOTCONN;
|
||||
}
|
||||
|
||||
if (urb->errorcode == -USB_ERR_BUSY) {
|
||||
return -USB_ERR_BUSY;
|
||||
}
|
||||
|
||||
bus = urb->hport->bus;
|
||||
|
||||
if (USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes) == USB_ENDPOINT_TYPE_CONTROL) {
|
||||
chidx = 0;
|
||||
/* all the control transfers use the only one ep0 register, we need to lock */
|
||||
usb_osal_mutex_take(g_rp2040_hcd[bus->hcd.hcd_id].ep0_mutex);
|
||||
} else {
|
||||
chidx = rp2040_pipe_alloc(bus);
|
||||
if (chidx == -1) {
|
||||
return -USB_ERR_NOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
flags = usb_osal_enter_critical_section();
|
||||
|
||||
pipe = &g_rp2040_hcd[bus->hcd.hcd_id].pipe_pool[chidx];
|
||||
pipe->chidx = chidx;
|
||||
pipe->urb = urb;
|
||||
|
||||
urb->hcpriv = pipe;
|
||||
urb->errorcode = -USB_ERR_BUSY;
|
||||
urb->actual_length = 0;
|
||||
usb_osal_leave_critical_section(flags);
|
||||
|
||||
switch (USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes)) {
|
||||
case USB_ENDPOINT_TYPE_CONTROL:
|
||||
pipe->ep0_state = USB_EP0_STATE_SETUP;
|
||||
rp2040_control_urb_init(bus, 0, urb, urb->setup, urb->transfer_buffer, urb->transfer_buffer_length);
|
||||
break;
|
||||
case USB_ENDPOINT_TYPE_BULK:
|
||||
case USB_ENDPOINT_TYPE_INTERRUPT:
|
||||
rp2040_bulk_int_urb_init(bus, chidx, urb, urb->transfer_buffer, urb->transfer_buffer_length);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (urb->timeout > 0) {
|
||||
/* wait until timeout or sem give */
|
||||
ret = usb_osal_sem_take(pipe->waitsem, urb->timeout);
|
||||
if (ret < 0) {
|
||||
goto errout_timeout;
|
||||
}
|
||||
urb->timeout = 0;
|
||||
ret = urb->errorcode;
|
||||
/* we can free pipe when waitsem is done */
|
||||
rp2040_pipe_free(pipe);
|
||||
|
||||
if (chidx == 0) {
|
||||
usb_osal_mutex_give(g_rp2040_hcd[bus->hcd.hcd_id].ep0_mutex);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
errout_timeout:
|
||||
if (chidx == 0) {
|
||||
usb_osal_mutex_give(g_rp2040_hcd[bus->hcd.hcd_id].ep0_mutex);
|
||||
}
|
||||
urb->timeout = 0;
|
||||
usbh_kill_urb(urb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int usbh_kill_urb(struct usbh_urb *urb)
|
||||
{
|
||||
struct rp2040_pipe *pipe;
|
||||
struct usbh_bus *bus;
|
||||
size_t flags;
|
||||
|
||||
if (!urb || !urb->hcpriv || !urb->hport->bus) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
|
||||
bus = urb->hport->bus;
|
||||
|
||||
ARG_UNUSED(bus);
|
||||
|
||||
flags = usb_osal_enter_critical_section();
|
||||
|
||||
pipe = (struct rp2040_pipe *)urb->hcpriv;
|
||||
urb->errorcode = -USB_ERR_SHUTDOWN;
|
||||
|
||||
usb_hw_clear->int_ep_ctrl = 1 << pipe->chidx;
|
||||
usb_hw_clear->buf_status = 1 << (pipe->chidx * 2 + 0);
|
||||
usb_hw_clear->buf_status = 1 << (pipe->chidx * 2 + 1);
|
||||
*pipe->endpoint_control = 0;
|
||||
*pipe->buffer_control = 0;
|
||||
|
||||
if (urb->timeout) {
|
||||
usb_osal_sem_give(pipe->waitsem);
|
||||
} else {
|
||||
rp2040_pipe_free(pipe);
|
||||
}
|
||||
|
||||
if (urb->complete) {
|
||||
urb->complete(urb->arg, urb->errorcode);
|
||||
}
|
||||
|
||||
usb_osal_leave_critical_section(flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rp2040_urb_waitup(struct usbh_urb *urb)
|
||||
{
|
||||
struct rp2040_pipe *pipe;
|
||||
|
||||
pipe = (struct rp2040_pipe *)urb->hcpriv;
|
||||
|
||||
if (urb->timeout) {
|
||||
usb_osal_sem_give(pipe->waitsem);
|
||||
} else {
|
||||
rp2040_pipe_free(pipe);
|
||||
}
|
||||
|
||||
if (urb->complete) {
|
||||
if (urb->errorcode < 0) {
|
||||
urb->complete(urb->arg, urb->errorcode);
|
||||
} else {
|
||||
urb->complete(urb->arg, urb->actual_length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void rp2040_handle_buffer_status(struct usbh_bus *bus)
|
||||
{
|
||||
struct rp2040_pipe *pipe;
|
||||
struct usbh_urb *urb;
|
||||
uint32_t remaining_buffers;
|
||||
uint32_t size;
|
||||
|
||||
remaining_buffers = usb_hw->buf_status;
|
||||
|
||||
uint32_t bit = 1u;
|
||||
if (remaining_buffers & bit) {
|
||||
remaining_buffers &= ~bit;
|
||||
usb_hw_clear->buf_status = bit;
|
||||
|
||||
pipe = &g_rp2040_hcd[bus->hcd.hcd_id].pipe_pool[0];
|
||||
urb = pipe->urb;
|
||||
switch (pipe->ep0_state) {
|
||||
case USB_EP0_STATE_IN_DATA:
|
||||
size = *pipe->buffer_control & USB_BUF_CTRL_LEN_MASK;
|
||||
memcpy(urb->transfer_buffer, (uint8_t *)pipe->data_buffer, size);
|
||||
|
||||
urb->transfer_buffer += size;
|
||||
urb->actual_length += size;
|
||||
|
||||
if (*pipe->endpoint_control & EP_CTRL_DOUBLE_BUFFERED_BITS) {
|
||||
if (size == USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize)) {
|
||||
size = (*pipe->buffer_control >> 16) & USB_BUF_CTRL_LEN_MASK;
|
||||
memcpy(urb->transfer_buffer, (uint8_t *)pipe->data_buffer + 64, size);
|
||||
|
||||
urb->transfer_buffer += size;
|
||||
urb->actual_length += size;
|
||||
}
|
||||
}
|
||||
|
||||
if ((size < USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize)) || (urb->transfer_buffer_length == 0)) {
|
||||
pipe->ep0_state = USB_EP0_STATE_OUT_STATUS;
|
||||
rp2040_control_urb_init(bus, 0, urb, urb->setup, urb->transfer_buffer, urb->transfer_buffer_length);
|
||||
} else {
|
||||
urb->data_toggle ^= 1;
|
||||
usb_start_transfer(bus, 0, 0x80);
|
||||
}
|
||||
break;
|
||||
case USB_EP0_STATE_OUT_DATA:
|
||||
urb->actual_length += *pipe->buffer_control & USB_BUF_CTRL_LEN_MASK;
|
||||
|
||||
if (*pipe->endpoint_control & EP_CTRL_DOUBLE_BUFFERED_BITS) {
|
||||
urb->actual_length += (*pipe->buffer_control >> 16) & USB_BUF_CTRL_LEN_MASK;
|
||||
}
|
||||
|
||||
if (urb->transfer_buffer_length == 0) {
|
||||
pipe->ep0_state = USB_EP0_STATE_IN_STATUS;
|
||||
rp2040_control_urb_init(bus, 0, urb, urb->setup, urb->transfer_buffer, urb->transfer_buffer_length);
|
||||
} else {
|
||||
urb->data_toggle ^= 1;
|
||||
usb_start_transfer(bus, 0, 0x00);
|
||||
}
|
||||
break;
|
||||
case USB_EP0_STATE_IN_STATUS:
|
||||
case USB_EP0_STATE_OUT_STATUS:
|
||||
urb->errorcode = 0;
|
||||
rp2040_urb_waitup(urb);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint8_t i = 1; remaining_buffers && i <= USB_HOST_INTERRUPT_ENDPOINTS; i++) {
|
||||
for (uint8_t j = 0; j < 2; j++) {
|
||||
bit = 1 << (i * 2 + j);
|
||||
if (remaining_buffers & bit) {
|
||||
remaining_buffers &= ~bit;
|
||||
usb_hw_clear->buf_status = bit;
|
||||
|
||||
pipe = &g_rp2040_hcd[bus->hcd.hcd_id].pipe_pool[i];
|
||||
urb = pipe->urb;
|
||||
if (urb == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (j == 0) { //IN
|
||||
size = *pipe->buffer_control & USB_BUF_CTRL_LEN_MASK;
|
||||
memcpy(urb->transfer_buffer, (uint8_t *)pipe->data_buffer, size);
|
||||
|
||||
urb->transfer_buffer += size;
|
||||
urb->actual_length += size;
|
||||
|
||||
urb->data_toggle ^= 1;
|
||||
if (size < USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize) || urb->transfer_buffer_length == 0) {
|
||||
urb->errorcode = 0;
|
||||
rp2040_urb_waitup(urb);
|
||||
} else {
|
||||
usb_start_transfer(bus, i, urb->ep->bEndpointAddress);
|
||||
}
|
||||
} else { //OUT
|
||||
urb->data_toggle ^= 1;
|
||||
|
||||
urb->actual_length += *pipe->buffer_control & USB_BUF_CTRL_LEN_MASK;
|
||||
|
||||
if (urb->transfer_buffer_length == 0) {
|
||||
urb->errorcode = 0;
|
||||
rp2040_urb_waitup(urb);
|
||||
} else {
|
||||
usb_start_transfer(bus, i, urb->ep->bEndpointAddress);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void USBH_IRQHandler(uint8_t busid)
|
||||
{
|
||||
uint32_t status;
|
||||
uint32_t handled = 0;
|
||||
struct usbh_bus *bus;
|
||||
struct rp2040_pipe *pipe;
|
||||
struct usbh_urb *urb;
|
||||
|
||||
bus = &g_usbhost_bus[busid];
|
||||
status = usb_hw->ints;
|
||||
|
||||
if (status & USB_INTS_HOST_CONN_DIS_BITS) {
|
||||
handled |= USB_INTS_HOST_CONN_DIS_BITS;
|
||||
usb_hw_clear->sie_status = USB_SIE_STATUS_SPEED_BITS;
|
||||
if (usbh_get_port_speed()) {
|
||||
g_rp2040_hcd[bus->hcd.hcd_id].port_csc = 1;
|
||||
g_rp2040_hcd[bus->hcd.hcd_id].port_pec = 1;
|
||||
g_rp2040_hcd[bus->hcd.hcd_id].port_pe = 1;
|
||||
bus->hcd.roothub.int_buffer[0] = (1 << 1);
|
||||
usbh_hub_thread_wakeup(&bus->hcd.roothub);
|
||||
} else {
|
||||
g_rp2040_hcd[bus->hcd.hcd_id].port_csc = 1;
|
||||
g_rp2040_hcd[bus->hcd.hcd_id].port_pec = 1;
|
||||
g_rp2040_hcd[bus->hcd.hcd_id].port_pe = 0;
|
||||
bus->hcd.roothub.int_buffer[0] = (1 << 1);
|
||||
usbh_hub_thread_wakeup(&bus->hcd.roothub);
|
||||
}
|
||||
}
|
||||
|
||||
if (status & USB_INTS_STALL_BITS) {
|
||||
handled |= USB_INTS_STALL_BITS;
|
||||
usb_hw_clear->sie_status = USB_SIE_STATUS_STALL_REC_BITS;
|
||||
}
|
||||
|
||||
if (status & USB_INTS_BUFF_STATUS_BITS) {
|
||||
handled |= USB_INTS_BUFF_STATUS_BITS;
|
||||
rp2040_handle_buffer_status(bus);
|
||||
}
|
||||
|
||||
if (status & USB_INTS_TRANS_COMPLETE_BITS) {
|
||||
handled |= USB_INTS_TRANS_COMPLETE_BITS;
|
||||
usb_hw_clear->sie_status = USB_SIE_STATUS_TRANS_COMPLETE_BITS;
|
||||
if (usb_hw->sie_ctrl & USB_SIE_CTRL_SEND_SETUP_BITS) {
|
||||
pipe = (struct rp2040_pipe *)&g_rp2040_hcd[bus->hcd.hcd_id].pipe_pool[0];
|
||||
urb = pipe->urb;
|
||||
if (urb) {
|
||||
if (urb->setup->wLength) {
|
||||
if (urb->setup->bmRequestType & 0x80) {
|
||||
pipe->ep0_state = USB_EP0_STATE_IN_DATA;
|
||||
} else {
|
||||
pipe->ep0_state = USB_EP0_STATE_OUT_DATA;
|
||||
}
|
||||
} else {
|
||||
pipe->ep0_state = USB_EP0_STATE_IN_STATUS;
|
||||
}
|
||||
urb->actual_length = 8;
|
||||
rp2040_control_urb_init(bus, 0, urb, urb->setup, urb->transfer_buffer, urb->transfer_buffer_length);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
}
|
||||
|
||||
if (status & USB_INTS_ERROR_RX_TIMEOUT_BITS) {
|
||||
handled |= USB_INTS_ERROR_RX_TIMEOUT_BITS;
|
||||
usb_hw_clear->sie_status = USB_SIE_STATUS_RX_TIMEOUT_BITS;
|
||||
}
|
||||
|
||||
if (status & USB_INTS_ERROR_DATA_SEQ_BITS) {
|
||||
handled |= USB_INTS_ERROR_DATA_SEQ_BITS;
|
||||
usb_hw_clear->sie_status = USB_SIE_STATUS_DATA_SEQ_ERROR_BITS;
|
||||
}
|
||||
|
||||
if (status ^ handled) {
|
||||
USB_LOG_ERR("Unhandled IRQ 0x%x\n", (uint)(status ^ handled));
|
||||
}
|
||||
}
|
||||
|
||||
void rp2040_usbh_irq(void)
|
||||
{
|
||||
USBH_IRQHandler(0);
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
#include "usbd_core.h"
|
||||
|
||||
/* Endpoint state */
|
||||
struct usb_dc_ep_state {
|
||||
uint16_t ep_mps; /* Endpoint max packet size */
|
||||
uint8_t ep_type; /* Endpoint type */
|
||||
uint8_t ep_stalled; /* Endpoint stall flag */
|
||||
uint8_t *xfer_buf;
|
||||
uint32_t xfer_len;
|
||||
uint32_t actual_xfer_len;
|
||||
};
|
||||
|
||||
/* Driver state */
|
||||
struct xxx_udc {
|
||||
volatile uint8_t dev_addr;
|
||||
struct usb_dc_ep_state in_ep[CONFIG_USBDEV_EP_NUM]; /*!< IN endpoint parameters*/
|
||||
struct usb_dc_ep_state out_ep[CONFIG_USBDEV_EP_NUM]; /*!< OUT endpoint parameters */
|
||||
} g_xxx_udc;
|
||||
|
||||
__WEAK void usb_dc_low_level_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
__WEAK void usb_dc_low_level_deinit(void)
|
||||
{
|
||||
}
|
||||
|
||||
int usb_dc_init(uint8_t busid)
|
||||
{
|
||||
memset(&g_xxx_udc, 0, sizeof(struct xxx_udc));
|
||||
|
||||
usb_dc_low_level_init();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_dc_deinit(uint8_t busid)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_set_address(uint8_t busid, const uint8_t addr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_set_remote_wakeup(uint8_t busid)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t usbd_get_port_speed(uint8_t busid)
|
||||
{
|
||||
return USB_SPEED_FULL;
|
||||
}
|
||||
|
||||
int usbd_ep_open(uint8_t busid, const struct usb_endpoint_descriptor *ep)
|
||||
{
|
||||
uint8_t ep_idx = USB_EP_GET_IDX(ep->bEndpointAddress);
|
||||
|
||||
if (USB_EP_DIR_IS_OUT(ep->bEndpointAddress)) {
|
||||
g_xxx_udc.out_ep[ep_idx].ep_mps = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
|
||||
g_xxx_udc.out_ep[ep_idx].ep_type = USB_GET_ENDPOINT_TYPE(ep->bmAttributes);
|
||||
g_xxx_udc.out_ep[ep_idx].ep_enable = true;
|
||||
} else {
|
||||
g_xxx_udc.in_ep[ep_idx].ep_mps = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
|
||||
g_xxx_udc.in_ep[ep_idx].ep_type = USB_GET_ENDPOINT_TYPE(ep->bmAttributes);
|
||||
g_xxx_udc.in_ep[ep_idx].ep_enable = true;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_close(uint8_t busid, const uint8_t ep)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_set_stall(uint8_t busid, const uint8_t ep)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_clear_stall(uint8_t busid, const uint8_t ep)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_is_stalled(uint8_t busid, const uint8_t ep, uint8_t *stalled)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_start_write(uint8_t busid, const uint8_t ep, const uint8_t *data, uint32_t data_len)
|
||||
{
|
||||
uint8_t ep_idx = USB_EP_GET_IDX(ep);
|
||||
uint32_t tmp;
|
||||
|
||||
if (!data && data_len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
g_xxx_udc.in_ep[ep_idx].xfer_buf = (uint8_t *)data;
|
||||
g_xxx_udc.in_ep[ep_idx].xfer_len = data_len;
|
||||
g_xxx_udc.in_ep[ep_idx].actual_xfer_len = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_start_read(uint8_t busid, const uint8_t ep, uint8_t *data, uint32_t data_len)
|
||||
{
|
||||
uint8_t ep_idx = USB_EP_GET_IDX(ep);
|
||||
|
||||
if (!data && data_len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
g_xxx_udc.out_ep[ep_idx].xfer_buf = (uint8_t *)data;
|
||||
g_xxx_udc.out_ep[ep_idx].xfer_len = data_len;
|
||||
g_xxx_udc.out_ep[ep_idx].actual_xfer_len = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void USBD_IRQHandler(uint8_t busid)
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (c) 2025, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usbh_core.h"
|
||||
#include "usbh_hub.h"
|
||||
|
||||
int usb_hc_init(struct usbh_bus *bus)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_hc_deinit(struct usbh_bus *bus)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t usbh_get_frame_number(struct usbh_bus *bus)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbh_roothub_control(struct usbh_bus *bus, struct usb_setup_packet *setup, uint8_t *buf)
|
||||
{
|
||||
uint8_t nports;
|
||||
uint8_t port;
|
||||
uint32_t status;
|
||||
|
||||
nports = CONFIG_USBHOST_MAX_RHPORTS;
|
||||
port = setup->wIndex;
|
||||
if (setup->bmRequestType & USB_REQUEST_RECIPIENT_DEVICE) {
|
||||
switch (setup->bRequest) {
|
||||
case HUB_REQUEST_CLEAR_FEATURE:
|
||||
switch (setup->wValue) {
|
||||
case HUB_FEATURE_HUB_C_LOCALPOWER:
|
||||
break;
|
||||
case HUB_FEATURE_HUB_C_OVERCURRENT:
|
||||
break;
|
||||
default:
|
||||
return -USB_ERR_NOTSUPP;
|
||||
}
|
||||
break;
|
||||
case HUB_REQUEST_SET_FEATURE:
|
||||
switch (setup->wValue) {
|
||||
case HUB_FEATURE_HUB_C_LOCALPOWER:
|
||||
break;
|
||||
case HUB_FEATURE_HUB_C_OVERCURRENT:
|
||||
break;
|
||||
default:
|
||||
return -USB_ERR_NOTSUPP;
|
||||
}
|
||||
break;
|
||||
case HUB_REQUEST_GET_DESCRIPTOR:
|
||||
break;
|
||||
case HUB_REQUEST_GET_STATUS:
|
||||
memset(buf, 0, 4);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (setup->bmRequestType & USB_REQUEST_RECIPIENT_OTHER) {
|
||||
switch (setup->bRequest) {
|
||||
case HUB_REQUEST_CLEAR_FEATURE:
|
||||
if (!port || port > nports) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
|
||||
switch (setup->wValue) {
|
||||
case HUB_PORT_FEATURE_ENABLE:
|
||||
break;
|
||||
case HUB_PORT_FEATURE_SUSPEND:
|
||||
break;
|
||||
case HUB_PORT_FEATURE_C_SUSPEND:
|
||||
break;
|
||||
case HUB_PORT_FEATURE_POWER:
|
||||
break;
|
||||
case HUB_PORT_FEATURE_C_CONNECTION:
|
||||
break;
|
||||
case HUB_PORT_FEATURE_C_ENABLE:
|
||||
break;
|
||||
case HUB_PORT_FEATURE_C_OVER_CURREN:
|
||||
break;
|
||||
case HUB_PORT_FEATURE_C_RESET:
|
||||
break;
|
||||
default:
|
||||
return -USB_ERR_NOTSUPP;
|
||||
}
|
||||
break;
|
||||
case HUB_REQUEST_SET_FEATURE:
|
||||
if (!port || port > nports) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
|
||||
switch (setup->wValue) {
|
||||
case HUB_PORT_FEATURE_SUSPEND:
|
||||
break;
|
||||
case HUB_PORT_FEATURE_POWER:
|
||||
break;
|
||||
case HUB_PORT_FEATURE_RESET:
|
||||
break;
|
||||
|
||||
default:
|
||||
return -USB_ERR_NOTSUPP;
|
||||
}
|
||||
break;
|
||||
case HUB_REQUEST_GET_STATUS:
|
||||
if (!port || port > nports) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
|
||||
memcpy(buf, &status, 4);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbh_submit_urb(struct usbh_urb *urb)
|
||||
{
|
||||
return -USB_ERR_NOTSUPP;
|
||||
}
|
||||
|
||||
int usbh_kill_urb(struct usbh_urb *urb)
|
||||
{
|
||||
return -USB_ERR_NOTSUPP;
|
||||
}
|
||||
|
||||
void USBH_IRQHandler(uint8_t busid)
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
# USB 3.0 Host 控制器 (XHCI)
|
||||
|
||||
- Phytium PI 和 Phyium E2000 系列开发板提供符合 XHCI 1.1 规范的 USB 3.0 Host 控制器, 其它 Phytium 系列平台可以通过 PCIe 扩展卡获得 XHCI 控制器
|
||||
- 相关的使用例程可以在 Phytium PI(飞腾派)、E2000 D/Q Demo 板以及 D2000 和后续平台上运行,例程包括
|
||||
|
||||
---------------------------------------------
|
||||
|
||||
- FreeRTOS
|
||||
|
||||
- - 1. [XHCI 平台控制器使用鼠标/键盘/U盘功能](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk/tree/master/example/peripheral/usb/xhci_platform/README.md)
|
||||
- - 2. [XHCI PCIe控制器使用鼠标/键盘/U盘功能](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk/tree/master/example/peripheral/usb/xhci_pcie/README.md)
|
||||
- - 3. [LVGL 中使用 XHCI 平台控制器连接的鼠标/键盘/U盘](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk/blob/master/example/peripheral/media/lvgl_indev/README.md)
|
||||
|
||||
---------------------------------------------
|
||||
|
||||
- RT-Thread
|
||||
|
||||
- - 1. [XHCI 平台控制器识别鼠标/键盘/U盘](https://github.com/RT-Thread/rt-thread/blob/master/bsp/phytium/doc/use_cherryusb.md)
|
||||
|
||||
---------------------------------------------
|
||||
|
||||
- Standalone 裸机
|
||||
|
||||
- - 暂不支持
|
||||
|
||||
---------------------------------------------
|
||||
|
||||
- XHCI 的驱动功能以静态库的方式提供,仅限在 Phytium 系列 CPU 平台使用,
|
||||
|
||||
- - libxhci_a64.a : AARCH64 驱动库
|
||||
- - libxhci_a32_hardfp.a : AARCH32 驱动库,使用硬浮点
|
||||
- - libxhci_a32_softfp.a : AARCH32 驱动库,使用软浮点
|
||||
|
||||
需要获取源代码请联系 `opensource_embedded@phytium.com.cn` 获取,如需移植运行到非 Phytium 系列 CPU 平台请提前联系`opensource_embedded@phytium.com.cn`获得允许
|
||||
|
||||
# USB 3.0 Host Controller (XHCI)
|
||||
|
||||
- The Phytium PI and Phytium E2000 series development boards provide USB 3.0 Host controllers that conform to the XHCI 1.1 specification. Other Phytium series platforms can obtain XHCI controllers through PCIe expansion cards.
|
||||
- Related example routines can be run on Phytium PI (Fetion Pi), E2000 D/Q Demo boards, and D2000 and later platforms. Examples include:
|
||||
|
||||
---------------------------------------------
|
||||
|
||||
- FreeRTOS
|
||||
|
||||
- 1. [XHCI platform controller for mouse/keyboard/USB drive functions](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk/tree/master/example/peripheral/usb/xhci_platform/README.md)
|
||||
- 2. [XHCI PCIe controller for mouse/keyboard/USB drive functions](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk/tree/master/example/peripheral/usb/xhci_pcie/README.md)
|
||||
- 3. [Using XHCI platform controller-connected mouse/keyboard/USB drive in LVGL](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk/blob/master/example/peripheral/media/lvgl_indev/README.md)
|
||||
|
||||
---------------------------------------------
|
||||
|
||||
- RT-Thread
|
||||
|
||||
- 1. [XHCI platform controller recognizing mouse/keyboard/USB drive](https://github.com/RT-Thread/rt-thread/blob/master/bsp/phytium/doc/use_cherryusb.md)
|
||||
|
||||
---------------------------------------------
|
||||
|
||||
- Standalone (Bare Metal)
|
||||
|
||||
- Not supported yet
|
||||
|
||||
---------------------------------------------
|
||||
|
||||
- This XHCI driver functionality is provided as a static library and is only available for Phytium series CPU platforms.
|
||||
|
||||
- - `libxhci_a64.a` : Driver library for AARCH64
|
||||
- - `libxhci_a32_hardfp.a` : Driver library for AARCH32, using hard floating point
|
||||
- - `libxhci_a32_softfp.a` : Driver library for AARCH32, using soft floating point
|
||||
|
||||
- To obtain the source code, please contact `opensource_embedded@phytium.com.cn`.
|
||||
- For porting to non-Phytium CPU platforms, shall contact `opensource_embedded@phytium.com.cn` in advance for permission.
|
||||
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,289 @@
|
||||
/*
|
||||
* Copyright : (C) 2024 Phytium Information Technology, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Modify History:
|
||||
* Ver Who Date Changes
|
||||
* ----- ------ -------- --------------------------------------
|
||||
* 1.0 zhugengyu 2024/6/26 first commit
|
||||
*/
|
||||
#ifndef CHERRYUSB_CONFIG_H
|
||||
#define CHERRYUSB_CONFIG_H
|
||||
|
||||
#include "rtthread.h"
|
||||
|
||||
/* ================ USB common Configuration ================ */
|
||||
|
||||
#define CONFIG_USB_PRINTF(...) rt_kprintf(__VA_ARGS__)
|
||||
|
||||
void *xhci_mem_malloc(size_t align, size_t size);
|
||||
void xhci_mem_free(void *ptr);
|
||||
|
||||
#define XHCI_DCACHE_FLUSH (1 << 0)
|
||||
#define XHCI_DCACHE_INVALIDATE (1 << 1)
|
||||
void xhci_dcache_sync(void *ptr, size_t len, uint32_t flags);
|
||||
|
||||
unsigned long usb_hc_get_register_base(uint32_t id);
|
||||
|
||||
#define usb_malloc(size) xhci_mem_malloc(sizeof(int), size)
|
||||
#define usb_free(ptr) xhci_mem_free(ptr)
|
||||
|
||||
#ifndef CONFIG_USB_DBG_LEVEL
|
||||
#if defined(CONFIG_LOG_ERROR)
|
||||
#define CONFIG_USB_DBG_LEVEL USB_DBG_ERROR
|
||||
#elif defined(CONFIG_LOG_WARN)
|
||||
#define CONFIG_USB_DBG_LEVEL USB_DBG_WARNING
|
||||
#elif defined(CONFIG_LOG_INFO)
|
||||
#define CONFIG_USB_DBG_LEVEL USB_DBG_INFO
|
||||
#elif defined(CONFIG_LOG_DEBUG) || defined(CONFIG_LOG_VERBOS)
|
||||
#define CONFIG_USB_DBG_LEVEL USB_DBG_LOG
|
||||
#else
|
||||
#define CONFIG_USB_DBG_LEVEL USB_DBG_ERROR
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Enable print with color */
|
||||
#define CONFIG_USB_PRINTF_COLOR_ENABLE
|
||||
|
||||
/* data align size when use dma */
|
||||
#ifndef CONFIG_USB_ALIGN_SIZE
|
||||
#define CONFIG_USB_ALIGN_SIZE 4
|
||||
#endif
|
||||
|
||||
/* attribute data into no cache ram */
|
||||
#define USB_NOCACHE_RAM_SECTION __attribute__((section(".noncacheable")))
|
||||
|
||||
/* ================= USB Device Stack Configuration ================ */
|
||||
|
||||
/* Ep0 in and out transfer buffer */
|
||||
#ifndef CONFIG_USBDEV_REQUEST_BUFFER_LEN
|
||||
#define CONFIG_USBDEV_REQUEST_BUFFER_LEN 512
|
||||
#endif
|
||||
|
||||
/* Setup packet log for debug */
|
||||
// #define CONFIG_USBDEV_SETUP_LOG_PRINT
|
||||
|
||||
/* Send ep0 in data from user buffer instead of copying into ep0 reqdata
|
||||
* Please note that user buffer must be aligned with CONFIG_USB_ALIGN_SIZE
|
||||
*/
|
||||
// #define CONFIG_USBDEV_EP0_INDATA_NO_COPY
|
||||
|
||||
/* Check if the input descriptor is correct */
|
||||
// #define CONFIG_USBDEV_DESC_CHECK
|
||||
|
||||
/* Enable test mode */
|
||||
// #define CONFIG_USBDEV_TEST_MODE
|
||||
|
||||
#ifndef CONFIG_USBDEV_MSC_MAX_LUN
|
||||
#define CONFIG_USBDEV_MSC_MAX_LUN 1
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_USBDEV_MSC_MAX_BUFSIZE
|
||||
#define CONFIG_USBDEV_MSC_MAX_BUFSIZE 512
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_USBDEV_MSC_MANUFACTURER_STRING
|
||||
#define CONFIG_USBDEV_MSC_MANUFACTURER_STRING ""
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_USBDEV_MSC_PRODUCT_STRING
|
||||
#define CONFIG_USBDEV_MSC_PRODUCT_STRING ""
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_USBDEV_MSC_VERSION_STRING
|
||||
#define CONFIG_USBDEV_MSC_VERSION_STRING "0.01"
|
||||
#endif
|
||||
|
||||
// #define CONFIG_USBDEV_MSC_THREAD
|
||||
|
||||
#ifndef CONFIG_USBDEV_MSC_PRIO
|
||||
#define CONFIG_USBDEV_MSC_PRIO 4
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_USBDEV_MSC_STACKSIZE
|
||||
#define CONFIG_USBDEV_MSC_STACKSIZE 2048
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE
|
||||
#define CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE 156
|
||||
#endif
|
||||
|
||||
/* rndis transfer buffer size, must be a multiple of (1536 + 44)*/
|
||||
#ifndef CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE
|
||||
#define CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE 1580
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_USBDEV_RNDIS_VENDOR_ID
|
||||
#define CONFIG_USBDEV_RNDIS_VENDOR_ID 0x0000ffff
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_USBDEV_RNDIS_VENDOR_DESC
|
||||
#define CONFIG_USBDEV_RNDIS_VENDOR_DESC "CherryUSB"
|
||||
#endif
|
||||
|
||||
#define CONFIG_USBDEV_RNDIS_USING_LWIP
|
||||
|
||||
/* ================ USB HOST Stack Configuration ================== */
|
||||
|
||||
#define CONFIG_USBHOST_MAX_RHPORTS 8
|
||||
#define CONFIG_USBHOST_MAX_EXTHUBS 4
|
||||
#define CONFIG_USBHOST_MAX_EHPORTS 8
|
||||
#define CONFIG_USBHOST_MAX_INTERFACES 8
|
||||
#define CONFIG_USBHOST_MAX_INTF_ALTSETTINGS 8
|
||||
#define CONFIG_USBHOST_MAX_ENDPOINTS 8
|
||||
|
||||
#define CONFIG_USBHOST_MAX_CDC_ACM_CLASS 4
|
||||
#define CONFIG_USBHOST_MAX_HID_CLASS 4
|
||||
#define CONFIG_USBHOST_MAX_MSC_CLASS 2
|
||||
#define CONFIG_USBHOST_MAX_AUDIO_CLASS 1
|
||||
#define CONFIG_USBHOST_MAX_VIDEO_CLASS 1
|
||||
|
||||
#define CONFIG_USBHOST_DEV_NAMELEN 16
|
||||
|
||||
#ifndef CONFIG_USBHOST_PSC_PRIO
|
||||
#define CONFIG_USBHOST_PSC_PRIO 0
|
||||
#endif
|
||||
#ifndef CONFIG_USBHOST_PSC_STACKSIZE
|
||||
#define CONFIG_USBHOST_PSC_STACKSIZE 8192
|
||||
#endif
|
||||
|
||||
//#define CONFIG_USBHOST_GET_STRING_DESC
|
||||
|
||||
// #define CONFIG_USBHOST_MSOS_ENABLE
|
||||
#ifndef CONFIG_USBHOST_MSOS_VENDOR_CODE
|
||||
#define CONFIG_USBHOST_MSOS_VENDOR_CODE 0x00
|
||||
#endif
|
||||
|
||||
/* Ep0 max transfer buffer */
|
||||
#ifndef CONFIG_USBHOST_REQUEST_BUFFER_LEN
|
||||
#define CONFIG_USBHOST_REQUEST_BUFFER_LEN 512
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT
|
||||
#define CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT 500
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_USBHOST_MSC_TIMEOUT
|
||||
#define CONFIG_USBHOST_MSC_TIMEOUT 0xffffffff
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_INPUT_MOUSE_WHEEL
|
||||
#define CONFIG_INPUT_MOUSE_WHEEL
|
||||
#endif
|
||||
|
||||
/* This parameter affects usb performance, and depends on (TCP_WND)tcp eceive windows size,
|
||||
* you can change to 2K ~ 16K and must be larger than TCP RX windows size in order to avoid being overflow.
|
||||
*/
|
||||
#ifndef CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE
|
||||
#define CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE (2048)
|
||||
#endif
|
||||
|
||||
/* Because lwip do not support multi pbuf at a time, so increasing this variable has no performance improvement */
|
||||
#ifndef CONFIG_USBHOST_RNDIS_ETH_MAX_TX_SIZE
|
||||
#define CONFIG_USBHOST_RNDIS_ETH_MAX_TX_SIZE (2048)
|
||||
#endif
|
||||
|
||||
/* This parameter affects usb performance, and depends on (TCP_WND)tcp eceive windows size,
|
||||
* you can change to 2K ~ 16K and must be larger than TCP RX windows size in order to avoid being overflow.
|
||||
*/
|
||||
#ifndef CONFIG_USBHOST_CDC_NCM_ETH_MAX_RX_SIZE
|
||||
#define CONFIG_USBHOST_CDC_NCM_ETH_MAX_RX_SIZE (2048)
|
||||
#endif
|
||||
/* Because lwip do not support multi pbuf at a time, so increasing this variable has no performance improvement */
|
||||
#ifndef CONFIG_USBHOST_CDC_NCM_ETH_MAX_TX_SIZE
|
||||
#define CONFIG_USBHOST_CDC_NCM_ETH_MAX_TX_SIZE (2048)
|
||||
#endif
|
||||
|
||||
/* This parameter affects usb performance, and depends on (TCP_WND)tcp eceive windows size,
|
||||
* you can change to 2K ~ 16K and must be larger than TCP RX windows size in order to avoid being overflow.
|
||||
*/
|
||||
#ifndef CONFIG_USBHOST_ASIX_ETH_MAX_RX_SIZE
|
||||
#define CONFIG_USBHOST_ASIX_ETH_MAX_RX_SIZE (2048)
|
||||
#endif
|
||||
/* Because lwip do not support multi pbuf at a time, so increasing this variable has no performance improvement */
|
||||
#ifndef CONFIG_USBHOST_ASIX_ETH_MAX_TX_SIZE
|
||||
#define CONFIG_USBHOST_ASIX_ETH_MAX_TX_SIZE (2048)
|
||||
#endif
|
||||
|
||||
/* This parameter affects usb performance, and depends on (TCP_WND)tcp eceive windows size,
|
||||
* you can change to 2K ~ 16K and must be larger than TCP RX windows size in order to avoid being overflow.
|
||||
*/
|
||||
#ifndef CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE
|
||||
#define CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE (2048)
|
||||
#endif
|
||||
/* Because lwip do not support multi pbuf at a time, so increasing this variable has no performance improvement */
|
||||
#ifndef CONFIG_USBHOST_RTL8152_ETH_MAX_TX_SIZE
|
||||
#define CONFIG_USBHOST_RTL8152_ETH_MAX_TX_SIZE (2048)
|
||||
#endif
|
||||
|
||||
#define CONFIG_USBHOST_BLUETOOTH_HCI_H4
|
||||
// #define CONFIG_USBHOST_BLUETOOTH_HCI_LOG
|
||||
|
||||
#ifndef CONFIG_USBHOST_BLUETOOTH_TX_SIZE
|
||||
#define CONFIG_USBHOST_BLUETOOTH_TX_SIZE 2048
|
||||
#endif
|
||||
#ifndef CONFIG_USBHOST_BLUETOOTH_RX_SIZE
|
||||
#define CONFIG_USBHOST_BLUETOOTH_RX_SIZE 2048
|
||||
#endif
|
||||
|
||||
/* ================ USB Device Port Configuration ================*/
|
||||
|
||||
#ifndef CONFIG_USBDEV_MAX_BUS
|
||||
#define CONFIG_USBDEV_MAX_BUS 2 // for now, bus num must be 1 except hpm ip
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_USBDEV_EP_NUM
|
||||
#define CONFIG_USBDEV_EP_NUM 8
|
||||
#endif
|
||||
|
||||
/* ---------------- FSDEV Configuration ---------------- */
|
||||
//#define CONFIG_USBDEV_FSDEV_PMA_ACCESS 2 // maybe 1 or 2, many chips may have a difference
|
||||
|
||||
/* ---------------- DWC2 Configuration ---------------- */
|
||||
// #define CONFIG_USB_DWC2_RXALL_FIFO_SIZE (1024 / 4)
|
||||
// #define CONFIG_USB_DWC2_TX0_FIFO_SIZE (64 / 4)
|
||||
// #define CONFIG_USB_DWC2_TX1_FIFO_SIZE (512 / 4)
|
||||
// #define CONFIG_USB_DWC2_TX2_FIFO_SIZE (64 / 4)
|
||||
// #define CONFIG_USB_DWC2_TX3_FIFO_SIZE (64 / 4)
|
||||
// #define CONFIG_USB_DWC2_TX4_FIFO_SIZE (0 / 4)
|
||||
// #define CONFIG_USB_DWC2_TX5_FIFO_SIZE (0 / 4)
|
||||
// #define CONFIG_USB_DWC2_TX6_FIFO_SIZE (0 / 4)
|
||||
// #define CONFIG_USB_DWC2_TX7_FIFO_SIZE (0 / 4)
|
||||
// #define CONFIG_USB_DWC2_TX8_FIFO_SIZE (0 / 4)
|
||||
|
||||
/* ---------------- MUSB Configuration ---------------- */
|
||||
// #define CONFIG_USB_MUSB_SUNXI
|
||||
|
||||
/* ================ USB Host Port Configuration ==================*/
|
||||
#ifndef CONFIG_USBHOST_MAX_BUS
|
||||
#define CONFIG_USBHOST_MAX_BUS 2
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_USBHOST_PIPE_NUM
|
||||
#define CONFIG_USBHOST_PIPE_NUM 10
|
||||
#endif
|
||||
|
||||
/* ---------------- EHCI Configuration ---------------- */
|
||||
|
||||
#define CONFIG_USB_EHCI_HCCR_OFFSET (0x0)
|
||||
#define CONFIG_USB_EHCI_FRAME_LIST_SIZE 1024
|
||||
#define CONFIG_USB_EHCI_QH_NUM CONFIG_USBHOST_PIPE_NUM
|
||||
#define CONFIG_USB_EHCI_QTD_NUM 3
|
||||
#define CONFIG_USB_EHCI_ITD_NUM 20
|
||||
// #define CONFIG_USB_EHCI_HCOR_RESERVED_DISABLE
|
||||
// #define CONFIG_USB_EHCI_CONFIGFLAG
|
||||
// #define CONFIG_USB_EHCI_ISO
|
||||
// #define CONFIG_USB_EHCI_WITH_OHCI
|
||||
|
||||
/* ---------------- OHCI Configuration ---------------- */
|
||||
#define CONFIG_USB_OHCI_HCOR_OFFSET (0x0)
|
||||
|
||||
/* ---------------- XHCI Configuration ---------------- */
|
||||
#define CONFIG_USB_XHCI_HCCR_OFFSET (0x0)
|
||||
|
||||
#ifndef CONFIG_USB_XHCI_ENABLE_SOFT_ISR
|
||||
#define CONFIG_USB_XHCI_ENABLE_SOFT_ISR 0
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright : (C) 2024 Phytium Information Technology, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Modify History:
|
||||
* Ver Who Date Changes
|
||||
* ----- ------ -------- --------------------------------------
|
||||
* 1.0 zhugengyu 2024/6/26 first commit
|
||||
*/
|
||||
#include "rtthread.h"
|
||||
#include "usbh_core.h"
|
||||
|
||||
#include "usb_config.h"
|
||||
|
||||
void usb_hc_setup_xhci_interrupt(uint32_t id);
|
||||
void usb_hc_revoke_xhci_interrupt(uint32_t id);
|
||||
|
||||
void *xhci_mem_malloc(size_t align, size_t size)
|
||||
{
|
||||
void *result = rt_malloc_align(size, align);
|
||||
|
||||
if (result)
|
||||
{
|
||||
memset(result, 0U, size);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void xhci_mem_free(void *ptr)
|
||||
{
|
||||
if (NULL != ptr)
|
||||
{
|
||||
rt_free(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void xhci_dcache_sync(void *ptr, size_t len, uint32_t flags)
|
||||
{
|
||||
if (flags & XHCI_DCACHE_FLUSH)
|
||||
{
|
||||
rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, ptr, len);
|
||||
}
|
||||
else if (flags & XHCI_DCACHE_INVALIDATE)
|
||||
{
|
||||
rt_hw_cpu_dcache_ops(RT_HW_CACHE_INVALIDATE, ptr, len);
|
||||
}
|
||||
}
|
||||
|
||||
void usb_assert(const char *filename, int linenum)
|
||||
{
|
||||
rt_assert_handler("", filename, linenum);
|
||||
}
|
||||
|
||||
void usb_hc_low_level_init(struct usbh_bus *bus)
|
||||
{
|
||||
/* platform XHCI controller */
|
||||
usb_hc_setup_xhci_interrupt(bus->busid);
|
||||
}
|
||||
|
||||
void usb_hc_low_level_deinit(struct usbh_bus *bus)
|
||||
{
|
||||
usb_hc_revoke_xhci_interrupt(bus->busid);
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright : (C) 2024 Phytium Information Technology, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Modify History:
|
||||
* Ver Who Date Changes
|
||||
* ----- ------ -------- --------------------------------------
|
||||
* 1.0 zhugengyu 2024/6/26 first commit
|
||||
*/
|
||||
#include "rtthread.h"
|
||||
#include "interrupt.h"
|
||||
|
||||
#include "fparameters.h"
|
||||
|
||||
void USBH_IRQHandler(uint8_t busid);
|
||||
|
||||
static void usb_hc_xhci_interrupt_handler(int irqno, void *param)
|
||||
{
|
||||
if (irqno == FUSB3_0_IRQ_NUM) {
|
||||
USBH_IRQHandler(FUSB3_ID_0);
|
||||
} else if (irqno == FUSB3_1_IRQ_NUM) {
|
||||
USBH_IRQHandler(FUSB3_ID_1);
|
||||
}
|
||||
}
|
||||
|
||||
void usb_hc_setup_xhci_interrupt(uint32_t id)
|
||||
{
|
||||
uint32_t irq_num = (id == FUSB3_ID_0) ? FUSB3_0_IRQ_NUM : FUSB3_1_IRQ_NUM;
|
||||
rt_hw_interrupt_set_priority(irq_num, 0xd0);
|
||||
rt_hw_interrupt_install(irq_num, usb_hc_xhci_interrupt_handler,
|
||||
NULL, "xhci");
|
||||
rt_hw_interrupt_umask(irq_num);
|
||||
}
|
||||
|
||||
void usb_hc_revoke_xhci_interrupt(uint32_t id)
|
||||
{
|
||||
uint32_t irq_num = (id == FUSB3_ID_0) ? FUSB3_0_IRQ_NUM : FUSB3_1_IRQ_NUM;
|
||||
|
||||
rt_hw_interrupt_mask(irq_num);
|
||||
}
|
||||
|
||||
unsigned long usb_hc_get_register_base(uint32_t id)
|
||||
{
|
||||
if (FUSB3_ID_0 == id)
|
||||
return FUSB3_0_BASE_ADDR + FUSB3_XHCI_OFFSET;
|
||||
else
|
||||
return FUSB3_1_BASE_ADDR + FUSB3_XHCI_OFFSET;
|
||||
}
|
||||
Reference in New Issue
Block a user