[coreboot] [PATCH] USB: Add OHCI debug functions

Daniel Mack daniel at caiaq.de
Mon Oct 5 04:44:48 CEST 2009


Signed-off-by: Daniel Mack <daniel at caiaq.de>
---
 drivers/usb/ohci_dbg.c |  297 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 297 insertions(+), 0 deletions(-)
 create mode 100644 drivers/usb/ohci_dbg.c

diff --git a/drivers/usb/ohci_dbg.c b/drivers/usb/ohci_dbg.c
new file mode 100644
index 0000000..8df83cb
--- /dev/null
+++ b/drivers/usb/ohci_dbg.c
@@ -0,0 +1,297 @@
+/*
+ * URB OHCI HCD (Host Controller Driver) for USB.
+ *
+ * Implementation taken from U-Boot sources,
+ * copyright (c) 1999-2007
+ *
+ *   Zhang Wei, Freescale Semiconductor, Inc. <wei.zhang at freescale.com>
+ *   Gary Jennejohn, DENX Software Engineering <garyj at denx.de>
+ *   Roman Weissgaerber <weissg at vienna.at>
+ *   David Brownell
+ *
+ * Port to libpayload by Daniel Mack <daniel at caiaq.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <libpayload-config.h>
+
+#include <usb/usb.h>
+#include <arch/virtual.h>
+#include <arch/endian.h>
+
+#include "ohci.h"
+#include "ohci_rh.h"
+
+#ifdef DEBUG
+
+static int sohci_get_current_frame_number(ohci_t *ohci)
+{
+	return readl(&ohci->hcca->frame_no);
+}
+
+static const char *ep_type_to_str(endpoint_t *ep)
+{
+	switch (ep->type) {
+	case CONTROL:		return "CONTROL";	break;
+	case BULK:		return "BULK";		break;
+	case INTERRUPT:		return "INTERRUPT";	break;
+	case ISOCHRONOUS:	return "ISOCHRONOUS";	break;
+	}
+
+	return "BOGUS";
+}
+
+void pkt_print(urb_priv_t *urb, void *setup, const char *str, int verbose)
+{
+	endpoint_t *ep = urb->ep;
+	usbdev_t *dev = ep->dev;
+	ohci_t *ohci = OHCI_INST(dev->controller);
+
+	dbg("%s URB:[%4x] dev:%2lu,ep:%2lu-%c,type:%s,len:%d/%d\n",
+			str,
+			sohci_get_current_frame_number(ohci),
+			dev->address,
+			ep->endpoint,
+			(ep->direction == OUT) ? 'O':
+				(ep->direction == SETUP) ? 'S' : 'I',
+			ep_type_to_str(ep),
+			(urb ? urb->actual_length : 0),
+			urb->transfer_buffer_length);
+
+	if (!verbose)
+		return;
+
+	if (ep->direction != IN) {
+		int i, len;
+
+		if (ep->type == CONTROL) {
+			printf( "%s: cmd(8):\n", __func__);
+			for (i = 0; i < 8 ; i++)
+				printf(" %02x", ((u8 *) setup) [i]);
+			printf("\n");
+		}
+
+		if (urb->transfer_buffer_length > 0 && urb->transfer_buffer) {
+			printf("%s: data(%d/%d):",
+				__func__,
+				urb->actual_length,
+				urb->transfer_buffer_length);
+			len = (ep->direction == OUT) ? urb->actual_length : 0;
+
+			for (i = 0; i < 16 && i < len; i++)
+				printf(" %02x", ((u8 *) urb->transfer_buffer)[i]);
+
+			printf("%s\n", i < len ? "...": "");
+		}
+	}
+}
+
+/* prints non-empty branches of the int ed tree inclusive iso eds */
+void ep_print_int_eds(ohci_t *ohci, const char *str)
+{
+	int i, j;
+	volatile u32 *ed_p;
+
+	for (i = 0; i < 32; i++) {
+		j = 5;
+		ed_p = &(ohci->hcca->int_table[i]);
+		if (!*ed_p)
+			continue;
+
+		dbg("%s: %s branch int %d (%x):", __func__, str, i, i);
+		while (*ed_p && j--) {
+			ohci_ed_t *ed = (ohci_ed_t *) le32_to_cpu(ed_p);
+			dbg(" ed: %4x;", ed->hwINFO);
+			ed_p = &ed->hwNextED;
+		}
+		dbg("\n");
+	}
+}
+
+static void ohci_dump_intr_mask(char *label, u32 mask)
+{
+	dbg("%s: 0x%08x%s%s%s%s%s%s%s%s%s\n",
+		label,
+		mask,
+		(mask & OHCI_INTR_MIE) ? " MIE" : "",
+		(mask & OHCI_INTR_OC) ? " OC" : "",
+		(mask & OHCI_INTR_RHSC) ? " RHSC" : "",
+		(mask & OHCI_INTR_FNO) ? " FNO" : "",
+		(mask & OHCI_INTR_UE) ? " UE" : "",
+		(mask & OHCI_INTR_RD) ? " RD" : "",
+		(mask & OHCI_INTR_SF) ? " SF" : "",
+		(mask & OHCI_INTR_WDH) ? " WDH" : "",
+		(mask & OHCI_INTR_SO) ? " SO" : ""
+		);
+}
+
+static void print_eds(const char *label, u32 value)
+{
+	ohci_ed_t *ed = phys_to_virt(value);
+	u32 hwNext;
+
+	if (!value)
+		return;
+
+	dbg("%s @%p: hwINFO %08x hwTailP %08x hwHeadP %08x hwNextED %08x\n",
+		label, ed, ed->hwINFO, ed->hwTailP, ed->hwHeadP, ed->hwNextED);
+
+	hwNext = ed->hwHeadP & ~0xf;
+
+	while (hwNext) {
+		ohci_td_t *td = phys_to_virt(hwNext);
+		dbg(" --- TD @%p: hwINFO %08x hwCBP %08x hwBE %08x hwNextTD %08x ",
+			td, td->hwINFO, td->hwCBP, td->hwBE, td->hwNextTD);
+
+		if (td->hwCBP) {
+			u8 *buf = phys_to_virt(td->hwCBP);
+			dbg("(%02x %02x %02x %02x %02x %02x %02x %02x)",
+				buf[0], buf[1], buf[2], buf[3],
+				buf[4], buf[5], buf[6], buf[7]);
+		}
+
+		dbg("\n");
+
+		hwNext = td->hwNextTD;
+	}
+}
+
+static char *hcfs2string(int state)
+{
+	switch (state) {
+	case OHCI_USB_RESET:    return "reset";
+	case OHCI_USB_RESUME:   return "resume";
+	case OHCI_USB_OPER:     return "operational";
+	case OHCI_USB_SUSPEND:  return "suspend";
+	}
+
+	return "?";
+}
+
+/* dump control and status registers */
+static void ohci_dump_status(ohci_t *ohci)
+{
+	u32 temp;
+	struct ohci_regs *regs = ohci->regs;
+
+	temp = readl(&regs->control);
+	dbg("control: 0x%08x%s%s%s HCFS=%s%s%s%s%s CBSR=%d\n", temp,
+		(temp & OHCI_CTRL_RWE) ? " RWE" : "",
+		(temp & OHCI_CTRL_RWC) ? " RWC" : "",
+		(temp & OHCI_CTRL_IR) ? " IR" : "",
+		hcfs2string(temp & OHCI_CTRL_HCFS),
+		(temp & OHCI_CTRL_BLE) ? " BLE" : "",
+		(temp & OHCI_CTRL_CLE) ? " CLE" : "",
+		(temp & OHCI_CTRL_IE) ? " IE" : "",
+		(temp & OHCI_CTRL_PLE) ? " PLE" : "",
+		temp & OHCI_CTRL_CBSR
+		);
+
+	temp = readl(&regs->cmdstatus);
+	dbg("cmdstatus: 0x%08x SOC=%d%s%s%s%s\n", temp,
+		(temp & OHCI_SOC) >> 16,
+		(temp & OHCI_OCR) ? " OCR" : "",
+		(temp & OHCI_BLF) ? " BLF" : "",
+		(temp & OHCI_CLF) ? " CLF" : "",
+		(temp & OHCI_HCR) ? " HCR" : ""
+		);
+
+	ohci_dump_intr_mask("intrstatus", readl(&regs->intrstatus));
+	ohci_dump_intr_mask("intrenable", readl(&regs->intrenable));
+
+	print_eds("ed_periodcurrent",	readl(&regs->ed_periodcurrent));
+	print_eds("ed_controlhead",	readl(&regs->ed_controlhead));
+	print_eds("ed_controlcurrent",	readl(&regs->ed_controlcurrent));
+	print_eds("ed_bulkhead",	readl(&regs->ed_bulkhead));
+	print_eds("ed_bulkcurrent",	readl(&regs->ed_bulkcurrent));
+	print_eds("donehead",		readl(&regs->donehead));
+}
+
+void ohci_dump_roothub(ohci_t *ohci, int verbose)
+{
+	u32 temp, ndp, i;
+
+	temp = roothub_a(ohci);
+	ndp = (temp & RH_A_NDP) & 0xf;
+
+	if (verbose) {
+		dbg("roothub.a: %08x POTPGT=%d%s%s%s%s%s NDP=%d\n", temp,
+			((temp & RH_A_POTPGT) >> 24) & 0xff,
+			(temp & RH_A_NOCP) ? " NOCP" : "",
+			(temp & RH_A_OCPM) ? " OCPM" : "",
+			(temp & RH_A_DT)   ? " DT"   : "",
+			(temp & RH_A_NPS)  ? " NPS"  : "",
+			(temp & RH_A_PSM)  ? " PSM"  : "",
+			ndp
+			);
+		temp = roothub_b(ohci);
+		dbg("roothub.b: %08x PPCM=%04x DR=%04x\n",
+			temp,
+			(temp & RH_B_PPCM) >> 16,
+			(temp & RH_B_DR)
+			);
+		temp = roothub_status(ohci);
+		dbg("roothub.status: %08x%s%s%s%s%s%s\n",
+			temp,
+			(temp & RH_HS_CRWE) ? " CRWE" : "",
+			(temp & RH_HS_OCIC) ? " OCIC" : "",
+			(temp & RH_HS_LPSC) ? " LPSC" : "",
+			(temp & RH_HS_DRWE) ? " DRWE" : "",
+			(temp & RH_HS_OCI)  ? " OCI"  : "",
+			(temp & RH_HS_LPS)  ? " LPS"  : ""
+			);
+	}
+
+	for (i = 0; i < ndp; i++) {
+		temp = roothub_portstatus(ohci, i);
+		dbg("roothub.portstatus[%d] = 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s\n",
+			i,
+			temp,
+			(temp & RH_PS_PRSC) ? " PRSC" : "",
+			(temp & RH_PS_OCIC) ? " OCIC" : "",
+			(temp & RH_PS_PSSC) ? " PSSC" : "",
+			(temp & RH_PS_PESC) ? " PESC" : "",
+			(temp & RH_PS_CSC) ? " CSC" : "",
+
+			(temp & RH_PS_LSDA) ? " LSDA" : "",
+			(temp & RH_PS_PPS) ? " PPS" : "",
+			(temp & RH_PS_PRS) ? " PRS" : "",
+			(temp & RH_PS_POCI) ? " POCI" : "",
+			(temp & RH_PS_PSS) ? " PSS" : "",
+
+			(temp & RH_PS_PES) ? " PES" : "",
+			(temp & RH_PS_CCS) ? " CCS" : ""
+			);
+	}
+}
+
+void ohci_dump(ohci_t *ohci, int verbose)
+{
+	dbg("----------------------\n");
+	dbg("OHCI @%p ohci state:", ohci->regs);
+
+	ohci_dump_status(ohci);
+
+	if (verbose)
+		ep_print_int_eds(ohci, "hcca");
+
+	dbg("hcca frame #%04x\n", ohci->hcca->frame_no);
+	ohci_dump_roothub(ohci, 1);
+	dbg("----------------------\n");
+}
+
+#endif /* DEBUG */
-- 
1.6.0.4





More information about the coreboot mailing list