23static qTD_T *_ghost_qtd;
24static QH_T *qh_remove_list;
26extern ISO_EP_T *iso_ep_list;
27extern int ehci_iso_xfer(UTR_T *utr);
28extern int ehci_quit_iso_xfer(UTR_T *utr, EP_INFO_T *ep);
31#pragma data_alignment=4096
32uint32_t _PFList[FL_SIZE];
40#ifdef ENABLE_ERROR_MSG
43 USB_debug(
"Dump HSUSBH(EHCI) registers:\n");
44 USB_debug(
" UCMDR = 0x%x\n", _ehci->UCMDR);
45 USB_debug(
" USTSR = 0x%x\n", _ehci->USTSR);
46 USB_debug(
" UIENR = 0x%x\n", _ehci->UIENR);
47 USB_debug(
" UFINDR = 0x%x\n", _ehci->UFINDR);
48 USB_debug(
" UPFLBAR = 0x%x\n", _ehci->UPFLBAR);
49 USB_debug(
" UCALAR = 0x%x\n", _ehci->UCALAR);
50 USB_debug(
" UASSTR = 0x%x\n", _ehci->UASSTR);
51 USB_debug(
" UCFGR = 0x%x\n", _ehci->UCFGR);
52 USB_debug(
" UPSCR = 0x%x\n", _ehci->UPSCR[0]);
53 USB_debug(
" PHYCTL0 = 0x%x\n", _ehci->USBPCR0);
54 USB_debug(
" PHYCTL1 = 0x%x\n", _ehci->USBPCR1);
59 USB_debug(
"_ehci port0=0x%x, port1=0x%x\n", _ehci->UPSCR[0], _ehci->UPSCR[1]);
62void dump_ehci_qtd(qTD_T *qtd)
64 USB_debug(
" [qTD] - 0x%08x\n", (
int)qtd);
65 USB_debug(
" 0x%08x (Next qtd Pointer)\n", qtd->Next_qTD);
66 USB_debug(
" 0x%08x (Alternate Next qtd Pointer)\n", qtd->Alt_Next_qTD);
67 USB_debug(
" 0x%08x (qtd Token) PID: %s, Bytes: %d, IOC: %d\n", qtd->Token, (((qtd->Token>>8)&0x3)==0) ?
"OUT" : ((((qtd->Token>>8)&0x3)==1) ?
"IN" :
"SETUP"), (qtd->Token>>16)&0x7FFF, (qtd->Token>>15)&0x1);
68 USB_debug(
" 0x%08x (Buffer Pointer (page 0))\n", qtd->Bptr[0]);
76void dump_ehci_asynclist(
void)
81 USB_debug(
">>> Dump EHCI Asynchronous List <<<\n");
84 USB_debug(
"[QH] - 0x%08x\n", (
int)qh);
85 USB_debug(
" 0x%08x (Queue Head Horizontal Link Pointer, Queue Head DWord 0)\n", qh->HLink);
86 USB_debug(
" 0x%08x (Endpoint Characteristics) DevAddr: %d, EP: 0x%x, PktSz: %d, Speed: %s\n", qh->Chrst, qh->Chrst&0x7F, (qh->Chrst>>8)&0xF, (qh->Chrst>>16)&0x7FF, ((qh->Chrst>>12)&0x3 == 0) ?
"Full" : (((qh->Chrst>>12)&0x3 == 1) ?
"Low" :
"High"));
87 USB_debug(
" 0x%08x (Endpoint Capabilities: Queue Head DWord 2)\n", qh->Cap);
88 USB_debug(
" 0x%08x (Current qtd Pointer)\n", qh->Curr_qTD);
89 USB_debug(
" --- Overlay Area ---\n");
90 USB_debug(
" 0x%08x (Next qtd Pointer)\n", qh->OL_Next_qTD);
91 USB_debug(
" 0x%08x (Alternate Next qtd Pointer)\n", qh->OL_Alt_Next_qTD);
92 USB_debug(
" 0x%08x (qtd Token)\n", qh->OL_Token);
93 USB_debug(
" 0x%08x (Buffer Pointer (page 0))\n", qh->OL_Bptr[0]);
96 qtd = QTD_PTR(qh->Curr_qTD);
100 qtd = QTD_PTR(qtd->Next_qTD);
102 qh = QH_PTR(qh->HLink);
107void dump_ehci_asynclist_simple(
void)
111 USB_debug(
">>> EHCI Asynchronous List <<<\n");
112 USB_debug(
"[QH] => ");
115 USB_debug(
"0x%08x ", (
int)qh);
116 qh = QH_PTR(qh->HLink);
122void dump_ehci_period_frame_list_simple(
void)
124 QH_T *qh = _Iqh[NUM_IQH-1];
126 USB_debug(
">>> EHCI period frame list simple <<<\n");
127 USB_debug(
"[FList] => ");
130 USB_debug(
"0x%08x ", (
int)qh);
131 qh = QH_PTR(qh->HLink);
137void dump_ehci_period_frame_list()
142 for (i = 0; i < FL_SIZE; i++)
144 USB_debug(
"!%02d: ", i);
145 qh = QH_PTR(_PFList[i]);;
149 USB_debug(
"0x%x => ", (
int)qh);
150 qh = QH_PTR(qh->HLink);
158static void init_periodic_frame_list()
161 int i, idx, interval;
163 memset(_PFList, 0,
sizeof(_PFList));
167 for (i = NUM_IQH-1; i >= 0; i--)
169 _Iqh[i] = alloc_ehci_QH();
171 _Iqh[i]->HLink = QH_HLNK_END;
172 _Iqh[i]->Curr_qTD = (uint32_t)_ghost_qtd;
173 _Iqh[i]->OL_Next_qTD = QTD_LIST_END;
174 _Iqh[i]->OL_Alt_Next_qTD = (uint32_t)_ghost_qtd;
175 _Iqh[i]->OL_Token = QTD_STS_HALT;
179 for (idx = interval - 1; idx < FL_SIZE; idx += interval)
181 if (_PFList[idx] == 0)
183 _PFList[idx] = QH_HLNK_QH(_Iqh[i]);
187 qh_p = QH_PTR(_PFList[idx]);
194 if (qh_p->HLink == QH_HLNK_END)
196 qh_p->HLink = QH_HLNK_QH(_Iqh[i]);
199 qh_p = QH_PTR(qh_p->HLink);
206static QH_T * get_int_tree_head_node(
int interval)
212 for (i = 0; i < NUM_IQH-1; i++)
218 return _Iqh[NUM_IQH-1];
221static int make_int_s_mask(
int bInterval)
226 while (bInterval > 1)
238 for (order = 0; (interval > 1); order++)
242 return (0x1 << (order % 8));
245static int ehci_init(
void)
247 int timeout = 250*1000;
263 _ghost_qtd = alloc_ehci_qTD(
NULL);
264 _ghost_qtd->Token = 0x11197B3F;
269 qh_remove_list =
NULL;
272 _H_qh = alloc_ehci_QH();
273 _H_qh->HLink = QH_HLNK_QH(_H_qh);
274 _H_qh->Chrst = QH_RCLM_LIST_HEAD;
275 _H_qh->Curr_qTD = (uint32_t)_ghost_qtd;
276 _H_qh->OL_Next_qTD = QTD_LIST_END;
277 _H_qh->OL_Alt_Next_qTD = (uint32_t)_ghost_qtd;
278 _H_qh->OL_Token = QTD_STS_HALT;
279 _ehci->UCALAR = (uint32_t)_H_qh;
286 else if (FL_SIZE == 512)
288 else if (FL_SIZE == 1024)
293 _ehci->UPFLBAR = (uint32_t)_PFList;
307 init_periodic_frame_list();
314static void ehci_suspend(
void)
316 if (_ehci->UPSCR[0] & 0x1)
320static void ehci_resume(
void)
322 if (_ehci->UPSCR[0] & 0x1)
326static void ehci_shutdown(
void)
331static void move_qh_to_remove_list(QH_T *qh)
354 while (QH_PTR(q->HLink) != _H_qh)
356 if (QH_PTR(q->HLink) == qh)
359 q->HLink = qh->HLink;
361 qh->next = qh_remove_list;
367 q = QH_PTR(q->HLink);
374 while (q->HLink != QH_HLNK_END)
376 if (QH_PTR(q->HLink) == qh)
379 q->HLink = qh->HLink;
381 qh->next = qh_remove_list;
387 q = QH_PTR(q->HLink);
392static void append_to_qtd_list_of_QH(QH_T *qh, qTD_T *qtd)
396 if (qh->qtd_list ==
NULL)
403 while (q->next !=
NULL)
414static void write_qh(UDEV_T *udev, EP_INFO_T *ep, QH_T *qh)
423 if (udev->descriptor.bMaxPacketSize0 == 0)
425 if (udev->speed == SPEED_LOW)
426 udev->descriptor.bMaxPacketSize0 = 8;
428 udev->descriptor.bMaxPacketSize0 = 64;
430 chrst = QH_DTC | QH_NAK_RL | (udev->descriptor.bMaxPacketSize0 << 16);
431 if (udev->speed != SPEED_HIGH)
432 chrst |= QH_CTRL_EP_FLAG;
436 chrst = QH_NAK_RL | (ep->wMaxPacketSize << 16);
437 chrst |= ((ep->bEndpointAddress & 0xf) << 8);
440 if (udev->speed == SPEED_LOW)
442 else if (udev->speed == SPEED_FULL)
443 chrst |= QH_EPS_FULL;
445 chrst |= QH_EPS_HIGH;
447 chrst |= udev->dev_num;
454 if (udev->speed == SPEED_HIGH)
466 port_num = udev->port_num;
469 while ((hub !=
NULL) && (hub->iface->udev->speed != SPEED_HIGH))
471 port_num = hub->iface->udev->port_num;
472 hub = hub->iface->udev->parent;
475 cap = (port_num << QH_HUB_PORT_Pos) |
476 (hub->iface->udev->dev_num << QH_HUB_ADDR_Pos);
482static void write_qtd_bptr(qTD_T *qtd, uint32_t buff_addr,
int xfer_len)
486 qtd->xfer_len = xfer_len;
487 qtd->Bptr[0] = buff_addr;
489 buff_addr = (buff_addr + 0x1000) & ~0xFFF;
491 for (i = 1; i < 5; i++)
493 qtd->Bptr[i] = buff_addr;
498static int ehci_ctrl_xfer(UTR_T *utr)
502 qTD_T *qtd_setup, *qtd_data, *qtd_status;
508 if (utr->data_len > 0)
510 if (((uint32_t)utr->buff + utr->data_len) > (((uint32_t)utr->buff & ~0xFFF)+0x5000))
517 if (udev->ep0.hw_pipe !=
NULL)
519 qh = (QH_T *)udev->ep0.hw_pipe;
525 qh = alloc_ehci_QH();
529 udev->ep0.hw_pipe = (
void *)qh;
532 write_qh(udev,
NULL, qh);
533 utr->ep = &udev->ep0;
538 qtd_setup = alloc_ehci_qTD(utr);
540 if (utr->data_len > 0)
541 qtd_data = alloc_ehci_qTD(utr);
545 qtd_status = alloc_ehci_qTD(utr);
547 if (qtd_status ==
NULL)
550 free_ehci_qTD(qtd_setup);
552 free_ehci_qTD(qtd_data);
563 write_qtd_bptr(qtd_setup, (uint32_t)&utr->setup, 8);
564 append_to_qtd_list_of_QH(qh, qtd_setup);
565 qtd_setup->Token = (8 << 16) | QTD_ERR_COUNTER | QTD_PID_SETUP | QTD_STS_ACTIVE;
570 if (utr->data_len > 0)
572 qtd_setup->Next_qTD = (uint32_t)qtd_data;
573 qtd_data->Next_qTD = (uint32_t)qtd_status;
575 if ((utr->setup.bmRequestType & 0x80) == REQ_TYPE_OUT)
576 token = QTD_ERR_COUNTER | QTD_PID_OUT | QTD_STS_ACTIVE;
578 token = QTD_ERR_COUNTER | QTD_PID_IN | QTD_STS_ACTIVE;
582 write_qtd_bptr(qtd_data, (uint32_t)utr->buff, utr->data_len);
583 append_to_qtd_list_of_QH(qh, qtd_data);
584 qtd_data->Token = QTD_DT | (utr->data_len << 16) | token;
588 qtd_setup->Next_qTD = (uint32_t)qtd_status;
594 qtd_status->Next_qTD = (uint32_t)_ghost_qtd;
595 qtd_status->Alt_Next_qTD = QTD_LIST_END;
597 if ((utr->setup.bmRequestType & 0x80) == REQ_TYPE_OUT)
598 token = QTD_ERR_COUNTER | QTD_PID_IN | QTD_STS_ACTIVE;
600 token = QTD_ERR_COUNTER | QTD_PID_OUT | QTD_STS_ACTIVE;
604 append_to_qtd_list_of_QH(qh, qtd_status);
605 qtd_status->Token = QTD_DT | QTD_IOC | token;
611 qh->OL_Next_qTD = (uint32_t)qtd_setup;
612 qh->OL_Alt_Next_qTD = QTD_LIST_END;
620 qh->HLink = _H_qh->HLink;
621 _H_qh->HLink = QH_HLNK_QH(qh);
629static int ehci_bulk_xfer(UTR_T *utr)
632 EP_INFO_T *ep = utr->ep;
634 qTD_T *qtd, *qtd_pre;
635 uint32_t data_len, xfer_len;
645 if (ep->hw_pipe !=
NULL)
647 qh = (QH_T *)ep->hw_pipe ;
655 qh = alloc_ehci_QH();
659 write_qh(udev, ep, qh);
660 ep->hw_pipe = (
void *)qh;
666 data_len = utr->data_len;
672 qtd = alloc_ehci_qTD(utr);
680 free_ehci_qTD(qtd_pre);
690 if ((ep->bEndpointAddress & EP_ADDR_DIR_MASK) == EP_ADDR_DIR_OUT)
691 token = QTD_ERR_COUNTER | QTD_PID_OUT | QTD_STS_ACTIVE;
693 token = QTD_ERR_COUNTER | QTD_PID_IN | QTD_STS_ACTIVE;
695 if (data_len > 0x4000)
701 qtd->Next_qTD = (uint32_t)_ghost_qtd;
702 qtd->Alt_Next_qTD = QTD_LIST_END;
703 write_qtd_bptr(qtd, (uint32_t)buff, xfer_len);
704 append_to_qtd_list_of_QH(qh, qtd);
705 qtd->Token = (xfer_len << 16) | token;
708 data_len -= xfer_len;
712 qtd->Token |= QTD_IOC;
713 qtd->Next_qTD = (uint32_t)_ghost_qtd;
717 qtd_pre->Next_qTD = (uint32_t)qtd;
726 qh->OL_Next_qTD = (uint32_t)qtd;
734 memcpy(&(qh->OL_Bptr[0]), &(qtd->Bptr[0]), 20);
735 qh->Curr_qTD = (uint32_t)qtd;
739 if (utr->ep->bToggle)
740 qh->OL_Token |= QTD_DT;
742 qh->HLink = _H_qh->HLink;
743 _H_qh->HLink = QH_HLNK_QH(qh);
752static int ehci_int_xfer(UTR_T *utr)
754 UDEV_T *udev = utr->udev;
755 EP_INFO_T *ep = utr->ep;
757 qTD_T *qtd, *dummy_qtd;
760 dummy_qtd = alloc_ehci_qTD(
NULL);
761 if (dummy_qtd ==
NULL)
763 dummy_qtd->Token &= ~(QTD_STS_ACTIVE | QTD_STS_HALT);
765 if (ep->hw_pipe !=
NULL)
767 qh = (QH_T *)ep->hw_pipe ;
771 qh = alloc_ehci_QH();
774 free_ehci_qTD(dummy_qtd);
777 write_qh(udev, ep, qh);
778 qh->Chrst &= ~0xF0000000;
780 if (udev->speed == SPEED_HIGH)
782 qh->Cap = (0x1 << QH_MULT_Pos) | (qh->Cap & 0xff) | make_int_s_mask(ep->bInterval);
786 qh->Cap = (0x1 << QH_MULT_Pos) | (qh->Cap & ~(QH_C_MASK_Msk | QH_S_MASK_Msk)) | 0x7802;
788 ep->hw_pipe = (
void *)qh;
793 qtd = alloc_ehci_qTD(
NULL);
796 free_ehci_qTD(dummy_qtd);
800 qtd->Token &= ~(QTD_STS_ACTIVE | QTD_STS_HALT);
802 qh->dummy = dummy_qtd;
803 qh->OL_Next_qTD = (uint32_t)dummy_qtd;
809 if (udev->speed == SPEED_HIGH)
810 iqh = get_int_tree_head_node(ep->bInterval);
812 iqh = get_int_tree_head_node(ep->bInterval * 8);
813 qh->HLink = iqh->HLink;
814 iqh->HLink = QH_HLNK_QH(qh);
820 qtd->Next_qTD = (uint32_t)dummy_qtd;
822 qh->dummy = dummy_qtd;
828 if ((ep->bEndpointAddress & EP_ADDR_DIR_MASK) == EP_ADDR_DIR_OUT)
829 token = QTD_ERR_COUNTER | QTD_PID_OUT;
831 token = QTD_ERR_COUNTER | QTD_PID_IN;
834 qtd->Alt_Next_qTD = QTD_LIST_END;
835 write_qtd_bptr(qtd, (uint32_t)utr->buff, utr->data_len);
836 append_to_qtd_list_of_QH(qh, qtd);
837 qtd->Token = QTD_IOC | (utr->data_len << 16) | token | QTD_STS_ACTIVE;
848static int ehci_quit_xfer(UTR_T *utr, EP_INFO_T *ep)
855 if (ehci_quit_iso_xfer(utr, ep) == 0)
867 qh = (QH_T *)(utr->ep->hw_pipe);
873 move_qh_to_remove_list(qh);
874 utr->ep->hw_pipe =
NULL;
877 if ((ep !=
NULL) && (ep->hw_pipe !=
NULL))
879 qh = (QH_T *)(ep->hw_pipe);
881 move_qh_to_remove_list(qh);
889static int visit_qtd(qTD_T *qtd)
891 if ((qtd->Token == 0x11197B3F) || (qtd->Token == 0x1197B3F))
896 if ((qtd->Token & QTD_STS_ACTIVE) == 0)
898 if (qtd->Token & (QTD_STS_HALT | QTD_STS_DATA_BUFF_ERR | QTD_STS_BABBLE | QTD_STS_XactErr | QTD_STS_MISS_MF))
900 USB_error(
"qTD error token=0x%x! 0x%x\n", qtd->Token, qtd->Bptr[0]);
901 if (qtd->utr->status == 0)
906 if ((qtd->Token & QTD_PID_Msk) != QTD_PID_SETUP)
908 qtd->utr->xfer_len += qtd->xfer_len - QTD_TODO_LEN(qtd->Token);
917static void scan_asynchronous_list()
920 qTD_T *q_pre, *qtd, *qtd_tmp;
923 qh = QH_PTR(_H_qh->HLink);
936 if (qtd == qh->qtd_list)
937 qh->qtd_list = qtd->next;
939 q_pre->next = qtd->next;
944 qtd_tmp->next = qh->done_list;
945 qh->done_list = qtd_tmp;
955 qh = QH_PTR(qh->HLink);
958 if ((qh_tmp->qtd_list ==
NULL) && utr)
961 if (qh_tmp->OL_Token & QTD_DT)
962 utr->ep->bToggle = 1;
964 utr->ep->bToggle = 0;
966 utr->bIsTransferDone = 1;
975static void scan_periodic_frame_list()
984 qh = _Iqh[NUM_IQH-1];
992 qh = QH_PTR(qh->HLink);
1002 qh->qtd_list = qtd->next;
1003 qtd->next = qh->done_list;
1004 qh->done_list = qtd;
1009 qtd = qh->done_list;
1015 if (qh->OL_Token & QTD_DT)
1016 utr->ep->bToggle = 1;
1018 utr->ep->bToggle = 0;
1020 utr->bIsTransferDone = 1;
1029 qh = QH_PTR(qh->HLink);
1036 scan_isochronous_list();
1039void iaad_remove_qh()
1048 while (qh_remove_list !=
NULL)
1050 qh = qh_remove_list;
1051 qh_remove_list = qh->next;
1055 while (qh->done_list)
1057 qtd = qh->done_list;
1058 qh->done_list = qtd->next;
1062 if (qh->qtd_list !=
NULL)
1064 utr = qh->qtd_list->utr;
1065 while (qh->qtd_list)
1068 qh->qtd_list = qtd->next;
1072 utr->bIsTransferDone = 1;
1082 qh = QH_PTR(_H_qh->HLink);
1085 while (qh->done_list)
1087 qtd = qh->done_list;
1088 qh->done_list = qtd->next;
1091 qh = QH_PTR(qh->HLink);
1097 qh = _Iqh[NUM_IQH-1];
1100 while (qh->done_list)
1102 qtd = qh->done_list;
1103 qh->done_list = qtd->next;
1106 qh = QH_PTR(qh->HLink);
1111void EHCI_IRQHandler(
void)
1115 intsts = _ehci->USTSR;
1116 _ehci->USTSR = intsts;
1129 scan_asynchronous_list();
1131 scan_periodic_frame_list();
1140static UDEV_T * ehci_find_device_by_port(
int port)
1145 while (udev !=
NULL)
1147 if ((udev->parent ==
NULL) && (udev->port_num == port) && (udev->speed == SPEED_HIGH))
1154static int ehci_rh_port_reset(
int port)
1160 reset_time = PORT_RESET_TIME_MS;
1162 for (retry = 0; retry < PORT_RESET_RETRY; retry++)
1167 while (
get_ticks() - t0 < (reset_time/10)+1) ;
1169 _ehci->UPSCR[port] &= ~HSUSBH_UPSCR_PRST_Msk;
1172 while (
get_ticks() - t0 < (reset_time/10)+1)
1176 goto port_reset_done;
1178 reset_time += PORT_RESET_RETRY_INC_MS;
1181 USB_debug(
"EHCI port %d - port reset failed!\n", port+1);
1194static int ehci_rh_polling(
void)
1198 int connect_status, t0;
1207 USB_debug(
"EHCI port1 status change: 0x%x\n", _ehci->UPSCR[0]);
1214 udev = ehci_find_device_by_port(1);
1217 disconnect_device(udev);
1225 while (
get_ticks() - t0 < HUB_DEBOUNCE_TIME/10)
1242 if (ehci_rh_port_reset(0) !=
USBH_OK)
1253 udev = alloc_device();
1257 udev->parent =
NULL;
1259 udev->speed = SPEED_HIGH;
1260 udev->hc_driver = &ehci_driver;
1262 ret = connect_device(udev);
1265 USB_error(
"connect_device error! [%d]\n", ret);
1276 udev = ehci_find_device_by_port(1);
1279 disconnect_device(udev);
1286HC_DRV_T ehci_driver =
void *__dso_handle __attribute__((weak))
NuMicro peripheral access layer header file.
#define NULL
NULL pointer.
#define HSUSBH_UCMDR_RUN_Msk
#define HSUSBH_UIENR_USBIEN_Msk
#define HSUSBH_UPSCR_PE_Msk
#define HSUSBH_USTSR_USBINT_Msk
#define HSUSBH_UCMDR_HCRST_Msk
#define HSUSBH_UCMDR_ASEN_Msk
#define HSUSBH_UIENR_HSERREN_Msk
#define HSUSBH_UCMDR_IAAD_Msk
#define HSUSBH_UPSCR_SUSPEND_Msk
#define HSUSBH_UIENR_IAAEN_Msk
#define HSUSBH_UPSCR_CSC_Msk
#define HSUSBH_UPSCR_CCS_Msk
#define HSUSBH_UPSCR_PP_Msk
#define HSUSBH_USTSR_UERRINT_Msk
#define HSUSBH_UCMDR_FLSZ_Pos
#define HSUSBH_UCMDR_PSEN_Msk
#define HSUSBH_UPSCR_PRST_Msk
#define HSUSBH_UIENR_UERRIEN_Msk
#define HSUSBH_USTSR_IAA_Msk
#define HSUSBH_UPSCR_PEC_Msk
#define HSUSBH_UPSCR_PO_Msk
#define HSUSBH_UPSCR_FPR_Msk
#define USBH_ERR_EHCI_QH_BUSY
#define USBH_ERR_EHCI_INIT
#define USBH_ERR_TRANSACTION
#define USBH_ERR_PORT_RESET
#define USBH_ERR_NOT_FOUND
#define USBH_ERR_MEMORY_OUT
#define USBH_ERR_BUFF_OVERRUN
#define USBH_ERR_DISCONNECTED
uint32_t get_ticks(void)
A function return current tick count.
USB Host hub class driver header file.
USB Host library header file.