summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/tusb_mcu.h12
-rw-r--r--src/portable/chipidea/ci_hs/ci_hs_hpm.h54
-rw-r--r--src/portable/chipidea/ci_hs/dcd_ci_hs.c402
-rw-r--r--src/portable/chipidea/ci_hs/hcd_ci_hs.c41
-rw-r--r--src/portable/ehci/ehci.c12
-rw-r--r--src/tusb_option.h3
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))