From 7359273d946a7dcde04c5e8d5bad669146efc87c Mon Sep 17 00:00:00 2001 From: Ajay Kumar Gupta Date: Tue, 22 Dec 2009 10:56:13 +0530 Subject: DA8xx: Add MUSB host support Tested USB host functionality on DA830 EVM. Signed-off-by: Ajay Kumar Gupta Signed-off-by: Swaminathan S --- drivers/usb/musb/Makefile | 1 + drivers/usb/musb/da8xx.c | 139 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/usb/musb/da8xx.h | 103 ++++++++++++++++++++++++++++++++++ 3 files changed, 243 insertions(+) create mode 100644 drivers/usb/musb/da8xx.c create mode 100644 drivers/usb/musb/da8xx.h (limited to 'drivers') diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile index f2ccd9fe06..12e115ef11 100644 --- a/drivers/usb/musb/Makefile +++ b/drivers/usb/musb/Makefile @@ -29,6 +29,7 @@ COBJS-$(CONFIG_MUSB_HCD) += musb_hcd.o musb_core.o COBJS-$(CONFIG_MUSB_UDC) += musb_udc.o musb_core.o COBJS-$(CONFIG_USB_DAVINCI) += davinci.o COBJS-$(CONFIG_USB_OMAP3) += omap3.o +COBJS-$(CONFIG_USB_DA8XX) += da8xx.o COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c new file mode 100644 index 0000000000..40bfe440d8 --- /dev/null +++ b/drivers/usb/musb/da8xx.c @@ -0,0 +1,139 @@ +/* + * da8xx.c - TI's DA8xx platform specific usb wrapper functions. + * + * Author: Ajay Kumar Gupta + * + * Based on drivers/usb/musb/davinci.c + * + * Copyright (C) 2009 Texas Instruments Incorporated + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include + +#include "da8xx.h" + +/* MUSB platform configuration */ +struct musb_config musb_cfg = { + (struct musb_regs *)DA8XX_USB_OTG_CORE_BASE, + DA8XX_USB_OTG_TIMEOUT, + 0 +}; + +/* + * This function enables VBUS by driving the GPIO Bank4 Pin 15 high. + */ +static void enable_vbus(void) +{ + u32 value; + + /* configure GPIO bank4 pin 15 in output direction */ + value = readl(&davinci_gpio_bank45->dir); + writel((value & (~DA8XX_USB_VBUS_GPIO)), &davinci_gpio_bank45->dir); + + /* set GPIO bank4 pin 15 high to drive VBUS */ + value = readl(&davinci_gpio_bank45->set_data); + writel((value | DA8XX_USB_VBUS_GPIO), &davinci_gpio_bank45->set_data); +} + +/* + * Enable the usb0 phy. This initialization procedure is explained in + * the DA8xx USB user guide document. + */ +static u8 phy_on(void) +{ + u32 timeout; + u32 cfgchip2; + + cfgchip2 = readl(&davinci_syscfg_regs->cfgchip2); + + cfgchip2 &= ~(CFGCHIP2_RESET | CFGCHIP2_PHYPWRDN | CFGCHIP2_OTGPWRDN | + CFGCHIP2_OTGMODE | CFGCHIP2_REFFREQ); + cfgchip2 |= CFGCHIP2_SESENDEN | CFGCHIP2_VBDTCTEN | CFGCHIP2_PHY_PLLON | + CFGCHIP2_REFFREQ_24MHZ; + + writel(cfgchip2, &davinci_syscfg_regs->cfgchip2); + + /* wait until the usb phy pll locks */ + timeout = musb_cfg.timeout; + while (timeout--) + if (readl(&davinci_syscfg_regs->cfgchip2) & CFGCHIP2_PHYCLKGD) + return 1; + + /* USB phy was not turned on */ + return 0; +} + +/* + * Disable the usb phy + */ +static void phy_off(void) +{ + u32 cfgchip2; + + /* + * Power down the on-chip PHY. + */ + cfgchip2 = readl(&davinci_syscfg_regs->cfgchip2); + cfgchip2 &= ~CFGCHIP2_PHY_PLLON; + cfgchip2 |= CFGCHIP2_PHYPWRDN | CFGCHIP2_OTGPWRDN; + writel(cfgchip2, &davinci_syscfg_regs->cfgchip2); +} + +/* + * This function performs DA8xx platform specific initialization for usb0. + */ +int musb_platform_init(void) +{ + u32 revision; + + /* enable psc for usb2.0 */ + lpsc_on(33); + + /* enable usb vbus */ + enable_vbus(); + + /* reset the controller */ + writel(0x1, &da8xx_usb_regs->control); + udelay(5000); + + /* start the on-chip usb phy and its pll */ + if (phy_on() == 0) + return -1; + + /* Returns zero if e.g. not clocked */ + revision = readl(&da8xx_usb_regs->revision); + if (revision == 0) + return -1; + + /* Disable all interrupts */ + writel((DA8XX_USB_USBINT_MASK | DA8XX_USB_TXINT_MASK | + DA8XX_USB_RXINT_MASK), &da8xx_usb_regs->intmsk_set); + return 0; +} + +/* + * This function performs DA8xx platform specific deinitialization for usb0. + */ +void musb_platform_deinit(void) +{ + /* Turn of the phy */ + phy_off(); + + /* flush any interrupts */ + writel((DA8XX_USB_USBINT_MASK | DA8XX_USB_TXINT_MASK | + DA8XX_USB_RXINT_MASK), &da8xx_usb_regs->intmsk_clr); + writel(0, &da8xx_usb_regs->eoi); +} diff --git a/drivers/usb/musb/da8xx.h b/drivers/usb/musb/da8xx.h new file mode 100644 index 0000000000..93234f0dd4 --- /dev/null +++ b/drivers/usb/musb/da8xx.h @@ -0,0 +1,103 @@ +/* + * da8xx.h -- TI's DA8xx platform specific usb wrapper definitions. + * + * Author: Ajay Kumar Gupta + * + * Based on drivers/usb/musb/davinci.h + * + * Copyright (C) 2009 Texas Instruments Incorporated + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __DA8XX_MUSB_H__ +#define __DA8XX_MUSB_H__ + +#include +#include +#include "musb_core.h" + +/* Base address of da8xx usb0 wrapper */ +#define DA8XX_USB_OTG_BASE 0x01E00000 + +/* Base address of da8xx musb core */ +#define DA8XX_USB_OTG_CORE_BASE (DA8XX_USB_OTG_BASE + 0x400) + +/* Timeout for DA8xx usb module */ +#define DA8XX_USB_OTG_TIMEOUT 0x3FFFFFF + +/* + * DA8xx platform USB wrapper register overlay. + */ +struct da8xx_usb_regs { + dv_reg revision; + dv_reg control; + dv_reg status; + dv_reg emulation; + dv_reg mode; + dv_reg autoreq; + dv_reg srpfixtime; + dv_reg teardown; + dv_reg intsrc; + dv_reg intsrc_set; + dv_reg intsrc_clr; + dv_reg intmsk; + dv_reg intmsk_set; + dv_reg intmsk_clr; + dv_reg intsrcmsk; + dv_reg eoi; + dv_reg intvector; + dv_reg grndis_size[4]; +}; + +#define da8xx_usb_regs ((struct da8xx_usb_regs *)DA8XX_USB_OTG_BASE) + +/* DA8XX interrupt bits definitions */ +#define DA8XX_USB_TX_ENDPTS_MASK 0x1f /* ep0 + 4 tx */ +#define DA8XX_USB_RX_ENDPTS_MASK 0x1e /* 4 rx */ +#define DA8XX_USB_TXINT_SHIFT 0 +#define DA8XX_USB_RXINT_SHIFT 8 + +#define DA8XX_USB_USBINT_MASK 0x01ff0000 /* 8 Mentor, DRVVBUS */ +#define DA8XX_USB_TXINT_MASK \ + (DA8XX_USB_TX_ENDPTS_MASK << DA8XX_USB_TXINT_SHIFT) +#define DA8XX_USB_RXINT_MASK \ + (DA8XX_USB_RX_ENDPTS_MASK << DA8XX_USB_RXINT_SHIFT) + +/* DA8xx CFGCHIP2 (USB 2.0 PHY Control) register bits */ +#define CFGCHIP2_PHYCLKGD (1 << 17) +#define CFGCHIP2_VBUSSENSE (1 << 16) +#define CFGCHIP2_RESET (1 << 15) +#define CFGCHIP2_OTGMODE (3 << 13) +#define CFGCHIP2_NO_OVERRIDE (0 << 13) +#define CFGCHIP2_FORCE_HOST (1 << 13) +#define CFGCHIP2_FORCE_DEVICE (2 << 13) +#define CFGCHIP2_FORCE_HOST_VBUS_LOW (3 << 13) +#define CFGCHIP2_USB1PHYCLKMUX (1 << 12) +#define CFGCHIP2_USB2PHYCLKMUX (1 << 11) +#define CFGCHIP2_PHYPWRDN (1 << 10) +#define CFGCHIP2_OTGPWRDN (1 << 9) +#define CFGCHIP2_DATPOL (1 << 8) +#define CFGCHIP2_USB1SUSPENDM (1 << 7) +#define CFGCHIP2_PHY_PLLON (1 << 6) /* override PLL suspend */ +#define CFGCHIP2_SESENDEN (1 << 5) /* Vsess_end comparator */ +#define CFGCHIP2_VBDTCTEN (1 << 4) /* Vbus comparator */ +#define CFGCHIP2_REFFREQ (0xf << 0) +#define CFGCHIP2_REFFREQ_12MHZ (1 << 0) +#define CFGCHIP2_REFFREQ_24MHZ (2 << 0) +#define CFGCHIP2_REFFREQ_48MHZ (3 << 0) + +#define DA8XX_USB_VBUS_GPIO (1 << 15) +#endif /* __DA8XX_MUSB_H__ */ + -- cgit v1.2.1 From dc2cd05c91a134d53fada41e8f97a434be22de02 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 16 Dec 2009 22:03:58 -0500 Subject: usb: musb: make sure the register layout is packed Signed-off-by: Mike Frysinger Signed-off-by: Remy Bohmer --- drivers/usb/musb/musb_core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index 15c7f49a35..cee7a11294 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -137,7 +137,7 @@ struct musb_regs { struct musb_epN_regs epN; } ep[16]; -} __attribute__((aligned(32))); +} __attribute__((packed, aligned(32))); /* * MUSB Register bits -- cgit v1.2.1 From df402ba38103df51f6929848b6a797eff4db61f8 Mon Sep 17 00:00:00 2001 From: Bryan Wu Date: Wed, 16 Dec 2009 22:03:59 -0500 Subject: usb: musb: make fifo support configurable The dynamic FIFO handling under MUSB is optional, and some parts (like the Blackfin processor) do not implement support for it. Due to this, the FIFO reading/writing steps need special handling, so mark the common versions weak so drivers can override. Signed-off-by: Bryan Wu Signed-off-by: Cliff Cai Signed-off-by: Mike Frysinger Signed-off-by: Remy Bohmer --- drivers/usb/musb/musb_core.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 22f3dba0cf..7766069bfc 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -50,6 +50,16 @@ void musb_start(void) #endif } +#ifdef MUSB_NO_DYNAMIC_FIFO +# define config_fifo(dir, idx, addr) +#else +# define config_fifo(dir, idx, addr) \ + do { \ + writeb(idx, &musbr->dir##fifosz); \ + writew(fifoaddr >> 3, &musbr->dir##fifoadd); \ + } while (0) +#endif + /* * This function configures the endpoint configuration. The musb hcd or musb * device implementation can use this function to configure the endpoints @@ -74,8 +84,7 @@ void musb_configure_ep(struct musb_epinfo *epinfo, u8 cnt) writeb(epinfo->epnum, &musbr->index); if (epinfo->epdir) { /* Configure fifo size and fifo base address */ - writeb(idx, &musbr->txfifosz); - writew(fifoaddr >> 3, &musbr->txfifoadd); + config_fifo(tx, idx, fifoaddr); csr = readw(&musbr->txcsr); #if defined(CONFIG_MUSB_HCD) @@ -88,8 +97,7 @@ void musb_configure_ep(struct musb_epinfo *epinfo, u8 cnt) &musbr->txcsr); } else { /* Configure fifo size and fifo base address */ - writeb(idx, &musbr->rxfifosz); - writew(fifoaddr >> 3, &musbr->rxfifoadd); + config_fifo(rx, idx, fifoaddr); csr = readw(&musbr->rxcsr); #if defined(CONFIG_MUSB_HCD) @@ -113,6 +121,7 @@ void musb_configure_ep(struct musb_epinfo *epinfo, u8 cnt) * length - number of bytes to write to FIFO * fifo_data - Pointer to data buffer that contains the data to write */ +__attribute__((weak)) void write_fifo(u8 ep, u32 length, void *fifo_data) { u8 *data = (u8 *)fifo_data; @@ -132,6 +141,7 @@ void write_fifo(u8 ep, u32 length, void *fifo_data) * length - number of bytes to read from FIFO * fifo_data - pointer to data buffer into which data is read */ +__attribute__((weak)) void read_fifo(u8 ep, u32 length, void *fifo_data) { u8 *data = (u8 *)fifo_data; -- cgit v1.2.1 From 8868fd443b7a52bf433903cc9527403ad055acb9 Mon Sep 17 00:00:00 2001 From: Bryan Wu Date: Wed, 16 Dec 2009 22:04:00 -0500 Subject: usb: musb: make multipoint optional The multipoint handling under MUSB is optional, and some parts (like the Blackfin processor) do not implement support for it. Signed-off-by: Bryan Wu Signed-off-by: Cliff Cai Signed-off-by: Mike Frysinger Signed-off-by: Remy Bohmer --- drivers/usb/musb/musb_hcd.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/musb/musb_hcd.c b/drivers/usb/musb/musb_hcd.c index 555d2dc1b0..5481600509 100644 --- a/drivers/usb/musb/musb_hcd.c +++ b/drivers/usb/musb/musb_hcd.c @@ -402,11 +402,13 @@ static void config_hub_port(struct usb_device *dev, u8 ep) if (dev->parent->children[chid] == dev) break; +#ifndef MUSB_NO_MULTIPOINT /* configure the hub address and the port address */ writeb(hub, &musbr->tar[ep].txhubaddr); writeb((chid + 1), &musbr->tar[ep].txhubport); writeb(hub, &musbr->tar[ep].rxhubaddr); writeb((chid + 1), &musbr->tar[ep].rxhubport); +#endif } /* @@ -415,7 +417,9 @@ static void config_hub_port(struct usb_device *dev, u8 ep) int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, int len, struct devrequest *setup) { +#ifndef MUSB_NO_MULTIPOINT int devnum = usb_pipedevice(pipe); +#endif u16 csr; u8 devspeed; @@ -423,9 +427,11 @@ int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, writeb(MUSB_CONTROL_EP, &musbr->index); csr = readw(&musbr->txcsr); +#ifndef MUSB_NO_MULTIPOINT /* target addr and (for multipoint) hub addr/port */ writeb(devnum, &musbr->tar[MUSB_CONTROL_EP].txfuncaddr); writeb(devnum, &musbr->tar[MUSB_CONTROL_EP].rxfuncaddr); +#endif /* configure the hub address and the port number as required */ devspeed = get_dev_speed(dev); @@ -435,10 +441,12 @@ int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, writeb(devspeed << 6, &musbr->txtype); } else { writeb(musb_cfg.musb_speed << 6, &musbr->txtype); +#ifndef MUSB_NO_MULTIPOINT writeb(0, &musbr->tar[MUSB_CONTROL_EP].txhubaddr); writeb(0, &musbr->tar[MUSB_CONTROL_EP].txhubport); writeb(0, &musbr->tar[MUSB_CONTROL_EP].rxhubaddr); writeb(0, &musbr->tar[MUSB_CONTROL_EP].rxhubport); +#endif } /* Control transfer setup phase */ @@ -497,7 +505,9 @@ int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, { int dir_out = usb_pipeout(pipe); int ep = usb_pipeendpoint(pipe); +#ifndef MUSB_NO_MULTIPOINT int devnum = usb_pipedevice(pipe); +#endif u8 type; u16 csr; u32 txlen = 0; @@ -507,11 +517,13 @@ int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, /* select bulk endpoint */ writeb(MUSB_BULK_EP, &musbr->index); +#ifndef MUSB_NO_MULTIPOINT /* write the address of the device */ if (dir_out) writeb(devnum, &musbr->tar[MUSB_BULK_EP].txfuncaddr); else writeb(devnum, &musbr->tar[MUSB_BULK_EP].rxfuncaddr); +#endif /* configure the hub address and the port number as required */ devspeed = get_dev_speed(dev); @@ -524,6 +536,7 @@ int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, */ config_hub_port(dev, MUSB_BULK_EP); } else { +#ifndef MUSB_NO_MULTIPOINT if (dir_out) { writeb(0, &musbr->tar[MUSB_BULK_EP].txhubaddr); writeb(0, &musbr->tar[MUSB_BULK_EP].txhubport); @@ -531,6 +544,7 @@ int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, writeb(0, &musbr->tar[MUSB_BULK_EP].rxhubaddr); writeb(0, &musbr->tar[MUSB_BULK_EP].rxhubport); } +#endif devspeed = musb_cfg.musb_speed; } @@ -696,7 +710,9 @@ int submit_int_msg(struct usb_device *dev, unsigned long pipe, { int dir_out = usb_pipeout(pipe); int ep = usb_pipeendpoint(pipe); +#ifndef MUSB_NO_MULTIPOINT int devnum = usb_pipedevice(pipe); +#endif u8 type; u16 csr; u32 txlen = 0; @@ -706,11 +722,13 @@ int submit_int_msg(struct usb_device *dev, unsigned long pipe, /* select interrupt endpoint */ writeb(MUSB_INTR_EP, &musbr->index); +#ifndef MUSB_NO_MULTIPOINT /* write the address of the device */ if (dir_out) writeb(devnum, &musbr->tar[MUSB_INTR_EP].txfuncaddr); else writeb(devnum, &musbr->tar[MUSB_INTR_EP].rxfuncaddr); +#endif /* configure the hub address and the port number as required */ devspeed = get_dev_speed(dev); @@ -723,6 +741,7 @@ int submit_int_msg(struct usb_device *dev, unsigned long pipe, */ config_hub_port(dev, MUSB_INTR_EP); } else { +#ifndef MUSB_NO_MULTIPOINT if (dir_out) { writeb(0, &musbr->tar[MUSB_INTR_EP].txhubaddr); writeb(0, &musbr->tar[MUSB_INTR_EP].txhubport); @@ -730,6 +749,7 @@ int submit_int_msg(struct usb_device *dev, unsigned long pipe, writeb(0, &musbr->tar[MUSB_INTR_EP].rxhubaddr); writeb(0, &musbr->tar[MUSB_INTR_EP].rxhubport); } +#endif devspeed = musb_cfg.musb_speed; } -- cgit v1.2.1 From bc72a919e037782f64e3ac45c91bc60408e57e85 Mon Sep 17 00:00:00 2001 From: Bryan Wu Date: Wed, 16 Dec 2009 22:04:01 -0500 Subject: usb: musb: change rxcsr register from write to read/modify/write The RX Control/Status register has bits that we want to preserve, so don't just write out a single bit. Preserve the others bits in the process. The original code posted to the u-boot list had this behavior, but looks like it was lost somewhere along the way to merging. Signed-off-by: Bryan Wu Signed-off-by: Cliff Cai Signed-off-by: Mike Frysinger Signed-off-by: Remy Bohmer --- drivers/usb/musb/musb_hcd.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/musb/musb_hcd.c b/drivers/usb/musb/musb_hcd.c index 5481600509..adb8c38527 100644 --- a/drivers/usb/musb/musb_hcd.c +++ b/drivers/usb/musb/musb_hcd.c @@ -604,7 +604,8 @@ int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, (len-txlen) : dev->epmaxpacketin[ep]; /* Set the ReqPkt bit */ - writew(MUSB_RXCSR_H_REQPKT, &musbr->rxcsr); + csr = readw(&musbr->rxcsr); + writew(csr | MUSB_RXCSR_H_REQPKT, &musbr->rxcsr); /* Wait until the RxPktRdy bit is set */ if (!wait_until_rxep_ready(dev, MUSB_BULK_EP)) { @@ -775,7 +776,8 @@ int submit_int_msg(struct usb_device *dev, unsigned long pipe, (len-txlen) : dev->epmaxpacketin[ep]; /* Set the ReqPkt bit */ - writew(MUSB_RXCSR_H_REQPKT, &musbr->rxcsr); + csr = readw(&musbr->rxcsr); + writew(csr | MUSB_RXCSR_H_REQPKT, &musbr->rxcsr); /* Wait until the RxPktRdy bit is set */ if (!wait_until_rxep_ready(dev, MUSB_INTR_EP)) { -- cgit v1.2.1 From e608f221c13943d88e86f44753e23668342c3df3 Mon Sep 17 00:00:00 2001 From: Bryan Wu Date: Wed, 16 Dec 2009 22:04:02 -0500 Subject: usb: musb: add support for Blackfin MUSB Signed-off-by: Bryan Wu Signed-off-by: Cliff Cai Signed-off-by: Mike Frysinger Signed-off-by: Remy Bohmer --- drivers/usb/musb/Makefile | 1 + drivers/usb/musb/blackfin_usb.c | 143 ++++++++++++++++++++++++++++++++++++++++ drivers/usb/musb/blackfin_usb.h | 99 ++++++++++++++++++++++++++++ drivers/usb/musb/musb_core.h | 16 +++++ drivers/usb/musb/musb_hcd.h | 4 +- 5 files changed, 262 insertions(+), 1 deletion(-) create mode 100644 drivers/usb/musb/blackfin_usb.c create mode 100644 drivers/usb/musb/blackfin_usb.h (limited to 'drivers') diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile index 12e115ef11..397f5fe7a3 100644 --- a/drivers/usb/musb/Makefile +++ b/drivers/usb/musb/Makefile @@ -27,6 +27,7 @@ LIB := $(obj)libusb_musb.a COBJS-$(CONFIG_MUSB_HCD) += musb_hcd.o musb_core.o COBJS-$(CONFIG_MUSB_UDC) += musb_udc.o musb_core.o +COBJS-$(CONFIG_USB_BLACKFIN) += blackfin_usb.o COBJS-$(CONFIG_USB_DAVINCI) += davinci.o COBJS-$(CONFIG_USB_OMAP3) += omap3.o COBJS-$(CONFIG_USB_DA8XX) += da8xx.o diff --git a/drivers/usb/musb/blackfin_usb.c b/drivers/usb/musb/blackfin_usb.c new file mode 100644 index 0000000000..38aceb2e93 --- /dev/null +++ b/drivers/usb/musb/blackfin_usb.c @@ -0,0 +1,143 @@ +/* + * Blackfin MUSB HCD (Host Controller Driver) for u-boot + * + * Copyright (c) 2008-2009 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include + +#include + +#include +#include + +#include "musb_core.h" + +/* MUSB platform configuration */ +struct musb_config musb_cfg = { + .regs = (struct musb_regs *)USB_FADDR, + .timeout = 0x3FFFFFF, + .musb_speed = 0, +}; + +/* + * This function read or write data to endpoint fifo + * Blackfin use DMA polling method to avoid buffer alignment issues + * + * ep - Endpoint number + * length - Number of bytes to write to FIFO + * fifo_data - Pointer to data buffer to be read/write + * is_write - Flag for read or write + */ +void rw_fifo(u8 ep, u32 length, void *fifo_data, int is_write) +{ + struct bfin_musb_dma_regs *regs; + u32 val = (u32)fifo_data; + + blackfin_dcache_flush_invalidate_range(fifo_data, fifo_data + length); + + regs = (void *)USB_DMA_INTERRUPT; + regs += ep; + + /* Setup DMA address register */ + bfin_write16(®s->addr_low, val); + SSYNC(); + + bfin_write16(®s->addr_high, val >> 16); + SSYNC(); + + /* Setup DMA count register */ + bfin_write16(®s->count_low, length); + bfin_write16(®s->count_high, 0); + SSYNC(); + + /* Enable the DMA */ + val = (ep << 4) | DMA_ENA | INT_ENA; + if (is_write) + val |= DIRECTION; + bfin_write16(®s->control, val); + SSYNC(); + + /* Wait for compelete */ + while (!(bfin_read_USB_DMA_INTERRUPT() & (1 << ep))) + continue; + + /* acknowledge dma interrupt */ + bfin_write_USB_DMA_INTERRUPT(1 << ep); + SSYNC(); + + /* Reset DMA */ + bfin_write16(®s->control, 0); + SSYNC(); +} + +void write_fifo(u8 ep, u32 length, void *fifo_data) +{ + rw_fifo(ep, length, fifo_data, 1); +} + +void read_fifo(u8 ep, u32 length, void *fifo_data) +{ + rw_fifo(ep, length, fifo_data, 0); +} + + +/* + * CPU and board-specific MUSB initializations. Aliased function + * signals caller to move on. + */ +static void __def_musb_init(void) +{ +} +void board_musb_init(void) __attribute__((weak, alias("__def_musb_init"))); + +int musb_platform_init(void) +{ + /* board specific initialization */ + board_musb_init(); + + if (ANOMALY_05000346) { + bfin_write_USB_APHY_CALIB(ANOMALY_05000346_value); + SSYNC(); + } + + if (ANOMALY_05000347) { + bfin_write_USB_APHY_CNTRL(0x0); + SSYNC(); + } + + /* Configure PLL oscillator register */ + bfin_write_USB_PLLOSC_CTRL(0x30a8); + SSYNC(); + + bfin_write_USB_SRP_CLKDIV((get_sclk()/1000) / 32 - 1); + SSYNC(); + + bfin_write_USB_EP_NI0_RXMAXP(64); + SSYNC(); + + bfin_write_USB_EP_NI0_TXMAXP(64); + SSYNC(); + + /* Route INTRUSB/INTR_RX/INTR_TX to USB_INT0*/ + bfin_write_USB_GLOBINTR(0x7); + SSYNC(); + + bfin_write_USB_GLOBAL_CTL(GLOBAL_ENA | EP1_TX_ENA | EP2_TX_ENA | + EP3_TX_ENA | EP4_TX_ENA | EP5_TX_ENA | + EP6_TX_ENA | EP7_TX_ENA | EP1_RX_ENA | + EP2_RX_ENA | EP3_RX_ENA | EP4_RX_ENA | + EP5_RX_ENA | EP6_RX_ENA | EP7_RX_ENA); + SSYNC(); + + return 0; +} + +/* + * This function performs Blackfin platform specific deinitialization for usb. +*/ +void musb_platform_deinit(void) +{ +} diff --git a/drivers/usb/musb/blackfin_usb.h b/drivers/usb/musb/blackfin_usb.h new file mode 100644 index 0000000000..ab26ca2d51 --- /dev/null +++ b/drivers/usb/musb/blackfin_usb.h @@ -0,0 +1,99 @@ +/* + * Blackfin MUSB HCD (Host Controller Driver) for u-boot + * + * Copyright (c) 2008-2009 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#ifndef __BLACKFIN_USB_H__ +#define __BLACKFIN_USB_H__ + +#include + +/* Every register is 32bit aligned, but only 16bits in size */ +#define ureg(name) u16 name; u16 __pad_##name; + +#define musb_regs musb_regs +struct musb_regs { + /* common registers */ + ureg(faddr) + ureg(power) + ureg(intrtx) + ureg(intrrx) + ureg(intrtxe) + ureg(intrrxe) + ureg(intrusb) + ureg(intrusbe) + ureg(frame) + ureg(index) + ureg(testmode) + ureg(globintr) + ureg(global_ctl) + u32 reserved0[3]; + /* indexed registers */ + ureg(txmaxp) + ureg(txcsr) + ureg(rxmaxp) + ureg(rxcsr) + ureg(rxcount) + ureg(txtype) + ureg(txinterval) + ureg(rxtype) + ureg(rxinterval) + u32 reserved1; + ureg(txcount) + u32 reserved2[5]; + /* fifo */ + u16 fifox[32]; + /* OTG, dynamic FIFO, version & vendor registers */ + u32 reserved3[16]; + ureg(devctl) + ureg(vbus_irq) + ureg(vbus_mask) + u32 reserved4[15]; + ureg(linkinfo) + ureg(vplen) + ureg(hseof1) + ureg(fseof1) + ureg(lseof1) + u32 reserved5[41]; + /* target address registers */ + struct musb_tar_regs { + ureg(txmaxp) + ureg(txcsr) + ureg(rxmaxp) + ureg(rxcsr) + ureg(rxcount) + ureg(txtype) + ureg(txinternal) + ureg(rxtype) + ureg(rxinternal) + u32 reserved6; + ureg(txcount) + u32 reserved7[5]; + } tar[8]; +} __attribute__((packed)); + +struct bfin_musb_dma_regs { + ureg(interrupt); + ureg(control); + ureg(addr_low); + ureg(addr_high); + ureg(count_low); + ureg(count_high); + ureg(pad); +}; + +#undef ureg + +/* EP5-EP7 are the only ones with 1024 byte FIFOs which BULK really needs */ +#define MUSB_BULK_EP 5 + +/* Blackfin FIFO's are static */ +#define MUSB_NO_DYNAMIC_FIFO + +/* No HUB support :( */ +#define MUSB_NO_MULTIPOINT + +#endif diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index cee7a11294..f0f0301bd1 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -38,6 +38,10 @@ #include #include +#ifdef CONFIG_USB_BLACKFIN +# include "blackfin_usb.h" +#endif + #define MUSB_EP0_FIFOSIZE 64 /* This is non-configurable */ /* EP0 */ @@ -71,6 +75,7 @@ struct musb_epN_regs { }; /* Mentor USB core register overlay structure */ +#ifndef musb_regs struct musb_regs { /* common registers */ u8 faddr; @@ -138,6 +143,7 @@ struct musb_regs { } ep[16]; } __attribute__((packed, aligned(32))); +#endif /* * MUSB Register bits @@ -347,4 +353,14 @@ extern void musb_configure_ep(struct musb_epinfo *epinfo, u8 cnt); extern void write_fifo(u8 ep, u32 length, void *fifo_data); extern void read_fifo(u8 ep, u32 length, void *fifo_data); +#if defined(CONFIG_USB_BLACKFIN) +/* Every USB register is accessed as a 16-bit even if the value itself + * is only 8-bits in size. Fun stuff. + */ +# undef readb +# define readb(addr) (u8)bfin_read16(addr) +# undef writeb +# define writeb(b, addr) bfin_write16(addr, b) +#endif + #endif /* __MUSB_HDRC_DEFS_H__ */ diff --git a/drivers/usb/musb/musb_hcd.h b/drivers/usb/musb/musb_hcd.h index 17e9091a0a..a437985dc8 100644 --- a/drivers/usb/musb/musb_hcd.h +++ b/drivers/usb/musb/musb_hcd.h @@ -38,7 +38,9 @@ extern unsigned char new[]; #define MUSB_CONTROL_EP 0 /* This defines the endpoint number used for bulk transfer */ -#define MUSB_BULK_EP 1 +#ifndef MUSB_BULK_EP +# define MUSB_BULK_EP 1 +#endif /* This defines the endpoint number used for interrupt transfer */ #define MUSB_INTR_EP 2 -- cgit v1.2.1 From b301be0599d14be46fc088861bb798648844aea5 Mon Sep 17 00:00:00 2001 From: Sanjeev Premi Date: Thu, 24 Dec 2009 14:20:41 +0530 Subject: omap3: fix compile warning This patch fixes this warning during compile: omap3.c: In function 'musb_platform_init': omap3.c:126: warning: label 'end' defined but not used Problem reported by: Dirk Behme[dirk.behme@googlemail.com] Signed-off-by: Sanjeev Premi --- drivers/usb/musb/omap3.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/musb/omap3.c b/drivers/usb/musb/omap3.c index ea98c3cac1..3bfd0a085f 100644 --- a/drivers/usb/musb/omap3.c +++ b/drivers/usb/musb/omap3.c @@ -123,7 +123,10 @@ int musb_platform_init(void) } ret = platform_needs_initialization; + +#ifdef CONFIG_TWL4030_USB end: +#endif return ret; } -- cgit v1.2.1 From b416191a14770c6bcc6fd67be7decf8159b2baee Mon Sep 17 00:00:00 2001 From: Chris Zhang Date: Wed, 6 Jan 2010 13:34:04 -0800 Subject: Fix EHCI port reset. In USB ehci driver, the port reset is not terminated. EHCI spec says "A host controller must terminate the reset and stabilize the state of the port within 2 milliseconds". Without termination, a port stays at reset state. This is observed on ppc4xx(sequoia) boards. Signed-off-by: Chris Zhang --- drivers/usb/host/ehci-hcd.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index ba85991e86..9ebeb4f23d 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -708,6 +708,9 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer, * root */ wait_ms(50); + /* terminate the reset */ + ehci_writel(status_reg, reg & ~EHCI_PS_PR); + wait_ms(2); portreset |= 1 << le16_to_cpu(req->index); } break; -- cgit v1.2.1 From 5f82887feecd7895593401f1ccda866bfb299fbb Mon Sep 17 00:00:00 2001 From: Chris Zhang Date: Wed, 6 Jan 2010 13:34:05 -0800 Subject: Add ppc440epx USB ehci support. Currently ppc440epx uses OHCI for USB full-speed support. This change adds support for EHCI. Signed-off-by: Chris Zhang --- drivers/usb/host/Makefile | 1 + drivers/usb/host/ehci-ppc4xx.c | 48 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 drivers/usb/host/ehci-ppc4xx.c (limited to 'drivers') diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 940d4a8b91..255679a186 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -36,6 +36,7 @@ COBJS-$(CONFIG_USB_SL811HS) += sl811-hcd.o # echi COBJS-$(CONFIG_USB_EHCI) += ehci-hcd.o COBJS-$(CONFIG_USB_EHCI_FSL) += ehci-fsl.o +COBJS-$(CONFIG_USB_EHCI_PPC4XX) += ehci-ppc4xx.o COBJS-$(CONFIG_USB_EHCI_IXP4XX) += ehci-ixp.o COBJS-$(CONFIG_USB_EHCI_KIRKWOOD) += ehci-kirkwood.o COBJS-$(CONFIG_USB_EHCI_PCI) += ehci-pci.o diff --git a/drivers/usb/host/ehci-ppc4xx.c b/drivers/usb/host/ehci-ppc4xx.c new file mode 100644 index 0000000000..946a0a07ef --- /dev/null +++ b/drivers/usb/host/ehci-ppc4xx.c @@ -0,0 +1,48 @@ +/* + * (C) Copyright 2010, Chris Zhang + * + * Author: Chris Zhang + * This code is based on ehci freescale driver + * + * 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 +#include + +#include "ehci.h" +#include "ehci-core.h" + +/* + * Create the appropriate control structures to manage + * a new EHCI host controller. + */ +int ehci_hcd_init(void) +{ + hccr = (struct ehci_hccr *)(CONFIG_SYS_PPC4XX_USB_ADDR); + hcor = (struct ehci_hcor *)((uint32_t) hccr + + HC_LENGTH(ehci_readl(&hccr->cr_capbase))); + usb_dev_init(); + return 0; +} + +/* + * Destroy the appropriate control structures corresponding + * the the EHCI host controller. + */ +int ehci_hcd_stop(void) +{ + return 0; +} -- cgit v1.2.1 From 321790f61bb92fead0fc01b8d055aa331d8dcf85 Mon Sep 17 00:00:00 2001 From: Bryan Wu Date: Sat, 9 Jan 2010 16:53:54 -0500 Subject: usb: musb: add virtual root hub control support For MUSB devices that do not support multipoint (hubs), we have to emulate a root hub so that we can support core operations like resetting ports. Signed-off-by: Bryan Wu Signed-off-by: Cliff Cai Signed-off-by: Mike Frysinger --- drivers/usb/musb/musb_hcd.c | 429 +++++++++++++++++++++++++++++++++++++++++++- drivers/usb/musb/musb_hcd.h | 55 ++++++ 2 files changed, 482 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/musb/musb_hcd.c b/drivers/usb/musb/musb_hcd.c index adb8c38527..dd2aa7f27c 100644 --- a/drivers/usb/musb/musb_hcd.c +++ b/drivers/usb/musb/musb_hcd.c @@ -35,6 +35,106 @@ static struct musb_epinfo epinfo[3] = { {MUSB_INTR_EP, 0, 64} /* EP2 - Interrupt IN - 64 Bytes */ }; +/* --- Virtual Root Hub ---------------------------------------------------- */ +#ifdef MUSB_NO_MULTIPOINT +static int rh_devnum; +static u32 port_status; + +/* Device descriptor */ +static u8 root_hub_dev_des[] = { + 0x12, /* __u8 bLength; */ + 0x01, /* __u8 bDescriptorType; Device */ + 0x00, /* __u16 bcdUSB; v1.1 */ + 0x02, + 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ + 0x00, /* __u8 bDeviceSubClass; */ + 0x00, /* __u8 bDeviceProtocol; */ + 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ + 0x00, /* __u16 idVendor; */ + 0x00, + 0x00, /* __u16 idProduct; */ + 0x00, + 0x00, /* __u16 bcdDevice; */ + 0x00, + 0x00, /* __u8 iManufacturer; */ + 0x01, /* __u8 iProduct; */ + 0x00, /* __u8 iSerialNumber; */ + 0x01 /* __u8 bNumConfigurations; */ +}; + +/* Configuration descriptor */ +static u8 root_hub_config_des[] = { + 0x09, /* __u8 bLength; */ + 0x02, /* __u8 bDescriptorType; Configuration */ + 0x19, /* __u16 wTotalLength; */ + 0x00, + 0x01, /* __u8 bNumInterfaces; */ + 0x01, /* __u8 bConfigurationValue; */ + 0x00, /* __u8 iConfiguration; */ + 0x40, /* __u8 bmAttributes; + Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */ + 0x00, /* __u8 MaxPower; */ + + /* interface */ + 0x09, /* __u8 if_bLength; */ + 0x04, /* __u8 if_bDescriptorType; Interface */ + 0x00, /* __u8 if_bInterfaceNumber; */ + 0x00, /* __u8 if_bAlternateSetting; */ + 0x01, /* __u8 if_bNumEndpoints; */ + 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */ + 0x00, /* __u8 if_bInterfaceSubClass; */ + 0x00, /* __u8 if_bInterfaceProtocol; */ + 0x00, /* __u8 if_iInterface; */ + + /* endpoint */ + 0x07, /* __u8 ep_bLength; */ + 0x05, /* __u8 ep_bDescriptorType; Endpoint */ + 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ + 0x03, /* __u8 ep_bmAttributes; Interrupt */ + 0x00, /* __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */ + 0x02, + 0xff /* __u8 ep_bInterval; 255 ms */ +}; + +static unsigned char root_hub_str_index0[] = { + 0x04, /* __u8 bLength; */ + 0x03, /* __u8 bDescriptorType; String-descriptor */ + 0x09, /* __u8 lang ID */ + 0x04, /* __u8 lang ID */ +}; + +static unsigned char root_hub_str_index1[] = { + 0x1c, /* __u8 bLength; */ + 0x03, /* __u8 bDescriptorType; String-descriptor */ + 'M', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'U', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'S', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'B', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + ' ', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'R', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'o', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'o', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 't', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + ' ', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'H', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'u', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'b', /* __u8 Unicode */ + 0, /* __u8 Unicode */ +}; +#endif + /* * This function writes the data toggle value. */ @@ -411,18 +511,341 @@ static void config_hub_port(struct usb_device *dev, u8 ep) #endif } +#ifdef MUSB_NO_MULTIPOINT + +static void musb_port_reset(int do_reset) +{ + u8 power = readb(&musbr->power); + + if (do_reset) { + power &= 0xf0; + writeb(power | MUSB_POWER_RESET, &musbr->power); + port_status |= USB_PORT_STAT_RESET; + port_status &= ~USB_PORT_STAT_ENABLE; + udelay(30000); + } else { + writeb(power & ~MUSB_POWER_RESET, &musbr->power); + + power = readb(&musbr->power); + if (power & MUSB_POWER_HSMODE) + port_status |= USB_PORT_STAT_HIGH_SPEED; + + port_status &= ~(USB_PORT_STAT_RESET | (USB_PORT_STAT_C_CONNECTION << 16)); + port_status |= USB_PORT_STAT_ENABLE + | (USB_PORT_STAT_C_RESET << 16) + | (USB_PORT_STAT_C_ENABLE << 16); + } +} + +/* + * root hub control + */ +static int musb_submit_rh_msg(struct usb_device *dev, unsigned long pipe, + void *buffer, int transfer_len, + struct devrequest *cmd) +{ + int leni = transfer_len; + int len = 0; + int stat = 0; + u32 datab[4]; + u8 *data_buf = (u8 *) datab; + u16 bmRType_bReq; + u16 wValue; + u16 wIndex; + u16 wLength; + u16 int_usb; + + if ((pipe & PIPE_INTERRUPT) == PIPE_INTERRUPT) { + debug("Root-Hub submit IRQ: NOT implemented\n"); + return 0; + } + + bmRType_bReq = cmd->requesttype | (cmd->request << 8); + wValue = swap_16(cmd->value); + wIndex = swap_16(cmd->index); + wLength = swap_16(cmd->length); + + debug("--- HUB ----------------------------------------\n"); + debug("submit rh urb, req=%x val=%#x index=%#x len=%d\n", + bmRType_bReq, wValue, wIndex, wLength); + debug("------------------------------------------------\n"); + + switch (bmRType_bReq) { + case RH_GET_STATUS: + debug("RH_GET_STATUS\n"); + + *(__u16 *) data_buf = swap_16(1); + len = 2; + break; + + case RH_GET_STATUS | RH_INTERFACE: + debug("RH_GET_STATUS | RH_INTERFACE\n"); + + *(__u16 *) data_buf = swap_16(0); + len = 2; + break; + + case RH_GET_STATUS | RH_ENDPOINT: + debug("RH_GET_STATUS | RH_ENDPOINT\n"); + + *(__u16 *) data_buf = swap_16(0); + len = 2; + break; + + case RH_GET_STATUS | RH_CLASS: + debug("RH_GET_STATUS | RH_CLASS\n"); + + *(__u32 *) data_buf = swap_32(0); + len = 4; + break; + + case RH_GET_STATUS | RH_OTHER | RH_CLASS: + debug("RH_GET_STATUS | RH_OTHER | RH_CLASS\n"); + + int_usb = readw(&musbr->intrusb); + if (int_usb & MUSB_INTR_CONNECT) { + port_status |= USB_PORT_STAT_CONNECTION + | (USB_PORT_STAT_C_CONNECTION << 16); + port_status |= USB_PORT_STAT_HIGH_SPEED + | USB_PORT_STAT_ENABLE; + } + + if (port_status & USB_PORT_STAT_RESET) + musb_port_reset(0); + + *(__u32 *) data_buf = swap_32(port_status); + len = 4; + break; + + case RH_CLEAR_FEATURE | RH_ENDPOINT: + debug("RH_CLEAR_FEATURE | RH_ENDPOINT\n"); + + switch (wValue) { + case RH_ENDPOINT_STALL: + debug("C_HUB_ENDPOINT_STALL\n"); + len = 0; + break; + } + port_status &= ~(1 << wValue); + break; + + case RH_CLEAR_FEATURE | RH_CLASS: + debug("RH_CLEAR_FEATURE | RH_CLASS\n"); + + switch (wValue) { + case RH_C_HUB_LOCAL_POWER: + debug("C_HUB_LOCAL_POWER\n"); + len = 0; + break; + + case RH_C_HUB_OVER_CURRENT: + debug("C_HUB_OVER_CURRENT\n"); + len = 0; + break; + } + port_status &= ~(1 << wValue); + break; + + case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS: + debug("RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS\n"); + + switch (wValue) { + case RH_PORT_ENABLE: + len = 0; + break; + + case RH_PORT_SUSPEND: + len = 0; + break; + + case RH_PORT_POWER: + len = 0; + break; + + case RH_C_PORT_CONNECTION: + len = 0; + break; + + case RH_C_PORT_ENABLE: + len = 0; + break; + + case RH_C_PORT_SUSPEND: + len = 0; + break; + + case RH_C_PORT_OVER_CURRENT: + len = 0; + break; + + case RH_C_PORT_RESET: + len = 0; + break; + + default: + debug("invalid wValue\n"); + stat = USB_ST_STALLED; + } + + port_status &= ~(1 << wValue); + break; + + case RH_SET_FEATURE | RH_OTHER | RH_CLASS: + debug("RH_SET_FEATURE | RH_OTHER | RH_CLASS\n"); + + switch (wValue) { + case RH_PORT_SUSPEND: + len = 0; + break; + + case RH_PORT_RESET: + musb_port_reset(1); + len = 0; + break; + + case RH_PORT_POWER: + len = 0; + break; + + case RH_PORT_ENABLE: + len = 0; + break; + + default: + debug("invalid wValue\n"); + stat = USB_ST_STALLED; + } + + port_status |= 1 << wValue; + break; + + case RH_SET_ADDRESS: + debug("RH_SET_ADDRESS\n"); + + rh_devnum = wValue; + len = 0; + break; + + case RH_GET_DESCRIPTOR: + debug("RH_GET_DESCRIPTOR: %x, %d\n", wValue, wLength); + + switch (wValue) { + case (USB_DT_DEVICE << 8): /* device descriptor */ + len = min_t(unsigned int, + leni, min_t(unsigned int, + sizeof(root_hub_dev_des), + wLength)); + data_buf = root_hub_dev_des; + break; + + case (USB_DT_CONFIG << 8): /* configuration descriptor */ + len = min_t(unsigned int, + leni, min_t(unsigned int, + sizeof(root_hub_config_des), + wLength)); + data_buf = root_hub_config_des; + break; + + case ((USB_DT_STRING << 8) | 0x00): /* string 0 descriptors */ + len = min_t(unsigned int, + leni, min_t(unsigned int, + sizeof(root_hub_str_index0), + wLength)); + data_buf = root_hub_str_index0; + break; + + case ((USB_DT_STRING << 8) | 0x01): /* string 1 descriptors */ + len = min_t(unsigned int, + leni, min_t(unsigned int, + sizeof(root_hub_str_index1), + wLength)); + data_buf = root_hub_str_index1; + break; + + default: + debug("invalid wValue\n"); + stat = USB_ST_STALLED; + } + + break; + + case RH_GET_DESCRIPTOR | RH_CLASS: + debug("RH_GET_DESCRIPTOR | RH_CLASS\n"); + + data_buf[0] = 0x09; /* min length; */ + data_buf[1] = 0x29; + data_buf[2] = 0x1; /* 1 port */ + data_buf[3] = 0x01; /* per-port power switching */ + data_buf[3] |= 0x10; /* no overcurrent reporting */ + + /* Corresponds to data_buf[4-7] */ + data_buf[4] = 0; + data_buf[5] = 5; + data_buf[6] = 0; + data_buf[7] = 0x02; + data_buf[8] = 0xff; + + len = min_t(unsigned int, leni, + min_t(unsigned int, data_buf[0], wLength)); + break; + + case RH_GET_CONFIGURATION: + debug("RH_GET_CONFIGURATION\n"); + + *(__u8 *) data_buf = 0x01; + len = 1; + break; + + case RH_SET_CONFIGURATION: + debug("RH_SET_CONFIGURATION\n"); + + len = 0; + break; + + default: + debug("*** *** *** unsupported root hub command *** *** ***\n"); + stat = USB_ST_STALLED; + } + + len = min_t(int, len, leni); + if (buffer != data_buf) + memcpy(buffer, data_buf, len); + + dev->act_len = len; + dev->status = stat; + debug("dev act_len %d, status %d\n", dev->act_len, dev->status); + + return stat; +} + +static void musb_rh_init(void) +{ + rh_devnum = 0; + port_status = 0; +} + +#else + +static void musb_rh_init(void) {} + +#endif + /* * do a control transfer */ int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, int len, struct devrequest *setup) { -#ifndef MUSB_NO_MULTIPOINT int devnum = usb_pipedevice(pipe); -#endif u16 csr; u8 devspeed; +#ifdef MUSB_NO_MULTIPOINT + /* Control message is for the HUB? */ + if (devnum == rh_devnum) + return musb_submit_rh_msg(dev, pipe, buffer, len, setup); +#endif + /* select control endpoint */ writeb(MUSB_CONTROL_EP, &musbr->index); csr = readw(&musbr->txcsr); @@ -649,6 +1072,8 @@ int usb_lowlevel_init(void) u8 power; u32 timeout; + musb_rh_init(); + if (musb_platform_init() == -1) return -1; diff --git a/drivers/usb/musb/musb_hcd.h b/drivers/usb/musb/musb_hcd.h index a437985dc8..dde7d37722 100644 --- a/drivers/usb/musb/musb_hcd.h +++ b/drivers/usb/musb/musb_hcd.h @@ -50,6 +50,61 @@ extern unsigned char new[]; ((readb(&musbr->power) & MUSB_POWER_HSMODE) \ >> MUSB_POWER_HSMODE_SHIFT) +#define min_t(type, x, y) \ + ({ type __x = (x); type __y = (y); __x < __y ? __x : __y; }) + +/* USB HUB CONSTANTS (not OHCI-specific; see hub.h) */ + +/* destination of request */ +#define RH_INTERFACE 0x01 +#define RH_ENDPOINT 0x02 +#define RH_OTHER 0x03 + +#define RH_CLASS 0x20 +#define RH_VENDOR 0x40 + +/* Requests: bRequest << 8 | bmRequestType */ +#define RH_GET_STATUS 0x0080 +#define RH_CLEAR_FEATURE 0x0100 +#define RH_SET_FEATURE 0x0300 +#define RH_SET_ADDRESS 0x0500 +#define RH_GET_DESCRIPTOR 0x0680 +#define RH_SET_DESCRIPTOR 0x0700 +#define RH_GET_CONFIGURATION 0x0880 +#define RH_SET_CONFIGURATION 0x0900 +#define RH_GET_STATE 0x0280 +#define RH_GET_INTERFACE 0x0A80 +#define RH_SET_INTERFACE 0x0B00 +#define RH_SYNC_FRAME 0x0C80 +/* Our Vendor Specific Request */ +#define RH_SET_EP 0x2000 + +/* Hub port features */ +#define RH_PORT_CONNECTION 0x00 +#define RH_PORT_ENABLE 0x01 +#define RH_PORT_SUSPEND 0x02 +#define RH_PORT_OVER_CURRENT 0x03 +#define RH_PORT_RESET 0x04 +#define RH_PORT_POWER 0x08 +#define RH_PORT_LOW_SPEED 0x09 + +#define RH_C_PORT_CONNECTION 0x10 +#define RH_C_PORT_ENABLE 0x11 +#define RH_C_PORT_SUSPEND 0x12 +#define RH_C_PORT_OVER_CURRENT 0x13 +#define RH_C_PORT_RESET 0x14 + +/* Hub features */ +#define RH_C_HUB_LOCAL_POWER 0x00 +#define RH_C_HUB_OVER_CURRENT 0x01 + +#define RH_DEVICE_REMOTE_WAKEUP 0x00 +#define RH_ENDPOINT_STALL 0x01 + +#define RH_ACK 0x01 +#define RH_REQ_ERR -1 +#define RH_NACK 0x00 + /* extern functions */ extern int musb_platform_init(void); extern void musb_platform_deinit(void); -- cgit v1.2.1