From patchwork Sat Feb 16 01:52:45 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Julius Werner X-Patchwork-Id: 220973 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id DA2132C008D for ; Sun, 17 Feb 2013 03:24:59 +1100 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 86ADF4A0AE; Sat, 16 Feb 2013 17:24:55 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id JWojXmniJCqF; Sat, 16 Feb 2013 17:24:55 +0100 (CET) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id F02494A0AF; Sat, 16 Feb 2013 17:24:51 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 5600A4A133 for ; Sat, 16 Feb 2013 03:20:43 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id bNR31h8siPuK for ; Sat, 16 Feb 2013 03:20:37 +0100 (CET) X-Greylist: delayed 1294 seconds by postgrey-1.27 at theia; Sat, 16 Feb 2013 03:20:35 CET X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mail-da0-f50.google.com (mail-da0-f50.google.com [209.85.210.50]) by theia.denx.de (Postfix) with ESMTPS id 104924A130 for ; Sat, 16 Feb 2013 03:20:34 +0100 (CET) Received: by mail-da0-f50.google.com with SMTP id h15so1708300dan.9 for ; Fri, 15 Feb 2013 18:20:33 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=x-received:from:to:cc:subject:date:message-id:x-mailer; bh=y2OCr6qvEUGB2dhdbFrXp9k9qm+fZJcX03DvNp8xA9c=; b=Dc+xolBzIiby6eaaiZU21cesqEBoZWfHmPSo47giq7eWd/7ZWtnslciJY8IAFaMvaR IOKyaRtr3VKwv4xxsR1JRXyWmAyDVbS1qjnazWTgeblnKSC0CtjSxWbCVySLYFPP5s4b ZJfXz5vcX83wReNvVGw5VPUGqM3l2H2zfSiwk= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-received:from:to:cc:subject:date:message-id:x-mailer :x-gm-message-state; bh=y2OCr6qvEUGB2dhdbFrXp9k9qm+fZJcX03DvNp8xA9c=; b=P4OPOexJscHQY8MjJ1DQJeoUpZQU06t9C7BxD8MLuDvi7Y2jDvA0Gnz/U4TSI2XOpv 71JAuCluCNK299IndJycDyruEBRYyX/OCOel+bIvQGiw2nCEAuiTrfRAK0qqio1WD+2W F20hUvurQaNbxNgVgoJYwvZeig1GtyVhR2G9ZEOD64kh/A789isEtHcAag9QsT2inlje TFDfdEcku58FXgSBsdW6B01YNUz0RBF6sSnyLL2bx0AW5+mbDmWkYDgvFiZR3oS2wJ7d tXHLEDSQUBDxuKJGMn3Be7NJbgST/crjXditbLfS3wyLu5R7Vfi+hdcvbQcCR+tSnFtX /IcQ== X-Received: by 10.68.232.69 with SMTP id tm5mr10646382pbc.150.1360979617652; Fri, 15 Feb 2013 17:53:37 -0800 (PST) Received: from jwerner-linux.mtv.corp.google.com (jwerner-linux.mtv.corp.google.com [172.22.72.75]) by mx.google.com with ESMTPS id d8sm95398806pax.23.2013.02.15.17.53.36 (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Fri, 15 Feb 2013 17:53:36 -0800 (PST) From: Julius Werner To: U-Boot Mailing List Date: Fri, 15 Feb 2013 17:52:45 -0800 Message-Id: <1360979565-23002-1-git-send-email-jwerner@chromium.org> X-Mailer: git-send-email 1.8.1.3 X-Gm-Message-State: ALoCoQlunbd35fKvYOmW3vm/a08obKAydpmBvNs/gOcWOGX5AuT5ygnjFSsmK0iemj9hsooo4ZZY X-Mailman-Approved-At: Sat, 16 Feb 2013 17:24:50 +0100 Cc: Julius Werner Subject: [U-Boot] [PATCH] usb: Add new command to set USB 2.0 port test modes X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.11 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de This patch adds a new 'usb test' command, that will set a port to a USB 2.0 test mode (see USB 2.0 spec 7.1.20). It supports all five test modes on both downstream hub ports and ordinary device's upstream ports. In addition, it supports EHCI root hub ports. The command is guarded by the CONFIG_CMD_USB_TEST ifdef (disabled by default). Signed-off-by: Julius Werner --- README | 1 + common/cmd_usb.c | 127 ++++++++++++++++++++++++++++++++++++-------- doc/README.usb | 1 + drivers/usb/host/ehci-hcd.c | 32 +++++++---- include/usb_defs.h | 13 +++++ 5 files changed, 140 insertions(+), 34 deletions(-) diff --git a/README b/README index 2352e38..996a938 100644 --- a/README +++ b/README @@ -892,6 +892,7 @@ The following options need to be configured: CONFIG_CMD_TIME * run command and report execution time (ARM specific) CONFIG_CMD_TIMER * access to the system tick timer CONFIG_CMD_USB * USB support + CONFIG_CMD_USB_TEST * USB 2.0 hardware test mode support CONFIG_CMD_CDP * Cisco Discover Protocol support CONFIG_CMD_MFSL * Microblaze FSL support diff --git a/common/cmd_usb.c b/common/cmd_usb.c index dacdc2d..38dbea6 100644 --- a/common/cmd_usb.c +++ b/common/cmd_usb.c @@ -269,6 +269,22 @@ static void usb_display_config(struct usb_device *dev) printf("\n"); } +static struct usb_device *usb_find_device(int devnum) +{ + struct usb_device *dev; + int d; + + for (d = 0; d < USB_MAX_DEVICE; d++) { + dev = usb_get_dev_index(d); + if (dev == NULL) + return NULL; + if (dev->devnum == devnum) + return dev; + } + + return NULL; +} + static inline char *portspeed(int speed) { if (speed == USB_SPEED_HIGH) @@ -348,6 +364,68 @@ static void usb_show_tree(struct usb_device *dev) usb_show_tree_graph(dev, &preamble[0]); } +#ifdef CONFIG_CMD_USB_TEST +static int usb_test(struct usb_device *dev, int port, char* arg) +{ + int mode; + + if (port > dev->maxchild) { + printf("Device is no hub or does not have %d ports.\n", port); + return 1; + } + + switch (arg[0]) { + case 'J': + case 'j': + printf("Setting Test_J mode"); + mode = USB_TEST_MODE_J; + break; + case 'K': + case 'k': + printf("Setting Test_K mode"); + mode = USB_TEST_MODE_K; + break; + case 'S': + case 's': + printf("Setting Test_SE0_NAK mode"); + mode = USB_TEST_MODE_SE0_NAK; + break; + case 'P': + case 'p': + printf("Setting Test_Packet mode"); + mode = USB_TEST_MODE_PACKET; + break; + case 'F': + case 'f': + printf("Setting Test_Force_Enable mode"); + mode = USB_TEST_MODE_FORCE_ENABLE; + break; + default: + printf("Unrecognized test mode: %s\nAvailable modes: " + "J, K, S[E0_NAK], P[acket], F[orce_Enable]\n", arg); + return 1; + } + + if (port) + printf(" on downstream facing port %d...\n", port); + else + printf(" on upstream facing port...\n"); + + if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_SET_FEATURE, + port ? USB_RT_PORT : USB_RECIP_DEVICE, + port ? USB_PORT_FEAT_TEST : USB_FEAT_TEST, + (mode << 8) | port, + NULL, 0, USB_CNTL_TIMEOUT) == -1) { + printf("Error during SET_FEATURE.\n"); + return 1; + } else { + printf("Test mode successfully set. Use 'usb start' " + "to return to normal operation.\n"); + return 0; + } +} +#endif /* CONFIG_CMD_USB_TEST */ + /****************************************************************************** * usb boot command intepreter. Derived from diskboot @@ -441,17 +519,9 @@ static int do_usb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) } return 0; } else { - int d; - - i = simple_strtoul(argv[2], NULL, 16); + i = simple_strtoul(argv[2], NULL, 10); printf("config for device %d\n", i); - for (d = 0; d < USB_MAX_DEVICE; d++) { - dev = usb_get_dev_index(d); - if (dev == NULL) - break; - if (dev->devnum == i) - break; - } + dev = usb_find_device(i); if (dev == NULL) { printf("*** No device available ***\n"); return 0; @@ -462,6 +532,20 @@ static int do_usb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) } return 0; } +#ifdef CONFIG_CMD_USB_TEST + if (strncmp(argv[1], "test", 4) == 0) { + if (argc < 5) + return CMD_RET_USAGE; + i = simple_strtoul(argv[2], NULL, 10); + dev = usb_find_device(i); + if (dev == NULL) { + printf("Device %d does not exist.\n", i); + return 1; + } + i = simple_strtoul(argv[3], NULL, 10); + return usb_test(dev, i, argv[4]); + } +#endif /* CONFIG_CMD_USB_TEST */ #ifdef CONFIG_USB_STORAGE if (strncmp(argv[1], "stor", 4) == 0) return usb_stor_info(); @@ -571,7 +655,6 @@ static int do_usb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) return CMD_RET_USAGE; } -#ifdef CONFIG_USB_STORAGE U_BOOT_CMD( usb, 5, 1, do_usb, "USB sub-system", @@ -580,30 +663,28 @@ U_BOOT_CMD( "usb stop [f] - stop USB [f]=force stop\n" "usb tree - show USB device tree\n" "usb info [dev] - show available USB devices\n" +#ifdef CONFIG_CMD_USB_TEST + "usb test [dev] [port] [mode] - set USB 2.0 test mode\n" + " (specify port 0 to indicate the device's upstream port)\n" + " Available modes: J, K, S[E0_NAK], P[acket], F[orce_Enable]\n" +#endif /* CONFIG_CMD_USB_TEST */ +#ifdef CONFIG_USB_STORAGE "usb storage - show details of USB storage devices\n" "usb dev [dev] - show or set current USB storage device\n" "usb part [dev] - print partition table of one or all USB storage" - " devices\n" + " devices\n" "usb read addr blk# cnt - read `cnt' blocks starting at block `blk#'\n" " to memory address `addr'\n" "usb write addr blk# cnt - write `cnt' blocks starting at block `blk#'\n" " from memory address `addr'" +#endif /* CONFIG_USB_STORAGE */ ); +#ifdef CONFIG_USB_STORAGE U_BOOT_CMD( usbboot, 3, 1, do_usbboot, "boot from USB device", "loadAddr dev:part" ); - -#else -U_BOOT_CMD( - usb, 5, 1, do_usb, - "USB sub-system", - "start - start (scan) USB controller\n" - "usb reset - reset (rescan) USB controller\n" - "usb tree - show USB device tree\n" - "usb info [dev] - show available USB devices" -); -#endif +#endif /* CONFIG_USB_STORAGE */ diff --git a/doc/README.usb b/doc/README.usb index b4c3ef5..5e44fe0 100644 --- a/doc/README.usb +++ b/doc/README.usb @@ -80,6 +80,7 @@ CONFIG_USB_UHCI defines the lowlevel part.A lowlevel part must be defined CONFIG_USB_KEYBOARD enables the USB Keyboard CONFIG_USB_STORAGE enables the USB storage devices CONFIG_USB_HOST_ETHER enables USB ethernet adapter support +CONFIG_CMD_USB_TEST enables the 'usb test' command for USB 2.0 test modes USB Host Networking diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 7f98a63..1d0299b 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -602,15 +602,19 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer, int len, srclen; uint32_t reg; uint32_t *status_reg; + int port = le16_to_cpu(req->index) & 0xff; struct ehci_ctrl *ctrl = dev->controller; - if (le16_to_cpu(req->index) > CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) { - printf("The request port(%d) is not configured\n", - le16_to_cpu(req->index) - 1); + if (port > CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) { + printf("The request port(%d) is not configured\n", port - 1); return -1; } - status_reg = (uint32_t *)&ctrl->hcor->or_portsc[ - le16_to_cpu(req->index) - 1]; + if (port && !(ctrl->port_enable_mask & + (1 << (port - 1)))) { + debug("skip request on disabled port%d\n", port - 1); + return 0; + } + status_reg = (uint32_t *)&hcor->or_portsc[port - 1]; srclen = 0; debug("req=%u (%#x), type=%u (%#x), value=%u, index=%u\n", @@ -727,7 +731,7 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer, tmpbuf[2] |= USB_PORT_STAT_C_ENABLE; if (reg & EHCI_PS_OCC) tmpbuf[2] |= USB_PORT_STAT_C_OVERCURRENT; - if (ctrl->portreset & (1 << le16_to_cpu(req->index))) + if (ctrl->portreset & (1 << port)) tmpbuf[2] |= USB_PORT_STAT_C_RESET; srcptr = tmpbuf; @@ -753,7 +757,7 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer, EHCI_PS_IS_LOWSPEED(reg)) { /* Low speed device, give up ownership. */ debug("port %d low speed --> companion\n", - req->index - 1); + port - 1); reg |= EHCI_PS_PO; ehci_writel(status_reg, reg); break; @@ -779,13 +783,19 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer, ret = handshake(status_reg, EHCI_PS_PR, 0, 2 * 1000); if (!ret) - ctrl->portreset |= - 1 << le16_to_cpu(req->index); + ctrl->portreset |= 1 << port; else printf("port(%d) reset error\n", - le16_to_cpu(req->index) - 1); + port - 1); } break; +#ifdef CONFIG_CMD_USB_TEST + case USB_PORT_FEAT_TEST: + reg &= ~(0xf << 16); + reg |= ((le16_to_cpu(req->index) >> 8) & 0xf) << 16; + ehci_writel(status_reg, reg); + break; +#endif /* CONFIG_CMD_USB_TEST */ default: debug("unknown feature %x\n", le16_to_cpu(req->value)); goto unknown; @@ -812,7 +822,7 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer, reg = (reg & ~EHCI_PS_CLEAR) | EHCI_PS_OCC; break; case USB_PORT_FEAT_C_RESET: - ctrl->portreset &= ~(1 << le16_to_cpu(req->index)); + ctrl->portreset &= ~(1 << port); break; default: debug("unknown feature %x\n", le16_to_cpu(req->value)); diff --git a/include/usb_defs.h b/include/usb_defs.h index 9502544..5c5478f 100644 --- a/include/usb_defs.h +++ b/include/usb_defs.h @@ -150,6 +150,18 @@ #define USB_REQ_SET_IDLE 0x0A #define USB_REQ_SET_PROTOCOL 0x0B +/* Device features */ +#define USB_FEAT_HALT 0x00 +#define USB_FEAT_WAKEUP 0x01 +#define USB_FEAT_TEST 0x02 + +/* Test modes */ +#define USB_TEST_MODE_J 0x01 +#define USB_TEST_MODE_K 0x02 +#define USB_TEST_MODE_SE0_NAK 0x03 +#define USB_TEST_MODE_PACKET 0x04 +#define USB_TEST_MODE_FORCE_ENABLE 0x05 + /* "pipe" definitions */ @@ -208,6 +220,7 @@ #define USB_PORT_FEAT_C_SUSPEND 18 #define USB_PORT_FEAT_C_OVER_CURRENT 19 #define USB_PORT_FEAT_C_RESET 20 +#define USB_PORT_FEAT_TEST 21 /* wPortStatus bits */ #define USB_PORT_STAT_CONNECTION 0x0001