Skip to content

Commit a3e017b

Browse files
committed
EHCI adding dcahe support, passing enumertaion
1 parent eb89df4 commit a3e017b

File tree

4 files changed

+117
-65
lines changed

4 files changed

+117
-65
lines changed

src/host/hcd.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,12 +108,18 @@ typedef struct
108108
// Memory API
109109
//--------------------------------------------------------------------+
110110

111-
// clean/flush data cache: write cache -> memory
111+
// clean/flush data cache: write cache -> memory.
112+
// Required before an DMA TX transfer to make sure data is in memory
112113
void hcd_dcache_clean(void* addr, uint32_t data_size) TU_ATTR_WEAK;
113114

114115
// invalidate data cache: mark cache as invalid, next read will read from memory
116+
// Required BOTH before and after an DMA RX transfer
115117
void hcd_dcache_invalidate(void* addr, uint32_t data_size) TU_ATTR_WEAK;
116118

119+
// clean and invalidate data cache
120+
// Required before an DMA transfer where memory is both read/write by DMA
121+
void hcd_dcache_clean_invalidate(void* addr, uint32_t data_size) TU_ATTR_WEAK;
122+
117123
//--------------------------------------------------------------------+
118124
// Controller API
119125
//--------------------------------------------------------------------+
@@ -194,6 +200,7 @@ void hcd_event_device_attach(uint8_t rhport, bool in_isr)
194200
event.event_id = HCD_EVENT_DEVICE_ATTACH;
195201
event.connection.hub_addr = 0;
196202
event.connection.hub_port = 0;
203+
197204
hcd_event_handler(&event, in_isr);
198205
}
199206

@@ -224,7 +231,6 @@ void hcd_event_xfer_complete(uint8_t dev_addr, uint8_t ep_addr, uint32_t xferred
224231
event.xfer_complete.result = result;
225232
event.xfer_complete.len = xferred_bytes;
226233

227-
228234
hcd_event_handler(&event, in_isr);
229235
}
230236

src/portable/chipidea/ci_hs/hcd_ci_hs.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@
5050
SCB_InvalidateDCache_by_Addr(addr, (int32_t) data_size);
5151
}
5252

53+
void hcd_dcache_clean_invalidate(void* addr, uint32_t data_size) {
54+
SCB_CleanInvalidateDCache_by_Addr(addr, (int32_t) data_size);
55+
}
56+
5357
#elif TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX)
5458
#include "ci_hs_lpc18_43.h"
5559
#else

src/portable/ehci/ehci.c

