From b068deb363e34a72754877d3d8c7a71a5bc834db Mon Sep 17 00:00:00 2001 From: Jim Lin Date: Wed, 27 Mar 2013 00:52:32 +0000 Subject: USB: EHCI: Add weak functions to support new chip Add ehci_get_port_speed() and ehci_set_usbmode() weak functions for platform driver to support new chip. Signed-off-by: Jim Lin --- drivers/usb/host/ehci-hcd.c | 40 ++++++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 12 deletions(-) (limited to 'drivers/usb/host') diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index c816878206..6a55cd244c 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -122,6 +122,31 @@ static struct descriptor { #define ehci_is_TDI() (0) #endif +int __ehci_get_port_speed(struct ehci_hcor *hcor, uint32_t reg) +{ + return PORTSC_PSPD(reg); +} + +int ehci_get_port_speed(struct ehci_hcor *hcor, uint32_t reg) + __attribute__((weak, alias("__ehci_get_port_speed"))); + +void __ehci_set_usbmode(int index) +{ + uint32_t tmp; + uint32_t *reg_ptr; + + reg_ptr = (uint32_t *)((u8 *)&ehcic[index].hcor->or_usbcmd + USBMODE); + tmp = ehci_readl(reg_ptr); + tmp |= USBMODE_CM_HC; +#if defined(CONFIG_EHCI_MMIO_BIG_ENDIAN) + tmp |= USBMODE_BE; +#endif + ehci_writel(reg_ptr, tmp); +} + +void ehci_set_usbmode(int index) + __attribute__((weak, alias("__ehci_set_usbmode"))); + void __ehci_powerup_fixup(uint32_t *status_reg, uint32_t *reg) { mdelay(50); @@ -149,8 +174,6 @@ static int handshake(uint32_t *ptr, uint32_t mask, uint32_t done, int usec) static int ehci_reset(int index) { uint32_t cmd; - uint32_t tmp; - uint32_t *reg_ptr; int ret = 0; cmd = ehci_readl(&ehcic[index].hcor->or_usbcmd); @@ -163,15 +186,8 @@ static int ehci_reset(int index) goto out; } - if (ehci_is_TDI()) { - reg_ptr = (uint32_t *)((u8 *)ehcic[index].hcor + USBMODE); - tmp = ehci_readl(reg_ptr); - tmp |= USBMODE_CM_HC; -#if defined(CONFIG_EHCI_MMIO_BIG_ENDIAN) - tmp |= USBMODE_BE; -#endif - ehci_writel(reg_ptr, tmp); - } + if (ehci_is_TDI()) + ehci_set_usbmode(index); #ifdef CONFIG_USB_EHCI_TXFIFO_THRESH cmd = ehci_readl(&ehcic[index].hcor->or_txfilltuning); @@ -711,7 +727,7 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer, tmpbuf[1] |= USB_PORT_STAT_POWER >> 8; if (ehci_is_TDI()) { - switch (PORTSC_PSPD(reg)) { + switch (ehci_get_port_speed(ctrl->hcor, reg)) { case PORTSC_PSPD_FS: break; case PORTSC_PSPD_LS: -- cgit v1.2.3 From 7d9aa8fd87171164a6f14167a0c9c066f4312b8d Mon Sep 17 00:00:00 2001 From: Julius Werner Date: Thu, 28 Feb 2013 18:08:40 +0000 Subject: usb: Add new command to set USB 2.0 port test modes 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. Signed-off-by: Julius Werner --- common/cmd_usb.c | 121 +++++++++++++++++++++++++++++++++++--------- drivers/usb/host/ehci-hcd.c | 25 +++++---- include/usb_defs.h | 13 +++++ 3 files changed, 125 insertions(+), 34 deletions(-) (limited to 'drivers/usb/host') diff --git a/common/cmd_usb.c b/common/cmd_usb.c index dacdc2d5b1..adc5f02a2c 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,66 @@ static void usb_show_tree(struct usb_device *dev) usb_show_tree_graph(dev, &preamble[0]); } +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; + } +} + /****************************************************************************** * usb boot command intepreter. Derived from diskboot @@ -441,17 +517,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 +530,18 @@ static int do_usb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) } return 0; } + 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]); + } #ifdef CONFIG_USB_STORAGE if (strncmp(argv[1], "stor", 4) == 0) return usb_stor_info(); @@ -571,7 +651,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 +659,26 @@ 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" + "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" +#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/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 6a55cd244c..19d4352024 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -623,15 +623,14 @@ 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]; + status_reg = (uint32_t *)&ctrl->hcor->or_portsc[port - 1]; srclen = 0; debug("req=%u (%#x), type=%u (%#x), value=%u, index=%u\n", @@ -748,7 +747,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; @@ -774,7 +773,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; @@ -800,13 +799,17 @@ 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; + case USB_PORT_FEAT_TEST: + reg &= ~(0xf << 16); + reg |= ((le16_to_cpu(req->index) >> 8) & 0xf) << 16; + ehci_writel(status_reg, reg); + break; default: debug("unknown feature %x\n", le16_to_cpu(req->value)); goto unknown; @@ -833,7 +836,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 9502544b21..5c5478f7cf 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 -- cgit v1.2.3 From 158947d276c96a49e0a99a97a61605be1bb5eb7a Mon Sep 17 00:00:00 2001 From: Bo Shen Date: Wed, 17 Apr 2013 00:09:51 +0000 Subject: USB: ohci-at91: make OHCI work on at91sam9g10 SoC The at91sam9g10 need to configure HCK0 to make OHCI work Signed-off-by: Bo Shen --- drivers/usb/host/ohci-at91.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/usb/host') diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index efd711d489..aa5cf57aed 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -55,7 +55,7 @@ int usb_cpu_init(void) /* Enable USB host clock. */ writel(1 << ATMEL_ID_UHP, &pmc->pcer); -#ifdef CONFIG_AT91SAM9261 +#if defined(CONFIG_AT91SAM9261) || defined(CONFIG_AT91SAM9G10) writel(ATMEL_PMC_UHP | AT91_PMC_HCK0, &pmc->scer); #else writel(ATMEL_PMC_UHP, &pmc->scer); @@ -70,7 +70,7 @@ int usb_cpu_stop(void) /* Disable USB host clock. */ writel(1 << ATMEL_ID_UHP, &pmc->pcdr); -#ifdef CONFIG_AT91SAM9261 +#if defined(CONFIG_AT91SAM9261) || defined(CONFIG_AT91SAM9G10) writel(ATMEL_PMC_UHP | AT91_PMC_HCK0, &pmc->scdr); #else writel(ATMEL_PMC_UHP, &pmc->scdr); -- cgit v1.2.3 From 4f4eab4d14b181c3a9447c75fd2b41b9d0d761e4 Mon Sep 17 00:00:00 2001 From: Vivek Gautam Date: Wed, 24 Apr 2013 02:50:13 +0000 Subject: usb: common: Use a global definition for 'min3' We can use a common global method for calculating minimum of 3 numbers. Put the same in 'common header' and let 'ehci' use it. Signed-off-by: Vivek Gautam Acked-by: Tom Rini --- drivers/usb/host/ehci-hcd.c | 10 ---------- include/common.h | 25 +++++++++++++++++++++---- 2 files changed, 21 insertions(+), 14 deletions(-) (limited to 'drivers/usb/host') diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 19d4352024..e0f3e4b6c7 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -603,16 +603,6 @@ fail: return -1; } -static inline int min3(int a, int b, int c) -{ - - if (b < a) - a = b; - if (c < a) - a = c; - return a; -} - int ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer, int length, struct devrequest *req) diff --git a/include/common.h b/include/common.h index 8a1f3e406d..40e4b077fd 100644 --- a/include/common.h +++ b/include/common.h @@ -199,18 +199,35 @@ typedef void (interrupt_handler_t)(void *); * General Purpose Utilities */ #define min(X, Y) \ - ({ typeof (X) __x = (X); \ - typeof (Y) __y = (Y); \ + ({ typeof(X) __x = (X); \ + typeof(Y) __y = (Y); \ (__x < __y) ? __x : __y; }) #define max(X, Y) \ - ({ typeof (X) __x = (X); \ - typeof (Y) __y = (Y); \ + ({ typeof(X) __x = (X); \ + typeof(Y) __y = (Y); \ (__x > __y) ? __x : __y; }) #define MIN(x, y) min(x, y) #define MAX(x, y) max(x, y) +#define min3(X, Y, Z) \ + ({ typeof(X) __x = (X); \ + typeof(Y) __y = (Y); \ + typeof(Z) __z = (Z); \ + __x < __y ? (__x < __z ? __x : __z) : \ + (__y < __z ? __y : __z); }) + +#define max3(X, Y, Z) \ + ({ typeof(X) __x = (X); \ + typeof(Y) __y = (Y); \ + typeof(Z) __z = (Z); \ + __x > __y ? (__x > __z ? __x : __z) : \ + (__y > __z ? __y : __z); }) + +#define MIN3(x, y, z) min3(x, y, z) +#define MAX3(x, y, z) max3(x, y, z) + /* * Return the absolute value of a number. * -- cgit v1.2.3