EHCI adding dcahe support, passing enumertaion
This commit is contained in:
		@@ -92,7 +92,7 @@ CFG_TUH_MEM_SECTION TU_ATTR_ALIGNED(4096) static ehci_data_t ehci_data;
 | 
			
		||||
//--------------------------------------------------------------------+
 | 
			
		||||
// Debug
 | 
			
		||||
//--------------------------------------------------------------------+
 | 
			
		||||
#if CFG_TUSB_DEBUG >= EHCI_DBG
 | 
			
		||||
#if CFG_TUSB_DEBUG >= (EHCI_DBG + 1)
 | 
			
		||||
static inline void print_portsc(ehci_registers_t* regs) {
 | 
			
		||||
  TU_LOG_HEX(EHCI_DBG, regs->portsc);
 | 
			
		||||
  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);
 | 
			
		||||
static inline ehci_qtd_t* qtd_next (ehci_qtd_t const * p_qtd);
 | 
			
		||||
static inline void qtd_insert_to_qhd (ehci_qhd_t *p_qhd, ehci_qtd_t *p_qtd_new);
 | 
			
		||||
static inline void qtd_remove_1st_from_qhd (ehci_qhd_t *p_qhd);
 | 
			
		||||
static void qtd_init (ehci_qtd_t* p_qtd, void const* buffer, uint16_t total_bytes);
 | 
			
		||||
static void qtd_init (ehci_qtd_t* qtd, void const* buffer, uint16_t total_bytes);
 | 
			
		||||
 | 
			
		||||
