first
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
# Note
|
||||
|
||||
## Support Chip List
|
||||
|
||||
- BL616/BL808
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,5 @@
|
||||
# Note
|
||||
|
||||
## Support Chip List
|
||||
|
||||
- CH32V30x
|
@@ -0,0 +1,409 @@
|
||||
/*
|
||||
* Copyright (c) 2022, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef _USB_CH32_USBFS_REG_H
|
||||
#define _USB_CH32_USBFS_REG_H
|
||||
|
||||
#define __IO volatile /* defines 'read / write' permissions */
|
||||
|
||||
/* USBOTG_FS Registers */
|
||||
typedef struct
|
||||
{
|
||||
__IO uint8_t BASE_CTRL;
|
||||
__IO uint8_t UDEV_CTRL;
|
||||
__IO uint8_t INT_EN;
|
||||
__IO uint8_t DEV_ADDR;
|
||||
__IO uint8_t Reserve0;
|
||||
__IO uint8_t MIS_ST;
|
||||
__IO uint8_t INT_FG;
|
||||
__IO uint8_t INT_ST;
|
||||
__IO uint16_t RX_LEN;
|
||||
__IO uint16_t Reserve1;
|
||||
__IO uint8_t UEP4_1_MOD;
|
||||
__IO uint8_t UEP2_3_MOD;
|
||||
__IO uint8_t UEP5_6_MOD;
|
||||
__IO uint8_t UEP7_MOD;
|
||||
__IO uint32_t UEP0_DMA;
|
||||
__IO uint32_t UEP1_DMA;
|
||||
__IO uint32_t UEP2_DMA;
|
||||
__IO uint32_t UEP3_DMA;
|
||||
__IO uint32_t UEP4_DMA;
|
||||
__IO uint32_t UEP5_DMA;
|
||||
__IO uint32_t UEP6_DMA;
|
||||
__IO uint32_t UEP7_DMA;
|
||||
__IO uint16_t UEP0_TX_LEN;
|
||||
__IO uint8_t UEP0_TX_CTRL;
|
||||
__IO uint8_t UEP0_RX_CTRL;
|
||||
__IO uint16_t UEP1_TX_LEN;
|
||||
__IO uint8_t UEP1_TX_CTRL;
|
||||
__IO uint8_t UEP1_RX_CTRL;
|
||||
__IO uint16_t UEP2_TX_LEN;
|
||||
__IO uint8_t UEP2_TX_CTRL;
|
||||
__IO uint8_t UEP2_RX_CTRL;
|
||||
__IO uint16_t UEP3_TX_LEN;
|
||||
__IO uint8_t UEP3_TX_CTRL;
|
||||
__IO uint8_t UEP3_RX_CTRL;
|
||||
__IO uint16_t UEP4_TX_LEN;
|
||||
__IO uint8_t UEP4_TX_CTRL;
|
||||
__IO uint8_t UEP4_RX_CTRL;
|
||||
__IO uint16_t UEP5_TX_LEN;
|
||||
__IO uint8_t UEP5_TX_CTRL;
|
||||
__IO uint8_t UEP5_RX_CTRL;
|
||||
__IO uint16_t UEP6_TX_LEN;
|
||||
__IO uint8_t UEP6_TX_CTRL;
|
||||
__IO uint8_t UEP6_RX_CTRL;
|
||||
__IO uint16_t UEP7_TX_LEN;
|
||||
__IO uint8_t UEP7_TX_CTRL;
|
||||
__IO uint8_t UEP7_RX_CTRL;
|
||||
__IO uint32_t Reserve2;
|
||||
__IO uint32_t OTG_CR;
|
||||
__IO uint32_t OTG_SR;
|
||||
} USBOTG_FS_TypeDef;
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
__IO uint8_t BASE_CTRL;
|
||||
__IO uint8_t HOST_CTRL;
|
||||
__IO uint8_t INT_EN;
|
||||
__IO uint8_t DEV_ADDR;
|
||||
__IO uint8_t Reserve0;
|
||||
__IO uint8_t MIS_ST;
|
||||
__IO uint8_t INT_FG;
|
||||
__IO uint8_t INT_ST;
|
||||
__IO uint16_t RX_LEN;
|
||||
__IO uint16_t Reserve1;
|
||||
__IO uint8_t Reserve2;
|
||||
__IO uint8_t HOST_EP_MOD;
|
||||
__IO uint16_t Reserve3;
|
||||
__IO uint32_t Reserve4;
|
||||
__IO uint32_t Reserve5;
|
||||
__IO uint32_t HOST_RX_DMA;
|
||||
__IO uint32_t HOST_TX_DMA;
|
||||
__IO uint32_t Reserve6;
|
||||
__IO uint32_t Reserve7;
|
||||
__IO uint32_t Reserve8;
|
||||
__IO uint32_t Reserve9;
|
||||
__IO uint32_t Reserve10;
|
||||
__IO uint16_t Reserve11;
|
||||
__IO uint16_t HOST_SETUP;
|
||||
__IO uint8_t HOST_EP_PID;
|
||||
__IO uint8_t Reserve12;
|
||||
__IO uint8_t Reserve13;
|
||||
__IO uint8_t HOST_RX_CTRL;
|
||||
__IO uint16_t HOST_TX_LEN;
|
||||
__IO uint8_t HOST_TX_CTRL;
|
||||
__IO uint8_t Reserve14;
|
||||
__IO uint32_t Reserve15;
|
||||
__IO uint32_t Reserve16;
|
||||
__IO uint32_t Reserve17;
|
||||
__IO uint32_t Reserve18;
|
||||
__IO uint32_t Reserve19;
|
||||
__IO uint32_t OTG_CR;
|
||||
__IO uint32_t OTG_SR;
|
||||
} USBOTGH_FS_TypeDef;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
__IO uint8_t BASE_CTRL; /*!< 0x40008000 */
|
||||
__IO uint8_t HOST_CTRL; /*!< 0x40008001 */
|
||||
__IO uint8_t INT_EN; /*!< 0x40008002 */
|
||||
__IO uint8_t DEV_ADDR; /*!< 0x40008003 */
|
||||
__IO uint8_t USB_STATUS0; /*!< 0x40008004 */
|
||||
__IO uint8_t MIS_ST; /*!< 0x40008005 */
|
||||
__IO uint8_t INT_FG; /*!< 0x40008006 */
|
||||
__IO uint8_t INT_ST; /*!< 0x40008007 */
|
||||
__IO uint8_t RX_LEN; /*!< 0x40008008 */
|
||||
__IO uint8_t Reserve1; /*!< 0x40008009 */
|
||||
__IO uint8_t Reserve2; /*!< 0x4000800a */
|
||||
__IO uint8_t Reserve3; /*!< 0x4000800b */
|
||||
__IO uint8_t UEP4_1_MOD; /*!< 0x4000800c */
|
||||
__IO uint8_t HOST_EP_MOD; /*!< 0x4000800d */
|
||||
__IO uint8_t UEP567_MOD; /*!< 0x4000800e */
|
||||
__IO uint8_t Reserve4; /*!< 0x4000800f */
|
||||
__IO uint16_t UEP0_DMA; /*!< 0x40008010 */
|
||||
__IO uint16_t Reserve5; /*!< 0x40008012 */
|
||||
__IO uint16_t UEP1_DMA; /*!< 0x40008014 */
|
||||
__IO uint16_t Reserve6; /*!< 0x40008016 */
|
||||
__IO uint16_t HOST_RX_DMA; /*!< 0x40008018 */
|
||||
__IO uint16_t Reserve7; /*!< 0x4000801a */
|
||||
__IO uint16_t HOST_TX_DMA; /*!< 0x4000801c */
|
||||
__IO uint16_t Reserve8; /*!< 0x4000801e */
|
||||
__IO uint8_t UEP0_T_LEN; /*!< 0x40008020 */
|
||||
__IO uint8_t Reserve9; /*!< 0x40008021 */
|
||||
__IO uint8_t UEP0_CTRL; /*!< 0x40008022 */
|
||||
__IO uint8_t Reserve10; /*!< 0x40008023 */
|
||||
__IO uint8_t UEP1_T_LEN; /*!< 0x40008024 */
|
||||
__IO uint8_t Reserve11; /*!< 0x40008025 */
|
||||
__IO uint8_t HOST_SETUP; /*!< 0x40008026 */
|
||||
__IO uint8_t Reserve12; /*!< 0x40008027 */
|
||||
__IO uint8_t HOST_EP_PID; /*!< 0x40008028 */
|
||||
__IO uint8_t Reserve13; /*!< 0x40008029 */
|
||||
__IO uint8_t HOST_RX_CTRL; /*!< 0x4000802a */
|
||||
__IO uint8_t Reserve14; /*!< 0x4000802b */
|
||||
__IO uint8_t HOST_TX_LEN; /*!< 0x4000802c */
|
||||
__IO uint8_t Reserve15; /*!< 0x4000802d */
|
||||
__IO uint8_t HOST_TX_CTRL; /*!< 0x4000802e */
|
||||
__IO uint8_t Reserve16; /*!< 0x4000802f */
|
||||
__IO uint8_t UEP4_T_LEN; /*!< 0x40008030 */
|
||||
__IO uint8_t Reserve17; /*!< 0x40008031 */
|
||||
__IO uint8_t UEP4_CTRL; /*!< 0x40008032 */
|
||||
__IO uint8_t Reserve18[33]; /*!< 0x40008033 */
|
||||
__IO uint16_t UEP5_DMA; /*!< 0x40008054 */
|
||||
__IO uint16_t Reserve19; /*!< 0x40008056 */
|
||||
__IO uint16_t UEP6_DMA; /*!< 0x40008058 */
|
||||
__IO uint16_t Reserve20; /*!< 0x4000805a */
|
||||
__IO uint16_t UEP7_DMA; /*!< 0x4000805c */
|
||||
__IO uint8_t Reserve21[6]; /*!< 0x4000805e */
|
||||
__IO uint8_t UEP5_T_LEN; /*!< 0x40008064 */
|
||||
__IO uint8_t Reserve22; /*!< 0x40008065 */
|
||||
__IO uint8_t UEP5_CTRL; /*!< 0x40008066 */
|
||||
__IO uint8_t Reserve23; /*!< 0x40008067 */
|
||||
__IO uint8_t UEP6_T_LEN; /*!< 0x40008068 */
|
||||
__IO uint8_t Reserve24; /*!< 0x40008069 */
|
||||
__IO uint8_t UEP6_CTRL; /*!< 0x4000806a */
|
||||
__IO uint8_t Reserve25; /*!< 0x4000806b */
|
||||
__IO uint8_t UEP7_T_LEN; /*!< 0x4000806c */
|
||||
__IO uint8_t Reserve26; /*!< 0x4000806d */
|
||||
__IO uint8_t UEP7_CTRL; /*!< 0x4000806e */
|
||||
} USB_FS_TypeDef;
|
||||
|
||||
#define USBFS_BASE ((uint32_t)0x50000000)
|
||||
|
||||
#define USBFS_DEVICE ((USBOTG_FS_TypeDef *)USBFS_BASE)
|
||||
#define USBFS_HOST ((USBOTGH_FS_TypeDef *)USBFS_BASE)
|
||||
|
||||
/******************* GLOBAL ******************/
|
||||
|
||||
/* BASE USB_CTRL */
|
||||
#define USBFS_BASE_CTRL_OFFSET 0x00 // USB base control
|
||||
#define USBFS_UC_HOST_MODE 0x80 // enable USB host mode: 0=device mode, 1=host mode
|
||||
#define USBFS_UC_LOW_SPEED 0x40 // enable USB low speed: 0=12Mbps, 1=1.5Mbps
|
||||
#define USBFS_UC_DEV_PU_EN 0x20 // USB device enable and internal pullup resistance enable
|
||||
#define USBFS_UC_SYS_CTRL1 0x20 // USB system control high bit
|
||||
#define USBFS_UC_SYS_CTRL0 0x10 // USB system control low bit
|
||||
#define USBFS_UC_SYS_CTRL_MASK 0x30 // bit mask of USB system control
|
||||
// UC_HOST_MODE & UC_SYS_CTRL1 & UC_SYS_CTRL0: USB system control
|
||||
// 0 00: disable USB device and disable internal pullup resistance
|
||||
// 0 01: enable USB device and disable internal pullup resistance, need external pullup resistance
|
||||
// 0 1x: enable USB device and enable internal pullup resistance
|
||||
// 1 00: enable USB host and normal status
|
||||
// 1 01: enable USB host and force UDP/UDM output SE0 state
|
||||
// 1 10: enable USB host and force UDP/UDM output J state
|
||||
// 1 11: enable USB host and force UDP/UDM output resume or K state
|
||||
#define USBFS_UC_INT_BUSY 0x08 // enable automatic responding busy for device mode or automatic pause for host mode during interrupt flag UIF_TRANSFER valid
|
||||
#define USBFS_UC_RESET_SIE 0x04 // force reset USB SIE, need software clear
|
||||
#define USBFS_UC_CLR_ALL 0x02 // force clear FIFO and count of USB
|
||||
#define USBFS_UC_DMA_EN 0x01 // DMA enable and DMA interrupt enable for USB
|
||||
|
||||
/* USB INT EN */
|
||||
#define USBFS_INT_EN_OFFSET 0x02
|
||||
#define USBFS_UIE_DEV_SOF 0x80 // enable interrupt for SOF received for USB device mode
|
||||
#define USBFS_UIE_DEV_NAK 0x40 // enable interrupt for NAK responded for USB device mode
|
||||
#define USBFS_UIE_FIFO_OV 0x10 // enable interrupt for FIFO overflow
|
||||
#define USBFS_UIE_HST_SOF 0x08 // enable interrupt for host SOF timer action for USB host mode
|
||||
#define USBFS_UIE_SUSPEND 0x04 // enable interrupt for USB suspend or resume event
|
||||
#define USBFS_UIE_TRANSFER 0x02 // enable interrupt for USB transfer completion
|
||||
#define USBFS_UIE_DETECT 0x01 // enable interrupt for USB device detected event for USB host mode
|
||||
#define USBFS_UIE_BUS_RST 0x01 // enable interrupt for USB bus reset event for USB device mode
|
||||
/* USB_DEV_ADDR */
|
||||
#define USBFS_DEV_ADDR_OFFSET 0x03
|
||||
#define USBFS_UDA_GP_BIT 0x80 // general purpose bit
|
||||
#define USBFS_USB_ADDR_MASK 0x7F // bit mask for USB device address
|
||||
|
||||
/* USB_STATUS */
|
||||
#define USBFS_USB_STATUS_OFFSET 0x04
|
||||
|
||||
/* USB_MIS_ST */
|
||||
#define USBFS_MIS_ST_OFFSET 0x05
|
||||
#define USBFS_UMS_SOF_PRES 0x80 // RO, indicate host SOF timer presage status
|
||||
#define USBFS_UMS_SOF_ACT 0x40 // RO, indicate host SOF timer action status for USB host
|
||||
#define USBFS_UMS_SIE_FREE 0x20 // RO, indicate USB SIE free status
|
||||
#define USBFS_UMS_R_FIFO_RDY 0x10 // RO, indicate USB receiving FIFO ready status (not empty)
|
||||
#define USBFS_UMS_BUS_RESET 0x08 // RO, indicate USB bus reset status
|
||||
#define USBFS_UMS_SUSPEND 0x04 // RO, indicate USB suspend status
|
||||
#define USBFS_UMS_DM_LEVEL 0x02 // RO, indicate UDM level saved at device attached to USB host
|
||||
#define USBFS_UMS_DEV_ATTACH 0x01 // RO, indicate device attached status on USB host
|
||||
|
||||
/* USB_INT_FG */
|
||||
#define USBFS_INT_FG_OFFSET 0x06
|
||||
#define USBFS_U_IS_NAK 0x80 // RO, indicate current USB transfer is NAK received
|
||||
#define USBFS_U_TOG_OK 0x40 // RO, indicate current USB transfer toggle is OK
|
||||
#define USBFS_U_SIE_FREE 0x20 // RO, indicate USB SIE free status
|
||||
#define USBFS_UIF_FIFO_OV 0x10 // FIFO overflow interrupt flag for USB, direct bit address clear or write 1 to clear
|
||||
#define USBFS_UIF_HST_SOF 0x08 // host SOF timer interrupt flag for USB host, direct bit address clear or write 1 to clear
|
||||
#define USBFS_UIF_SUSPEND 0x04 // USB suspend or resume event interrupt flag, direct bit address clear or write 1 to clear
|
||||
#define USBFS_UIF_TRANSFER 0x02 // USB transfer completion interrupt flag, direct bit address clear or write 1 to clear
|
||||
#define USBFS_UIF_DETECT 0x01 // device detected event interrupt flag for USB host mode, direct bit address clear or write 1 to clear
|
||||
#define USBFS_UIF_BUS_RST 0x01 // bus reset event interrupt flag for USB device mode, direct bit address clear or write 1 to clear
|
||||
|
||||
/* USB_INT_ST */
|
||||
#define USBFS_INT_ST_OFFSET 0x07
|
||||
#define USBFS_UIS_IS_SETUP 0x80 // RO, indicate current USB transfer is setup received for USB device mode
|
||||
#define USBFS_UIS_IS_NAK 0x80 // RO, indicate current USB transfer is NAK received for USB device mode
|
||||
#define USBFS_UIS_TOG_OK 0x40 // RO, indicate current USB transfer toggle is OK
|
||||
#define USBFS_UIS_TOKEN1 0x20 // RO, current token PID code bit 1 received for USB device mode
|
||||
#define USBFS_UIS_TOKEN0 0x10 // RO, current token PID code bit 0 received for USB device mode
|
||||
#define USBFS_UIS_TOKEN_MASK 0x30 // RO, bit mask of current token PID code received for USB device mode
|
||||
#define USBFS_UIS_TOKEN_OUT 0x00
|
||||
#define USBFS_UIS_TOKEN_SOF 0x10
|
||||
#define USBFS_UIS_TOKEN_IN 0x20
|
||||
#define USBFS_UIS_TOKEN_SETUP 0x30
|
||||
// UIS_TOKEN1 & UIS_TOKEN0: current token PID code received for USB device mode
|
||||
// 00: OUT token PID received
|
||||
// 01: SOF token PID received
|
||||
// 10: IN token PID received
|
||||
// 11: SETUP token PID received
|
||||
#define USBFS_UIS_ENDP_MASK 0x0F // RO, bit mask of current transfer endpoint number for USB device mode
|
||||
/* USB_RX_LEN */
|
||||
#define USBFS_RX_LEN_OFFSET 0x08
|
||||
|
||||
/******************* DEVICE ******************/
|
||||
|
||||
/* UDEV_CTRL */
|
||||
#define USBFS_UDEV_CTRL_OFFSET 0x01
|
||||
#define USBFS_UD_PD_DIS 0x80 // disable USB UDP/UDM pulldown resistance: 0=enable pulldown, 1=disable
|
||||
#define USBFS_UD_DP_PIN 0x20 // ReadOnly: indicate current UDP pin level
|
||||
#define USBFS_UD_DM_PIN 0x10 // ReadOnly: indicate current UDM pin level
|
||||
#define USBFS_UD_LOW_SPEED 0x04 // enable USB physical port low speed: 0=full speed, 1=low speed
|
||||
#define USBFS_UD_GP_BIT 0x02 // general purpose bit
|
||||
#define USBFS_UD_PORT_EN 0x01 // enable USB physical port I/O: 0=disable, 1=enable
|
||||
|
||||
/* UEP4_1_MOD */
|
||||
#define USBFS_UEP4_1_MOD_OFFSET 0x0C
|
||||
#define USBFS_UEP1_RX_EN 0x80 // enable USB endpoint 1 receiving (OUT)
|
||||
#define USBFS_UEP1_TX_EN 0x40 // enable USB endpoint 1 transmittal (IN)
|
||||
#define USBFS_UEP1_BUF_MOD 0x10 // buffer mode of USB endpoint 1
|
||||
// UEPn_RX_EN & UEPn_TX_EN & UEPn_BUF_MOD: USB endpoint 1/2/3 buffer mode, buffer start address is UEPn_DMA
|
||||
// 0 0 x: disable endpoint and disable buffer
|
||||
// 1 0 0: 64 bytes buffer for receiving (OUT endpoint)
|
||||
// 1 0 1: dual 64 bytes buffer by toggle bit bUEP_R_TOG selection for receiving (OUT endpoint), total=128bytes
|
||||
// 0 1 0: 64 bytes buffer for transmittal (IN endpoint)
|
||||
// 0 1 1: dual 64 bytes buffer by toggle bit bUEP_T_TOG selection for transmittal (IN endpoint), total=128bytes
|
||||
// 1 1 0: 64 bytes buffer for receiving (OUT endpoint) + 64 bytes buffer for transmittal (IN endpoint), total=128bytes
|
||||
// 1 1 1: dual 64 bytes buffer by bUEP_R_TOG selection for receiving (OUT endpoint) + dual 64 bytes buffer by bUEP_T_TOG selection for transmittal (IN endpoint), total=256bytes
|
||||
#define USBFS_UEP4_RX_EN 0x08 // enable USB endpoint 4 receiving (OUT)
|
||||
#define USBFS_UEP4_TX_EN 0x04 // enable USB endpoint 4 transmittal (IN)
|
||||
// UEP4_RX_EN & UEP4_TX_EN: USB endpoint 4 buffer mode, buffer start address is UEP0_DMA
|
||||
// 0 0: single 64 bytes buffer for endpoint 0 receiving & transmittal (OUT & IN endpoint)
|
||||
// 1 0: single 64 bytes buffer for endpoint 0 receiving & transmittal (OUT & IN endpoint) + 64 bytes buffer for endpoint 4 receiving (OUT endpoint), total=128bytes
|
||||
// 0 1: single 64 bytes buffer for endpoint 0 receiving & transmittal (OUT & IN endpoint) + 64 bytes buffer for endpoint 4 transmittal (IN endpoint), total=128bytes
|
||||
// 1 1: single 64 bytes buffer for endpoint 0 receiving & transmittal (OUT & IN endpoint)
|
||||
// + 64 bytes buffer for endpoint 4 receiving (OUT endpoint) + 64 bytes buffer for endpoint 4 transmittal (IN endpoint), total=192bytes
|
||||
|
||||
/* UEP2_3_MOD */
|
||||
#define USBFS_UEP2_3_MOD_OFFSET 0x0D
|
||||
#define USBFS_UEP3_RX_EN 0x80 // enable USB endpoint 3 receiving (OUT)
|
||||
#define USBFS_UEP3_TX_EN 0x40 // enable USB endpoint 3 transmittal (IN)
|
||||
#define USBFS_UEP3_BUF_MOD 0x10 // buffer mode of USB endpoint 3
|
||||
#define USBFS_UEP2_RX_EN 0x08 // enable USB endpoint 2 receiving (OUT)
|
||||
#define USBFS_UEP2_TX_EN 0x04 // enable USB endpoint 2 transmittal (IN)
|
||||
#define USBFS_UEP2_BUF_MOD 0x01 // buffer mode of USB endpoint 2
|
||||
|
||||
/* UEP5_6_MOD */
|
||||
#define USBFS_UEP5_6_MOD_OFFSET 0x0E
|
||||
#define USBFS_UEP6_RX_EN 0x80 // enable USB endpoint 6 receiving (OUT)
|
||||
#define USBFS_UEP6_TX_EN 0x40 // enable USB endpoint 6 transmittal (IN)
|
||||
#define USBFS_UEP6_BUF_MOD 0x10 // buffer mode of USB endpoint 6
|
||||
#define USBFS_UEP5_RX_EN 0x08 // enable USB endpoint 5 receiving (OUT)
|
||||
#define USBFS_UEP5_TX_EN 0x04 // enable USB endpoint 5 transmittal (IN)
|
||||
#define USBFS_UEP5_BUF_MOD 0x01 // buffer mode of USB endpoint 5
|
||||
|
||||
/* UEP7_MOD */
|
||||
#define USBFS_UEP7_MOD_OFFSET 0x0F
|
||||
#define USBFS_UEP7_RX_EN 0x08 // enable USB endpoint 7 receiving (OUT)
|
||||
#define USBFS_UEP7_TX_EN 0x04 // enable USB endpoint 7 transmittal (IN)
|
||||
#define USBFS_UEP7_BUF_MOD 0x01 // buffer mode of USB endpoint 7
|
||||
|
||||
/* USB_DMA */
|
||||
#define USBFS_UEPx_DMA_OFFSET(n) (0x10 + 4 * (n)) // endpoint x DMA buffer address
|
||||
#define USBFS_UEP0_DMA_OFFSET 0x10 // endpoint 0 DMA buffer address
|
||||
#define USBFS_UEP1_DMA_OFFSET 0x14 // endpoint 1 DMA buffer address
|
||||
#define USBFS_UEP2_DMA_OFFSET 0x18 // endpoint 2 DMA buffer address
|
||||
#define USBFS_UEP3_DMA_OFFSET 0x1c // endpoint 3 DMA buffer address
|
||||
#define USBFS_UEP4_DMA_OFFSET 0x20 // endpoint 4 DMA buffer address
|
||||
#define USBFS_UEP5_DMA_OFFSET 0x24 // endpoint 5 DMA buffer address
|
||||
#define USBFS_UEP6_DMA_OFFSET 0x28 // endpoint 6 DMA buffer address
|
||||
#define USBFS_UEP7_DMA_OFFSET 0x2c // endpoint 7 DMA buffer address
|
||||
/* USB_EP_CTRL */
|
||||
#define USBFS_UEPx_T_LEN_OFFSET(n) (0x30 + 4 * (n)) // endpoint x DMA buffer address
|
||||
#define USBFS_UEPx_TX_CTRL_OFFSET(n) (0x30 + 4 * (n) + 2) // endpoint x DMA buffer address
|
||||
#define USBFS_UEPx_RX_CTRL_OFFSET(n) (0x30 + 4 * (n) + 3) // endpoint x DMA buffer address
|
||||
|
||||
#define USBFS_UEP_AUTO_TOG 0x08 // enable automatic toggle after successful transfer completion on endpoint 1/2/3: 0=manual toggle, 1=automatic toggle
|
||||
#define USBFS_UEP_R_TOG 0x04 // expected data toggle flag of USB endpoint X receiving (OUT): 0=DATA0, 1=DATA1
|
||||
#define USBFS_UEP_T_TOG 0x04 // prepared data toggle flag of USB endpoint X transmittal (IN): 0=DATA0, 1=DATA1
|
||||
|
||||
#define USBFS_UEP_R_RES1 0x02 // handshake response type high bit for USB endpoint X receiving (OUT)
|
||||
#define USBFS_UEP_R_RES0 0x01 // handshake response type low bit for USB endpoint X receiving (OUT)
|
||||
#define USBFS_UEP_R_RES_MASK 0x03 // bit mask of handshake response type for USB endpoint X receiving (OUT)
|
||||
#define USBFS_UEP_R_RES_ACK 0x00
|
||||
#define USBFS_UEP_R_RES_TOUT 0x01
|
||||
#define USBFS_UEP_R_RES_NAK 0x02
|
||||
#define USBFS_UEP_R_RES_STALL 0x03
|
||||
// RB_UEP_R_RES1 & RB_UEP_R_RES0: handshake response type for USB endpoint X receiving (OUT)
|
||||
// 00: ACK (ready)
|
||||
// 01: no response, time out to host, for non-zero endpoint isochronous transactions
|
||||
// 10: NAK (busy)
|
||||
// 11: STALL (error)
|
||||
#define USBFS_UEP_T_RES1 0x02 // handshake response type high bit for USB endpoint X transmittal (IN)
|
||||
#define USBFS_UEP_T_RES0 0x01 // handshake response type low bit for USB endpoint X transmittal (IN)
|
||||
#define USBFS_UEP_T_RES_MASK 0x03 // bit mask of handshake response type for USB endpoint X transmittal (IN)
|
||||
#define USBFS_UEP_T_RES_ACK 0x00
|
||||
#define USBFS_UEP_T_RES_TOUT 0x01
|
||||
#define USBFS_UEP_T_RES_NAK 0x02
|
||||
#define USBFS_UEP_T_RES_STALL 0x03
|
||||
// bUEP_T_RES1 & bUEP_T_RES0: handshake response type for USB endpoint X transmittal (IN)
|
||||
// 00: DATA0 or DATA1 then expecting ACK (ready)
|
||||
// 01: DATA0 or DATA1 then expecting no response, time out from host, for non-zero endpoint isochronous transactions
|
||||
// 10: NAK (busy)
|
||||
// 11: TALL (error)
|
||||
|
||||
/******************* HOST ******************/
|
||||
|
||||
#define USBFS_UHOST_CTRL_OFFSET 0x01 // USB host physical prot control
|
||||
#define USBFS_UH_PD_DIS 0x80 // disable USB UDP/UDM pulldown resistance: 0=enable pulldown, 1=disable
|
||||
#define USBFS_UH_DP_PIN 0x20 // ReadOnly: indicate current UDP pin level
|
||||
#define USBFS_UH_DM_PIN 0x10 // ReadOnly: indicate current UDM pin level
|
||||
#define USBFS_UH_LOW_SPEED 0x04 // enable USB port low speed: 0=full speed, 1=low speed
|
||||
#define USBFS_UH_BUS_RESET 0x02 // control USB bus reset: 0=normal, 1=force bus reset
|
||||
#define USBFS_UH_PORT_EN 0x01 // enable USB port: 0=disable, 1=enable port, automatic disabled if USB device detached
|
||||
|
||||
#define USBFS_UH_EP_MOD_OFFSET USBFS_UEP2_3_MOD_OFFSET
|
||||
#define USBFS_UH_EP_TX_EN 0x40 // enable USB host OUT endpoint transmittal
|
||||
#define USBFS_UH_EP_TBUF_MOD 0x10 // buffer mode of USB host OUT endpoint
|
||||
// bUH_EP_TX_EN & bUH_EP_TBUF_MOD: USB host OUT endpoint buffer mode, buffer start address is UH_TX_DMA
|
||||
// 0 x: disable endpoint and disable buffer
|
||||
// 1 0: 64 bytes buffer for transmittal (OUT endpoint)
|
||||
// 1 1: dual 64 bytes buffer by toggle bit bUH_T_TOG selection for transmittal (OUT endpoint), total=128bytes
|
||||
#define USBFS_UH_EP_RX_EN 0x08 // enable USB host IN endpoint receiving
|
||||
#define USBFS_UH_EP_RBUF_MOD 0x01 // buffer mode of USB host IN endpoint
|
||||
// bUH_EP_RX_EN & bUH_EP_RBUF_MOD: USB host IN endpoint buffer mode, buffer start address is UH_RX_DMA
|
||||
// 0 x: disable endpoint and disable buffer
|
||||
// 1 0: 64 bytes buffer for receiving (IN endpoint)
|
||||
// 1 1: dual 64 bytes buffer by toggle bit bUH_R_TOG selection for receiving (IN endpoint), total=128bytes
|
||||
|
||||
#define USBFS_UH_RX_DMA_OFFSET USBFS_UEPx_DMA_OFFSET(2) // host rx endpoint buffer high address
|
||||
#define USBFS_UH_TX_DMA_OFFSET USBFS_UEPx_DMA_OFFSET(3) // host tx endpoint buffer high address
|
||||
|
||||
#define USBFS_UH_SETUP_OFFSET USBFS_UEPx_TX_CTRL_OFFSET(1)
|
||||
#define USBFS_UH_PRE_PID_EN 0x0400 // USB host PRE PID enable for low speed device via hub
|
||||
#define USBFS_UH_SOF_EN 0x04 // USB host automatic SOF enable
|
||||
|
||||
#define USBFS_UH_EP_PID_OFFSET USBFS_UEPx_T_LEN_OFFSET(2)
|
||||
#define USBFS_UH_TOKEN_MASK 0xF0 // bit mask of token PID for USB host transfer
|
||||
#define USBFS_UH_ENDP_MASK 0x0F // bit mask of endpoint number for USB host transfer
|
||||
|
||||
#define USBFS_UH_RX_CTRL_OFFSET USBFS_UEPx_RX_CTRL_OFFSET(2) // host receiver endpoint control
|
||||
#define USBFS_UH_R_AUTO_TOG 0x08 // enable automatic toggle after successful transfer completion: 0=manual toggle, 1=automatic toggle
|
||||
#define USBFS_UH_R_TOG 0x04 // expected data toggle flag of host receiving (IN): 0=DATA0, 1=DATA1
|
||||
#define USBFS_UH_R_RES 0x01 // prepared handshake response type for host receiving (IN): 0=ACK (ready), 1=no response, time out to device, for isochronous transactions
|
||||
|
||||
#define USBFS_UH_TX_LEN_OFFSET USBFS_UEPx_T_LEN_OFFSET(3)
|
||||
|
||||
#define USBFS_UH_TX_CTRL_OFFSET USBFS_UEPx_TX_CTRL_OFFSET(3) // host transmittal endpoint control
|
||||
#define USBFS_UH_T_AUTO_TOG 0x08 // enable automatic toggle after successful transfer completion: 0=manual toggle, 1=automatic toggle
|
||||
#define USBFS_UH_T_TOG 0x04 // prepared data toggle flag of host transmittal (SETUP/OUT): 0=DATA0, 1=DATA1
|
||||
#define USBFS_UH_T_RES 0x01 // expected handshake response type for host transmittal (SETUP/OUT): 0=ACK (ready), 1=no response, time out from device, for isochronous transactions
|
||||
|
||||
#endif
|
@@ -0,0 +1,564 @@
|
||||
/*
|
||||
* Copyright (c) 2022, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef _USB_CH32_USBHS_REG_H
|
||||
#define _USB_CH32_USBHS_REG_H
|
||||
|
||||
#define __IO volatile /* defines 'read / write' permissions */
|
||||
|
||||
/* USBHS Registers */
|
||||
typedef struct
|
||||
{
|
||||
__IO uint8_t CONTROL;
|
||||
__IO uint8_t HOST_CTRL;
|
||||
__IO uint8_t INT_EN;
|
||||
__IO uint8_t DEV_AD;
|
||||
__IO uint16_t FRAME_NO;
|
||||
__IO uint8_t SUSPEND;
|
||||
__IO uint8_t RESERVED0;
|
||||
__IO uint8_t SPEED_TYPE;
|
||||
__IO uint8_t MIS_ST;
|
||||
__IO uint8_t INT_FG;
|
||||
__IO uint8_t INT_ST;
|
||||
__IO uint16_t RX_LEN;
|
||||
__IO uint16_t RESERVED1;
|
||||
__IO uint32_t ENDP_CONFIG;
|
||||
__IO uint32_t ENDP_TYPE;
|
||||
__IO uint32_t BUF_MODE;
|
||||
__IO uint32_t UEP0_DMA;
|
||||
__IO uint32_t UEP1_RX_DMA;
|
||||
__IO uint32_t UEP2_RX_DMA;
|
||||
__IO uint32_t UEP3_RX_DMA;
|
||||
__IO uint32_t UEP4_RX_DMA;
|
||||
__IO uint32_t UEP5_RX_DMA;
|
||||
__IO uint32_t UEP6_RX_DMA;
|
||||
__IO uint32_t UEP7_RX_DMA;
|
||||
__IO uint32_t UEP8_RX_DMA;
|
||||
__IO uint32_t UEP9_RX_DMA;
|
||||
__IO uint32_t UEP10_RX_DMA;
|
||||
__IO uint32_t UEP11_RX_DMA;
|
||||
__IO uint32_t UEP12_RX_DMA;
|
||||
__IO uint32_t UEP13_RX_DMA;
|
||||
__IO uint32_t UEP14_RX_DMA;
|
||||
__IO uint32_t UEP15_RX_DMA;
|
||||
__IO uint32_t UEP1_TX_DMA;
|
||||
__IO uint32_t UEP2_TX_DMA;
|
||||
__IO uint32_t UEP3_TX_DMA;
|
||||
__IO uint32_t UEP4_TX_DMA;
|
||||
__IO uint32_t UEP5_TX_DMA;
|
||||
__IO uint32_t UEP6_TX_DMA;
|
||||
__IO uint32_t UEP7_TX_DMA;
|
||||
__IO uint32_t UEP8_TX_DMA;
|
||||
__IO uint32_t UEP9_TX_DMA;
|
||||
__IO uint32_t UEP10_TX_DMA;
|
||||
__IO uint32_t UEP11_TX_DMA;
|
||||
__IO uint32_t UEP12_TX_DMA;
|
||||
__IO uint32_t UEP13_TX_DMA;
|
||||
__IO uint32_t UEP14_TX_DMA;
|
||||
__IO uint32_t UEP15_TX_DMA;
|
||||
__IO uint16_t UEP0_MAX_LEN;
|
||||
__IO uint16_t RESERVED2;
|
||||
__IO uint16_t UEP1_MAX_LEN;
|
||||
__IO uint16_t RESERVED3;
|
||||
__IO uint16_t UEP2_MAX_LEN;
|
||||
__IO uint16_t RESERVED4;
|
||||
__IO uint16_t UEP3_MAX_LEN;
|
||||
__IO uint16_t RESERVED5;
|
||||
__IO uint16_t UEP4_MAX_LEN;
|
||||
__IO uint16_t RESERVED6;
|
||||
__IO uint16_t UEP5_MAX_LEN;
|
||||
__IO uint16_t RESERVED7;
|
||||
__IO uint16_t UEP6_MAX_LEN;
|
||||
__IO uint16_t RESERVED8;
|
||||
__IO uint16_t UEP7_MAX_LEN;
|
||||
__IO uint16_t RESERVED9;
|
||||
__IO uint16_t UEP8_MAX_LEN;
|
||||
__IO uint16_t RESERVED10;
|
||||
__IO uint16_t UEP9_MAX_LEN;
|
||||
__IO uint16_t RESERVED11;
|
||||
__IO uint16_t UEP10_MAX_LEN;
|
||||
__IO uint16_t RESERVED12;
|
||||
__IO uint16_t UEP11_MAX_LEN;
|
||||
__IO uint16_t RESERVED13;
|
||||
__IO uint16_t UEP12_MAX_LEN;
|
||||
__IO uint16_t RESERVED14;
|
||||
__IO uint16_t UEP13_MAX_LEN;
|
||||
__IO uint16_t RESERVED15;
|
||||
__IO uint16_t UEP14_MAX_LEN;
|
||||
__IO uint16_t RESERVED16;
|
||||
__IO uint16_t UEP15_MAX_LEN;
|
||||
__IO uint16_t RESERVED17;
|
||||
__IO uint16_t UEP0_TX_LEN;
|
||||
__IO uint8_t UEP0_TX_CTRL;
|
||||
__IO uint8_t UEP0_RX_CTRL;
|
||||
__IO uint16_t UEP1_TX_LEN;
|
||||
__IO uint8_t UEP1_TX_CTRL;
|
||||
__IO uint8_t UEP1_RX_CTRL;
|
||||
__IO uint16_t UEP2_TX_LEN;
|
||||
__IO uint8_t UEP2_TX_CTRL;
|
||||
__IO uint8_t UEP2_RX_CTRL;
|
||||
__IO uint16_t UEP3_TX_LEN;
|
||||
__IO uint8_t UEP3_TX_CTRL;
|
||||
__IO uint8_t UEP3_RX_CTRL;
|
||||
__IO uint16_t UEP4_TX_LEN;
|
||||
__IO uint8_t UEP4_TX_CTRL;
|
||||
__IO uint8_t UEP4_RX_CTRL;
|
||||
__IO uint16_t UEP5_TX_LEN;
|
||||
__IO uint8_t UEP5_TX_CTRL;
|
||||
__IO uint8_t UEP5_RX_CTRL;
|
||||
__IO uint16_t UEP6_TX_LEN;
|
||||
__IO uint8_t UEP6_TX_CTRL;
|
||||
__IO uint8_t UEP6_RX_CTRL;
|
||||
__IO uint16_t UEP7_TX_LEN;
|
||||
__IO uint8_t UEP7_TX_CTRL;
|
||||
__IO uint8_t UEP7_RX_CTRL;
|
||||
__IO uint16_t UEP8_TX_LEN;
|
||||
__IO uint8_t UEP8_TX_CTRL;
|
||||
__IO uint8_t UEP8_RX_CTRL;
|
||||
__IO uint16_t UEP9_TX_LEN;
|
||||
__IO uint8_t UEP9_TX_CTRL;
|
||||
__IO uint8_t UEP9_RX_CTRL;
|
||||
__IO uint16_t UEP10_TX_LEN;
|
||||
__IO uint8_t UEP10_TX_CTRL;
|
||||
__IO uint8_t UEP10_RX_CTRL;
|
||||
__IO uint16_t UEP11_TX_LEN;
|
||||
__IO uint8_t UEP11_TX_CTRL;
|
||||
__IO uint8_t UEP11_RX_CTRL;
|
||||
__IO uint16_t UEP12_TX_LEN;
|
||||
__IO uint8_t UEP12_TX_CTRL;
|
||||
__IO uint8_t UEP12_RX_CTRL;
|
||||
__IO uint16_t UEP13_TX_LEN;
|
||||
__IO uint8_t UEP13_TX_CTRL;
|
||||
__IO uint8_t UEP13_RX_CTRL;
|
||||
__IO uint16_t UEP14_TX_LEN;
|
||||
__IO uint8_t UEP14_TX_CTRL;
|
||||
__IO uint8_t UEP14_RX_CTRL;
|
||||
__IO uint16_t UEP15_TX_LEN;
|
||||
__IO uint8_t UEP15_TX_CTRL;
|
||||
__IO uint8_t UEP15_RX_CTRL;
|
||||
} USBHSD_TypeDef;
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
__IO uint8_t CONTROL;
|
||||
__IO uint8_t HOST_CTRL;
|
||||
__IO uint8_t INT_EN;
|
||||
__IO uint8_t DEV_AD;
|
||||
__IO uint16_t FRAME_NO;
|
||||
__IO uint8_t SUSPEND;
|
||||
__IO uint8_t RESERVED0;
|
||||
__IO uint8_t SPEED_TYPE;
|
||||
__IO uint8_t MIS_ST;
|
||||
__IO uint8_t INT_FG;
|
||||
__IO uint8_t INT_ST;
|
||||
__IO uint16_t RX_LEN;
|
||||
__IO uint16_t RESERVED1;
|
||||
__IO uint32_t HOST_EP_CONFIG;
|
||||
__IO uint32_t HOST_EP_TYPE;
|
||||
__IO uint32_t RESERVED2;
|
||||
__IO uint32_t RESERVED3;
|
||||
__IO uint32_t RESERVED4;
|
||||
__IO uint32_t HOST_RX_DMA;
|
||||
__IO uint32_t RESERVED5;
|
||||
__IO uint32_t RESERVED6;
|
||||
__IO uint32_t RESERVED7;
|
||||
__IO uint32_t RESERVED8;
|
||||
__IO uint32_t RESERVED9;
|
||||
__IO uint32_t RESERVED10;
|
||||
__IO uint32_t RESERVED11;
|
||||
__IO uint32_t RESERVED12;
|
||||
__IO uint32_t RESERVED13;
|
||||
__IO uint32_t RESERVED14;
|
||||
__IO uint32_t RESERVED15;
|
||||
__IO uint32_t RESERVED16;
|
||||
__IO uint32_t RESERVED17;
|
||||
__IO uint32_t RESERVED18;
|
||||
__IO uint32_t RESERVED19;
|
||||
__IO uint32_t HOST_TX_DMA;
|
||||
__IO uint32_t RESERVED20;
|
||||
__IO uint32_t RESERVED21;
|
||||
__IO uint32_t RESERVED22;
|
||||
__IO uint32_t RESERVED23;
|
||||
__IO uint32_t RESERVED24;
|
||||
__IO uint32_t RESERVED25;
|
||||
__IO uint32_t RESERVED26;
|
||||
__IO uint32_t RESERVED27;
|
||||
__IO uint32_t RESERVED28;
|
||||
__IO uint32_t RESERVED29;
|
||||
__IO uint32_t RESERVED30;
|
||||
__IO uint32_t RESERVED31;
|
||||
__IO uint32_t RESERVED32;
|
||||
__IO uint32_t RESERVED33;
|
||||
__IO uint16_t HOST_RX_MAX_LEN;
|
||||
__IO uint16_t RESERVED34;
|
||||
__IO uint32_t RESERVED35;
|
||||
__IO uint32_t RESERVED36;
|
||||
__IO uint32_t RESERVED37;
|
||||
__IO uint32_t RESERVED38;
|
||||
__IO uint32_t RESERVED39;
|
||||
__IO uint32_t RESERVED40;
|
||||
__IO uint32_t RESERVED41;
|
||||
__IO uint32_t RESERVED42;
|
||||
__IO uint32_t RESERVED43;
|
||||
__IO uint32_t RESERVED44;
|
||||
__IO uint32_t RESERVED45;
|
||||
__IO uint32_t RESERVED46;
|
||||
__IO uint32_t RESERVED47;
|
||||
__IO uint32_t RESERVED48;
|
||||
__IO uint32_t RESERVED49;
|
||||
__IO uint8_t HOST_EP_PID;
|
||||
__IO uint8_t RESERVED50;
|
||||
__IO uint8_t RESERVED51;
|
||||
__IO uint8_t HOST_RX_CTRL;
|
||||
__IO uint16_t HOST_TX_LEN;
|
||||
__IO uint8_t HOST_TX_CTRL;
|
||||
__IO uint8_t RESERVED52;
|
||||
__IO uint16_t HOST_SPLIT_DATA;
|
||||
} USBHSH_TypeDef;
|
||||
|
||||
#define USBHS_BASE ((uint32_t)(0x40000000 + 0x23400))
|
||||
|
||||
#define USBHS_DEVICE ((USBHSD_TypeDef *)USBHS_BASE)
|
||||
#define USBHS_HOST ((USBHSH_TypeDef *)USBHS_BASE)
|
||||
|
||||
/******************* GLOBAL ******************/
|
||||
|
||||
// USB CONTROL
|
||||
#define USBHS_CONTROL_OFFSET 0x00
|
||||
#define USBHS_DMA_EN (1 << 0)
|
||||
#define USBHS_ALL_CLR (1 << 1)
|
||||
#define USBHS_FORCE_RST (1 << 2)
|
||||
#define USBHS_INT_BUSY_EN (1 << 3)
|
||||
#define USBHS_DEV_PU_EN (1 << 4)
|
||||
#define USBHS_SPEED_MASK (3 << 5)
|
||||
#define USBHS_FULL_SPEED (0 << 5)
|
||||
#define USBHS_HIGH_SPEED (1 << 5)
|
||||
#define USBHS_LOW_SPEED (2 << 5)
|
||||
#define USBHS_HOST_MODE (1 << 7)
|
||||
|
||||
// USB_INT_EN
|
||||
#define USBHS_INT_EN_OFFSET 0x02
|
||||
#define USBHS_BUS_RST_EN (1 << 0)
|
||||
#define USBHS_DETECT_EN (1 << 0)
|
||||
#define USBHS_TRANSFER_EN (1 << 1)
|
||||
#define USBHS_SUSPEND_EN (1 << 2)
|
||||
#define USBHS_SOF_ACT_EN (1 << 3)
|
||||
#define USBHS_FIFO_OV_EN (1 << 4)
|
||||
#define USBHS_SETUP_ACT_EN (1 << 5)
|
||||
#define USBHS_ISO_ACT_EN (1 << 6)
|
||||
#define USBHS_DEV_NAK_EN (1 << 7)
|
||||
|
||||
// USB DEV AD
|
||||
#define USBHS_DEV_AD_OFFSET 0x03
|
||||
// USB FRAME_NO
|
||||
#define USBHS_FRAME_NO_OFFSET 0x04
|
||||
// USB SUSPEND
|
||||
#define USBHS_SUSPEND_OFFSET 0x06
|
||||
#define USBHS_DEV_REMOTE_WAKEUP (1 << 2)
|
||||
#define USBHS_LINESTATE_MASK (2 << 4) /* Read Only */
|
||||
|
||||
// RESERVED0
|
||||
|
||||
// USB SPEED TYPE
|
||||
#define USBHS_SPEED_TYPE_OFFSET 0x08
|
||||
#define USBSPEED_MASK (0x03)
|
||||
|
||||
// USB_MIS_ST
|
||||
#define USBHS_MIS_ST_OFFSET 0x09
|
||||
#define USBHS_SPLIT_CAN (1 << 0)
|
||||
#define USBHS_ATTACH (1 << 1)
|
||||
#define USBHS_SUSPEND (1 << 2)
|
||||
#define USBHS_BUS_RESET (1 << 3)
|
||||
#define USBHS_R_FIFO_RDY (1 << 4)
|
||||
#define USBHS_SIE_FREE (1 << 5)
|
||||
#define USBHS_SOF_ACT (1 << 6)
|
||||
#define USBHS_SOF_PRES (1 << 7)
|
||||
|
||||
// INT_FLAG
|
||||
#define USBHS_INT_FLAG_OFFSET 0x0A
|
||||
#define USBHS_BUS_RST_FLAG (1 << 0)
|
||||
#define USBHS_DETECT_FLAG (1 << 0)
|
||||
#define USBHS_TRANSFER_FLAG (1 << 1)
|
||||
#define USBHS_SUSPEND_FLAG (1 << 2)
|
||||
#define USBHS_HST_SOF_FLAG (1 << 3)
|
||||
#define USBHS_FIFO_OV_FLAG (1 << 4)
|
||||
#define USBHS_SETUP_FLAG (1 << 5)
|
||||
#define USBHS_ISO_ACT_FLAG (1 << 6)
|
||||
|
||||
// INT_ST
|
||||
#define USBHS_INT_ST_OFFSET 0x0B
|
||||
#define USBHS_DEV_UIS_IS_NAK (1 << 7)
|
||||
#define USBHS_DEV_UIS_TOG_OK (1 << 6)
|
||||
#define MASK_UIS_TOKEN (3 << 4)
|
||||
#define MASK_UIS_ENDP (0x0F)
|
||||
#define MASK_UIS_H_RES (0x0F)
|
||||
|
||||
#define USBHS_TOGGLE_OK (0x40)
|
||||
#define USBHS_HOST_RES (0x0f)
|
||||
|
||||
//USB_RX_LEN
|
||||
#define USBHS_RX_LEN_OFFSET 0x0C
|
||||
/******************* DEVICE ******************/
|
||||
|
||||
//UEP_CONFIG
|
||||
#define USBHS_UEP_CONFIG_OFFSET 0x10
|
||||
#define USBHS_EP0_T_EN (1 << 0)
|
||||
#define USBHS_EP0_R_EN (1 << 16)
|
||||
|
||||
#define USBHS_EP1_T_EN (1 << 1)
|
||||
#define USBHS_EP1_R_EN (1 << 17)
|
||||
|
||||
#define USBHS_EP2_T_EN (1 << 2)
|
||||
#define USBHS_EP2_R_EN (1 << 18)
|
||||
|
||||
#define USBHS_EP3_T_EN (1 << 3)
|
||||
#define USBHS_EP3_R_EN (1 << 19)
|
||||
|
||||
#define USBHS_EP4_T_EN (1 << 4)
|
||||
#define USBHS_EP4_R_EN (1 << 20)
|
||||
|
||||
#define USBHS_EP5_T_EN (1 << 5)
|
||||
#define USBHS_EP5_R_EN (1 << 21)
|
||||
|
||||
#define USBHS_EP6_T_EN (1 << 6)
|
||||
#define USBHS_EP6_R_EN (1 << 22)
|
||||
|
||||
#define USBHS_EP7_T_EN (1 << 7)
|
||||
#define USBHS_EP7_R_EN (1 << 23)
|
||||
|
||||
#define USBHS_EP8_T_EN (1 << 8)
|
||||
#define USBHS_EP8_R_EN (1 << 24)
|
||||
|
||||
#define USBHS_EP9_T_EN (1 << 9)
|
||||
#define USBHS_EP9_R_EN (1 << 25)
|
||||
|
||||
#define USBHS_EP10_T_EN (1 << 10)
|
||||
#define USBHS_EP10_R_EN (1 << 26)
|
||||
|
||||
#define USBHS_EP11_T_EN (1 << 11)
|
||||
#define USBHS_EP11_R_EN (1 << 27)
|
||||
|
||||
#define USBHS_EP12_T_EN (1 << 12)
|
||||
#define USBHS_EP12_R_EN (1 << 28)
|
||||
|
||||
#define USBHS_EP13_T_EN (1 << 13)
|
||||
#define USBHS_EP13_R_EN (1 << 29)
|
||||
|
||||
#define USBHS_EP14_T_EN (1 << 14)
|
||||
#define USBHS_EP14_R_EN (1 << 30)
|
||||
|
||||
#define USBHS_EP15_T_EN (1 << 15)
|
||||
#define USBHS_EP15_R_EN (1 << 31)
|
||||
|
||||
//UEP_TYPE
|
||||
#define USBHS_UEP_TYPE_OFFSET 0x14
|
||||
#define USBHS_EP0_T_TYP (1 << 0)
|
||||
#define USBHS_EP0_R_TYP (1 << 16)
|
||||
|
||||
#define USBHS_EP1_T_TYP (1 << 1)
|
||||
#define USBHS_EP1_R_TYP (1 << 17)
|
||||
|
||||
#define USBHS_EP2_T_TYP (1 << 2)
|
||||
#define USBHS_EP2_R_TYP (1 << 18)
|
||||
|
||||
#define USBHS_EP3_T_TYP (1 << 3)
|
||||
#define USBHS_EP3_R_TYP (1 << 19)
|
||||
|
||||
#define USBHS_EP4_T_TYP (1 << 4)
|
||||
#define USBHS_EP4_R_TYP (1 << 20)
|
||||
|
||||
#define USBHS_EP5_T_TYP (1 << 5)
|
||||
#define USBHS_EP5_R_TYP (1 << 21)
|
||||
|
||||
#define USBHS_EP6_T_TYP (1 << 6)
|
||||
#define USBHS_EP6_R_TYP (1 << 22)
|
||||
|
||||
#define USBHS_EP7_T_TYP (1 << 7)
|
||||
#define USBHS_EP7_R_TYP (1 << 23)
|
||||
|
||||
#define USBHS_EP8_T_TYP (1 << 8)
|
||||
#define USBHS_EP8_R_TYP (1 << 24)
|
||||
|
||||
#define USBHS_EP9_T_TYP (1 << 8)
|
||||
#define USBHS_EP9_R_TYP (1 << 25)
|
||||
|
||||
#define USBHS_EP10_T_TYP (1 << 10)
|
||||
#define USBHS_EP10_R_TYP (1 << 26)
|
||||
|
||||
#define USBHS_EP11_T_TYP (1 << 11)
|
||||
#define USBHS_EP11_R_TYP (1 << 27)
|
||||
|
||||
#define USBHS_EP12_T_TYP (1 << 12)
|
||||
#define USBHS_EP12_R_TYP (1 << 28)
|
||||
|
||||
#define USBHS_EP13_T_TYP (1 << 13)
|
||||
#define USBHS_EP13_R_TYP (1 << 29)
|
||||
|
||||
#define USBHS_EP14_T_TYP (1 << 14)
|
||||
#define USBHS_EP14_R_TYP (1 << 30)
|
||||
|
||||
#define USBHS_EP15_T_TYP (1 << 15)
|
||||
#define USBHS_EP15_R_TYP (1 << 31)
|
||||
|
||||
/* BUF_MOD UEP1~15 */
|
||||
#define USBHS_BUF_MOD_OFFSET 0x18
|
||||
#define USBHS_EP0_BUF_MOD (1 << 0)
|
||||
#define USBHS_EP0_ISO_BUF_MOD (1 << 16)
|
||||
|
||||
#define USBHS_EP1_BUF_MOD (1 << 1)
|
||||
#define USBHS_EP1_ISO_BUF_MOD (1 << 17)
|
||||
|
||||
#define USBHS_EP2_BUF_MOD (1 << 2)
|
||||
#define USBHS_EP2_ISO_BUF_MOD (1 << 18)
|
||||
|
||||
#define USBHS_EP3_BUF_MOD (1 << 3)
|
||||
#define USBHS_EP3_ISO_BUF_MOD (1 << 19)
|
||||
|
||||
#define USBHS_EP4_BUF_MOD (1 << 4)
|
||||
#define USBHS_EP4_ISO_BUF_MOD (1 << 20)
|
||||
|
||||
#define USBHS_EP5_BUF_MOD (1 << 5)
|
||||
#define USBHS_EP5_ISO_BUF_MOD (1 << 21)
|
||||
|
||||
#define USBHS_EP6_BUF_MOD (1 << 6)
|
||||
#define USBHS_EP6_ISO_BUF_MOD (1 << 22)
|
||||
|
||||
#define USBHS_EP7_BUF_MOD (1 << 7)
|
||||
#define USBHS_EP7_ISO_BUF_MOD (1 << 23)
|
||||
|
||||
#define USBHS_EP8_BUF_MOD (1 << 8)
|
||||
#define USBHS_EP8_ISO_BUF_MOD (1 << 24)
|
||||
|
||||
#define USBHS_EP9_BUF_MOD (1 << 9)
|
||||
#define USBHS_EP9_ISO_BUF_MOD (1 << 25)
|
||||
|
||||
#define USBHS_EP10_BUF_MOD (1 << 10)
|
||||
#define USBHS_EP10_ISO_BUF_MOD (1 << 26)
|
||||
|
||||
#define USBHS_EP11_BUF_MOD (1 << 11)
|
||||
#define USBHS_EP11_ISO_BUF_MOD (1 << 27)
|
||||
|
||||
#define USBHS_EP12_BUF_MOD (1 << 12)
|
||||
#define USBHS_EP12_ISO_BUF_MOD (1 << 28)
|
||||
|
||||
#define USBHS_EP13_BUF_MOD (1 << 13)
|
||||
#define USBHS_EP13_ISO_BUF_MOD (1 << 29)
|
||||
|
||||
#define USBHS_EP14_BUF_MOD (1 << 14)
|
||||
#define USBHS_EP14_ISO_BUF_MOD (1 << 30)
|
||||
|
||||
#define USBHS_EP15_BUF_MOD (1 << 15)
|
||||
#define USBHS_EP15_ISO_BUF_MOD (1 << 31)
|
||||
//USBHS_EPn_T_EN USBHS_EPn_R_EN USBHS_EPn_BUF_MOD 锟斤拷锟斤拷锟斤拷锟斤拷UEPn_DMA为锟斤拷始锟斤拷址锟缴碉拷锟斤拷锟斤拷锟斤拷锟<E68BB7>
|
||||
// 0 0 x 锟剿点被锟斤拷锟矫o拷未锟矫碉拷UEPn_*_DMA锟斤拷锟斤拷锟斤拷锟斤拷
|
||||
// 1 0 0 锟斤拷锟秸o拷OUT锟斤拷锟斤拷锟斤拷锟斤拷锟阶碉拷址为UEPn_RX_DMA
|
||||
// 1 0 1 bUEPn_RX_TOG[0]=0,使锟矫伙拷锟斤拷锟斤拷UEPn_RX_DMA锟斤拷bUEPn_RX_TOG[0]=1,使锟矫伙拷锟斤拷锟斤拷UEPn_TX_DMA
|
||||
// 0 1 0 锟斤拷锟斤拷(IN)锟斤拷锟斤拷锟斤拷锟阶碉拷址为UEPn_TX_DMA锟斤拷
|
||||
// 0 1 1 bUEPn_TX_TOG[0]=0,使锟矫伙拷锟斤拷锟斤拷UEPn_TX_DMA锟斤拷bUEPn_TX_TOG[0]=1,使锟矫伙拷锟斤拷锟斤拷UEPn_RX_DMA
|
||||
|
||||
/* USB0_DMA */
|
||||
#define USBHS_UEP0_DMA_OFFSET(n) (0x1C) // endpoint 0 DMA buffer address
|
||||
|
||||
/* USBX_RX_DMA */
|
||||
#define USBHS_UEPx_RX_DMA_OFFSET(n) (0x1C + 4 * (n)) // endpoint x DMA buffer address
|
||||
|
||||
#define USBHS_UEPx_TX_DMA_OFFSET(n) (0x58 + 4 * (n)) // endpoint x DMA buffer address
|
||||
|
||||
#define USBHS_UEPx_MAX_LEN_OFFSET(n) (0x98 + 4 * (n)) // endpoint x DMA buffer address
|
||||
|
||||
#define USBHS_UEPx_T_LEN_OFFSET(n) (0xD8 + 4 * (n)) // endpoint x DMA buffer address
|
||||
#define USBHS_UEPx_TX_CTRL_OFFSET(n) (0xD8 + 4 * (n) + 2) // endpoint x DMA buffer address
|
||||
#define USBHS_UEPx_RX_CTRL_OFFSET(n) (0xD8 + 4 * (n) + 3) // endpoint x DMA buffer address
|
||||
|
||||
// UEPn_T_LEN
|
||||
#define USBHS_EP_T_LEN_MASK (0x7FF)
|
||||
|
||||
//UEPn_TX_CTRL
|
||||
#define USBHS_EP_T_RES_MASK (3 << 0)
|
||||
#define USBHS_EP_T_RES_ACK (0 << 0)
|
||||
#define USBHS_EP_T_RES_NYET (1 << 0)
|
||||
#define USBHS_EP_T_RES_NAK (2 << 0)
|
||||
#define USBHS_EP_T_RES_STALL (3 << 0)
|
||||
|
||||
#define USBHS_EP_T_TOG_MASK (3 << 3)
|
||||
#define USBHS_EP_T_TOG_0 (0 << 3)
|
||||
#define USBHS_EP_T_TOG_1 (1 << 3)
|
||||
#define USBHS_EP_T_TOG_2 (2 << 3)
|
||||
#define USBHS_EP_T_TOG_M (3 << 3)
|
||||
|
||||
#define USBHS_EP_T_AUTOTOG (1 << 5)
|
||||
|
||||
//UEPn_RX_CTRL
|
||||
#define USBHS_EP_R_RES_MASK (3 << 0)
|
||||
#define USBHS_EP_R_RES_ACK (0 << 0)
|
||||
#define USBHS_EP_R_RES_NYET (1 << 0)
|
||||
#define USBHS_EP_R_RES_NAK (2 << 0)
|
||||
#define USBHS_EP_R_RES_STALL (3 << 0)
|
||||
|
||||
#define USBHS_EP_R_TOG_MASK (3 << 3)
|
||||
#define USBHS_EP_R_TOG_0 (0 << 3)
|
||||
#define USBHS_EP_R_TOG_1 (1 << 3)
|
||||
#define USBHS_EP_R_TOG_2 (2 << 3)
|
||||
#define USBHS_EP_R_TOG_M (3 << 3)
|
||||
|
||||
#define USBHS_EP_R_AUTOTOG (1 << 5)
|
||||
|
||||
#define USBHS_TOG_MATCH (1 << 6)
|
||||
|
||||
/******************* HOST ******************/
|
||||
// USB HOST_CTRL
|
||||
#define USBHS_SEND_BUS_RESET (1 << 0)
|
||||
#define USBHS_SEND_BUS_SUSPEND (1 << 1)
|
||||
#define USBHS_SEND_BUS_RESUME (1 << 2)
|
||||
#define USBHS_REMOTE_WAKE (1 << 3)
|
||||
#define USBHS_PHY_SUSPENDM (1 << 4)
|
||||
#define USBHS_UH_SOFT_FREE (1 << 6)
|
||||
#define USBHS_SEND_SOF_EN (1 << 7)
|
||||
|
||||
//UH_CONFIG
|
||||
#define USBHS_HOST_TX_EN (1 << 3)
|
||||
#define USBHS_HOST_RX_EN (1 << 18)
|
||||
|
||||
// HOST_EP_TYPE
|
||||
#define USBHS_ENDP_TX_ISO (1 << 3)
|
||||
#define USBHS_ENDP_RX_ISO (1 << (16 + 2))
|
||||
|
||||
// R32_UH_EP_PID
|
||||
#define USBHS_HOST_MASK_TOKEN (0x0f)
|
||||
#define USBHS_HOST_MASK_ENDP (0x0f << 4)
|
||||
|
||||
//R8_UH_RX_CTRL
|
||||
#define USBHS_EP_R_RES_MASK (3 << 0)
|
||||
#define USBHS_EP_R_RES_ACK (0 << 0)
|
||||
#define USBHS_EP_R_RES_NYET (1 << 0)
|
||||
#define USBHS_EP_R_RES_NAK (2 << 0)
|
||||
#define USBHS_EP_R_RES_STALL (3 << 0)
|
||||
|
||||
#define USBHS_UH_R_RES_NO (1 << 2)
|
||||
#define USBHS_UH_R_TOG_1 (1 << 3)
|
||||
#define USBHS_UH_R_TOG_2 (2 << 3)
|
||||
#define USBHS_UH_R_TOG_3 (3 << 3)
|
||||
#define USBHS_UH_R_TOG_AUTO (1 << 5)
|
||||
#define USBHS_UH_R_DATA_NO (1 << 6)
|
||||
//R8_UH_TX_CTRL
|
||||
#define USBHS_UH_T_RES_MASK (3 << 0)
|
||||
#define USBHS_UH_T_RES_ACK (0 << 0)
|
||||
#define USBHS_UH_T_RES_NYET (1 << 0)
|
||||
#define USBHS_UH_T_RES_NAK (2 << 0)
|
||||
#define USBHS_UH_T_RES_STALL (3 << 0)
|
||||
|
||||
#define USBHS_UH_T_RES_NO (1 << 2)
|
||||
#define USBHS_UH_T_TOG_1 (1 << 3)
|
||||
#define USBHS_UH_T_TOG_2 (2 << 3)
|
||||
#define USBHS_UH_T_TOG_3 (3 << 3)
|
||||
#define USBHS_UH_T_TOG_AUTO (1 << 5)
|
||||
#define USBHS_UH_T_DATA_NO (1 << 6)
|
||||
|
||||
// 00: OUT, 01:SOF, 10:IN, 11:SETUP
|
||||
#define PID_OUT 0
|
||||
#define PID_SOF 1
|
||||
#define PID_IN 2
|
||||
#define PID_SETUP 3
|
||||
|
||||
#endif
|
@@ -0,0 +1,404 @@
|
||||
/*
|
||||
* Copyright (c) 2022, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usbd_core.h"
|
||||
#include "usb_ch32_usbfs_reg.h"
|
||||
|
||||
#ifdef CONFIG_USB_HS
|
||||
#error "usb fs do not support hs"
|
||||
#endif
|
||||
|
||||
#ifndef USBD_IRQHandler
|
||||
#define USBD_IRQHandler OTG_FS_IRQHandler //use actual usb irq name instead
|
||||
#endif
|
||||
|
||||
#ifndef USB_NUM_BIDIR_ENDPOINTS
|
||||
#define USB_NUM_BIDIR_ENDPOINTS 8
|
||||
#endif
|
||||
|
||||
#define USB_SET_DMA(ep_idx, addr) (*(volatile uint32_t *)((uint32_t)(&USBFS_DEVICE->UEP0_DMA) + 4 * ep_idx) = addr)
|
||||
#define USB_SET_TX_LEN(ep_idx, len) (*(volatile uint16_t *)((uint32_t)(&USBFS_DEVICE->UEP0_TX_LEN) + 4 * ep_idx) = len)
|
||||
#define USB_GET_TX_LEN(ep_idx) (*(volatile uint16_t *)((uint32_t)(&USBFS_DEVICE->UEP0_TX_LEN) + 4 * ep_idx))
|
||||
#define USB_SET_TX_CTRL(ep_idx, val) (*(volatile uint8_t *)((uint32_t)(&USBFS_DEVICE->UEP0_TX_CTRL) + 4 * ep_idx) = val)
|
||||
#define USB_GET_TX_CTRL(ep_idx) (*(volatile uint8_t *)((uint32_t)(&USBFS_DEVICE->UEP0_TX_CTRL) + 4 * ep_idx))
|
||||
#define USB_SET_RX_CTRL(ep_idx, val) (*(volatile uint8_t *)((uint32_t)(&USBFS_DEVICE->UEP0_RX_CTRL) + 4 * ep_idx) = val)
|
||||
#define USB_GET_RX_CTRL(ep_idx) (*(volatile uint8_t *)((uint32_t)(&USBFS_DEVICE->UEP0_RX_CTRL) + 4 * ep_idx))
|
||||
|
||||
/* Endpoint state */
|
||||
struct ch32_usbfs_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 ch32_usbfs_udc {
|
||||
__attribute__((aligned(4))) struct usb_setup_packet setup;
|
||||
volatile uint8_t dev_addr;
|
||||
struct ch32_usbfs_ep_state in_ep[USB_NUM_BIDIR_ENDPOINTS]; /*!< IN endpoint parameters*/
|
||||
struct ch32_usbfs_ep_state out_ep[USB_NUM_BIDIR_ENDPOINTS]; /*!< OUT endpoint parameters */
|
||||
__attribute__((aligned(4))) uint8_t ep_databuf[USB_NUM_BIDIR_ENDPOINTS - 1][64 + 64]; //epx_out(64)+epx_in(64)
|
||||
} g_ch32_usbfs_udc;
|
||||
|
||||
volatile bool ep0_rx_data_toggle;
|
||||
volatile bool ep0_tx_data_toggle;
|
||||
|
||||
void USBD_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
|
||||
|
||||
__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();
|
||||
|
||||
USBFS_DEVICE->BASE_CTRL = 0x00;
|
||||
|
||||
USBFS_DEVICE->UEP4_1_MOD = USBFS_UEP4_RX_EN | USBFS_UEP4_TX_EN | USBFS_UEP1_RX_EN | USBFS_UEP1_TX_EN;
|
||||
USBFS_DEVICE->UEP2_3_MOD = USBFS_UEP2_RX_EN | USBFS_UEP2_TX_EN | USBFS_UEP3_RX_EN | USBFS_UEP3_TX_EN;
|
||||
USBFS_DEVICE->UEP5_6_MOD = USBFS_UEP5_RX_EN | USBFS_UEP5_TX_EN | USBFS_UEP6_RX_EN | USBFS_UEP6_TX_EN;
|
||||
USBFS_DEVICE->UEP7_MOD = USBFS_UEP7_RX_EN | USBFS_UEP7_TX_EN;
|
||||
|
||||
USBFS_DEVICE->UEP1_DMA = (uint32_t)g_ch32_usbfs_udc.ep_databuf[0];
|
||||
USBFS_DEVICE->UEP2_DMA = (uint32_t)g_ch32_usbfs_udc.ep_databuf[1];
|
||||
USBFS_DEVICE->UEP3_DMA = (uint32_t)g_ch32_usbfs_udc.ep_databuf[2];
|
||||
USBFS_DEVICE->UEP4_DMA = (uint32_t)g_ch32_usbfs_udc.ep_databuf[3];
|
||||
USBFS_DEVICE->UEP5_DMA = (uint32_t)g_ch32_usbfs_udc.ep_databuf[4];
|
||||
USBFS_DEVICE->UEP6_DMA = (uint32_t)g_ch32_usbfs_udc.ep_databuf[5];
|
||||
USBFS_DEVICE->UEP7_DMA = (uint32_t)g_ch32_usbfs_udc.ep_databuf[6];
|
||||
|
||||
USBFS_DEVICE->INT_FG = 0xFF;
|
||||
USBFS_DEVICE->INT_EN = USBFS_UIE_SUSPEND | USBFS_UIE_BUS_RST | USBFS_UIE_TRANSFER;
|
||||
USBFS_DEVICE->DEV_ADDR = 0x00;
|
||||
|
||||
USBFS_DEVICE->BASE_CTRL = USBFS_UC_DEV_PU_EN | USBFS_UC_INT_BUSY | USBFS_UC_DMA_EN;
|
||||
USBFS_DEVICE->UDEV_CTRL = USBFS_UD_PD_DIS | USBFS_UD_PORT_EN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_dc_deinit(uint8_t busid)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_set_address(uint8_t busid, const uint8_t addr)
|
||||
{
|
||||
if (addr == 0) {
|
||||
USBFS_DEVICE->DEV_ADDR = (USBFS_DEVICE->DEV_ADDR & USBFS_UDA_GP_BIT) | 0;
|
||||
}
|
||||
g_ch32_usbfs_udc.dev_addr = addr;
|
||||
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);
|
||||
|
||||
if (USB_EP_DIR_IS_OUT(ep->bEndpointAddress)) {
|
||||
g_ch32_usbfs_udc.out_ep[ep_idx].ep_mps = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
|
||||
g_ch32_usbfs_udc.out_ep[ep_idx].ep_type = USB_GET_ENDPOINT_TYPE(ep->bmAttributes);
|
||||
g_ch32_usbfs_udc.out_ep[ep_idx].ep_enable = true;
|
||||
USB_SET_RX_CTRL(ep_idx, USBFS_UEP_R_RES_NAK | USBFS_UEP_AUTO_TOG);
|
||||
} else {
|
||||
g_ch32_usbfs_udc.in_ep[ep_idx].ep_mps = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
|
||||
g_ch32_usbfs_udc.in_ep[ep_idx].ep_type = USB_GET_ENDPOINT_TYPE(ep->bmAttributes);
|
||||
g_ch32_usbfs_udc.in_ep[ep_idx].ep_enable = true;
|
||||
USB_SET_TX_CTRL(ep_idx, USBFS_UEP_T_RES_NAK | USBFS_UEP_AUTO_TOG);
|
||||
}
|
||||
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);
|
||||
|
||||
if (USB_EP_DIR_IS_OUT(ep)) {
|
||||
if (ep_idx == 0) {
|
||||
USBFS_DEVICE->UEP0_RX_CTRL = USBFS_UEP_R_TOG | USBFS_UEP_R_RES_STALL;
|
||||
} else {
|
||||
USB_SET_RX_CTRL(ep_idx, (USB_GET_RX_CTRL(ep_idx) & ~USBFS_UEP_R_RES_MASK) | USBFS_UEP_R_RES_STALL);
|
||||
}
|
||||
} else {
|
||||
if (ep_idx == 0) {
|
||||
USBFS_DEVICE->UEP0_TX_CTRL = USBFS_UEP_T_TOG | USBFS_UEP_T_RES_STALL;
|
||||
} else {
|
||||
USB_SET_TX_CTRL(ep_idx, (USB_GET_TX_CTRL(ep_idx) & ~USBFS_UEP_T_RES_MASK) | USBFS_UEP_T_RES_STALL);
|
||||
}
|
||||
}
|
||||
|
||||
if (ep_idx == 0) {
|
||||
USB_SET_DMA(ep_idx, (uint32_t)&g_ch32_usbfs_udc.setup);
|
||||
USB_SET_RX_CTRL(ep_idx, USBFS_UEP_R_RES_ACK);
|
||||
}
|
||||
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) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (USB_EP_DIR_IS_OUT(ep)) {
|
||||
USB_SET_RX_CTRL(ep_idx, (USB_GET_RX_CTRL(ep_idx) & ~(USBFS_UEP_R_TOG | USBFS_UEP_R_RES_MASK)) | USBFS_UEP_R_RES_ACK);
|
||||
} else {
|
||||
USB_SET_TX_CTRL(ep_idx, (USB_GET_TX_CTRL(ep_idx) & ~(USBFS_UEP_T_TOG | USBFS_UEP_T_RES_MASK)) | USBFS_UEP_T_RES_NAK);
|
||||
}
|
||||
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);
|
||||
|
||||
if (!data && data_len) {
|
||||
return -1;
|
||||
}
|
||||
if (!g_ch32_usbfs_udc.in_ep[ep_idx].ep_enable) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
if ((uint32_t)data & 0x03) {
|
||||
printf("data do not align4\r\n");
|
||||
return -3;
|
||||
}
|
||||
|
||||
g_ch32_usbfs_udc.in_ep[ep_idx].xfer_buf = (uint8_t *)data;
|
||||
g_ch32_usbfs_udc.in_ep[ep_idx].xfer_len = data_len;
|
||||
g_ch32_usbfs_udc.in_ep[ep_idx].actual_xfer_len = 0;
|
||||
|
||||
if (ep_idx == 0) {
|
||||
if (data_len == 0) {
|
||||
USB_SET_TX_LEN(ep_idx, 0);
|
||||
} else {
|
||||
data_len = MIN(data_len, g_ch32_usbfs_udc.in_ep[ep_idx].ep_mps);
|
||||
USB_SET_TX_LEN(ep_idx, data_len);
|
||||
USB_SET_DMA(ep_idx, (uint32_t)data);
|
||||
}
|
||||
if (ep0_tx_data_toggle) {
|
||||
USB_SET_TX_CTRL(ep_idx, USBFS_UEP_T_TOG | USBFS_UEP_T_RES_ACK);
|
||||
} else {
|
||||
USB_SET_TX_CTRL(ep_idx, USBFS_UEP_T_RES_ACK);
|
||||
}
|
||||
|
||||
} else {
|
||||
if (data_len == 0) {
|
||||
USB_SET_TX_LEN(ep_idx, 0);
|
||||
} else {
|
||||
data_len = MIN(data_len, g_ch32_usbfs_udc.in_ep[ep_idx].ep_mps);
|
||||
USB_SET_TX_LEN(ep_idx, data_len);
|
||||
memcpy(&g_ch32_usbfs_udc.ep_databuf[ep_idx - 1][64], data, data_len);
|
||||
}
|
||||
USB_SET_TX_CTRL(ep_idx, (USB_GET_TX_CTRL(ep_idx) & ~USBFS_UEP_T_RES_MASK) | USBFS_UEP_T_RES_ACK);
|
||||
}
|
||||
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_ch32_usbfs_udc.out_ep[ep_idx].ep_enable) {
|
||||
return -2;
|
||||
}
|
||||
if ((uint32_t)data & 0x03) {
|
||||
printf("data do not align4\r\n");
|
||||
return -3;
|
||||
}
|
||||
|
||||
g_ch32_usbfs_udc.out_ep[ep_idx].xfer_buf = (uint8_t *)data;
|
||||
g_ch32_usbfs_udc.out_ep[ep_idx].xfer_len = data_len;
|
||||
g_ch32_usbfs_udc.out_ep[ep_idx].actual_xfer_len = 0;
|
||||
|
||||
if (ep_idx == 0) {
|
||||
if (data_len == 0) {
|
||||
} else {
|
||||
USB_SET_DMA(ep_idx, (uint32_t)data);
|
||||
}
|
||||
if (ep0_rx_data_toggle) {
|
||||
USB_SET_RX_CTRL(ep_idx, USBFS_UEP_R_TOG | USBFS_UEP_R_RES_ACK);
|
||||
} else {
|
||||
USB_SET_RX_CTRL(ep_idx, USBFS_UEP_R_RES_ACK);
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
USB_SET_RX_CTRL(ep_idx, (USB_GET_RX_CTRL(ep_idx) & ~USBFS_UEP_R_RES_MASK) | USBFS_UEP_R_RES_ACK);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void USBD_IRQHandler(void)
|
||||
{
|
||||
uint32_t ep_idx = 0, token, write_count, read_count;
|
||||
uint8_t intflag = 0;
|
||||
|
||||
intflag = USBFS_DEVICE->INT_FG;
|
||||
|
||||
if (intflag & USBFS_UIF_TRANSFER) {
|
||||
token = USBFS_DEVICE->INT_ST & USBFS_UIS_TOKEN_MASK;
|
||||
ep_idx = USBFS_DEVICE->INT_ST & USBFS_UIS_ENDP_MASK;
|
||||
switch (token) {
|
||||
case USBFS_UIS_TOKEN_SETUP:
|
||||
USB_SET_RX_CTRL(ep_idx, USBFS_UEP_R_RES_NAK);
|
||||
usbd_event_ep0_setup_complete_handler(0, (uint8_t *)&g_ch32_usbfs_udc.setup);
|
||||
break;
|
||||
|
||||
case USBFS_UIS_TOKEN_IN:
|
||||
if (ep_idx == 0x00) {
|
||||
if (g_ch32_usbfs_udc.in_ep[ep_idx].xfer_len >= g_ch32_usbfs_udc.in_ep[ep_idx].ep_mps) {
|
||||
g_ch32_usbfs_udc.in_ep[ep_idx].xfer_len -= g_ch32_usbfs_udc.in_ep[ep_idx].ep_mps;
|
||||
g_ch32_usbfs_udc.in_ep[ep_idx].actual_xfer_len += g_ch32_usbfs_udc.in_ep[ep_idx].ep_mps;
|
||||
ep0_tx_data_toggle ^= 1;
|
||||
} else {
|
||||
g_ch32_usbfs_udc.in_ep[ep_idx].actual_xfer_len += g_ch32_usbfs_udc.in_ep[ep_idx].xfer_len;
|
||||
g_ch32_usbfs_udc.in_ep[ep_idx].xfer_len = 0;
|
||||
ep0_tx_data_toggle = true;
|
||||
}
|
||||
|
||||
usbd_event_ep_in_complete_handler(0, ep_idx | 0x80, g_ch32_usbfs_udc.in_ep[ep_idx].actual_xfer_len);
|
||||
|
||||
if (g_ch32_usbfs_udc.dev_addr > 0) {
|
||||
USBFS_DEVICE->DEV_ADDR = (USBFS_DEVICE->DEV_ADDR & USBFS_UDA_GP_BIT) | g_ch32_usbfs_udc.dev_addr;
|
||||
g_ch32_usbfs_udc.dev_addr = 0;
|
||||
}
|
||||
|
||||
if (g_ch32_usbfs_udc.setup.wLength && ((g_ch32_usbfs_udc.setup.bmRequestType & USB_REQUEST_DIR_MASK) == USB_REQUEST_DIR_OUT)) {
|
||||
/* In status, start reading setup */
|
||||
USB_SET_DMA(ep_idx, (uint32_t)&g_ch32_usbfs_udc.setup);
|
||||
USB_SET_RX_CTRL(ep_idx, USBFS_UEP_R_RES_ACK);
|
||||
ep0_tx_data_toggle = true;
|
||||
|
||||
} else if (g_ch32_usbfs_udc.setup.wLength == 0) {
|
||||
/* In status, start reading setup */
|
||||
USB_SET_DMA(ep_idx, (uint32_t)&g_ch32_usbfs_udc.setup);
|
||||
USB_SET_RX_CTRL(ep_idx, USBFS_UEP_R_RES_ACK);
|
||||
ep0_tx_data_toggle = true;
|
||||
}
|
||||
} else {
|
||||
USB_SET_TX_CTRL(ep_idx, (USB_GET_TX_CTRL(ep_idx) & ~USBFS_UEP_T_RES_MASK) | USBFS_UEP_T_RES_NAK);
|
||||
|
||||
if (g_ch32_usbfs_udc.in_ep[ep_idx].xfer_len > g_ch32_usbfs_udc.in_ep[ep_idx].ep_mps) {
|
||||
g_ch32_usbfs_udc.in_ep[ep_idx].xfer_buf += g_ch32_usbfs_udc.in_ep[ep_idx].ep_mps;
|
||||
g_ch32_usbfs_udc.in_ep[ep_idx].xfer_len -= g_ch32_usbfs_udc.in_ep[ep_idx].ep_mps;
|
||||
g_ch32_usbfs_udc.in_ep[ep_idx].actual_xfer_len += g_ch32_usbfs_udc.in_ep[ep_idx].ep_mps;
|
||||
|
||||
write_count = MIN(g_ch32_usbfs_udc.in_ep[ep_idx].xfer_len, g_ch32_usbfs_udc.in_ep[ep_idx].ep_mps);
|
||||
USB_SET_TX_LEN(ep_idx, write_count);
|
||||
memcpy(&g_ch32_usbfs_udc.ep_databuf[ep_idx - 1][64], g_ch32_usbfs_udc.in_ep[ep_idx].xfer_buf, write_count);
|
||||
|
||||
USB_SET_TX_CTRL(ep_idx, (USB_GET_TX_CTRL(ep_idx) & ~USBFS_UEP_T_RES_MASK) | USBFS_UEP_T_RES_ACK);
|
||||
} else {
|
||||
g_ch32_usbfs_udc.in_ep[ep_idx].actual_xfer_len += g_ch32_usbfs_udc.in_ep[ep_idx].xfer_len;
|
||||
g_ch32_usbfs_udc.in_ep[ep_idx].xfer_len = 0;
|
||||
usbd_event_ep_in_complete_handler(0, ep_idx | 0x80, g_ch32_usbfs_udc.in_ep[ep_idx].actual_xfer_len);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case USBFS_UIS_TOKEN_OUT:
|
||||
if (ep_idx == 0x00) {
|
||||
USB_SET_RX_CTRL(ep_idx, USBFS_UEP_R_RES_NAK);
|
||||
|
||||
read_count = USBFS_DEVICE->RX_LEN;
|
||||
|
||||
g_ch32_usbfs_udc.out_ep[ep_idx].actual_xfer_len += read_count;
|
||||
g_ch32_usbfs_udc.out_ep[ep_idx].xfer_len -= read_count;
|
||||
|
||||
usbd_event_ep_out_complete_handler(0, 0x00, g_ch32_usbfs_udc.out_ep[ep_idx].actual_xfer_len);
|
||||
|
||||
if (read_count == 0) {
|
||||
/* Out status, start reading setup */
|
||||
USB_SET_DMA(ep_idx, (uint32_t)&g_ch32_usbfs_udc.setup);
|
||||
USB_SET_RX_CTRL(ep_idx, USBFS_UEP_R_RES_ACK);
|
||||
ep0_rx_data_toggle = true;
|
||||
ep0_tx_data_toggle = true;
|
||||
} else {
|
||||
ep0_rx_data_toggle ^= 1;
|
||||
}
|
||||
} else {
|
||||
if (USBFS_DEVICE->INT_ST & USBFS_UIS_TOG_OK) {
|
||||
USB_SET_RX_CTRL(ep_idx, (USB_GET_RX_CTRL(ep_idx) & ~USBFS_UEP_R_RES_MASK) | USBFS_UEP_R_RES_NAK);
|
||||
read_count = USBFS_DEVICE->RX_LEN;
|
||||
|
||||
memcpy(g_ch32_usbfs_udc.out_ep[ep_idx].xfer_buf, &g_ch32_usbfs_udc.ep_databuf[ep_idx - 1][0], read_count);
|
||||
|
||||
g_ch32_usbfs_udc.out_ep[ep_idx].xfer_buf += read_count;
|
||||
g_ch32_usbfs_udc.out_ep[ep_idx].actual_xfer_len += read_count;
|
||||
g_ch32_usbfs_udc.out_ep[ep_idx].xfer_len -= read_count;
|
||||
|
||||
if ((read_count < g_ch32_usbfs_udc.out_ep[ep_idx].ep_mps) || (g_ch32_usbfs_udc.out_ep[ep_idx].xfer_len == 0)) {
|
||||
usbd_event_ep_out_complete_handler(0, ep_idx, g_ch32_usbfs_udc.out_ep[ep_idx].actual_xfer_len);
|
||||
} else {
|
||||
USB_SET_RX_CTRL(ep_idx, (USB_GET_RX_CTRL(ep_idx) & ~USBFS_UEP_R_RES_MASK) | USBFS_UEP_R_RES_ACK);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case USBFS_UIS_TOKEN_SOF:
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
USBFS_DEVICE->INT_FG = USBFS_UIF_TRANSFER;
|
||||
} else if (intflag & USBFS_UIF_BUS_RST) {
|
||||
USBFS_DEVICE->UEP0_TX_LEN = 0;
|
||||
USBFS_DEVICE->UEP0_TX_CTRL = USBFS_UEP_T_RES_NAK;
|
||||
USBFS_DEVICE->UEP0_RX_CTRL = USBFS_UEP_R_RES_NAK;
|
||||
|
||||
for (uint8_t ep_idx = 1; ep_idx < USB_NUM_BIDIR_ENDPOINTS; ep_idx++) {
|
||||
USB_SET_TX_LEN(ep_idx, 0);
|
||||
USB_SET_TX_CTRL(ep_idx, USBFS_UEP_T_RES_NAK | USBFS_UEP_AUTO_TOG);
|
||||
USB_SET_RX_CTRL(ep_idx, USBFS_UEP_R_RES_NAK | USBFS_UEP_AUTO_TOG);
|
||||
}
|
||||
|
||||
ep0_tx_data_toggle = true;
|
||||
ep0_rx_data_toggle = true;
|
||||
|
||||
memset(&g_ch32_usbfs_udc, 0, sizeof(struct ch32_usbfs_udc));
|
||||
usbd_event_reset_handler(0);
|
||||
USB_SET_DMA(ep_idx, (uint32_t)&g_ch32_usbfs_udc.setup);
|
||||
USB_SET_RX_CTRL(ep_idx, USBFS_UEP_R_RES_ACK);
|
||||
|
||||
USBFS_DEVICE->INT_FG |= USBFS_UIF_BUS_RST;
|
||||
} else if (intflag & USBFS_UIF_SUSPEND) {
|
||||
if (USBFS_DEVICE->MIS_ST & USBFS_UMS_SUSPEND) {
|
||||
} else {
|
||||
}
|
||||
USBFS_DEVICE->INT_FG = USBFS_UIF_SUSPEND;
|
||||
} else {
|
||||
USBFS_DEVICE->INT_FG = intflag;
|
||||
}
|
||||
}
|
@@ -0,0 +1,382 @@
|
||||
/*
|
||||
* Copyright (c) 2022, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usbd_core.h"
|
||||
#include "usb_ch32_usbhs_reg.h"
|
||||
|
||||
#ifndef USBD_IRQHandler
|
||||
#define USBD_IRQHandler USBHS_IRQHandler //use actual usb irq name instead
|
||||
#endif
|
||||
|
||||
#ifndef USB_NUM_BIDIR_ENDPOINTS
|
||||
#define USB_NUM_BIDIR_ENDPOINTS 16
|
||||
#endif
|
||||
|
||||
#define USB_SET_RX_DMA(ep_idx, addr) (*(volatile uint32_t *)((uint32_t)(&USBHS_DEVICE->UEP1_RX_DMA) + 4 * (ep_idx - 1)) = addr)
|
||||
#define USB_SET_TX_DMA(ep_idx, addr) (*(volatile uint32_t *)((uint32_t)(&USBHS_DEVICE->UEP1_TX_DMA) + 4 * (ep_idx - 1)) = addr)
|
||||
#define USB_SET_MAX_LEN(ep_idx, len) (*(volatile uint16_t *)((uint32_t)(&USBHS_DEVICE->UEP0_MAX_LEN) + 4 * ep_idx) = len)
|
||||
#define USB_SET_TX_LEN(ep_idx, len) (*(volatile uint16_t *)((uint32_t)(&USBHS_DEVICE->UEP0_TX_LEN) + 4 * ep_idx) = len)
|
||||
#define USB_GET_TX_LEN(ep_idx) (*(volatile uint16_t *)((uint32_t)(&USBHS_DEVICE->UEP0_TX_LEN) + 4 * ep_idx))
|
||||
#define USB_SET_TX_CTRL(ep_idx, val) (*(volatile uint8_t *)((uint32_t)(&USBHS_DEVICE->UEP0_TX_CTRL) + 4 * ep_idx) = val)
|
||||
#define USB_GET_TX_CTRL(ep_idx) (*(volatile uint8_t *)((uint32_t)(&USBHS_DEVICE->UEP0_TX_CTRL) + 4 * ep_idx))
|
||||
#define USB_SET_RX_CTRL(ep_idx, val) (*(volatile uint8_t *)((uint32_t)(&USBHS_DEVICE->UEP0_RX_CTRL) + 4 * ep_idx) = val)
|
||||
#define USB_GET_RX_CTRL(ep_idx) (*(volatile uint8_t *)((uint32_t)(&USBHS_DEVICE->UEP0_RX_CTRL) + 4 * ep_idx))
|
||||
|
||||
/* Endpoint state */
|
||||
struct ch32_usbhs_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 ch32_usbhs_udc {
|
||||
__attribute__((aligned(4))) struct usb_setup_packet setup;
|
||||
volatile uint8_t dev_addr;
|
||||
struct ch32_usbhs_ep_state in_ep[USB_NUM_BIDIR_ENDPOINTS]; /*!< IN endpoint parameters*/
|
||||
struct ch32_usbhs_ep_state out_ep[USB_NUM_BIDIR_ENDPOINTS]; /*!< OUT endpoint parameters */
|
||||
} g_ch32_usbhs_udc;
|
||||
|
||||
void USBHS_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
|
||||
|
||||
volatile uint8_t mps_over_flag = 0;
|
||||
volatile bool ep0_rx_data_toggle;
|
||||
volatile bool ep0_tx_data_toggle;
|
||||
volatile bool epx_tx_data_toggle[USB_NUM_BIDIR_ENDPOINTS - 1];
|
||||
|
||||
__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();
|
||||
|
||||
USBHS_DEVICE->HOST_CTRL = 0x00;
|
||||
USBHS_DEVICE->HOST_CTRL = USBHS_PHY_SUSPENDM;
|
||||
|
||||
USBHS_DEVICE->CONTROL = 0;
|
||||
#ifdef CONFIG_USB_HS
|
||||
USBHS_DEVICE->CONTROL = USBHS_DMA_EN | USBHS_INT_BUSY_EN | USBHS_HIGH_SPEED;
|
||||
#else
|
||||
USBHS_DEVICE->CONTROL = USBHS_DMA_EN | USBHS_INT_BUSY_EN | USBHS_FULL_SPEED;
|
||||
#endif
|
||||
|
||||
USBHS_DEVICE->INT_FG = 0xff;
|
||||
USBHS_DEVICE->INT_EN = 0;
|
||||
USBHS_DEVICE->INT_EN = USBHS_SETUP_ACT_EN | USBHS_TRANSFER_EN | USBHS_DETECT_EN;
|
||||
|
||||
/* ALL endpoint enable */
|
||||
USBHS_DEVICE->ENDP_CONFIG = 0xffffffff;
|
||||
|
||||
USBHS_DEVICE->ENDP_TYPE = 0x00;
|
||||
USBHS_DEVICE->BUF_MODE = 0x00;
|
||||
|
||||
USBHS_DEVICE->CONTROL |= USBHS_DEV_PU_EN;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_dc_deinit(uint8_t busid)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_set_address(uint8_t busid, const uint8_t addr)
|
||||
{
|
||||
if (addr == 0) {
|
||||
USBHS_DEVICE->DEV_AD = addr & 0xff;
|
||||
}
|
||||
g_ch32_usbhs_udc.dev_addr = addr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t usbd_get_port_speed(uint8_t busid)
|
||||
{
|
||||
return USB_SPEED_HIGH;
|
||||
}
|
||||
|
||||
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_ch32_usbhs_udc.out_ep[ep_idx].ep_mps = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
|
||||
g_ch32_usbhs_udc.out_ep[ep_idx].ep_type = USB_GET_ENDPOINT_TYPE(ep->bmAttributes);
|
||||
g_ch32_usbhs_udc.out_ep[ep_idx].ep_enable = true;
|
||||
USBHS_DEVICE->ENDP_CONFIG |= (1 << (ep_idx + 16));
|
||||
USB_SET_RX_CTRL(ep_idx, USBHS_EP_R_RES_NAK | USBHS_EP_R_TOG_0 | USBHS_EP_R_AUTOTOG);
|
||||
} else {
|
||||
g_ch32_usbhs_udc.in_ep[ep_idx].ep_mps = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
|
||||
g_ch32_usbhs_udc.in_ep[ep_idx].ep_type = USB_GET_ENDPOINT_TYPE(ep->bmAttributes);
|
||||
g_ch32_usbhs_udc.in_ep[ep_idx].ep_enable = true;
|
||||
USBHS_DEVICE->ENDP_CONFIG |= (1 << (ep_idx));
|
||||
USB_SET_TX_CTRL(ep_idx, USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0 | USBHS_EP_T_AUTOTOG);
|
||||
}
|
||||
USB_SET_MAX_LEN(ep_idx, USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize));
|
||||
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);
|
||||
|
||||
if (USB_EP_DIR_IS_OUT(ep)) {
|
||||
if (ep_idx == 0) {
|
||||
USBHS_DEVICE->UEP0_RX_CTRL = USBHS_EP_R_RES_STALL;
|
||||
} else {
|
||||
USB_SET_RX_CTRL(ep_idx, (USB_GET_RX_CTRL(ep_idx) & ~USBHS_EP_R_RES_MASK) | USBHS_EP_R_RES_STALL);
|
||||
}
|
||||
} else {
|
||||
if (ep_idx == 0) {
|
||||
USBHS_DEVICE->UEP0_TX_CTRL = USBHS_EP_T_RES_STALL;
|
||||
} else {
|
||||
USB_SET_TX_CTRL(ep_idx, (USB_GET_TX_CTRL(ep_idx) & ~USBHS_EP_T_RES_MASK) | USBHS_EP_T_RES_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)) {
|
||||
USB_SET_RX_CTRL(ep_idx, USBHS_EP_R_RES_ACK | USBHS_EP_R_TOG_0);
|
||||
} else {
|
||||
USB_SET_TX_CTRL(ep_idx, USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0);
|
||||
}
|
||||
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;
|
||||
}
|
||||
if (!g_ch32_usbhs_udc.in_ep[ep_idx].ep_enable) {
|
||||
return -2;
|
||||
}
|
||||
if ((uint32_t)data & 0x03) {
|
||||
return -3;
|
||||
}
|
||||
|
||||
g_ch32_usbhs_udc.in_ep[ep_idx].xfer_buf = (uint8_t *)data;
|
||||
g_ch32_usbhs_udc.in_ep[ep_idx].xfer_len = data_len;
|
||||
g_ch32_usbhs_udc.in_ep[ep_idx].actual_xfer_len = 0;
|
||||
|
||||
if (ep_idx == 0) {
|
||||
if (data_len == 0) {
|
||||
USB_SET_TX_LEN(ep_idx, 0);
|
||||
} else {
|
||||
data_len = MIN(data_len, g_ch32_usbhs_udc.in_ep[ep_idx].ep_mps);
|
||||
USB_SET_TX_LEN(ep_idx, data_len);
|
||||
USBHS_DEVICE->UEP0_DMA = (uint32_t)data;
|
||||
}
|
||||
tmp = ep0_tx_data_toggle ? USBHS_EP_T_TOG_1 : USBHS_EP_T_TOG_0;
|
||||
USBHS_DEVICE->UEP0_TX_CTRL = USBHS_EP_T_RES_ACK | tmp;
|
||||
} else {
|
||||
if (data_len == 0) {
|
||||
USB_SET_TX_LEN(ep_idx, 0);
|
||||
} else {
|
||||
data_len = MIN(data_len, g_ch32_usbhs_udc.in_ep[ep_idx].ep_mps);
|
||||
USB_SET_TX_LEN(ep_idx, data_len);
|
||||
USB_SET_TX_DMA(ep_idx, (uint32_t)data);
|
||||
}
|
||||
tmp = USB_GET_TX_CTRL(ep_idx);
|
||||
tmp &= ~(USBHS_EP_T_RES_MASK | USBHS_EP_T_TOG_MASK);
|
||||
tmp |= USBHS_EP_T_RES_ACK;
|
||||
tmp |= (epx_tx_data_toggle[ep_idx - 1] ? USBHS_EP_T_TOG_1 : USBHS_EP_T_TOG_0);
|
||||
USB_SET_TX_CTRL(ep_idx, tmp);
|
||||
}
|
||||
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_ch32_usbhs_udc.out_ep[ep_idx].ep_enable) {
|
||||
return -2;
|
||||
}
|
||||
if ((uint32_t)data & 0x03) {
|
||||
return -3;
|
||||
}
|
||||
|
||||
g_ch32_usbhs_udc.out_ep[ep_idx].xfer_buf = (uint8_t *)data;
|
||||
g_ch32_usbhs_udc.out_ep[ep_idx].xfer_len = data_len;
|
||||
g_ch32_usbhs_udc.out_ep[ep_idx].actual_xfer_len = 0;
|
||||
|
||||
if (ep_idx == 0) {
|
||||
if (data_len == 0) {
|
||||
USBHS_DEVICE->UEP0_RX_CTRL = USBHS_EP_R_RES_ACK | USBHS_EP_R_TOG_1;
|
||||
} else {
|
||||
USBHS_DEVICE->UEP0_DMA = (uint32_t)data;
|
||||
USBHS_DEVICE->UEP0_RX_CTRL = USBHS_EP_R_RES_ACK | (ep0_rx_data_toggle ? USBHS_EP_R_TOG_1 : USBHS_EP_R_TOG_0);
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
USB_SET_RX_DMA(ep_idx, (uint32_t)data);
|
||||
USB_SET_RX_CTRL(ep_idx, (USB_GET_RX_CTRL(ep_idx) & ~USBHS_EP_R_RES_MASK) | USBHS_EP_R_RES_ACK);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void USBD_IRQHandler(void)
|
||||
{
|
||||
uint32_t ep_idx, token, write_count, read_count;
|
||||
uint8_t intflag = 0;
|
||||
|
||||
intflag = USBHS_DEVICE->INT_FG;
|
||||
|
||||
if (intflag & USBHS_TRANSFER_FLAG) {
|
||||
ep_idx = (USBHS_DEVICE->INT_ST) & MASK_UIS_ENDP;
|
||||
token = (((USBHS_DEVICE->INT_ST) & MASK_UIS_TOKEN) >> 4) & 0x03;
|
||||
|
||||
if (token == PID_IN) {
|
||||
if (ep_idx == 0x00) {
|
||||
if (g_ch32_usbhs_udc.in_ep[ep_idx].xfer_len >= g_ch32_usbhs_udc.in_ep[ep_idx].ep_mps) {
|
||||
g_ch32_usbhs_udc.in_ep[ep_idx].xfer_len -= g_ch32_usbhs_udc.in_ep[ep_idx].ep_mps;
|
||||
g_ch32_usbhs_udc.in_ep[ep_idx].actual_xfer_len += g_ch32_usbhs_udc.in_ep[ep_idx].ep_mps;
|
||||
ep0_tx_data_toggle ^= 1;
|
||||
} else {
|
||||
g_ch32_usbhs_udc.in_ep[ep_idx].actual_xfer_len += g_ch32_usbhs_udc.in_ep[ep_idx].xfer_len;
|
||||
g_ch32_usbhs_udc.in_ep[ep_idx].xfer_len = 0;
|
||||
ep0_tx_data_toggle = true;
|
||||
}
|
||||
|
||||
usbd_event_ep_in_complete_handler(0, ep_idx | 0x80, g_ch32_usbhs_udc.in_ep[ep_idx].actual_xfer_len);
|
||||
|
||||
if (g_ch32_usbhs_udc.dev_addr > 0) {
|
||||
USBHS_DEVICE->DEV_AD = g_ch32_usbhs_udc.dev_addr & 0xff;
|
||||
g_ch32_usbhs_udc.dev_addr = 0;
|
||||
}
|
||||
|
||||
if (g_ch32_usbhs_udc.setup.wLength && ((g_ch32_usbhs_udc.setup.bmRequestType & USB_REQUEST_DIR_MASK) == USB_REQUEST_DIR_OUT)) {
|
||||
/* In status, start reading setup */
|
||||
USBHS_DEVICE->UEP0_DMA = (uint32_t)&g_ch32_usbhs_udc.setup;
|
||||
USBHS_DEVICE->UEP0_RX_CTRL = USBHS_EP_R_RES_ACK;
|
||||
ep0_tx_data_toggle = true;
|
||||
|
||||
} else if (g_ch32_usbhs_udc.setup.wLength == 0) {
|
||||
/* In status, start reading setup */
|
||||
USBHS_DEVICE->UEP0_DMA = (uint32_t)&g_ch32_usbhs_udc.setup;
|
||||
USBHS_DEVICE->UEP0_RX_CTRL = USBHS_EP_R_RES_ACK;
|
||||
ep0_tx_data_toggle = true;
|
||||
}
|
||||
} else {
|
||||
USB_SET_TX_CTRL(ep_idx, (USB_GET_TX_CTRL(ep_idx) & ~(USBHS_EP_T_RES_MASK | USBHS_EP_T_TOG_MASK)) | USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0);
|
||||
|
||||
if (g_ch32_usbhs_udc.in_ep[ep_idx].xfer_len > g_ch32_usbhs_udc.in_ep[ep_idx].ep_mps) {
|
||||
g_ch32_usbhs_udc.in_ep[ep_idx].xfer_buf += g_ch32_usbhs_udc.in_ep[ep_idx].ep_mps;
|
||||
g_ch32_usbhs_udc.in_ep[ep_idx].xfer_len -= g_ch32_usbhs_udc.in_ep[ep_idx].ep_mps;
|
||||
g_ch32_usbhs_udc.in_ep[ep_idx].actual_xfer_len += g_ch32_usbhs_udc.in_ep[ep_idx].ep_mps;
|
||||
epx_tx_data_toggle[ep_idx - 1] ^= 1;
|
||||
|
||||
write_count = MIN(g_ch32_usbhs_udc.in_ep[ep_idx].xfer_len, g_ch32_usbhs_udc.in_ep[ep_idx].ep_mps);
|
||||
USB_SET_TX_LEN(ep_idx, write_count);
|
||||
USB_SET_TX_DMA(ep_idx, (uint32_t)g_ch32_usbhs_udc.in_ep[ep_idx].xfer_buf);
|
||||
|
||||
uint32_t tmp = USB_GET_TX_CTRL(ep_idx);
|
||||
tmp &= ~(USBHS_EP_T_RES_MASK | USBHS_EP_T_TOG_MASK);
|
||||
tmp |= USBHS_EP_T_RES_ACK;
|
||||
tmp |= (epx_tx_data_toggle[ep_idx - 1] ? USBHS_EP_T_TOG_1 : USBHS_EP_T_TOG_0);
|
||||
USB_SET_TX_CTRL(ep_idx, tmp);
|
||||
} else {
|
||||
g_ch32_usbhs_udc.in_ep[ep_idx].actual_xfer_len += g_ch32_usbhs_udc.in_ep[ep_idx].xfer_len;
|
||||
g_ch32_usbhs_udc.in_ep[ep_idx].xfer_len = 0;
|
||||
epx_tx_data_toggle[ep_idx - 1] ^= 1;
|
||||
usbd_event_ep_in_complete_handler(0, ep_idx | 0x80, g_ch32_usbhs_udc.in_ep[ep_idx].actual_xfer_len);
|
||||
}
|
||||
}
|
||||
} else if (token == PID_OUT) {
|
||||
if (ep_idx == 0x00) {
|
||||
read_count = USBHS_DEVICE->RX_LEN;
|
||||
|
||||
g_ch32_usbhs_udc.out_ep[ep_idx].actual_xfer_len += read_count;
|
||||
g_ch32_usbhs_udc.out_ep[ep_idx].xfer_len -= read_count;
|
||||
|
||||
usbd_event_ep_out_complete_handler(0, 0x00, g_ch32_usbhs_udc.out_ep[ep_idx].actual_xfer_len);
|
||||
|
||||
if (read_count == 0) {
|
||||
/* Out status, start reading setup */
|
||||
USBHS_DEVICE->UEP0_DMA = (uint32_t)&g_ch32_usbhs_udc.setup;
|
||||
USBHS_DEVICE->UEP0_RX_CTRL = USBHS_EP_R_RES_ACK;
|
||||
ep0_rx_data_toggle = true;
|
||||
ep0_tx_data_toggle = true;
|
||||
} else {
|
||||
ep0_rx_data_toggle ^= 1;
|
||||
}
|
||||
} else {
|
||||
if (USBHS_DEVICE->INT_ST & USBHS_DEV_UIS_TOG_OK) {
|
||||
USB_SET_RX_CTRL(ep_idx, (USB_GET_RX_CTRL(ep_idx) & ~USBHS_EP_R_RES_MASK) | USBHS_EP_R_RES_NAK);
|
||||
read_count = USBHS_DEVICE->RX_LEN;
|
||||
|
||||
g_ch32_usbhs_udc.out_ep[ep_idx].xfer_buf += read_count;
|
||||
g_ch32_usbhs_udc.out_ep[ep_idx].actual_xfer_len += read_count;
|
||||
g_ch32_usbhs_udc.out_ep[ep_idx].xfer_len -= read_count;
|
||||
|
||||
if ((read_count < g_ch32_usbhs_udc.out_ep[ep_idx].ep_mps) || (g_ch32_usbhs_udc.out_ep[ep_idx].xfer_len == 0)) {
|
||||
usbd_event_ep_out_complete_handler(0, ep_idx, g_ch32_usbhs_udc.out_ep[ep_idx].actual_xfer_len);
|
||||
} else {
|
||||
USB_SET_RX_DMA(ep_idx, (uint32_t)g_ch32_usbhs_udc.out_ep[ep_idx].xfer_buf);
|
||||
USB_SET_RX_CTRL(ep_idx, (USB_GET_RX_CTRL(ep_idx) & ~USBHS_EP_R_RES_MASK) | USBHS_EP_R_RES_ACK);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
USBHS_DEVICE->INT_FG = USBHS_TRANSFER_FLAG;
|
||||
} else if (intflag & USBHS_SETUP_FLAG) {
|
||||
usbd_event_ep0_setup_complete_handler(0, (uint8_t *)&g_ch32_usbhs_udc.setup);
|
||||
USBHS_DEVICE->INT_FG = USBHS_SETUP_FLAG;
|
||||
} else if (intflag & USBHS_DETECT_FLAG) {
|
||||
USBHS_DEVICE->ENDP_CONFIG = USBHS_EP0_T_EN | USBHS_EP0_R_EN;
|
||||
|
||||
USBHS_DEVICE->UEP0_TX_LEN = 0;
|
||||
USBHS_DEVICE->UEP0_TX_CTRL = USBHS_EP_T_RES_NAK;
|
||||
|
||||
ep0_tx_data_toggle = true;
|
||||
ep0_rx_data_toggle = true;
|
||||
|
||||
for (uint8_t ep_idx = 1; ep_idx < USB_NUM_BIDIR_ENDPOINTS; ep_idx++) {
|
||||
USB_SET_TX_LEN(ep_idx, 0);
|
||||
USB_SET_TX_CTRL(ep_idx, USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK); // autotog does not work
|
||||
USB_SET_RX_CTRL(ep_idx, USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK);
|
||||
epx_tx_data_toggle[ep_idx - 1] = false;
|
||||
}
|
||||
|
||||
memset(&g_ch32_usbhs_udc, 0, sizeof(struct ch32_usbhs_udc));
|
||||
usbd_event_reset_handler(0);
|
||||
USBHS_DEVICE->UEP0_DMA = (uint32_t)&g_ch32_usbhs_udc.setup;
|
||||
USBHS_DEVICE->UEP0_RX_CTRL = USBHS_EP_R_RES_ACK;
|
||||
USBHS_DEVICE->INT_FG = USBHS_DETECT_FLAG;
|
||||
}
|
||||
}
|
@@ -0,0 +1,39 @@
|
||||
# Note
|
||||
|
||||
## Support Chip List
|
||||
|
||||
## STM32
|
||||
|
||||
- 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
|
||||
- STM32MPxx
|
||||
|
||||
## AT32
|
||||
|
||||
- AT32F402xx、AT32F405xx、AT32F415xx、AT32F423xx、AT32F425xx、AT32F435xx、AT32F437xx
|
||||
|
||||
## GD32
|
||||
|
||||
- GD32F30X_CL
|
||||
- GD32F405、GD32F407
|
||||
- GD32F450
|
||||
|
||||
## HC32
|
||||
|
||||
- HC32F4A0
|
||||
|
||||
## Espressif
|
||||
|
||||
- ESP32S2、ESP32S3
|
||||
|
||||
## Sophgo
|
||||
|
||||
- CV18xx
|
||||
|
||||
## Kendryte
|
||||
|
||||
- K230
|
1191
rt-thread/components/drivers/usb/cherryusb/port/dwc2/usb_dc_dwc2.c
Normal file
1191
rt-thread/components/drivers/usb/cherryusb/port/dwc2/usb_dc_dwc2.c
Normal file
File diff suppressed because it is too large
Load Diff
1721
rt-thread/components/drivers/usb/cherryusb/port/dwc2/usb_dwc2_reg.h
Normal file
1721
rt-thread/components/drivers/usb/cherryusb/port/dwc2/usb_dwc2_reg.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2024, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usb_config.h"
|
||||
#include "stdint.h"
|
||||
#include "usb_dwc2_reg.h"
|
||||
|
||||
/* you can find this config in function: usb_global_init, file:at32fxxx_usb.c, for example:
|
||||
*
|
||||
* usbx->gccfg_bit.pwrdown = TRUE;
|
||||
* usbx->gccfg_bit.avalidsesen = TRUE;
|
||||
* usbx->gccfg_bit.bvalidsesen = TRUE;
|
||||
*
|
||||
*/
|
||||
|
||||
uint32_t usbd_get_dwc2_gccfg_conf(uint32_t reg_base)
|
||||
{
|
||||
#ifdef CONFIG_USB_HS
|
||||
return ((1 << 16) | (1 << 21));
|
||||
#else
|
||||
// AT32F415
|
||||
#if defined(AT32F415RCT7) || defined(AT32F415RCT7_7) || defined(AT32F415CCT7) || \
|
||||
defined(AT32F415CCU7) || defined(AT32F415KCU7_4) || defined(AT32F415RBT7) || \
|
||||
defined(AT32F415RBT7_7) || defined(AT32F415CBT7) || defined(AT32F415CBU7) || \
|
||||
defined(AT32F415KBU7_4) || defined(AT32F415R8T7) || defined(AT32F415R8T7_7) || \
|
||||
defined(AT32F415C8T7) || defined(AT32F415K8U7_4)
|
||||
return ((1 << 16) | (1 << 18) | (1 << 19) | (1 << 21));
|
||||
#else
|
||||
return ((1 << 16) | (1 << 21));
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t usbh_get_dwc2_gccfg_conf(uint32_t reg_base)
|
||||
{
|
||||
#ifdef CONFIG_USB_HS
|
||||
return ((1 << 16) | (1 << 21));
|
||||
#else
|
||||
// AT32F415
|
||||
#if defined(AT32F415RCT7) || defined(AT32F415RCT7_7) || defined(AT32F415CCT7) || \
|
||||
defined(AT32F415CCU7) || defined(AT32F415KCU7_4) || defined(AT32F415RBT7) || \
|
||||
defined(AT32F415RBT7_7) || defined(AT32F415CBT7) || defined(AT32F415CBU7) || \
|
||||
defined(AT32F415KBU7_4) || defined(AT32F415R8T7) || defined(AT32F415R8T7_7) || \
|
||||
defined(AT32F415C8T7) || defined(AT32F415K8U7_4)
|
||||
return ((1 << 16) | (1 << 18) | (1 << 19) | (1 << 21));
|
||||
#else
|
||||
return ((1 << 16) | (1 << 21));
|
||||
#endif
|
||||
#endif
|
||||
}
|
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* 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 "usbd_core.h"
|
||||
#include "usbh_core.h"
|
||||
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32S2
|
||||
#define DEFAULT_CPU_FREQ_MHZ CONFIG_ESP32S2_DEFAULT_CPU_FREQ_MHZ
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||
#define DEFAULT_CPU_FREQ_MHZ CONFIG_ESP32S3_DEFAULT_CPU_FREQ_MHZ
|
||||
#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 = NULL;
|
||||
static intr_handle_t s_interrupt_handle = NULL;
|
||||
|
||||
static void usb_dc_interrupt_cb(void *arg_pv)
|
||||
{
|
||||
extern void USBD_IRQHandler(uint8_t busid);
|
||||
USBD_IRQHandler(0);
|
||||
}
|
||||
|
||||
void usb_dc_low_level_init(void)
|
||||
{
|
||||
usb_phy_config_t phy_config = {
|
||||
.controller = USB_PHY_CTRL_OTG,
|
||||
.otg_mode = USB_OTG_MODE_DEVICE,
|
||||
.target = USB_PHY_TARGET_INT,
|
||||
};
|
||||
|
||||
esp_err_t ret = usb_new_phy(&phy_config, &s_phy_handle);
|
||||
if (ret != ESP_OK) {
|
||||
USB_LOG_ERR("USB Phy Init Failed!\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Check when to enable interrupt
|
||||
ret = esp_intr_alloc(ETS_USB_INTR_SOURCE, ESP_INTR_FLAG_LEVEL2, usb_dc_interrupt_cb, 0, &s_interrupt_handle);
|
||||
if (ret != ESP_OK) {
|
||||
USB_LOG_ERR("USB Interrupt Init Failed!\r\n");
|
||||
return;
|
||||
}
|
||||
USB_LOG_INFO("cherryusb, version: 0x%06x\r\n", CHERRYUSB_VERSION);
|
||||
}
|
||||
|
||||
void usb_dc_low_level_deinit(void)
|
||||
{
|
||||
if (s_interrupt_handle) {
|
||||
esp_intr_free(s_interrupt_handle);
|
||||
s_interrupt_handle = NULL;
|
||||
}
|
||||
if (s_phy_handle) {
|
||||
usb_del_phy(s_phy_handle);
|
||||
s_phy_handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t usbd_get_dwc2_gccfg_conf(uint32_t reg_base)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void usb_hc_interrupt_cb(void *arg_pv)
|
||||
{
|
||||
extern void USBH_IRQHandler(uint8_t busid);
|
||||
USBH_IRQHandler(0);
|
||||
}
|
||||
|
||||
void usb_hc_low_level_init(struct usbh_bus *bus)
|
||||
{
|
||||
// Host Library defaults to internal PHY
|
||||
usb_phy_config_t phy_config = {
|
||||
.controller = USB_PHY_CTRL_OTG,
|
||||
.target = USB_PHY_TARGET_INT,
|
||||
.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,
|
||||
};
|
||||
|
||||
esp_err_t ret = usb_new_phy(&phy_config, &s_phy_handle);
|
||||
if (ret != ESP_OK) {
|
||||
USB_LOG_ERR("USB Phy Init Failed!\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Check when to enable interrupt
|
||||
ret = esp_intr_alloc(ETS_USB_INTR_SOURCE, ESP_INTR_FLAG_LEVEL2, usb_hc_interrupt_cb, 0, &s_interrupt_handle);
|
||||
if (ret != ESP_OK) {
|
||||
USB_LOG_ERR("USB Interrupt Init Failed!\r\n");
|
||||
return;
|
||||
}
|
||||
USB_LOG_INFO("cherryusb, version: 0x%06x\r\n", CHERRYUSB_VERSION);
|
||||
}
|
||||
|
||||
void usb_hc_low_level_deinit(struct usbh_bus *bus)
|
||||
{
|
||||
if (s_interrupt_handle) {
|
||||
esp_intr_free(s_interrupt_handle);
|
||||
s_interrupt_handle = NULL;
|
||||
}
|
||||
if (s_phy_handle) {
|
||||
usb_del_phy(s_phy_handle);
|
||||
s_phy_handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t usbh_get_dwc2_gccfg_conf(uint32_t reg_base)
|
||||
{
|
||||
return 0;
|
||||
}
|
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2024, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usb_config.h"
|
||||
#include "stdint.h"
|
||||
#include "usb_dwc2_reg.h"
|
||||
|
||||
/* 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
|
||||
}
|
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
* Copyright (c) 2024, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usb_config.h"
|
||||
#include "stdint.h"
|
||||
#include "usb_dwc2_reg.h"
|
||||
|
||||
/* you can find this config in function: USB_DevInit, file:stm32xxx_ll_usb.c, for example:
|
||||
*
|
||||
* USBx->GCCFG |= USB_OTG_GCCFG_PWRDWN;
|
||||
* USBx->GCCFG |= USB_OTG_GCCFG_NOVBUSSENS;
|
||||
* USBx->GCCFG &= ~USB_OTG_GCCFG_VBUSBSEN;
|
||||
* USBx->GCCFG &= ~USB_OTG_GCCFG_VBUSASEN;
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(STM32F722xx) || defined(STM32F723xx) || defined(STM32F730xx) || defined(STM32F732xx) || defined(STM32F733xx)
|
||||
/**
|
||||
* @brief USB_HS_PHY_Registers
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
|
||||
__IO uint32_t USB_HS_PHYC_PLL; /*!< This register is used to control the PLL of the HS PHY. 000h */
|
||||
__IO uint32_t Reserved04; /*!< Reserved 004h */
|
||||
__IO uint32_t Reserved08; /*!< Reserved 008h */
|
||||
__IO uint32_t USB_HS_PHYC_TUNE; /*!< This register is used to control the tuning interface of the High Speed PHY. 00Ch */
|
||||
__IO uint32_t Reserved10; /*!< Reserved 010h */
|
||||
__IO uint32_t Reserved14; /*!< Reserved 014h */
|
||||
__IO uint32_t USB_HS_PHYC_LDO; /*!< This register is used to control the regulator (LDO). 018h */
|
||||
} USB_HS_PHYC_GlobalTypeDef;
|
||||
|
||||
#define USB_HS_PHYC_CONTROLLER_BASE 0x40017C00UL
|
||||
#define USB_HS_PHYC ((USB_HS_PHYC_GlobalTypeDef *) USB_HS_PHYC_CONTROLLER_BASE)
|
||||
|
||||
/******************** Bit definition for USBPHYC_PLL1 register ********************/
|
||||
#define USB_HS_PHYC_PLL1_PLLEN_Pos (0U)
|
||||
#define USB_HS_PHYC_PLL1_PLLEN_Msk (0x1UL << USB_HS_PHYC_PLL1_PLLEN_Pos) /*!< 0x00000001 */
|
||||
#define USB_HS_PHYC_PLL1_PLLEN USB_HS_PHYC_PLL1_PLLEN_Msk /*!< Enable PLL */
|
||||
#define USB_HS_PHYC_PLL1_PLLSEL_Pos (1U)
|
||||
#define USB_HS_PHYC_PLL1_PLLSEL_Msk (0x7UL << USB_HS_PHYC_PLL1_PLLSEL_Pos) /*!< 0x0000000E */
|
||||
#define USB_HS_PHYC_PLL1_PLLSEL USB_HS_PHYC_PLL1_PLLSEL_Msk /*!< Controls PHY frequency operation selection */
|
||||
#define USB_HS_PHYC_PLL1_PLLSEL_1 (0x1UL << USB_HS_PHYC_PLL1_PLLSEL_Pos) /*!< 0x00000002 */
|
||||
#define USB_HS_PHYC_PLL1_PLLSEL_2 (0x2UL << USB_HS_PHYC_PLL1_PLLSEL_Pos) /*!< 0x00000004 */
|
||||
#define USB_HS_PHYC_PLL1_PLLSEL_3 (0x4UL << USB_HS_PHYC_PLL1_PLLSEL_Pos) /*!< 0x00000008 */
|
||||
|
||||
#define USB_HS_PHYC_PLL1_PLLSEL_12MHZ 0x00000000U /*!< PHY PLL1 input clock frequency 12 MHz */
|
||||
#define USB_HS_PHYC_PLL1_PLLSEL_12_5MHZ USB_HS_PHYC_PLL1_PLLSEL_1 /*!< PHY PLL1 input clock frequency 12.5 MHz */
|
||||
#define USB_HS_PHYC_PLL1_PLLSEL_16MHZ (uint32_t)(USB_HS_PHYC_PLL1_PLLSEL_1 | USB_HS_PHYC_PLL1_PLLSEL_2) /*!< PHY PLL1 input clock frequency 16 MHz */
|
||||
#define USB_HS_PHYC_PLL1_PLLSEL_24MHZ USB_HS_PHYC_PLL1_PLLSEL_3 /*!< PHY PLL1 input clock frequency 24 MHz */
|
||||
#define USB_HS_PHYC_PLL1_PLLSEL_25MHZ (uint32_t)(USB_HS_PHYC_PLL1_PLLSEL_2 | USB_HS_PHYC_PLL1_PLLSEL_3) /*!< PHY PLL1 input clock frequency 25 MHz */
|
||||
|
||||
/******************** Bit definition for USBPHYC_LDO register ********************/
|
||||
#define USB_HS_PHYC_LDO_USED_Pos (0U)
|
||||
#define USB_HS_PHYC_LDO_USED_Msk (0x1UL << USB_HS_PHYC_LDO_USED_Pos) /*!< 0x00000001 */
|
||||
#define USB_HS_PHYC_LDO_USED USB_HS_PHYC_LDO_USED_Msk /*!< Monitors the usage status of the PHY's LDO */
|
||||
#define USB_HS_PHYC_LDO_STATUS_Pos (1U)
|
||||
#define USB_HS_PHYC_LDO_STATUS_Msk (0x1UL << USB_HS_PHYC_LDO_STATUS_Pos) /*!< 0x00000002 */
|
||||
#define USB_HS_PHYC_LDO_STATUS USB_HS_PHYC_LDO_STATUS_Msk /*!< Monitors the status of the PHY's LDO. */
|
||||
#define USB_HS_PHYC_LDO_DISABLE_Pos (2U)
|
||||
#define USB_HS_PHYC_LDO_DISABLE_Msk (0x1UL << USB_HS_PHYC_LDO_DISABLE_Pos) /*!< 0x00000004 */
|
||||
#define USB_HS_PHYC_LDO_DISABLE USB_HS_PHYC_LDO_DISABLE_Msk /*!< Controls disable of the High Speed PHY's LDO */
|
||||
|
||||
/* Legacy */
|
||||
#define USB_HS_PHYC_PLL_PLLEN_Pos USB_HS_PHYC_PLL1_PLLEN_Pos
|
||||
#define USB_HS_PHYC_PLL_PLLEN_Msk USB_HS_PHYC_PLL1_PLLEN_Msk
|
||||
#define USB_HS_PHYC_PLL_PLLEN USB_HS_PHYC_PLL1_PLLEN
|
||||
#define USB_HS_PHYC_PLL_PLLSEL_Pos USB_HS_PHYC_PLL1_PLLSEL_Pos
|
||||
#define USB_HS_PHYC_PLL_PLLSEL_Msk USB_HS_PHYC_PLL1_PLLSEL_Msk
|
||||
#define USB_HS_PHYC_PLL_PLLSEL USB_HS_PHYC_PLL1_PLLSEL
|
||||
#define USB_HS_PHYC_PLL_PLLSEL_1 USB_HS_PHYC_PLL1_PLLSEL_1
|
||||
#define USB_HS_PHYC_PLL_PLLSEL_2 USB_HS_PHYC_PLL1_PLLSEL_2
|
||||
#define USB_HS_PHYC_PLL_PLLSEL_3 USB_HS_PHYC_PLL1_PLLSEL_3
|
||||
|
||||
#define USB_HS_PHYC_LDO_ENABLE_Pos USB_HS_PHYC_LDO_DISABLE_Pos
|
||||
#define USB_HS_PHYC_LDO_ENABLE_Msk USB_HS_PHYC_LDO_DISABLE_Msk
|
||||
#define USB_HS_PHYC_LDO_ENABLE USB_HS_PHYC_LDO_DISABLE
|
||||
|
||||
#if !defined (USB_HS_PHYC_TUNE_VALUE)
|
||||
#define USB_HS_PHYC_TUNE_VALUE 0x00000F13U /*!< Value of USB HS PHY Tune */
|
||||
#endif /* USB_HS_PHYC_TUNE_VALUE */
|
||||
/**
|
||||
* @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
|
||||
|
||||
uint32_t usbd_get_dwc2_gccfg_conf(uint32_t reg_base)
|
||||
{
|
||||
#if __has_include("stm32h7xx.h") || __has_include("stm32f7xx.h") || __has_include("stm32l4xx.h")
|
||||
#define USB_OTG_GLB ((DWC2_GlobalTypeDef *)(reg_base))
|
||||
/* B-peripheral session valid override enable */
|
||||
USB_OTG_GLB->GOTGCTL |= USB_OTG_GOTGCTL_BVALOEN;
|
||||
USB_OTG_GLB->GOTGCTL |= USB_OTG_GOTGCTL_BVALOVAL;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_HS
|
||||
#if defined(STM32F722xx) || defined(STM32F723xx) || defined(STM32F730xx) || defined(STM32F732xx) || defined(STM32F733xx)
|
||||
USB_OTG_GLB->GCCFG = (1 << 23);
|
||||
usb_hsphy_init(25000000U);
|
||||
return (1 << 23); /* Enable USB HS PHY USBx->GCCFG |= USB_OTG_GCCFG_PHYHSEN;*/
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
#else
|
||||
#if __has_include("stm32h7xx.h") || __has_include("stm32f7xx.h") || __has_include("stm32l4xx.h")
|
||||
return (1 << 16);
|
||||
#else
|
||||
return ((1 << 16) | (1 << 21));
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t usbh_get_dwc2_gccfg_conf(uint32_t reg_base)
|
||||
{
|
||||
#if __has_include("stm32h7xx.h") || __has_include("stm32f7xx.h") || __has_include("stm32l4xx.h")
|
||||
#define USB_OTG_GLB ((DWC2_GlobalTypeDef *)(reg_base))
|
||||
/* B-peripheral session valid override enable */
|
||||
USB_OTG_GLB->GOTGCTL &= ~USB_OTG_GOTGCTL_BVALOEN;
|
||||
USB_OTG_GLB->GOTGCTL &= ~USB_OTG_GOTGCTL_BVALOVAL;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_HS
|
||||
#if defined(STM32F722xx) || defined(STM32F723xx) || defined(STM32F730xx) || defined(STM32F732xx) || defined(STM32F733xx)
|
||||
USB_OTG_GLB->GCCFG = (1 << 23);
|
||||
usb_hsphy_init(25000000U);
|
||||
return (1 << 23); /* Enable USB HS PHY USBx->GCCFG |= USB_OTG_GCCFG_PHYHSEN;*/
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
#else
|
||||
#if __has_include("stm32h7xx.h") || __has_include("stm32f7xx.h") || __has_include("stm32l4xx.h")
|
||||
return (1 << 16);
|
||||
#else
|
||||
return ((1 << 16) | (1 << 21));
|
||||
#endif
|
||||
#endif
|
||||
}
|
1112
rt-thread/components/drivers/usb/cherryusb/port/dwc2/usb_hc_dwc2.c
Normal file
1112
rt-thread/components/drivers/usb/cherryusb/port/dwc2/usb_hc_dwc2.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,27 @@
|
||||
# Note
|
||||
|
||||
## Support Chip List
|
||||
|
||||
### BouffaloLab
|
||||
|
||||
- BouffaloLab BL616/BL808
|
||||
|
||||
### HPMicro
|
||||
|
||||
- HPM all series
|
||||
|
||||
### AllwinnerTech
|
||||
|
||||
- F133
|
||||
|
||||
### Nuvoton
|
||||
|
||||
- Nuvoton all series
|
||||
|
||||
### Artinchip
|
||||
|
||||
- d13x, d21x
|
||||
|
||||
### Intel
|
||||
|
||||
- Intel 6 Series Chipset and Intel C200 Series Chipset
|
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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_hc_ehci.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 CONFIG_USBHOST_PIPE_NUM
|
||||
#endif
|
||||
#ifndef CONFIG_USB_EHCI_QTD_NUM
|
||||
#define CONFIG_USB_EHCI_QTD_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
|
||||
|
||||
extern uint8_t usbh_get_port_speed(struct usbh_bus *bus, const uint8_t port);
|
||||
|
||||
struct ehci_qtd_hw {
|
||||
struct ehci_qtd hw;
|
||||
struct usbh_urb *urb;
|
||||
uint32_t length;
|
||||
} __attribute__((aligned(32)));
|
||||
|
||||
struct ehci_qh_hw {
|
||||
struct ehci_qh hw;
|
||||
struct ehci_qtd_hw qtd_pool[CONFIG_USB_EHCI_QTD_NUM];
|
||||
uint32_t first_qtd;
|
||||
struct usbh_urb *urb;
|
||||
usb_osal_sem_t waitsem;
|
||||
uint8_t remove_in_iaad;
|
||||
} __attribute__((aligned(32)));
|
||||
|
||||
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];
|
||||
} __attribute__((aligned(32)));
|
||||
|
||||
struct ehci_iso_hw
|
||||
{
|
||||
struct ehci_itd_hw itd_pool[CONFIG_USB_EHCI_ITD_NUM];
|
||||
uint32_t itd_num;
|
||||
};
|
||||
|
||||
struct ehci_hcd {
|
||||
bool ehci_qh_used[CONFIG_USB_EHCI_QH_NUM];
|
||||
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)];
|
||||
|
||||
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,181 @@
|
||||
/*
|
||||
* 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_ehci_priv.h"
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
#if defined (RT_USING_FINSH)
|
||||
#include <finsh.h>
|
||||
|
||||
MSH_CMD_EXPORT_ALIAS(lsusb, lsusb, list usb device);
|
||||
#endif
|
||||
#endif
|
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright (c) 2024, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "bflb_core.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;
|
||||
}
|
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2024 HPMicro
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
#include "usbh_core.h"
|
||||
#include "hpm_common.h"
|
||||
#include "hpm_soc.h"
|
||||
#include "hpm_usb_drv.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
|
||||
|
||||
static uint32_t _hcd_irqnum[CONFIG_USBHOST_MAX_BUS];
|
||||
static uint8_t _hcd_busid[CONFIG_USBHOST_MAX_BUS];
|
||||
|
||||
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;
|
||||
|
||||
/* Not use interrupt threshold. */
|
||||
ptr->USBCMD &= ~USB_USBCMD_ITC_MASK;
|
||||
}
|
||||
|
||||
void usb_hc_low_level_init(struct usbh_bus *bus)
|
||||
{
|
||||
if (bus->hcd.reg_base == HPM_USB0_BASE) {
|
||||
_hcd_irqnum[bus->hcd.hcd_id] = IRQn_USB0;
|
||||
_hcd_busid[0] = bus->hcd.hcd_id;
|
||||
} else {
|
||||
#ifdef HPM_USB1_BASE
|
||||
if (bus->hcd.reg_base == HPM_USB1_BASE) {
|
||||
_hcd_irqnum[bus->hcd.hcd_id] = IRQn_USB1;
|
||||
_hcd_busid[1] = bus->hcd.hcd_id;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
usb_phy_init((USB_Type *)(bus->hcd.reg_base));
|
||||
intc_m_enable_irq(_hcd_irqnum[bus->hcd.hcd_id]);
|
||||
}
|
||||
|
||||
void usb_hc_low_level2_init(struct usbh_bus *bus)
|
||||
{
|
||||
usb_host_mode_init((USB_Type *)(bus->hcd.reg_base));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
extern void USBH_IRQHandler(uint8_t busid);
|
||||
|
||||
void isr_usbh0(void)
|
||||
{
|
||||
USBH_IRQHandler(_hcd_busid[0]);
|
||||
}
|
||||
SDK_DECLARE_EXT_ISR_M(IRQn_USB0, isr_usbh0)
|
||||
|
||||
#ifdef HPM_USB1_BASE
|
||||
void isr_usbh1(void)
|
||||
{
|
||||
USBH_IRQHandler(_hcd_busid[1]);
|
||||
}
|
||||
SDK_DECLARE_EXT_ISR_M(IRQn_USB1, isr_usbh1)
|
||||
#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
|
1369
rt-thread/components/drivers/usb/cherryusb/port/ehci/usb_hc_ehci.c
Normal file
1369
rt-thread/components/drivers/usb/cherryusb/port/ehci/usb_hc_ehci.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,375 @@
|
||||
/*
|
||||
* Copyright 2020 The Apache Software Foundation
|
||||
* Copyright 2022 sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef USB_HC_EHCI_H
|
||||
#define USB_HC_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 /* USB_HC_EHCI_H */
|
@@ -0,0 +1,33 @@
|
||||
# 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_MD、GD32F10X_HD、GD32F10X_XD
|
||||
- GD32F30X_HD、GD32F30X_XD
|
||||
- GD32F350
|
||||
- GD32F407
|
||||
|
||||
## CH32
|
||||
|
||||
- CH32F10x、CH32V10x
|
@@ -0,0 +1,540 @@
|
||||
/*
|
||||
* Copyright (c) 2022, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usbd_core.h"
|
||||
|
||||
#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
|
||||
|
||||
#ifndef CONFIG_USBDEV_EP_NUM
|
||||
#define CONFIG_USBDEV_EP_NUM 8
|
||||
#endif
|
||||
|
||||
#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_SOFM | USB_CNTR_ESOFM |
|
||||
USB_CNTR_RESETM;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
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 (ep_idx > (CONFIG_USBDEV_EP_NUM - 1)) {
|
||||
USB_LOG_ERR("Ep addr %02x overflow\r\n", ep->bEndpointAddress);
|
||||
return -1;
|
||||
}
|
||||
|
||||
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:
|
||||
break;
|
||||
}
|
||||
|
||||
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) {
|
||||
if (g_fsdev_udc.pma_offset + g_fsdev_udc.out_ep[ep_idx].ep_mps > CONFIG_USB_FSDEV_RAM_SIZE) {
|
||||
USB_LOG_ERR("Ep pma %02x overflow\r\n", ep->bEndpointAddress);
|
||||
return -1;
|
||||
}
|
||||
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) {
|
||||
if (g_fsdev_udc.pma_offset + g_fsdev_udc.in_ep[ep_idx].ep_mps > CONFIG_USB_FSDEV_RAM_SIZE) {
|
||||
USB_LOG_ERR("Ep pma %02x overflow\r\n", ep->bEndpointAddress);
|
||||
return -1;
|
||||
}
|
||||
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)
|
||||
{
|
||||
if (USB_EP_DIR_IS_OUT(ep)) {
|
||||
} else {
|
||||
}
|
||||
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;
|
||||
}
|
||||
if (wIstr & USB_ISTR_SOF) {
|
||||
USB->ISTR &= (uint16_t)(~USB_ISTR_SOF);
|
||||
}
|
||||
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
350
rt-thread/components/drivers/usb/cherryusb/port/hpm/usb_dc_hpm.c
Normal file
350
rt-thread/components/drivers/usb/cherryusb/port/hpm/usb_dc_hpm.c
Normal file
@@ -0,0 +1,350 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2024 HPMicro
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
#include "usbd_core.h"
|
||||
#include "hpm_usb_device.h"
|
||||
|
||||
#ifndef USB_NUM_BIDIR_ENDPOINTS
|
||||
#define USB_NUM_BIDIR_ENDPOINTS CONFIG_USBDEV_EP_NUM
|
||||
#endif
|
||||
|
||||
/* USBSTS, USBINTR */
|
||||
enum {
|
||||
intr_usb = HPM_BITSMASK(1, 0),
|
||||
intr_error = HPM_BITSMASK(1, 1),
|
||||
intr_port_change = HPM_BITSMASK(1, 2),
|
||||
intr_reset = HPM_BITSMASK(1, 6),
|
||||
intr_sof = HPM_BITSMASK(1, 7),
|
||||
intr_suspend = HPM_BITSMASK(1, 8),
|
||||
intr_nak = HPM_BITSMASK(1, 16)
|
||||
};
|
||||
|
||||
/* 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;
|
||||
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 ATTR_PLACE_AT_NONCACHEABLE_WITH_ALIGNMENT(USB_SOC_DCD_DATA_RAM_ADDRESS_ALIGNMENT) dcd_data_t _dcd_data0;
|
||||
#ifdef HPM_USB1_BASE
|
||||
static ATTR_PLACE_AT_NONCACHEABLE_WITH_ALIGNMENT(USB_SOC_DCD_DATA_RAM_ADDRESS_ALIGNMENT) dcd_data_t _dcd_data1;
|
||||
#endif
|
||||
static ATTR_PLACE_AT_NONCACHEABLE usb_device_handle_t usb_device_handle[CONFIG_USBDEV_MAX_BUS];
|
||||
static uint32_t _dcd_irqnum[CONFIG_USBDEV_MAX_BUS];
|
||||
static uint8_t _dcd_busid[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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (g_usbdev_bus[busid].reg_base == HPM_USB0_BASE) {
|
||||
_dcd_irqnum[busid] = IRQn_USB0;
|
||||
_dcd_busid[0] = busid;
|
||||
} else {
|
||||
#ifdef HPM_USB1_BASE
|
||||
if (g_usbdev_bus[busid].reg_base == HPM_USB1_BASE) {
|
||||
_dcd_irqnum[busid] = IRQn_USB1;
|
||||
_dcd_busid[1] = busid;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (busid == 0) {
|
||||
g_hpm_udc[busid].handle->dcd_data = &_dcd_data0;
|
||||
} else if (busid == 1) {
|
||||
#ifdef HPM_USB1_BASE
|
||||
g_hpm_udc[busid].handle->dcd_data = &_dcd_data1;
|
||||
#endif
|
||||
} else {
|
||||
;
|
||||
}
|
||||
|
||||
uint32_t int_mask;
|
||||
int_mask = (USB_USBINTR_UE_MASK | USB_USBINTR_UEE_MASK |
|
||||
USB_USBINTR_PCE_MASK | USB_USBINTR_URE_MASK);
|
||||
|
||||
usb_device_init(g_hpm_udc[busid].handle, int_mask);
|
||||
|
||||
intc_m_enable_irq(_dcd_irqnum[busid]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_dc_deinit(uint8_t busid)
|
||||
{
|
||||
intc_m_disable_irq(_dcd_irqnum[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;
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
if (int_status & intr_reset) {
|
||||
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)) {
|
||||
usbd_event_suspend_handler(busid);
|
||||
/* Note: Host may delay more than 3 ms before and/or after bus reset before doing enumeration. */
|
||||
if (usb_device_get_address(handle)) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (int_status & intr_port_change) {
|
||||
if (!usb_device_get_port_ccs(handle)) {
|
||||
usbd_event_disconnect_handler(busid);
|
||||
} else {
|
||||
usbd_event_connect_handler(busid);
|
||||
}
|
||||
}
|
||||
|
||||
if (int_status & intr_usb) {
|
||||
uint32_t const edpt_complete = usb_device_get_edpt_complete_status(handle);
|
||||
usb_device_clear_edpt_complete_status(handle, edpt_complete);
|
||||
uint32_t edpt_setup_status = usb_device_get_setup_status(handle);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (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_qtd_t *p_qtd = usb_device_qtd_get(handle, 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 == 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void isr_usbd0(void)
|
||||
{
|
||||
USBD_IRQHandler(_dcd_busid[0]);
|
||||
}
|
||||
SDK_DECLARE_EXT_ISR_M(IRQn_USB0, isr_usbd0)
|
||||
|
||||
#ifdef HPM_USB1_BASE
|
||||
void isr_usbd1(void)
|
||||
{
|
||||
USBD_IRQHandler(_dcd_busid[1]);
|
||||
}
|
||||
SDK_DECLARE_EXT_ISR_M(IRQn_USB1, isr_usbd1)
|
||||
#endif
|
@@ -0,0 +1,19 @@
|
||||
# Note
|
||||
|
||||
## Support Chip List
|
||||
|
||||
### Eastsoft
|
||||
|
||||
- ES32F3xx
|
||||
|
||||
### TI
|
||||
|
||||
- MSP432E4x
|
||||
|
||||
### Bekencorp
|
||||
|
||||
- BK7256/BK7258
|
||||
|
||||
### AllwinnerTech
|
||||
|
||||
- F1Cxxx, F2Cxxx
|
@@ -0,0 +1,786 @@
|
||||
/*
|
||||
* 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_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
|
||||
|
||||
#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_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
|
||||
|
||||
#endif // CONFIG_USB_MUSB_SUNXI
|
||||
|
||||
#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_USBDEV_EP_NUM]; /*!< IN endpoint parameters*/
|
||||
struct musb_ep_state out_ep[CONFIG_USBDEV_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);
|
||||
}
|
||||
|
||||
if (offset > usb_get_musb_ram_size()) {
|
||||
USB_LOG_ERR("offset:%d is overflow, please check your table\r\n", offset);
|
||||
while (1) {
|
||||
}
|
||||
}
|
||||
|
||||
/* Enable USB interrupts */
|
||||
HWREGB(USB_BASE + MUSB_IE_OFFSET) = USB_IE_RESET;
|
||||
HWREGH(USB_BASE + MUSB_TXIE_OFFSET) = USB_TXIE_EP0;
|
||||
HWREGH(USB_BASE + MUSB_RXIE_OFFSET) = 0;
|
||||
|
||||
HWREGB(USB_BASE + MUSB_POWER_OFFSET) |= USB_POWER_SOFTCONN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_dc_deinit(uint8_t busid)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (ep_idx > (CONFIG_USBDEV_EP_NUM - 1)) {
|
||||
USB_LOG_ERR("Ep addr %02x overflow\r\n", ep->bEndpointAddress);
|
||||
return -1;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if ((8 << HWREGB(USB_BASE + MUSB_RXFIFOSZ_OFFSET)) < g_musb_udc.out_ep[ep_idx].ep_mps) {
|
||||
USB_LOG_ERR("Ep %02x fifo is overflow\r\n", ep->bEndpointAddress);
|
||||
return -2;
|
||||
}
|
||||
|
||||
HWREGH(USB_BASE + MUSB_IND_RXMAP_OFFSET) = 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_BASE + MUSB_IND_RXCSRH_OFFSET) = ui32Register;
|
||||
|
||||
// Reset the Data toggle to zero.
|
||||
if (HWREGB(USB_BASE + MUSB_IND_RXCSRL_OFFSET) & USB_RXCSRL1_RXRDY)
|
||||
HWREGB(USB_BASE + MUSB_IND_RXCSRL_OFFSET) = (USB_RXCSRL1_CLRDT | USB_RXCSRL1_FLUSH);
|
||||
else
|
||||
HWREGB(USB_BASE + MUSB_IND_RXCSRL_OFFSET) = USB_RXCSRL1_CLRDT;
|
||||
} 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;
|
||||
|
||||
if ((8 << HWREGB(USB_BASE + MUSB_TXFIFOSZ_OFFSET)) < g_musb_udc.in_ep[ep_idx].ep_mps) {
|
||||
USB_LOG_ERR("Ep %02x fifo is overflow\r\n", ep->bEndpointAddress);
|
||||
return -2;
|
||||
}
|
||||
|
||||
HWREGH(USB_BASE + MUSB_IND_TXMAP_OFFSET) = 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_BASE + MUSB_IND_TXCSRH_OFFSET) = ui32Register;
|
||||
|
||||
// Reset the Data toggle to zero.
|
||||
if (HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) & USB_TXCSRL1_TXRDY)
|
||||
HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) = (USB_TXCSRL1_CLRDT | USB_TXCSRL1_FLUSH);
|
||||
else
|
||||
HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) = 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_BASE + MUSB_IND_TXCSRL_OFFSET) |= (USB_CSRL0_STALL | USB_CSRL0_RXRDYC);
|
||||
} else {
|
||||
HWREGB(USB_BASE + MUSB_IND_RXCSRL_OFFSET) |= USB_RXCSRL1_STALL;
|
||||
}
|
||||
} else {
|
||||
if (ep_idx == 0x00) {
|
||||
usb_ep0_state = USB_EP0_STATE_STALL;
|
||||
HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) |= (USB_CSRL0_STALL | USB_CSRL0_RXRDYC);
|
||||
} else {
|
||||
HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) |= 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_BASE + MUSB_IND_TXCSRL_OFFSET) &= ~USB_CSRL0_STALLED;
|
||||
} else {
|
||||
// Clear the stall on an OUT endpoint.
|
||||
HWREGB(USB_BASE + MUSB_IND_RXCSRL_OFFSET) &= ~(USB_RXCSRL1_STALL | USB_RXCSRL1_STALLED);
|
||||
// Reset the data toggle.
|
||||
HWREGB(USB_BASE + MUSB_IND_RXCSRL_OFFSET) |= USB_RXCSRL1_CLRDT;
|
||||
}
|
||||
} else {
|
||||
if (ep_idx == 0x00) {
|
||||
HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) &= ~USB_CSRL0_STALLED;
|
||||
} else {
|
||||
// Clear the stall on an IN endpoint.
|
||||
HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) &= ~(USB_TXCSRL1_STALL | USB_TXCSRL1_STALLED);
|
||||
// Reset the data toggle.
|
||||
HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) |= 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)
|
||||
{
|
||||
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_BASE + MUSB_IND_TXCSRL_OFFSET) & 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_BASE + MUSB_IND_TXCSRL_OFFSET) = (USB_CSRL0_TXRDY | USB_CSRL0_DATAEND);
|
||||
} else {
|
||||
HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) = 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_BASE + MUSB_IND_TXCSRL_OFFSET) = (USB_CSRL0_TXRDY | USB_CSRL0_DATAEND);
|
||||
} else {
|
||||
HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) = USB_CSRL0_TXRDY;
|
||||
}
|
||||
} else {
|
||||
HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) = 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 ep0_status = HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET);
|
||||
uint16_t read_count;
|
||||
|
||||
if (ep0_status & USB_CSRL0_STALLED) {
|
||||
HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) &= ~USB_CSRL0_STALLED;
|
||||
usb_ep0_state = USB_EP0_STATE_SETUP;
|
||||
return;
|
||||
}
|
||||
|
||||
if (ep0_status & USB_CSRL0_SETEND) {
|
||||
HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) = 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_BASE + MUSB_IND_RXCOUNT_OFFSET);
|
||||
|
||||
if (read_count != 8) {
|
||||
return;
|
||||
}
|
||||
|
||||
musb_read_packet(0, (uint8_t *)&g_musb_udc.setup, 8);
|
||||
if (g_musb_udc.setup.wLength) {
|
||||
HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) = USB_CSRL0_RXRDYC;
|
||||
} else {
|
||||
HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) = (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_BASE + MUSB_IND_RXCOUNT_OFFSET);
|
||||
|
||||
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_BASE + MUSB_IND_TXCSRL_OFFSET) = (USB_CSRL0_RXRDYC | USB_CSRL0_DATAEND);
|
||||
usb_ep0_state = USB_EP0_STATE_IN_STATUS;
|
||||
} else {
|
||||
HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) = 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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (is & USB_IS_SOF) {
|
||||
}
|
||||
|
||||
if (is & USB_IS_RESUME) {
|
||||
}
|
||||
|
||||
if (is & USB_IS_SUSPEND) {
|
||||
}
|
||||
|
||||
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_BASE + MUSB_IND_TXCSRL_OFFSET) & USB_TXCSRL1_UNDRN) {
|
||||
HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) &= ~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_BASE + MUSB_IND_TXCSRL_OFFSET) = 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_BASE + MUSB_IND_RXCSRL_OFFSET) & USB_RXCSRL1_RXRDY) {
|
||||
read_count = HWREGH(USB_BASE + MUSB_IND_RXCOUNT_OFFSET);
|
||||
|
||||
musb_read_packet(ep_idx, g_musb_udc.out_ep[ep_idx].xfer_buf, read_count);
|
||||
HWREGB(USB_BASE + MUSB_IND_RXCSRL_OFFSET) &= ~(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,321 @@
|
||||
/*
|
||||
* 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_USBDEV_EP_NUM != 8
|
||||
#error beken chips only support 8 endpoints
|
||||
#endif
|
||||
|
||||
#if CONFIG_USBHOST_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);
|
||||
}
|
||||
|
||||
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,53 @@
|
||||
/*
|
||||
* Copyright (c) 2024, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usb_config.h"
|
||||
#include "stdint.h"
|
||||
#include "usb_musb_reg.h"
|
||||
|
||||
#if CONFIG_USBDEV_EP_NUM != 6
|
||||
#error es32 chips only support 6 endpoints
|
||||
#endif
|
||||
|
||||
#if CONFIG_USBHOST_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;
|
||||
}
|
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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_USBDEV_EP_NUM != 4
|
||||
#error sunxi chips only support 4 endpoints
|
||||
#endif
|
||||
|
||||
#if CONFIG_USBHOST_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;
|
||||
}
|
1081
rt-thread/components/drivers/usb/cherryusb/port/musb/usb_hc_musb.c
Normal file
1081
rt-thread/components/drivers/usb/cherryusb/port/musb/usb_hc_musb.c
Normal file
File diff suppressed because it is too large
Load Diff
3886
rt-thread/components/drivers/usb/cherryusb/port/musb/usb_musb_reg.h
Normal file
3886
rt-thread/components/drivers/usb/cherryusb/port/musb/usb_musb_reg.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,18 @@
|
||||
# Note
|
||||
|
||||
This OHCI is a companion controller of EHCI.
|
||||
|
||||
## Support Chip List
|
||||
|
||||
### AllwinnerTech
|
||||
|
||||
- F133
|
||||
|
||||
### Nuvoton
|
||||
|
||||
- Nuvoton all series
|
||||
|
||||
### Artinchip
|
||||
|
||||
- d13x, d21x
|
||||
|
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
* Copyright (c) 2024, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usb_ohci_priv.h"
|
||||
#include "usb_ehci_priv.h"
|
||||
|
||||
int ohci_init(struct usbh_bus *bus)
|
||||
{
|
||||
volatile uint32_t timeout = 0;
|
||||
uint32_t regval;
|
||||
|
||||
USB_LOG_INFO("OHCI hcrevision:0x%02x\r\n", (unsigned int)OHCI_HCOR->hcrevision);
|
||||
|
||||
OHCI_HCOR->hccontrol = 0;
|
||||
OHCI_HCOR->hccontrolheaded = 0;
|
||||
OHCI_HCOR->hcbulkheaded = 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;
|
||||
}
|
||||
}
|
||||
|
||||
/* Frame Interval / Periodic Start.
|
||||
*
|
||||
* At 12Mbps, there are 12000 bit time in each 1Msec frame.
|
||||
*/
|
||||
|
||||
#define BITS_PER_FRAME 12000
|
||||
#define FI (BITS_PER_FRAME - 1)
|
||||
#define FSMPS ((6 * (FI - 210)) / 7)
|
||||
#define DEFAULT_FMINTERVAL ((FSMPS << OHCI_FMINT_FSMPS_SHIFT) | FI)
|
||||
#define DEFAULT_PERSTART (((9 * BITS_PER_FRAME) / 10) - 1)
|
||||
|
||||
OHCI_HCOR->hcfminterval = DEFAULT_FMINTERVAL;
|
||||
OHCI_HCOR->hcperiodicstart = DEFAULT_PERSTART;
|
||||
|
||||
/* Put HC in operational state */
|
||||
regval = OHCI_HCOR->hccontrol;
|
||||
regval &= ~OHCI_CTRL_HCFS_MASK;
|
||||
regval |= OHCI_CTRL_HCFS_OPER;
|
||||
OHCI_HCOR->hccontrol = regval;
|
||||
|
||||
/* Set global power in HcRhStatus */
|
||||
OHCI_HCOR->hcrhsts = OHCI_RHSTATUS_SGP;
|
||||
|
||||
/* Set HCCA base address */
|
||||
OHCI_HCOR->hchcca = 0;
|
||||
|
||||
/* Clear pending interrupts */
|
||||
regval = OHCI_HCOR->hcintsts;
|
||||
OHCI_HCOR->hcintsts = regval;
|
||||
|
||||
for (uint8_t port = 0; port < g_ehci_hcd[bus->hcd.hcd_id].n_pcc; port++) {
|
||||
regval = OHCI_HCOR->hcrhportsts[port];
|
||||
regval |= OHCI_RHPORTST_PPS;
|
||||
OHCI_HCOR->hcrhportsts[port] = regval;
|
||||
}
|
||||
|
||||
/* Enable OHCI interrupts */
|
||||
OHCI_HCOR->hcinten = OHCI_INT_SO | OHCI_INT_RD | OHCI_INT_UE | OHCI_INT_OC |
|
||||
OHCI_INT_WDH | OHCI_INT_RHSC | OHCI_INT_MIE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ohci_deinit(struct usbh_bus *bus)
|
||||
{
|
||||
uint32_t regval;
|
||||
|
||||
/* Disable OHCI interrupts */
|
||||
OHCI_HCOR->hcintdis = OHCI_INT_SO | OHCI_INT_RD | OHCI_INT_UE | OHCI_INT_OC |
|
||||
OHCI_INT_WDH | OHCI_INT_RHSC | OHCI_INT_MIE;
|
||||
|
||||
for (uint8_t port = 0; port < g_ehci_hcd[bus->hcd.hcd_id].n_pcc; port++) {
|
||||
regval = OHCI_HCOR->hcrhportsts[port];
|
||||
regval &= ~OHCI_RHPORTST_PPS;
|
||||
OHCI_HCOR->hcrhportsts[port] = regval;
|
||||
}
|
||||
|
||||
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_ehci_hcd[bus->hcd.hcd_id].n_pcc;
|
||||
|
||||
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:
|
||||
|
||||
case HUB_PORT_FEATURE_C_SUSPEND:
|
||||
break;
|
||||
case HUB_PORT_FEATURE_POWER:
|
||||
break;
|
||||
case HUB_PORT_FEATURE_C_CONNECTION:
|
||||
OHCI_HCOR->hcrhportsts[port - 1] |= OHCI_RHPORTST_CSC;
|
||||
break;
|
||||
case HUB_PORT_FEATURE_C_ENABLE:
|
||||
OHCI_HCOR->hcrhportsts[port - 1] |= OHCI_RHPORTST_PESC;
|
||||
break;
|
||||
case HUB_PORT_FEATURE_C_OVER_CURREN:
|
||||
OHCI_HCOR->hcrhportsts[port - 1] |= OHCI_RHPORTST_OCIC;
|
||||
break;
|
||||
case HUB_PORT_FEATURE_C_RESET:
|
||||
OHCI_HCOR->hcrhportsts[port - 1] |= OHCI_RHPORTST_PRSC;
|
||||
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:
|
||||
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;
|
||||
OHCI_HCOR->hcintsts = usbsts;
|
||||
|
||||
if (usbsts & 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) {
|
||||
}
|
||||
}
|
@@ -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 1: Periodic list enable */
|
||||
#define OHCI_CTRL_IE (1 << 3) /* Bit 2: Isochronous enable */
|
||||
#define OHCI_CTRL_CLE (1 << 4) /* Bit 3: Control list enable */
|
||||
#define OHCI_CTRL_BLE (1 << 5) /* Bit 4: 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_S (1 << 13) /* Bit 13: Speed (low) */
|
||||
#define ED_CONTROL_K (1 << 14) /* Bit 14: Skip */
|
||||
#define ED_CONTROL_F (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_s
|
||||
{
|
||||
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_s
|
||||
{
|
||||
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_s
|
||||
{
|
||||
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_s
|
||||
{
|
||||
/* 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,24 @@
|
||||
/*
|
||||
* 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_hc_ohci.h"
|
||||
|
||||
#define OHCI_HCOR ((struct ohci_hcor *)(uintptr_t)(bus->hcd.reg_base + CONFIG_USB_OHCI_HCOR_OFFSET))
|
||||
|
||||
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
|
Reference in New Issue
Block a user