29#if CFG_TUH_ENABLED && defined(TUP_USBIP_EHCI)
48#ifdef TUP_USBIP_CHIPIDEA_HS
50 #define FRAMELIST_SIZE_BIT_VALUE 7u
51 #define FRAMELIST_SIZE_USBCMD_VALUE (((FRAMELIST_SIZE_BIT_VALUE & 3) << EHCI_USBCMD_FRAMELIST_SIZE_SHIFT) | \
52 ((FRAMELIST_SIZE_BIT_VALUE >> 2) << EHCI_USBCMD_CHIPIDEA_FRAMELIST_SIZE_MSB_SHIFT))
55 #define FRAMELIST_SIZE_BIT_VALUE 2u
56 #define FRAMELIST_SIZE_USBCMD_VALUE ((FRAMELIST_SIZE_BIT_VALUE & 3) << EHCI_USBCMD_POS_FRAMELIST_SIZE)
59#define FRAMELIST_SIZE (1024 >> FRAMELIST_SIZE_BIT_VALUE)
62#define QHD_MAX (CFG_TUH_DEVICE_MAX*CFG_TUH_ENDPOINT_MAX + CFG_TUH_HUB)
63#define QTD_MAX QHD_MAX
78 }control[CFG_TUH_DEVICE_MAX+CFG_TUH_HUB+1];
95#if 0 && CFG_TUSB_DEBUG >= (EHCI_DBG + 1)
97 TU_LOG_HEX(EHCI_DBG, regs->
portsc);
111 TU_LOG_HEX(EHCI_DBG, intr);
123#define print_portsc(_reg)
131TU_ATTR_WEAK
bool hcd_dcache_clean(
void const* addr, uint32_t data_size) { (void) addr; (void) data_size;
return true; }
132TU_ATTR_WEAK
bool hcd_dcache_invalidate(
void const* addr, uint32_t data_size) { (void) addr; (void) data_size;
return true; }
182 return (ehci_data.uframe_number + ehci_data.regs->frame_index) >> 3;
197 uint32_t portsc = regs->
portsc & ~EHCI_PORTSC_MASK_W1C;
218 uint32_t portsc = regs->
portsc & ~EHCI_PORTSC_MASK_W1C;
219 portsc &= ~EHCI_PORTSC_MASK_PORT_RESET;
227 return ehci_data.regs->portsc_bm.current_connect_status;
233 return (
tusb_speed_t) ehci_data.regs->portsc_bm.nxp_port_speed;
248 for(uint8_t i = 0; i < TU_ARRAY_SIZE(ehci_data.period_head_arr); i++) {
253 ehci_data.regs->command_bm.async_adv_doorbell = 1;
260 for ( uint32_t i = 0; i < TU_ARRAY_SIZE(ehci_data.period_head_arr); i++ ) {
261 ehci_data.period_head_arr[i].int_smask = 1;
262 ehci_data.period_head_arr[i].qtd_overlay.halted = 1;
271 ehci_link_t *
const framelist = ehci_data.period_framelist;
277 for (uint32_t i = 0; i < FRAMELIST_SIZE; i++) {
278 framelist[i].
address = (uint32_t) head_1ms;
282 for (uint32_t i = 0; i < FRAMELIST_SIZE; i += 2) {
286 for (uint32_t i = 1; i < FRAMELIST_SIZE; i += 4) {
295bool ehci_init(uint8_t rhport, uint32_t capability_reg, uint32_t operatial_reg)
324 async_head->next.address = (uint32_t) async_head;
326 async_head->head_list_flag = 1;
327 async_head->qtd_overlay.halted = 1;
328 async_head->qtd_overlay.next.terminate = 1;
343 FRAMELIST_SIZE_USBCMD_VALUE;
349 if (ehci_data.cap_regs->hcsparams_bm.port_power_control) {
351 uint32_t portsc = (regs->
portsc & ~EHCI_PORTSC_MASK_W1C);
414 TU_ASSERT(list_head);
437 if (qhd->qtd_overlay.halted) {
438 qhd->qtd_overlay.halted =
false;
459 if (qhd->qtd_overlay.halted) {
460 qhd->qtd_overlay.
halted =
false;
471 TU_VERIFY(!qhd->qtd_overlay.halted);
498 ehci_qtd_t *
volatile qtd = qhd->attached_qtd;
499 TU_VERIFY(qtd != NULL);
505 bool const is_period = (qhd->interval_ms > 0);
510 bool const still_active = qtd->
active;
513 qhd->qtd_overlay.next.terminate = 1;
528 qhd->qtd_overlay.halted = 0;
529 qhd->qtd_overlay.data_toggle = 0;
542TU_ATTR_ALWAYS_INLINE
static inline
548 for (uint32_t i = 0; i < QHD_MAX; i++) {
549 if (qhd_pool[i].removing) {
550 qhd_pool[i].removing = 0;
551 qhd_pool[i].used = 0;
556TU_ATTR_ALWAYS_INLINE
static inline
559 if ( ehci_data.regs->portsc_bm.current_connect_status ) {
569TU_ATTR_ALWAYS_INLINE
static inline
572 volatile ehci_qtd_t *qtd_overlay = &qhd->qtd_overlay;
575 if ( !qtd_overlay->
active && qhd->attached_qtd != NULL ) {
578 if ( qtd_overlay->
halted ) {
583 qtd_overlay->
halted =
false;
584 TU_LOG3(
" QHD xfer err count: %d\r\n", qtd_overlay->
err_count);
594 ehci_qtd_t *
volatile qtd = qhd->attached_qtd;
601 if (dir == 1 && qhd->attached_buffer != 0 && xferred_bytes > 0) {
609 uint8_t
const ep_addr =
tu_edpt_addr(qhd->ep_number, dir);
614TU_ATTR_ALWAYS_INLINE
static inline
622 }
while ( qhd != list_head );
625TU_ATTR_ALWAYS_INLINE
static inline
639 switch (next_link.
type) {
662 uint32_t
const int_status = regs->
status;
667 TU_LOG1(
" HC halted\r\n");
672 ehci_data.uframe_number += (FRAMELIST_SIZE << 3);
685 regs->
portsc |= port_status;
694 for ( uint32_t i = 1; i <= FRAMELIST_SIZE; i *= 2 ) {
731 new->address =
current->address;
732 current->address = ((uint32_t)
new) | (new_type << 1);
743 if ( (uintptr_t) qhd == (uintptr_t) list_head) {
749 prev->
address = qhd->next.address;
752 qhd->next.address = ((uint32_t) list_head) | (
EHCI_QTYPE_QHD << 1);
754 if ( qhd->int_smask )
780 return &ehci_data.control[
dev_addr].qhd;
785 for ( uint32_t i = 0; i < QHD_MAX; i++ ) {
786 if ( !ehci_data.qhd_pool[i].used )
return &ehci_data.qhd_pool[i];
804 for ( uint32_t i = 0; i < QHD_MAX; i++ ) {
806 ep_addr ==
tu_edpt_addr(qhd_pool[i].ep_number, qhd_pool[i].pid) ) {
826 uint8_t
const interval = ep_desc->
bInterval;
829 p_qhd->fl_inactive_next_xact = 0;
831 p_qhd->ep_speed = devtree_info.
speed;
833 p_qhd->head_list_flag = (
dev_addr == 0) ? 1 : 0;
836 p_qhd->nak_reload = 0;
844 TU_ASSERT( interval <= 16, );
847 p_qhd->interval_ms = 0;
848 p_qhd->int_smask = (interval == 1) ? TU_BIN8(11111111) :
849 (interval == 2) ? TU_BIN8(10101010) : TU_BIN8(01000100);
852 p_qhd->interval_ms = (uint8_t)
tu_min16( 1 << (interval-4), 255 );
853 p_qhd->int_smask = TU_BIT(interval % 8);
857 TU_ASSERT( 0 != interval, );
859 p_qhd->int_smask = 0x01;
860 p_qhd->fl_int_cmask = TU_BIN8(11100);
861 p_qhd->interval_ms = interval;
865 p_qhd->int_smask = p_qhd->fl_int_cmask = 0;
868 p_qhd->fl_hub_addr = devtree_info.
hub_addr;
869 p_qhd->fl_hub_port = devtree_info.
hub_port;
875 p_qhd->attached_qtd = NULL;
879 p_qhd->qtd_overlay.halted = 0;
880 p_qhd->qtd_overlay.next.terminate = 1;
881 p_qhd->qtd_overlay.alternate.terminate = 1;
885 p_qhd->qtd_overlay.ping_err = 1;
891 qhd->attached_qtd = qtd;
892 qhd->attached_buffer = qtd->
buffer[0];
897 qhd->qtd_overlay.next.address = (uint32_t) qtd;
903 ehci_qtd_t *
volatile qtd = qhd->attached_qtd;
905 qhd->attached_qtd = NULL;
906 qhd->attached_buffer = 0;
919 return &ehci_data.control[
dev_addr].qtd;
923 for (uint32_t i = 0; i < QTD_MAX; i++) {
924 if (!ehci_data.qtd_pool[i].used)
return &ehci_data.qtd_pool[i];
943 for(uint8_t i=1; i<5; i++) {
static void list_remove_qhd_by_daddr(ehci_link_t *list_head, uint8_t dev_addr)
bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8])
static TU_ATTR_ALWAYS_INLINE ehci_qhd_t * qhd_find_free(void)
static TU_ATTR_ALWAYS_INLINE void list_insert(ehci_link_t *current, ehci_link_t *new, uint8_t new_type)
static TU_ATTR_ALWAYS_INLINE ehci_qhd_t * qhd_next(ehci_qhd_t const *p_qhd)
static void qtd_init(ehci_qtd_t *qtd, void const *buffer, uint16_t total_bytes)
TU_ATTR_WEAK bool hcd_dcache_invalidate(void const *addr, uint32_t data_size)
static void init_periodic_list(uint8_t rhport)
static void ehci_stop(uint8_t rhport)
static ehci_qhd_t * qhd_get_from_addr(uint8_t dev_addr, uint8_t ep_addr)
static TU_ATTR_ALWAYS_INLINE ehci_link_t * list_get_period_head(uint8_t rhport, uint32_t interval_ms)
static void qhd_attach_qtd(ehci_qhd_t *qhd, ehci_qtd_t *qtd)
static TU_ATTR_ALWAYS_INLINE ehci_link_t * list_next(ehci_link_t const *p_link)
static TU_ATTR_ALWAYS_INLINE void qhd_xfer_complete_isr(ehci_qhd_t *qhd)
static TU_ATTR_ALWAYS_INLINE void port_connect_status_change_isr(uint8_t rhport)
static TU_ATTR_ALWAYS_INLINE ehci_qhd_t * qhd_control(uint8_t dev_addr)
TU_ATTR_WEAK bool hcd_dcache_clean_invalidate(void const *addr, uint32_t data_size)
bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *buffer, uint16_t buflen)
bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t daddr, uint8_t ep_addr)
bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr)
static TU_ATTR_ALWAYS_INLINE void async_advance_isr(uint8_t rhport)
void hcd_port_reset_end(uint8_t rhport)
static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t const *ep_desc)
bool ehci_init(uint8_t rhport, uint32_t capability_reg, uint32_t operatial_reg)
void hcd_port_reset(uint8_t rhport)
static void print_intr(uint32_t intr)
bool hcd_port_connect_status(uint8_t rhport)
static TU_ATTR_ALWAYS_INLINE void proccess_async_xfer_isr(ehci_qhd_t *const list_head)
uint32_t hcd_frame_number(uint8_t rhport)
static TU_ATTR_ALWAYS_INLINE void process_period_xfer_isr(uint8_t rhport, uint32_t interval_ms)
tusb_speed_t hcd_port_speed_get(uint8_t rhport)
void hcd_int_handler(uint8_t rhport, bool in_isr)
static TU_ATTR_ALWAYS_INLINE ehci_qtd_t * qtd_control(uint8_t dev_addr)
bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const *ep_desc)
void hcd_device_close(uint8_t rhport, uint8_t daddr)
CFG_TUH_MEM_SECTION TU_ATTR_ALIGNED(4096)
TU_ATTR_WEAK bool hcd_dcache_clean(void const *addr, uint32_t data_size)
static TU_ATTR_ALWAYS_INLINE ehci_qtd_t * qtd_find_free(void)
static void ehci_enable_schedule(ehci_registers_t *regs, bool is_period)
static TU_ATTR_ALWAYS_INLINE ehci_qhd_t * list_get_async_head(uint8_t rhport)
static void qhd_remove_qtd(ehci_qhd_t *qhd)
static void ehci_disable_schedule(ehci_registers_t *regs, bool is_period)
@ EHCI_INT_MASK_PCI_HOST_SYSTEM_ERROR
@ EHCI_INT_MASK_FRAMELIST_ROLLOVER
@ EHCI_INT_MASK_HC_HALTED
@ EHCI_INT_MASK_PORT_CHANGE
@ EHCI_INT_MASK_ASYNC_ADVANCE
@ EHCI_PORTSC_MASK_PORT_POWER
@ EHCI_PORTSC_MASK_PORT_EANBLED
@ EHCI_PORTSC_MASK_PORT_RESET
@ EHCI_USBCMD_ASYNC_SCHEDULE_ENABLE
@ EHCI_USBCMD_PERIOD_SCHEDULE_ENABLE
static TU_ATTR_ALWAYS_INLINE void hcd_event_device_remove(uint8_t rhport, bool in_isr)
static TU_ATTR_ALWAYS_INLINE void hcd_event_xfer_complete(uint8_t dev_addr, uint8_t ep_addr, uint32_t xferred_bytes, xfer_result_t result, bool in_isr)
static TU_ATTR_ALWAYS_INLINE void hcd_event_device_attach(uint8_t rhport, bool in_isr)
void hcd_devtree_get_info(uint8_t dev_addr, hcd_devtree_info_t *devtree_info)
AUDIO Channel Cluster Descriptor (4.1)
uint8_t bmAttributes
See: audio_clock_source_attribute_t.
volatile uint32_t uframe_number
ehci_cap_registers_t * cap_regs
ehci_qtd_t qtd_pool[QTD_MAX] TU_ATTR_ALIGNED(32)
volatile uint32_t buffer_err
Data overrun/underrun error.
uint32_t pid
0: OUT, 1: IN, 2 Setup
volatile uint32_t babble_err
Babble detected, also set Halted bit to 1.
volatile uint32_t active
Start transfer, clear by HC when complete.
uint32_t buffer[5]
Buffer Page Pointer List, Each element in the list is a 4K page aligned, physical memory address....
volatile uint32_t total_bytes
Transfer bytes, decreased during transaction.
volatile uint32_t halted
Serious error or STALL received.
volatile uint32_t data_toggle
Data Toggle bit.
volatile uint32_t xact_err
Error (Timeout, CRC, Bad PID ... )
volatile uint32_t err_count
Error Counter of consecutive errors.
uint32_t int_on_complete
Interrupt on complete.
uint32_t port_power
12: 0= power off, 1= power on
uint32_t async_list_addr
0x18 Address of next async QHD to be executed
uint32_t connect_status_change
01: [R/WC] Change in Current Connect Status
uint32_t port_reset
08: 1=Port is in Reset. 0=Port is not in Reset
const struct ehci_registers_t::@169::@174 portsc_bm
uint32_t async_status
Async schedule status.
uint32_t port_enabled
02: Ports can only be enabled by HC as a part of the reset and enable. SW can write 0 to disable
uint32_t async_enable
This bit controls whether the host controller skips processing the Asynchronous Schedule....
uint32_t run_stop
1=Run. 0=Stop
uint32_t suspend
07: Port in suspend state
uint32_t force_port_resume
06: Resume detected/driven on port. This functionality defined for manipulating this bit depends on t...
uint32_t over_current_change
05: [R/WC] Change to Over-current Active
uint32_t port_enable_change
03: [R/WC] Port Enabled has changed
uint32_t periodic_enable
This bit controls whether the host controller skips processing the Periodic Schedule....
uint32_t nxp_tt_control
nxp embedded transaction translator (reserved by EHCI specs)
uint32_t hc_halted
Opposite value to run_stop bit.
struct ehci_registers_t::@163::@171 command_bm
uint32_t periodic_status
Periodic schedule status.
struct ehci_registers_t::@165::@172 status_bm
uint32_t current_connect_status
00: 0: No device, 1: Device is present on port
uint32_t portsc
0x44 port status and control
uint32_t periodic_list_base
0x14 Beginning address of perodic frame list
static TU_ATTR_ALWAYS_INLINE uint32_t tu_align32(uint32_t value)
static TU_ATTR_ALWAYS_INLINE uint16_t tu_min16(uint16_t x, uint16_t y)
static TU_ATTR_ALWAYS_INLINE uint32_t tu_align4k(uint32_t value)
static TU_ATTR_ALWAYS_INLINE uint32_t tu_min32(uint32_t x, uint32_t y)
static uint8_t tu_log2(uint32_t value)
tusb_speed_t
defined base on EHCI specs value for Endpoint Speed
static TU_ATTR_ALWAYS_INLINE uint8_t tu_edpt_number(uint8_t addr)
static TU_ATTR_ALWAYS_INLINE uint16_t tu_edpt_packet_size(tusb_desc_endpoint_t const *desc_ep)
TU_ATTR_PACKED_END TU_ATTR_BIT_FIELD_ORDER_END static TU_ATTR_ALWAYS_INLINE tusb_dir_t tu_edpt_dir(uint8_t addr)
static TU_ATTR_ALWAYS_INLINE uint8_t tu_edpt_addr(uint8_t num, uint8_t dir)