| /* |
| * Copyright 2017, Data61 |
| * Commonwealth Scientific and Industrial Research Organisation (CSIRO) |
| * ABN 41 687 119 230. |
| * |
| * This software may be distributed and modified according to the terms of |
| * the BSD 2-Clause license. Note that NO WARRANTY is provided. |
| * See "LICENSE_BSD2.txt" for details. |
| * |
| * @TAG(DATA61_BSD) |
| */ |
| #include "ehci.h" |
| |
| /****** DEBUG printing *******/ |
| static const char *dump_colour(enum usb_xact_status stat) |
| { |
| switch (stat) { |
| case XACTSTAT_PENDING: |
| return A_FG_Y; |
| case XACTSTAT_ERROR: |
| case XACTSTAT_HOSTERROR: |
| return A_FG_R; |
| case XACTSTAT_SUCCESS: |
| return A_FG_G; |
| default: |
| return ""; |
| } |
| } |
| |
| void dump_qtd(volatile struct TD *qtd) |
| { |
| int pid; |
| uint32_t tok; |
| const char *col = dump_colour(qtd_get_status(qtd)); |
| printf("%s", col); |
| printf("-- td 0x%08x\n", (uint32_t) qtd); |
| printf("%s", col); |
| printf("- next: 0x%08x | 0x%08x (%s)\n", |
| qtd->next, qtd->next & ~0x1f, |
| (qtd->next & 0x1) ? "TERMINATE" : "CONTINUE"); |
| printf("- altnext: 0x%08x | 0x%08x (%s)\n", |
| qtd->alt, qtd->alt & ~0x1f, |
| (qtd->alt & 0x1) ? "TERMINATE" : "CONTINUE"); |
| /* Complicated token */ |
| tok = qtd->token; |
| printf("- token: 0x%08x | ", tok); |
| printf("%s", (tok & (1UL << 31)) ? "TOG;" : ""); |
| printf("totx %d;", (tok >> 16) & 0x7fff); |
| printf("%s", (tok & (1UL << 15)) ? "IOC;" : ""); |
| printf("page %d;", (tok >> 12) & 0x7); |
| printf("errs %d;", (tok >> 10) & 0x3); |
| pid = (tok >> 8) & 0x3; |
| printf("pid %d (%s)", pid, (pid == 0) ? "OUT" : |
| (pid == 1) ? "IN" : (pid == 2) ? "SETUP" : "RES"); |
| if (tok & BIT(7)) { |
| printf(";ACTIVE"); |
| } |
| if (tok & BIT(6)) { |
| printf(";HALTED"); |
| } |
| if (tok & BIT(5)) { |
| printf(";BUFFER ERROR"); |
| } |
| if (tok & BIT(4)) { |
| printf(";BABBLE DETECTED"); |
| } |
| if (tok & BIT(3)) { |
| printf(";TRANSACTION ERR"); |
| } |
| if (tok & BIT(2)) { |
| printf(";MISSED uFRAME"); |
| } |
| if (tok & BIT(1)) { |
| printf(";COMPLETE SPLIT"); |
| } |
| if (tok & BIT(0)) { |
| printf(";DO PING"); |
| } |
| printf("\n"); |
| /* buffer list */ |
| { |
| int i; |
| for (i = 0; i < 5; i++) { |
| if (qtd->buf[i] & ~(0x1000 - 1)) { |
| printf("- buffer%d: 0x%08x | 0x%08x", |
| i, qtd->buf[i], qtd->buf[i] & ~0xfff); |
| |
| if (i == 0) { |
| printf(" (0x%x bytes left)\n", |
| qtd->buf[i] & 0xfff); |
| } else { |
| printf("\n"); |
| } |
| } |
| } |
| } |
| printf(A_FG_RESET); |
| } |
| |
| void dump_qhn(struct QHn *qhn) |
| { |
| uint32_t v; |
| volatile struct QH *qh; |
| const char *col; |
| col = dump_colour(qhn_get_status(qhn)); |
| qh = qhn->qh; |
| printf("%s", col); |
| printf("++ qh 0x%08x(0x%08x)\n", (uint32_t) qh, (uint32_t) qhn->pqh); |
| printf("%s", col); |
| printf("+ link: 0x%08x | 0x%08x (%s|", |
| qh->qhlptr, qh->qhlptr & ~0xf, |
| (qh->qhlptr & 0x1) ? "TERMINATE" : "CONTINUE"); |
| switch ((qh->qhlptr >> 1) & 0x3) { |
| case 0: |
| printf("ITD)\n"); |
| break; |
| case 1: |
| printf("QH)\n"); |
| break; |
| case 2: |
| printf("SITD)\n"); |
| break; |
| case 3: |
| printf("FSTN)\n"); |
| break; |
| } |
| v = qh->epc[0]; |
| printf("+ epc0: 0x%08x| addr %d(%d); NAC reload %d;max pkt %d", |
| v, v & 0x7f, (v >> 8) & 0xf, v >> 28, (v >> 16) & 0x7ff); |
| if (v & (1 << 27)) { |
| printf(";C"); |
| } |
| if (v & (1 << 15)) { |
| printf(";H"); |
| } |
| if (v & (1 << 14)) { |
| printf(";DTC"); |
| } |
| if (v & (1 << 7)) { |
| printf(";I"); |
| } |
| |
| v = (v >> 12) & 0x3; |
| switch (v) { |
| case 0: |
| printf("; 12Mbs"); |
| break; |
| case 1: |
| printf(";1.5Mbs"); |
| break; |
| case 2: |
| printf(";480Mbs"); |
| break; |
| case 3: |
| printf(";???Mbs"); |
| break; |
| } |
| printf("\n"); |
| printf("C-PROG Mask: 0x%x s-bytes 0x%x frametag 0x%x\n", |
| (qh->td_overlay.buf[1] >> 0) & 0xff, |
| (qh->td_overlay.buf[2] >> 5) & 0x7f, |
| (qh->td_overlay.buf[2] >> 0) & 0x1f); |
| v = qh->epc[1]; |
| printf("+ epc1: 0x%08x; hub %d; port %d; txc %d; uF c%d s%d\n", |
| v, (v >> 16) & 0x7f, (v >> 23) & 0x7f, v >> 30, |
| (v >> 8) & 0xff, v & 0xff); |
| printf("+ current: 0x%08x\n", qh->td_cur); |
| dump_qtd(&qh->td_overlay); |
| struct TDn *tdn = qhn->tdns; |
| while (tdn) { |
| printf("-- ptd 0x%08x\n", tdn->ptd); |
| dump_qtd(tdn->td); |
| tdn = tdn->next; |
| } |
| printf(A_FG_RESET); |
| } |
| |
| void UNUSED dump_q(struct QHn *qhn) |
| { |
| int i = 1; |
| struct QHn *head = qhn; |
| printf("##### Start Async list #####\n"); |
| do { |
| printf("{QH %d}\n", i++); |
| dump_qhn(qhn); |
| qhn = qhn->next; |
| } while (qhn && qhn != head); |
| printf("##### End Async list #####\n"); |
| } |
| |
| void UNUSED dump_edev(struct ehci_host *edev) |
| { |
| uint32_t sts, cmd, intr; |
| sts = edev->op_regs->usbsts; |
| cmd = edev->op_regs->usbcmd; |
| intr = edev->op_regs->usbintr; |
| printf("*** EHCI edevice ***\n"); |
| printf("* usbcmd\n"); |
| printf(" IRQ threshold: 0x%x\n", (cmd >> 16) & 0xff); |
| printf(" async parked: %s\n", |
| (cmd & EHCICMD_ASYNC_PARK) ? "yes" : "no"); |
| printf(" async park mode: %d\n", (cmd >> 8) & 0x3); |
| printf(" light reset: %s\n", |
| (cmd & EHCICMD_LIGHT_RST) ? "yes" : "no"); |
| printf(" async doorbell: %s\n", |
| (cmd & EHCICMD_ASYNC_DB) ? "yes" : "no"); |
| printf(" async: %s\n", |
| (cmd & EHCICMD_ASYNC_EN) ? "Enabled" : "Disabled"); |
| printf(" frame list size: "); |
| switch (cmd & EHCICMD_LIST_SMASK) { |
| case EHCICMD_LIST_S1024: |
| printf("1024\n"); |
| break; |
| case EHCICMD_LIST_S512: |
| printf("512\n"); |
| break; |
| case EHCICMD_LIST_S256: |
| printf("256\n"); |
| break; |
| default: |
| printf("Unknown\n"); |
| } |
| printf(" hcreset: %s\n", |
| (cmd & EHCICMD_HCRESET) ? "yes" : "no"); |
| printf(" hcrunstop: %s\n", |
| (cmd & EHCICMD_RUNSTOP) ? "yes" : "no"); |
| printf("* usbsts\n"); |
| printf(" async en: %s\n", |
| (sts & EHCISTS_ASYNC_EN) ? "yes" : "no"); |
| printf(" periodic en: %s\n", |
| (sts & EHCISTS_PERI_EN) ? "yes" : "no"); |
| printf(" async empty: %s\n", |
| (sts & EHCISTS_ASYNC_EMPTY) ? "yes" : "no"); |
| printf(" hc halted: %s\n", |
| (sts & EHCISTS_HCHALTED) ? "yes" : "no"); |
| printf(" async advance: %s\n", |
| (sts & EHCISTS_ASYNC_ADV) ? "yes" : "no"); |
| printf(" host err: %s\n", |
| (sts & EHCISTS_HOST_ERR) ? "yes" : "no"); |
| printf(" frame list roll: %s\n", |
| (sts & EHCISTS_FLIST_ROLL) ? "yes" : "no"); |
| printf(" port change: %s\n", |
| (sts & EHCISTS_PORTC_DET) ? "yes" : "no"); |
| printf(" usb err: %s\n", |
| (sts & EHCISTS_USBERRINT) ? "yes" : "no"); |
| printf(" usb event: %s\n", (sts & EHCISTS_USBINT) ? "yes" : "no"); |
| printf("* usbintr\n"); |
| printf(" async advance: %s\n", |
| (intr & EHCIINTR_ASYNC_ADV) ? "yes" : "no"); |
| printf(" host err: %s\n", |
| (intr & EHCIINTR_HOST_ERR) ? "yes" : "no"); |
| printf(" frame list roll: %s\n", |
| (intr & EHCIINTR_FLIST_ROLL) ? "yes" : "no"); |
| printf(" port change: %s\n", |
| (intr & EHCIINTR_PORTC_DET) ? "yes" : "no"); |
| printf(" usb err: %s\n", |
| (intr & EHCIINTR_USBERRINT) ? "yes" : "no"); |
| printf(" usb event: %s\n", |
| (intr & EHCIINTR_USBINT) ? "yes" : "no"); |
| printf(" * Frame index: 0x%x\n", edev->op_regs->frindex); |
| printf(" * periodic base: 0x%x\n", edev->op_regs->periodiclistbase); |
| printf(" * async base: 0x%x\n", edev->op_regs->asynclistaddr); |
| } |