diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/common/tusb_mcu.h | 12 | ||||
| -rw-r--r-- | src/portable/chipidea/ci_hs/ci_hs_hpm.h | 54 | ||||
| -rw-r--r-- | src/portable/chipidea/ci_hs/dcd_ci_hs.c | 402 | ||||
| -rw-r--r-- | src/portable/chipidea/ci_hs/hcd_ci_hs.c | 41 | ||||
| -rw-r--r-- | src/portable/ehci/ehci.c | 12 | ||||
| -rw-r--r-- | src/tusb_option.h | 3 |
6 files changed, 298 insertions, 226 deletions
diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h index 89316ee77..55f7e0b7c 100644 --- a/src/common/tusb_mcu.h +++ b/src/common/tusb_mcu.h @@ -661,6 +661,18 @@ #define TUP_USBIP_DWC2_AT32 #define TUP_DCD_ENDPOINT_MAX 8 +//--------------------------------------------------------------------+ +// HPMicro +//--------------------------------------------------------------------+ +#elif TU_CHECK_MCU(OPT_MCU_HPM) + #define TUP_USBIP_CHIPIDEA_HS + #define TUP_USBIP_EHCI + + #define TUP_DCD_ENDPOINT_MAX 16 + #define TUP_RHPORT_HIGHSPEED 1 + + #define TU_ATTR_FAST_FUNC __attribute__((section(".fast"))) + #endif //--------------------------------------------------------------------+ diff --git a/src/portable/chipidea/ci_hs/ci_hs_hpm.h b/src/portable/chipidea/ci_hs/ci_hs_hpm.h new file mode 100644 index 000000000..68211448c --- /dev/null +++ b/src/portable/chipidea/ci_hs/ci_hs_hpm.h @@ -0,0 +1,54 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021, Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _CI_HS_HPM_H_ +#define _CI_HS_HPM_H_ + +#include "ci_hs_type.h" +#include "hpm_soc.h" +#include "hpm_interrupt.h" +#include "hpm_usb_drv.h" + +static const ci_hs_controller_t _ci_controller[] = +{ + { .reg_base = HPM_USB0_BASE, .irqnum = IRQn_USB0}, + #ifdef HPM_USB1_BASE + { .reg_base = HPM_USB1_BASE, .irqnum = IRQn_USB1}, + #endif +}; + +#define CI_HS_REG(_port) ((ci_hs_regs_t*) _ci_controller[_port].reg_base) + +//------------- DCD -------------// +#define CI_DCD_INT_ENABLE(_p) intc_m_enable_irq (_ci_controller[_p].irqnum) +#define CI_DCD_INT_DISABLE(_p) intc_m_disable_irq(_ci_controller[_p].irqnum) + +//------------- HCD -------------// +#define CI_HCD_INT_ENABLE(_p) intc_m_enable_irq (_ci_controller[_p].irqnum) +#define CI_HCD_INT_DISABLE(_p) intc_m_disable_irq(_ci_controller[_p].irqnum) + + +#endif diff --git a/src/portable/chipidea/ci_hs/dcd_ci_hs.c b/src/portable/chipidea/ci_hs/dcd_ci_hs.c index 27298989c..2bba32ada 100644 --- a/src/portable/chipidea/ci_hs/dcd_ci_hs.c +++ b/src/portable/chipidea/ci_hs/dcd_ci_hs.c @@ -34,19 +34,19 @@ #if CFG_TUSB_MCU == OPT_MCU_MIMXRT1XXX #include "ci_hs_imxrt.h" -#if CFG_TUD_MEM_DCACHE_ENABLE -bool dcd_dcache_clean(void const* addr, uint32_t data_size) { - return imxrt_dcache_clean(addr, data_size); -} + #if CFG_TUD_MEM_DCACHE_ENABLE + bool dcd_dcache_clean(const void *addr, uint32_t data_size) { + return imxrt_dcache_clean(addr, data_size); + } -bool dcd_dcache_invalidate(void const* addr, uint32_t data_size) { - return imxrt_dcache_invalidate(addr, data_size); -} + bool dcd_dcache_invalidate(const void *addr, uint32_t data_size) { + return imxrt_dcache_invalidate(addr, data_size); + } -bool dcd_dcache_clean_invalidate(void const* addr, uint32_t data_size) { - return imxrt_dcache_clean_invalidate(addr, data_size); -} -#endif + bool dcd_dcache_clean_invalidate(const void *addr, uint32_t data_size) { + return imxrt_dcache_clean_invalidate(addr, data_size); + } + #endif #elif TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX) #include "ci_hs_lpc18_43.h" @@ -55,6 +55,9 @@ bool dcd_dcache_clean_invalidate(void const* addr, uint32_t data_size) { // MCX N9 only port 1 use this controller #include "ci_hs_mcx.h" +#elif TU_CHECK_MCU(OPT_MCU_HPM) + #include "ci_hs_hpm.h" + #elif TU_CHECK_MCU(OPT_MCU_RW61X) #include "ci_hs_rw61x.h" @@ -79,7 +82,7 @@ enum { }; #define ENDPTCTRL_TYPE(_type) ((_type) << ENDPTCTRL_TYPE_POS) - #define ENDPTCTRL_RESET_MASK (ENDPTCTRL_TYPE(TUSB_XFER_BULK) | (ENDPTCTRL_TYPE(TUSB_XFER_BULK) << 16u)) +#define ENDPTCTRL_RESET_MASK (ENDPTCTRL_TYPE(TUSB_XFER_BULK) | (ENDPTCTRL_TYPE(TUSB_XFER_BULK) << 16u)) // USBSTS, USBINTR enum { @@ -93,26 +96,28 @@ enum { }; // Queue Transfer Descriptor -typedef struct -{ +typedef struct { // Word 0: Next QTD Pointer uint32_t next; ///< Next link pointer This field contains the physical memory address of the next dTD to be processed // Word 1: qTQ Token - uint32_t : 3 ; - volatile uint32_t xact_err : 1 ; - uint32_t : 1 ; - volatile uint32_t buffer_err : 1 ; - volatile uint32_t halted : 1 ; - volatile uint32_t active : 1 ; - uint32_t : 2 ; - uint32_t iso_mult_override : 2 ; ///< This field can be used for transmit ISOs to override the MULT field in the dQH. This field must be zero for all packet types that are not transmit-ISO. - uint32_t : 3 ; - uint32_t int_on_complete : 1 ; - volatile uint32_t total_bytes : 15 ; - uint32_t : 1 ; + uint32_t : 3; + volatile uint32_t xact_err : 1; + uint32_t : 1; + volatile uint32_t buffer_err : 1; + volatile uint32_t halted : 1; + volatile uint32_t active : 1; + uint32_t : 2; + uint32_t iso_mult_override : 2; ///< This field can be used for transmit ISOs to override the MULT field in the dQH. + ///< This field must be zero for all packet types that are not transmit-ISO. + uint32_t : 3; + uint32_t int_on_complete : 1; + volatile uint32_t total_bytes : 15; + uint32_t : 1; - // Word 2-6: Buffer Page Pointer List, Each element in the list is a 4K page aligned, physical memory address. The lower 12 bits in each pointer are reserved (except for the first one) as each memory pointer must reference the start of a 4K page + // Word 2-6: Buffer Page Pointer List, Each element in the list is a 4K page aligned, physical memory address. The + // lower 12 bits in each pointer are reserved (except for the first one) as each memory pointer must reference the + // start of a 4K page uint32_t buffer[5]; ///< buffer1 has frame_n for TODO Isochronous //--------------------------------------------------------------------+ @@ -120,21 +125,28 @@ typedef struct // Therefore there are 4 bytes padding that we can use. //--------------------------------------------------------------------+ uint16_t expected_bytes; - uint8_t reserved[2]; + uint8_t reserved[2]; } dcd_qtd_t; -TU_VERIFY_STATIC( sizeof(dcd_qtd_t) == 32, "size is not correct"); +TU_VERIFY_STATIC(sizeof(dcd_qtd_t) == 32, "size is not correct"); // Queue Head -typedef struct -{ +typedef struct { // Word 0: Capabilities and Characteristics - uint32_t : 15 ; ///< Number of packets executed per transaction descriptor 00 - Execute N transactions as demonstrated by the USB variable length protocol where N is computed using Max_packet_length and the Total_bytes field in the dTD. 01 - Execute one transaction 10 - Execute two transactions 11 - Execute three transactions Remark: Non-isochronous endpoints must set MULT = 00. Remark: Isochronous endpoints must set MULT = 01, 10, or 11 as needed. - uint32_t int_on_setup : 1 ; ///< Interrupt on setup This bit is used on control type endpoints to indicate if USBINT is set in response to a setup being received. - uint32_t max_packet_size : 11 ; ///< Endpoint's wMaxPacketSize - uint32_t : 2 ; - uint32_t zero_length_termination : 1 ; ///< This bit is used for non-isochronous endpoints to indicate when a zero-length packet is received to terminate transfers in case the total transfer length is “multiple”. 0 - Enable zero-length packet to terminate transfers equal to a multiple of Max_packet_length (default). 1 - Disable zero-length packet on transfers that are equal in length to a multiple Max_packet_length. - uint32_t iso_mult : 2 ; ///< + uint32_t : 15; ///< Number of packets executed per transaction descriptor 00 - Execute N transactions as demonstrated + ///< by the USB variable length protocol where N is computed using Max_packet_length and the + ///< Total_bytes field in the dTD. 01 - Execute one transaction 10 - Execute two transactions 11 - + ///< Execute three transactions Remark: Non-isochronous endpoints must set MULT = 00. Remark: + ///< Isochronous endpoints must set MULT = 01, 10, or 11 as needed. + uint32_t int_on_setup : 1; ///< Interrupt on setup This bit is used on control type endpoints to indicate if USBINT is + ///< set in response to a setup being received. + uint32_t max_packet_size : 11; ///< Endpoint's wMaxPacketSize + uint32_t : 2; + uint32_t zero_length_termination : 1; ///< This bit is used for non-isochronous endpoints to indicate when a zero-length packet is received to + ///< terminate transfers in case the total transfer length is “multiple”. 0 - Enable zero-length packet to + ///< terminate transfers equal to a multiple of Max_packet_length (default). 1 - Disable zero-length packet on + ///< transfers that are equal in length to a multiple Max_packet_length. + uint32_t iso_mult : 2; ///< // Word 1: Current qTD Pointer volatile uint32_t qtd_addr; @@ -149,11 +161,11 @@ typedef struct // QHD is 64 bytes aligned but occupies only 48 bytes // Therefore there are 16 bytes padding that we can use. //--------------------------------------------------------------------+ - tu_fifo_t * ff; - uint8_t reserved[12]; + tu_fifo_t *ff; + uint8_t reserved[12]; } dcd_qhd_t; -TU_VERIFY_STATIC( sizeof(dcd_qhd_t) == 64, "size is not correct"); +TU_VERIFY_STATIC(sizeof(dcd_qhd_t) == 64, "size is not correct"); //--------------------------------------------------------------------+ // Variables @@ -167,10 +179,9 @@ typedef struct { // for portability, TinyUSB only queue 1 TD for each Qhd dcd_qhd_t qhd[TUP_DCD_ENDPOINT_MAX][2] TU_ATTR_ALIGNED(64); dcd_qtd_t qtd[TUP_DCD_ENDPOINT_MAX][2] TU_ATTR_ALIGNED(32); -}dcd_data_t; +} dcd_data_t; -CFG_TUD_MEM_SECTION TU_ATTR_ALIGNED(2048) -static dcd_data_t _dcd_data; +CFG_TUD_MEM_SECTION TU_ATTR_ALIGNED(2048) static dcd_data_t _dcd_data; //--------------------------------------------------------------------+ // Prototypes and Helper Functions @@ -185,16 +196,15 @@ TU_ATTR_ALWAYS_INLINE static inline uint8_t ci_ep_count(const ci_hs_regs_t *dcd_ //--------------------------------------------------------------------+ /// follows LPC43xx User Manual 23.10.3 -static void bus_reset(uint8_t rhport) -{ - ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport); +static void bus_reset(uint8_t rhport) { + ci_hs_regs_t *dcd_reg = CI_HS_REG(rhport); // The reset value for all endpoint types is the control endpoint. If one endpoint // direction is enabled and the paired endpoint of opposite direction is disabled, then the // endpoint type of the unused direction must be changed from the control type to any other // type (e.g. bulk). Leaving an un-configured endpoint control will cause undefined behavior // for the data PID tracking on the active endpoint. - uint8_t const ep_count = ci_ep_count(dcd_reg); + const uint8_t ep_count = ci_ep_count(dcd_reg); for (uint8_t i = 1; i < ep_count; i++) { dcd_reg->ENDPTCTRL[i] = ENDPTCTRL_RESET_MASK; } @@ -217,7 +227,7 @@ static void bus_reset(uint8_t rhport) //------------- Set up Control Endpoints (0 OUT, 1 IN) -------------// _dcd_data.qhd[0][0].zero_length_termination = _dcd_data.qhd[0][1].zero_length_termination = 1; - _dcd_data.qhd[0][0].max_packet_size = _dcd_data.qhd[0][1].max_packet_size = CFG_TUD_ENDPOINT0_SIZE; + _dcd_data.qhd[0][0].max_packet_size = _dcd_data.qhd[0][1].max_packet_size = CFG_TUD_ENDPOINT0_SIZE; _dcd_data.qhd[0][0].qtd_overlay.next = _dcd_data.qhd[0][1].qtd_overlay.next = QTD_NEXT_INVALID; _dcd_data.qhd[0][0].int_on_setup = 1; // OUT only @@ -225,92 +235,93 @@ static void bus_reset(uint8_t rhport) dcd_dcache_clean_invalidate(&_dcd_data, sizeof(dcd_data_t)); } -bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { - (void) rh_init; +bool dcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init) { + (void)rh_init; tu_memclr(&_dcd_data, sizeof(dcd_data_t)); - ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport); + ci_hs_regs_t *dcd_reg = CI_HS_REG(rhport); TU_ASSERT(ci_ep_count(dcd_reg) <= TUP_DCD_ENDPOINT_MAX); + #if TU_CHECK_MCU(OPT_MCU_HPM) + usb_phy_init((USB_Type *)dcd_reg, false); + #endif + // Reset controller dcd_reg->USBCMD |= USBCMD_RESET; - while( dcd_reg->USBCMD & USBCMD_RESET ) {} + while (dcd_reg->USBCMD & USBCMD_RESET) {} // Set mode to device, must be set immediately after reset uint32_t usbmode = dcd_reg->USBMODE & ~USBMOD_CM_MASK; usbmode |= USBMODE_CM_DEVICE; dcd_reg->USBMODE = usbmode; -#ifdef CFG_TUD_CI_HS_VBUS_CHARGE + #ifdef CFG_TUD_CI_HS_VBUS_CHARGE dcd_reg->OTGSC = OTGSC_VBUS_CHARGE | OTGSC_OTG_TERMINATION; -#else + #else dcd_reg->OTGSC = OTGSC_VBUS_DISCHARGE | OTGSC_OTG_TERMINATION; -#endif + #endif -#if !TUD_OPT_HIGH_SPEED - dcd_reg->PORTSC1 = PORTSC1_FORCE_FULL_SPEED; -#endif + #if !TUD_OPT_HIGH_SPEED + dcd_reg->PORTSC1 |= PORTSC1_FORCE_FULL_SPEED; + #endif + + #if TU_CHECK_MCU(OPT_MCU_HPM) + dcd_reg->PORTSC1 &= ~USB_PORTSC1_STS_MASK; + #endif dcd_dcache_clean_invalidate(&_dcd_data, sizeof(dcd_data_t)); - dcd_reg->ENDPTLISTADDR = (uint32_t) _dcd_data.qhd; // Endpoint List Address has to be 2K alignment - dcd_reg->USBSTS = dcd_reg->USBSTS; - dcd_reg->USBINTR = INTR_USB | INTR_ERROR | INTR_PORT_CHANGE | INTR_SUSPEND; + dcd_reg->ENDPTLISTADDR = (uint32_t)_dcd_data.qhd; // Endpoint List Address has to be 2K alignment + dcd_reg->USBSTS = dcd_reg->USBSTS; + dcd_reg->USBINTR = INTR_USB | INTR_ERROR | INTR_PORT_CHANGE | INTR_SUSPEND; uint32_t usbcmd = dcd_reg->USBCMD; usbcmd &= ~USBCMD_INTR_THRESHOLD_MASK; // Interrupt Threshold Interval = 0 - usbcmd |= USBCMD_RUN_STOP; // run + usbcmd |= USBCMD_RUN_STOP; // run dcd_reg->USBCMD = usbcmd; return true; } -void dcd_int_enable(uint8_t rhport) -{ +void dcd_int_enable(uint8_t rhport) { CI_DCD_INT_ENABLE(rhport); } -void dcd_int_disable(uint8_t rhport) -{ +void dcd_int_disable(uint8_t rhport) { CI_DCD_INT_DISABLE(rhport); } -void dcd_set_address(uint8_t rhport, uint8_t dev_addr) -{ +void dcd_set_address(uint8_t rhport, uint8_t dev_addr) { // Response with status first before changing device address dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0, false); - ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport); - dcd_reg->DEVICEADDR = (dev_addr << 25) | TU_BIT(24); + ci_hs_regs_t *dcd_reg = CI_HS_REG(rhport); + dcd_reg->DEVICEADDR = (dev_addr << 25) | TU_BIT(24); } -void dcd_remote_wakeup(uint8_t rhport) -{ - ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport); +void dcd_remote_wakeup(uint8_t rhport) { + ci_hs_regs_t *dcd_reg = CI_HS_REG(rhport); dcd_reg->PORTSC1 |= PORTSC1_FORCE_PORT_RESUME; } -void dcd_connect(uint8_t rhport) -{ - ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport); +void dcd_connect(uint8_t rhport) { + ci_hs_regs_t *dcd_reg = CI_HS_REG(rhport); dcd_reg->USBCMD |= USBCMD_RUN_STOP; } -void dcd_disconnect(uint8_t rhport) -{ - ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport); +void dcd_disconnect(uint8_t rhport) { + ci_hs_regs_t *dcd_reg = CI_HS_REG(rhport); dcd_reg->USBCMD &= ~USBCMD_RUN_STOP; } -void dcd_sof_enable(uint8_t rhport, bool en) -{ - ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport); +void dcd_sof_enable(uint8_t rhport, bool en) { + ci_hs_regs_t *dcd_reg = CI_HS_REG(rhport); if (en) { - dcd_reg->USBINTR |= INTR_SOF; + dcd_reg->USBINTR |= INTR_SOF; } else { - dcd_reg->USBINTR &= ~INTR_SOF; + dcd_reg->USBINTR &= ~INTR_SOF; } } @@ -377,26 +388,24 @@ TU_ATTR_ALWAYS_INLINE static inline void ep_ctrl_clear(volatile uint32_t *epctrl ep_ctrl_mask(epctrl, dir, ~mask, 0); } -void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) -{ - uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); +void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { + const uint8_t epnum = tu_edpt_number(ep_addr); + const uint8_t dir = tu_edpt_dir(ep_addr); - ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport); + ci_hs_regs_t *dcd_reg = CI_HS_REG(rhport); dcd_reg->ENDPTCTRL[epnum] |= ENDPTCTRL_STALL << (dir ? 16 : 0); // flush to abort any primed buffer dcd_reg->ENDPTFLUSH = TU_BIT(epnum + (dir ? 16 : 0)); } -void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) -{ - uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); +void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { + const uint8_t epnum = tu_edpt_number(ep_addr); + const uint8_t dir = tu_edpt_dir(ep_addr); // data toggle also need to be reset - ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport); - dcd_reg->ENDPTCTRL[epnum] |= ENDPTCTRL_TOGGLE_RESET << ( dir ? 16 : 0 ); + ci_hs_regs_t *dcd_reg = CI_HS_REG(rhport); + dcd_reg->ENDPTCTRL[epnum] |= ENDPTCTRL_TOGGLE_RESET << (dir ? 16 : 0); dcd_reg->ENDPTCTRL[epnum] &= ~(ENDPTCTRL_STALL << (dir ? 16 : 0)); } @@ -474,7 +483,7 @@ void dcd_edpt_close_all(uint8_t rhport) { ci_hs_regs_t *dcd_reg = CI_HS_REG(rhport); // Disable all non-control endpoints - uint8_t const ep_count = ci_ep_count(dcd_reg); + const uint8_t ep_count = ci_ep_count(dcd_reg); for (uint8_t epnum = 1; epnum < ep_count; epnum++) { _dcd_data.qhd[epnum][TUSB_DIR_OUT].qtd_overlay.halted = 1; _dcd_data.qhd[epnum][TUSB_DIR_IN].qtd_overlay.halted = 1; @@ -484,37 +493,34 @@ void dcd_edpt_close_all(uint8_t rhport) { } } -static void qhd_start_xfer(uint8_t rhport, uint8_t epnum, uint8_t dir) -{ - ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport); - dcd_qhd_t* p_qhd = &_dcd_data.qhd[epnum][dir]; - dcd_qtd_t* p_qtd = &_dcd_data.qtd[epnum][dir]; +static void qhd_start_xfer(uint8_t rhport, uint8_t epnum, uint8_t dir) { + ci_hs_regs_t *dcd_reg = CI_HS_REG(rhport); + dcd_qhd_t *p_qhd = &_dcd_data.qhd[epnum][dir]; + dcd_qtd_t *p_qtd = &_dcd_data.qtd[epnum][dir]; - p_qhd->qtd_overlay.halted = false; // clear any previous error - p_qhd->qtd_overlay.next = (uint32_t) p_qtd; // link qtd to qhd + p_qhd->qtd_overlay.halted = false; // clear any previous error + p_qhd->qtd_overlay.next = (uint32_t)p_qtd; // link qtd to qhd // flush cache dcd_dcache_clean_invalidate(&_dcd_data, sizeof(dcd_data_t)); - if ( epnum == 0 ) - { + if (epnum == 0) { // follows UM 24.10.8.1.1 Setup packet handling using setup lockout mechanism // wait until ENDPTSETUPSTAT before priming data/status in response TODO add time out - while(dcd_reg->ENDPTSETUPSTAT & TU_BIT(0)) {} + while (dcd_reg->ENDPTSETUPSTAT & TU_BIT(0)) {} } // start transfer dcd_reg->ENDPTPRIME = TU_BIT(epnum + (dir ? 16 : 0)); } -bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, bool is_isr) -{ - (void) is_isr; - uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes, bool is_isr) { + (void)is_isr; + const uint8_t epnum = tu_edpt_number(ep_addr); + const uint8_t dir = tu_edpt_dir(ep_addr); - dcd_qhd_t* p_qhd = &_dcd_data.qhd[epnum][dir]; - dcd_qtd_t* p_qtd = &_dcd_data.qtd[epnum][dir]; + dcd_qhd_t *p_qhd = &_dcd_data.qhd[epnum][dir]; + dcd_qtd_t *p_qtd = &_dcd_data.qtd[epnum][dir]; // Prepare qtd qtd_init(p_qtd, buffer, total_bytes); @@ -526,58 +532,47 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t return true; } -#if !CFG_TUD_MEM_DCACHE_ENABLE + #if !CFG_TUD_MEM_DCACHE_ENABLE // fifo has to be aligned to 4k boundary // It's incompatible with dcache enabled transfer, since neither address nor size is aligned to cache line -bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes, bool is_isr) -{ - (void) is_isr; - uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); +bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t *ff, uint16_t total_bytes, bool is_isr) { + (void)is_isr; + const uint8_t epnum = tu_edpt_number(ep_addr); + const uint8_t dir = tu_edpt_dir(ep_addr); - dcd_qhd_t * p_qhd = &_dcd_data.qhd[epnum][dir]; - dcd_qtd_t * p_qtd = &_dcd_data.qtd[epnum][dir]; + dcd_qhd_t *p_qhd = &_dcd_data.qhd[epnum][dir]; + dcd_qtd_t *p_qtd = &_dcd_data.qtd[epnum][dir]; tu_fifo_buffer_info_t fifo_info; - if (dir) - { + if (dir) { tu_fifo_get_read_info(ff, &fifo_info); - } else - { + } else { tu_fifo_get_write_info(ff, &fifo_info); } - if ( fifo_info.linear.len >= total_bytes ) - { + if (fifo_info.linear.len >= total_bytes) { // Linear length is enough for this transfer qtd_init(p_qtd, fifo_info.linear.ptr, total_bytes); - } - else - { + } else { // linear part is not enough // prepare TD up to linear length qtd_init(p_qtd, fifo_info.linear.ptr, fifo_info.linear.len); - if ( !tu_offset4k((uint32_t) fifo_info.wrapped.ptr) && !tu_offset4k(tu_fifo_depth(ff)) ) - { + if (!tu_offset4k((uint32_t)fifo_info.wrapped.ptr) && !tu_offset4k(tu_fifo_depth(ff))) { // If buffer is aligned to 4K & buffer size is multiple of 4K // We can make use of buffer page array to also combine the linear + wrapped length p_qtd->total_bytes = p_qtd->expected_bytes = total_bytes; - for(uint8_t i = 1, page = 0; i < 5; i++) - { + for (uint8_t i = 1, page = 0; i < 5; i++) { // pick up buffer array where linear ends - if (p_qtd->buffer[i] == 0) - { - p_qtd->buffer[i] = (uint32_t) fifo_info.wrapped.ptr + 4096 * page; + if (p_qtd->buffer[i] == 0) { + p_qtd->buffer[i] = (uint32_t)fifo_info.wrapped.ptr + 4096 * page; page++; } } - } - else - { + } else { // TODO we may need to carry the wrapped length after the linear part complete // for now only transfer up to linear part } @@ -589,36 +584,32 @@ bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_ return true; } -#endif + #endif //--------------------------------------------------------------------+ // ISR //--------------------------------------------------------------------+ -static void process_edpt_complete_isr(uint8_t rhport, uint8_t epnum, uint8_t dir) -{ - dcd_qhd_t * p_qhd = &_dcd_data.qhd[epnum][dir]; - dcd_qtd_t * p_qtd = &_dcd_data.qtd[epnum][dir]; +static void process_edpt_complete_isr(uint8_t rhport, uint8_t epnum, uint8_t dir) { + dcd_qhd_t *p_qhd = &_dcd_data.qhd[epnum][dir]; + dcd_qtd_t *p_qtd = &_dcd_data.qtd[epnum][dir]; - uint8_t result = p_qtd->halted ? XFER_RESULT_STALLED : - ( p_qtd->xact_err || p_qtd->buffer_err ) ? XFER_RESULT_FAILED : XFER_RESULT_SUCCESS; + uint8_t result = p_qtd->halted ? XFER_RESULT_STALLED + : (p_qtd->xact_err || p_qtd->buffer_err) ? XFER_RESULT_FAILED + : XFER_RESULT_SUCCESS; - if ( result != XFER_RESULT_SUCCESS ) - { - ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport); + if (result != XFER_RESULT_SUCCESS) { + ci_hs_regs_t *dcd_reg = CI_HS_REG(rhport); // flush to abort error buffer dcd_reg->ENDPTFLUSH = TU_BIT(epnum + (dir ? 16 : 0)); } - uint16_t const xferred_bytes = p_qtd->expected_bytes - p_qtd->total_bytes; + const uint16_t xferred_bytes = p_qtd->expected_bytes - p_qtd->total_bytes; - if (p_qhd->ff) - { - if (dir == TUSB_DIR_IN) - { + if (p_qhd->ff) { + if (dir == TUSB_DIR_IN) { tu_fifo_advance_read_pointer(p_qhd->ff, xferred_bytes); - } else - { + } else { tu_fifo_advance_write_pointer(p_qhd->ff, xferred_bytes); } } @@ -627,82 +618,74 @@ static void process_edpt_complete_isr(uint8_t rhport, uint8_t epnum, uint8_t dir dcd_event_xfer_complete(rhport, tu_edpt_addr(epnum, dir), xferred_bytes, result, true); } -void dcd_int_handler(uint8_t rhport) -{ - ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport); +void dcd_int_handler(uint8_t rhport) { + ci_hs_regs_t *dcd_reg = CI_HS_REG(rhport); - uint32_t const int_enable = dcd_reg->USBINTR; - uint32_t const int_status = dcd_reg->USBSTS & int_enable; - dcd_reg->USBSTS = int_status; // Acknowledge handled interrupt + const uint32_t int_enable = dcd_reg->USBINTR; + const uint32_t int_status = dcd_reg->USBSTS & int_enable; + dcd_reg->USBSTS = int_status; // Acknowledge handled interrupt // disabled interrupt sources - if (int_status == 0) return; + if (int_status == 0) { + return; + } // Set if the port controller enters the full or high-speed operational state. // either from Bus Reset or Suspended state - if (int_status & INTR_PORT_CHANGE) - { - // TU_LOG2("PortChange %08lx\r\n", dcd_reg->PORTSC1); + if (int_status & INTR_PORT_CHANGE) { + // TU_LOG2("PortChange %08lx\r\n", dcd_reg->PORTSC1); - // Reset interrupt is not enabled, we manually check if Port Change is due - // to connection / disconnection - if ( dcd_reg->USBSTS & INTR_RESET ) - { - dcd_reg->USBSTS = INTR_RESET; + // Reset interrupt is not enabled, we manually check if Port Change is due + // to connection / disconnection + if (dcd_reg->USBSTS & INTR_RESET) { + dcd_reg->USBSTS = INTR_RESET; - if (dcd_reg->PORTSC1 & PORTSC1_CURRENT_CONNECT_STATUS) - { - uint32_t const speed = (dcd_reg->PORTSC1 & PORTSC1_PORT_SPEED) >> PORTSC1_PORT_SPEED_POS; - bus_reset(rhport); - dcd_event_bus_reset(rhport, (tusb_speed_t) speed, true); - }else - { - dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true); - } - } - else - { - // Triggered by resuming from suspended state - if ( !(dcd_reg->PORTSC1 & PORTSC1_SUSPEND) ) - { - dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true); - } - } - } + if (dcd_reg->PORTSC1 & PORTSC1_CURRENT_CONNECT_STATUS) { + const uint32_t speed = (dcd_reg->PORTSC1 & PORTSC1_PORT_SPEED) >> PORTSC1_PORT_SPEED_POS; + bus_reset(rhport); + dcd_event_bus_reset(rhport, (tusb_speed_t)speed, true); + } else { + dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true); + } + } else { + // Triggered by resuming from suspended state + if (!(dcd_reg->PORTSC1 & PORTSC1_SUSPEND)) { + dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true); + } + } + } - if (int_status & INTR_SUSPEND) - { + if (int_status & INTR_SUSPEND) { // TU_LOG2("Suspend %08lx\r\n", dcd_reg->PORTSC1); - if (dcd_reg->PORTSC1 & PORTSC1_SUSPEND) - { + if (dcd_reg->PORTSC1 & PORTSC1_SUSPEND) { // Note: Host may delay more than 3 ms before and/or after bus reset before doing enumeration. // Skip suspend event if we are not addressed - if ((dcd_reg->DEVICEADDR >> 25) & 0x0f) - { + if ((dcd_reg->DEVICEADDR >> 25) & 0x0f) { dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true); } } } - if (int_status & INTR_USB) - { + if (int_status & INTR_USB) { // Make sure we read the latest version of _dcd_data. dcd_dcache_clean_invalidate(&_dcd_data, sizeof(dcd_data_t)); - uint32_t const edpt_complete = dcd_reg->ENDPTCOMPLETE; - dcd_reg->ENDPTCOMPLETE = edpt_complete; // acknowledge + const uint32_t edpt_complete = dcd_reg->ENDPTCOMPLETE; + dcd_reg->ENDPTCOMPLETE = edpt_complete; // acknowledge // 23.10.12.3 Failed QTD also get ENDPTCOMPLETE set // nothing to do, we will submit xfer as error to usbd // if (int_status & INTR_ERROR) { } - if ( edpt_complete ) - { - for(uint8_t epnum = 0; epnum < TUP_DCD_ENDPOINT_MAX; epnum++) - { - if ( tu_bit_test(edpt_complete, epnum) ) process_edpt_complete_isr(rhport, epnum, TUSB_DIR_OUT); - if ( tu_bit_test(edpt_complete, epnum+16) ) process_edpt_complete_isr(rhport, epnum, TUSB_DIR_IN); + if (edpt_complete) { + for (uint8_t epnum = 0; epnum < TUP_DCD_ENDPOINT_MAX; epnum++) { + if (tu_bit_test(edpt_complete, epnum)) { + process_edpt_complete_isr(rhport, epnum, TUSB_DIR_OUT); + } + if (tu_bit_test(edpt_complete, epnum + 16)) { + process_edpt_complete_isr(rhport, epnum, TUSB_DIR_IN); + } } } @@ -712,12 +695,11 @@ void dcd_int_handler(uint8_t rhport) // in the same frame and we should handle previous status first. if (dcd_reg->ENDPTSETUPSTAT) { dcd_reg->ENDPTSETUPSTAT = dcd_reg->ENDPTSETUPSTAT; - dcd_event_setup_received(rhport, (uint8_t *) (uintptr_t) &_dcd_data.qhd[0][0].setup_request, true); + dcd_event_setup_received(rhport, (uint8_t *)(uintptr_t)&_dcd_data.qhd[0][0].setup_request, true); } } - if (int_status & INTR_SOF) - { + if (int_status & INTR_SOF) { const uint32_t frame = dcd_reg->FRINDEX; dcd_event_sof(rhport, frame, true); } diff --git a/src/portable/chipidea/ci_hs/hcd_ci_hs.c b/src/portable/chipidea/ci_hs/hcd_ci_hs.c index fe2895f6a..29ce0cd7f 100644 --- a/src/portable/chipidea/ci_hs/hcd_ci_hs.c +++ b/src/portable/chipidea/ci_hs/hcd_ci_hs.c @@ -41,31 +41,36 @@ #if CFG_TUSB_MCU == OPT_MCU_MIMXRT1XXX -#include "ci_hs_imxrt.h" + #include "ci_hs_imxrt.h" -#if CFG_TUH_MEM_DCACHE_ENABLE -bool hcd_dcache_clean(void const* addr, uint32_t data_size) { + #if CFG_TUH_MEM_DCACHE_ENABLE +bool hcd_dcache_clean(const void *addr, uint32_t data_size) { return imxrt_dcache_clean(addr, data_size); } -bool hcd_dcache_invalidate(void const* addr, uint32_t data_size) { +bool hcd_dcache_invalidate(const void *addr, uint32_t data_size) { return imxrt_dcache_invalidate(addr, data_size); } -bool hcd_dcache_clean_invalidate(void const* addr, uint32_t data_size) { +bool hcd_dcache_clean_invalidate(const void *addr, uint32_t data_size) { return imxrt_dcache_clean_invalidate(addr, data_size); } -#endif + #endif #elif TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX) -#include "ci_hs_lpc18_43.h" + #include "ci_hs_lpc18_43.h" + +#elif TU_CHECK_MCU(OPT_MCU_HPM) + + #include "ci_hs_hpm.h" #elif TU_CHECK_MCU(OPT_MCU_RW61X) -#include "ci_hs_rw61x.h" + + #include "ci_hs_rw61x.h" #else -#error "Unsupported MCUs" + #error "Unsupported MCUs" #endif //--------------------------------------------------------------------+ @@ -76,27 +81,31 @@ bool hcd_dcache_clean_invalidate(void const* addr, uint32_t data_size) { // Controller API //--------------------------------------------------------------------+ -bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { - (void) rh_init; +bool hcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init) { + (void)rh_init; ci_hs_regs_t *hcd_reg = CI_HS_REG(rhport); + #if CFG_TUSB_MCU == OPT_MCU_HPM + usb_phy_init((USB_Type *)hcd_reg, true); + #endif + // Reset controller hcd_reg->USBCMD |= USBCMD_RESET; - while ( hcd_reg->USBCMD & USBCMD_RESET ) {} + while (hcd_reg->USBCMD & USBCMD_RESET) {} // Set mode to device, must be set immediately after reset -#if CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX + #if CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX // LPC18XX/43XX need to set VBUS Power Select to HIGH // RHPORT1 is fullspeed only (need external PHY for Highspeed) hcd_reg->USBMODE = USBMODE_CM_HOST | USBMODE_VBUS_POWER_SELECT; if (rhport == 1) { hcd_reg->PORTSC1 |= PORTSC1_FORCE_FULL_SPEED; } -#else + #else hcd_reg->USBMODE = USBMODE_CM_HOST; -#endif + #endif - return ehci_init(rhport, (uint32_t) &hcd_reg->CAPLENGTH, (uint32_t) &hcd_reg->USBCMD); + return ehci_init(rhport, (uint32_t)&hcd_reg->CAPLENGTH, (uint32_t)&hcd_reg->USBCMD); } void hcd_int_enable(uint8_t rhport) { diff --git a/src/portable/ehci/ehci.c b/src/portable/ehci/ehci.c index e604a0360..9b2cf98be 100644 --- a/src/portable/ehci/ehci.c +++ b/src/portable/ehci/ehci.c @@ -44,6 +44,10 @@ #include "fsl_device_registers.h" #endif +#if TU_CHECK_MCU(OPT_MCU_HPM) +#include "ci_hs_hpm.h" +#endif + //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ @@ -237,6 +241,14 @@ void hcd_port_reset(uint8_t rhport) { // mask out Write-1-to-Clear bits uint32_t portsc = regs->portsc & ~EHCI_PORTSC_MASK_W1C; +#if TU_CHECK_MCU(OPT_MCU_HPM) + if (usb_phy_get_line_state((USB_Type *)CI_HS_REG(rhport)) == usb_line_state2) { + portsc |= USB_PORTSC1_STS_MASK; + } else { + portsc &= ~USB_PORTSC1_STS_MASK; + } +#endif + // EHCI Table 2-16 PortSC // when software writes Port Reset bit to a one, it must also write a zero to the Port Enable bit. portsc &= ~(EHCI_PORTSC_MASK_PORT_EANBLED); diff --git a/src/tusb_option.h b/src/tusb_option.h index caf8c4156..64fe899db 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -217,6 +217,9 @@ #define OPT_MCU_AT32F425 2505 ///< ArteryTek AT32F425 #define OPT_MCU_AT32F413 2506 ///< ArteryTek AT32F413 +// HPMicro +#define OPT_MCU_HPM 2600 ///< HPMicro + // Check if configured MCU is one of listed // Apply TU_MCU_IS_EQUAL with || as separator to list of input #define TU_MCU_IS_EQUAL(_m) (CFG_TUSB_MCU == (_m)) |