static inline void list_insert (ehci_link_t *current, ehci_link_t *new, uint8_t new_type);
 | 
			
		||||
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)
 | 
			
		||||
  // 3 --> period_head_arr[3] (8ms)
 | 
			
		||||
 | 
			
		||||
  // TODO EHCI_FRAMELIST_SIZE with other size than 8
 | 
			
		||||
  for(uint32_t i=0; i<FRAMELIST_SIZE; i++)
 | 
			
		||||
  {
 | 
			
		||||
  for (uint32_t i = 0; i < FRAMELIST_SIZE; i++) {
 | 
			
		||||
    framelist[i].address = (uint32_t) period_1ms;
 | 
			
		||||
    framelist[i].type    = EHCI_QTYPE_QHD;
 | 
			
		||||
    framelist[i].type = EHCI_QTYPE_QHD;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  for(uint32_t i=0; i<FRAMELIST_SIZE; i+=2)
 | 
			
		||||
  {
 | 
			
		||||
  for (uint32_t i = 0; i < FRAMELIST_SIZE; i += 2) {
 | 
			
		||||
    list_insert(framelist + i, get_period_head(rhport, 2u), EHCI_QTYPE_QHD);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  for(uint32_t i=1; i<FRAMELIST_SIZE; i+=4)
 | 
			
		||||
  {
 | 
			
		||||
  for (uint32_t i = 1; i < FRAMELIST_SIZE; i += 4) {
 | 
			
		||||
    list_insert(framelist + i, get_period_head(rhport, 4u), EHCI_QTYPE_QHD);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  list_insert(framelist+3, get_period_head(rhport, 8u), EHCI_QTYPE_QHD);
 | 
			
		||||
 | 
			
		||||
  list_insert(framelist + 3, get_period_head(rhport, 8u), EHCI_QTYPE_QHD);
 | 
			
		||||
  period_1ms->terminate    = 1;
 | 
			
		||||
 | 
			
		||||
  regs->periodic_list_base = (uint32_t) framelist;
 | 
			
		||||
 | 
			
		||||
  if(hcd_dcache_clean) {
 | 
			
		||||
    hcd_dcache_clean(&ehci_data, sizeof(ehci_data_t));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  //------------- TT Control (NXP only) -------------//
 | 
			
		||||
  regs->nxp_tt_control = 0;
 | 
			
		||||
 | 
			
		||||
@@ -430,6 +429,11 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const
 | 
			
		||||
  // TODO might need to disable async/period list
 | 
			
		||||
  list_insert(list_head, (ehci_link_t*) p_qhd, EHCI_QTYPE_QHD);
 | 
			
		||||
 | 
			
		||||
  if(hcd_dcache_clean) {
 | 
			
		||||
    hcd_dcache_clean(p_qhd, sizeof(ehci_qhd_t));
 | 
			
		||||
    hcd_dcache_clean(list_head, sizeof(ehci_link_t));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -441,9 +445,12 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet
 | 
			
		||||
  ehci_qtd_t* td  = &ehci_data.control[dev_addr].qtd;
 | 
			
		||||
 | 
			
		||||
  qtd_init(td, setup_packet, 8);
 | 
			
		||||
  td->pid          = EHCI_PID_SETUP;
 | 
			
		||||
  td->int_on_complete = 1;
 | 
			
		||||
  td->next.terminate  = 1;
 | 
			
		||||
  td->pid = EHCI_PID_SETUP;
 | 
			
		||||
 | 
			
		||||
  if (hcd_dcache_clean && hcd_dcache_clean_invalidate) {
 | 
			
		||||
    hcd_dcache_clean((void *) setup_packet, 8);
 | 
			
		||||
    hcd_dcache_clean_invalidate(td, sizeof(ehci_qtd_t));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // sw region
 | 
			
		||||
  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
 | 
			
		||||
  // attach TD
 | 
			
		||||
  qhd->qtd_overlay.next.address = (uint32_t) td;
 | 
			
		||||
 | 
			
		||||
  if (hcd_dcache_clean_invalidate) {
 | 
			
		||||
    hcd_dcache_clean_invalidate(qhd, sizeof(ehci_qhd_t));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -462,41 +473,48 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
 | 
			
		||||
  uint8_t const epnum = tu_edpt_number(ep_addr);
 | 
			
		||||
  uint8_t const dir   = tu_edpt_dir(ep_addr);
 | 
			
		||||
 | 
			
		||||
  ehci_qhd_t* qhd;
 | 
			
		||||
  ehci_qtd_t* qtd;
 | 
			
		||||
 | 
			
		||||
  if ( epnum == 0 )
 | 
			
		||||
  {
 | 
			
		||||
    ehci_qhd_t* qhd = qhd_control(dev_addr);
 | 
			
		||||
    ehci_qtd_t* qtd = qtd_control(dev_addr);
 | 
			
		||||
    qhd = qhd_control(dev_addr);
 | 
			
		||||
    qtd = qtd_control(dev_addr);
 | 
			
		||||
 | 
			
		||||
    qtd_init(qtd, buffer, buflen);
 | 
			
		||||
 | 
			
		||||
    // first first data toggle is always 1 (data & setup stage)
 | 
			
		||||
    qtd->data_toggle = 1;
 | 
			
		||||
    qtd->pid = dir ? EHCI_PID_IN : EHCI_PID_OUT;
 | 
			
		||||
    qtd->int_on_complete = 1;
 | 
			
		||||
    qtd->next.terminate  = 1;
 | 
			
		||||
 | 
			
		||||
    // sw region
 | 
			
		||||
    qhd->p_qtd_list_head = qtd;
 | 
			
		||||
    qhd->p_qtd_list_tail = qtd;
 | 
			
		||||
 | 
			
		||||
    // attach TD
 | 
			
		||||
    qhd->qtd_overlay.next.address = (uint32_t) qtd;
 | 
			
		||||
  }else
 | 
			
		||||
  {
 | 
			
		||||
    ehci_qhd_t *p_qhd = qhd_get_from_addr(dev_addr, ep_addr);
 | 
			
		||||
    ehci_qtd_t *p_qtd = qtd_find_free();
 | 
			
		||||
    TU_ASSERT(p_qtd);
 | 
			
		||||
    qhd = qhd_get_from_addr(dev_addr, ep_addr);
 | 
			
		||||
    qtd = qtd_find_free();
 | 
			
		||||
    TU_ASSERT(qtd);
 | 
			
		||||
 | 
			
		||||
    qtd_init(p_qtd, buffer, buflen);
 | 
			
		||||
    p_qtd->pid = p_qhd->pid;
 | 
			
		||||
    qtd_init(qtd, buffer, buflen);
 | 
			
		||||
    qtd->pid = qhd->pid;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
    // Insert TD to QH
 | 
			
		||||
    qtd_insert_to_qhd(p_qhd, p_qtd);
 | 
			
		||||
  if (hcd_dcache_clean && hcd_dcache_clean_invalidate) {
 | 
			
		||||
    // IN transfer: invalidate buffer, OUT transfer: clean buffer
 | 
			
		||||
    if (dir) {
 | 
			
		||||
      hcd_dcache_invalidate(buffer, buflen);
 | 
			
		||||
    }else {
 | 
			
		||||
      hcd_dcache_clean(buffer, buflen);
 | 
			
		||||
    }
 | 
			
		||||
    hcd_dcache_clean_invalidate(qtd, sizeof(ehci_qtd_t));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
    p_qhd->p_qtd_list_tail->int_on_complete = 1;
 | 
			
		||||
  // Software: assign TD to QHD
 | 
			
		||||
  qhd->p_qtd_list_head = qtd;
 | 
			
		||||
  qhd->p_qtd_list_tail = qtd;
 | 
			
		||||
 | 
			
		||||
    // attach head QTD to QHD start transferring
 | 
			
		||||
    p_qhd->qtd_overlay.next.address = (uint32_t) p_qhd->p_qtd_list_head;
 | 
			
		||||
  // attach TD to QHD start transferring
 | 
			
		||||
  qhd->qtd_overlay.next.address = (uint32_t) qtd;
 | 
			
		||||
 | 
			
		||||
  if (hcd_dcache_clean_invalidate) {
 | 
			
		||||
    hcd_dcache_clean_invalidate(qhd, sizeof(ehci_qhd_t));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return true;
 | 
			
		||||
@@ -551,6 +569,11 @@ static void qhd_xfer_complete_isr(ehci_qhd_t * p_qhd)
 | 
			
		||||
  while(p_qhd->p_qtd_list_head != NULL && !p_qhd->p_qtd_list_head->active)
 | 
			
		||||
  {
 | 
			
		||||
    ehci_qtd_t * volatile qtd = (ehci_qtd_t * volatile) p_qhd->p_qtd_list_head;
 | 
			
		||||
 | 
			
		||||
    if (hcd_dcache_invalidate) {
 | 
			
		||||
      hcd_dcache_invalidate(qtd, sizeof(ehci_qtd_t));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool const is_ioc = (qtd->int_on_complete != 0);
 | 
			
		||||
    uint8_t const ep_addr = tu_edpt_addr(p_qhd->ep_number, qtd->pid == EHCI_PID_IN ? 1 : 0);
 | 
			
		||||
 | 
			
		||||
@@ -573,8 +596,12 @@ static void async_list_xfer_complete_isr(ehci_qhd_t * const async_head)
 | 
			
		||||
  ehci_qhd_t *p_qhd = async_head;
 | 
			
		||||
  do
 | 
			
		||||
  {
 | 
			
		||||
    if ( !p_qhd->qtd_overlay.halted ) // halted or error is processed in error isr
 | 
			
		||||
    {
 | 
			
		||||
    if (hcd_dcache_invalidate) {
 | 
			
		||||
      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);
 | 
			
		||||
@@ -640,8 +667,8 @@ static void qhd_xfer_error_isr(ehci_qhd_t * p_qhd)
 | 
			
		||||
//      while(1){}
 | 
			
		||||
//    }
 | 
			
		||||
 | 
			
		||||
    // No TD, probably an signal noise ?
 | 
			
		||||
    TU_VERIFY(p_qhd->p_qtd_list_head, );
 | 
			
		||||
    // No TD yet, it is probably the probably an signal noise ?
 | 
			
		||||
    TU_ASSERT(p_qhd->p_qtd_list_head, );
 | 
			
		||||
 | 
			
		||||
    p_qhd->p_qtd_list_head->used = 0; // free QTD
 | 
			
		||||
    qtd_remove_1st_from_qhd(p_qhd);
 | 
			
		||||
@@ -714,17 +741,19 @@ static void xfer_error_isr(uint8_t hostid)
 | 
			
		||||
void hcd_int_handler(uint8_t rhport)
 | 
			
		||||
{
 | 
			
		||||
  ehci_registers_t* regs = ehci_data.regs;
 | 
			
		||||
  uint32_t const int_status = regs->status;
 | 
			
		||||
 | 
			
		||||
  uint32_t int_status = regs->status;
 | 
			
		||||
  int_status &= regs->inten;
 | 
			
		||||
 | 
			
		||||
  regs->status = int_status; // Acknowledge handled interrupt
 | 
			
		||||
 | 
			
		||||
  if (int_status == 0) return;
 | 
			
		||||
  if (int_status & EHCI_INT_MASK_HC_HALTED) {
 | 
			
		||||
    // something seriously wrong, maybe forget to flush/invalidate cache
 | 
			
		||||
    TU_BREAKPOINT();
 | 
			
		||||
    TU_LOG1("  HC halted\n");
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (int_status & EHCI_INT_MASK_FRAMELIST_ROLLOVER)
 | 
			
		||||
  {
 | 
			
		||||
    ehci_data.uframe_number += (FRAMELIST_SIZE << 3);
 | 
			
		||||
    regs->status = EHCI_INT_MASK_FRAMELIST_ROLLOVER; // Acknowledge
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (int_status & EHCI_INT_MASK_PORT_CHANGE)
 | 
			
		||||
@@ -739,31 +768,41 @@ void hcd_int_handler(uint8_t rhport)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    regs->portsc |= port_status; // Acknowledge change bits in portsc
 | 
			
		||||
    regs->status = EHCI_INT_MASK_PORT_CHANGE; // Acknowledge
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (int_status & EHCI_INT_MASK_ERROR)
 | 
			
		||||
  {
 | 
			
		||||
    xfer_error_isr(rhport);
 | 
			
		||||
    regs->status = EHCI_INT_MASK_ERROR; // Acknowledge
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  //------------- some QTD/SITD/ITD with IOC set is completed -------------//
 | 
			
		||||
  if (int_status & EHCI_INT_MASK_NXP_ASYNC)
 | 
			
		||||
  {
 | 
			
		||||
    async_list_xfer_complete_isr( qhd_async_head(rhport) );
 | 
			
		||||
    async_list_xfer_complete_isr(qhd_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 );
 | 
			
		||||
      period_list_xfer_complete_isr(rhport, i);
 | 
			
		||||
    }
 | 
			
		||||
    regs->status = EHCI_INT_MASK_NXP_PERIODIC; // Acknowledge
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (int_status & EHCI_INT_MASK_USB) {
 | 
			
		||||
    // TODO standard EHCI xfer complete
 | 
			
		||||
    regs->status = EHCI_INT_MASK_USB; // Acknowledge
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  //------------- There is some removed async previously -------------//
 | 
			
		||||
  if (int_status & EHCI_INT_MASK_ASYNC_ADVANCE) // need to place after EHCI_INT_MASK_NXP_ASYNC
 | 
			
		||||
  {
 | 
			
		||||
  // need to place after EHCI_INT_MASK_NXP_ASYNC
 | 
			
		||||
  if (int_status & EHCI_INT_MASK_ASYNC_ADVANCE) {
 | 
			
		||||
    async_advance_isr(rhport);
 | 
			
		||||
    regs->status = EHCI_INT_MASK_ASYNC_ADVANCE; // Acknowledge
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -918,28 +957,30 @@ static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t c
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void qtd_init(ehci_qtd_t* p_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(p_qtd, sizeof(ehci_qtd_t));
 | 
			
		||||
  tu_memclr(qtd, sizeof(ehci_qtd_t));
 | 
			
		||||
  qtd->used                = 1;
 | 
			
		||||
 | 
			
		||||
  p_qtd->used                = 1;
 | 
			
		||||
  qtd->next.terminate      = 1; // init to null
 | 
			
		||||
  qtd->alternate.terminate = 1; // not used, always set to terminated
 | 
			
		||||
  qtd->active              = 1;
 | 
			
		||||
  qtd->err_count           = 3; // TODO 3 consecutive errors tolerance
 | 
			
		||||
  qtd->data_toggle         = 0;
 | 
			
		||||
  qtd->int_on_complete     = 1;
 | 
			
		||||
  qtd->total_bytes         = total_bytes;
 | 
			
		||||
  qtd->expected_bytes      = total_bytes;
 | 
			
		||||
 | 
			
		||||
  p_qtd->next.terminate      = 1; // init to null
 | 
			
		||||
  p_qtd->alternate.terminate = 1; // not used, always set to terminated
 | 
			
		||||
  p_qtd->active              = 1;
 | 
			
		||||
  p_qtd->err_count           = 3; // TODO 3 consecutive errors tolerance
 | 
			
		||||
  p_qtd->data_toggle         = 0;
 | 
			
		||||
  p_qtd->total_bytes         = total_bytes;
 | 
			
		||||
  p_qtd->expected_bytes      = total_bytes;
 | 
			
		||||
 | 
			
		||||
  p_qtd->buffer[0] = (uint32_t) buffer;
 | 
			
		||||
  qtd->buffer[0] = (uint32_t) buffer;
 | 
			
		||||
  for(uint8_t i=1; i<5; i++)
 | 
			
		||||
  {
 | 
			
		||||
    p_qtd->buffer[i] |= tu_align4k( p_qtd->buffer[i-1] ) + 4096;
 | 
			
		||||
    qtd->buffer[i] |= tu_align4k(qtd->buffer[i - 1] ) + 4096;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//------------- List Managing Helper -------------//
 | 
			
		||||
 | 
			
		||||
// insert at head
 | 
			
		||||
static inline void list_insert(ehci_link_t *current, ehci_link_t *new, uint8_t new_type)
 | 
			
		||||
{
 | 
			
		||||
  new->address = current->address;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user