From d367e8f8a8acd82c89ba3c029495b9404c3b7fdb Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Sat, 4 Jun 2022 13:44:22 +0930 Subject: [PATCH 01/16] ohci: Expand roothub descriptors into unions --- src/portable/ohci/ohci.h | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/portable/ohci/ohci.h b/src/portable/ohci/ohci.h index f40ae24cc..c42db141a 100644 --- a/src/portable/ohci/ohci.h +++ b/src/portable/ohci/ohci.h @@ -230,8 +230,27 @@ typedef volatile struct uint32_t periodic_start; uint32_t lowspeed_threshold; - uint32_t rh_descriptorA; - uint32_t rh_descriptorB; + union { + uint32_t rh_descriptorA; + struct { + uint32_t number_downstream_ports : 8; + uint32_t power_switching_mode : 1; + uint32_t no_power_switching : 1; + uint32_t device_type : 1; + uint32_t overcurrent_protection_mode : 1; + uint32_t no_over_current_protection : 1; + uint32_t reserved : 11; + uint32_t power_on_to_good_time : 8; + } rh_descriptorA_bit; + }; + + union { + uint32_t rh_descriptorB; + struct { + uint32_t device_removable : 16; + uint32_t port_power_control_mask : 16; + } rh_descriptorB_bit; + }; union { uint32_t rh_status; From c820c8769267644af049e0be73b04b45d57e8d98 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Sat, 4 Jun 2022 13:47:02 +0930 Subject: [PATCH 02/16] ohci: Support configurable number of roothub ports --- src/common/tusb_mcu.h | 1 + src/portable/ohci/ohci.c | 43 ++++++++++++++++++++++------------------ src/portable/ohci/ohci.h | 6 +++--- 3 files changed, 28 insertions(+), 22 deletions(-) diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h index 0b10c5118..ee2b896ac 100644 --- a/src/common/tusb_mcu.h +++ b/src/common/tusb_mcu.h @@ -55,6 +55,7 @@ #elif TU_CHECK_MCU(OPT_MCU_LPC175X_6X, OPT_MCU_LPC177X_8X, OPT_MCU_LPC40XX) #define TUP_DCD_ENDPOINT_MAX 16 #define TUP_USBIP_OHCI + #define OHCI_RHPORTS 2 #elif TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX) // TODO USB0 has 6, USB1 has 4 diff --git a/src/portable/ohci/ohci.c b/src/portable/ohci/ohci.c index 228da6ae0..45600c03b 100644 --- a/src/portable/ohci/ohci.c +++ b/src/portable/ohci/ohci.c @@ -28,6 +28,10 @@ #if CFG_TUH_ENABLED && defined(TUP_USBIP_OHCI) +#ifndef OHCI_RHPORTS +#error OHCI is enabled, but OHCI_RHPORTS is not defined. +#endif + //--------------------------------------------------------------------+ // INCLUDE //--------------------------------------------------------------------+ @@ -620,29 +624,30 @@ void hcd_int_handler(uint8_t hostid) //------------- RootHub status -------------// if ( int_status & OHCI_INT_RHPORT_STATUS_CHANGE_MASK ) { - uint32_t const rhport_status = OHCI_REG->rhport_status[0] & RHPORT_ALL_CHANGE_MASK; - - // TODO dual port is not yet supported - if ( rhport_status & RHPORT_CONNECT_STATUS_CHANGE_MASK ) + for (int i = 0; i < OHCI_RHPORTS; i++) { - // TODO check if remote wake-up - if ( OHCI_REG->rhport_status_bit[0].current_connect_status ) + uint32_t const rhport_status = OHCI_REG->rhport_status[i] & RHPORT_ALL_CHANGE_MASK; + if ( rhport_status & RHPORT_CONNECT_STATUS_CHANGE_MASK ) { - // TODO reset port immediately, without this controller will got 2-3 (debouncing connection status change) - OHCI_REG->rhport_status[0] = RHPORT_PORT_RESET_STATUS_MASK; - hcd_event_device_attach(hostid, true); - }else - { - hcd_event_device_remove(hostid, true); + // TODO check if remote wake-up + if ( OHCI_REG->rhport_status_bit[i].current_connect_status ) + { + // TODO reset port immediately, without this controller will got 2-3 (debouncing connection status change) + OHCI_REG->rhport_status[i] = RHPORT_PORT_RESET_STATUS_MASK; + hcd_event_device_attach(i, true); + }else + { + hcd_event_device_remove(i, true); + } } + + if ( rhport_status & RHPORT_PORT_SUSPEND_CHANGE_MASK) + { + + } + + OHCI_REG->rhport_status[i] = rhport_status; // acknowledge all interrupt } - - if ( rhport_status & RHPORT_PORT_SUSPEND_CHANGE_MASK) - { - - } - - OHCI_REG->rhport_status[0] = rhport_status; // acknowledge all interrupt } //------------- Transfer Complete -------------// diff --git a/src/portable/ohci/ohci.h b/src/portable/ohci/ohci.h index c42db141a..b7706b636 100644 --- a/src/portable/ohci/ohci.h +++ b/src/portable/ohci/ohci.h @@ -267,7 +267,7 @@ typedef volatile struct }; union { - uint32_t rhport_status[2]; // TODO NXP OHCI controller only has 2 ports + uint32_t rhport_status[OHCI_RHPORTS]; struct { uint32_t current_connect_status : 1; uint32_t port_enable_status : 1; @@ -284,11 +284,11 @@ typedef volatile struct uint32_t port_over_current_indicator_change : 1; uint32_t port_reset_status_change : 1; uint32_t TU_RESERVED : 11; - }rhport_status_bit[2]; + }rhport_status_bit[OHCI_RHPORTS]; }; }ohci_registers_t; -TU_VERIFY_STATIC( sizeof(ohci_registers_t) == 0x5c, "size is not correct"); +TU_VERIFY_STATIC( sizeof(ohci_registers_t) == (0x54 + (4 * OHCI_RHPORTS)), "size is not correct"); #ifdef __cplusplus } From d5e6d028171a38e435ac1ab7c18ae5615f8af5cf Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Sat, 4 Jun 2022 14:06:23 +0930 Subject: [PATCH 03/16] ohci: Leave SMM or bios mode during init --- src/portable/ohci/ohci.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/portable/ohci/ohci.c b/src/portable/ohci/ohci.c index 45600c03b..364f61cf1 100644 --- a/src/portable/ohci/ohci.c +++ b/src/portable/ohci/ohci.c @@ -177,6 +177,22 @@ bool hcd_init(uint8_t rhport) ohci_data.bulk_head_ed.skip = 1; ohci_data.period_head_ed.skip = 1; + //If OHCI hardware is in SMM mode, gain ownership (Ref OHCI spec 5.1.1.3.3) + if (OHCI_REG->control_bit.interrupt_routing == 1) + { + OHCI_REG->command_status_bit.ownership_change_request = 1; + while (OHCI_REG->control_bit.interrupt_routing == 1) {} + } + + //If OHCI hardware has come from warm-boot, signal resume (Ref OHCI spec 5.1.1.3.4) + else if (OHCI_REG->control_bit.hc_functional_state != OHCI_CONTROL_FUNCSTATE_RESET && + OHCI_REG->control_bit.hc_functional_state != OHCI_CONTROL_FUNCSTATE_OPERATIONAL) + { + //Wait 20 ms. (Ref Usb spec 7.1.7.7) + OHCI_REG->control_bit.hc_functional_state = OHCI_CONTROL_FUNCSTATE_RESUME; + osal_task_delay(20); + } + // reset controller OHCI_REG->command_status_bit.controller_reset = 1; while( OHCI_REG->command_status_bit.controller_reset ) {} // should not take longer than 10 us From 2063ee5f1592979cc858b748aff51dba7cb3bcd5 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Sat, 4 Jun 2022 14:09:21 +0930 Subject: [PATCH 04/16] ohci: Toggle frameinterval bit on update --- src/portable/ohci/ohci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/portable/ohci/ohci.c b/src/portable/ohci/ohci.c index 364f61cf1..cf6cff364 100644 --- a/src/portable/ohci/ohci.c +++ b/src/portable/ohci/ohci.c @@ -212,6 +212,7 @@ bool hcd_init(uint8_t rhport) OHCI_CONTROL_LIST_BULK_ENABLE_MASK | OHCI_CONTROL_LIST_PERIODIC_ENABLE_MASK; // TODO Isochronous OHCI_REG->frame_interval = (OHCI_FMINTERVAL_FSMPS << 16) | OHCI_FMINTERVAL_FI; + OHCI_REG->frame_interval ^= (1 << 31); //Must toggle when frame_interval is updated. OHCI_REG->periodic_start = (OHCI_FMINTERVAL_FI * 9) / 10; // Periodic start is 90% of frame interval OHCI_REG->control_bit.hc_functional_state = OHCI_CONTROL_FUNCSTATE_OPERATIONAL; // make HC's state to operational state TODO use this to suspend (save power) From c1d0fd1bd747bfc4881ecf69bc60fbcb106a7afd Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Sat, 4 Jun 2022 14:11:34 +0930 Subject: [PATCH 05/16] ohci: Wait POTG time after port power --- src/portable/ohci/ohci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/portable/ohci/ohci.c b/src/portable/ohci/ohci.c index cf6cff364..0a715a962 100644 --- a/src/portable/ohci/ohci.c +++ b/src/portable/ohci/ohci.c @@ -217,6 +217,7 @@ bool hcd_init(uint8_t rhport) OHCI_REG->control_bit.hc_functional_state = OHCI_CONTROL_FUNCSTATE_OPERATIONAL; // make HC's state to operational state TODO use this to suspend (save power) OHCI_REG->rh_status_bit.local_power_status_change = 1; // set global power for ports + osal_task_delay(OHCI_REG->rh_descriptorA_bit.power_on_to_good_time * 2); // Wait POTG after power up return true; } From 5d3c0fb922604989e7f7e7f628fe43553ac78df7 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Sat, 4 Jun 2022 14:14:53 +0930 Subject: [PATCH 06/16] ohci: Force reset of devices already connected on power up --- src/portable/ohci/ohci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/portable/ohci/ohci.c b/src/portable/ohci/ohci.c index 0a715a962..85795c5b4 100644 --- a/src/portable/ohci/ohci.c +++ b/src/portable/ohci/ohci.c @@ -208,7 +208,7 @@ bool hcd_init(uint8_t rhport) OHCI_INT_UNRECOVERABLE_ERROR_MASK | OHCI_INT_FRAME_OVERFLOW_MASK | OHCI_INT_RHPORT_STATUS_CHANGE_MASK | OHCI_INT_MASTER_ENABLE_MASK; - OHCI_REG->control |= OHCI_CONTROL_CONTROL_BULK_RATIO | OHCI_CONTROL_LIST_CONTROL_ENABLE_MASK | + OHCI_REG->control = OHCI_CONTROL_CONTROL_BULK_RATIO | OHCI_CONTROL_LIST_CONTROL_ENABLE_MASK | OHCI_CONTROL_LIST_BULK_ENABLE_MASK | OHCI_CONTROL_LIST_PERIODIC_ENABLE_MASK; // TODO Isochronous OHCI_REG->frame_interval = (OHCI_FMINTERVAL_FSMPS << 16) | OHCI_FMINTERVAL_FI; From e89e8ba392dae795663169d02952116b3f3980f3 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Sat, 4 Jun 2022 14:18:53 +0930 Subject: [PATCH 07/16] ohci: Direct port commands to the correct rhport. --- src/portable/ohci/ohci.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/portable/ohci/ohci.c b/src/portable/ohci/ohci.c index 85795c5b4..b0c6bb63c 100644 --- a/src/portable/ohci/ohci.c +++ b/src/portable/ohci/ohci.c @@ -234,8 +234,7 @@ uint32_t hcd_frame_number(uint8_t rhport) //--------------------------------------------------------------------+ void hcd_port_reset(uint8_t hostid) { - (void) hostid; - OHCI_REG->rhport_status[0] = RHPORT_PORT_RESET_STATUS_MASK; + OHCI_REG->rhport_status[hostid] = RHPORT_PORT_RESET_STATUS_MASK; } void hcd_port_reset_end(uint8_t rhport) @@ -245,14 +244,12 @@ void hcd_port_reset_end(uint8_t rhport) bool hcd_port_connect_status(uint8_t hostid) { - (void) hostid; - return OHCI_REG->rhport_status_bit[0].current_connect_status; + return OHCI_REG->rhport_status_bit[hostid].current_connect_status; } tusb_speed_t hcd_port_speed_get(uint8_t hostid) { - (void) hostid; - return OHCI_REG->rhport_status_bit[0].low_speed_device_attached ? TUSB_SPEED_LOW : TUSB_SPEED_FULL; + return OHCI_REG->rhport_status_bit[hostid].low_speed_device_attached ? TUSB_SPEED_LOW : TUSB_SPEED_FULL; } // endpoints are tied to an address, which only reclaim after a long delay when enumerating From cc9c3feeaee69b369aea4fb4f70e4f0fb1033990 Mon Sep 17 00:00:00 2001 From: Ryan Wendland Date: Sat, 4 Jun 2022 22:40:06 +0930 Subject: [PATCH 08/16] ohci: Fix bug in ed removal --- src/portable/ohci/ohci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/portable/ohci/ohci.c b/src/portable/ohci/ohci.c index b0c6bb63c..59ffd2725 100644 --- a/src/portable/ohci/ohci.c +++ b/src/portable/ohci/ohci.c @@ -383,6 +383,7 @@ static void ed_list_remove_by_addr(ohci_ed_t * p_head, uint8_t dev_addr) // point the removed ED's next pointer to list head to make sure HC can always safely move away from this ED ed->next = (uint32_t) p_head; ed->used = 0; + continue; } // check next valid since we could remove it From f87262185ec64e6ad616972720a72ffed65708ac Mon Sep 17 00:00:00 2001 From: Ryan Wendland Date: Sat, 4 Jun 2022 22:49:07 +0930 Subject: [PATCH 09/16] ohci: Set skip on ed prior to removal --- src/portable/ohci/ohci.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/portable/ohci/ohci.c b/src/portable/ohci/ohci.c index 59ffd2725..d51b9a883 100644 --- a/src/portable/ohci/ohci.c +++ b/src/portable/ohci/ohci.c @@ -377,12 +377,16 @@ static void ed_list_remove_by_addr(ohci_ed_t * p_head, uint8_t dev_addr) if (ed->dev_addr == dev_addr) { + //Prevent Host Controller from processing this ED while we remove it + ed->skip = 1; + // unlink ed p_prev->next = ed->next; // point the removed ED's next pointer to list head to make sure HC can always safely move away from this ED ed->next = (uint32_t) p_head; ed->used = 0; + ed->skip = 0; continue; } From f2a6af05b1cd7c298e6781e4374d744e2625c63f Mon Sep 17 00:00:00 2001 From: Ryan Wendland Date: Thu, 9 Jun 2022 08:32:49 +0930 Subject: [PATCH 10/16] ohci: Add ability to separate physical and virtual memory --- src/portable/ohci/ohci.c | 51 ++++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/src/portable/ohci/ohci.c b/src/portable/ohci/ohci.c index d51b9a883..d85550d80 100644 --- a/src/portable/ohci/ohci.c +++ b/src/portable/ohci/ohci.c @@ -161,6 +161,22 @@ static void ed_list_remove_by_addr(ohci_ed_t * p_head, uint8_t dev_addr); //--------------------------------------------------------------------+ // USBH-HCD API //--------------------------------------------------------------------+ + +//If your system requires separation of virtual and physical memory, implement +//tuh_get_phys_addr and tuh_get_virt_addr in your application. +TU_ATTR_WEAK void *tuh_get_phys_addr(void *virtual_address); +TU_ATTR_WEAK void *tuh_get_virt_addr(void *physical_address); +TU_ATTR_ALWAYS_INLINE static void *_phys_addr(void *virtual_address) +{ + if (tuh_get_phys_addr) return tuh_get_phys_addr(virtual_address); + return virtual_address; +} +TU_ATTR_ALWAYS_INLINE static void *_virt_addr(void *physical_address) +{ + if (tuh_get_virt_addr) return tuh_get_virt_addr(physical_address); + return physical_address; +} + // Initialization according to 5.1.1.4 bool hcd_init(uint8_t rhport) { @@ -170,7 +186,7 @@ bool hcd_init(uint8_t rhport) tu_memclr(&ohci_data, sizeof(ohci_data_t)); for(uint8_t i=0; i<32; i++) { // assign all interrupt pointers to period head ed - ohci_data.hcca.interrupt_table[i] = (uint32_t) &ohci_data.period_head_ed; + ohci_data.hcca.interrupt_table[i] = (uint32_t) _phys_addr(&ohci_data.period_head_ed); } ohci_data.control[0].ed.skip = 1; @@ -198,9 +214,9 @@ bool hcd_init(uint8_t rhport) while( OHCI_REG->command_status_bit.controller_reset ) {} // should not take longer than 10 us //------------- init ohci registers -------------// - OHCI_REG->control_head_ed = (uint32_t) &ohci_data.control[0].ed; - OHCI_REG->bulk_head_ed = (uint32_t) &ohci_data.bulk_head_ed; - OHCI_REG->hcca = (uint32_t) &ohci_data.hcca; + OHCI_REG->control_head_ed = (uint32_t) _phys_addr(&ohci_data.control[0].ed); + OHCI_REG->bulk_head_ed = (uint32_t) _phys_addr(&ohci_data.bulk_head_ed); + OHCI_REG->hcca = (uint32_t) _phys_addr(&ohci_data.hcca); OHCI_REG->interrupt_disable = OHCI_REG->interrupt_enable; // disable all interrupts OHCI_REG->interrupt_status = OHCI_REG->interrupt_status; // clear current set bits @@ -327,8 +343,8 @@ static void gtd_init(ohci_gtd_t* p_td, uint8_t* data_ptr, uint16_t total_bytes) p_td->delay_interrupt = OHCI_INT_ON_COMPLETE_NO; p_td->condition_code = OHCI_CCODE_NOT_ACCESSED; - p_td->current_buffer_pointer = data_ptr; - p_td->buffer_end = total_bytes ? (data_ptr + total_bytes-1) : data_ptr; + p_td->current_buffer_pointer = _phys_addr(data_ptr); + p_td->buffer_end = total_bytes ? (_phys_addr(data_ptr + total_bytes - 1)) : (uint8_t *)p_td->current_buffer_pointer; } static ohci_ed_t * ed_from_addr(uint8_t dev_addr, uint8_t ep_addr) @@ -364,7 +380,7 @@ static ohci_ed_t * ed_find_free(void) static void ed_list_insert(ohci_ed_t * p_pre, ohci_ed_t * p_ed) { p_ed->next = p_pre->next; - p_pre->next = (uint32_t) p_ed; + p_pre->next = (uint32_t) _phys_addr(p_ed); } static void ed_list_remove_by_addr(ohci_ed_t * p_head, uint8_t dev_addr) @@ -373,7 +389,7 @@ static void ed_list_remove_by_addr(ohci_ed_t * p_head, uint8_t dev_addr) while( p_prev->next ) { - ohci_ed_t* ed = (ohci_ed_t*) p_prev->next; + ohci_ed_t* ed = (ohci_ed_t*) _virt_addr((void *)p_prev->next); if (ed->dev_addr == dev_addr) { @@ -384,14 +400,14 @@ static void ed_list_remove_by_addr(ohci_ed_t * p_head, uint8_t dev_addr) p_prev->next = ed->next; // point the removed ED's next pointer to list head to make sure HC can always safely move away from this ED - ed->next = (uint32_t) p_head; + ed->next = (uint32_t) _phys_addr(p_head); ed->used = 0; ed->skip = 0; continue; } // check next valid since we could remove it - if (p_prev->next) p_prev = (ohci_ed_t*) p_prev->next; + if (p_prev->next) p_prev = (ohci_ed_t*) _virt_addr((void *)p_prev->next); } } @@ -410,11 +426,11 @@ static void td_insert_to_ed(ohci_ed_t* p_ed, ohci_gtd_t * p_gtd) // tail is always NULL if ( tu_align16(p_ed->td_head.address) == 0 ) { // TD queue is empty --> head = TD - p_ed->td_head.address |= (uint32_t) p_gtd; + p_ed->td_head.address |= (uint32_t) _phys_addr(p_gtd); } else { // TODO currently only support queue up to 2 TD each endpoint at a time - ((ohci_gtd_t*) tu_align16(p_ed->td_head.address))->next = (uint32_t) p_gtd; + ((ohci_gtd_t*) tu_align16((uint32_t)_virt_addr((void *)p_ed->td_head.address)))->next = (uint32_t) _phys_addr(p_gtd); } } @@ -470,7 +486,7 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet qtd->delay_interrupt = 0; //------------- Attach TDs list to Control Endpoint -------------// - ed->td_head.address = (uint32_t) qtd; + ed->td_head.address = (uint32_t) _phys_addr(qtd); OHCI_REG->command_status_bit.control_list_filled = 1; @@ -496,7 +512,7 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * gtd->data_toggle = GTD_DT_DATA1; // Both Data and Ack stage start with DATA1 gtd->delay_interrupt = 0; - ed->td_head.address = (uint32_t) gtd; + ed->td_head.address = (uint32_t) _phys_addr(gtd); OHCI_REG->command_status_bit.control_list_filled = 1; }else @@ -544,16 +560,17 @@ static ohci_td_item_t* list_reverse(ohci_td_item_t* td_head) while(td_head != NULL) { + td_head = _virt_addr(td_head); uint32_t next = td_head->next; // make current's item become reverse's first item td_head->next = (uint32_t) td_reverse_head; - td_reverse_head = td_head; + td_reverse_head = _phys_addr(td_head); td_head = (ohci_td_item_t*) next; // advance to next item } - return td_reverse_head; + return _virt_addr(td_reverse_head); } static inline bool gtd_is_control(ohci_gtd_t const * const p_qtd) @@ -624,7 +641,7 @@ static void done_queue_isr(uint8_t hostid) hcd_event_xfer_complete(ed->dev_addr, tu_edpt_addr(ed->ep_number, dir), xferred_bytes, event, true); } - td_head = (ohci_td_item_t*) td_head->next; + td_head = (ohci_td_item_t*) _virt_addr((void *)td_head->next); } } From 75f6583c1c9ad3e0c2fc9e3427a649edbf765bef Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Mon, 13 Jun 2022 13:01:41 +0930 Subject: [PATCH 11/16] ohci: Use enum instead of magic number --- src/portable/ohci/ohci.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/portable/ohci/ohci.c b/src/portable/ohci/ohci.c index d85550d80..d16de0cca 100644 --- a/src/portable/ohci/ohci.c +++ b/src/portable/ohci/ohci.c @@ -483,7 +483,7 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet qtd->index = dev_addr; qtd->pid = PID_SETUP; qtd->data_toggle = GTD_DT_DATA0; - qtd->delay_interrupt = 0; + qtd->delay_interrupt = OHCI_INT_ON_COMPLETE_YES; //------------- Attach TDs list to Control Endpoint -------------// ed->td_head.address = (uint32_t) _phys_addr(qtd); @@ -510,7 +510,7 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * gtd->index = dev_addr; gtd->pid = dir ? PID_IN : PID_OUT; gtd->data_toggle = GTD_DT_DATA1; // Both Data and Ack stage start with DATA1 - gtd->delay_interrupt = 0; + gtd->delay_interrupt = OHCI_INT_ON_COMPLETE_YES; ed->td_head.address = (uint32_t) _phys_addr(gtd); @@ -524,7 +524,7 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * gtd_init(gtd, buffer, buflen); gtd->index = ed-ohci_data.ed_pool; - gtd->delay_interrupt = 0; + gtd->delay_interrupt = OHCI_INT_ON_COMPLETE_YES; td_insert_to_ed(ed, gtd); From 4e2afdf5e1d72a2232f349a878c3d4147fc43cd6 Mon Sep 17 00:00:00 2001 From: wooyay <7655456+wooyay@users.noreply.github.com> Date: Tue, 14 Feb 2023 17:03:19 +0000 Subject: [PATCH 12/16] ohci: Disable MIE interrupt during IRQ processing, zero HccADoneHead on completion --- src/portable/ohci/ohci.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/portable/ohci/ohci.c b/src/portable/ohci/ohci.c index d16de0cca..76f97844c 100644 --- a/src/portable/ohci/ohci.c +++ b/src/portable/ohci/ohci.c @@ -606,6 +606,7 @@ static void done_queue_isr(uint8_t hostid) // done head is written in reversed order of completion --> need to reverse the done queue first ohci_td_item_t* td_head = list_reverse ( (ohci_td_item_t*) tu_align16(ohci_data.hcca.done_head) ); + ohci_data.hcca.done_head = 0; while( td_head != NULL ) { @@ -652,6 +653,9 @@ void hcd_int_handler(uint8_t hostid) if (int_status == 0) return; + // Disable MIE as per OHCI spec 5.3 + OHCI_REG->interrupt_disable = OHCI_INT_MASTER_ENABLE_MASK; + // Frame number overflow if ( int_status & OHCI_INT_FRAME_OVERFLOW_MASK ) { @@ -694,6 +698,8 @@ void hcd_int_handler(uint8_t hostid) } OHCI_REG->interrupt_status = int_status; // Acknowledge handled interrupt + + OHCI_REG->interrupt_enable = OHCI_INT_MASTER_ENABLE_MASK; // Enable MIE } //--------------------------------------------------------------------+ // HELPER From 4c846af53e993d635e6fff7e2611a554b55fc441 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 22 Feb 2023 16:18:45 +0700 Subject: [PATCH 13/16] rename OHCI_RHPORTS to TUP_OHCI_RHPORTS --- src/common/tusb_mcu.h | 2 +- src/portable/ohci/ohci.c | 17 ++++++++--------- src/portable/ohci/ohci.h | 6 +++--- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h index ee2b896ac..a599c4fe9 100644 --- a/src/common/tusb_mcu.h +++ b/src/common/tusb_mcu.h @@ -55,7 +55,7 @@ #elif TU_CHECK_MCU(OPT_MCU_LPC175X_6X, OPT_MCU_LPC177X_8X, OPT_MCU_LPC40XX) #define TUP_DCD_ENDPOINT_MAX 16 #define TUP_USBIP_OHCI - #define OHCI_RHPORTS 2 + #define TUP_OHCI_RHPORTS 2 #elif TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX) // TODO USB0 has 6, USB1 has 4 diff --git a/src/portable/ohci/ohci.c b/src/portable/ohci/ohci.c index 76f97844c..792ef65ff 100644 --- a/src/portable/ohci/ohci.c +++ b/src/portable/ohci/ohci.c @@ -28,8 +28,8 @@ #if CFG_TUH_ENABLED && defined(TUP_USBIP_OHCI) -#ifndef OHCI_RHPORTS -#error OHCI is enabled, but OHCI_RHPORTS is not defined. +#ifndef TUP_OHCI_RHPORTS +#error OHCI is enabled, but TUP_OHCI_RHPORTS is not defined. #endif //--------------------------------------------------------------------+ @@ -393,21 +393,20 @@ static void ed_list_remove_by_addr(ohci_ed_t * p_head, uint8_t dev_addr) if (ed->dev_addr == dev_addr) { - //Prevent Host Controller from processing this ED while we remove it + // Prevent Host Controller from processing this ED while we remove it ed->skip = 1; - // unlink ed + // unlink ed, will also move up p_prev p_prev->next = ed->next; // point the removed ED's next pointer to list head to make sure HC can always safely move away from this ED ed->next = (uint32_t) _phys_addr(p_head); ed->used = 0; ed->skip = 0; - continue; + }else + { + p_prev = (ohci_ed_t*) _virt_addr((void *)p_prev->next); } - - // check next valid since we could remove it - if (p_prev->next) p_prev = (ohci_ed_t*) _virt_addr((void *)p_prev->next); } } @@ -665,7 +664,7 @@ void hcd_int_handler(uint8_t hostid) //------------- RootHub status -------------// if ( int_status & OHCI_INT_RHPORT_STATUS_CHANGE_MASK ) { - for (int i = 0; i < OHCI_RHPORTS; i++) + for (int i = 0; i < TUP_OHCI_RHPORTS; i++) { uint32_t const rhport_status = OHCI_REG->rhport_status[i] & RHPORT_ALL_CHANGE_MASK; if ( rhport_status & RHPORT_CONNECT_STATUS_CHANGE_MASK ) diff --git a/src/portable/ohci/ohci.h b/src/portable/ohci/ohci.h index b7706b636..38c258e80 100644 --- a/src/portable/ohci/ohci.h +++ b/src/portable/ohci/ohci.h @@ -267,7 +267,7 @@ typedef volatile struct }; union { - uint32_t rhport_status[OHCI_RHPORTS]; + uint32_t rhport_status[TUP_OHCI_RHPORTS]; struct { uint32_t current_connect_status : 1; uint32_t port_enable_status : 1; @@ -284,11 +284,11 @@ typedef volatile struct uint32_t port_over_current_indicator_change : 1; uint32_t port_reset_status_change : 1; uint32_t TU_RESERVED : 11; - }rhport_status_bit[OHCI_RHPORTS]; + }rhport_status_bit[TUP_OHCI_RHPORTS]; }; }ohci_registers_t; -TU_VERIFY_STATIC( sizeof(ohci_registers_t) == (0x54 + (4 * OHCI_RHPORTS)), "size is not correct"); +TU_VERIFY_STATIC( sizeof(ohci_registers_t) == (0x54 + (4 * TUP_OHCI_RHPORTS)), "size is not correct"); #ifdef __cplusplus } From 1466afafeb927621f9cbb6efd2a0d7e4b6cf8d41 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 22 Feb 2023 22:14:50 +0700 Subject: [PATCH 14/16] move and add optional tusb_app_virt_to_phys/tusb_app_phys_to_virt also add place holder for tusb_app_dcache_flush() and tusb_app_dcache_invalidate() --- src/common/tusb_common.h | 15 +++++++++++++++ src/common/tusb_mcu.h | 4 ++-- src/host/hcd.h | 2 +- src/osal/osal_none.h | 4 ++++ src/portable/ohci/ohci.c | 21 +++++++++++++-------- src/portable/ohci/ohci.h | 4 +++- 6 files changed, 38 insertions(+), 12 deletions(-) diff --git a/src/common/tusb_common.h b/src/common/tusb_common.h index b1ee40a1a..270339cca 100644 --- a/src/common/tusb_common.h +++ b/src/common/tusb_common.h @@ -75,6 +75,21 @@ #include "tusb_timeout.h" // TODO remove +//--------------------------------------------------------------------+ +// Optional API implemented by application if needed +// TODO move to a more ovious place/file +//--------------------------------------------------------------------+ + +// flush data cache +TU_ATTR_WEAK extern void tusb_app_dcache_flush(uintptr_t addr, uint32_t data_size); + +// invalidate data cache +TU_ATTR_WEAK extern void tusb_app_dcache_invalidate(uintptr_t addr, uint32_t data_size); + +// Optional physical <-> virtual address translation +TU_ATTR_WEAK extern void* tusb_app_virt_to_phys(void *virt_addr); +TU_ATTR_WEAK extern void* tusb_app_phys_to_virt(void *phys_addr); + //--------------------------------------------------------------------+ // Internal Inline Functions //--------------------------------------------------------------------+ diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h index a599c4fe9..e7d4e2c32 100644 --- a/src/common/tusb_mcu.h +++ b/src/common/tusb_mcu.h @@ -28,8 +28,8 @@ #define TUSB_MCU_H_ //--------------------------------------------------------------------+ -// Port Specific -// TUP stand for TinyUSB Port (can be renamed) +// Port/Platform Specific +// TUP stand for TinyUSB Port/Platform (can be renamed) //--------------------------------------------------------------------+ //------------- Unaligned Memory Access -------------// diff --git a/src/host/hcd.h b/src/host/hcd.h index deebc59d4..a400626e4 100644 --- a/src/host/hcd.h +++ b/src/host/hcd.h @@ -106,7 +106,7 @@ typedef struct // Controller API //--------------------------------------------------------------------+ -// optional hcd configuration, called by tuh_config() +// optional hcd configuration, called by tuh_configure() bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) TU_ATTR_WEAK; // Initialize controller to host mode diff --git a/src/osal/osal_none.h b/src/osal/osal_none.h index 1ad130557..2e2b3c7ce 100644 --- a/src/osal/osal_none.h +++ b/src/osal/osal_none.h @@ -35,6 +35,10 @@ // TASK API //--------------------------------------------------------------------+ +#if CFG_TUH_ENABLED +// currently only needed/available in host mode +void osal_task_delay(uint32_t msec); +#endif //--------------------------------------------------------------------+ // Binary Semaphore API diff --git a/src/portable/ohci/ohci.c b/src/portable/ohci/ohci.c index 792ef65ff..339f8e896 100644 --- a/src/portable/ohci/ohci.c +++ b/src/portable/ohci/ohci.c @@ -162,18 +162,16 @@ static void ed_list_remove_by_addr(ohci_ed_t * p_head, uint8_t dev_addr); // USBH-HCD API //--------------------------------------------------------------------+ -//If your system requires separation of virtual and physical memory, implement -//tuh_get_phys_addr and tuh_get_virt_addr in your application. -TU_ATTR_WEAK void *tuh_get_phys_addr(void *virtual_address); -TU_ATTR_WEAK void *tuh_get_virt_addr(void *physical_address); -TU_ATTR_ALWAYS_INLINE static void *_phys_addr(void *virtual_address) +// If your system requires separation of virtual and physical memory, implement +// tusb_app_virt_to_phys and tusb_app_virt_to_phys in your application. +TU_ATTR_ALWAYS_INLINE static inline void *_phys_addr(void *virtual_address) { - if (tuh_get_phys_addr) return tuh_get_phys_addr(virtual_address); + if (tusb_app_virt_to_phys) return tusb_app_virt_to_phys(virtual_address); return virtual_address; } -TU_ATTR_ALWAYS_INLINE static void *_virt_addr(void *physical_address) +TU_ATTR_ALWAYS_INLINE static inline void *_virt_addr(void *physical_address) { - if (tuh_get_virt_addr) return tuh_get_virt_addr(physical_address); + if (tusb_app_phys_to_virt) return tusb_app_phys_to_virt(physical_address); return physical_address; } @@ -206,7 +204,13 @@ bool hcd_init(uint8_t rhport) { //Wait 20 ms. (Ref Usb spec 7.1.7.7) OHCI_REG->control_bit.hc_functional_state = OHCI_CONTROL_FUNCSTATE_RESUME; + +#if CFG_TUSB_OS != OPT_OS_NONE + // os_none implement task delay using usb frame counter which is not started yet + // therefore cause infinite delay. + // TODO find a way to delay in case of os none e.g __nop osal_task_delay(20); +#endif } // reset controller @@ -233,6 +237,7 @@ bool hcd_init(uint8_t rhport) OHCI_REG->control_bit.hc_functional_state = OHCI_CONTROL_FUNCSTATE_OPERATIONAL; // make HC's state to operational state TODO use this to suspend (save power) OHCI_REG->rh_status_bit.local_power_status_change = 1; // set global power for ports + osal_task_delay(OHCI_REG->rh_descriptorA_bit.power_on_to_good_time * 2); // Wait POTG after power up return true; diff --git a/src/portable/ohci/ohci.h b/src/portable/ohci/ohci.h index 38c258e80..2081ffabb 100644 --- a/src/portable/ohci/ohci.h +++ b/src/portable/ohci/ohci.h @@ -58,7 +58,9 @@ typedef struct { TU_VERIFY_STATIC( sizeof(ohci_hcca_t) == 256, "size is not correct" ); -typedef struct { +// common link item for gtd and itd for list travel +// use as pointer only +typedef struct TU_ATTR_ALIGNED(16) { uint32_t reserved[2]; volatile uint32_t next; uint32_t reserved2; From 4caa6063b092de2a9efadb6a4ac247543662731f Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 22 Feb 2023 22:17:45 +0700 Subject: [PATCH 15/16] white space --- src/common/tusb_mcu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h index e7d4e2c32..1f27afa4e 100644 --- a/src/common/tusb_mcu.h +++ b/src/common/tusb_mcu.h @@ -55,7 +55,7 @@ #elif TU_CHECK_MCU(OPT_MCU_LPC175X_6X, OPT_MCU_LPC177X_8X, OPT_MCU_LPC40XX) #define TUP_DCD_ENDPOINT_MAX 16 #define TUP_USBIP_OHCI - #define TUP_OHCI_RHPORTS 2 + #define TUP_OHCI_RHPORTS 2 #elif TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX) // TODO USB0 has 6, USB1 has 4 From eca96c635da52ab516e3dda47348ef8977ffd8ad Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 22 Feb 2023 22:28:22 +0700 Subject: [PATCH 16/16] comment out osal_task_delay if using os none --- src/portable/ohci/ohci.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/portable/ohci/ohci.c b/src/portable/ohci/ohci.c index 339f8e896..b615743b8 100644 --- a/src/portable/ohci/ohci.c +++ b/src/portable/ohci/ohci.c @@ -169,6 +169,7 @@ TU_ATTR_ALWAYS_INLINE static inline void *_phys_addr(void *virtual_address) if (tusb_app_virt_to_phys) return tusb_app_virt_to_phys(virtual_address); return virtual_address; } + TU_ATTR_ALWAYS_INLINE static inline void *_virt_addr(void *physical_address) { if (tusb_app_phys_to_virt) return tusb_app_phys_to_virt(physical_address); @@ -238,7 +239,10 @@ bool hcd_init(uint8_t rhport) OHCI_REG->control_bit.hc_functional_state = OHCI_CONTROL_FUNCSTATE_OPERATIONAL; // make HC's state to operational state TODO use this to suspend (save power) OHCI_REG->rh_status_bit.local_power_status_change = 1; // set global power for ports +#if CFG_TUSB_OS != OPT_OS_NONE + // TODO as above delay osal_task_delay(OHCI_REG->rh_descriptorA_bit.power_on_to_good_time * 2); // Wait POTG after power up +#endif return true; }