Lines changed: 104 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ CFG_TUH_MEM_SECTION TU_ATTR_ALIGNED(4096) static ehci_data_t ehci_data;
9292
//--------------------------------------------------------------------+
9393
// Debug
9494
//--------------------------------------------------------------------+
95-
#if CFG_TUSB_DEBUG >= EHCI_DBG
95+
#if CFG_TUSB_DEBUG >= (EHCI_DBG + 1)
9696
static inline void print_portsc(ehci_registers_t* regs) {
9797
TU_LOG_HEX(EHCI_DBG, regs->portsc);
9898
TU_LOG(EHCI_DBG, " Connect Status : %u\r\n", regs->portsc_bm.current_connect_status);
@@ -159,7 +159,7 @@ static inline ehci_qtd_t* qtd_find_free (void);
159159
static inline ehci_qtd_t* qtd_next (ehci_qtd_t const * p_qtd);
160160
static inline void qtd_insert_to_qhd (ehci_qhd_t *p_qhd, ehci_qtd_t *p_qtd_new);
161161
static inline void qtd_remove_1st_from_qhd (ehci_qhd_t *p_qhd);
162-
static void qtd_init (ehci_qtd_t* p_qtd, void const* buffer, uint16_t total_bytes);
162+
static void qtd_init (ehci_qtd_t* qtd, void const* buffer, uint16_t total_bytes);
163163

164164
static inline void list_insert (ehci_link_t *current, ehci_link_t *new, uint8_t new_type);
165165
static inline ehci_link_t* list_next (ehci_link_t *p_link_pointer);
@@ -325,28 +325,27 @@ bool ehci_init(uint8_t rhport, uint32_t capability_reg, uint32_t operatial_reg)
325325
// 3 --> period_head_arr[3] (8ms)
326326

327327
// TODO EHCI_FRAMELIST_SIZE with other size than 8
328-
for(uint32_t i=0; i<FRAMELIST_SIZE; i++)
329-
{
328+
for (uint32_t i = 0; i < FRAMELIST_SIZE; i++) {
330329
framelist[i].address = (uint32_t) period_1ms;
331-
framelist[i].type = EHCI_QTYPE_QHD;
330+
framelist[i].type = EHCI_QTYPE_QHD;
332331
}
333332

334-
for(uint32_t i=0; i<FRAMELIST_SIZE; i+=2)
335-
{
333+
for (uint32_t i = 0; i < FRAMELIST_SIZE; i += 2) {
336334
list_insert(framelist + i, get_period_head(rhport, 2u), EHCI_QTYPE_QHD);
337335
}
338336

339-
for(uint32_t i=1; i<FRAMELIST_SIZE; i+=4)
340-
{
337+
for (uint32_t i = 1; i < FRAMELIST_SIZE; i += 4) {
341338
list_insert(framelist + i, get_period_head(rhport, 4u), EHCI_QTYPE_QHD);
342339
}
343-
344-
list_insert(framelist+3, get_period_head(rhport, 8u), EHCI_QTYPE_QHD);
345-
340+
list_insert(framelist + 3, get_period_head(rhport, 8u), EHCI_QTYPE_QHD);
346341
period_1ms->terminate = 1;
347342

348343
regs->periodic_list_base = (uint32_t) framelist;
349344

345+
if(hcd_dcache_clean) {
346+
hcd_dcache_clean(&ehci_data, sizeof(ehci_data_t));
347+
}
348+
350349
//------------- TT Control (NXP only) -------------//
351350
regs->nxp_tt_control = 0;
352351

@@ -430,6 +429,11 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const
430429
// TODO might need to disable async/period list
431430
list_insert(list_head, (ehci_link_t*) p_qhd, EHCI_QTYPE_QHD);
432431

432+
if(hcd_dcache_clean) {
433+
hcd_dcache_clean(p_qhd, sizeof(ehci_qhd_t));
434+
hcd_dcache_clean(list_head, sizeof(ehci_link_t));
435+
}
436+
433437
return true;
434438
}
435439

@@ -441,9 +445,12 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet
441445
ehci_qtd_t* td = &ehci_data.control[dev_addr].qtd;
442446

443447
qtd_init(td, setup_packet, 8);
444-
td->pid = EHCI_PID_SETUP;
445-
td->int_on_complete = 1;
446-
td->next.terminate = 1;
448+
td->pid = EHCI_PID_SETUP;
449+
450+
if (hcd_dcache_clean && hcd_dcache_clean_invalidate) {
451+
hcd_dcache_clean((void *) setup_packet, 8);
452+
hcd_dcache_clean_invalidate(td, sizeof(ehci_qtd_t));
453+
}
447454

448455
// sw region
449456
qhd->p_qtd_list_head = td;
@@ -452,6 +459,10 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet
452459
// attach TD
453460
qhd->qtd_overlay.next.address = (uint32_t) td;
454461

462+
if (hcd_dcache_clean_invalidate) {
463+
hcd_dcache_clean_invalidate(qhd, sizeof(ehci_qhd_t));
464+
}
465+
455466
return true;
456467
}
457468

@@ -462,41 +473,48 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
462473
uint8_t const epnum = tu_edpt_number(ep_addr);
463474
uint8_t const dir = tu_edpt_dir(ep_addr);
464475

476+
ehci_qhd_t* qhd;
477+
ehci_qtd_t* qtd;
478+
465479
if ( epnum == 0 )
466480
{
467-
ehci_qhd_t* qhd = qhd_control(dev_addr);
468-
ehci_qtd_t* qtd = qtd_control(dev_addr);
481+
qhd = qhd_control(dev_addr);
482+
qtd = qtd_control(dev_addr);
469483

470484
qtd_init(qtd, buffer, buflen);
471485

472486
// first first data toggle is always 1 (data & setup stage)
473487
qtd->data_toggle = 1;
474488
qtd->pid = dir ? EHCI_PID_IN : EHCI_PID_OUT;
475-
qtd->int_on_complete = 1;
476-
qtd->next.terminate = 1;
477-
478-
// sw region
479-
qhd->p_qtd_list_head = qtd;
480-
qhd->p_qtd_list_tail = qtd;
481-
482-
// attach TD
483-
qhd->qtd_overlay.next.address = (uint32_t) qtd;
484489
}else
485490
{
486-
ehci_qhd_t *p_qhd = qhd_get_from_addr(dev_addr, ep_addr);
487-
ehci_qtd_t *p_qtd = qtd_find_free();
488-
TU_ASSERT(p_qtd);
491+
qhd = qhd_get_from_addr(dev_addr, ep_addr);
492+
qtd = qtd_find_free();
493+
TU_ASSERT(qtd);
494+
495+
qtd_init(qtd, buffer, buflen);
496+
qtd->pid = qhd->pid;
497+
}
489498

490-
qtd_init(p_qtd, buffer, buflen);
491-
p_qtd->pid = p_qhd->pid;
499+
if (hcd_dcache_clean && hcd_dcache_clean_invalidate) {
500+
// IN transfer: invalidate buffer, OUT transfer: clean buffer
501+
if (dir) {
502+
hcd_dcache_invalidate(buffer, buflen);
503+
}else {
504+
hcd_dcache_clean(buffer, buflen);
505+
}
506+
hcd_dcache_clean_invalidate(qtd, sizeof(ehci_qtd_t));
507+
}
492508

493-
// Insert TD to QH
494-
qtd_insert_to_qhd(p_qhd, p_qtd);
509+
// Software: assign TD to QHD
510+
qhd->p_qtd_list_head = qtd;
511+
qhd->p_qtd_list_tail = qtd;
495512

496-
p_qhd->p_qtd_list_tail->int_on_complete = 1;
513+
// attach TD to QHD start transferring
514+
qhd->qtd_overlay.next.address = (uint32_t) qtd;
497515

498-
// attach head QTD to QHD start transferring
499-
p_qhd->qtd_overlay.next.address = (uint32_t) p_qhd->p_qtd_list_head;
516+
if (hcd_dcache_clean_invalidate) {
517+
hcd_dcache_clean_invalidate(qhd, sizeof(ehci_qhd_t));
500518
}
501519

502520
return true;
@@ -551,6 +569,11 @@ static void qhd_xfer_complete_isr(ehci_qhd_t * p_qhd)
551569
while(p_qhd->p_qtd_list_head != NULL && !p_qhd->p_qtd_list_head->active)
552570
{
553571
ehci_qtd_t * volatile qtd = (ehci_qtd_t * volatile) p_qhd->p_qtd_list_head;
572+
573+
if (hcd_dcache_invalidate) {
574+
hcd_dcache_invalidate(qtd, sizeof(ehci_qtd_t));
575+
}
576+
554577
bool const is_ioc = (qtd->int_on_complete != 0);
555578
uint8_t const ep_addr = tu_edpt_addr(p_qhd->ep_number, qtd->pid == EHCI_PID_IN ? 1 : 0);
556579

@@ -573,8 +596,12 @@ static void async_list_xfer_complete_isr(ehci_qhd_t * const async_head)
573596
ehci_qhd_t *p_qhd = async_head;
574597
do
575598
{
576-
if ( !p_qhd->qtd_overlay.halted ) // halted or error is processed in error isr
577-
{
599+
if (hcd_dcache_invalidate) {
600+
hcd_dcache_invalidate(p_qhd, sizeof(ehci_qhd_t));
601+
}
602+
603+
// halted or error is processed in error isr
604+
if ( !p_qhd->qtd_overlay.halted ) {
578605
qhd_xfer_complete_isr(p_qhd);
579606
}
580607
p_qhd = qhd_next(p_qhd);
@@ -640,8 +667,8 @@ static void qhd_xfer_error_isr(ehci_qhd_t * p_qhd)
640667
// while(1){}
641668
// }
642669

643-
// No TD, probably an signal noise ?
644-
TU_VERIFY(p_qhd->p_qtd_list_head, );
670+
// No TD yet, it is probably the probably an signal noise ?
671+
TU_ASSERT(p_qhd->p_qtd_list_head, );
645672

646673
p_qhd->p_qtd_list_head->used = 0; // free QTD
647674
qtd_remove_1st_from_qhd(p_qhd);
@@ -714,17 +741,19 @@ static void xfer_error_isr(uint8_t hostid)
714741
void hcd_int_handler(uint8_t rhport)
715742
{
716743
ehci_registers_t* regs = ehci_data.regs;
744+
uint32_t const int_status = regs->status;
717745

718-
uint32_t int_status = regs->status;
719-
int_status &= regs->inten;
720-
721-
regs->status = int_status; // Acknowledge handled interrupt
722-
723-
if (int_status == 0) return;
746+
if (int_status & EHCI_INT_MASK_HC_HALTED) {
747+
// something seriously wrong, maybe forget to flush/invalidate cache
748+
TU_BREAKPOINT();
749+
TU_LOG1(" HC halted\n");
750+
return;
751+
}
724752

725753
if (int_status & EHCI_INT_MASK_FRAMELIST_ROLLOVER)
726754
{
727755
ehci_data.uframe_number += (FRAMELIST_SIZE << 3);
756+
regs->status = EHCI_INT_MASK_FRAMELIST_ROLLOVER; // Acknowledge
728757
}
729758

730759
if (int_status & EHCI_INT_MASK_PORT_CHANGE)
@@ -739,31 +768,41 @@ void hcd_int_handler(uint8_t rhport)
739768
}
740769

741770
regs->portsc |= port_status; // Acknowledge change bits in portsc
771+
regs->status = EHCI_INT_MASK_PORT_CHANGE; // Acknowledge
742772
}
743773

744774
if (int_status & EHCI_INT_MASK_ERROR)
745775
{
746776
xfer_error_isr(rhport);
777+
regs->status = EHCI_INT_MASK_ERROR; // Acknowledge
747778
}
748779

749780
//------------- some QTD/SITD/ITD with IOC set is completed -------------//
750781
if (int_status & EHCI_INT_MASK_NXP_ASYNC)
751782
{
752-
async_list_xfer_complete_isr( qhd_async_head(rhport) );
783+
async_list_xfer_complete_isr(qhd_async_head(rhport));
784+
regs->status = EHCI_INT_MASK_NXP_ASYNC; // Acknowledge
753785
}
754786

755787
if (int_status & EHCI_INT_MASK_NXP_PERIODIC)
756788
{
757789
for (uint32_t i=1; i <= FRAMELIST_SIZE; i *= 2)
758790
{
759-
period_list_xfer_complete_isr( rhport, i );
791+
period_list_xfer_complete_isr(rhport, i);
760792
}
793+
regs->status = EHCI_INT_MASK_NXP_PERIODIC; // Acknowledge
794+
}
795+
796+
if (int_status & EHCI_INT_MASK_USB) {
797+
// TODO standard EHCI xfer complete
798+
regs->status = EHCI_INT_MASK_USB; // Acknowledge
761799
}
762800

763801
//------------- There is some removed async previously -------------//
764-
if (int_status & EHCI_INT_MASK_ASYNC_ADVANCE) // need to place after EHCI_INT_MASK_NXP_ASYNC
765-
{
802+
// need to place after EHCI_INT_MASK_NXP_ASYNC
803+
if (int_status & EHCI_INT_MASK_ASYNC_ADVANCE) {
766804
async_advance_isr(rhport);
805+
regs->status = EHCI_INT_MASK_ASYNC_ADVANCE; // Acknowledge
767806
}
768807
}
769808

@@ -918,28 +957,30 @@ static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t c
918957
}
919958
}
920959

921-
static void qtd_init(ehci_qtd_t* p_qtd, void const* buffer, uint16_t total_bytes)
960+
static void qtd_init(ehci_qtd_t* qtd, void const* buffer, uint16_t total_bytes)
922961
{
923-
tu_memclr(p_qtd, sizeof(ehci_qtd_t));
962+
tu_memclr(qtd, sizeof(ehci_qtd_t));
963+
qtd->used = 1;
924964

925-
p_qtd->used = 1;
965+
qtd->next.terminate = 1; // init to null
966+
qtd->alternate.terminate = 1; // not used, always set to terminated
967+
qtd->active = 1;
968+
qtd->err_count = 3; // TODO 3 consecutive errors tolerance
969+
qtd->data_toggle = 0;
970+
qtd->int_on_complete = 1;
971+
qtd->total_bytes = total_bytes;
972+
qtd->expected_bytes = total_bytes;
926973

927-
p_qtd->next.terminate = 1; // init to null
928-
p_qtd->alternate.terminate = 1; // not used, always set to terminated
929-
p_qtd->active = 1;
930-
p_qtd->err_count = 3; // TODO 3 consecutive errors tolerance
931-
p_qtd->data_toggle = 0;
932-
p_qtd->total_bytes = total_bytes;
933-
p_qtd->expected_bytes = total_bytes;
934-
935-
p_qtd->buffer[0] = (uint32_t) buffer;
974+
qtd->buffer[0] = (uint32_t) buffer;
936975
for(uint8_t i=1; i<5; i++)
937976
{
938-
p_qtd->buffer[i] |= tu_align4k( p_qtd->buffer[i-1] ) + 4096;
977+
qtd->buffer[i] |= tu_align4k(qtd->buffer[i - 1] ) + 4096;
939978
}
940979
}
941980

942981
//------------- List Managing Helper -------------//
982+
983+
// insert at head
943984
static inline void list_insert(ehci_link_t *current, ehci_link_t *new, uint8_t new_type)
944985
{
945986
new->address = current->address;

src/portable/ehci/ehci.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ typedef struct TU_ATTR_ALIGNED(32)
165165
uint16_t total_xferred_bytes; // number of bytes xferred until a qtd with ioc bit set
166166
uint8_t reserved2[2];
167167

168+
// TODO USBH will only queue 1 TD per QHD, thus we can remove the list
168169
ehci_qtd_t * volatile p_qtd_list_head; // head of the scheduled TD list
169170
ehci_qtd_t * volatile p_qtd_list_tail; // tail of the scheduled TD list
170171
} ehci_qhd_t;

0 commit comments

Comments
 (0)