mirror of
https://github.com/hathach/tinyusb.git
synced 2025-02-07 05:54:11 +08:00
commit
db59494b1b
@ -22,69 +22,71 @@ set(FAMILY_MCUS MIMXRT1XXX CACHE INTERNAL "")
|
|||||||
#------------------------------------
|
#------------------------------------
|
||||||
# only need to be built ONCE for all examples
|
# only need to be built ONCE for all examples
|
||||||
function(add_board_target BOARD_TARGET)
|
function(add_board_target BOARD_TARGET)
|
||||||
if (NOT TARGET ${BOARD_TARGET})
|
if (TARGET ${BOARD_TARGET})
|
||||||
add_library(${BOARD_TARGET} STATIC
|
return()
|
||||||
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/boards/${BOARD}/board/clock_config.c
|
endif ()
|
||||||
#${SDK_DIR}/drivers/adc_12b1msps_sar/fsl_adc.c
|
|
||||||
${SDK_DIR}/drivers/common/fsl_common.c
|
add_library(${BOARD_TARGET} STATIC
|
||||||
${SDK_DIR}/drivers/igpio/fsl_gpio.c
|
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/boards/${BOARD}/board/clock_config.c
|
||||||
${SDK_DIR}/drivers/lpspi/fsl_lpspi.c
|
#${SDK_DIR}/drivers/adc_12b1msps_sar/fsl_adc.c
|
||||||
${SDK_DIR}/drivers/lpuart/fsl_lpuart.c
|
${SDK_DIR}/drivers/common/fsl_common.c
|
||||||
${SDK_DIR}/devices/${MCU_VARIANT}/system_${MCU_VARIANT}.c
|
${SDK_DIR}/drivers/igpio/fsl_gpio.c
|
||||||
${SDK_DIR}/devices/${MCU_VARIANT}/xip/fsl_flexspi_nor_boot.c
|
${SDK_DIR}/drivers/lpspi/fsl_lpspi.c
|
||||||
${SDK_DIR}/devices/${MCU_VARIANT}/drivers/fsl_clock.c
|
${SDK_DIR}/drivers/lpuart/fsl_lpuart.c
|
||||||
|
${SDK_DIR}/devices/${MCU_VARIANT}/system_${MCU_VARIANT}.c
|
||||||
|
${SDK_DIR}/devices/${MCU_VARIANT}/xip/fsl_flexspi_nor_boot.c
|
||||||
|
${SDK_DIR}/devices/${MCU_VARIANT}/drivers/fsl_clock.c
|
||||||
|
)
|
||||||
|
target_compile_definitions(${BOARD_TARGET} PUBLIC
|
||||||
|
__ARMVFP__=0
|
||||||
|
__ARMFPV5__=0
|
||||||
|
XIP_EXTERNAL_FLASH=1
|
||||||
|
XIP_BOOT_HEADER_ENABLE=1
|
||||||
|
)
|
||||||
|
target_include_directories(${BOARD_TARGET} PUBLIC
|
||||||
|
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/boards/${BOARD}
|
||||||
|
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/boards/${BOARD}/board
|
||||||
|
${CMSIS_DIR}/CMSIS/Core/Include
|
||||||
|
${SDK_DIR}/devices/${MCU_VARIANT}
|
||||||
|
${SDK_DIR}/devices/${MCU_VARIANT}/drivers
|
||||||
|
#${SDK_DIR}/drivers/adc_12b1msps_sar
|
||||||
|
${SDK_DIR}/drivers/common
|
||||||
|
${SDK_DIR}/drivers/igpio
|
||||||
|
${SDK_DIR}/drivers/lpspi
|
||||||
|
${SDK_DIR}/drivers/lpuart
|
||||||
|
)
|
||||||
|
|
||||||
|
update_board(${BOARD_TARGET})
|
||||||
|
|
||||||
|
# LD_FILE and STARTUP_FILE can be defined in board.cmake
|
||||||
|
if (NOT DEFINED LD_FILE_${CMAKE_C_COMPILER_ID})
|
||||||
|
set(LD_FILE_GNU ${SDK_DIR}/devices/${MCU_VARIANT}/gcc/${MCU_VARIANT}xxxxx_flexspi_nor.ld)
|
||||||
|
#set(LD_FILE_IAR ${SDK_DIR}/devices/${MCU_VARIANT}/gcc/${MCU_VARIANT}xxxxx_flexspi_nor.ld)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
if (NOT DEFINED STARTUP_FILE_${CMAKE_C_COMPILER_ID})
|
||||||
|
set(STARTUP_FILE_GNU ${SDK_DIR}/devices/${MCU_VARIANT}/gcc/startup_${MCU_VARIANT}.S)
|
||||||
|
#set(STARTUP_FILE_IAR ${SDK_DIR}/devices/${MCU_VARIANT}/gcc/startup_${MCU_VARIANT}.S)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
target_sources(${BOARD_TARGET} PUBLIC
|
||||||
|
${STARTUP_FILE_${CMAKE_C_COMPILER_ID}}
|
||||||
|
)
|
||||||
|
|
||||||
|
if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
|
||||||
|
target_link_options(${BOARD_TARGET} PUBLIC
|
||||||
|
"LINKER:--script=${LD_FILE_GNU}"
|
||||||
|
# nanolib
|
||||||
|
--specs=nosys.specs
|
||||||
|
--specs=nano.specs
|
||||||
|
# force linker to look for these symbols
|
||||||
|
-Wl,-uimage_vector_table
|
||||||
|
-Wl,-ug_boot_data
|
||||||
)
|
)
|
||||||
target_compile_definitions(${BOARD_TARGET} PUBLIC
|
elseif (CMAKE_C_COMPILER_ID STREQUAL "IAR")
|
||||||
__ARMVFP__=0
|
target_link_options(${BOARD_TARGET} PUBLIC
|
||||||
__ARMFPV5__=0
|
"LINKER:--config=${LD_FILE_IAR}"
|
||||||
XIP_EXTERNAL_FLASH=1
|
|
||||||
XIP_BOOT_HEADER_ENABLE=1
|
|
||||||
)
|
)
|
||||||
target_include_directories(${BOARD_TARGET} PUBLIC
|
|
||||||
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/boards/${BOARD}
|
|
||||||
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/boards/${BOARD}/board
|
|
||||||
${CMSIS_DIR}/CMSIS/Core/Include
|
|
||||||
${SDK_DIR}/devices/${MCU_VARIANT}
|
|
||||||
${SDK_DIR}/devices/${MCU_VARIANT}/drivers
|
|
||||||
#${SDK_DIR}/drivers/adc_12b1msps_sar
|
|
||||||
${SDK_DIR}/drivers/common
|
|
||||||
${SDK_DIR}/drivers/igpio
|
|
||||||
${SDK_DIR}/drivers/lpspi
|
|
||||||
${SDK_DIR}/drivers/lpuart
|
|
||||||
)
|
|
||||||
|
|
||||||
update_board(${BOARD_TARGET})
|
|
||||||
|
|
||||||
# LD_FILE and STARTUP_FILE can be defined in board.cmake
|
|
||||||
if (NOT DEFINED LD_FILE_${CMAKE_C_COMPILER_ID})
|
|
||||||
set(LD_FILE_GNU ${SDK_DIR}/devices/${MCU_VARIANT}/gcc/${MCU_VARIANT}xxxxx_flexspi_nor.ld)
|
|
||||||
#set(LD_FILE_IAR ${SDK_DIR}/devices/${MCU_VARIANT}/gcc/${MCU_VARIANT}xxxxx_flexspi_nor.ld)
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
if (NOT DEFINED STARTUP_FILE_${CMAKE_C_COMPILER_ID})
|
|
||||||
set(STARTUP_FILE_GNU ${SDK_DIR}/devices/${MCU_VARIANT}/gcc/startup_${MCU_VARIANT}.S)
|
|
||||||
#set(STARTUP_FILE_IAR ${SDK_DIR}/devices/${MCU_VARIANT}/gcc/startup_${MCU_VARIANT}.S)
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
target_sources(${BOARD_TARGET} PUBLIC
|
|
||||||
${STARTUP_FILE_${CMAKE_C_COMPILER_ID}}
|
|
||||||
)
|
|
||||||
|
|
||||||
if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
|
|
||||||
target_link_options(${BOARD_TARGET} PUBLIC
|
|
||||||
"LINKER:--script=${LD_FILE_GNU}"
|
|
||||||
# nanolib
|
|
||||||
--specs=nosys.specs
|
|
||||||
--specs=nano.specs
|
|
||||||
# force linker to look for these symbols
|
|
||||||
-Wl,-uimage_vector_table
|
|
||||||
-Wl,-ug_boot_data
|
|
||||||
)
|
|
||||||
elseif (CMAKE_C_COMPILER_ID STREQUAL "IAR")
|
|
||||||
target_link_options(${BOARD_TARGET} PUBLIC
|
|
||||||
"LINKER:--config=${LD_FILE_IAR}"
|
|
||||||
)
|
|
||||||
endif ()
|
|
||||||
endif ()
|
endif ()
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
@ -114,7 +116,7 @@ function(family_configure_example TARGET RTOS)
|
|||||||
|
|
||||||
# Add TinyUSB target and port source
|
# Add TinyUSB target and port source
|
||||||
family_add_tinyusb(${TARGET} OPT_MCU_MIMXRT1XXX ${RTOS})
|
family_add_tinyusb(${TARGET} OPT_MCU_MIMXRT1XXX ${RTOS})
|
||||||
target_sources(${TARGET}-tinyusb PUBLIC
|
target_sources(${TARGET}-tinyusb PRIVATE
|
||||||
${TOP}/src/portable/chipidea/ci_hs/dcd_ci_hs.c
|
${TOP}/src/portable/chipidea/ci_hs/dcd_ci_hs.c
|
||||||
${TOP}/src/portable/chipidea/ci_hs/hcd_ci_hs.c
|
${TOP}/src/portable/chipidea/ci_hs/hcd_ci_hs.c
|
||||||
${TOP}/src/portable/ehci/ehci.c
|
${TOP}/src/portable/ehci/ehci.c
|
||||||
|
@ -64,6 +64,7 @@ function(add_tinyusb TARGET)
|
|||||||
-Wnull-dereference
|
-Wnull-dereference
|
||||||
-Wuninitialized
|
-Wuninitialized
|
||||||
-Wunused
|
-Wunused
|
||||||
|
-Wunused-function
|
||||||
-Wreturn-type
|
-Wreturn-type
|
||||||
-Wredundant-decls
|
-Wredundant-decls
|
||||||
)
|
)
|
||||||
|
@ -45,8 +45,8 @@ typedef struct
|
|||||||
uint8_t itf_num;
|
uint8_t itf_num;
|
||||||
uint8_t ep_in;
|
uint8_t ep_in;
|
||||||
uint8_t port_count;
|
uint8_t port_count;
|
||||||
uint8_t status_change; // data from status change interrupt endpoint
|
|
||||||
|
|
||||||
|
CFG_TUH_MEM_ALIGN uint8_t status_change;
|
||||||
CFG_TUH_MEM_ALIGN hub_port_status_response_t port_status;
|
CFG_TUH_MEM_ALIGN hub_port_status_response_t port_status;
|
||||||
CFG_TUH_MEM_ALIGN hub_status_response_t hub_status;
|
CFG_TUH_MEM_ALIGN hub_status_response_t hub_status;
|
||||||
} hub_interface_t;
|
} hub_interface_t;
|
||||||
|
@ -307,18 +307,18 @@ bool ehci_init(uint8_t rhport, uint32_t capability_reg, uint32_t operatial_reg)
|
|||||||
regs->status = (EHCI_INT_MASK_ALL & ~EHCI_INT_MASK_PORT_CHANGE);
|
regs->status = (EHCI_INT_MASK_ALL & ~EHCI_INT_MASK_PORT_CHANGE);
|
||||||
|
|
||||||
// Enable interrupts
|
// Enable interrupts
|
||||||
regs->inten = EHCI_INT_MASK_ERROR | EHCI_INT_MASK_PORT_CHANGE | EHCI_INT_MASK_ASYNC_ADVANCE |
|
regs->inten = EHCI_INT_MASK_USB | EHCI_INT_MASK_ERROR | EHCI_INT_MASK_PORT_CHANGE |
|
||||||
EHCI_INT_MASK_NXP_PERIODIC | EHCI_INT_MASK_NXP_ASYNC | EHCI_INT_MASK_FRAMELIST_ROLLOVER;
|
EHCI_INT_MASK_ASYNC_ADVANCE | EHCI_INT_MASK_FRAMELIST_ROLLOVER;
|
||||||
|
|
||||||
//------------- Asynchronous List -------------//
|
//------------- Asynchronous List -------------//
|
||||||
ehci_qhd_t * const async_head = list_get_async_head(rhport);
|
ehci_qhd_t * const async_head = list_get_async_head(rhport);
|
||||||
tu_memclr(async_head, sizeof(ehci_qhd_t));
|
tu_memclr(async_head, sizeof(ehci_qhd_t));
|
||||||
|
|
||||||
async_head->next.address = (uint32_t) async_head; // circular list, next is itself
|
async_head->next.address = (uint32_t) async_head; // circular list, next is itself
|
||||||
async_head->next.type = EHCI_QTYPE_QHD;
|
async_head->next.type = EHCI_QTYPE_QHD;
|
||||||
async_head->head_list_flag = 1;
|
async_head->head_list_flag = 1;
|
||||||
async_head->qtd_overlay.halted = 1; // inactive most of time
|
async_head->qtd_overlay.halted = 1; // inactive most of time
|
||||||
async_head->qtd_overlay.next.terminate = 1; // TODO removed if verified
|
async_head->qtd_overlay.next.terminate = 1; // TODO removed if verified
|
||||||
|
|
||||||
regs->async_list_addr = (uint32_t) async_head;
|
regs->async_list_addr = (uint32_t) async_head;
|
||||||
|
|
||||||
@ -443,6 +443,11 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
|
|||||||
ehci_qtd_t* qtd;
|
ehci_qtd_t* qtd;
|
||||||
|
|
||||||
if (epnum == 0) {
|
if (epnum == 0) {
|
||||||
|
// Control endpoint never be stalled. Skip reset Data Toggle since it is fixed per stage
|
||||||
|
if (qhd->qtd_overlay.halted) {
|
||||||
|
qhd->qtd_overlay.halted = false;
|
||||||
|
}
|
||||||
|
|
||||||
qtd = qtd_control(dev_addr);
|
qtd = qtd_control(dev_addr);
|
||||||
qtd_init(qtd, buffer, buflen);
|
qtd_init(qtd, buffer, buflen);
|
||||||
|
|
||||||
@ -450,6 +455,9 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
|
|||||||
qtd->data_toggle = 1;
|
qtd->data_toggle = 1;
|
||||||
qtd->pid = dir ? EHCI_PID_IN : EHCI_PID_OUT;
|
qtd->pid = dir ? EHCI_PID_IN : EHCI_PID_OUT;
|
||||||
} else {
|
} else {
|
||||||
|
// skip if endpoint is halted
|
||||||
|
TU_VERIFY(!qhd->qtd_overlay.halted);
|
||||||
|
|
||||||
qtd = qtd_find_free();
|
qtd = qtd_find_free();
|
||||||
TU_ASSERT(qtd);
|
TU_ASSERT(qtd);
|
||||||
|
|
||||||
@ -506,8 +514,9 @@ bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t daddr, uint8_t ep_addr) {
|
|||||||
(void) rhport;
|
(void) rhport;
|
||||||
ehci_qhd_t *qhd = qhd_get_from_addr(daddr, ep_addr);
|
ehci_qhd_t *qhd = qhd_get_from_addr(daddr, ep_addr);
|
||||||
qhd->qtd_overlay.halted = 0;
|
qhd->qtd_overlay.halted = 0;
|
||||||
|
qhd->qtd_overlay.data_toggle = 0;
|
||||||
hcd_dcache_clean_invalidate(qhd, sizeof(ehci_qhd_t));
|
hcd_dcache_clean_invalidate(qhd, sizeof(ehci_qhd_t));
|
||||||
// TODO reset data toggle ?
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -533,70 +542,74 @@ void async_advance_isr(uint8_t rhport)
|
|||||||
}
|
}
|
||||||
|
|
||||||
TU_ATTR_ALWAYS_INLINE static inline
|
TU_ATTR_ALWAYS_INLINE static inline
|
||||||
void port_connect_status_change_isr(uint8_t rhport)
|
void port_connect_status_change_isr(uint8_t rhport) {
|
||||||
{
|
|
||||||
// NOTE There is an sequence plug->unplug->…..-> plug if device is powering with pre-plugged device
|
// NOTE There is an sequence plug->unplug->…..-> plug if device is powering with pre-plugged device
|
||||||
if (ehci_data.regs->portsc_bm.current_connect_status)
|
if ( ehci_data.regs->portsc_bm.current_connect_status ) {
|
||||||
{
|
|
||||||
hcd_port_reset(rhport);
|
hcd_port_reset(rhport);
|
||||||
hcd_event_device_attach(rhport, true);
|
hcd_event_device_attach(rhport, true);
|
||||||
}else // device unplugged
|
} else // device unplugged
|
||||||
{
|
{
|
||||||
hcd_event_device_remove(rhport, true);
|
hcd_event_device_remove(rhport, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check queue head for potential transfer complete (successful or error)
|
||||||
TU_ATTR_ALWAYS_INLINE static inline
|
TU_ATTR_ALWAYS_INLINE static inline
|
||||||
void qhd_xfer_complete_isr(ehci_qhd_t * qhd) {
|
void qhd_xfer_complete_isr(ehci_qhd_t * qhd) {
|
||||||
// examine TD attached to queue head
|
hcd_dcache_invalidate(qhd, sizeof(ehci_qhd_t)); // HC may have updated the overlay
|
||||||
ehci_qtd_t * volatile qtd = qhd->attached_qtd;
|
volatile ehci_qtd_t *qtd_overlay = &qhd->qtd_overlay;
|
||||||
|
|
||||||
if (qtd == NULL) {
|
// process non-active (completed) QHD with attached (scheduled) TD
|
||||||
return; // no TD attached
|
if ( !qtd_overlay->active && qhd->attached_qtd != NULL ) {
|
||||||
}
|
xfer_result_t xfer_result;
|
||||||
|
|
||||||
hcd_dcache_invalidate(qtd, sizeof(ehci_qtd_t));
|
if ( qtd_overlay->halted ) {
|
||||||
|
if (qtd_overlay->xact_err || qtd_overlay->err_count == 0 || qtd_overlay->buffer_err || qtd_overlay->babble_err) {
|
||||||
// TD is still active, no need to process
|
// Error count = 0 often occurs when device disconnected, or other bus-related error
|
||||||
if (qtd->active) {
|
xfer_result = XFER_RESULT_FAILED;
|
||||||
return;
|
TU_LOG3(" QHD xfer err count: %d\n", qtd_overlay->err_count);
|
||||||
}
|
// TU_BREAKPOINT(); // TODO skip unplugged device
|
||||||
|
}else {
|
||||||
uint8_t dir = (qtd->pid == EHCI_PID_IN) ? 1 : 0;
|
// no error bits are set, endpoint is halted due to STALL
|
||||||
uint32_t const xferred_bytes = qtd->expected_bytes - qtd->total_bytes;
|
xfer_result = XFER_RESULT_STALLED;
|
||||||
|
}
|
||||||
// invalidate dcache if IN transfer
|
} else {
|
||||||
if (dir == 1 && qhd->attached_buffer != 0 && xferred_bytes > 0) {
|
xfer_result = XFER_RESULT_SUCCESS;
|
||||||
hcd_dcache_invalidate((void*) qhd->attached_buffer, xferred_bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove and free TD before invoking callback
|
|
||||||
qhd_remove_qtd(qhd);
|
|
||||||
|
|
||||||
// notify usbh
|
|
||||||
uint8_t const ep_addr = tu_edpt_addr(qhd->ep_number, dir);
|
|
||||||
hcd_event_xfer_complete(qhd->dev_addr, ep_addr, xferred_bytes, XFER_RESULT_SUCCESS, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
TU_ATTR_ALWAYS_INLINE static inline
|
|
||||||
void async_list_xfer_complete_isr(ehci_qhd_t * const async_head)
|
|
||||||
{
|
|
||||||
ehci_qhd_t *p_qhd = async_head;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
hcd_dcache_invalidate(p_qhd, sizeof(ehci_qhd_t));
|
|
||||||
|
|
||||||
// halted or error is processed in error isr
|
|
||||||
if ( !p_qhd->qtd_overlay.halted ) {
|
|
||||||
qhd_xfer_complete_isr(p_qhd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
p_qhd = qhd_next(p_qhd);
|
ehci_qtd_t * volatile qtd = qhd->attached_qtd;
|
||||||
}while(p_qhd != async_head); // async list traversal, stop if loop around
|
hcd_dcache_invalidate(qtd, sizeof(ehci_qtd_t)); // HC may have written back TD
|
||||||
|
|
||||||
|
uint8_t const dir = (qtd->pid == EHCI_PID_IN) ? 1 : 0;
|
||||||
|
uint32_t const xferred_bytes = qtd->expected_bytes - qtd->total_bytes;
|
||||||
|
|
||||||
|
// invalidate dcache if IN transfer with data
|
||||||
|
if (dir == 1 && qhd->attached_buffer != 0 && xferred_bytes > 0) {
|
||||||
|
hcd_dcache_invalidate((void*) qhd->attached_buffer, xferred_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove and free TD before invoking callback
|
||||||
|
qhd_remove_qtd(qhd);
|
||||||
|
|
||||||
|
// notify usbh
|
||||||
|
uint8_t const ep_addr = tu_edpt_addr(qhd->ep_number, dir);
|
||||||
|
hcd_event_xfer_complete(qhd->dev_addr, ep_addr, xferred_bytes, xfer_result, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TU_ATTR_ALWAYS_INLINE static inline
|
TU_ATTR_ALWAYS_INLINE static inline
|
||||||
void period_list_xfer_complete_isr(uint8_t rhport, uint32_t interval_ms)
|
void proccess_async_xfer_isr(ehci_qhd_t * const list_head)
|
||||||
|
{
|
||||||
|
ehci_qhd_t *qhd = list_head;
|
||||||
|
|
||||||
|
do {
|
||||||
|
qhd_xfer_complete_isr(qhd);
|
||||||
|
qhd = qhd_next(qhd);
|
||||||
|
} while ( qhd != list_head ); // async list traversal, stop if loop around
|
||||||
|
}
|
||||||
|
|
||||||
|
TU_ATTR_ALWAYS_INLINE static inline
|
||||||
|
void process_period_xfer_isr(uint8_t rhport, uint32_t interval_ms)
|
||||||
{
|
{
|
||||||
uint32_t const period_1ms_addr = (uint32_t) list_get_period_head(rhport, 1u);
|
uint32_t const period_1ms_addr = (uint32_t) list_get_period_head(rhport, 1u);
|
||||||
ehci_link_t next_link = *list_get_period_head(rhport, interval_ms);
|
ehci_link_t next_link = *list_get_period_head(rhport, interval_ms);
|
||||||
@ -612,22 +625,13 @@ void period_list_xfer_complete_isr(uint8_t rhport, uint32_t interval_ms)
|
|||||||
switch (next_link.type) {
|
switch (next_link.type) {
|
||||||
case EHCI_QTYPE_QHD: {
|
case EHCI_QTYPE_QHD: {
|
||||||
ehci_qhd_t *qhd = (ehci_qhd_t *) entry_addr;
|
ehci_qhd_t *qhd = (ehci_qhd_t *) entry_addr;
|
||||||
hcd_dcache_invalidate(qhd, sizeof(ehci_qhd_t));
|
qhd_xfer_complete_isr(qhd);
|
||||||
|
|
||||||
if (!qhd->qtd_overlay.halted) {
|
|
||||||
qhd_xfer_complete_isr(qhd);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// TODO support hs/fs ISO
|
||||||
case EHCI_QTYPE_ITD:
|
case EHCI_QTYPE_ITD:
|
||||||
// TODO support hs ISO
|
|
||||||
break;
|
|
||||||
|
|
||||||
case EHCI_QTYPE_SITD:
|
case EHCI_QTYPE_SITD:
|
||||||
// TODO support split ISO
|
|
||||||
break;
|
|
||||||
|
|
||||||
case EHCI_QTYPE_FSTN:
|
case EHCI_QTYPE_FSTN:
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -637,106 +641,6 @@ void period_list_xfer_complete_isr(uint8_t rhport, uint32_t interval_ms)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO merge with qhd_xfer_complete_isr()
|
|
||||||
TU_ATTR_ALWAYS_INLINE static inline
|
|
||||||
void qhd_xfer_error_isr(ehci_qhd_t * qhd)
|
|
||||||
{
|
|
||||||
volatile ehci_qtd_t *qtd_overlay = &qhd->qtd_overlay;
|
|
||||||
|
|
||||||
// TD has error
|
|
||||||
if (qtd_overlay->halted) {
|
|
||||||
xfer_result_t xfer_result;
|
|
||||||
|
|
||||||
if (qtd_overlay->xact_err || qtd_overlay->err_count == 0 || qtd_overlay->buffer_err || qtd_overlay->babble_err) {
|
|
||||||
// Error count = 0 often occurs when device disconnected, or other bus-related error
|
|
||||||
xfer_result = XFER_RESULT_FAILED;
|
|
||||||
}else {
|
|
||||||
// no error bits are set, endpoint is halted due to STALL
|
|
||||||
xfer_result = XFER_RESULT_STALLED;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if (XFER_RESULT_FAILED == xfer_result ) {
|
|
||||||
// TU_LOG1(" QHD xfer err count: %d\n", qtd_overlay->err_count);
|
|
||||||
// TU_BREAKPOINT(); // TODO skip unplugged device
|
|
||||||
// }
|
|
||||||
|
|
||||||
ehci_qtd_t * volatile qtd = (ehci_qtd_t * volatile) qhd->attached_qtd;
|
|
||||||
TU_ASSERT(qtd, ); // No TD yet, probably a race condition or cache issue !?
|
|
||||||
|
|
||||||
hcd_dcache_invalidate(qtd, sizeof(ehci_qtd_t));
|
|
||||||
|
|
||||||
uint8_t dir = (qtd->pid == EHCI_PID_IN) ? 1 : 0;
|
|
||||||
uint32_t const xferred_bytes = qtd->expected_bytes - qtd->total_bytes;
|
|
||||||
|
|
||||||
// invalidate dcache if IN transfer
|
|
||||||
if (dir == 1 && qhd->attached_buffer != 0 && xferred_bytes > 0) {
|
|
||||||
hcd_dcache_invalidate((void*) qhd->attached_buffer, xferred_bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove and free TD before invoking callback
|
|
||||||
qhd_remove_qtd(qhd);
|
|
||||||
|
|
||||||
if (0 == qhd->ep_number ) {
|
|
||||||
// control cannot be halted
|
|
||||||
qhd->qtd_overlay.next.terminate = 1;
|
|
||||||
qhd->qtd_overlay.alternate.terminate = 1;
|
|
||||||
qhd->qtd_overlay.halted = 0;
|
|
||||||
|
|
||||||
hcd_dcache_clean(qhd, sizeof(ehci_qhd_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
// notify usbh
|
|
||||||
uint8_t const ep_addr = tu_edpt_addr(qhd->ep_number, dir);
|
|
||||||
hcd_event_xfer_complete(qhd->dev_addr, ep_addr, xferred_bytes, xfer_result, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TU_ATTR_ALWAYS_INLINE static inline
|
|
||||||
void xfer_error_isr(uint8_t rhport)
|
|
||||||
{
|
|
||||||
//------------- async list -------------//
|
|
||||||
ehci_qhd_t * const async_head = list_get_async_head(rhport);
|
|
||||||
ehci_qhd_t *p_qhd = async_head;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
hcd_dcache_invalidate(p_qhd, sizeof(ehci_qhd_t));
|
|
||||||
qhd_xfer_error_isr( p_qhd );
|
|
||||||
p_qhd = qhd_next(p_qhd);
|
|
||||||
}while(p_qhd != async_head); // async list traversal, stop if loop around
|
|
||||||
|
|
||||||
//------------- TODO refractor period list -------------//
|
|
||||||
uint32_t const period_1ms_addr = (uint32_t) list_get_period_head(rhport, 1u);
|
|
||||||
for (uint32_t interval_ms=1; interval_ms <= FRAMELIST_SIZE; interval_ms *= 2)
|
|
||||||
{
|
|
||||||
ehci_link_t next_item = *list_get_period_head(rhport, interval_ms);
|
|
||||||
|
|
||||||
// TODO abstract max loop guard for period
|
|
||||||
while( !next_item.terminate &&
|
|
||||||
!(interval_ms > 1 && period_1ms_addr == tu_align32(next_item.address)) )
|
|
||||||
{
|
|
||||||
switch ( next_item.type )
|
|
||||||
{
|
|
||||||
case EHCI_QTYPE_QHD:
|
|
||||||
{
|
|
||||||
ehci_qhd_t *p_qhd_int = (ehci_qhd_t *) tu_align32(next_item.address);
|
|
||||||
hcd_dcache_invalidate(p_qhd_int, sizeof(ehci_qhd_t));
|
|
||||||
|
|
||||||
qhd_xfer_error_isr(p_qhd_int);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
// TODO support hs/fs ISO
|
|
||||||
case EHCI_QTYPE_ITD:
|
|
||||||
case EHCI_QTYPE_SITD:
|
|
||||||
case EHCI_QTYPE_FSTN:
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
|
|
||||||
next_item = *list_next(&next_item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------- Host Controller Driver's Interrupt Handler -------------//
|
//------------- Host Controller Driver's Interrupt Handler -------------//
|
||||||
void hcd_int_handler(uint8_t rhport)
|
void hcd_int_handler(uint8_t rhport)
|
||||||
{
|
{
|
||||||
@ -768,29 +672,16 @@ void hcd_int_handler(uint8_t rhport)
|
|||||||
regs->status = EHCI_INT_MASK_PORT_CHANGE; // Acknowledge
|
regs->status = EHCI_INT_MASK_PORT_CHANGE; // Acknowledge
|
||||||
}
|
}
|
||||||
|
|
||||||
if (int_status & EHCI_INT_MASK_ERROR) {
|
// A USB transfer is completed (OK or error)
|
||||||
xfer_error_isr(rhport);
|
uint32_t const usb_int = int_status & (EHCI_INT_MASK_USB | EHCI_INT_MASK_ERROR);
|
||||||
regs->status = EHCI_INT_MASK_ERROR; // Acknowledge
|
if (usb_int) {
|
||||||
}
|
proccess_async_xfer_isr(list_get_async_head(rhport));
|
||||||
|
|
||||||
//------------- some QTD/SITD/ITD with IOC set is completed -------------//
|
for ( uint32_t i = 1; i <= FRAMELIST_SIZE; i *= 2 ) {
|
||||||
if (int_status & EHCI_INT_MASK_NXP_ASYNC) {
|
process_period_xfer_isr(rhport, i);
|
||||||
async_list_xfer_complete_isr(list_get_async_head(rhport));
|
|
||||||
regs->status = EHCI_INT_MASK_NXP_ASYNC; // Acknowledge
|
|
||||||
}
|
|
||||||
|
|
||||||
if (int_status & EHCI_INT_MASK_NXP_PERIODIC)
|
|
||||||
{
|
|
||||||
for (uint32_t i=1; i <= FRAMELIST_SIZE; i *= 2)
|
|
||||||
{
|
|
||||||
period_list_xfer_complete_isr(rhport, i);
|
|
||||||
}
|
}
|
||||||
regs->status = EHCI_INT_MASK_NXP_PERIODIC; // Acknowledge
|
|
||||||
}
|
|
||||||
|
|
||||||
if (int_status & EHCI_INT_MASK_USB) {
|
regs->status = usb_int; // Acknowledge
|
||||||
// TODO standard EHCI xfer complete
|
|
||||||
regs->status = EHCI_INT_MASK_USB; // Acknowledge
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------- There is some removed async previously -------------//
|
//------------- There is some removed async previously -------------//
|
||||||
@ -999,8 +890,10 @@ static void qhd_remove_qtd(ehci_qhd_t *qhd) {
|
|||||||
|
|
||||||
qhd->attached_qtd = NULL;
|
qhd->attached_qtd = NULL;
|
||||||
qhd->attached_buffer = 0;
|
qhd->attached_buffer = 0;
|
||||||
|
hcd_dcache_clean(qhd, sizeof(ehci_qhd_t));
|
||||||
|
|
||||||
qtd->used = 0; // free QTD
|
qtd->used = 0; // free QTD
|
||||||
|
hcd_dcache_clean(qtd, sizeof(ehci_qtd_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
@ -1019,8 +912,7 @@ TU_ATTR_ALWAYS_INLINE static inline ehci_qtd_t *qtd_find_free(void) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qtd_init(ehci_qtd_t* qtd, void const* buffer, uint16_t total_bytes)
|
static void qtd_init(ehci_qtd_t* qtd, void const* buffer, uint16_t total_bytes) {
|
||||||
{
|
|
||||||
tu_memclr(qtd, sizeof(ehci_qtd_t));
|
tu_memclr(qtd, sizeof(ehci_qtd_t));
|
||||||
qtd->used = 1;
|
qtd->used = 1;
|
||||||
|
|
||||||
@ -1034,8 +926,7 @@ static void qtd_init(ehci_qtd_t* qtd, void const* buffer, uint16_t total_bytes)
|
|||||||
qtd->expected_bytes = total_bytes;
|
qtd->expected_bytes = total_bytes;
|
||||||
|
|
||||||
qtd->buffer[0] = (uint32_t) buffer;
|
qtd->buffer[0] = (uint32_t) buffer;
|
||||||
for(uint8_t i=1; i<5; i++)
|
for(uint8_t i=1; i<5; i++) {
|
||||||
{
|
|
||||||
qtd->buffer[i] |= tu_align4k(qtd->buffer[i - 1] ) + 4096;
|
qtd->buffer[i] |= tu_align4k(qtd->buffer[i - 1] ) + 4096;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -278,14 +278,10 @@ enum {
|
|||||||
EHCI_INT_MASK_PERIODIC_SCHED_STATUS = TU_BIT(14),
|
EHCI_INT_MASK_PERIODIC_SCHED_STATUS = TU_BIT(14),
|
||||||
EHCI_INT_MASK_ASYNC_SCHED_STATUS = TU_BIT(15),
|
EHCI_INT_MASK_ASYNC_SCHED_STATUS = TU_BIT(15),
|
||||||
|
|
||||||
EHCI_INT_MASK_NXP_ASYNC = TU_BIT(18),
|
|
||||||
EHCI_INT_MASK_NXP_PERIODIC = TU_BIT(19),
|
|
||||||
|
|
||||||
EHCI_INT_MASK_ALL =
|
EHCI_INT_MASK_ALL =
|
||||||
EHCI_INT_MASK_USB | EHCI_INT_MASK_ERROR | EHCI_INT_MASK_PORT_CHANGE |
|
EHCI_INT_MASK_USB | EHCI_INT_MASK_ERROR | EHCI_INT_MASK_PORT_CHANGE |
|
||||||
EHCI_INT_MASK_FRAMELIST_ROLLOVER | EHCI_INT_MASK_PCI_HOST_SYSTEM_ERROR |
|
EHCI_INT_MASK_FRAMELIST_ROLLOVER | EHCI_INT_MASK_PCI_HOST_SYSTEM_ERROR |
|
||||||
EHCI_INT_MASK_ASYNC_ADVANCE | EHCI_INT_MASK_NXP_SOF |
|
EHCI_INT_MASK_ASYNC_ADVANCE | EHCI_INT_MASK_NXP_SOF
|
||||||
EHCI_INT_MASK_NXP_ASYNC | EHCI_INT_MASK_NXP_PERIODIC
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user