Browse Source

Merge branch 'master' of git://git.denx.de/u-boot-usb

* 'master' of git://git.denx.de/u-boot-usb:
  USB: efikamx: Enable USB on EfikaMX and EfikaSB
  USB: Add generic ULPI layer and a viewport
  USB: EHCI: Allow EHCI post-powerup configuration in board files
  USB: mx51evk: add end enable USB host support on port 1
  USB: mx53loco: add end enable USB host support on port 1
  USB: MX5: Add MX5 usb post-init callback
  USB: MX5: Abstract out mx51 USB pixmux configuration
  USB: MX5: add generic USB EHCI support for mx51 and mx53
  USB: MX5: add helper functions to enable USB clocks
  usb:gadget:s5p Enable the USB Gadget framework at GONI
  usb:gadget:s5p USB Device Controller (UDC) implementation
  ehci: speed up initialization
  usb: add help for missing start subcommand
  cosmetic: remove excess whitespace from usb command help
  usb: align usb_endpoint_descriptor to 16-bit boundary
  usbtty: init endpoints prior to startup events
  pxa: convert pxa27x_udc to use read and write functions
  pxa: activate the first usb host port on pxa27x by default
  pxa: fix usb host register mismatch
  ehci-fsl: correct size of ehci caplength
  USB: Add usb_event_poll() to get keyboards working with EHCI
  USB: gadaget: add Marvell controller support
  USB: Fix complaints about strict aliasing in OHCI-HCD
  USB: Drop dead code from usb_kbd.c
  USB: Rework usb_kbd.c
  USB: Add functionality to poll the USB keyboard via control EP
Wolfgang Denk 13 năm trước cách đây
mục cha
commit
b2eb7d9bc6
40 tập tin đã thay đổi với 5512 bổ sung759 xóa
  1. 1 0
      Makefile
  2. 72 0
      arch/arm/cpu/armv7/mx5/clock.c
  3. 3 3
      arch/arm/cpu/pxa/usb.c
  4. 5 0
      arch/arm/include/asm/arch-mx5/clock.h
  5. 3 0
      arch/arm/include/asm/arch-mx5/crm_regs.h
  6. 6 4
      arch/arm/include/asm/arch-pxa/pxa-regs.h
  7. 4 0
      arch/arm/include/asm/arch-s5pc1xx/cpu.h
  8. 4 0
      board/efikamx/Makefile
  9. 210 0
      board/efikamx/efikamx-usb.c
  10. 15 0
      board/efikamx/efikamx.c
  11. 62 0
      board/freescale/mx51evk/mx51evk.c
  12. 10 0
      board/freescale/mx53loco/mx53loco.c
  13. 47 1
      board/samsung/goni/goni.c
  14. 9 7
      common/cmd_usb.c
  15. 324 604
      common/usb_kbd.c
  16. 2 2
      drivers/serial/usbtty.c
  17. 5 0
      drivers/usb/gadget/Makefile
  18. 7 0
      drivers/usb/gadget/gadget_chips.h
  19. 499 0
      drivers/usb/gadget/mv_udc.c
  20. 100 83
      drivers/usb/gadget/pxa27x_udc.c
  21. 271 0
      drivers/usb/gadget/regs-otg.h
  22. 892 0
      drivers/usb/gadget/s3c_udc_otg.c
  23. 1444 0
      drivers/usb/gadget/s3c_udc_otg_xfer_dma.c
  24. 1 0
      drivers/usb/host/Makefile
  25. 43 4
      drivers/usb/host/ehci-hcd.c
  26. 255 0
      drivers/usb/host/ehci-mx5.c
  27. 43 32
      drivers/usb/host/ohci-hcd.c
  28. 44 0
      drivers/usb/ulpi/Makefile
  29. 118 0
      drivers/usb/ulpi/ulpi-viewport.c
  30. 227 0
      drivers/usb/ulpi/ulpi.c
  31. 41 6
      include/configs/efikamx.h
  32. 13 0
      include/configs/mx51evk.h
  33. 13 0
      include/configs/mx53loco.h
  34. 3 0
      include/configs/s5p_goni.h
  35. 29 12
      include/usb/ehci-fsl.h
  36. 62 0
      include/usb/lin_gadget_compat.h
  37. 151 0
      include/usb/mv_udc.h
  38. 175 0
      include/usb/s3c_udc.h
  39. 298 0
      include/usb/ulpi.h
  40. 1 1
      include/usbdescriptors.h

+ 1 - 0
Makefile

@@ -286,6 +286,7 @@ LIBS += drivers/usb/gadget/libusb_gadget.o
 LIBS += drivers/usb/host/libusb_host.o
 LIBS += drivers/usb/musb/libusb_musb.o
 LIBS += drivers/usb/phy/libusb_phy.o
+LIBS += drivers/usb/ulpi/libusb_ulpi.o
 LIBS += drivers/video/libvideo.o
 LIBS += drivers/watchdog/libwatchdog.o
 LIBS += common/libcommon.o

+ 72 - 0
arch/arm/cpu/armv7/mx5/clock.c

@@ -50,6 +50,78 @@ struct mxc_pll_reg *mxc_plls[PLL_CLOCKS] = {
 
 struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)MXC_CCM_BASE;
 
+void set_usboh3_clk(void)
+{
+	unsigned int reg;
+
+	reg = readl(&mxc_ccm->cscmr1) &
+		 ~MXC_CCM_CSCMR1_USBOH3_CLK_SEL_MASK;
+	reg |= 1 << MXC_CCM_CSCMR1_USBOH3_CLK_SEL_OFFSET;
+	writel(reg, &mxc_ccm->cscmr1);
+
+	reg = readl(&mxc_ccm->cscdr1);
+	reg &= ~MXC_CCM_CSCDR1_USBOH3_CLK_PODF_MASK;
+	reg &= ~MXC_CCM_CSCDR1_USBOH3_CLK_PRED_MASK;
+	reg |= 4 << MXC_CCM_CSCDR1_USBOH3_CLK_PRED_OFFSET;
+	reg |= 1 << MXC_CCM_CSCDR1_USBOH3_CLK_PODF_OFFSET;
+
+	writel(reg, &mxc_ccm->cscdr1);
+}
+
+void enable_usboh3_clk(unsigned char enable)
+{
+	unsigned int reg;
+
+	reg = readl(&mxc_ccm->CCGR2);
+	if (enable)
+		reg |= 1 << MXC_CCM_CCGR2_CG14_OFFSET;
+	else
+		reg &= ~(1 << MXC_CCM_CCGR2_CG14_OFFSET);
+	writel(reg, &mxc_ccm->CCGR2);
+}
+
+void set_usb_phy1_clk(void)
+{
+	unsigned int reg;
+
+	reg = readl(&mxc_ccm->cscmr1);
+	reg &= ~MXC_CCM_CSCMR1_USB_PHY_CLK_SEL;
+	writel(reg, &mxc_ccm->cscmr1);
+}
+
+void enable_usb_phy1_clk(unsigned char enable)
+{
+	unsigned int reg;
+
+	reg = readl(&mxc_ccm->CCGR4);
+	if (enable)
+		reg |= 1 << MXC_CCM_CCGR4_CG5_OFFSET;
+	else
+		reg &= ~(1 << MXC_CCM_CCGR4_CG5_OFFSET);
+	writel(reg, &mxc_ccm->CCGR4);
+}
+
+void set_usb_phy2_clk(void)
+{
+	unsigned int reg;
+
+	reg = readl(&mxc_ccm->cscmr1);
+	reg &= ~MXC_CCM_CSCMR1_USB_PHY_CLK_SEL;
+	writel(reg, &mxc_ccm->cscmr1);
+}
+
+void enable_usb_phy2_clk(unsigned char enable)
+{
+	unsigned int reg;
+
+	reg = readl(&mxc_ccm->CCGR4);
+	if (enable)
+		reg |= 1 << MXC_CCM_CCGR4_CG6_OFFSET;
+	else
+		reg &= ~(1 << MXC_CCM_CCGR4_CG6_OFFSET);
+	writel(reg, &mxc_ccm->CCGR4);
+}
+
 /*
  * Calculate the frequency of PLLn.
  */

+ 3 - 3
arch/arm/cpu/pxa/usb.c

@@ -55,7 +55,7 @@ int usb_cpu_init(void)
 	while (readl(UHCHR) & UHCHR_FSBIR)
 		udelay(1);
 
-#if defined(CONFIG_CPU_MONAHANS)
+#if defined(CONFIG_CPU_MONAHANS) || defined(CONFIG_PXA27X)
 	writel(readl(UHCHR) & ~UHCHR_SSEP0, UHCHR);
 #endif
 #if defined(CONFIG_CPU_PXA27X)
@@ -72,10 +72,10 @@ int usb_cpu_stop(void)
 	udelay(11);
 	writel(readl(UHCHR) & ~UHCHR_FHR, UHCHR);
 
-	writel(readl(UHCCOMS) | UHCHR_FHR, UHCCOMS);
+	writel(readl(UHCCOMS) | UHCCOMS_HCR, UHCCOMS);
 	udelay(10);
 
-#if defined(CONFIG_CPU_MONAHANS)
+#if defined(CONFIG_CPU_MONAHANS) || defined(CONFIG_PXA27X)
 	writel(readl(UHCHR) | UHCHR_SSEP0, UHCHR);
 #endif
 #if defined(CONFIG_CPU_PXA27X)

+ 5 - 0
arch/arm/include/asm/arch-mx5/clock.h

@@ -40,4 +40,9 @@ u32 imx_get_uartclk(void);
 u32 imx_get_fecclk(void);
 unsigned int mxc_get_clock(enum mxc_clock clk);
 
+void set_usb_phy2_clk(void);
+void enable_usb_phy2_clk(unsigned char enable);
+void set_usboh3_clk(void);
+void enable_usboh3_clk(unsigned char enable);
+
 #endif /* __ASM_ARCH_CLOCK_H */

+ 3 - 0
arch/arm/include/asm/arch-mx5/crm_regs.h

@@ -195,7 +195,10 @@ struct mxc_ccm_reg {
 /* Define the bits in register CCGRx */
 #define MXC_CCM_CCGR_CG_MASK				0x3
 
+#define MXC_CCM_CCGR4_CG5_OFFSET			10
+#define MXC_CCM_CCGR4_CG6_OFFSET			12
 #define MXC_CCM_CCGR5_CG5_OFFSET			10
+#define MXC_CCM_CCGR2_CG14_OFFSET			28
 
 /* Define the bits in register CLPCR */
 #define MXC_CCM_CLPCR_BYPASS_IPU_LPM_HS                 (0x1 << 18)

+ 6 - 4
arch/arm/include/asm/arch-pxa/pxa-regs.h

@@ -645,7 +645,7 @@ typedef void		(*ExcpHndlr) (void) ;
 #define UDCOTGICR_IEIDR		(1 << 1)	/* OTG ID Change Rising Edge Interrupt Enable */
 #define UDCOTGICR_IEIDF		(1 << 0)	/* OTG ID Change Falling Edge Interrupt Enable */
 
-#define UDCCSN(x)	__REG2(0x40600100, (x) << 2)
+#define UDCCSN(x)	(0x40600100 + ((x) << 2))
 #define UDCCSR0		0x40600100 /* UDC Control/Status register - Endpoint 0 */
 
 #define UDCCSR0_SA	(1 << 7)	/* Setup Active */
@@ -693,7 +693,7 @@ typedef void		(*ExcpHndlr) (void) ;
 #define UDCCSR_PC	(1 << 1)	/* Packet Complete */
 #define UDCCSR_FS	(1 << 0)	/* FIFO needs service */
 
-#define UDCBCN(x)	__REG2(0x40600200, (x)<<2)
+#define UDCBCN(x)	(0x40600200 + ((x) << 2))
 #define UDCBCR0         0x40600200 /* Byte Count Register - EP0 */
 #define UDCBCRA         0x40600204 /* Byte Count Register - EPA */
 #define UDCBCRB         0x40600208 /* Byte Count Register - EPB */
@@ -719,7 +719,7 @@ typedef void		(*ExcpHndlr) (void) ;
 #define UDCBCRW         0x40600258 /* Byte Count Register - EPW */
 #define UDCBCRX         0x4060025C /* Byte Count Register - EPX */
 
-#define UDCDN(x)	__REG2(0x40600300, (x)<<2)
+#define UDCDN(x)	(0x40600300 + ((x) << 2))
 #define UDCDR0          0x40600300 /* Data Register - EP0 */
 #define UDCDRA          0x40600304 /* Data Register - EPA */
 #define UDCDRB          0x40600308 /* Data Register - EPB */
@@ -745,7 +745,7 @@ typedef void		(*ExcpHndlr) (void) ;
 #define UDCDRW          0x40600358 /* Data Register - EPW */
 #define UDCDRX          0x4060035C /* Data Register - EPX */
 
-#define UDCCN(x)	__REG2(0x40600400, (x)<<2)
+#define UDCCN(x)	(0x40600400 + ((x) << 2))
 #define UDCCRA          0x40600404 /* Configuration register EPA */
 #define UDCCRB          0x40600408 /* Configuration register EPB */
 #define UDCCRC          0x4060040C /* Configuration register EPC */
@@ -835,6 +835,8 @@ typedef void		(*ExcpHndlr) (void) ;
 #define UHCHIE		0x4C000068
 #define UHCHIT		0x4C00006C
 
+#define UHCCOMS_HCR	(1<<0)
+
 #define UHCHR_FSBIR	(1<<0)
 #define UHCHR_FHR	(1<<1)
 #define UHCHR_CGR	(1<<2)

+ 4 - 0
arch/arm/include/asm/arch-s5pc1xx/cpu.h

@@ -55,6 +55,10 @@
 #define S5PC110_VIC1_BASE	0xF2100000
 #define S5PC110_VIC2_BASE	0xF2200000
 #define S5PC110_VIC3_BASE	0xF2300000
+#define S5PC110_OTG_BASE	0xEC000000
+#define S5PC110_PHY_BASE	0xEC100000
+#define S5PC110_USB_PHY_CONTROL 0xE010E80C
+
 
 #ifndef __ASSEMBLY__
 #include <asm/io.h>

+ 4 - 0
board/efikamx/Makefile

@@ -29,6 +29,10 @@ LIB	= $(obj)lib$(BOARD).o
 
 COBJS	:= efikamx.o
 
+ifdef	CONFIG_CMD_USB
+COBJS	+= efikamx-usb.o
+endif
+
 SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
 OBJS	:= $(addprefix $(obj),$(COBJS))
 SOBJS	:= $(addprefix $(obj),$(SOBJS))

+ 210 - 0
board/efikamx/efikamx-usb.c

@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2010 Marek Vasut <marek.vasut@gmail.com>
+ *
+ * (C) Copyright 2009 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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 <common.h>
+#include <usb.h>
+#include <asm/io.h>
+#include <asm/arch/imx-regs.h>
+#include <asm/arch/mx5x_pins.h>
+#include <asm/arch/iomux.h>
+#include <asm/gpio.h>
+#include <usb/ehci-fsl.h>
+#include <usb/ulpi.h>
+#include <errno.h>
+
+#include "../../drivers/usb/host/ehci.h"
+
+/* USB pin configuration */
+#define USB_PAD_CONFIG	(PAD_CTL_PKE_ENABLE | PAD_CTL_SRE_FAST | \
+			PAD_CTL_DRV_HIGH | PAD_CTL_100K_PU | \
+			PAD_CTL_HYS_ENABLE | PAD_CTL_PUE_PULL)
+
+/*
+ * Configure the USB H1 and USB H2 IOMUX
+ */
+void setup_iomux_usb(void)
+{
+	setup_iomux_usb_h1();
+
+	if (machine_is_efikasb())
+		setup_iomux_usb_h2();
+
+	/* USB PHY reset */
+	mxc_request_iomux(MX51_PIN_EIM_D27, IOMUX_CONFIG_ALT1);
+	mxc_iomux_set_pad(MX51_PIN_EIM_D27, PAD_CTL_PKE_ENABLE |
+			PAD_CTL_SRE_FAST | PAD_CTL_DRV_HIGH);
+
+	/* USB HUB reset */
+	mxc_request_iomux(MX51_PIN_GPIO1_5, IOMUX_CONFIG_ALT0);
+	mxc_iomux_set_pad(MX51_PIN_GPIO1_5, PAD_CTL_PKE_ENABLE |
+			PAD_CTL_SRE_FAST | PAD_CTL_DRV_HIGH);
+
+	/* WIFI EN (act low) */
+	mxc_request_iomux(MX51_PIN_EIM_A22, IOMUX_CONFIG_GPIO);
+	mxc_iomux_set_pad(MX51_PIN_EIM_A22, 0);
+	/* WIFI RESET */
+	mxc_request_iomux(MX51_PIN_EIM_A16, IOMUX_CONFIG_GPIO);
+	mxc_iomux_set_pad(MX51_PIN_EIM_A16, 0);
+	/* BT EN (act low) */
+	mxc_request_iomux(MX51_PIN_EIM_A17, IOMUX_CONFIG_GPIO);
+	mxc_iomux_set_pad(MX51_PIN_EIM_A17, 0);
+}
+
+/*
+ * Enable devices connected to USB BUSes
+ */
+static void efika_usb_enable_devices(void)
+{
+	/* Enable Bluetooth */
+	gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_EIM_A17), 0);
+	udelay(10000);
+	gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_EIM_A17), 1);
+
+	/* Enable WiFi */
+	gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_EIM_A22), 1);
+	udelay(10000);
+
+	/* Reset the WiFi chip */
+	gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_EIM_A16), 0);
+	udelay(10000);
+	gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_EIM_A16), 1);
+}
+
+/*
+ * Reset USB HUB (or HUBs on EfikaSB)
+ */
+static void efika_usb_hub_reset(void)
+{
+	/* HUB reset */
+	gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_GPIO1_5), 1);
+	udelay(1000);
+	gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_GPIO1_5), 0);
+	udelay(1000);
+	gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_GPIO1_5), 1);
+}
+
+/*
+ * Reset USB PHY (or PHYs on EfikaSB)
+ */
+static void efika_usb_phy_reset(void)
+{
+	/* SMSC 3317 PHY reset */
+	gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_EIM_D27), 0);
+	udelay(1000);
+	gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_EIM_D27), 1);
+}
+
+static void efika_ehci_init(struct usb_ehci *ehci, uint32_t stp_gpio,
+				uint32_t alt0, uint32_t alt1)
+{
+	int ret;
+	struct ulpi_regs *ulpi = (struct ulpi_regs *)0;
+
+	mxc_request_iomux(stp_gpio, alt0);
+	mxc_iomux_set_pad(stp_gpio, PAD_CTL_DRV_HIGH |
+				PAD_CTL_PKE_ENABLE | PAD_CTL_SRE_FAST);
+	gpio_direction_output(IOMUX_TO_GPIO(stp_gpio), 0);
+	udelay(1000);
+	gpio_set_value(IOMUX_TO_GPIO(stp_gpio), 1);
+	udelay(1000);
+
+	mxc_request_iomux(stp_gpio, alt1);
+	mxc_iomux_set_pad(stp_gpio, USB_PAD_CONFIG);
+	udelay(10000);
+
+	ret = ulpi_init((u32)&ehci->ulpi_viewpoint);
+	if (ret) {
+		printf("Efika USB ULPI initialization failed\n");
+		return;
+	}
+
+	/* ULPI set flags */
+	ulpi_write((u32)&ehci->ulpi_viewpoint, &ulpi->otg_ctrl,
+			ULPI_OTG_DP_PULLDOWN | ULPI_OTG_DM_PULLDOWN |
+			ULPI_OTG_EXTVBUSIND);
+	ulpi_write((u32)&ehci->ulpi_viewpoint, &ulpi->function_ctrl,
+			ULPI_FC_FULL_SPEED | ULPI_FC_OPMODE_NORMAL |
+			ULPI_FC_SUSPENDM);
+	ulpi_write((u32)&ehci->ulpi_viewpoint, &ulpi->iface_ctrl, 0);
+
+	/* Set VBus */
+	ulpi_write((u32)&ehci->ulpi_viewpoint, &ulpi->otg_ctrl_set,
+			ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT);
+
+	/*
+	 * Set VBusChrg
+	 *
+	 * NOTE: This violates USB specification, but otherwise, USB on Efika
+	 * doesn't work.
+	 */
+	ulpi_write((u32)&ehci->ulpi_viewpoint, &ulpi->otg_ctrl_set,
+			ULPI_OTG_CHRGVBUS);
+}
+
+int board_ehci_hcd_init(int port)
+{
+	/* Init iMX51 EHCI */
+	efika_usb_phy_reset();
+	efika_usb_hub_reset();
+	efika_usb_enable_devices();
+
+	return 0;
+}
+
+void ehci_powerup_fixup(uint32_t *status_reg, uint32_t *reg)
+{
+	uint32_t port = OTG_BASE_ADDR + (0x200 * CONFIG_MXC_USB_PORT);
+	struct usb_ehci *ehci = (struct usb_ehci *)port;
+	struct ulpi_regs *ulpi = (struct ulpi_regs *)0;
+
+	ulpi_write((u32)&ehci->ulpi_viewpoint, &ulpi->otg_ctrl_set,
+			ULPI_OTG_CHRGVBUS);
+
+	wait_ms(50);
+
+	/* terminate the reset */
+	*reg = ehci_readl(status_reg);
+	*reg |= EHCI_PS_PE;
+}
+
+void board_ehci_hcd_postinit(struct usb_ehci *ehci, int port)
+{
+	uint32_t tmp;
+
+	if (port == 0) {
+		/* Adjust UTMI PHY frequency to 24MHz */
+		tmp = readl(OTG_BASE_ADDR + 0x80c);
+		tmp = (tmp & ~0x3) | 0x01;
+		writel(tmp, OTG_BASE_ADDR + 0x80c);
+	} else if (port == 1) {
+		efika_ehci_init(ehci, MX51_PIN_USBH1_STP,
+				IOMUX_CONFIG_ALT2, IOMUX_CONFIG_ALT0);
+	} else if ((port == 2) && machine_is_efikasb()) {
+		efika_ehci_init(ehci, MX51_PIN_EIM_A26,
+				IOMUX_CONFIG_ALT1, IOMUX_CONFIG_ALT2);
+	}
+
+	if (port)
+		mdelay(10);
+}

+ 15 - 0
board/efikamx/efikamx.c

@@ -539,6 +539,15 @@ void setup_iomux_ata(void)
 static inline void setup_iomux_ata(void) { }
 #endif
 
+/*
+ * EHCI USB
+ */
+#ifdef	CONFIG_CMD_USB
+extern void setup_iomux_usb(void);
+#else
+static inline void setup_iomux_usb(void) { }
+#endif
+
 /*
  * LED configuration
  */
@@ -688,6 +697,12 @@ int board_late_init(void)
 
 	setup_iomux_led();
 	setup_iomux_ata();
+	setup_iomux_usb();
+
+	if (machine_is_efikasb())
+		setenv("preboot", "usb reset ; setenv stdin usbkbd\0");
+
+	setup_iomux_led();
 
 	efikamx_toggle_led(EFIKAMX_LED_BLUE);
 

+ 62 - 0
board/freescale/mx51evk/mx51evk.c

@@ -35,6 +35,7 @@
 #include <pmic.h>
 #include <fsl_pmic.h>
 #include <mc13892.h>
+#include <usb/ehci-fsl.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -172,6 +173,64 @@ static void setup_iomux_spi(void)
 }
 #endif
 
+#ifdef CONFIG_USB_EHCI_MX5
+#define MX51EVK_USBH1_HUB_RST	IOMUX_TO_GPIO(MX51_PIN_GPIO1_7) /* GPIO1_7 */
+#define MX51EVK_USBH1_STP	IOMUX_TO_GPIO(MX51_PIN_USBH1_STP) /* GPIO1_27 */
+#define MX51EVK_USB_CLK_EN_B	IOMUX_TO_GPIO(MX51_PIN_EIM_D18) /* GPIO2_1 */
+#define MX51EVK_USB_PHY_RESET	IOMUX_TO_GPIO(MX51_PIN_EIM_D21) /* GPIO2_5 */
+
+#define USBH1_PAD	(PAD_CTL_SRE_FAST | PAD_CTL_DRV_HIGH |		\
+			 PAD_CTL_100K_PU | PAD_CTL_PUE_PULL |		\
+			 PAD_CTL_PKE_ENABLE | PAD_CTL_HYS_ENABLE)
+#define GPIO_PAD	(PAD_CTL_DRV_HIGH | PAD_CTL_PKE_ENABLE |	\
+			 PAD_CTL_SRE_FAST)
+#define NO_PAD		(1 << 16)
+
+static void setup_usb_h1(void)
+{
+	setup_iomux_usb_h1();
+
+	/* GPIO_1_7 for USBH1 hub reset */
+	mxc_request_iomux(MX51_PIN_GPIO1_7, IOMUX_CONFIG_ALT0);
+	mxc_iomux_set_pad(MX51_PIN_GPIO1_7, NO_PAD);
+
+	/* GPIO_2_1 */
+	mxc_request_iomux(MX51_PIN_EIM_D17, IOMUX_CONFIG_ALT1);
+	mxc_iomux_set_pad(MX51_PIN_EIM_D17, GPIO_PAD);
+
+	/* GPIO_2_5 for USB PHY reset */
+	mxc_request_iomux(MX51_PIN_EIM_D21, IOMUX_CONFIG_ALT1);
+	mxc_iomux_set_pad(MX51_PIN_EIM_D21, GPIO_PAD);
+}
+
+void board_ehci_hcd_init(int port)
+{
+	/* Set USBH1_STP to GPIO and toggle it */
+	mxc_request_iomux(MX51_PIN_USBH1_STP, IOMUX_CONFIG_GPIO);
+	mxc_iomux_set_pad(MX51_PIN_USBH1_STP, USBH1_PAD);
+
+	gpio_direction_output(MX51EVK_USBH1_STP, 0);
+	gpio_direction_output(MX51EVK_USB_PHY_RESET, 0);
+	mdelay(10);
+	gpio_set_value(MX51EVK_USBH1_STP, 1);
+
+	/* Set back USBH1_STP to be function */
+	mxc_request_iomux(MX51_PIN_USBH1_STP, IOMUX_CONFIG_ALT0);
+	mxc_iomux_set_pad(MX51_PIN_USBH1_STP, USBH1_PAD);
+
+	/* De-assert USB PHY RESETB */
+	gpio_set_value(MX51EVK_USB_PHY_RESET, 1);
+
+	/* Drive USB_CLK_EN_B line low */
+	gpio_direction_output(MX51EVK_USB_CLK_EN_B, 0);
+
+	/* Reset USB hub */
+	gpio_direction_output(MX51EVK_USBH1_HUB_RST, 0);
+	mdelay(2);
+	gpio_set_value(MX51EVK_USBH1_HUB_RST, 1);
+}
+#endif
+
 static void power_init(void)
 {
 	unsigned int val;
@@ -394,6 +453,9 @@ int board_early_init_f(void)
 {
 	setup_iomux_uart();
 	setup_iomux_fec();
+#ifdef CONFIG_USB_EHCI_MX5
+	setup_usb_h1();
+#endif
 
 	return 0;
 }

+ 10 - 0
board/freescale/mx53loco/mx53loco.c

@@ -78,6 +78,16 @@ static void setup_iomux_uart(void)
 				PAD_CTL_ODE_OPENDRAIN_ENABLE);
 }
 
+#ifdef CONFIG_USB_EHCI_MX5
+void board_ehci_hcd_init(int port)
+{
+	/* request VBUS power enable pin, GPIO[8}, gpio7 */
+	mxc_request_iomux(MX53_PIN_ATA_DA_2, IOMUX_CONFIG_ALT1);
+	gpio_direction_output(IOMUX_TO_GPIO(MX53_PIN_ATA_DA_2), 0);
+	gpio_set_value(IOMUX_TO_GPIO(MX53_PIN_ATA_DA_2), 1);
+}
+#endif
+
 static void setup_iomux_fec(void)
 {
 	/*FEC_MDIO*/

+ 47 - 1
board/samsung/goni/goni.c

@@ -26,7 +26,9 @@
 #include <asm/arch/gpio.h>
 #include <asm/arch/mmc.h>
 #include <pmic.h>
-
+#include <usb/s3c_udc.h>
+#include <asm/arch/cpu.h>
+#include <max8998_pmic.h>
 DECLARE_GLOBAL_DATA_PTR;
 
 static struct s5pc110_gpio *s5pc110_gpio;
@@ -100,3 +102,47 @@ int board_mmc_init(bd_t *bis)
 	return s5p_mmc_init(0, 4);
 }
 #endif
+
+#ifdef CONFIG_USB_GADGET
+static int s5pc1xx_phy_control(int on)
+{
+	int ret;
+	static int status;
+	struct pmic *p = get_pmic();
+
+	if (pmic_probe(p))
+		return -1;
+
+	if (on && !status) {
+		ret = pmic_set_output(p, MAX8998_REG_ONOFF1,
+				      MAX8998_LDO3, LDO_ON);
+		ret = pmic_set_output(p, MAX8998_REG_ONOFF2,
+				      MAX8998_LDO8, LDO_ON);
+		if (ret) {
+			puts("MAX8998 LDO setting error!\n");
+			return -1;
+		}
+		status = 1;
+	} else if (!on && status) {
+		ret = pmic_set_output(p, MAX8998_REG_ONOFF1,
+				      MAX8998_LDO3, LDO_OFF);
+		ret = pmic_set_output(p, MAX8998_REG_ONOFF2,
+				      MAX8998_LDO8, LDO_OFF);
+		if (ret) {
+			puts("MAX8998 LDO setting error!\n");
+			return -1;
+		}
+		status = 0;
+	}
+	udelay(10000);
+
+	return 0;
+}
+
+struct s3c_plat_otg_data s5pc110_otg_data = {
+	.phy_control = s5pc1xx_phy_control,
+	.regs_phy = S5PC110_PHY_BASE,
+	.regs_otg = S5PC110_OTG_BASE,
+	.usb_phy_ctrl = S5PC110_USB_PHY_CONTROL,
+};
+#endif

+ 9 - 7
common/cmd_usb.c

@@ -700,11 +700,12 @@ int do_usb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 U_BOOT_CMD(
 	usb,	5,	1,	do_usb,
 	"USB sub-system",
-	"reset - reset (rescan) USB controller\n"
-	"usb stop [f]  - stop USB [f]=force stop\n"
-	"usb tree  - show USB device tree\n"
+	"start - start (scan) USB controller\n"
+	"usb reset - reset (rescan) USB controller\n"
+	"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 storage  - show details of USB storage devices\n"
+	"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"
@@ -725,8 +726,9 @@ U_BOOT_CMD(
 U_BOOT_CMD(
 	usb,	5,	1,	do_usb,
 	"USB sub-system",
-	"reset - reset (rescan) USB controller\n"
-	"usb  tree  - show USB device tree\n"
-	"usb  info [dev] - show available USB devices"
+	"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

+ 324 - 604
common/usb_kbd.c

@@ -25,12 +25,18 @@
  *
  */
 #include <common.h>
+#include <malloc.h>
 #include <stdio_dev.h>
 #include <asm/byteorder.h>
 
 #include <usb.h>
 
-#undef USB_KBD_DEBUG
+#ifdef	USB_KBD_DEBUG
+#define USB_KBD_PRINTF(fmt, args...)	printf(fmt, ##args)
+#else
+#define USB_KBD_PRINTF(fmt, args...)
+#endif
+
 /*
  * If overwrite_console returns 1, the stdin, stderr and stdout
  * are switched to the serial port, else the settings in the
@@ -45,743 +51,457 @@ int overwrite_console(void)
 }
 #endif
 
-#ifdef USB_KBD_DEBUG
-#define USB_KBD_PRINTF(fmt, args...)	printf(fmt, ##args)
-#else
-#define USB_KBD_PRINTF(fmt, args...)
-#endif
-
-
-#define REPEAT_RATE	(40/4)	/* 40msec -> 25cps */
-#define REPEAT_DELAY	10	/* 10 x REPEAT_RATE = 400msec */
+/* Keyboard sampling rate */
+#define REPEAT_RATE	(40 / 4)	/* 40msec -> 25cps */
+#define REPEAT_DELAY	10		/* 10 x REPEAT_RATE = 400msec */
 
 #define NUM_LOCK	0x53
 #define CAPS_LOCK	0x39
 #define SCROLL_LOCK	0x47
 
-
 /* Modifier bits */
-#define LEFT_CNTR		0
-#define LEFT_SHIFT		1
-#define LEFT_ALT		2
-#define LEFT_GUI		3
-#define RIGHT_CNTR		4
-#define RIGHT_SHIFT		5
-#define RIGHT_ALT		6
-#define RIGHT_GUI		7
-
-#define USB_KBD_BUFFER_LEN	0x20	/* size of the keyboardbuffer */
-
-static char usb_kbd_buffer[USB_KBD_BUFFER_LEN];
-static int usb_in_pointer;
-static int usb_out_pointer;
-
-unsigned char new[8];
-unsigned char old[8];
-int repeat_delay;
+#define LEFT_CNTR	(1 << 0)
+#define LEFT_SHIFT	(1 << 1)
+#define LEFT_ALT	(1 << 2)
+#define LEFT_GUI	(1 << 3)
+#define RIGHT_CNTR	(1 << 4)
+#define RIGHT_SHIFT	(1 << 5)
+#define RIGHT_ALT	(1 << 6)
+#define RIGHT_GUI	(1 << 7)
+
+/* Size of the keyboard buffer */
+#define USB_KBD_BUFFER_LEN	0x20
+
+/* Device name */
 #define DEVNAME			"usbkbd"
-static unsigned char num_lock;
-static unsigned char caps_lock;
-static unsigned char scroll_lock;
-static unsigned char ctrl;
-
-static unsigned char leds __attribute__((aligned(0x4)));
 
-static unsigned char usb_kbd_numkey[] = {
+/* Keyboard maps */
+static const unsigned char usb_kbd_numkey[] = {
 	'1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
 	'\r', 0x1b, '\b', '\t', ' ', '-', '=', '[', ']',
 	'\\', '#', ';', '\'', '`', ',', '.', '/'
 };
-static unsigned char usb_kbd_numkey_shifted[] = {
+static const unsigned char usb_kbd_numkey_shifted[] = {
 	'!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
 	'\r', 0x1b, '\b', '\t', ' ', '_', '+', '{', '}',
 	'|', '~', ':', '"', '~', '<', '>', '?'
 };
 
-/******************************************************************
- * Queue handling
- ******************************************************************/
-/* puts character in the queue and sets up the in and out pointer */
-static void usb_kbd_put_queue(char data)
-{
-	if ((usb_in_pointer+1) == USB_KBD_BUFFER_LEN) {
-		if (usb_out_pointer == 0)
-			return; /* buffer full */
-		else
-			usb_in_pointer = 0;
-	} else {
-		if ((usb_in_pointer+1) == usb_out_pointer)
-			return; /* buffer full */
-		usb_in_pointer++;
-	}
-	usb_kbd_buffer[usb_in_pointer] = data;
-	return;
-}
+/*
+ * NOTE: It's important for the NUM, CAPS, SCROLL-lock bits to be in this
+ *       order. See usb_kbd_setled() function!
+ */
+#define USB_KBD_NUMLOCK		(1 << 0)
+#define USB_KBD_CAPSLOCK	(1 << 1)
+#define USB_KBD_SCROLLLOCK	(1 << 2)
+#define USB_KBD_CTRL		(1 << 3)
 
-/* test if a character is in the queue */
-static int usb_kbd_testc(void)
-{
-#ifdef CONFIG_SYS_USB_EVENT_POLL
-	usb_event_poll();
-#endif
-	if (usb_in_pointer == usb_out_pointer)
-		return 0; /* no data */
-	else
-		return 1;
-}
-/* gets the character from the queue */
-static int usb_kbd_getc(void)
-{
-	char c;
-	while (usb_in_pointer == usb_out_pointer) {
-#ifdef CONFIG_SYS_USB_EVENT_POLL
-		usb_event_poll();
-#endif
-	}
-	if ((usb_out_pointer+1) == USB_KBD_BUFFER_LEN)
-		usb_out_pointer = 0;
-	else
-		usb_out_pointer++;
-	c = usb_kbd_buffer[usb_out_pointer];
-	return (int)c;
+#define USB_KBD_LEDMASK		\
+	(USB_KBD_NUMLOCK | USB_KBD_CAPSLOCK | USB_KBD_SCROLLLOCK)
 
-}
+struct usb_kbd_pdata {
+	uint32_t	repeat_delay;
 
-/* forward decleration */
-static int usb_kbd_probe(struct usb_device *dev, unsigned int ifnum);
+	uint32_t	usb_in_pointer;
+	uint32_t	usb_out_pointer;
+	uint8_t		usb_kbd_buffer[USB_KBD_BUFFER_LEN];
 
-/* search for keyboard and register it if found */
-int drv_usb_kbd_init(void)
+	uint8_t		new[8];
+	uint8_t		old[8];
+
+	uint8_t		flags;
+};
+
+/* Generic keyboard event polling. */
+void usb_kbd_generic_poll(void)
 {
-	int error, i;
-	struct stdio_dev usb_kbd_dev, *old_dev;
-	struct usb_device *dev;
-	char *stdinname = getenv("stdin");
+	struct stdio_dev *dev;
+	struct usb_device *usb_kbd_dev;
+	struct usb_kbd_pdata *data;
+	struct usb_interface *iface;
+	struct usb_endpoint_descriptor *ep;
+	int pipe;
+	int maxp;
+
+	/* Get the pointer to USB Keyboard device pointer */
+	dev = stdio_get_by_name(DEVNAME);
+	usb_kbd_dev = (struct usb_device *)dev->priv;
+	data = usb_kbd_dev->privptr;
+	iface = &usb_kbd_dev->config.if_desc[0];
+	ep = &iface->ep_desc[0];
+	pipe = usb_rcvintpipe(usb_kbd_dev, ep->bEndpointAddress);
 
-	usb_in_pointer = 0;
-	usb_out_pointer = 0;
-	/* scan all USB Devices */
-	for (i = 0 ; i < USB_MAX_DEVICE ; i++) {
-		dev = usb_get_dev_index(i); /* get device */
-		if (dev == NULL)
-			return -1;
-		if (dev->devnum != -1) {
-			/* Ok, we found a keyboard */
-			if (usb_kbd_probe(dev, 0) == 1) {
-				/* check, if it is already registered */
-				USB_KBD_PRINTF("USB KBD found set up "
-						"device.\n");
-				old_dev = stdio_get_by_name(DEVNAME);
-				if (old_dev) {
-					/* already registered, just return ok */
-					USB_KBD_PRINTF("USB KBD is already "
-							"registered.\n");
-					return 1;
-				}
-				/* register the keyboard */
-				USB_KBD_PRINTF("USB KBD register.\n");
-				memset(&usb_kbd_dev, 0,
-						sizeof(struct stdio_dev));
-				strcpy(usb_kbd_dev.name, DEVNAME);
-				usb_kbd_dev.flags =  DEV_FLAGS_INPUT |
-							DEV_FLAGS_SYSTEM;
-				usb_kbd_dev.putc = NULL;
-				usb_kbd_dev.puts = NULL;
-				usb_kbd_dev.getc = usb_kbd_getc;
-				usb_kbd_dev.tstc = usb_kbd_testc;
-				usb_kbd_dev.priv = (void *)dev;
-				error = stdio_register(&usb_kbd_dev);
-				if (error == 0) {
-					/*
-					 * check if this is the standard
-					 * input device
-					 */
-					if (strcmp(stdinname, DEVNAME) == 0) {
-						/* reassign the console */
-						if (overwrite_console())
-							return 1;
-						error = console_assign(stdin,
-								DEVNAME);
-						if (error == 0)
-							return 1;
-						else
-							return error;
-					}
-					return 1;
-				}
-				return error;
-			}
-		}
-	}
-	/* no USB Keyboard found */
-	return -1;
+	/* Submit a interrupt transfer request */
+	maxp = usb_maxpacket(usb_kbd_dev, pipe);
+	usb_submit_int_msg(usb_kbd_dev, pipe, data->new,
+			maxp > 8 ? 8 : maxp, ep->bInterval);
 }
 
-
-/* deregistering the keyboard */
-int usb_kbd_deregister(void)
+/* Puts character in the queue and sets up the in and out pointer. */
+static void usb_kbd_put_queue(struct usb_kbd_pdata *data, char c)
 {
-#ifdef CONFIG_SYS_STDIO_DEREGISTER
-	return stdio_deregister(DEVNAME);
-#else
-	return 1;
-#endif
-}
+	if (data->usb_in_pointer == USB_KBD_BUFFER_LEN - 1) {
+		/* Check for buffer full. */
+		if (data->usb_out_pointer == 0)
+			return;
 
-/**************************************************************************
- * Low Level drivers
- */
+		data->usb_in_pointer = 0;
+	} else {
+		/* Check for buffer full. */
+		if (data->usb_in_pointer == data->usb_out_pointer - 1)
+			return;
+
+		data->usb_in_pointer++;
+	}
 
-/* set the LEDs. Since this is used in the irq routine, the control job
-   is issued with a timeout of 0. This means, that the job is queued without
-   waiting for job completion */
+	data->usb_kbd_buffer[data->usb_in_pointer] = c;
+}
 
+/*
+ * Set the LEDs. Since this is used in the irq routine, the control job is
+ * issued with a timeout of 0. This means, that the job is queued without
+ * waiting for job completion.
+ */
 static void usb_kbd_setled(struct usb_device *dev)
 {
-	struct usb_interface *iface;
-	iface = &dev->config.if_desc[0];
-	leds = 0;
-	if (scroll_lock != 0)
-		leds |= 1;
-	leds <<= 1;
-	if (caps_lock != 0)
-		leds |= 1;
-	leds <<= 1;
-	if (num_lock != 0)
-		leds |= 1;
+	struct usb_interface *iface = &dev->config.if_desc[0];
+	struct usb_kbd_pdata *data = dev->privptr;
+	uint32_t leds = data->flags & USB_KBD_LEDMASK;
+
 	usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
 		USB_REQ_SET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
 		0x200, iface->desc.bInterfaceNumber, (void *)&leds, 1, 0);
-
 }
 
-
-#define CAPITAL_MASK 0x20
+#define CAPITAL_MASK	0x20
 /* Translate the scancode in ASCII */
-static int usb_kbd_translate(unsigned char scancode, unsigned char modifier,
-				int pressed)
+static int usb_kbd_translate(struct usb_kbd_pdata *data, unsigned char scancode,
+				unsigned char modifier, int pressed)
 {
-	unsigned char keycode;
+	uint8_t keycode = 0;
 
+	/* Key released */
 	if (pressed == 0) {
-		/* key released */
-		repeat_delay = 0;
+		data->repeat_delay = 0;
 		return 0;
 	}
+
 	if (pressed == 2) {
-		repeat_delay++;
-		if (repeat_delay < REPEAT_DELAY)
+		data->repeat_delay++;
+		if (data->repeat_delay < REPEAT_DELAY)
 			return 0;
-		repeat_delay = REPEAT_DELAY;
+
+		data->repeat_delay = REPEAT_DELAY;
 	}
-	keycode = 0;
-	if ((scancode > 3) && (scancode <= 0x1d)) { /* alpha numeric values */
-		keycode = scancode - 4 + 0x61;
-		if (caps_lock)
-			/* switch to capital Letters */
+
+	/* Alphanumeric values */
+	if ((scancode > 3) && (scancode <= 0x1d)) {
+		keycode = scancode - 4 + 'a';
+
+		if (data->flags & USB_KBD_CAPSLOCK)
 			keycode &= ~CAPITAL_MASK;
-		if (((modifier&(1 << LEFT_SHIFT)) != 0) ||
-			((modifier&(1 << RIGHT_SHIFT)) != 0)) {
+
+		if (modifier & (LEFT_SHIFT | RIGHT_SHIFT)) {
+			/* Handle CAPSLock + Shift pressed simultaneously */
 			if (keycode & CAPITAL_MASK)
-				/* switch to capital Letters */
 				keycode &= ~CAPITAL_MASK;
 			else
-				/* switch to non capital Letters */
 				keycode |= CAPITAL_MASK;
 		}
 	}
-	if ((scancode > 0x1d) && (scancode < 0x3A)) {
-		if (((modifier&(1 << LEFT_SHIFT)) != 0) ||
-			((modifier&(1 << RIGHT_SHIFT)) != 0))  /* shifted */
-			keycode = usb_kbd_numkey_shifted[scancode-0x1e];
-		else /* non shifted */
-			keycode = usb_kbd_numkey[scancode-0x1e];
+
+	if ((scancode > 0x1d) && (scancode < 0x3a)) {
+		/* Shift pressed */
+		if (modifier & (LEFT_SHIFT | RIGHT_SHIFT))
+			keycode = usb_kbd_numkey_shifted[scancode - 0x1e];
+		else
+			keycode = usb_kbd_numkey[scancode - 0x1e];
 	}
 
-	if (ctrl)
+	if (data->flags & USB_KBD_CTRL)
 		keycode = scancode - 0x3;
 
 	if (pressed == 1) {
 		if (scancode == NUM_LOCK) {
-			num_lock = ~num_lock;
+			data->flags ^= USB_KBD_NUMLOCK;
 			return 1;
 		}
+
 		if (scancode == CAPS_LOCK) {
-			caps_lock = ~caps_lock;
+			data->flags ^= USB_KBD_CAPSLOCK;
 			return 1;
 		}
 		if (scancode == SCROLL_LOCK) {
-			scroll_lock = ~scroll_lock;
+			data->flags ^= USB_KBD_SCROLLLOCK;
 			return 1;
 		}
 	}
-	if (keycode != 0) {
+
+	/* Report keycode if any */
+	if (keycode) {
 		USB_KBD_PRINTF("%c", keycode);
-		usb_kbd_put_queue(keycode);
+		usb_kbd_put_queue(data, keycode);
 	}
+
 	return 0;
 }
 
+static uint32_t usb_kbd_service_key(struct usb_device *dev, int i, int up)
+{
+	uint32_t res = 0;
+	struct usb_kbd_pdata *data = dev->privptr;
+	uint8_t *new;
+	uint8_t *old;
+
+	if (up) {
+		new = data->old;
+		old = data->new;
+	} else {
+		new = data->new;
+		old = data->old;
+	}
+
+	if ((old[i] > 3) && (memscan(new + 2, old[i], 6) == new + 8))
+		res |= usb_kbd_translate(data, old[i], data->new[0], up);
+
+	return res;
+}
+
 /* Interrupt service routine */
-static int usb_kbd_irq(struct usb_device *dev)
+static int usb_kbd_irq_worker(struct usb_device *dev)
 {
-	int i, res;
+	struct usb_kbd_pdata *data = dev->privptr;
+	int i, res = 0;
+
+	/* No combo key pressed */
+	if (data->new[0] == 0x00)
+		data->flags &= ~USB_KBD_CTRL;
+	/* Left or Right Ctrl pressed */
+	else if ((data->new[0] == LEFT_CNTR) || (data->new[0] == RIGHT_CNTR))
+		data->flags |= USB_KBD_CTRL;
+
+	for (i = 2; i < 8; i++) {
+		res |= usb_kbd_service_key(dev, i, 0);
+		res |= usb_kbd_service_key(dev, i, 1);
+	}
+
+	/* Key is still pressed */
+	if ((data->new[2] > 3) && (data->old[2] == data->new[2]))
+		res |= usb_kbd_translate(data, data->new[2], data->new[0], 2);
+
+	if (res == 1)
+		usb_kbd_setled(dev);
 
+	memcpy(data->old, data->new, 8);
+
+	return 1;
+}
+
+/* Keyboard interrupt handler */
+static int usb_kbd_irq(struct usb_device *dev)
+{
 	if ((dev->irq_status != 0) || (dev->irq_act_len != 8)) {
-		USB_KBD_PRINTF("usb_keyboard Error %lX, len %d\n",
+		USB_KBD_PRINTF("USB KBD: Error %lX, len %d\n",
 				dev->irq_status, dev->irq_act_len);
 		return 1;
 	}
-	res = 0;
-
-	switch (new[0]) {
-	case 0x0:	/* No combo key pressed */
-		ctrl = 0;
-		break;
-	case 0x01:	/* Left Ctrl pressed */
-	case 0x10:	/* Right Ctrl pressed */
-		ctrl = 1;
-		break;
-	}
 
-	for (i = 2; i < 8; i++) {
-		if (old[i] > 3 && memscan(&new[2], old[i], 6) == &new[8])
-			res |= usb_kbd_translate(old[i], new[0], 0);
+	return usb_kbd_irq_worker(dev);
+}
 
-		if (new[i] > 3 && memscan(&old[2], new[i], 6) == &old[8])
-			res |= usb_kbd_translate(new[i], new[0], 1);
-	}
+/* Interrupt polling */
+static inline void usb_kbd_poll_for_event(struct usb_device *dev)
+{
+#if	defined(CONFIG_SYS_USB_EVENT_POLL)
+	usb_event_poll();
+	usb_kbd_irq_worker(dev);
+#elif	defined(CONFIG_SYS_USB_EVENT_POLL_VIA_CONTROL_EP)
+	struct usb_interface *iface;
+	struct usb_kbd_pdata *data = dev->privptr;
+	iface = &dev->config.if_desc[0];
+	usb_get_report(dev, iface->desc.bInterfaceNumber,
+			1, 1, data->new, sizeof(data->new));
+	if (memcmp(data->old, data->new, sizeof(data->new)))
+		usb_kbd_irq_worker(dev);
+#endif
+}
 
-	if ((new[2] > 3) && (old[2] == new[2])) /* still pressed */
-		res |= usb_kbd_translate(new[2], new[0], 2);
-	if (res == 1)
-		usb_kbd_setled(dev);
+/* test if a character is in the queue */
+static int usb_kbd_testc(void)
+{
+	struct stdio_dev *dev;
+	struct usb_device *usb_kbd_dev;
+	struct usb_kbd_pdata *data;
+
+	dev = stdio_get_by_name(DEVNAME);
+	usb_kbd_dev = (struct usb_device *)dev->priv;
+	data = usb_kbd_dev->privptr;
 
-	memcpy(&old[0], &new[0], 8);
+	usb_kbd_poll_for_event(usb_kbd_dev);
 
-	return 1; /* install IRQ Handler again */
+	return !(data->usb_in_pointer == data->usb_out_pointer);
 }
 
-/* probes the USB device dev for keyboard type */
+/* gets the character from the queue */
+static int usb_kbd_getc(void)
+{
+	struct stdio_dev *dev;
+	struct usb_device *usb_kbd_dev;
+	struct usb_kbd_pdata *data;
+
+	dev = stdio_get_by_name(DEVNAME);
+	usb_kbd_dev = (struct usb_device *)dev->priv;
+	data = usb_kbd_dev->privptr;
+
+	while (data->usb_in_pointer == data->usb_out_pointer)
+		usb_kbd_poll_for_event(usb_kbd_dev);
+
+	if (data->usb_out_pointer == USB_KBD_BUFFER_LEN - 1)
+		data->usb_out_pointer = 0;
+	else
+		data->usb_out_pointer++;
+
+	return data->usb_kbd_buffer[data->usb_out_pointer];
+}
+
+/* probes the USB device dev for keyboard type. */
 static int usb_kbd_probe(struct usb_device *dev, unsigned int ifnum)
 {
 	struct usb_interface *iface;
 	struct usb_endpoint_descriptor *ep;
+	struct usb_kbd_pdata *data;
 	int pipe, maxp;
 
 	if (dev->descriptor.bNumConfigurations != 1)
 		return 0;
+
 	iface = &dev->config.if_desc[ifnum];
 
 	if (iface->desc.bInterfaceClass != 3)
 		return 0;
+
 	if (iface->desc.bInterfaceSubClass != 1)
 		return 0;
+
 	if (iface->desc.bInterfaceProtocol != 1)
 		return 0;
+
 	if (iface->desc.bNumEndpoints != 1)
 		return 0;
 
 	ep = &iface->ep_desc[0];
 
+	/* Check if endpoint 1 is interrupt endpoint */
 	if (!(ep->bEndpointAddress & 0x80))
 		return 0;
+
 	if ((ep->bmAttributes & 3) != 3)
 		return 0;
-	USB_KBD_PRINTF("USB KBD found set protocol...\n");
-	/* ok, we found a USB Keyboard, install it */
-	/* usb_kbd_get_hid_desc(dev); */
-	usb_set_protocol(dev, iface->desc.bInterfaceNumber, 0);
-	USB_KBD_PRINTF("USB KBD found set idle...\n");
-	usb_set_idle(dev, iface->desc.bInterfaceNumber, REPEAT_RATE, 0);
-	memset(&new[0], 0, 8);
-	memset(&old[0], 0, 8);
-	repeat_delay = 0;
-	pipe = usb_rcvintpipe(dev, ep->bEndpointAddress);
-	maxp = usb_maxpacket(dev, pipe);
-	dev->irq_handle = usb_kbd_irq;
-	USB_KBD_PRINTF("USB KBD enable interrupt pipe...\n");
-	usb_submit_int_msg(dev, pipe, &new[0], maxp > 8 ? 8 : maxp,
-				ep->bInterval);
-	return 1;
-}
 
+	USB_KBD_PRINTF("USB KBD: found set protocol...\n");
 
-#if 0
-struct usb_hid_descriptor {
-	unsigned char  bLength;
-	unsigned char  bDescriptorType; /* 0x21 for HID */
-	unsigned short bcdHID; /* release number */
-	unsigned char  bCountryCode;
-	unsigned char  bNumDescriptors;
-	unsigned char  bReportDescriptorType;
-	unsigned short wDescriptorLength;
-} __packed;
+	data = malloc(sizeof(struct usb_kbd_pdata));
+	if (!data) {
+		printf("USB KBD: Error allocating private data\n");
+		return 0;
+	}
 
-/*
- * We parse each description item into this structure. Short items data
- * values are expanded to 32-bit signed int, long items contain a pointer
- * into the data area.
- */
+	/* Clear private data */
+	memset(data, 0, sizeof(struct usb_kbd_pdata));
 
-struct hid_item {
-	unsigned char format;
-	unsigned char size;
-	unsigned char type;
-	unsigned char tag;
-	union {
-	    unsigned char   u8;
-	    char            s8;
-	    unsigned short  u16;
-	    short           s16;
-	    unsigned long   u32;
-	    long            s32;
-	    unsigned char  *longdata;
-	} data;
-};
+	/* Insert private data into USB device structure */
+	dev->privptr = data;
 
-/*
- * HID report item format
- */
-
-#define HID_ITEM_FORMAT_SHORT	0
-#define HID_ITEM_FORMAT_LONG	1
+	/* Set IRQ handler */
+	dev->irq_handle = usb_kbd_irq;
 
-/*
- * Special tag indicating long items
- */
+	pipe = usb_rcvintpipe(dev, ep->bEndpointAddress);
+	maxp = usb_maxpacket(dev, pipe);
 
-#define HID_ITEM_TAG_LONG	15
+	/* We found a USB Keyboard, install it. */
+	usb_set_protocol(dev, iface->desc.bInterfaceNumber, 0);
 
+	USB_KBD_PRINTF("USB KBD: found set idle...\n");
+	usb_set_idle(dev, iface->desc.bInterfaceNumber, REPEAT_RATE, 0);
 
-static struct usb_hid_descriptor usb_kbd_hid_desc;
+	USB_KBD_PRINTF("USB KBD: enable interrupt pipe...\n");
+	usb_submit_int_msg(dev, pipe, data->new, maxp > 8 ? 8 : maxp,
+				ep->bInterval);
 
-void usb_kbd_display_hid(struct usb_hid_descriptor *hid)
-{
-	printf("USB_HID_DESC:\n");
-	printf("  bLenght               0x%x\n", hid->bLength);
-	printf("  bcdHID                0x%x\n", hid->bcdHID);
-	printf("  bCountryCode          %d\n", hid->bCountryCode);
-	printf("  bNumDescriptors       0x%x\n", hid->bNumDescriptors);
-	printf("  bReportDescriptorType 0x%x\n", hid->bReportDescriptorType);
-	printf("  wDescriptorLength     0x%x\n", hid->wDescriptorLength);
+	/* Success. */
+	return 1;
 }
 
-
-/*
- * Fetch a report description item from the data stream. We support long
- * items, though they are not used yet.
- */
-
-static int fetch_item(unsigned char *start, unsigned char *end,
-			struct hid_item *item)
+/* Search for keyboard and register it if found. */
+int drv_usb_kbd_init(void)
 {
-	if ((end - start) > 0) {
-		unsigned char b = *start++;
-		item->type = (b >> 2) & 3;
-		item->tag  = (b >> 4) & 15;
-		if (item->tag == HID_ITEM_TAG_LONG) {
-			item->format = HID_ITEM_FORMAT_LONG;
-			if ((end - start) >= 2) {
-				item->size = *start++;
-				item->tag  = *start++;
-				if ((end - start) >= item->size) {
-					item->data.longdata = start;
-					start += item->size;
-					return item->size;
-				}
-			}
-		} else {
-			item->format = HID_ITEM_FORMAT_SHORT;
-			item->size = b & 3;
-			switch (item->size) {
-			case 0:
-				return item->size;
-			case 1:
-				if ((end - start) >= 1) {
-					item->data.u8 = *start++;
-					return item->size;
-				}
-				break;
-			case 2:
-				if ((end - start) >= 2) {
-					item->data.u16 = le16_to_cpu(
-						(unsigned short *)start);
-					start += 2;
-					return item->size;
-				}
-			case 3:
-				item->size++;
-				if ((end - start) >= 4) {
-					item->data.u32 = le32_to_cpu(
-						(unsigned long *)start);
-					start += 4;
-					return item->size;
-				}
-			}
-		}
-	}
-	return -1;
-}
-
-/*
- * HID report descriptor item type (prefix bit 2, 3)
- */
-
-#define HID_ITEM_TYPE_MAIN		0
-#define HID_ITEM_TYPE_GLOBAL		1
-#define HID_ITEM_TYPE_LOCAL		2
-#define HID_ITEM_TYPE_RESERVED		3
-/*
- * HID report descriptor main item tags
- */
-
-#define HID_MAIN_ITEM_TAG_INPUT			8
-#define HID_MAIN_ITEM_TAG_OUTPUT		9
-#define HID_MAIN_ITEM_TAG_FEATURE		11
-#define HID_MAIN_ITEM_TAG_BEGIN_COLLECTION	10
-#define HID_MAIN_ITEM_TAG_END_COLLECTION	12
-/*
- * HID report descriptor main item contents
- */
-
-#define HID_MAIN_ITEM_CONSTANT		0x001
-#define HID_MAIN_ITEM_VARIABLE		0x002
-#define HID_MAIN_ITEM_RELATIVE		0x004
-#define HID_MAIN_ITEM_WRAP		0x008
-#define HID_MAIN_ITEM_NONLINEAR		0x010
-#define HID_MAIN_ITEM_NO_PREFERRED	0x020
-#define HID_MAIN_ITEM_NULL_STATE	0x040
-#define HID_MAIN_ITEM_VOLATILE		0x080
-#define HID_MAIN_ITEM_BUFFERED_BYTE	0x100
+	struct stdio_dev usb_kbd_dev, *old_dev;
+	struct usb_device *dev;
+	char *stdinname = getenv("stdin");
+	int error, i;
 
-/*
- * HID report descriptor collection item types
- */
+	/* Scan all USB Devices */
+	for (i = 0; i < USB_MAX_DEVICE; i++) {
+		/* Get USB device. */
+		dev = usb_get_dev_index(i);
+		if (!dev)
+			return -1;
 
-#define HID_COLLECTION_PHYSICAL		0
-#define HID_COLLECTION_APPLICATION	1
-#define HID_COLLECTION_LOGICAL		2
-/*
- * HID report descriptor global item tags
- */
+		if (dev->devnum == -1)
+			continue;
 
-#define HID_GLOBAL_ITEM_TAG_USAGE_PAGE		0
-#define HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM	1
-#define HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM	2
-#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM	3
-#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM	4
-#define HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT	5
-#define HID_GLOBAL_ITEM_TAG_UNIT		6
-#define HID_GLOBAL_ITEM_TAG_REPORT_SIZE		7
-#define HID_GLOBAL_ITEM_TAG_REPORT_ID		8
-#define HID_GLOBAL_ITEM_TAG_REPORT_COUNT	9
-#define HID_GLOBAL_ITEM_TAG_PUSH		10
-#define HID_GLOBAL_ITEM_TAG_POP			11
+		/* Try probing the keyboard */
+		if (usb_kbd_probe(dev, 0) != 1)
+			continue;
 
-/*
- * HID report descriptor local item tags
- */
-
-#define HID_LOCAL_ITEM_TAG_USAGE		0
-#define HID_LOCAL_ITEM_TAG_USAGE_MINIMUM	1
-#define HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM	2
-#define HID_LOCAL_ITEM_TAG_DESIGNATOR_INDEX	3
-#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MINIMUM	4
-#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MAXIMUM	5
-#define HID_LOCAL_ITEM_TAG_STRING_INDEX		7
-#define HID_LOCAL_ITEM_TAG_STRING_MINIMUM	8
-#define HID_LOCAL_ITEM_TAG_STRING_MAXIMUM	9
-#define HID_LOCAL_ITEM_TAG_DELIMITER		10
+		/* We found a keyboard, check if it is already registered. */
+		USB_KBD_PRINTF("USB KBD: found set up device.\n");
+		old_dev = stdio_get_by_name(DEVNAME);
+		if (old_dev) {
+			/* Already registered, just return ok. */
+			USB_KBD_PRINTF("USB KBD: is already registered.\n");
+			return 1;
+		}
 
+		/* Register the keyboard */
+		USB_KBD_PRINTF("USB KBD: register.\n");
+		memset(&usb_kbd_dev, 0, sizeof(struct stdio_dev));
+		strcpy(usb_kbd_dev.name, DEVNAME);
+		usb_kbd_dev.flags =  DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
+		usb_kbd_dev.putc = NULL;
+		usb_kbd_dev.puts = NULL;
+		usb_kbd_dev.getc = usb_kbd_getc;
+		usb_kbd_dev.tstc = usb_kbd_testc;
+		usb_kbd_dev.priv = (void *)dev;
+		error = stdio_register(&usb_kbd_dev);
+		if (error)
+			return error;
+
+		/* Check if this is the standard input device. */
+		if (strcmp(stdinname, DEVNAME))
+			return 1;
 
-static void usb_kbd_show_item(struct hid_item *item)
-{
-	switch (item->type) {
-	case HID_ITEM_TYPE_MAIN:
-		switch (item->tag) {
-		case HID_MAIN_ITEM_TAG_INPUT:
-			printf("Main Input");
-			break;
-		case HID_MAIN_ITEM_TAG_OUTPUT:
-			printf("Main Output");
-			break;
-		case HID_MAIN_ITEM_TAG_FEATURE:
-			printf("Main Feature");
-			break;
-		case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION:
-			printf("Main Begin Collection");
-			break;
-		case HID_MAIN_ITEM_TAG_END_COLLECTION:
-			printf("Main End Collection");
-			break;
-		default:
-			printf("Main reserved %d", item->tag);
-			break;
-		}
-		break;
-	case HID_ITEM_TYPE_GLOBAL:
-		switch (item->tag) {
-		case HID_GLOBAL_ITEM_TAG_USAGE_PAGE:
-			printf("- Global Usage Page");
-			break;
-		case HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM:
-			printf("- Global Logical Minimum");
-			break;
-		case HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM:
-			printf("- Global Logical Maximum");
-			break;
-		case HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM:
-			printf("- Global physical Minimum");
-			break;
-		case HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM:
-			printf("- Global physical Maximum");
-			break;
-		case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT:
-			printf("- Global Unit Exponent");
-			break;
-		case HID_GLOBAL_ITEM_TAG_UNIT:
-			printf("- Global Unit");
-			break;
-		case HID_GLOBAL_ITEM_TAG_REPORT_SIZE:
-			printf("- Global Report Size");
-			break;
-		case HID_GLOBAL_ITEM_TAG_REPORT_ID:
-			printf("- Global Report ID");
-			break;
-		case HID_GLOBAL_ITEM_TAG_REPORT_COUNT:
-			printf("- Global Report Count");
-			break;
-		case HID_GLOBAL_ITEM_TAG_PUSH:
-			printf("- Global Push");
-			break;
-		case HID_GLOBAL_ITEM_TAG_POP:
-			printf("- Global Pop");
-			break;
-		default:
-			printf("- Global reserved %d", item->tag);
-			break;
-		}
-		break;
-	case HID_ITEM_TYPE_LOCAL:
-		switch (item->tag) {
-		case HID_LOCAL_ITEM_TAG_USAGE:
-			printf("-- Local Usage");
-			break;
-		case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:
-			printf("-- Local Usage Minimum");
-			break;
-		case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM:
-			printf("-- Local Usage Maximum");
-			break;
-		case HID_LOCAL_ITEM_TAG_DESIGNATOR_INDEX:
-			printf("-- Local Designator Index");
-			break;
-		case HID_LOCAL_ITEM_TAG_DESIGNATOR_MINIMUM:
-			printf("-- Local Designator Minimum");
-			break;
-		case HID_LOCAL_ITEM_TAG_DESIGNATOR_MAXIMUM:
-			printf("-- Local Designator Maximum");
-			break;
-		case HID_LOCAL_ITEM_TAG_STRING_INDEX:
-			printf("-- Local String Index");
-			break;
-		case HID_LOCAL_ITEM_TAG_STRING_MINIMUM:
-			printf("-- Local String Minimum");
-			break;
-		case HID_LOCAL_ITEM_TAG_STRING_MAXIMUM:
-			printf("-- Local String Maximum");
-			break;
-		case HID_LOCAL_ITEM_TAG_DELIMITER:
-			printf("-- Local Delimiter");
-			break;
-		default:
-			printf("-- Local reserved %d", item->tag);
-			break;
-		}
-		break;
-	default:
-		printf("--- reserved %d", item->type);
-		break;
-	}
-	switch (item->size) {
-	case 1:
-		printf("  %d", item->data.u8);
-		break;
-	case 2:
-		printf("  %d", item->data.u16);
-		break;
-	case 4:
-		printf("  %ld", item->data.u32);
-		break;
-	}
-	printf("\n");
-}
+		/* Reassign the console */
+		if (overwrite_console())
+			return 1;
 
+		error = console_assign(stdin, DEVNAME);
+		if (error)
+			return error;
 
-static int usb_kbd_get_hid_desc(struct usb_device *dev)
-{
-	unsigned char buffer[256];
-	struct usb_descriptor_header *head;
-	struct usb_config_descriptor *config;
-	int index, len, i;
-	unsigned char *start, *end;
-	struct hid_item item;
-
-	if (usb_get_configuration_no(dev, &buffer[0], 0) == -1)
-		return -1;
-	head = (struct usb_descriptor_header *)&buffer[0];
-	if (head->bDescriptorType != USB_DT_CONFIG) {
-		printf(" ERROR: NOT USB_CONFIG_DESC %x\n",
-				head->bDescriptorType);
-		return -1;
-	}
-	index = head->bLength;
-	config = (struct usb_config_descriptor *)&buffer[0];
-	len = le16_to_cpu(config->wTotalLength);
-	/*
-	 * Ok the first entry must be a configuration entry,
-	 * now process the others
-	 */
-	head = (struct usb_descriptor_header *)&buffer[index];
-	while (index+1 < len) {
-		if (head->bDescriptorType == USB_DT_HID) {
-			printf("HID desc found\n");
-			memcpy(&usb_kbd_hid_desc, &buffer[index],
-					buffer[index]);
-			le16_to_cpus(&usb_kbd_hid_desc.bcdHID);
-			le16_to_cpus(&usb_kbd_hid_desc.wDescriptorLength);
-			usb_kbd_display_hid(&usb_kbd_hid_desc);
-			len = 0;
-			break;
-		}
-		index += head->bLength;
-		head = (struct usb_descriptor_header *)&buffer[index];
-	}
-	if (len > 0)
-		return -1;
-	len = usb_kbd_hid_desc.wDescriptorLength;
-	index = usb_get_class_descriptor(dev, 0, USB_DT_REPORT, 0, &buffer[0],
-						len);
-	if (index < 0) {
-		printf("reading report descriptor failed\n");
-		return -1;
+		return 1;
 	}
-	printf(" report descriptor (size %u, read %d)\n", len, index);
-	start = &buffer[0];
-	end = &buffer[len];
-	i = 0;
-	do {
-		index = fetch_item(start, end, &item);
-		i += index;
-		i++;
-		if (index >= 0)
-			usb_kbd_show_item(&item);
-
-		start += index;
-		start++;
-	} while (index >= 0);
 
+	/* No USB Keyboard found */
+	return -1;
 }
 
+/* Deregister the keyboard. */
+int usb_kbd_deregister(void)
+{
+#ifdef CONFIG_SYS_STDIO_DEREGISTER
+	return stdio_deregister(DEVNAME);
+#else
+	return 1;
 #endif
+}

+ 2 - 2
drivers/serial/usbtty.c

@@ -554,11 +554,11 @@ int drv_usbtty_init (void)
 	usbtty_init_strings ();
 	usbtty_init_instances ();
 
+	usbtty_init_endpoints ();
+
 	udc_startup_events (device_instance);/* Enable dev, init udc pointers */
 	udc_connect ();		/* Enable pullup for host detection */
 
-	usbtty_init_endpoints ();
-
 	/* Device initialization */
 	memset (&usbttydev, 0, sizeof (usbttydev));
 

+ 5 - 0
drivers/usb/gadget/Makefile

@@ -26,9 +26,14 @@ include $(TOPDIR)/config.mk
 LIB	:= $(obj)libusb_gadget.o
 
 # new USB gadget layer dependencies
+ifdef CONFIG_USB_GADGET
+COBJS-y += epautoconf.o config.o usbstring.o
+COBJS-$(CONFIG_USB_GADGET_S3C_UDC_OTG) += s3c_udc_otg.o
+endif
 ifdef CONFIG_USB_ETHER
 COBJS-y += ether.o epautoconf.o config.o usbstring.o
 COBJS-$(CONFIG_USB_ETH_RNDIS) += rndis.o
+COBJS-$(CONFIG_MV_UDC)	+= mv_udc.o
 else
 # Devices not related to the new gadget layer depend on CONFIG_USB_DEVICE
 ifdef CONFIG_USB_DEVICE

+ 7 - 0
drivers/usb/gadget/gadget_chips.h

@@ -150,6 +150,11 @@
 #define	gadget_is_m66592(g)	0
 #endif
 
+#ifdef CONFIG_USB_GADGET_MV
+#define gadget_is_mv(g)        (!strcmp("mv_udc", (g)->name))
+#else
+#define gadget_is_mv(g)        0
+#endif
 
 /*
  * CONFIG_USB_GADGET_SX2
@@ -216,5 +221,7 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
 		return 0x20;
 	else if (gadget_is_m66592(gadget))
 		return 0x21;
+	else if (gadget_is_mv(gadget))
+		return 0x22;
 	return -ENOENT;
 }

+ 499 - 0
drivers/usb/gadget/mv_udc.c

@@ -0,0 +1,499 @@
+/*
+ * Copyright 2011, Marvell Semiconductor Inc.
+ * Lei Wen <leiwen@marvell.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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
+ *
+ * Back ported to the 8xx platform (from the 8260 platform) by
+ * Murray.Jensen@cmst.csiro.au, 27-Jan-01.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <config.h>
+#include <net.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <linux/types.h>
+#include <usb/mv_udc.h>
+
+#ifndef DEBUG
+#define DBG(x...) do {} while (0)
+#else
+#define DBG(x...) printf(x)
+static const char *reqname(unsigned r)
+{
+	switch (r) {
+	case USB_REQ_GET_STATUS: return "GET_STATUS";
+	case USB_REQ_CLEAR_FEATURE: return "CLEAR_FEATURE";
+	case USB_REQ_SET_FEATURE: return "SET_FEATURE";
+	case USB_REQ_SET_ADDRESS: return "SET_ADDRESS";
+	case USB_REQ_GET_DESCRIPTOR: return "GET_DESCRIPTOR";
+	case USB_REQ_SET_DESCRIPTOR: return "SET_DESCRIPTOR";
+	case USB_REQ_GET_CONFIGURATION: return "GET_CONFIGURATION";
+	case USB_REQ_SET_CONFIGURATION: return "SET_CONFIGURATION";
+	case USB_REQ_GET_INTERFACE: return "GET_INTERFACE";
+	case USB_REQ_SET_INTERFACE: return "SET_INTERFACE";
+	default: return "*UNKNOWN*";
+	}
+}
+#endif
+
+#define PAGE_SIZE	4096
+#define QH_MAXNUM	32
+static struct usb_endpoint_descriptor ep0_out_desc = {
+	.bLength = sizeof(struct usb_endpoint_descriptor),
+	.bDescriptorType = USB_DT_ENDPOINT,
+	.bEndpointAddress = 0,
+	.bmAttributes =	USB_ENDPOINT_XFER_CONTROL,
+};
+
+static struct usb_endpoint_descriptor ep0_in_desc = {
+	.bLength = sizeof(struct usb_endpoint_descriptor),
+	.bDescriptorType = USB_DT_ENDPOINT,
+	.bEndpointAddress = USB_DIR_IN,
+	.bmAttributes =	USB_ENDPOINT_XFER_CONTROL,
+};
+
+struct ept_queue_head *epts;
+struct ept_queue_item *items[2 * NUM_ENDPOINTS];
+static int mv_pullup(struct usb_gadget *gadget, int is_on);
+static int mv_ep_enable(struct usb_ep *ep,
+		const struct usb_endpoint_descriptor *desc);
+static int mv_ep_disable(struct usb_ep *ep);
+static int mv_ep_queue(struct usb_ep *ep,
+		struct usb_request *req, gfp_t gfp_flags);
+static struct usb_request *
+mv_ep_alloc_request(struct usb_ep *ep, unsigned int gfp_flags);
+static void mv_ep_free_request(struct usb_ep *ep, struct usb_request *_req);
+
+static struct usb_gadget_ops mv_udc_ops = {
+	.pullup = mv_pullup,
+};
+
+static struct usb_ep_ops mv_ep_ops = {
+	.enable         = mv_ep_enable,
+	.disable        = mv_ep_disable,
+	.queue          = mv_ep_queue,
+	.alloc_request  = mv_ep_alloc_request,
+	.free_request   = mv_ep_free_request,
+};
+
+static struct mv_ep ep[2 * NUM_ENDPOINTS];
+static struct mv_drv controller = {
+	.gadget = {
+		.ep0 = &ep[0].ep,
+		.name = "mv_udc",
+	},
+};
+
+static struct usb_request *
+mv_ep_alloc_request(struct usb_ep *ep, unsigned int gfp_flags)
+{
+	struct mv_ep *mv_ep = container_of(ep, struct mv_ep, ep);
+	return &mv_ep->req;
+}
+
+static void mv_ep_free_request(struct usb_ep *ep, struct usb_request *_req)
+{
+	return;
+}
+
+static void ep_enable(int num, int in)
+{
+	struct ept_queue_head *head;
+	struct mv_udc *udc = controller.udc;
+	unsigned n;
+	head = epts + 2*num + in;
+
+	n = readl(&udc->epctrl[num]);
+	if (in)
+		n |= (CTRL_TXE | CTRL_TXR | CTRL_TXT_BULK);
+	else
+		n |= (CTRL_RXE | CTRL_RXR | CTRL_RXT_BULK);
+
+	if (num != 0)
+		head->config = CONFIG_MAX_PKT(EP_MAX_PACKET_SIZE) | CONFIG_ZLT;
+	writel(n, &udc->epctrl[num]);
+}
+
+static int mv_ep_enable(struct usb_ep *ep,
+		const struct usb_endpoint_descriptor *desc)
+{
+	struct mv_ep *mv_ep = container_of(ep, struct mv_ep, ep);
+	int num, in;
+	num = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+	in = (desc->bEndpointAddress & USB_DIR_IN) != 0;
+	ep_enable(num, in);
+	mv_ep->desc = desc;
+	return 0;
+}
+
+static int mv_ep_disable(struct usb_ep *ep)
+{
+	return 0;
+}
+
+static int mv_ep_queue(struct usb_ep *ep,
+		struct usb_request *req, gfp_t gfp_flags)
+{
+	struct mv_ep *mv_ep = container_of(ep, struct mv_ep, ep);
+	struct mv_udc *udc = controller.udc;
+	struct ept_queue_item *item;
+	struct ept_queue_head *head;
+	unsigned phys;
+	int bit, num, len, in;
+	num = mv_ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+	in = (mv_ep->desc->bEndpointAddress & USB_DIR_IN) != 0;
+	item = items[2 * num + in];
+	head = epts + 2 * num + in;
+	phys = (unsigned)req->buf;
+	len = req->length;
+
+	item->next = TERMINATE;
+	item->info = INFO_BYTES(len) | INFO_IOC | INFO_ACTIVE;
+	item->page0 = phys;
+	item->page1 = (phys & 0xfffff000) + 0x1000;
+
+	head->next = (unsigned) item;
+	head->info = 0;
+
+	DBG("ept%d %s queue len %x, buffer %x\n",
+			num, in ? "in" : "out", len, phys);
+
+	if (in)
+		bit = EPT_TX(num);
+	else
+		bit = EPT_RX(num);
+
+	flush_cache(phys, len);
+	flush_cache((unsigned long)item, sizeof(struct ept_queue_item));
+	writel(bit, &udc->epprime);
+
+	return 0;
+}
+
+static void handle_ep_complete(struct mv_ep *ep)
+{
+	struct ept_queue_item *item;
+	int num, in, len;
+	num = ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+	in = (ep->desc->bEndpointAddress & USB_DIR_IN) != 0;
+	if (num == 0)
+		ep->desc = &ep0_out_desc;
+	item = items[2 * num + in];
+
+	if (item->info & 0xff)
+		printf("EP%d/%s FAIL nfo=%x pg0=%x\n",
+			num, in ? "in" : "out", item->info, item->page0);
+
+	len = (item->info >> 16) & 0x7fff;
+	ep->req.length -= len;
+	DBG("ept%d %s complete %x\n",
+			num, in ? "in" : "out", len);
+	ep->req.complete(&ep->ep, &ep->req);
+	if (num == 0) {
+		ep->req.length = 0;
+		usb_ep_queue(&ep->ep, &ep->req, 0);
+		ep->desc = &ep0_in_desc;
+	}
+}
+
+#define SETUP(type, request) (((type) << 8) | (request))
+
+static void handle_setup(void)
+{
+	struct usb_request *req = &ep[0].req;
+	struct mv_udc *udc = controller.udc;
+	struct ept_queue_head *head;
+	struct usb_ctrlrequest r;
+	int status = 0;
+	int num, in, _num, _in, i;
+	char *buf;
+	head = epts;
+
+	flush_cache((unsigned long)head, sizeof(struct ept_queue_head));
+	memcpy(&r, head->setup_data, sizeof(struct usb_ctrlrequest));
+	writel(EPT_RX(0), &udc->epstat);
+	DBG("handle setup %s, %x, %x index %x value %x\n", reqname(r.bRequest),
+	    r.bRequestType, r.bRequest, r.wIndex, r.wValue);
+
+	switch (SETUP(r.bRequestType, r.bRequest)) {
+	case SETUP(USB_RECIP_ENDPOINT, USB_REQ_CLEAR_FEATURE):
+		_num = r.wIndex & 15;
+		_in = !!(r.wIndex & 0x80);
+
+		if ((r.wValue == 0) && (r.wLength == 0)) {
+			req->length = 0;
+			for (i = 0; i < NUM_ENDPOINTS; i++) {
+				if (!ep[i].desc)
+					continue;
+				num = ep[i].desc->bEndpointAddress
+					& USB_ENDPOINT_NUMBER_MASK;
+				in = (ep[i].desc->bEndpointAddress
+						& USB_DIR_IN) != 0;
+				if ((num == _num) && (in == _in)) {
+					ep_enable(num, in);
+					usb_ep_queue(controller.gadget.ep0,
+							req, 0);
+					break;
+				}
+			}
+		}
+		return;
+
+	case SETUP(USB_RECIP_DEVICE, USB_REQ_SET_ADDRESS):
+		/*
+		 * write address delayed (will take effect
+		 * after the next IN txn)
+		 */
+		writel((r.wValue << 25) | (1 << 24), &udc->devaddr);
+		req->length = 0;
+		usb_ep_queue(controller.gadget.ep0, req, 0);
+		return;
+
+	case SETUP(USB_DIR_IN | USB_RECIP_DEVICE, USB_REQ_GET_STATUS):
+		req->length = 2;
+		buf = (char *)req->buf;
+		buf[0] = 1 << USB_DEVICE_SELF_POWERED;
+		buf[1] = 0;
+		usb_ep_queue(controller.gadget.ep0, req, 0);
+		return;
+	}
+	/* pass request up to the gadget driver */
+	if (controller.driver)
+		status = controller.driver->setup(&controller.gadget, &r);
+	else
+		status = -ENODEV;
+
+	if (!status)
+		return;
+	DBG("STALL reqname %s type %x value %x, index %x\n",
+	    reqname(r.bRequest), r.bRequestType, r.wValue, r.wIndex);
+	writel((1<<16) | (1 << 0), &udc->epctrl[0]);
+}
+
+static void stop_activity(void)
+{
+	int i, num, in;
+	struct ept_queue_head *head;
+	struct mv_udc *udc = controller.udc;
+	writel(readl(&udc->epcomp), &udc->epcomp);
+	writel(readl(&udc->epstat), &udc->epstat);
+	writel(0xffffffff, &udc->epflush);
+
+	/* error out any pending reqs */
+	for (i = 0; i < NUM_ENDPOINTS; i++) {
+		if (i != 0)
+			writel(0, &udc->epctrl[i]);
+		if (ep[i].desc) {
+			num = ep[i].desc->bEndpointAddress
+				& USB_ENDPOINT_NUMBER_MASK;
+			in = (ep[i].desc->bEndpointAddress & USB_DIR_IN) != 0;
+			head = epts + (num * 2) + (in);
+			head->info = INFO_ACTIVE;
+		}
+	}
+}
+
+void udc_irq(void)
+{
+	struct mv_udc *udc = controller.udc;
+	unsigned n = readl(&udc->usbsts);
+	writel(n, &udc->usbsts);
+	int bit, i, num, in;
+
+	n &= (STS_SLI | STS_URI | STS_PCI | STS_UI | STS_UEI);
+	if (n == 0)
+		return;
+
+	if (n & STS_URI) {
+		DBG("-- reset --\n");
+		stop_activity();
+	}
+	if (n & STS_SLI)
+		DBG("-- suspend --\n");
+
+	if (n & STS_PCI) {
+		DBG("-- portchange --\n");
+		bit = (readl(&udc->portsc) >> 26) & 3;
+		if (bit == 2) {
+			controller.gadget.speed = USB_SPEED_HIGH;
+			for (i = 1; i < NUM_ENDPOINTS && n; i++)
+				if (ep[i].desc)
+					ep[i].ep.maxpacket = 512;
+		} else {
+			controller.gadget.speed = USB_SPEED_FULL;
+		}
+	}
+
+	if (n & STS_UEI)
+		printf("<UEI %x>\n", readl(&udc->epcomp));
+
+	if ((n & STS_UI) || (n & STS_UEI)) {
+		n = readl(&udc->epstat);
+		if (n & EPT_RX(0))
+			handle_setup();
+
+		n = readl(&udc->epcomp);
+		if (n != 0)
+			writel(n, &udc->epcomp);
+
+		for (i = 0; i < NUM_ENDPOINTS && n; i++) {
+			if (ep[i].desc) {
+				num = ep[i].desc->bEndpointAddress
+					& USB_ENDPOINT_NUMBER_MASK;
+				in = (ep[i].desc->bEndpointAddress
+						& USB_DIR_IN) != 0;
+				bit = (in) ? EPT_TX(num) : EPT_RX(num);
+				if (n & bit)
+					handle_ep_complete(&ep[i]);
+			}
+		}
+	}
+}
+
+int usb_gadget_handle_interrupts(void)
+{
+	u32 value;
+	struct mv_udc *udc = controller.udc;
+
+	value = readl(&udc->usbsts);
+	if (value)
+		udc_irq();
+
+	return value;
+}
+
+static int mv_pullup(struct usb_gadget *gadget, int is_on)
+{
+	struct mv_udc *udc = controller.udc;
+	if (is_on) {
+		/* RESET */
+		writel(USBCMD_ITC(MICRO_8FRAME) | USBCMD_RST, &udc->usbcmd);
+		udelay(200);
+
+		writel((unsigned) epts, &udc->epinitaddr);
+
+		/* select DEVICE mode */
+		writel(USBMODE_DEVICE, &udc->usbmode);
+
+		writel(0xffffffff, &udc->epflush);
+
+		/* Turn on the USB connection by enabling the pullup resistor */
+		writel(USBCMD_ITC(MICRO_8FRAME) | USBCMD_RUN, &udc->usbcmd);
+	} else {
+		stop_activity();
+		writel(USBCMD_FS2, &udc->usbcmd);
+		udelay(800);
+		if (controller.driver)
+			controller.driver->disconnect(gadget);
+	}
+
+	return 0;
+}
+
+void udc_disconnect(void)
+{
+	struct mv_udc *udc = controller.udc;
+	/* disable pullup */
+	stop_activity();
+	writel(USBCMD_FS2, &udc->usbcmd);
+	udelay(800);
+	if (controller.driver)
+		controller.driver->disconnect(&controller.gadget);
+}
+
+static int mvudc_probe(void)
+{
+	struct ept_queue_head *head;
+	int i;
+
+	controller.gadget.ops = &mv_udc_ops;
+	controller.udc = (struct mv_udc *)CONFIG_USB_REG_BASE;
+	epts = memalign(PAGE_SIZE, QH_MAXNUM * sizeof(struct ept_queue_head));
+	memset(epts, 0, QH_MAXNUM * sizeof(struct ept_queue_head));
+	for (i = 0; i < 2 * NUM_ENDPOINTS; i++) {
+		/*
+		 * For item0 and item1, they are served as ep0
+		 * out&in seperately
+		 */
+		head = epts + i;
+		if (i < 2)
+			head->config = CONFIG_MAX_PKT(EP0_MAX_PACKET_SIZE)
+				| CONFIG_ZLT | CONFIG_IOS;
+		else
+			head->config = CONFIG_MAX_PKT(EP_MAX_PACKET_SIZE)
+				| CONFIG_ZLT;
+		head->next = TERMINATE;
+		head->info = 0;
+
+		items[i] = memalign(PAGE_SIZE, sizeof(struct ept_queue_item));
+	}
+
+	INIT_LIST_HEAD(&controller.gadget.ep_list);
+	ep[0].ep.maxpacket = 64;
+	ep[0].ep.name = "ep0";
+	ep[0].desc = &ep0_in_desc;
+	INIT_LIST_HEAD(&controller.gadget.ep0->ep_list);
+	for (i = 0; i < 2 * NUM_ENDPOINTS; i++) {
+		if (i != 0) {
+			ep[i].ep.maxpacket = 512;
+			ep[i].ep.name = "ep-";
+			list_add_tail(&ep[i].ep.ep_list,
+				      &controller.gadget.ep_list);
+			ep[i].desc = NULL;
+		}
+		ep[i].ep.ops = &mv_ep_ops;
+	}
+	return 0;
+}
+
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+	struct mv_udc *udc = controller.udc;
+	int             retval;
+
+	if (!driver
+			|| driver->speed < USB_SPEED_FULL
+			|| !driver->bind
+			|| !driver->setup) {
+		DBG("bad parameter.\n");
+		return -EINVAL;
+	}
+
+	if (!mvudc_probe()) {
+		usb_lowlevel_init();
+		/* select ULPI phy */
+		writel(PTS(PTS_ENABLE) | PFSC, &udc->portsc);
+	}
+	retval = driver->bind(&controller.gadget);
+	if (retval) {
+		DBG("driver->bind() returned %d\n", retval);
+		return retval;
+	}
+	controller.driver = driver;
+
+	return 0;
+}
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+	return 0;
+}

+ 100 - 83
drivers/usb/gadget/pxa27x_udc.c

@@ -26,11 +26,13 @@
 #include <common.h>
 #include <config.h>
 #include <asm/byteorder.h>
-#include <usbdcore.h>
-#include <usbdcore_ep0.h>
+#include <usbdevice.h>
 #include <asm/arch/hardware.h>
+#include <asm/io.h>
 #include <usb/pxa27x_udc.h>
 
+#include "ep0.h"
+
 /* number of endpoints on this UDC */
 #define UDC_MAX_ENDPOINTS	24
 
@@ -50,7 +52,7 @@ static void udc_dump_buffer(char *name, u8 *buf, int len)
 
 static inline void udc_ack_int_UDCCR(int mask)
 {
-	USIR1	= mask | USIR1;
+	writel(readl(USIR1) | mask, USIR1);
 }
 
 /*
@@ -68,9 +70,7 @@ static int udc_write_urb(struct usb_endpoint_instance *endpoint)
 {
 	struct urb *urb = endpoint->tx_urb;
 	int ep_num = endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK;
-	u32 *addr32 = (u32 *) &UDCDN(ep_num);
 	u32 *data32 = (u32 *) urb->buffer;
-	u8  *addr8 = (u8 *) &UDCDN(ep_num);
 	u8  *data8 = (u8 *) urb->buffer;
 	unsigned int i, n, w, b, is_short;
 	int timeout = 2000;	/* 2ms */
@@ -98,26 +98,28 @@ static int udc_write_urb(struct usb_endpoint_instance *endpoint)
 
 	/* Prepare for data send */
 	if (ep_num)
-		UDCCSN(ep_num) = UDCCSR_PC;
+		writel(UDCCSR_PC ,UDCCSN(ep_num));
 
 	for (i = 0; i < w; i++)
-		*addr32 = data32[endpoint->sent/4 + i];
+		  writel(data32[endpoint->sent / 4 + i], UDCDN(ep_num));
+
 	for (i = 0; i < b; i++)
-		*addr8 = data8[endpoint->sent + w*4 + i];
+		  writeb(data8[endpoint->sent + w * 4 + i], UDCDN(ep_num));
 
 	/* Set "Packet Complete" if less data then tx_packetSize */
 	if (is_short)
-		UDCCSN(ep_num) = ep_num ? UDCCSR_SP : UDCCSR0_IPR;
+		writel(ep_num ? UDCCSR_SP : UDCCSR0_IPR, UDCCSN(ep_num));
 
 	/* Wait for data sent */
-	while (!(UDCCSN(ep_num) & (ep_num ? UDCCSR_PC : UDCCSR0_IPR))) {
-		if (ep_num) {
+	if (ep_num) {
+		while (!(readl(UDCCSN(ep_num)) & UDCCSR_PC)) {
 			if (timeout-- == 0)
 				return -1;
 			else
 				udelay(1);
-		};
+		}
 	}
+
 	endpoint->last = n;
 
 	if (ep_num) {
@@ -127,7 +129,7 @@ static int udc_write_urb(struct usb_endpoint_instance *endpoint)
 		endpoint->last -= n;
 	}
 
-	if ((endpoint->tx_urb->actual_length - endpoint->sent) <= 0) {
+	if (endpoint->sent >= urb->actual_length) {
 		urb->actual_length = 0;
 		endpoint->sent = 0;
 		endpoint->last = 0;
@@ -148,7 +150,6 @@ static int udc_read_urb(struct usb_endpoint_instance *endpoint)
 {
 	struct urb *urb = endpoint->rcv_urb;
 	int ep_num = endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK;
-	u32 *addr32 = (u32 *) &UDCDN(ep_num);
 	u32 *data32 = (u32 *) urb->buffer;
 	unsigned int i, n, is_short ;
 
@@ -160,15 +161,15 @@ static int udc_read_urb(struct usb_endpoint_instance *endpoint)
 		endpoint->rcv_packetSize);
 #endif
 
-	if (UDCCSN(ep_num) & UDCCSR_BNE)
-		n = UDCBCN(ep_num) & 0x3ff;
+	if (readl(UDCCSN(ep_num)) & UDCCSR_BNE)
+		n = readl(UDCBCN(ep_num)) & 0x3ff;
 	else /* zlp */
 		n = 0;
 	is_short = n != endpoint->rcv_packetSize;
 
 	usbdbg("n %d%s", n, is_short ? "-s" : "");
 	for (i = 0; i < n; i += 4)
-		data32[urb->actual_length/4 + i/4] = *addr32;
+		data32[urb->actual_length / 4 + i / 4] = readl(UDCDN(ep_num));
 
 	udc_dump_buffer("urb read", (u8 *) data32, urb->actual_length + n);
 	usbd_rcv_complete(endpoint, n, 0);
@@ -178,27 +179,35 @@ static int udc_read_urb(struct usb_endpoint_instance *endpoint)
 
 static int udc_read_urb_ep0(void)
 {
-	u32 *addr32 = (u32 *) &UDCDN(0);
 	u32 *data32 = (u32 *) ep0_urb->buffer;
-	u8 *addr8 = (u8 *) &UDCDN(0);
 	u8 *data8 = (u8 *) ep0_urb->buffer;
 	unsigned int i, n, w, b;
 
-	n = UDCBCR0;
+	usbdbg("read urb on ep 0");
+#if defined(USBDDBG) && defined(USBDPARANOIA)
+	usbdbg("urb: buf %p, buf_len %d, actual_len %d",
+		ep0_urb->buffer, ep0_urb->buffer_length, ep0_urb->actual_length);
+#endif
+
+	n = readl(UDCBCR0);
 	w = n / 4;
 	b = n % 4;
 
 	for (i = 0; i < w; i++) {
-		data32[ep0_urb->actual_length/4 + i] = *addr32;
-		ep0_urb->actual_length += 4;
+		data32[ep0_urb->actual_length / 4 + i] = readl(UDCDN(0));
+//		ep0_urb->actual_length += 4;
 	}
 
 	for (i = 0; i < b; i++) {
-		data8[ep0_urb->actual_length + w*4 + i] = *addr8;
-		ep0_urb->actual_length++;
+		data8[ep0_urb->actual_length + w * 4 + i] = readb(UDCDN(0));
+//		ep0_urb->actual_length++;
 	}
 
-	UDCCSR0 = UDCCSR0_OPC | UDCCSR0_IPR;
+	ep0_urb->actual_length += n;
+
+	udc_dump_buffer("urb read", (u8 *) data32, ep0_urb->actual_length);
+
+	writel(UDCCSR0_OPC | UDCCSR0_IPR, UDCCSR0);
 	if (ep0_urb->actual_length == ep0_urb->device_request.wLength)
 		return 1;
 
@@ -207,7 +216,7 @@ static int udc_read_urb_ep0(void)
 
 static void udc_handle_ep0(struct usb_endpoint_instance *endpoint)
 {
-	u32 udccsr0 = UDCCSR0;
+	u32 udccsr0 = readl(UDCCSR0);
 	u32 *data = (u32 *) &ep0_urb->device_request;
 	int i;
 
@@ -216,7 +225,7 @@ static void udc_handle_ep0(struct usb_endpoint_instance *endpoint)
 	/* Clear stall status */
 	if (udccsr0 & UDCCSR0_SST) {
 		usberr("clear stall status");
-		UDCCSR0 = UDCCSR0_SST;
+		writel(UDCCSR0_SST, UDCCSR0);
 		ep0state = EP0_IDLE;
 	}
 
@@ -227,8 +236,7 @@ static void udc_handle_ep0(struct usb_endpoint_instance *endpoint)
 	switch (ep0state) {
 
 	case EP0_IDLE:
-
-		udccsr0 = UDCCSR0;
+		udccsr0 = readl(UDCCSR0);
 		/* Start control request? */
 		if ((udccsr0 & (UDCCSR0_OPC | UDCCSR0_SA | UDCCSR0_RNE))
 			== (UDCCSR0_OPC | UDCCSR0_SA | UDCCSR0_RNE)) {
@@ -238,15 +246,15 @@ static void udc_handle_ep0(struct usb_endpoint_instance *endpoint)
 			 */
 			usbdbg("try reading SETUP packet");
 			for (i = 0; i < 2; i++) {
-				if ((UDCCSR0 & UDCCSR0_RNE) == 0) {
+				if ((readl(UDCCSR0) & UDCCSR0_RNE) == 0) {
 					usberr("setup packet too short:%d", i);
 					goto stall;
 				}
-				data[i] = UDCDR0;
+				data[i] = readl(UDCDR0);
 			}
 
-			UDCCSR0 |= (UDCCSR0_OPC | UDCCSR0_SA);
-			if ((UDCCSR0 & UDCCSR0_RNE) != 0) {
+			writel(readl(UDCCSR0) | UDCCSR0_OPC | UDCCSR0_SA, UDCCSR0);
+			if ((readl(UDCCSR0) & UDCCSR0_RNE) != 0) {
 				usberr("setup packet too long");
 				goto stall;
 			}
@@ -261,7 +269,7 @@ static void udc_handle_ep0(struct usb_endpoint_instance *endpoint)
 								(u8 *)data, 8);
 					goto stall;
 				}
-				UDCCSR0 = UDCCSR0_IPR;
+				writel(UDCCSR0_IPR, UDCCSR0);
 				ep0state = EP0_IDLE;
 			} else {
 				/* Check direction */
@@ -274,7 +282,7 @@ static void udc_handle_ep0(struct usb_endpoint_instance *endpoint)
 					ep0_urb->buffer_length =
 						sizeof(ep0_urb->buffer_data);
 					ep0_urb->actual_length = 0;
-					UDCCSR0 = UDCCSR0_IPR;
+					writel(UDCCSR0_IPR, UDCCSR0);
 				} else {
 					/* The ep0_recv_setup function has
 					 * already placed our response packet
@@ -289,9 +297,9 @@ stall:
 							, (u8 *) data, 8);
 						ep0state = EP0_IDLE;
 
-						UDCCSR0 = UDCCSR0_SA |
+						writel(UDCCSR0_SA |
 						UDCCSR0_OPC | UDCCSR0_FST |
-						UDCCS0_FTF;
+						UDCCS0_FTF, UDCCSR0);
 
 						return;
 					}
@@ -317,7 +325,7 @@ stall:
 			 * - IPR cleared
 			 * - OPC got set, without SA (likely status stage)
 			 */
-			UDCCSR0 = udccsr0 & (UDCCSR0_SA | UDCCSR0_OPC);
+			writel(udccsr0 & (UDCCSR0_SA | UDCCSR0_OPC), UDCCSR0);
 		}
 		break;
 
@@ -351,7 +359,7 @@ read_complete:
 	case EP0_IN_DATA:
 		/* GET_DESCRIPTOR etc */
 		if (udccsr0 & UDCCSR0_OPC) {
-			UDCCSR0 = UDCCSR0_OPC | UDCCSR0_FTF;
+			writel(UDCCSR0_OPC | UDCCSR0_FTF, UDCCSR0);
 			usberr("ep0in premature status");
 			ep0state = EP0_IDLE;
 		} else {
@@ -364,14 +372,14 @@ read_complete:
 		break;
 
 	case EP0_XFER_COMPLETE:
-		UDCCSR0 = UDCCSR0_IPR;
+		writel(UDCCSR0_IPR, UDCCSR0);
 		ep0state = EP0_IDLE;
 		break;
 
 	default:
 		usbdbg("Default\n");
 	}
-	USIR0 = USIR0_IR0;
+	writel(USIR0_IR0, USIR0);
 }
 
 static void udc_handle_ep(struct usb_endpoint_instance *endpoint)
@@ -380,33 +388,33 @@ static void udc_handle_ep(struct usb_endpoint_instance *endpoint)
 	int ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK;
 	int ep_isout = (ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT;
 
-	u32 flags = UDCCSN(ep_num) & (UDCCSR_SST | UDCCSR_TRN);
+	u32 flags = readl(UDCCSN(ep_num)) & (UDCCSR_SST | UDCCSR_TRN);
 	if (flags)
-		UDCCSN(ep_num) = flags;
+		writel(flags, UDCCSN(ep_num));
 
 	if (ep_isout)
 		udc_read_urb(endpoint);
 	else
 		udc_write_urb(endpoint);
 
-	UDCCSN(ep_num) = UDCCSR_PC;
+	writel(UDCCSR_PC, UDCCSN(ep_num));
 }
 
 static void udc_state_changed(void)
 {
 	int config, interface, alternate;
 
-	UDCCR |= UDCCR_SMAC;
+	writel(readl(UDCCR) | UDCCR_SMAC, UDCCR);
 
-	config = (UDCCR & UDCCR_ACN) >> UDCCR_ACN_S;
-	interface = (UDCCR & UDCCR_AIN) >> UDCCR_AIN_S;
-	alternate = (UDCCR & UDCCR_AAISN) >> UDCCR_AAISN_S;
+	config = (readl(UDCCR) & UDCCR_ACN) >> UDCCR_ACN_S;
+	interface = (readl(UDCCR) & UDCCR_AIN) >> UDCCR_AIN_S;
+	alternate = (readl(UDCCR) & UDCCR_AAISN) >> UDCCR_AAISN_S;
 
 	usbdbg("New UDC settings are: conf %d - inter %d - alter %d",
 		config, interface, alternate);
 
 	usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0);
-	UDCISR1 = UDCISR1_IRCC;
+	writel(UDCISR1_IRCC, UDCISR1);
 }
 
 void udc_irq(void)
@@ -419,7 +427,7 @@ void udc_irq(void)
 	do {
 		handled = 0;
 		/* Suspend Interrupt Request */
-		if (USIR1 & UDCCR_SUSIR) {
+		if (readl(USIR1) & UDCCR_SUSIR) {
 			usbdbg("Suspend\n");
 			udc_ack_int_UDCCR(UDCCR_SUSIR);
 			handled = 1;
@@ -427,35 +435,35 @@ void udc_irq(void)
 		}
 
 		/* Resume Interrupt Request */
-		if (USIR1 & UDCCR_RESIR) {
+		if (readl(USIR1) & UDCCR_RESIR) {
 			udc_ack_int_UDCCR(UDCCR_RESIR);
 			handled = 1;
 			usbdbg("USB resume\n");
 		}
 
-		if (USIR1 & (1<<31)) {
+		if (readl(USIR1) & (1<<31)) {
 			handled = 1;
 			udc_state_changed();
 		}
 
 		/* Reset Interrupt Request */
-		if (USIR1 & UDCCR_RSTIR) {
+		if (readl(USIR1) & UDCCR_RSTIR) {
 			udc_ack_int_UDCCR(UDCCR_RSTIR);
 			handled = 1;
 			usbdbg("Reset\n");
 			usbd_device_event_irq(udc_device, DEVICE_RESET, 0);
 		} else {
-			if (USIR0)
-				usbdbg("UISR0: %x \n", USIR0);
+			if (readl(USIR0))
+				usbdbg("UISR0: %x \n", readl(USIR0));
 
-			if (USIR0 & 0x2)
-				USIR0 = 0x2;
+			if (readl(USIR0) & 0x2)
+				writel(0x2, USIR0);
 
 			/* Control traffic */
-			if (USIR0  & USIR0_IR0) {
+			if (readl(USIR0)  & USIR0_IR0) {
 				handled = 1;
+				writel(USIR0_IR0, USIR0);
 				udc_handle_ep0(udc_device->bus->endpoint_array);
-				USIR0 = USIR0_IR0;
 			}
 
 			endpoint = udc_device->bus->endpoint_array;
@@ -464,11 +472,11 @@ void udc_irq(void)
 						USB_ENDPOINT_NUMBER_MASK;
 				if (!ep_num)
 					continue;
-				udcisr0 = UDCISR0;
+				udcisr0 = readl(UDCISR0);
 				if (udcisr0 &
 					UDCISR_INT(ep_num, UDC_INT_PACKETCMP)) {
-					UDCISR0 = UDCISR_INT(ep_num,
-							 UDC_INT_PACKETCMP);
+					writel(UDCISR_INT(ep_num, UDC_INT_PACKETCMP),
+					       UDCISR0);
 					udc_handle_ep(&endpoint[i]);
 				}
 			}
@@ -485,21 +493,21 @@ void udc_irq(void)
 
 static inline void udc_set_mask_UDCCR(int mask)
 {
-    UDCCR = (UDCCR & UDCCR_MASK_BITS) | (mask & UDCCR_MASK_BITS);
+    writel((readl(UDCCR) & UDCCR_MASK_BITS) | (mask & UDCCR_MASK_BITS), UDCCR);
 }
 
 static inline void udc_clear_mask_UDCCR(int mask)
 {
-    UDCCR = (UDCCR & UDCCR_MASK_BITS) & ~(mask & UDCCR_MASK_BITS);
+    writel((readl(UDCCR) & UDCCR_MASK_BITS) & ~(mask & UDCCR_MASK_BITS), UDCCR);
 }
 
 static void pio_irq_enable(int ep_num)
 {
 	if (ep_num < 16)
-		UDCICR0 |= 3 << (ep_num * 2);
+		writel(readl(UDCICR0) | 3 << (ep_num * 2), UDCICR0);
 	else {
 		ep_num -= 16;
-		UDCICR1 |= 3 << (ep_num * 2);
+		writel(readl(UDCICR1) | 3 << (ep_num * 2), UDCICR1);
 	}
 }
 
@@ -589,22 +597,26 @@ void udc_setup_ep(struct usb_device_instance *device, unsigned int id,
 	tmp |= (ep_size << UDCCONR_MPS_S) & UDCCONR_MPS;
 	tmp |= UDCCONR_EE;
 
-	UDCCN(ep_num) = tmp;
+	writel(tmp, UDCCN(ep_num));
 
-	usbdbg("UDCCR%c = %x", 'A' + ep_num-1, UDCCN(ep_num));
-	usbdbg("UDCCSR%c = %x", 'A' + ep_num-1, UDCCSN(ep_num));
+	//usbdbg
+	usbdbg("UDCCR%c = %x", 'A' + ep_num-1, readl(UDCCN(ep_num)));
+	usbdbg("UDCCSR%c = %x", 'A' + ep_num-1, readl(UDCCSN(ep_num)));
 }
 
-#define CONFIG_USB_DEV_PULLUP_GPIO 87
-
 /* Connect the USB device to the bus */
 void udc_connect(void)
 {
 	usbdbg("UDC connect");
 
+#ifdef CONFIG_USB_DEV_PULLUP_GPIO
 	/* Turn on the USB connection by enabling the pullup resistor */
 	set_GPIO_mode(CONFIG_USB_DEV_PULLUP_GPIO | GPIO_OUT);
-	GPSR(CONFIG_USB_DEV_PULLUP_GPIO) = GPIO_bit(CONFIG_USB_DEV_PULLUP_GPIO);
+	writel(GPIO_bit(CONFIG_USB_DEV_PULLUP_GPIO), GPSR(CONFIG_USB_DEV_PULLUP_GPIO));
+#else
+	/* Host port 2 transceiver D+ pull up enable */
+	writel(readl(UP2OCR) | UP2OCR_DPPUE, UP2OCR);
+#endif
 }
 
 /* Disconnect the USB device to the bus */
@@ -612,8 +624,13 @@ void udc_disconnect(void)
 {
 	usbdbg("UDC disconnect");
 
+#ifdef CONFIG_USB_DEV_PULLUP_GPIO
 	/* Turn off the USB connection by disabling the pullup resistor */
-	GPCR(CONFIG_USB_DEV_PULLUP_GPIO) = GPIO_bit(CONFIG_USB_DEV_PULLUP_GPIO);
+	writel(GPIO_bit(CONFIG_USB_DEV_PULLUP_GPIO), GPCR(CONFIG_USB_DEV_PULLUP_GPIO));
+#else
+	/* Host port 2 transceiver D+ pull up disable */
+	writel(readl(UP2OCR) & ~UP2OCR_DPPUE, UP2OCR);
+#endif
 }
 
 /* Switch on the UDC */
@@ -621,15 +638,14 @@ void udc_enable(struct usb_device_instance *device)
 {
 
 	ep0state = EP0_IDLE;
-	CKEN |= CKEN11_USB;
 
 	/* enable endpoint 0, A, B's Packet Complete Interrupt. */
-	UDCICR0 = 0x0000003f;
-	UDCICR1 = 0xa8000000;
+	writel(0xffffffff, UDCICR0);
+	writel(0xa8000000, UDCICR1);
 
 	/* clear the interrupt status/control registers */
-	UDCISR0 = 0xffffffff;
-	UDCISR1 = 0xffffffff;
+	writel(0xffffffff, UDCISR0);
+	writel(0xffffffff, UDCISR1);
 
 	/* set UDC-enable */
 	udc_set_mask_UDCCR(UDCCR_UDE);
@@ -652,7 +668,7 @@ void udc_disable(void)
 	udc_clear_mask_UDCCR(UDCCR_UDE);
 
 	/* Disable clock for USB device */
-	CKEN &= ~CKEN11_USB;
+	writel(readl(CKEN) & ~CKEN11_USB, CKEN);
 
 	/* Free ep0 URB */
 	if (ep0_urb) {
@@ -689,14 +705,15 @@ int udc_init(void)
 	udc_device = NULL;
 	usbdbg("PXA27x usbd start");
 
+	/* Enable clock for USB device */
+	writel(readl(CKEN) | CKEN11_USB, CKEN);
+
 	/* Disable the UDC */
 	udc_clear_mask_UDCCR(UDCCR_UDE);
 
-	/* Disable clock for USB device */
-	CKEN &= ~CKEN11_USB;
-
 	/* Disable IRQs: we don't use them */
-	UDCICR0 = UDCICR1 = 0;
+	writel(0, UDCICR0);
+	writel(0, UDCICR1);
 
 	return 0;
 }

+ 271 - 0
drivers/usb/gadget/regs-otg.h

@@ -0,0 +1,271 @@
+/* linux/arch/arm/plat-s3c/include/plat/regs-otg.h
+ *
+ * Copyright (C) 2004 Herbert Poetzl <herbert@13thfloor.at>
+ *
+ * Registers remapping:
+ * Lukasz Majewski <l.majewski@samsumg.com>
+ *
+ * This include file 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.
+ */
+
+#ifndef __ASM_ARCH_REGS_USB_OTG_HS_H
+#define __ASM_ARCH_REGS_USB_OTG_HS_H
+
+/* USB2.0 OTG Controller register */
+struct s3c_usbotg_phy {
+	u32 phypwr;
+	u32 phyclk;
+	u32 rstcon;
+};
+
+/* Device Logical IN Endpoint-Specific Registers */
+struct s3c_dev_in_endp {
+	u32 diepctl;
+	u8  res1[4];
+	u32 diepint;
+	u8  res2[4];
+	u32 dieptsiz;
+	u32 diepdma;
+	u8  res3[4];
+	u32 diepdmab;
+};
+
+/* Device Logical OUT Endpoint-Specific Registers */
+struct s3c_dev_out_endp {
+	u32 doepctl;
+	u8  res1[4];
+	u32 doepint;
+	u8  res2[4];
+	u32 doeptsiz;
+	u32 doepdma;
+	u8  res3[4];
+	u32 doepdmab;
+};
+
+struct ep_fifo {
+	u32 fifo;
+	u8  res[4092];
+};
+
+/* USB2.0 OTG Controller register */
+struct s3c_usbotg_reg {
+	/* Core Global Registers */
+	u32 gotgctl; /* OTG Control & Status */
+	u32 gotgint; /* OTG Interrupt */
+	u32 gahbcfg; /* Core AHB Configuration */
+	u32 gusbcfg; /* Core USB Configuration */
+	u32 grstctl; /* Core Reset */
+	u32 gintsts; /* Core Interrupt */
+	u32 gintmsk; /* Core Interrupt Mask */
+	u32 grxstsr; /* Receive Status Debug Read/Status Read */
+	u32 grxstsp; /* Receive Status Debug Pop/Status Pop */
+	u32 grxfsiz; /* Receive FIFO Size */
+	u32 gnptxfsiz; /* Non-Periodic Transmit FIFO Size */
+	u8  res1[216];
+	u32 dieptxf[15]; /* Device Periodic Transmit FIFO size register */
+	u8  res2[1728];
+	/* Device Configuration */
+	u32 dcfg; /* Device Configuration Register */
+	u32 dctl; /* Device Control */
+	u32 dsts; /* Device Status */
+	u8  res3[4];
+	u32 diepmsk; /* Device IN Endpoint Common Interrupt Mask */
+	u32 doepmsk; /* Device OUT Endpoint Common Interrupt Mask */
+	u32 daint; /* Device All Endpoints Interrupt */
+	u32 daintmsk; /* Device All Endpoints Interrupt Mask */
+	u8  res4[224];
+	struct s3c_dev_in_endp in_endp[16];
+	struct s3c_dev_out_endp out_endp[16];
+	u8  res5[768];
+	struct ep_fifo ep[16];
+};
+
+/*===================================================================== */
+/*definitions related to CSR setting */
+
+/* S3C_UDC_OTG_GOTGCTL */
+#define B_SESSION_VALID		(0x1<<19)
+#define A_SESSION_VALID		(0x1<<18)
+
+/* S3C_UDC_OTG_GAHBCFG */
+#define PTXFE_HALF			(0<<8)
+#define PTXFE_ZERO			(1<<8)
+#define NPTXFE_HALF			(0<<7)
+#define NPTXFE_ZERO			(1<<7)
+#define MODE_SLAVE			(0<<5)
+#define MODE_DMA			(1<<5)
+#define BURST_SINGLE			(0<<1)
+#define BURST_INCR			(1<<1)
+#define BURST_INCR4			(3<<1)
+#define BURST_INCR8			(5<<1)
+#define BURST_INCR16			(7<<1)
+#define GBL_INT_UNMASK			(1<<0)
+#define GBL_INT_MASK			(0<<0)
+
+/* S3C_UDC_OTG_GRSTCTL */
+#define AHB_MASTER_IDLE		(1u<<31)
+#define CORE_SOFT_RESET		(0x1<<0)
+
+/* S3C_UDC_OTG_GINTSTS/S3C_UDC_OTG_GINTMSK core interrupt register */
+#define INT_RESUME			(1u<<31)
+#define INT_DISCONN			(0x1<<29)
+#define INT_CONN_ID_STS_CNG		(0x1<<28)
+#define INT_OUT_EP			(0x1<<19)
+#define INT_IN_EP			(0x1<<18)
+#define INT_ENUMDONE			(0x1<<13)
+#define INT_RESET			(0x1<<12)
+#define INT_SUSPEND			(0x1<<11)
+#define INT_EARLY_SUSPEND		(0x1<<10)
+#define INT_NP_TX_FIFO_EMPTY		(0x1<<5)
+#define INT_RX_FIFO_NOT_EMPTY		(0x1<<4)
+#define INT_SOF			(0x1<<3)
+#define INT_DEV_MODE			(0x0<<0)
+#define INT_HOST_MODE			(0x1<<1)
+#define INT_GOUTNakEff			(0x01<<7)
+#define INT_GINNakEff			(0x01<<6)
+
+#define FULL_SPEED_CONTROL_PKT_SIZE	8
+#define FULL_SPEED_BULK_PKT_SIZE	64
+
+#define HIGH_SPEED_CONTROL_PKT_SIZE	64
+#define HIGH_SPEED_BULK_PKT_SIZE	512
+
+#define RX_FIFO_SIZE			(1024*4)
+#define NPTX_FIFO_SIZE			(1024*4)
+#define PTX_FIFO_SIZE			(1536*1)
+
+#define DEPCTL_TXFNUM_0		(0x0<<22)
+#define DEPCTL_TXFNUM_1		(0x1<<22)
+#define DEPCTL_TXFNUM_2		(0x2<<22)
+#define DEPCTL_TXFNUM_3		(0x3<<22)
+#define DEPCTL_TXFNUM_4		(0x4<<22)
+
+/* Enumeration speed */
+#define USB_HIGH_30_60MHZ		(0x0<<1)
+#define USB_FULL_30_60MHZ		(0x1<<1)
+#define USB_LOW_6MHZ			(0x2<<1)
+#define USB_FULL_48MHZ			(0x3<<1)
+
+/* S3C_UDC_OTG_GRXSTSP STATUS */
+#define OUT_PKT_RECEIVED		(0x2<<17)
+#define OUT_TRANSFER_COMPLELTED	(0x3<<17)
+#define SETUP_TRANSACTION_COMPLETED	(0x4<<17)
+#define SETUP_PKT_RECEIVED		(0x6<<17)
+#define GLOBAL_OUT_NAK			(0x1<<17)
+
+/* S3C_UDC_OTG_DCTL device control register */
+#define NORMAL_OPERATION		(0x1<<0)
+#define SOFT_DISCONNECT		(0x1<<1)
+
+/* S3C_UDC_OTG_DAINT device all endpoint interrupt register */
+#define DAINT_OUT_BIT			(16)
+#define DAINT_MASK			(0xFFFF)
+
+/* S3C_UDC_OTG_DIEPCTL0/DOEPCTL0 device
+   control IN/OUT endpoint 0 control register */
+#define DEPCTL_EPENA			(0x1<<31)
+#define DEPCTL_EPDIS			(0x1<<30)
+#define DEPCTL_SETD1PID		(0x1<<29)
+#define DEPCTL_SETD0PID		(0x1<<28)
+#define DEPCTL_SNAK			(0x1<<27)
+#define DEPCTL_CNAK			(0x1<<26)
+#define DEPCTL_STALL			(0x1<<21)
+#define DEPCTL_TYPE_BIT		(18)
+#define DEPCTL_TYPE_MASK		(0x3<<18)
+#define DEPCTL_CTRL_TYPE		(0x0<<18)
+#define DEPCTL_ISO_TYPE		(0x1<<18)
+#define DEPCTL_BULK_TYPE		(0x2<<18)
+#define DEPCTL_INTR_TYPE		(0x3<<18)
+#define DEPCTL_USBACTEP		(0x1<<15)
+#define DEPCTL_NEXT_EP_BIT		(11)
+#define DEPCTL_MPS_BIT			(0)
+#define DEPCTL_MPS_MASK		(0x7FF)
+
+#define DEPCTL0_MPS_64			(0x0<<0)
+#define DEPCTL0_MPS_32			(0x1<<0)
+#define DEPCTL0_MPS_16			(0x2<<0)
+#define DEPCTL0_MPS_8			(0x3<<0)
+#define DEPCTL_MPS_BULK_512		(512<<0)
+#define DEPCTL_MPS_INT_MPS_16		(16<<0)
+
+#define DIEPCTL0_NEXT_EP_BIT		(11)
+
+
+/* S3C_UDC_OTG_DIEPMSK/DOEPMSK device IN/OUT endpoint
+   common interrupt mask register */
+/* S3C_UDC_OTG_DIEPINTn/DOEPINTn device IN/OUT endpoint interrupt register */
+#define BACK2BACK_SETUP_RECEIVED	(0x1<<6)
+#define INTKNEPMIS			(0x1<<5)
+#define INTKN_TXFEMP			(0x1<<4)
+#define NON_ISO_IN_EP_TIMEOUT		(0x1<<3)
+#define CTRL_OUT_EP_SETUP_PHASE_DONE	(0x1<<3)
+#define AHB_ERROR			(0x1<<2)
+#define EPDISBLD			(0x1<<1)
+#define TRANSFER_DONE			(0x1<<0)
+
+#define USB_PHY_CTRL_EN0                (0x1 << 0)
+
+/* OPHYPWR */
+#define PHY_0_SLEEP                     (0x1 << 5)
+#define OTG_DISABLE_0                   (0x1 << 4)
+#define ANALOG_PWRDOWN                  (0x1 << 3)
+#define FORCE_SUSPEND_0                 (0x1 << 0)
+
+/* URSTCON */
+#define HOST_SW_RST                     (0x1 << 4)
+#define PHY_SW_RST1                     (0x1 << 3)
+#define PHYLNK_SW_RST                   (0x1 << 2)
+#define LINK_SW_RST                     (0x1 << 1)
+#define PHY_SW_RST0                     (0x1 << 0)
+
+/* OPHYCLK */
+#define COMMON_ON_N1                    (0x1 << 7)
+#define COMMON_ON_N0                    (0x1 << 4)
+#define ID_PULLUP0                      (0x1 << 2)
+#define CLK_SEL_24MHZ                   (0x3 << 0)
+#define CLK_SEL_12MHZ                   (0x2 << 0)
+#define CLK_SEL_48MHZ                   (0x0 << 0)
+
+/* Device Configuration Register DCFG */
+#define DEV_SPEED_HIGH_SPEED_20         (0x0 << 0)
+#define DEV_SPEED_FULL_SPEED_20         (0x1 << 0)
+#define DEV_SPEED_LOW_SPEED_11          (0x2 << 0)
+#define DEV_SPEED_FULL_SPEED_11         (0x3 << 0)
+#define EP_MISS_CNT(x)                  (x << 18)
+#define DEVICE_ADDRESS(x)               (x << 4)
+
+/* Core Reset Register (GRSTCTL) */
+#define TX_FIFO_FLUSH                   (0x1 << 5)
+#define RX_FIFO_FLUSH                   (0x1 << 4)
+#define TX_FIFO_NUMBER(x)               (x << 6)
+#define TX_FIFO_FLUSH_ALL               TX_FIFO_NUMBER(0x10)
+
+/* Masks definitions */
+#define GINTMSK_INIT	(INT_OUT_EP | INT_IN_EP | INT_RESUME | INT_ENUMDONE\
+			| INT_RESET | INT_SUSPEND)
+#define DOEPMSK_INIT	(CTRL_OUT_EP_SETUP_PHASE_DONE | AHB_ERROR|TRANSFER_DONE)
+#define DIEPMSK_INIT	(NON_ISO_IN_EP_TIMEOUT|AHB_ERROR|TRANSFER_DONE)
+#define GAHBCFG_INIT	(PTXFE_HALF | NPTXFE_HALF | MODE_DMA | BURST_INCR4\
+			| GBL_INT_UNMASK)
+
+/* Device Endpoint X Transfer Size Register (DIEPTSIZX) */
+#define DIEPT_SIZ_PKT_CNT(x)                      (x << 19)
+#define DIEPT_SIZ_XFER_SIZE(x)                    (x << 0)
+
+/* Device OUT Endpoint X Transfer Size Register (DOEPTSIZX) */
+#define DOEPT_SIZ_PKT_CNT(x)                      (x << 19)
+#define DOEPT_SIZ_XFER_SIZE(x)                    (x << 0)
+#define DOEPT_SIZ_XFER_SIZE_MAX_EP0               (0x7F << 0)
+#define DOEPT_SIZ_XFER_SIZE_MAX_EP                (0x7FFF << 0)
+
+/* Device Endpoint-N Control Register (DIEPCTLn/DOEPCTLn) */
+#define DIEPCTL_TX_FIFO_NUM(x)                    (x << 22)
+#define DIEPCTL_TX_FIFO_NUM_MASK                  (~DIEPCTL_TX_FIFO_NUM(0xF))
+
+/* Device ALL Endpoints Interrupt Register (DAINT) */
+#define DAINT_IN_EP_INT(x)                        (x << 0)
+#define DAINT_OUT_EP_INT(x)                       (x << 16)
+#endif

+ 892 - 0
drivers/usb/gadget/s3c_udc_otg.c

@@ -0,0 +1,892 @@
+/*
+ * drivers/usb/gadget/s3c_udc_otg.c
+ * Samsung S3C on-chip full/high speed USB OTG 2.0 device controllers
+ *
+ * Copyright (C) 2008 for Samsung Electronics
+ *
+ * BSP Support for Samsung's UDC driver
+ * available at:
+ * git://git.kernel.org/pub/scm/linux/kernel/git/kki_ap/linux-2.6-samsung.git
+ *
+ * State machine bugfixes:
+ * Marek Szyprowski <m.szyprowski@samsung.com>
+ *
+ * Ported to u-boot:
+ * Marek Szyprowski <m.szyprowski@samsung.com>
+ * Lukasz Majewski <l.majewski@samsumg.com>
+ *
+ * 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 <common.h>
+#include <asm/errno.h>
+#include <linux/list.h>
+#include <malloc.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+
+#include <asm/mach-types.h>
+#include <asm/arch/gpio.h>
+
+#include "regs-otg.h"
+#include <usb/s3c_udc.h>
+#include <usb/lin_gadget_compat.h>
+
+/***********************************************************/
+
+#define OTG_DMA_MODE		1
+
+#undef DEBUG_S3C_UDC_SETUP
+#undef DEBUG_S3C_UDC_EP0
+#undef DEBUG_S3C_UDC_ISR
+#undef DEBUG_S3C_UDC_OUT_EP
+#undef DEBUG_S3C_UDC_IN_EP
+#undef DEBUG_S3C_UDC
+
+/* #define DEBUG_S3C_UDC_SETUP */
+/* #define DEBUG_S3C_UDC_EP0 */
+/* #define DEBUG_S3C_UDC_ISR */
+/* #define DEBUG_S3C_UDC_OUT_EP */
+/* #define DEBUG_S3C_UDC_IN_EP */
+/* #define DEBUG_S3C_UDC */
+
+#include <usb/s3c_udc.h>
+
+#define EP0_CON		0
+#define EP_MASK		0xF
+
+#if defined(DEBUG_S3C_UDC_SETUP) || defined(DEBUG_S3C_UDC_ISR)	  \
+	|| defined(DEBUG_S3C_UDC_OUT_EP)
+static char *state_names[] = {
+	"WAIT_FOR_SETUP",
+	"DATA_STATE_XMIT",
+	"DATA_STATE_NEED_ZLP",
+	"WAIT_FOR_OUT_STATUS",
+	"DATA_STATE_RECV",
+	"WAIT_FOR_COMPLETE",
+	"WAIT_FOR_OUT_COMPLETE",
+	"WAIT_FOR_IN_COMPLETE",
+	"WAIT_FOR_NULL_COMPLETE",
+};
+#endif
+
+#define DRIVER_DESC "S3C HS USB OTG Device Driver, (c) Samsung Electronics"
+#define DRIVER_VERSION "15 March 2009"
+
+struct s3c_udc	*the_controller;
+
+static const char driver_name[] = "s3c-udc";
+static const char driver_desc[] = DRIVER_DESC;
+static const char ep0name[] = "ep0-control";
+
+/* Max packet size*/
+static unsigned int ep0_fifo_size = 64;
+static unsigned int ep_fifo_size =  512;
+static unsigned int ep_fifo_size2 = 1024;
+static int reset_available = 1;
+
+static struct usb_ctrlrequest *usb_ctrl;
+static dma_addr_t usb_ctrl_dma_addr;
+
+/*
+  Local declarations.
+*/
+static int s3c_ep_enable(struct usb_ep *ep,
+			 const struct usb_endpoint_descriptor *);
+static int s3c_ep_disable(struct usb_ep *ep);
+static struct usb_request *s3c_alloc_request(struct usb_ep *ep,
+					     gfp_t gfp_flags);
+static void s3c_free_request(struct usb_ep *ep, struct usb_request *);
+
+static int s3c_queue(struct usb_ep *ep, struct usb_request *, gfp_t gfp_flags);
+static int s3c_dequeue(struct usb_ep *ep, struct usb_request *);
+static int s3c_fifo_status(struct usb_ep *ep);
+static void s3c_fifo_flush(struct usb_ep *ep);
+static void s3c_ep0_read(struct s3c_udc *dev);
+static void s3c_ep0_kick(struct s3c_udc *dev, struct s3c_ep *ep);
+static void s3c_handle_ep0(struct s3c_udc *dev);
+static int s3c_ep0_write(struct s3c_udc *dev);
+static int write_fifo_ep0(struct s3c_ep *ep, struct s3c_request *req);
+static void done(struct s3c_ep *ep, struct s3c_request *req, int status);
+static void stop_activity(struct s3c_udc *dev,
+			  struct usb_gadget_driver *driver);
+static int udc_enable(struct s3c_udc *dev);
+static void udc_set_address(struct s3c_udc *dev, unsigned char address);
+static void reconfig_usbd(void);
+static void set_max_pktsize(struct s3c_udc *dev, enum usb_device_speed speed);
+static void nuke(struct s3c_ep *ep, int status);
+static int s3c_udc_set_halt(struct usb_ep *_ep, int value);
+static void s3c_udc_set_nak(struct s3c_ep *ep);
+
+static struct usb_ep_ops s3c_ep_ops = {
+	.enable = s3c_ep_enable,
+	.disable = s3c_ep_disable,
+
+	.alloc_request = s3c_alloc_request,
+	.free_request = s3c_free_request,
+
+	.queue = s3c_queue,
+	.dequeue = s3c_dequeue,
+
+	.set_halt = s3c_udc_set_halt,
+	.fifo_status = s3c_fifo_status,
+	.fifo_flush = s3c_fifo_flush,
+};
+
+#define create_proc_files() do {} while (0)
+#define remove_proc_files() do {} while (0)
+
+/***********************************************************/
+
+void __iomem		*regs_otg;
+struct s3c_usbotg_reg *reg;
+struct s3c_usbotg_phy *phy;
+static unsigned int usb_phy_ctrl;
+
+void otg_phy_init(struct s3c_udc *dev)
+{
+	dev->pdata->phy_control(1);
+
+	/*USB PHY0 Enable */
+	printf("USB PHY0 Enable\n");
+
+	/* Enable PHY */
+	writel(readl(usb_phy_ctrl) | USB_PHY_CTRL_EN0, usb_phy_ctrl);
+
+	if (dev->pdata->usb_flags == PHY0_SLEEP) /* C210 Universal */
+		writel((readl(&phy->phypwr)
+			&~(PHY_0_SLEEP | OTG_DISABLE_0 | ANALOG_PWRDOWN)
+			&~FORCE_SUSPEND_0), &phy->phypwr);
+	else /* C110 GONI */
+		writel((readl(&phy->phypwr) &~(OTG_DISABLE_0 | ANALOG_PWRDOWN)
+			&~FORCE_SUSPEND_0), &phy->phypwr);
+
+	writel((readl(&phy->phyclk) &~(ID_PULLUP0 | COMMON_ON_N0)) |
+	       CLK_SEL_24MHZ, &phy->phyclk); /* PLL 24Mhz */
+
+	writel((readl(&phy->rstcon) &~(LINK_SW_RST | PHYLNK_SW_RST))
+	       | PHY_SW_RST0, &phy->rstcon);
+	udelay(10);
+	writel(readl(&phy->rstcon)
+	       &~(PHY_SW_RST0 | LINK_SW_RST | PHYLNK_SW_RST), &phy->rstcon);
+	udelay(10);
+}
+
+void otg_phy_off(struct s3c_udc *dev)
+{
+	/* reset controller just in case */
+	writel(PHY_SW_RST0, &phy->rstcon);
+	udelay(20);
+	writel(readl(&phy->phypwr) &~PHY_SW_RST0, &phy->rstcon);
+	udelay(20);
+
+	writel(readl(&phy->phypwr) | OTG_DISABLE_0 | ANALOG_PWRDOWN
+	       | FORCE_SUSPEND_0, &phy->phypwr);
+
+	writel(readl(usb_phy_ctrl) &~USB_PHY_CTRL_EN0, usb_phy_ctrl);
+
+	writel((readl(&phy->phyclk) & ~(ID_PULLUP0 | COMMON_ON_N0)),
+	      &phy->phyclk);
+
+	udelay(10000);
+
+	dev->pdata->phy_control(0);
+}
+
+/***********************************************************/
+
+#include "s3c_udc_otg_xfer_dma.c"
+
+/*
+ *	udc_disable - disable USB device controller
+ */
+static void udc_disable(struct s3c_udc *dev)
+{
+	DEBUG_SETUP("%s: %p\n", __func__, dev);
+
+	udc_set_address(dev, 0);
+
+	dev->ep0state = WAIT_FOR_SETUP;
+	dev->gadget.speed = USB_SPEED_UNKNOWN;
+	dev->usb_address = 0;
+
+	otg_phy_off(dev);
+}
+
+/*
+ *	udc_reinit - initialize software state
+ */
+static void udc_reinit(struct s3c_udc *dev)
+{
+	unsigned int i;
+
+	DEBUG_SETUP("%s: %p\n", __func__, dev);
+
+	/* device/ep0 records init */
+	INIT_LIST_HEAD(&dev->gadget.ep_list);
+	INIT_LIST_HEAD(&dev->gadget.ep0->ep_list);
+	dev->ep0state = WAIT_FOR_SETUP;
+
+	/* basic endpoint records init */
+	for (i = 0; i < S3C_MAX_ENDPOINTS; i++) {
+		struct s3c_ep *ep = &dev->ep[i];
+
+		if (i != 0)
+			list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list);
+
+		ep->desc = 0;
+		ep->stopped = 0;
+		INIT_LIST_HEAD(&ep->queue);
+		ep->pio_irqs = 0;
+	}
+
+	/* the rest was statically initialized, and is read-only */
+}
+
+#define BYTES2MAXP(x)	(x / 8)
+#define MAXP2BYTES(x)	(x * 8)
+
+/* until it's enabled, this UDC should be completely invisible
+ * to any USB host.
+ */
+static int udc_enable(struct s3c_udc *dev)
+{
+	DEBUG_SETUP("%s: %p\n", __func__, dev);
+
+	otg_phy_init(dev);
+	reconfig_usbd();
+
+	DEBUG_SETUP("S3C USB 2.0 OTG Controller Core Initialized : 0x%x\n",
+		    readl(&reg->gintmsk));
+
+	dev->gadget.speed = USB_SPEED_UNKNOWN;
+
+	return 0;
+}
+
+/*
+  Register entry point for the peripheral controller driver.
+*/
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+	struct s3c_udc *dev = the_controller;
+	int retval = 0;
+	unsigned long flags;
+
+	DEBUG_SETUP("%s: %s\n", __func__, "no name");
+
+	if (!driver
+	    || (driver->speed != USB_SPEED_FULL
+		&& driver->speed != USB_SPEED_HIGH)
+	    || !driver->bind || !driver->disconnect || !driver->setup)
+		return -EINVAL;
+	if (!dev)
+		return -ENODEV;
+	if (dev->driver)
+		return -EBUSY;
+
+	spin_lock_irqsave(&dev->lock, flags);
+	/* first hook up the driver ... */
+	dev->driver = driver;
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	if (retval) { /* TODO */
+		printf("target device_add failed, error %d\n", retval);
+		return retval;
+	}
+
+	retval = driver->bind(&dev->gadget);
+	if (retval) {
+		DEBUG_SETUP("%s: bind to driver --> error %d\n",
+			    dev->gadget.name, retval);
+		dev->driver = 0;
+		return retval;
+	}
+
+	enable_irq(IRQ_OTG);
+
+	DEBUG_SETUP("Registered gadget driver %s\n", dev->gadget.name);
+	udc_enable(dev);
+
+	return 0;
+}
+
+/*
+ * Unregister entry point for the peripheral controller driver.
+ */
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+	struct s3c_udc *dev = the_controller;
+	unsigned long flags;
+
+	if (!dev)
+		return -ENODEV;
+	if (!driver || driver != dev->driver)
+		return -EINVAL;
+
+	spin_lock_irqsave(&dev->lock, flags);
+	dev->driver = 0;
+	stop_activity(dev, driver);
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	driver->unbind(&dev->gadget);
+
+	disable_irq(IRQ_OTG);
+
+	udc_disable(dev);
+	return 0;
+}
+
+/*
+ *	done - retire a request; caller blocked irqs
+ */
+static void done(struct s3c_ep *ep, struct s3c_request *req, int status)
+{
+	unsigned int stopped = ep->stopped;
+
+	DEBUG("%s: %s %p, req = %p, stopped = %d\n",
+	      __func__, ep->ep.name, ep, &req->req, stopped);
+
+	list_del_init(&req->queue);
+
+	if (likely(req->req.status == -EINPROGRESS))
+		req->req.status = status;
+	else
+		status = req->req.status;
+
+	if (status && status != -ESHUTDOWN) {
+		DEBUG("complete %s req %p stat %d len %u/%u\n",
+		      ep->ep.name, &req->req, status,
+		      req->req.actual, req->req.length);
+	}
+
+	/* don't modify queue heads during completion callback */
+	ep->stopped = 1;
+
+#ifdef DEBUG_S3C_UDC
+	printf("calling complete callback\n");
+	{
+		int i, len = req->req.length;
+
+		printf("pkt[%d] = ", req->req.length);
+		if (len > 64)
+			len = 64;
+		for (i = 0; i < len; i++) {
+			printf("%02x", ((u8 *)req->req.buf)[i]);
+			if ((i & 7) == 7)
+				printf(" ");
+		}
+		printf("\n");
+	}
+#endif
+	spin_unlock(&ep->dev->lock);
+	req->req.complete(&ep->ep, &req->req);
+	spin_lock(&ep->dev->lock);
+
+	DEBUG("callback completed\n");
+
+	ep->stopped = stopped;
+}
+
+/*
+ *	nuke - dequeue ALL requests
+ */
+static void nuke(struct s3c_ep *ep, int status)
+{
+	struct s3c_request *req;
+
+	DEBUG("%s: %s %p\n", __func__, ep->ep.name, ep);
+
+	/* called with irqs blocked */
+	while (!list_empty(&ep->queue)) {
+		req = list_entry(ep->queue.next, struct s3c_request, queue);
+		done(ep, req, status);
+	}
+}
+
+static void stop_activity(struct s3c_udc *dev,
+			  struct usb_gadget_driver *driver)
+{
+	int i;
+
+	/* don't disconnect drivers more than once */
+	if (dev->gadget.speed == USB_SPEED_UNKNOWN)
+		driver = 0;
+	dev->gadget.speed = USB_SPEED_UNKNOWN;
+
+	/* prevent new request submissions, kill any outstanding requests  */
+	for (i = 0; i < S3C_MAX_ENDPOINTS; i++) {
+		struct s3c_ep *ep = &dev->ep[i];
+		ep->stopped = 1;
+		nuke(ep, -ESHUTDOWN);
+	}
+
+	/* report disconnect; the driver is already quiesced */
+	if (driver) {
+		spin_unlock(&dev->lock);
+		driver->disconnect(&dev->gadget);
+		spin_lock(&dev->lock);
+	}
+
+	/* re-init driver-visible data structures */
+	udc_reinit(dev);
+}
+
+static void reconfig_usbd(void)
+{
+	/* 2. Soft-reset OTG Core and then unreset again. */
+	int i;
+	unsigned int uTemp = writel(CORE_SOFT_RESET, &reg->grstctl);
+
+	DEBUG(2, "Reseting OTG controller\n");
+
+	writel(0<<15		/* PHY Low Power Clock sel*/
+		|1<<14		/* Non-Periodic TxFIFO Rewind Enable*/
+		|0x5<<10	/* Turnaround time*/
+		|0<<9 | 0<<8	/* [0:HNP disable,1:HNP enable][ 0:SRP disable*/
+				/* 1:SRP enable] H1= 1,1*/
+		|0<<7		/* Ulpi DDR sel*/
+		|0<<6		/* 0: high speed utmi+, 1: full speed serial*/
+		|0<<4		/* 0: utmi+, 1:ulpi*/
+		|1<<3		/* phy i/f  0:8bit, 1:16bit*/
+		|0x7<<0,	/* HS/FS Timeout**/
+		&reg->gusbcfg);
+
+	/* 3. Put the OTG device core in the disconnected state.*/
+	uTemp = readl(&reg->dctl);
+	uTemp |= SOFT_DISCONNECT;
+	writel(uTemp, &reg->dctl);
+
+	udelay(20);
+
+	/* 4. Make the OTG device core exit from the disconnected state.*/
+	uTemp = readl(&reg->dctl);
+	uTemp = uTemp & ~SOFT_DISCONNECT;
+	writel(uTemp, &reg->dctl);
+
+	/* 5. Configure OTG Core to initial settings of device mode.*/
+	/* [][1: full speed(30Mhz) 0:high speed]*/
+	writel(EP_MISS_CNT(1) | DEV_SPEED_HIGH_SPEED_20, &reg->dcfg);
+
+	mdelay(1);
+
+	/* 6. Unmask the core interrupts*/
+	writel(GINTMSK_INIT, &reg->gintmsk);
+
+	/* 7. Set NAK bit of EP0, EP1, EP2*/
+	writel(DEPCTL_EPDIS|DEPCTL_SNAK, &reg->out_endp[EP0_CON].doepctl);
+	writel(DEPCTL_EPDIS|DEPCTL_SNAK, &reg->in_endp[EP0_CON].diepctl);
+
+	for (i = 1; i < S3C_MAX_ENDPOINTS; i++) {
+		writel(DEPCTL_EPDIS|DEPCTL_SNAK, &reg->out_endp[i].doepctl);
+		writel(DEPCTL_EPDIS|DEPCTL_SNAK, &reg->in_endp[i].diepctl);
+	}
+
+	/* 8. Unmask EPO interrupts*/
+	writel(((1 << EP0_CON) << DAINT_OUT_BIT)
+	       | (1 << EP0_CON), &reg->daintmsk);
+
+	/* 9. Unmask device OUT EP common interrupts*/
+	writel(DOEPMSK_INIT, &reg->doepmsk);
+
+	/* 10. Unmask device IN EP common interrupts*/
+	writel(DIEPMSK_INIT, &reg->diepmsk);
+
+	/* 11. Set Rx FIFO Size (in 32-bit words) */
+	writel(RX_FIFO_SIZE >> 2, &reg->grxfsiz);
+
+	/* 12. Set Non Periodic Tx FIFO Size */
+	writel((NPTX_FIFO_SIZE >> 2) << 16 | ((RX_FIFO_SIZE >> 2)) << 0,
+	       &reg->gnptxfsiz);
+
+	for (i = 1; i < S3C_MAX_HW_ENDPOINTS; i++)
+		writel((PTX_FIFO_SIZE >> 2) << 16 |
+		       ((RX_FIFO_SIZE + NPTX_FIFO_SIZE +
+			 PTX_FIFO_SIZE*(i-1)) >> 2) << 0,
+		       &reg->dieptxf[i-1]);
+
+	/* Flush the RX FIFO */
+	writel(RX_FIFO_FLUSH, &reg->grstctl);
+	while (readl(&reg->grstctl) & RX_FIFO_FLUSH)
+		DEBUG("%s: waiting for S3C_UDC_OTG_GRSTCTL\n", __func__);
+
+	/* Flush all the Tx FIFO's */
+	writel(TX_FIFO_FLUSH_ALL, &reg->grstctl);
+	writel(TX_FIFO_FLUSH_ALL | TX_FIFO_FLUSH, &reg->grstctl);
+	while (readl(&reg->grstctl) & TX_FIFO_FLUSH)
+		DEBUG("%s: waiting for S3C_UDC_OTG_GRSTCTL\n", __func__);
+
+	/* 13. Clear NAK bit of EP0, EP1, EP2*/
+	/* For Slave mode*/
+	/* EP0: Control OUT */
+	writel(DEPCTL_EPDIS | DEPCTL_CNAK,
+	       &reg->out_endp[EP0_CON].doepctl);
+
+	/* 14. Initialize OTG Link Core.*/
+	writel(GAHBCFG_INIT, &reg->gahbcfg);
+}
+
+static void set_max_pktsize(struct s3c_udc *dev, enum usb_device_speed speed)
+{
+	unsigned int ep_ctrl;
+	int i;
+
+	if (speed == USB_SPEED_HIGH) {
+		ep0_fifo_size = 64;
+		ep_fifo_size = 512;
+		ep_fifo_size2 = 1024;
+		dev->gadget.speed = USB_SPEED_HIGH;
+	} else {
+		ep0_fifo_size = 64;
+		ep_fifo_size = 64;
+		ep_fifo_size2 = 64;
+		dev->gadget.speed = USB_SPEED_FULL;
+	}
+
+	dev->ep[0].ep.maxpacket = ep0_fifo_size;
+	for (i = 1; i < S3C_MAX_ENDPOINTS; i++)
+		dev->ep[i].ep.maxpacket = ep_fifo_size;
+
+	/* EP0 - Control IN (64 bytes)*/
+	ep_ctrl = readl(&reg->in_endp[EP0_CON].diepctl);
+	writel(ep_ctrl|(0<<0), &reg->in_endp[EP0_CON].diepctl);
+
+	/* EP0 - Control OUT (64 bytes)*/
+	ep_ctrl = readl(&reg->out_endp[EP0_CON].doepctl);
+	writel(ep_ctrl|(0<<0), &reg->out_endp[EP0_CON].doepctl);
+}
+
+static int s3c_ep_enable(struct usb_ep *_ep,
+			 const struct usb_endpoint_descriptor *desc)
+{
+	struct s3c_ep *ep;
+	struct s3c_udc *dev;
+	unsigned long flags;
+
+	DEBUG("%s: %p\n", __func__, _ep);
+
+	ep = container_of(_ep, struct s3c_ep, ep);
+	if (!_ep || !desc || ep->desc || _ep->name == ep0name
+	    || desc->bDescriptorType != USB_DT_ENDPOINT
+	    || ep->bEndpointAddress != desc->bEndpointAddress
+	    || ep_maxpacket(ep) < le16_to_cpu(desc->wMaxPacketSize)) {
+
+		DEBUG("%s: bad ep or descriptor\n", __func__);
+		return -EINVAL;
+	}
+
+	/* xfer types must match, except that interrupt ~= bulk */
+	if (ep->bmAttributes != desc->bmAttributes
+	    && ep->bmAttributes != USB_ENDPOINT_XFER_BULK
+	    && desc->bmAttributes != USB_ENDPOINT_XFER_INT) {
+
+		DEBUG("%s: %s type mismatch\n", __func__, _ep->name);
+		return -EINVAL;
+	}
+
+	/* hardware _could_ do smaller, but driver doesn't */
+	if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK
+	     && le16_to_cpu(desc->wMaxPacketSize) != ep_maxpacket(ep))
+	    || !desc->wMaxPacketSize) {
+
+		DEBUG("%s: bad %s maxpacket\n", __func__, _ep->name);
+		return -ERANGE;
+	}
+
+	dev = ep->dev;
+	if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) {
+
+		DEBUG("%s: bogus device state\n", __func__);
+		return -ESHUTDOWN;
+	}
+
+	ep->stopped = 0;
+	ep->desc = desc;
+	ep->pio_irqs = 0;
+	ep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
+
+	/* Reset halt state */
+	s3c_udc_set_nak(ep);
+	s3c_udc_set_halt(_ep, 0);
+
+	spin_lock_irqsave(&ep->dev->lock, flags);
+	s3c_udc_ep_activate(ep);
+	spin_unlock_irqrestore(&ep->dev->lock, flags);
+
+	DEBUG("%s: enabled %s, stopped = %d, maxpacket = %d\n",
+	      __func__, _ep->name, ep->stopped, ep->ep.maxpacket);
+	return 0;
+}
+
+/*
+ * Disable EP
+ */
+static int s3c_ep_disable(struct usb_ep *_ep)
+{
+	struct s3c_ep *ep;
+	unsigned long flags;
+
+	DEBUG("%s: %p\n", __func__, _ep);
+
+	ep = container_of(_ep, struct s3c_ep, ep);
+	if (!_ep || !ep->desc) {
+		DEBUG("%s: %s not enabled\n", __func__,
+		      _ep ? ep->ep.name : NULL);
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&ep->dev->lock, flags);
+
+	/* Nuke all pending requests */
+	nuke(ep, -ESHUTDOWN);
+
+	ep->desc = 0;
+	ep->stopped = 1;
+
+	spin_unlock_irqrestore(&ep->dev->lock, flags);
+
+	DEBUG("%s: disabled %s\n", __func__, _ep->name);
+	return 0;
+}
+
+static struct usb_request *s3c_alloc_request(struct usb_ep *ep,
+					     gfp_t gfp_flags)
+{
+	struct s3c_request *req;
+
+	DEBUG("%s: %s %p\n", __func__, ep->name, ep);
+
+	req = kmalloc(sizeof *req, gfp_flags);
+	if (!req)
+		return 0;
+
+	memset(req, 0, sizeof *req);
+	INIT_LIST_HEAD(&req->queue);
+
+	return &req->req;
+}
+
+static void s3c_free_request(struct usb_ep *ep, struct usb_request *_req)
+{
+	struct s3c_request *req;
+
+	DEBUG("%s: %p\n", __func__, ep);
+
+	req = container_of(_req, struct s3c_request, req);
+	WARN_ON(!list_empty(&req->queue));
+	kfree(req);
+}
+
+/* dequeue JUST ONE request */
+static int s3c_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct s3c_ep *ep;
+	struct s3c_request *req;
+	unsigned long flags;
+
+	DEBUG("%s: %p\n", __func__, _ep);
+
+	ep = container_of(_ep, struct s3c_ep, ep);
+	if (!_ep || ep->ep.name == ep0name)
+		return -EINVAL;
+
+	spin_lock_irqsave(&ep->dev->lock, flags);
+
+	/* make sure it's actually queued on this endpoint */
+	list_for_each_entry(req, &ep->queue, queue) {
+		if (&req->req == _req)
+			break;
+	}
+	if (&req->req != _req) {
+		spin_unlock_irqrestore(&ep->dev->lock, flags);
+		return -EINVAL;
+	}
+
+	done(ep, req, -ECONNRESET);
+
+	spin_unlock_irqrestore(&ep->dev->lock, flags);
+	return 0;
+}
+
+/*
+ * Return bytes in EP FIFO
+ */
+static int s3c_fifo_status(struct usb_ep *_ep)
+{
+	int count = 0;
+	struct s3c_ep *ep;
+
+	ep = container_of(_ep, struct s3c_ep, ep);
+	if (!_ep) {
+		DEBUG("%s: bad ep\n", __func__);
+		return -ENODEV;
+	}
+
+	DEBUG("%s: %d\n", __func__, ep_index(ep));
+
+	/* LPD can't report unclaimed bytes from IN fifos */
+	if (ep_is_in(ep))
+		return -EOPNOTSUPP;
+
+	return count;
+}
+
+/*
+ * Flush EP FIFO
+ */
+static void s3c_fifo_flush(struct usb_ep *_ep)
+{
+	struct s3c_ep *ep;
+
+	ep = container_of(_ep, struct s3c_ep, ep);
+	if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) {
+		DEBUG("%s: bad ep\n", __func__);
+		return;
+	}
+
+	DEBUG("%s: %d\n", __func__, ep_index(ep));
+}
+
+static const struct usb_gadget_ops s3c_udc_ops = {
+	/* current versions must always be self-powered */
+};
+
+static struct s3c_udc memory = {
+	.usb_address = 0,
+	.gadget = {
+		.ops = &s3c_udc_ops,
+		.ep0 = &memory.ep[0].ep,
+		.name = driver_name,
+	},
+
+	/* control endpoint */
+	.ep[0] = {
+		.ep = {
+			.name = ep0name,
+			.ops = &s3c_ep_ops,
+			.maxpacket = EP0_FIFO_SIZE,
+		},
+		.dev = &memory,
+
+		.bEndpointAddress = 0,
+		.bmAttributes = 0,
+
+		.ep_type = ep_control,
+	},
+
+	/* first group of endpoints */
+	.ep[1] = {
+		.ep = {
+			.name = "ep1in-bulk",
+			.ops = &s3c_ep_ops,
+			.maxpacket = EP_FIFO_SIZE,
+		},
+		.dev = &memory,
+
+		.bEndpointAddress = USB_DIR_IN | 1,
+		.bmAttributes = USB_ENDPOINT_XFER_BULK,
+
+		.ep_type = ep_bulk_out,
+		.fifo_num = 1,
+	},
+
+	.ep[2] = {
+		.ep = {
+			.name = "ep2out-bulk",
+			.ops = &s3c_ep_ops,
+			.maxpacket = EP_FIFO_SIZE,
+		},
+		.dev = &memory,
+
+		.bEndpointAddress = USB_DIR_OUT | 2,
+		.bmAttributes = USB_ENDPOINT_XFER_BULK,
+
+		.ep_type = ep_bulk_in,
+		.fifo_num = 2,
+	},
+
+	.ep[3] = {
+		.ep = {
+			.name = "ep3in-int",
+			.ops = &s3c_ep_ops,
+			.maxpacket = EP_FIFO_SIZE,
+		},
+		.dev = &memory,
+
+		.bEndpointAddress = USB_DIR_IN | 3,
+		.bmAttributes = USB_ENDPOINT_XFER_INT,
+
+		.ep_type = ep_interrupt,
+		.fifo_num = 3,
+	},
+};
+
+/*
+ *	probe - binds to the platform device
+ */
+
+int s3c_udc_probe(struct s3c_plat_otg_data *pdata)
+{
+	struct s3c_udc *dev = &memory;
+	int retval = 0, i;
+
+	DEBUG("%s: %p\n", __func__, pdata);
+
+	dev->pdata = pdata;
+
+	phy = (struct s3c_usbotg_phy *)pdata->regs_phy;
+	reg = (struct s3c_usbotg_reg *)pdata->regs_otg;
+	usb_phy_ctrl = pdata->usb_phy_ctrl;
+
+	/* regs_otg = (void *)pdata->regs_otg; */
+
+	dev->gadget.is_dualspeed = 1;	/* Hack only*/
+	dev->gadget.is_otg = 0;
+	dev->gadget.is_a_peripheral = 0;
+	dev->gadget.b_hnp_enable = 0;
+	dev->gadget.a_hnp_support = 0;
+	dev->gadget.a_alt_hnp_support = 0;
+
+	the_controller = dev;
+
+	for (i = 0; i < S3C_MAX_ENDPOINTS+1; i++) {
+		dev->dma_buf[i] = kmalloc(DMA_BUFFER_SIZE, GFP_KERNEL);
+		dev->dma_addr[i] = (dma_addr_t) dev->dma_buf[i];
+		invalidate_dcache_range((unsigned long) dev->dma_buf[i],
+					(unsigned long) (dev->dma_buf[i]
+							 + DMA_BUFFER_SIZE));
+	}
+	usb_ctrl = dev->dma_buf[0];
+	usb_ctrl_dma_addr = dev->dma_addr[0];
+
+	udc_reinit(dev);
+
+	return retval;
+}
+
+int usb_gadget_handle_interrupts()
+{
+	u32 intr_status = readl(&reg->gintsts);
+	u32 gintmsk = readl(&reg->gintmsk);
+
+	if (intr_status & gintmsk)
+		return s3c_udc_irq(1, (void *)the_controller);
+	return 0;
+}

+ 1444 - 0
drivers/usb/gadget/s3c_udc_otg_xfer_dma.c

@@ -0,0 +1,1444 @@
+/*
+ * drivers/usb/gadget/s3c_udc_otg_xfer_dma.c
+ * Samsung S3C on-chip full/high speed USB OTG 2.0 device controllers
+ *
+ * Copyright (C) 2009 for Samsung Electronics
+ *
+ * BSP Support for Samsung's UDC driver
+ * available at:
+ * git://git.kernel.org/pub/scm/linux/kernel/git/kki_ap/linux-2.6-samsung.git
+ *
+ * State machine bugfixes:
+ * Marek Szyprowski <m.szyprowski@samsung.com>
+ *
+ * Ported to u-boot:
+ * Marek Szyprowski <m.szyprowski@samsung.com>
+ * Lukasz Majewski <l.majewski@samsumg.com>
+ *
+ * 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
+ *
+ */
+
+static u8 clear_feature_num;
+int clear_feature_flag;
+
+/* Bulk-Only Mass Storage Reset (class-specific request) */
+#define GET_MAX_LUN_REQUEST	0xFE
+#define BOT_RESET_REQUEST	0xFF
+
+static inline void s3c_udc_ep0_zlp(struct s3c_udc *dev)
+{
+	u32 ep_ctrl;
+
+	flush_dcache_range((unsigned long) usb_ctrl_dma_addr,
+			   (unsigned long) usb_ctrl_dma_addr
+			   + DMA_BUFFER_SIZE);
+
+	writel(usb_ctrl_dma_addr, &reg->in_endp[EP0_CON].diepdma);
+	writel(DIEPT_SIZ_PKT_CNT(1), &reg->in_endp[EP0_CON].dieptsiz);
+
+	ep_ctrl = readl(&reg->in_endp[EP0_CON].diepctl);
+	writel(ep_ctrl|DEPCTL_EPENA|DEPCTL_CNAK,
+	       &reg->in_endp[EP0_CON].diepctl);
+
+	DEBUG_EP0("%s:EP0 ZLP DIEPCTL0 = 0x%x\n",
+		__func__, readl(&reg->in_endp[EP0_CON].diepctl));
+	dev->ep0state = WAIT_FOR_IN_COMPLETE;
+}
+
+void s3c_udc_pre_setup(void)
+{
+	u32 ep_ctrl;
+
+	DEBUG_IN_EP("%s : Prepare Setup packets.\n", __func__);
+
+	invalidate_dcache_range((unsigned long) usb_ctrl_dma_addr,
+				(unsigned long) usb_ctrl_dma_addr
+				+ DMA_BUFFER_SIZE);
+
+	writel(DOEPT_SIZ_PKT_CNT(1) | sizeof(struct usb_ctrlrequest),
+	       &reg->out_endp[EP0_CON].doeptsiz);
+	writel(usb_ctrl_dma_addr, &reg->out_endp[EP0_CON].doepdma);
+
+	ep_ctrl = readl(&reg->out_endp[EP0_CON].doepctl);
+	writel(ep_ctrl|DEPCTL_EPENA, &reg->out_endp[EP0_CON].doepctl);
+
+	DEBUG_EP0("%s:EP0 ZLP DIEPCTL0 = 0x%x\n",
+		__func__, readl(&reg->in_endp[EP0_CON].diepctl));
+	DEBUG_EP0("%s:EP0 ZLP DOEPCTL0 = 0x%x\n",
+		__func__, readl(&reg->out_endp[EP0_CON].doepctl));
+
+}
+
+static inline void s3c_ep0_complete_out(void)
+{
+	u32 ep_ctrl;
+
+	DEBUG_EP0("%s:EP0 ZLP DIEPCTL0 = 0x%x\n",
+		__func__, readl(&reg->in_endp[EP0_CON].diepctl));
+	DEBUG_EP0("%s:EP0 ZLP DOEPCTL0 = 0x%x\n",
+		__func__, readl(&reg->out_endp[EP0_CON].doepctl));
+
+	DEBUG_IN_EP("%s : Prepare Complete Out packet.\n", __func__);
+
+	invalidate_dcache_range((unsigned long) usb_ctrl_dma_addr,
+				(unsigned long) usb_ctrl_dma_addr
+				+ DMA_BUFFER_SIZE);
+
+	writel(DOEPT_SIZ_PKT_CNT(1) | sizeof(struct usb_ctrlrequest),
+	       &reg->out_endp[EP0_CON].doeptsiz);
+	writel(usb_ctrl_dma_addr, &reg->out_endp[EP0_CON].doepdma);
+
+	ep_ctrl = readl(&reg->out_endp[EP0_CON].doepctl);
+	writel(ep_ctrl|DEPCTL_EPENA|DEPCTL_CNAK,
+	       &reg->out_endp[EP0_CON].doepctl);
+
+	DEBUG_EP0("%s:EP0 ZLP DIEPCTL0 = 0x%x\n",
+		__func__, readl(&reg->in_endp[EP0_CON].diepctl));
+	DEBUG_EP0("%s:EP0 ZLP DOEPCTL0 = 0x%x\n",
+		__func__, readl(&reg->out_endp[EP0_CON].doepctl));
+
+}
+
+
+static int setdma_rx(struct s3c_ep *ep, struct s3c_request *req)
+{
+	u32 *buf, ctrl;
+	u32 length, pktcnt;
+	u32 ep_num = ep_index(ep);
+
+	buf = req->req.buf + req->req.actual;
+
+	length = min(req->req.length - req->req.actual, (int)ep->ep.maxpacket);
+
+	ep->len = length;
+	ep->dma_buf = buf;
+
+	invalidate_dcache_range((unsigned long) ep->dev->dma_buf[ep_num],
+				(unsigned long) ep->dev->dma_buf[ep_num]
+				+ DMA_BUFFER_SIZE);
+
+	if (length == 0)
+		pktcnt = 1;
+	else
+		pktcnt = (length - 1)/(ep->ep.maxpacket) + 1;
+
+	pktcnt = 1;
+	ctrl =  readl(&reg->out_endp[ep_num].doepctl);
+
+	writel(the_controller->dma_addr[ep_index(ep)+1],
+	       &reg->out_endp[ep_num].doepdma);
+	writel(DOEPT_SIZ_PKT_CNT(pktcnt) | DOEPT_SIZ_XFER_SIZE(length),
+	       &reg->out_endp[ep_num].doeptsiz);
+	writel(DEPCTL_EPENA|DEPCTL_CNAK|ctrl, &reg->out_endp[ep_num].doepctl);
+
+	DEBUG_OUT_EP("%s: EP%d RX DMA start : DOEPDMA = 0x%x,"
+		     "DOEPTSIZ = 0x%x, DOEPCTL = 0x%x\n"
+		     "\tbuf = 0x%p, pktcnt = %d, xfersize = %d\n",
+		     __func__, ep_num,
+		     readl(&reg->out_endp[ep_num].doepdma),
+		     readl(&reg->out_endp[ep_num].doeptsiz),
+		     readl(&reg->out_endp[ep_num].doepctl),
+		     buf, pktcnt, length);
+	return 0;
+
+}
+
+int setdma_tx(struct s3c_ep *ep, struct s3c_request *req)
+{
+	u32 *buf, ctrl = 0;
+	u32 length, pktcnt;
+	u32 ep_num = ep_index(ep);
+	u32 *p = the_controller->dma_buf[ep_index(ep)+1];
+
+	buf = req->req.buf + req->req.actual;
+	length = req->req.length - req->req.actual;
+
+	if (ep_num == EP0_CON)
+		length = min_t(length, (u32)ep_maxpacket(ep));
+
+	ep->len = length;
+	ep->dma_buf = buf;
+	memcpy(p, ep->dma_buf, length);
+
+	flush_dcache_range((unsigned long) p ,
+			   (unsigned long) p + DMA_BUFFER_SIZE);
+
+	if (length == 0)
+		pktcnt = 1;
+	else
+		pktcnt = (length - 1)/(ep->ep.maxpacket) + 1;
+
+	/* Flush the endpoint's Tx FIFO */
+	writel(TX_FIFO_NUMBER(ep->fifo_num), &reg->grstctl);
+	writel(TX_FIFO_NUMBER(ep->fifo_num) | TX_FIFO_FLUSH, &reg->grstctl);
+	while (readl(&reg->grstctl) & TX_FIFO_FLUSH)
+		;
+
+	writel(the_controller->dma_addr[ep_index(ep)+1],
+	       &reg->in_endp[ep_num].diepdma);
+	writel(DIEPT_SIZ_PKT_CNT(pktcnt) | DIEPT_SIZ_XFER_SIZE(length),
+	       &reg->in_endp[ep_num].dieptsiz);
+
+	ctrl = readl(&reg->in_endp[ep_num].diepctl);
+
+	/* Write the FIFO number to be used for this endpoint */
+	ctrl &= DIEPCTL_TX_FIFO_NUM_MASK;
+	ctrl |= DIEPCTL_TX_FIFO_NUM(ep->fifo_num);
+
+	/* Clear reserved (Next EP) bits */
+	ctrl = (ctrl&~(EP_MASK<<DEPCTL_NEXT_EP_BIT));
+
+	writel(DEPCTL_EPENA|DEPCTL_CNAK|ctrl, &reg->in_endp[ep_num].diepctl);
+
+	DEBUG_IN_EP("%s:EP%d TX DMA start : DIEPDMA0 = 0x%x,"
+		    "DIEPTSIZ0 = 0x%x, DIEPCTL0 = 0x%x\n"
+		    "\tbuf = 0x%p, pktcnt = %d, xfersize = %d\n",
+		    __func__, ep_num,
+		    readl(&reg->in_endp[ep_num].diepdma),
+		    readl(&reg->in_endp[ep_num].dieptsiz),
+		    readl(&reg->in_endp[ep_num].diepctl),
+		    buf, pktcnt, length);
+
+	return length;
+}
+
+static void complete_rx(struct s3c_udc *dev, u8 ep_num)
+{
+	struct s3c_ep *ep = &dev->ep[ep_num];
+	struct s3c_request *req = NULL;
+	u32 ep_tsr = 0, xfer_size = 0, is_short = 0;
+	u32 *p = the_controller->dma_buf[ep_index(ep)+1];
+
+	if (list_empty(&ep->queue)) {
+		DEBUG_OUT_EP("%s: RX DMA done : NULL REQ on OUT EP-%d\n",
+					__func__, ep_num);
+		return;
+
+	}
+
+	req = list_entry(ep->queue.next, struct s3c_request, queue);
+	ep_tsr = readl(&reg->out_endp[ep_num].doeptsiz);
+
+	if (ep_num == EP0_CON)
+		xfer_size = (ep_tsr & DOEPT_SIZ_XFER_SIZE_MAX_EP0);
+	else
+		xfer_size = (ep_tsr & DOEPT_SIZ_XFER_SIZE_MAX_EP);
+
+	xfer_size = ep->len - xfer_size;
+
+	invalidate_dcache_range((unsigned long) p,
+				(unsigned long) p + DMA_BUFFER_SIZE);
+
+	memcpy(ep->dma_buf, p, ep->len);
+
+	req->req.actual += min(xfer_size, req->req.length - req->req.actual);
+	is_short = (xfer_size < ep->ep.maxpacket);
+
+	DEBUG_OUT_EP("%s: RX DMA done : ep = %d, rx bytes = %d/%d, "
+		     "is_short = %d, DOEPTSIZ = 0x%x, remained bytes = %d\n",
+			__func__, ep_num, req->req.actual, req->req.length,
+			is_short, ep_tsr, xfer_size);
+
+	if (is_short || req->req.actual == req->req.length) {
+		if (ep_num == EP0_CON && dev->ep0state == DATA_STATE_RECV) {
+			DEBUG_OUT_EP("	=> Send ZLP\n");
+			s3c_udc_ep0_zlp(dev);
+			/* packet will be completed in complete_tx() */
+			dev->ep0state = WAIT_FOR_IN_COMPLETE;
+		} else {
+			done(ep, req, 0);
+
+			if (!list_empty(&ep->queue)) {
+				req = list_entry(ep->queue.next,
+					struct s3c_request, queue);
+				DEBUG_OUT_EP("%s: Next Rx request start...\n",
+					 __func__);
+				setdma_rx(ep, req);
+			}
+		}
+	} else
+		setdma_rx(ep, req);
+}
+
+static void complete_tx(struct s3c_udc *dev, u8 ep_num)
+{
+	struct s3c_ep *ep = &dev->ep[ep_num];
+	struct s3c_request *req;
+	u32 ep_tsr = 0, xfer_size = 0, is_short = 0;
+	u32 last;
+
+	if (dev->ep0state == WAIT_FOR_NULL_COMPLETE) {
+		dev->ep0state = WAIT_FOR_OUT_COMPLETE;
+		s3c_ep0_complete_out();
+		return;
+	}
+
+	if (list_empty(&ep->queue)) {
+		DEBUG_IN_EP("%s: TX DMA done : NULL REQ on IN EP-%d\n",
+					__func__, ep_num);
+		return;
+
+	}
+
+	req = list_entry(ep->queue.next, struct s3c_request, queue);
+
+	ep_tsr = readl(&reg->in_endp[ep_num].dieptsiz);
+
+	xfer_size = ep->len;
+	is_short = (xfer_size < ep->ep.maxpacket);
+	req->req.actual += min(xfer_size, req->req.length - req->req.actual);
+
+	DEBUG_IN_EP("%s: TX DMA done : ep = %d, tx bytes = %d/%d, "
+		     "is_short = %d, DIEPTSIZ = 0x%x, remained bytes = %d\n",
+			__func__, ep_num, req->req.actual, req->req.length,
+			is_short, ep_tsr, xfer_size);
+
+	if (ep_num == 0) {
+		if (dev->ep0state == DATA_STATE_XMIT) {
+			DEBUG_IN_EP("%s: ep_num = %d, ep0stat =="
+				    "DATA_STATE_XMIT\n",
+				    __func__, ep_num);
+			last = write_fifo_ep0(ep, req);
+			if (last)
+				dev->ep0state = WAIT_FOR_COMPLETE;
+		} else if (dev->ep0state == WAIT_FOR_IN_COMPLETE) {
+			DEBUG_IN_EP("%s: ep_num = %d, completing request\n",
+				    __func__, ep_num);
+			done(ep, req, 0);
+			dev->ep0state = WAIT_FOR_SETUP;
+		} else if (dev->ep0state == WAIT_FOR_COMPLETE) {
+			DEBUG_IN_EP("%s: ep_num = %d, completing request\n",
+				    __func__, ep_num);
+			done(ep, req, 0);
+			dev->ep0state = WAIT_FOR_OUT_COMPLETE;
+			s3c_ep0_complete_out();
+		} else {
+			DEBUG_IN_EP("%s: ep_num = %d, invalid ep state\n",
+				    __func__, ep_num);
+		}
+		return;
+	}
+
+	if (req->req.actual == req->req.length)
+		done(ep, req, 0);
+
+	if (!list_empty(&ep->queue)) {
+		req = list_entry(ep->queue.next, struct s3c_request, queue);
+		DEBUG_IN_EP("%s: Next Tx request start...\n", __func__);
+		setdma_tx(ep, req);
+	}
+}
+
+static inline void s3c_udc_check_tx_queue(struct s3c_udc *dev, u8 ep_num)
+{
+	struct s3c_ep *ep = &dev->ep[ep_num];
+	struct s3c_request *req;
+
+	DEBUG_IN_EP("%s: Check queue, ep_num = %d\n", __func__, ep_num);
+
+	if (!list_empty(&ep->queue)) {
+		req = list_entry(ep->queue.next, struct s3c_request, queue);
+		DEBUG_IN_EP("%s: Next Tx request(0x%p) start...\n",
+			    __func__, req);
+
+		if (ep_is_in(ep))
+			setdma_tx(ep, req);
+		else
+			setdma_rx(ep, req);
+	} else {
+		DEBUG_IN_EP("%s: NULL REQ on IN EP-%d\n", __func__, ep_num);
+
+		return;
+	}
+
+}
+
+static void process_ep_in_intr(struct s3c_udc *dev)
+{
+	u32 ep_intr, ep_intr_status;
+	u8 ep_num = 0;
+
+	ep_intr = readl(&reg->daint);
+	DEBUG_IN_EP("*** %s: EP In interrupt : DAINT = 0x%x\n",
+				__func__, ep_intr);
+
+	ep_intr &= DAINT_MASK;
+
+	while (ep_intr) {
+		if (ep_intr & DAINT_IN_EP_INT(1)) {
+			ep_intr_status = readl(&reg->in_endp[ep_num].diepint);
+			DEBUG_IN_EP("\tEP%d-IN : DIEPINT = 0x%x\n",
+						ep_num, ep_intr_status);
+
+			/* Interrupt Clear */
+			writel(ep_intr_status, &reg->in_endp[ep_num].diepint);
+
+			if (ep_intr_status & TRANSFER_DONE) {
+				complete_tx(dev, ep_num);
+
+				if (ep_num == 0) {
+					if (dev->ep0state ==
+					    WAIT_FOR_IN_COMPLETE)
+						dev->ep0state = WAIT_FOR_SETUP;
+
+					if (dev->ep0state == WAIT_FOR_SETUP)
+						s3c_udc_pre_setup();
+
+					/* continue transfer after
+					   set_clear_halt for DMA mode */
+					if (clear_feature_flag == 1) {
+						s3c_udc_check_tx_queue(dev,
+							clear_feature_num);
+						clear_feature_flag = 0;
+					}
+				}
+			}
+		}
+		ep_num++;
+		ep_intr >>= 1;
+	}
+}
+
+static void process_ep_out_intr(struct s3c_udc *dev)
+{
+	u32 ep_intr, ep_intr_status;
+	u8 ep_num = 0;
+
+	ep_intr = readl(&reg->daint);
+	DEBUG_OUT_EP("*** %s: EP OUT interrupt : DAINT = 0x%x\n",
+				__func__, ep_intr);
+
+	ep_intr = (ep_intr >> DAINT_OUT_BIT) & DAINT_MASK;
+
+	while (ep_intr) {
+		if (ep_intr & 0x1) {
+			ep_intr_status = readl(&reg->out_endp[ep_num].doepint);
+			DEBUG_OUT_EP("\tEP%d-OUT : DOEPINT = 0x%x\n",
+						ep_num, ep_intr_status);
+
+			/* Interrupt Clear */
+			writel(ep_intr_status, &reg->out_endp[ep_num].doepint);
+
+			if (ep_num == 0) {
+				if (ep_intr_status & TRANSFER_DONE) {
+					if (dev->ep0state !=
+					    WAIT_FOR_OUT_COMPLETE)
+						complete_rx(dev, ep_num);
+					else {
+						dev->ep0state = WAIT_FOR_SETUP;
+						s3c_udc_pre_setup();
+					}
+				}
+
+				if (ep_intr_status &
+				    CTRL_OUT_EP_SETUP_PHASE_DONE) {
+					DEBUG_OUT_EP("SETUP packet arrived\n");
+					s3c_handle_ep0(dev);
+				}
+			} else {
+				if (ep_intr_status & TRANSFER_DONE)
+					complete_rx(dev, ep_num);
+			}
+		}
+		ep_num++;
+		ep_intr >>= 1;
+	}
+}
+
+/*
+ *	usb client interrupt handler.
+ */
+static int s3c_udc_irq(int irq, void *_dev)
+{
+	struct s3c_udc *dev = _dev;
+	u32 intr_status;
+	u32 usb_status, gintmsk;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->lock, flags);
+
+	intr_status = readl(&reg->gintsts);
+	gintmsk = readl(&reg->gintmsk);
+
+	DEBUG_ISR("\n*** %s : GINTSTS=0x%x(on state %s), GINTMSK : 0x%x,"
+		  "DAINT : 0x%x, DAINTMSK : 0x%x\n",
+		  __func__, intr_status, state_names[dev->ep0state], gintmsk,
+		  readl(&reg->daint), readl(&reg->daintmsk));
+
+	if (!intr_status) {
+		spin_unlock_irqrestore(&dev->lock, flags);
+		return IRQ_HANDLED;
+	}
+
+	if (intr_status & INT_ENUMDONE) {
+		DEBUG_ISR("\tSpeed Detection interrupt\n");
+
+		writel(INT_ENUMDONE, &reg->gintsts);
+		usb_status = (readl(&reg->dsts) & 0x6);
+
+		if (usb_status & (USB_FULL_30_60MHZ | USB_FULL_48MHZ)) {
+			DEBUG_ISR("\t\tFull Speed Detection\n");
+			set_max_pktsize(dev, USB_SPEED_FULL);
+
+		} else {
+			DEBUG_ISR("\t\tHigh Speed Detection : 0x%x\n",
+				  usb_status);
+			set_max_pktsize(dev, USB_SPEED_HIGH);
+		}
+	}
+
+	if (intr_status & INT_EARLY_SUSPEND) {
+		DEBUG_ISR("\tEarly suspend interrupt\n");
+		writel(INT_EARLY_SUSPEND, &reg->gintsts);
+	}
+
+	if (intr_status & INT_SUSPEND) {
+		usb_status = readl(&reg->dsts);
+		DEBUG_ISR("\tSuspend interrupt :(DSTS):0x%x\n", usb_status);
+		writel(INT_SUSPEND, &reg->gintsts);
+
+		if (dev->gadget.speed != USB_SPEED_UNKNOWN
+		    && dev->driver) {
+			if (dev->driver->suspend)
+				dev->driver->suspend(&dev->gadget);
+
+			/* HACK to let gadget detect disconnected state */
+			if (dev->driver->disconnect) {
+				spin_unlock_irqrestore(&dev->lock, flags);
+				dev->driver->disconnect(&dev->gadget);
+				spin_lock_irqsave(&dev->lock, flags);
+			}
+		}
+	}
+
+	if (intr_status & INT_RESUME) {
+		DEBUG_ISR("\tResume interrupt\n");
+		writel(INT_RESUME, &reg->gintsts);
+
+		if (dev->gadget.speed != USB_SPEED_UNKNOWN
+		    && dev->driver
+		    && dev->driver->resume) {
+
+			dev->driver->resume(&dev->gadget);
+		}
+	}
+
+	if (intr_status & INT_RESET) {
+		usb_status = readl(&reg->gotgctl);
+		DEBUG_ISR("\tReset interrupt - (GOTGCTL):0x%x\n", usb_status);
+		writel(INT_RESET, &reg->gintsts);
+
+		if ((usb_status & 0xc0000) == (0x3 << 18)) {
+			if (reset_available) {
+				DEBUG_ISR("\t\tOTG core got reset (%d)!!\n",
+					  reset_available);
+				reconfig_usbd();
+				dev->ep0state = WAIT_FOR_SETUP;
+				reset_available = 0;
+				s3c_udc_pre_setup();
+			} else
+				reset_available = 1;
+
+		} else {
+			reset_available = 1;
+			DEBUG_ISR("\t\tRESET handling skipped\n");
+		}
+	}
+
+	if (intr_status & INT_IN_EP)
+		process_ep_in_intr(dev);
+
+	if (intr_status & INT_OUT_EP)
+		process_ep_out_intr(dev);
+
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	return IRQ_HANDLED;
+}
+
+/** Queue one request
+ *  Kickstart transfer if needed
+ */
+static int s3c_queue(struct usb_ep *_ep, struct usb_request *_req,
+			 gfp_t gfp_flags)
+{
+	struct s3c_request *req;
+	struct s3c_ep *ep;
+	struct s3c_udc *dev;
+	unsigned long flags;
+	u32 ep_num, gintsts;
+
+	req = container_of(_req, struct s3c_request, req);
+	if (unlikely(!_req || !_req->complete || !_req->buf
+		     || !list_empty(&req->queue))) {
+
+		DEBUG("%s: bad params\n", __func__);
+		return -EINVAL;
+	}
+
+	ep = container_of(_ep, struct s3c_ep, ep);
+
+	if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) {
+
+		DEBUG("%s: bad ep: %s, %d, %x\n", __func__,
+		      ep->ep.name, !ep->desc, _ep);
+		return -EINVAL;
+	}
+
+	ep_num = ep_index(ep);
+	dev = ep->dev;
+	if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) {
+
+		DEBUG("%s: bogus device state %p\n", __func__, dev->driver);
+		return -ESHUTDOWN;
+	}
+
+	spin_lock_irqsave(&dev->lock, flags);
+
+	_req->status = -EINPROGRESS;
+	_req->actual = 0;
+
+	/* kickstart this i/o queue? */
+	DEBUG("\n*** %s: %s-%s req = %p, len = %d, buf = %p"
+		"Q empty = %d, stopped = %d\n",
+		__func__, _ep->name, ep_is_in(ep) ? "in" : "out",
+		_req, _req->length, _req->buf,
+		list_empty(&ep->queue), ep->stopped);
+
+#ifdef DEBUG_S3C_UDC
+	{
+		int i, len = _req->length;
+
+		printf("pkt = ");
+		if (len > 64)
+			len = 64;
+		for (i = 0; i < len; i++) {
+			printf("%02x", ((u8 *)_req->buf)[i]);
+			if ((i & 7) == 7)
+				printf(" ");
+		}
+		printf("\n");
+	}
+#endif
+
+	if (list_empty(&ep->queue) && !ep->stopped) {
+
+		if (ep_num == 0) {
+			/* EP0 */
+			list_add_tail(&req->queue, &ep->queue);
+			s3c_ep0_kick(dev, ep);
+			req = 0;
+
+		} else if (ep_is_in(ep)) {
+			gintsts = readl(&reg->gintsts);
+			DEBUG_IN_EP("%s: ep_is_in, S3C_UDC_OTG_GINTSTS=0x%x\n",
+						__func__, gintsts);
+
+			setdma_tx(ep, req);
+		} else {
+			gintsts = readl(&reg->gintsts);
+			DEBUG_OUT_EP("%s:ep_is_out, S3C_UDC_OTG_GINTSTS=0x%x\n",
+				__func__, gintsts);
+
+			setdma_rx(ep, req);
+		}
+	}
+
+	/* pio or dma irq handler advances the queue. */
+	if (likely(req != 0))
+		list_add_tail(&req->queue, &ep->queue);
+
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	return 0;
+}
+
+/****************************************************************/
+/* End Point 0 related functions                                */
+/****************************************************************/
+
+/* return:  0 = still running, 1 = completed, negative = errno */
+static int write_fifo_ep0(struct s3c_ep *ep, struct s3c_request *req)
+{
+	u32 max;
+	unsigned count;
+	int is_last;
+
+	max = ep_maxpacket(ep);
+
+	DEBUG_EP0("%s: max = %d\n", __func__, max);
+
+	count = setdma_tx(ep, req);
+
+	/* last packet is usually short (or a zlp) */
+	if (likely(count != max))
+		is_last = 1;
+	else {
+		if (likely(req->req.length != req->req.actual + count)
+		    || req->req.zero)
+			is_last = 0;
+		else
+			is_last = 1;
+	}
+
+	DEBUG_EP0("%s: wrote %s %d bytes%s %d left %p\n", __func__,
+		  ep->ep.name, count,
+		  is_last ? "/L" : "",
+		  req->req.length - req->req.actual - count, req);
+
+	/* requests complete when all IN data is in the FIFO */
+	if (is_last) {
+		ep->dev->ep0state = WAIT_FOR_SETUP;
+		return 1;
+	}
+
+	return 0;
+}
+
+int s3c_fifo_read(struct s3c_ep *ep, u32 *cp, int max)
+{
+	u32 bytes;
+
+	bytes = sizeof(struct usb_ctrlrequest);
+
+	invalidate_dcache_range((unsigned long) ep->dev->dma_buf[ep_index(ep)],
+				(unsigned long) ep->dev->dma_buf[ep_index(ep)]
+				+ DMA_BUFFER_SIZE);
+
+	DEBUG_EP0("%s: bytes=%d, ep_index=%d %p\n", __func__,
+		  bytes, ep_index(ep), ep->dev->dma_buf[ep_index(ep)]);
+
+	return bytes;
+}
+
+/**
+ * udc_set_address - set the USB address for this device
+ * @address:
+ *
+ * Called from control endpoint function
+ * after it decodes a set address setup packet.
+ */
+static void udc_set_address(struct s3c_udc *dev, unsigned char address)
+{
+	u32 ctrl = readl(&reg->dcfg);
+	writel(DEVICE_ADDRESS(address) | ctrl, &reg->dcfg);
+
+	s3c_udc_ep0_zlp(dev);
+
+	DEBUG_EP0("%s: USB OTG 2.0 Device address=%d, DCFG=0x%x\n",
+		__func__, address, readl(&reg->dcfg));
+
+	dev->usb_address = address;
+}
+
+static inline void s3c_udc_ep0_set_stall(struct s3c_ep *ep)
+{
+	struct s3c_udc *dev;
+	u32		ep_ctrl = 0;
+
+	dev = ep->dev;
+	ep_ctrl = readl(&reg->in_endp[EP0_CON].diepctl);
+
+	/* set the disable and stall bits */
+	if (ep_ctrl & DEPCTL_EPENA)
+		ep_ctrl |= DEPCTL_EPDIS;
+
+	ep_ctrl |= DEPCTL_STALL;
+
+	writel(ep_ctrl, &reg->in_endp[EP0_CON].diepctl);
+
+	DEBUG_EP0("%s: set ep%d stall, DIEPCTL0 = 0x%x\n",
+		__func__, ep_index(ep), &reg->in_endp[EP0_CON].diepctl);
+	/*
+	 * The application can only set this bit, and the core clears it,
+	 * when a SETUP token is received for this endpoint
+	 */
+	dev->ep0state = WAIT_FOR_SETUP;
+
+	s3c_udc_pre_setup();
+}
+
+static void s3c_ep0_read(struct s3c_udc *dev)
+{
+	struct s3c_request *req;
+	struct s3c_ep *ep = &dev->ep[0];
+	int ret;
+
+	if (!list_empty(&ep->queue)) {
+		req = list_entry(ep->queue.next, struct s3c_request, queue);
+
+	} else {
+		DEBUG("%s: ---> BUG\n", __func__);
+		BUG();
+		return;
+	}
+
+	DEBUG_EP0("%s: req = %p, req.length = 0x%x, req.actual = 0x%x\n",
+		__func__, req, req->req.length, req->req.actual);
+
+	if (req->req.length == 0) {
+		/* zlp for Set_configuration, Set_interface,
+		 * or Bulk-Only mass storge reset */
+
+		ep->len = 0;
+		s3c_udc_ep0_zlp(dev);
+
+		DEBUG_EP0("%s: req.length = 0, bRequest = %d\n",
+			  __func__, usb_ctrl->bRequest);
+		return;
+	}
+
+	ret = setdma_rx(ep, req);
+}
+
+/*
+ * DATA_STATE_XMIT
+ */
+static int s3c_ep0_write(struct s3c_udc *dev)
+{
+	struct s3c_request *req;
+	struct s3c_ep *ep = &dev->ep[0];
+	int ret, need_zlp = 0;
+
+	if (list_empty(&ep->queue))
+		req = 0;
+	else
+		req = list_entry(ep->queue.next, struct s3c_request, queue);
+
+	if (!req) {
+		DEBUG_EP0("%s: NULL REQ\n", __func__);
+		return 0;
+	}
+
+	DEBUG_EP0("%s: req = %p, req.length = 0x%x, req.actual = 0x%x\n",
+		__func__, req, req->req.length, req->req.actual);
+
+	if (req->req.length - req->req.actual == ep0_fifo_size) {
+		/* Next write will end with the packet size, */
+		/* so we need Zero-length-packet */
+		need_zlp = 1;
+	}
+
+	ret = write_fifo_ep0(ep, req);
+
+	if ((ret == 1) && !need_zlp) {
+		/* Last packet */
+		dev->ep0state = WAIT_FOR_COMPLETE;
+		DEBUG_EP0("%s: finished, waiting for status\n", __func__);
+
+	} else {
+		dev->ep0state = DATA_STATE_XMIT;
+		DEBUG_EP0("%s: not finished\n", __func__);
+	}
+
+	return 1;
+}
+
+u16	g_status;
+
+int s3c_udc_get_status(struct s3c_udc *dev,
+		struct usb_ctrlrequest *crq)
+{
+	u8 ep_num = crq->wIndex & 0x7F;
+	u32 ep_ctrl;
+	u32 *p = the_controller->dma_buf[1];
+
+	DEBUG_SETUP("%s: *** USB_REQ_GET_STATUS\n", __func__);
+	printf("crq->brequest:0x%x\n", crq->bRequestType & USB_RECIP_MASK);
+	switch (crq->bRequestType & USB_RECIP_MASK) {
+	case USB_RECIP_INTERFACE:
+		g_status = 0;
+		DEBUG_SETUP("\tGET_STATUS:USB_RECIP_INTERFACE, g_stauts = %d\n",
+			    g_status);
+		break;
+
+	case USB_RECIP_DEVICE:
+		g_status = 0x1; /* Self powered */
+		DEBUG_SETUP("\tGET_STATUS: USB_RECIP_DEVICE, g_stauts = %d\n",
+			    g_status);
+		break;
+
+	case USB_RECIP_ENDPOINT:
+		if (crq->wLength > 2) {
+			DEBUG_SETUP("\tGET_STATUS:Not support EP or wLength\n");
+			return 1;
+		}
+
+		g_status = dev->ep[ep_num].stopped;
+		DEBUG_SETUP("\tGET_STATUS: USB_RECIP_ENDPOINT, g_stauts = %d\n",
+			    g_status);
+
+		break;
+
+	default:
+		return 1;
+	}
+
+	memcpy(p, &g_status, sizeof(g_status));
+
+	flush_dcache_range((unsigned long) p,
+			   (unsigned long) p + DMA_BUFFER_SIZE);
+
+	writel(the_controller->dma_addr[1], &reg->in_endp[EP0_CON].diepdma);
+	writel(DIEPT_SIZ_PKT_CNT(1) | DIEPT_SIZ_XFER_SIZE(2),
+	       &reg->in_endp[EP0_CON].dieptsiz);
+
+	ep_ctrl = readl(&reg->in_endp[EP0_CON].diepctl);
+	writel(ep_ctrl|DEPCTL_EPENA|DEPCTL_CNAK,
+	       &reg->in_endp[EP0_CON].diepctl);
+	dev->ep0state = WAIT_FOR_NULL_COMPLETE;
+
+	return 0;
+}
+
+static void s3c_udc_set_nak(struct s3c_ep *ep)
+{
+	u8		ep_num;
+	u32		ep_ctrl = 0;
+
+	ep_num = ep_index(ep);
+	DEBUG("%s: ep_num = %d, ep_type = %d\n", __func__, ep_num, ep->ep_type);
+
+	if (ep_is_in(ep)) {
+		ep_ctrl = readl(&reg->in_endp[ep_num].diepctl);
+		ep_ctrl |= DEPCTL_SNAK;
+		writel(ep_ctrl, &reg->in_endp[ep_num].diepctl);
+		DEBUG("%s: set NAK, DIEPCTL%d = 0x%x\n",
+			__func__, ep_num, readl(&reg->in_endp[ep_num].diepctl));
+	} else {
+		ep_ctrl = readl(&reg->out_endp[ep_num].doepctl);
+		ep_ctrl |= DEPCTL_SNAK;
+		writel(ep_ctrl, &reg->out_endp[ep_num].doepctl);
+		DEBUG("%s: set NAK, DOEPCTL%d = 0x%x\n",
+		      __func__, ep_num, readl(&reg->out_endp[ep_num].doepctl));
+	}
+
+	return;
+}
+
+
+void s3c_udc_ep_set_stall(struct s3c_ep *ep)
+{
+	u8		ep_num;
+	u32		ep_ctrl = 0;
+
+	ep_num = ep_index(ep);
+	DEBUG("%s: ep_num = %d, ep_type = %d\n", __func__, ep_num, ep->ep_type);
+
+	if (ep_is_in(ep)) {
+		ep_ctrl = readl(&reg->in_endp[ep_num].diepctl);
+
+		/* set the disable and stall bits */
+		if (ep_ctrl & DEPCTL_EPENA)
+			ep_ctrl |= DEPCTL_EPDIS;
+
+		ep_ctrl |= DEPCTL_STALL;
+
+		writel(ep_ctrl, &reg->in_endp[ep_num].diepctl);
+		DEBUG("%s: set stall, DIEPCTL%d = 0x%x\n",
+		      __func__, ep_num, readl(&reg->in_endp[ep_num].diepctl));
+
+	} else {
+		ep_ctrl = readl(&reg->out_endp[ep_num].doepctl);
+
+		/* set the stall bit */
+		ep_ctrl |= DEPCTL_STALL;
+
+		writel(ep_ctrl, &reg->out_endp[ep_num].doepctl);
+		DEBUG("%s: set stall, DOEPCTL%d = 0x%x\n",
+		      __func__, ep_num, readl(&reg->out_endp[ep_num].doepctl));
+	}
+
+	return;
+}
+
+void s3c_udc_ep_clear_stall(struct s3c_ep *ep)
+{
+	u8		ep_num;
+	u32		ep_ctrl = 0;
+
+	ep_num = ep_index(ep);
+	DEBUG("%s: ep_num = %d, ep_type = %d\n", __func__, ep_num, ep->ep_type);
+
+	if (ep_is_in(ep)) {
+		ep_ctrl = readl(&reg->in_endp[ep_num].diepctl);
+
+		/* clear stall bit */
+		ep_ctrl &= ~DEPCTL_STALL;
+
+		/*
+		 * USB Spec 9.4.5: For endpoints using data toggle, regardless
+		 * of whether an endpoint has the Halt feature set, a
+		 * ClearFeature(ENDPOINT_HALT) request always results in the
+		 * data toggle being reinitialized to DATA0.
+		 */
+		if (ep->bmAttributes == USB_ENDPOINT_XFER_INT
+		    || ep->bmAttributes == USB_ENDPOINT_XFER_BULK) {
+			ep_ctrl |= DEPCTL_SETD0PID; /* DATA0 */
+		}
+
+		writel(ep_ctrl, &reg->in_endp[ep_num].diepctl);
+		DEBUG("%s: cleared stall, DIEPCTL%d = 0x%x\n",
+			__func__, ep_num, readl(&reg->in_endp[ep_num].diepctl));
+
+	} else {
+		ep_ctrl = readl(&reg->out_endp[ep_num].doepctl);
+
+		/* clear stall bit */
+		ep_ctrl &= ~DEPCTL_STALL;
+
+		if (ep->bmAttributes == USB_ENDPOINT_XFER_INT
+		    || ep->bmAttributes == USB_ENDPOINT_XFER_BULK) {
+			ep_ctrl |= DEPCTL_SETD0PID; /* DATA0 */
+		}
+
+		writel(ep_ctrl, &reg->out_endp[ep_num].doepctl);
+		DEBUG("%s: cleared stall, DOEPCTL%d = 0x%x\n",
+		      __func__, ep_num, readl(&reg->out_endp[ep_num].doepctl));
+	}
+
+	return;
+}
+
+static int s3c_udc_set_halt(struct usb_ep *_ep, int value)
+{
+	struct s3c_ep	*ep;
+	struct s3c_udc	*dev;
+	unsigned long	flags;
+	u8		ep_num;
+
+	ep = container_of(_ep, struct s3c_ep, ep);
+	ep_num = ep_index(ep);
+
+	if (unlikely(!_ep || !ep->desc || ep_num == EP0_CON ||
+		     ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC)) {
+		DEBUG("%s: %s bad ep or descriptor\n", __func__, ep->ep.name);
+		return -EINVAL;
+	}
+
+	/* Attempt to halt IN ep will fail if any transfer requests
+	 * are still queue */
+	if (value && ep_is_in(ep) && !list_empty(&ep->queue)) {
+		DEBUG("%s: %s queue not empty, req = %p\n",
+			__func__, ep->ep.name,
+			list_entry(ep->queue.next, struct s3c_request, queue));
+
+		return -EAGAIN;
+	}
+
+	dev = ep->dev;
+	DEBUG("%s: ep_num = %d, value = %d\n", __func__, ep_num, value);
+
+	spin_lock_irqsave(&dev->lock, flags);
+
+	if (value == 0) {
+		ep->stopped = 0;
+		s3c_udc_ep_clear_stall(ep);
+	} else {
+		if (ep_num == 0)
+			dev->ep0state = WAIT_FOR_SETUP;
+
+		ep->stopped = 1;
+		s3c_udc_ep_set_stall(ep);
+	}
+
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	return 0;
+}
+
+void s3c_udc_ep_activate(struct s3c_ep *ep)
+{
+	u8 ep_num;
+	u32 ep_ctrl = 0, daintmsk = 0;
+
+	ep_num = ep_index(ep);
+
+	/* Read DEPCTLn register */
+	if (ep_is_in(ep)) {
+		ep_ctrl = readl(&reg->in_endp[ep_num].diepctl);
+		daintmsk = 1 << ep_num;
+	} else {
+		ep_ctrl = readl(&reg->out_endp[ep_num].doepctl);
+		daintmsk = (1 << ep_num) << DAINT_OUT_BIT;
+	}
+
+	DEBUG("%s: EPCTRL%d = 0x%x, ep_is_in = %d\n",
+		__func__, ep_num, ep_ctrl, ep_is_in(ep));
+
+	/* If the EP is already active don't change the EP Control
+	 * register. */
+	if (!(ep_ctrl & DEPCTL_USBACTEP)) {
+		ep_ctrl = (ep_ctrl & ~DEPCTL_TYPE_MASK) |
+			(ep->bmAttributes << DEPCTL_TYPE_BIT);
+		ep_ctrl = (ep_ctrl & ~DEPCTL_MPS_MASK) |
+			(ep->ep.maxpacket << DEPCTL_MPS_BIT);
+		ep_ctrl |= (DEPCTL_SETD0PID | DEPCTL_USBACTEP | DEPCTL_SNAK);
+
+		if (ep_is_in(ep)) {
+			writel(ep_ctrl, &reg->in_endp[ep_num].diepctl);
+			DEBUG("%s: USB Ative EP%d, DIEPCTRL%d = 0x%x\n",
+			      __func__, ep_num, ep_num,
+			      readl(&reg->in_endp[ep_num].diepctl));
+		} else {
+			writel(ep_ctrl, &reg->out_endp[ep_num].doepctl);
+			DEBUG("%s: USB Ative EP%d, DOEPCTRL%d = 0x%x\n",
+			      __func__, ep_num, ep_num,
+			      readl(&reg->out_endp[ep_num].doepctl));
+		}
+	}
+
+	/* Unmask EP Interrtupt */
+	writel(readl(&reg->daintmsk)|daintmsk, &reg->daintmsk);
+	DEBUG("%s: DAINTMSK = 0x%x\n", __func__, readl(&reg->daintmsk));
+
+}
+
+static int s3c_udc_clear_feature(struct usb_ep *_ep)
+{
+	struct s3c_udc	*dev;
+	struct s3c_ep	*ep;
+	u8		ep_num;
+
+	ep = container_of(_ep, struct s3c_ep, ep);
+	ep_num = ep_index(ep);
+
+	dev = ep->dev;
+	DEBUG_SETUP("%s: ep_num = %d, is_in = %d, clear_feature_flag = %d\n",
+		__func__, ep_num, ep_is_in(ep), clear_feature_flag);
+
+	if (usb_ctrl->wLength != 0) {
+		DEBUG_SETUP("\tCLEAR_FEATURE: wLength is not zero.....\n");
+		return 1;
+	}
+
+	switch (usb_ctrl->bRequestType & USB_RECIP_MASK) {
+	case USB_RECIP_DEVICE:
+		switch (usb_ctrl->wValue) {
+		case USB_DEVICE_REMOTE_WAKEUP:
+			DEBUG_SETUP("\tOFF:USB_DEVICE_REMOTE_WAKEUP\n");
+			break;
+
+		case USB_DEVICE_TEST_MODE:
+			DEBUG_SETUP("\tCLEAR_FEATURE: USB_DEVICE_TEST_MODE\n");
+			/** @todo Add CLEAR_FEATURE for TEST modes. */
+			break;
+		}
+
+		s3c_udc_ep0_zlp(dev);
+		break;
+
+	case USB_RECIP_ENDPOINT:
+		DEBUG_SETUP("\tCLEAR_FEATURE:USB_RECIP_ENDPOINT, wValue = %d\n",
+				usb_ctrl->wValue);
+
+		if (usb_ctrl->wValue == USB_ENDPOINT_HALT) {
+			if (ep_num == 0) {
+				s3c_udc_ep0_set_stall(ep);
+				return 0;
+			}
+
+			s3c_udc_ep0_zlp(dev);
+
+			s3c_udc_ep_clear_stall(ep);
+			s3c_udc_ep_activate(ep);
+			ep->stopped = 0;
+
+			clear_feature_num = ep_num;
+			clear_feature_flag = 1;
+		}
+		break;
+	}
+
+	return 0;
+}
+
+static int s3c_udc_set_feature(struct usb_ep *_ep)
+{
+	struct s3c_udc	*dev;
+	struct s3c_ep	*ep;
+	u8		ep_num;
+
+	ep = container_of(_ep, struct s3c_ep, ep);
+	ep_num = ep_index(ep);
+	dev = ep->dev;
+
+	DEBUG_SETUP("%s: *** USB_REQ_SET_FEATURE , ep_num = %d\n",
+		    __func__, ep_num);
+
+	if (usb_ctrl->wLength != 0) {
+		DEBUG_SETUP("\tSET_FEATURE: wLength is not zero.....\n");
+		return 1;
+	}
+
+	switch (usb_ctrl->bRequestType & USB_RECIP_MASK) {
+	case USB_RECIP_DEVICE:
+		switch (usb_ctrl->wValue) {
+		case USB_DEVICE_REMOTE_WAKEUP:
+			DEBUG_SETUP("\tSET_FEATURE:USB_DEVICE_REMOTE_WAKEUP\n");
+			break;
+		case USB_DEVICE_B_HNP_ENABLE:
+			DEBUG_SETUP("\tSET_FEATURE: USB_DEVICE_B_HNP_ENABLE\n");
+			break;
+
+		case USB_DEVICE_A_HNP_SUPPORT:
+			/* RH port supports HNP */
+			DEBUG_SETUP("\tSET_FEATURE:USB_DEVICE_A_HNP_SUPPORT\n");
+			break;
+
+		case USB_DEVICE_A_ALT_HNP_SUPPORT:
+			/* other RH port does */
+			DEBUG_SETUP("\tSET: USB_DEVICE_A_ALT_HNP_SUPPORT\n");
+			break;
+		}
+
+		s3c_udc_ep0_zlp(dev);
+		return 0;
+
+	case USB_RECIP_INTERFACE:
+		DEBUG_SETUP("\tSET_FEATURE: USB_RECIP_INTERFACE\n");
+		break;
+
+	case USB_RECIP_ENDPOINT:
+		DEBUG_SETUP("\tSET_FEATURE: USB_RECIP_ENDPOINT\n");
+		if (usb_ctrl->wValue == USB_ENDPOINT_HALT) {
+			if (ep_num == 0) {
+				s3c_udc_ep0_set_stall(ep);
+				return 0;
+			}
+			ep->stopped = 1;
+			s3c_udc_ep_set_stall(ep);
+		}
+
+		s3c_udc_ep0_zlp(dev);
+		return 0;
+	}
+
+	return 1;
+}
+
+/*
+ * WAIT_FOR_SETUP (OUT_PKT_RDY)
+ */
+void s3c_ep0_setup(struct s3c_udc *dev)
+{
+	struct s3c_ep *ep = &dev->ep[0];
+	int i, bytes, is_in;
+	u8 ep_num;
+
+	/* Nuke all previous transfers */
+	nuke(ep, -EPROTO);
+
+	/* read control req from fifo (8 bytes) */
+	bytes = s3c_fifo_read(ep, (u32 *)usb_ctrl, 8);
+
+	DEBUG_SETUP("%s: bRequestType = 0x%x(%s), bRequest = 0x%x"
+		    "\twLength = 0x%x, wValue = 0x%x, wIndex= 0x%x\n",
+		    __func__, usb_ctrl->bRequestType,
+		    (usb_ctrl->bRequestType & USB_DIR_IN) ? "IN" : "OUT",
+		    usb_ctrl->bRequest,
+		    usb_ctrl->wLength, usb_ctrl->wValue, usb_ctrl->wIndex);
+
+#ifdef DEBUG_S3C_UDC
+	{
+		int i, len = sizeof(*usb_ctrl);
+		char *p = usb_ctrl;
+
+		printf("pkt = ");
+		for (i = 0; i < len; i++) {
+			printf("%02x", ((u8 *)p)[i]);
+			if ((i & 7) == 7)
+				printf(" ");
+		}
+		printf("\n");
+	}
+#endif
+
+	if (usb_ctrl->bRequest == GET_MAX_LUN_REQUEST &&
+	    usb_ctrl->wLength != 1) {
+		DEBUG_SETUP("\t%s:GET_MAX_LUN_REQUEST:invalid",
+			      __func__);
+		DEBUG_SETUP("wLength = %d, setup returned\n",
+			    usb_ctrl->wLength);
+
+		s3c_udc_ep0_set_stall(ep);
+		dev->ep0state = WAIT_FOR_SETUP;
+
+		return;
+	} else if (usb_ctrl->bRequest == BOT_RESET_REQUEST &&
+		 usb_ctrl->wLength != 0) {
+		/* Bulk-Only *mass storge reset of class-specific request */
+		DEBUG_SETUP("%s:BOT Rest:invalid wLength =%d, setup returned\n",
+			    __func__, usb_ctrl->wLength);
+
+		s3c_udc_ep0_set_stall(ep);
+		dev->ep0state = WAIT_FOR_SETUP;
+
+		return;
+	}
+
+	/* Set direction of EP0 */
+	if (likely(usb_ctrl->bRequestType & USB_DIR_IN)) {
+		ep->bEndpointAddress |= USB_DIR_IN;
+		is_in = 1;
+
+	} else {
+		ep->bEndpointAddress &= ~USB_DIR_IN;
+		is_in = 0;
+	}
+	/* cope with automagic for some standard requests. */
+	dev->req_std = (usb_ctrl->bRequestType & USB_TYPE_MASK)
+		== USB_TYPE_STANDARD;
+	dev->req_config = 0;
+	dev->req_pending = 1;
+
+	/* Handle some SETUP packets ourselves */
+	if (dev->req_std) {
+		switch (usb_ctrl->bRequest) {
+		case USB_REQ_SET_ADDRESS:
+		DEBUG_SETUP("%s: *** USB_REQ_SET_ADDRESS (%d)\n",
+				__func__, usb_ctrl->wValue);
+			if (usb_ctrl->bRequestType
+				!= (USB_TYPE_STANDARD | USB_RECIP_DEVICE))
+				break;
+
+			udc_set_address(dev, usb_ctrl->wValue);
+			return;
+
+		case USB_REQ_SET_CONFIGURATION:
+			DEBUG_SETUP("=====================================\n");
+			DEBUG_SETUP("%s: USB_REQ_SET_CONFIGURATION (%d)\n",
+					__func__, usb_ctrl->wValue);
+
+			if (usb_ctrl->bRequestType == USB_RECIP_DEVICE) {
+				reset_available = 1;
+				dev->req_config = 1;
+			}
+			break;
+
+		case USB_REQ_GET_DESCRIPTOR:
+			DEBUG_SETUP("%s: *** USB_REQ_GET_DESCRIPTOR\n",
+				    __func__);
+			break;
+
+		case USB_REQ_SET_INTERFACE:
+			DEBUG_SETUP("%s: *** USB_REQ_SET_INTERFACE (%d)\n",
+					__func__, usb_ctrl->wValue);
+
+			if (usb_ctrl->bRequestType == USB_RECIP_INTERFACE) {
+				reset_available = 1;
+				dev->req_config = 1;
+			}
+			break;
+
+		case USB_REQ_GET_CONFIGURATION:
+			DEBUG_SETUP("%s: *** USB_REQ_GET_CONFIGURATION\n",
+				    __func__);
+			break;
+
+		case USB_REQ_GET_STATUS:
+			if (!s3c_udc_get_status(dev, usb_ctrl))
+				return;
+
+			break;
+
+		case USB_REQ_CLEAR_FEATURE:
+			ep_num = usb_ctrl->wIndex & 0x7f;
+
+			if (!s3c_udc_clear_feature(&dev->ep[ep_num].ep))
+				return;
+
+			break;
+
+		case USB_REQ_SET_FEATURE:
+			ep_num = usb_ctrl->wIndex & 0x7f;
+
+			if (!s3c_udc_set_feature(&dev->ep[ep_num].ep))
+				return;
+
+			break;
+
+		default:
+			DEBUG_SETUP("%s: *** Default of usb_ctrl->bRequest=0x%x"
+				"happened.\n", __func__, usb_ctrl->bRequest);
+			break;
+		}
+	}
+
+
+	if (likely(dev->driver)) {
+		/* device-2-host (IN) or no data setup command,
+		 * process immediately */
+		DEBUG_SETUP("%s:usb_ctrlreq will be passed to fsg_setup()\n",
+			    __func__);
+
+		spin_unlock(&dev->lock);
+		i = dev->driver->setup(&dev->gadget, usb_ctrl);
+		spin_lock(&dev->lock);
+
+		if (i < 0) {
+			if (dev->req_config) {
+				DEBUG_SETUP("\tconfig change 0x%02x fail %d?\n",
+					(u32)usb_ctrl->bRequest, i);
+				return;
+			}
+
+			/* setup processing failed, force stall */
+			s3c_udc_ep0_set_stall(ep);
+			dev->ep0state = WAIT_FOR_SETUP;
+
+			DEBUG_SETUP("\tdev->driver->setup failed (%d),"
+				    " bRequest = %d\n",
+				i, usb_ctrl->bRequest);
+
+
+		} else if (dev->req_pending) {
+			dev->req_pending = 0;
+			DEBUG_SETUP("\tdev->req_pending...\n");
+		}
+
+		DEBUG_SETUP("\tep0state = %s\n", state_names[dev->ep0state]);
+
+	}
+}
+
+/*
+ * handle ep0 interrupt
+ */
+static void s3c_handle_ep0(struct s3c_udc *dev)
+{
+	if (dev->ep0state == WAIT_FOR_SETUP) {
+		DEBUG_OUT_EP("%s: WAIT_FOR_SETUP\n", __func__);
+		s3c_ep0_setup(dev);
+
+	} else {
+		DEBUG_OUT_EP("%s: strange state!!(state = %s)\n",
+			__func__, state_names[dev->ep0state]);
+	}
+}
+
+static void s3c_ep0_kick(struct s3c_udc *dev, struct s3c_ep *ep)
+{
+	DEBUG_EP0("%s: ep_is_in = %d\n", __func__, ep_is_in(ep));
+	if (ep_is_in(ep)) {
+		dev->ep0state = DATA_STATE_XMIT;
+		s3c_ep0_write(dev);
+
+	} else {
+		dev->ep0state = DATA_STATE_RECV;
+		s3c_ep0_read(dev);
+	}
+}

+ 1 - 0
drivers/usb/host/Makefile

@@ -42,6 +42,7 @@ COBJS-$(CONFIG_USB_EHCI_FSL) += ehci-fsl.o
 endif
 COBJS-$(CONFIG_USB_EHCI_MXC) += ehci-mxc.o
 COBJS-$(CONFIG_USB_EHCI_MXS) += ehci-mxs.o
+COBJS-$(CONFIG_USB_EHCI_MX5) += ehci-mx5.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

+ 43 - 4
drivers/usb/host/ehci-hcd.c

@@ -26,6 +26,10 @@
 #include <asm/io.h>
 #include <malloc.h>
 #include <watchdog.h>
+#ifdef CONFIG_USB_KEYBOARD
+#include <stdio_dev.h>
+extern unsigned char new[];
+#endif
 
 #include "ehci.h"
 
@@ -48,7 +52,7 @@ static struct descriptor {
 		0x29,		/* bDescriptorType: hub descriptor */
 		2,		/* bNrPorts -- runtime modified */
 		0,		/* wHubCharacteristics */
-		0xff,		/* bPwrOn2PwrGood */
+		10,		/* bPwrOn2PwrGood */
 		0,		/* bHubCntrCurrent */
 		{},		/* Device removable */
 		{}		/* at most 7 ports! XXX */
@@ -201,6 +205,14 @@ static inline void ehci_invalidate_dcache(struct QH *qh)
 }
 #endif /* CONFIG_EHCI_DCACHE */
 
+void __ehci_powerup_fixup(uint32_t *status_reg, uint32_t *reg)
+{
+	mdelay(50);
+}
+
+void ehci_powerup_fixup(uint32_t *status_reg, uint32_t *reg)
+	__attribute__((weak, alias("__ehci_powerup_fixup")));
+
 static int handshake(uint32_t *ptr, uint32_t mask, uint32_t done, int usec)
 {
 	uint32_t result;
@@ -709,8 +721,8 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 				 * usb 2.0 specification say 50 ms resets on
 				 * root
 				 */
-				wait_ms(50);
-				/* terminate the reset */
+				ehci_powerup_fixup(status_reg, &reg);
+
 				ehci_writel(status_reg, reg & ~EHCI_PS_PR);
 				/*
 				 * A host controller must terminate the reset
@@ -895,5 +907,32 @@ submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
 
 	debug("dev=%p, pipe=%lu, buffer=%p, length=%d, interval=%d",
 	      dev, pipe, buffer, length, interval);
-	return -1;
+	return ehci_submit_async(dev, pipe, buffer, length, NULL);
+}
+
+#ifdef CONFIG_SYS_USB_EVENT_POLL
+/*
+ * This function polls for USB keyboard data.
+ */
+void usb_event_poll()
+{
+	struct stdio_dev *dev;
+	struct usb_device *usb_kbd_dev;
+	struct usb_interface *iface;
+	struct usb_endpoint_descriptor *ep;
+	int pipe;
+	int maxp;
+
+	/* Get the pointer to USB Keyboard device pointer */
+	dev = stdio_get_by_name("usbkbd");
+	usb_kbd_dev = (struct usb_device *)dev->priv;
+	iface = &usb_kbd_dev->config.if_desc[0];
+	ep = &iface->ep_desc[0];
+	pipe = usb_rcvintpipe(usb_kbd_dev, ep->bEndpointAddress);
+
+	/* Submit a interrupt transfer request */
+	maxp = usb_maxpacket(usb_kbd_dev, pipe);
+	usb_submit_int_msg(usb_kbd_dev, pipe, &new[0],
+			maxp > 8 ? 8 : maxp, ep->bInterval);
 }
+#endif /* CONFIG_SYS_USB_EVENT_POLL */

+ 255 - 0
drivers/usb/host/ehci-mx5.c

@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
+ * Copyright (C) 2010 Freescale Semiconductor, Inc.
+ *
+ * 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.
+ */
+
+#include <common.h>
+#include <usb.h>
+#include <errno.h>
+#include <linux/compiler.h>
+#include <usb/ehci-fsl.h>
+#include <asm/io.h>
+#include <asm/arch/imx-regs.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/mx5x_pins.h>
+#include <asm/arch/iomux.h>
+
+#include "ehci.h"
+#include "ehci-core.h"
+
+#define MX5_USBOTHER_REGS_OFFSET 0x800
+
+
+#define MXC_OTG_OFFSET		0
+#define MXC_H1_OFFSET		0x200
+#define MXC_H2_OFFSET		0x400
+
+#define MXC_USBCTRL_OFFSET		0
+#define MXC_USB_PHY_CTR_FUNC_OFFSET	0x8
+#define MXC_USB_PHY_CTR_FUNC2_OFFSET	0xc
+#define MXC_USB_CTRL_1_OFFSET		0x10
+#define MXC_USBH2CTRL_OFFSET		0x14
+
+/* USB_CTRL */
+#define MXC_OTG_UCTRL_OWIE_BIT	(1 << 27) /* OTG wakeup intr enable */
+#define MXC_OTG_UCTRL_OPM_BIT	(1 << 24) /* OTG power mask */
+#define MXC_H1_UCTRL_H1UIE_BIT	(1 << 12) /* Host1 ULPI interrupt enable */
+#define MXC_H1_UCTRL_H1WIE_BIT	(1 << 11) /* HOST1 wakeup intr enable */
+#define MXC_H1_UCTRL_H1PM_BIT	(1 << 8) /* HOST1 power mask */
+
+/* USB_PHY_CTRL_FUNC */
+#define MXC_OTG_PHYCTRL_OC_DIS_BIT (1 << 8) /* OTG Disable Overcurrent Event */
+#define MXC_H1_OC_DIS_BIT	(1 << 5) /* UH1 Disable Overcurrent Event */
+
+/* USBH2CTRL */
+#define MXC_H2_UCTRL_H2UIE_BIT	(1 << 8)
+#define MXC_H2_UCTRL_H2WIE_BIT	(1 << 7)
+#define MXC_H2_UCTRL_H2PM_BIT	(1 << 4)
+
+/* USB_CTRL_1 */
+#define MXC_USB_CTRL_UH1_EXT_CLK_EN		(1 << 25)
+
+/* USB pin configuration */
+#define USB_PAD_CONFIG	(PAD_CTL_PKE_ENABLE | PAD_CTL_SRE_FAST | \
+			PAD_CTL_DRV_HIGH | PAD_CTL_100K_PU | \
+			PAD_CTL_HYS_ENABLE | PAD_CTL_PUE_PULL)
+
+#ifdef CONFIG_MX51
+/*
+ * Configure the MX51 USB H1 IOMUX
+ */
+void setup_iomux_usb_h1(void)
+{
+	mxc_request_iomux(MX51_PIN_USBH1_STP, IOMUX_CONFIG_ALT0);
+	mxc_iomux_set_pad(MX51_PIN_USBH1_STP, USB_PAD_CONFIG);
+	mxc_request_iomux(MX51_PIN_USBH1_CLK, IOMUX_CONFIG_ALT0);
+	mxc_iomux_set_pad(MX51_PIN_USBH1_CLK, USB_PAD_CONFIG);
+	mxc_request_iomux(MX51_PIN_USBH1_DIR, IOMUX_CONFIG_ALT0);
+	mxc_iomux_set_pad(MX51_PIN_USBH1_DIR, USB_PAD_CONFIG);
+	mxc_request_iomux(MX51_PIN_USBH1_NXT, IOMUX_CONFIG_ALT0);
+	mxc_iomux_set_pad(MX51_PIN_USBH1_NXT, USB_PAD_CONFIG);
+
+	mxc_request_iomux(MX51_PIN_USBH1_DATA0, IOMUX_CONFIG_ALT0);
+	mxc_iomux_set_pad(MX51_PIN_USBH1_DATA0, USB_PAD_CONFIG);
+	mxc_request_iomux(MX51_PIN_USBH1_DATA1, IOMUX_CONFIG_ALT0);
+	mxc_iomux_set_pad(MX51_PIN_USBH1_DATA1, USB_PAD_CONFIG);
+	mxc_request_iomux(MX51_PIN_USBH1_DATA2, IOMUX_CONFIG_ALT0);
+	mxc_iomux_set_pad(MX51_PIN_USBH1_DATA2, USB_PAD_CONFIG);
+	mxc_request_iomux(MX51_PIN_USBH1_DATA3, IOMUX_CONFIG_ALT0);
+	mxc_iomux_set_pad(MX51_PIN_USBH1_DATA3, USB_PAD_CONFIG);
+	mxc_request_iomux(MX51_PIN_USBH1_DATA4, IOMUX_CONFIG_ALT0);
+	mxc_iomux_set_pad(MX51_PIN_USBH1_DATA4, USB_PAD_CONFIG);
+	mxc_request_iomux(MX51_PIN_USBH1_DATA5, IOMUX_CONFIG_ALT0);
+	mxc_iomux_set_pad(MX51_PIN_USBH1_DATA5, USB_PAD_CONFIG);
+	mxc_request_iomux(MX51_PIN_USBH1_DATA6, IOMUX_CONFIG_ALT0);
+	mxc_iomux_set_pad(MX51_PIN_USBH1_DATA6, USB_PAD_CONFIG);
+	mxc_request_iomux(MX51_PIN_USBH1_DATA7, IOMUX_CONFIG_ALT0);
+	mxc_iomux_set_pad(MX51_PIN_USBH1_DATA7, USB_PAD_CONFIG);
+}
+
+/*
+ * Configure the MX51 USB H2 IOMUX
+ */
+void setup_iomux_usb_h2(void)
+{
+	mxc_request_iomux(MX51_PIN_EIM_A24, IOMUX_CONFIG_ALT2);
+	mxc_iomux_set_pad(MX51_PIN_EIM_A24, USB_PAD_CONFIG);
+	mxc_request_iomux(MX51_PIN_EIM_A25, IOMUX_CONFIG_ALT2);
+	mxc_iomux_set_pad(MX51_PIN_EIM_A25, USB_PAD_CONFIG);
+	mxc_request_iomux(MX51_PIN_EIM_A26, IOMUX_CONFIG_ALT2);
+	mxc_iomux_set_pad(MX51_PIN_EIM_A26, USB_PAD_CONFIG);
+	mxc_request_iomux(MX51_PIN_EIM_A27, IOMUX_CONFIG_ALT2);
+	mxc_iomux_set_pad(MX51_PIN_EIM_A27, USB_PAD_CONFIG);
+
+	mxc_request_iomux(MX51_PIN_EIM_D16, IOMUX_CONFIG_ALT2);
+	mxc_iomux_set_pad(MX51_PIN_EIM_D16, USB_PAD_CONFIG);
+	mxc_request_iomux(MX51_PIN_EIM_D17, IOMUX_CONFIG_ALT2);
+	mxc_iomux_set_pad(MX51_PIN_EIM_D17, USB_PAD_CONFIG);
+	mxc_request_iomux(MX51_PIN_EIM_D18, IOMUX_CONFIG_ALT2);
+	mxc_iomux_set_pad(MX51_PIN_EIM_D18, USB_PAD_CONFIG);
+	mxc_request_iomux(MX51_PIN_EIM_D19, IOMUX_CONFIG_ALT2);
+	mxc_iomux_set_pad(MX51_PIN_EIM_D19, USB_PAD_CONFIG);
+	mxc_request_iomux(MX51_PIN_EIM_D20, IOMUX_CONFIG_ALT2);
+	mxc_iomux_set_pad(MX51_PIN_EIM_D20, USB_PAD_CONFIG);
+	mxc_request_iomux(MX51_PIN_EIM_D21, IOMUX_CONFIG_ALT2);
+	mxc_iomux_set_pad(MX51_PIN_EIM_D21, USB_PAD_CONFIG);
+	mxc_request_iomux(MX51_PIN_EIM_D22, IOMUX_CONFIG_ALT2);
+	mxc_iomux_set_pad(MX51_PIN_EIM_D22, USB_PAD_CONFIG);
+	mxc_request_iomux(MX51_PIN_EIM_D23, IOMUX_CONFIG_ALT2);
+	mxc_iomux_set_pad(MX51_PIN_EIM_D23, USB_PAD_CONFIG);
+}
+#endif
+
+int mxc_set_usbcontrol(int port, unsigned int flags)
+{
+	unsigned int v;
+	void __iomem *usb_base = (void __iomem *)OTG_BASE_ADDR;
+	void __iomem *usbother_base;
+	int ret = 0;
+
+	usbother_base = usb_base + MX5_USBOTHER_REGS_OFFSET;
+
+	switch (port) {
+	case 0:	/* OTG port */
+		if (flags & MXC_EHCI_INTERNAL_PHY) {
+			v = __raw_readl(usbother_base +
+					MXC_USB_PHY_CTR_FUNC_OFFSET);
+			if (flags & MXC_EHCI_POWER_PINS_ENABLED)
+				/* OC/USBPWR is not used */
+				v |= MXC_OTG_PHYCTRL_OC_DIS_BIT;
+			else
+				/* OC/USBPWR is used */
+				v &= ~MXC_OTG_PHYCTRL_OC_DIS_BIT;
+			__raw_writel(v, usbother_base +
+					MXC_USB_PHY_CTR_FUNC_OFFSET);
+
+			v = __raw_readl(usbother_base + MXC_USBCTRL_OFFSET);
+			if (flags & MXC_EHCI_POWER_PINS_ENABLED)
+				v |= MXC_OTG_UCTRL_OPM_BIT;
+			else
+				v &= ~MXC_OTG_UCTRL_OPM_BIT;
+			__raw_writel(v, usbother_base + MXC_USBCTRL_OFFSET);
+		}
+		break;
+	case 1:	/* Host 1 Host ULPI */
+#ifdef CONFIG_MX51
+		/* The clock for the USBH1 ULPI port will come externally
+		   from the PHY. */
+		v = __raw_readl(usbother_base + MXC_USB_CTRL_1_OFFSET);
+		__raw_writel(v | MXC_USB_CTRL_UH1_EXT_CLK_EN, usbother_base +
+				MXC_USB_CTRL_1_OFFSET);
+#endif
+
+		v = __raw_readl(usbother_base + MXC_USBCTRL_OFFSET);
+		if (flags & MXC_EHCI_POWER_PINS_ENABLED)
+			v &= ~MXC_H1_UCTRL_H1PM_BIT; /* HOST1 power mask used */
+		else
+			v |= MXC_H1_UCTRL_H1PM_BIT; /* HOST1 power mask used */
+		__raw_writel(v, usbother_base + MXC_USBCTRL_OFFSET);
+
+		v = __raw_readl(usbother_base + MXC_USB_PHY_CTR_FUNC_OFFSET);
+		if (flags & MXC_EHCI_POWER_PINS_ENABLED)
+			v &= ~MXC_H1_OC_DIS_BIT; /* OC is used */
+		else
+			v |= MXC_H1_OC_DIS_BIT; /* OC is not used */
+		__raw_writel(v, usbother_base + MXC_USB_PHY_CTR_FUNC_OFFSET);
+
+		break;
+	case 2: /* Host 2 ULPI */
+		v = __raw_readl(usbother_base + MXC_USBH2CTRL_OFFSET);
+		if (flags & MXC_EHCI_POWER_PINS_ENABLED)
+			v &= ~MXC_H2_UCTRL_H2PM_BIT; /* HOST2 power mask used */
+		else
+			v |= MXC_H2_UCTRL_H2PM_BIT; /* HOST2 power mask used */
+
+		__raw_writel(v, usbother_base + MXC_USBH2CTRL_OFFSET);
+		break;
+	}
+
+	return ret;
+}
+
+void __board_ehci_hcd_postinit(struct usb_ehci *ehci, int port)
+{
+}
+
+void board_ehci_hcd_postinit(struct usb_ehci *ehci, int port)
+	__attribute((weak, alias("__board_ehci_hcd_postinit")));
+
+int ehci_hcd_init(void)
+{
+	struct usb_ehci *ehci;
+#ifdef CONFIG_MX53
+	struct clkctl *sc_regs = (struct clkctl *)CCM_BASE_ADDR;
+	u32 reg;
+
+	reg = __raw_readl(&sc_regs->cscmr1) & ~(1 << 26);
+	/* derive USB PHY clock multiplexer from PLL3 */
+	reg |= 1 << 26;
+	__raw_writel(reg, &sc_regs->cscmr1);
+#endif
+
+	set_usboh3_clk();
+	enable_usboh3_clk(1);
+	set_usb_phy2_clk();
+	enable_usb_phy2_clk(1);
+	mdelay(1);
+
+	/* Do board specific initialization */
+	board_ehci_hcd_init(CONFIG_MXC_USB_PORT);
+
+	ehci = (struct usb_ehci *)(OTG_BASE_ADDR +
+		(0x200 * CONFIG_MXC_USB_PORT));
+	hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength);
+	hcor = (struct ehci_hcor *)((uint32_t)hccr +
+			HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
+	setbits_le32(&ehci->usbmode, CM_HOST);
+
+	__raw_writel(CONFIG_MXC_USB_PORTSC, &ehci->portsc);
+	setbits_le32(&ehci->portsc, USB_EN);
+
+	mxc_set_usbcontrol(CONFIG_MXC_USB_PORT, CONFIG_MXC_USB_FLAGS);
+	mdelay(10);
+
+	/* Do board specific post-initialization */
+	board_ehci_hcd_postinit(ehci, CONFIG_MXC_USB_PORT);
+
+	return 0;
+}
+
+int ehci_hcd_stop(void)
+{
+	return 0;
+}
+
+

+ 43 - 32
drivers/usb/host/ohci-hcd.c

@@ -1262,12 +1262,19 @@ static int ohci_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
 	int len = 0;
 	int stat = 0;
 	__u32 datab[4];
-	__u8 *data_buf = (__u8 *)datab;
+	union {
+		void *ptr;
+		__u8 *u8;
+		__u16 *u16;
+		__u32 *u32;
+	} databuf;
 	__u16 bmRType_bReq;
 	__u16 wValue;
 	__u16 wIndex;
 	__u16 wLength;
 
+	databuf.u32 = (__u32 *)datab;
+
 #ifdef DEBUG
 pkt_print(NULL, dev, pipe, buffer, transfer_len,
 	  cmd, "SUB(rh)", usb_pipein(pipe));
@@ -1297,20 +1304,20 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len,
 	*/
 
 	case RH_GET_STATUS:
-		*(__u16 *) data_buf = cpu_to_le16(1);
+		databuf.u16[0] = cpu_to_le16(1);
 		OK(2);
 	case RH_GET_STATUS | RH_INTERFACE:
-		*(__u16 *) data_buf = cpu_to_le16(0);
+		databuf.u16[0] = cpu_to_le16(0);
 		OK(2);
 	case RH_GET_STATUS | RH_ENDPOINT:
-		*(__u16 *) data_buf = cpu_to_le16(0);
+		databuf.u16[0] = cpu_to_le16(0);
 		OK(2);
 	case RH_GET_STATUS | RH_CLASS:
-		*(__u32 *) data_buf = cpu_to_le32(
+		databuf.u32[0] = cpu_to_le32(
 				RD_RH_STAT & ~(RH_HS_CRWE | RH_HS_DRWE));
 		OK(4);
 	case RH_GET_STATUS | RH_OTHER | RH_CLASS:
-		*(__u32 *) data_buf = cpu_to_le32(RD_RH_PORTSTAT);
+		databuf.u32[0] = cpu_to_le32(RD_RH_PORTSTAT);
 		OK(4);
 
 	case RH_CLEAR_FEATURE | RH_ENDPOINT:
@@ -1374,14 +1381,14 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len,
 					min_t(unsigned int,
 					sizeof(root_hub_dev_des),
 					wLength));
-			data_buf = root_hub_dev_des; OK(len);
+			databuf.ptr = root_hub_dev_des; OK(len);
 		case (0x02): /* configuration descriptor */
 			len = min_t(unsigned int,
 					leni,
 					min_t(unsigned int,
 					sizeof(root_hub_config_des),
 					wLength));
-			data_buf = root_hub_config_des; OK(len);
+			databuf.ptr = root_hub_config_des; OK(len);
 		case (0x03): /* string descriptors */
 			if (wValue == 0x0300) {
 				len = min_t(unsigned int,
@@ -1389,7 +1396,7 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len,
 						min_t(unsigned int,
 						sizeof(root_hub_str_index0),
 						wLength));
-				data_buf = root_hub_str_index0;
+				databuf.ptr = root_hub_str_index0;
 				OK(len);
 			}
 			if (wValue == 0x0301) {
@@ -1398,7 +1405,7 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len,
 						min_t(unsigned int,
 						sizeof(root_hub_str_index1),
 						wLength));
-				data_buf = root_hub_str_index1;
+				databuf.ptr = root_hub_str_index1;
 				OK(len);
 		}
 		default:
@@ -1410,41 +1417,45 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len,
 	{
 		__u32 temp = roothub_a(&gohci);
 
-		data_buf [0] = 9;		/* min length; */
-		data_buf [1] = 0x29;
-		data_buf [2] = temp & RH_A_NDP;
+		databuf.u8[0] = 9;		/* min length; */
+		databuf.u8[1] = 0x29;
+		databuf.u8[2] = temp & RH_A_NDP;
 #ifdef CONFIG_AT91C_PQFP_UHPBUG
-		data_buf [2] = (data_buf [2] == 2) ? 1:0;
+		databuf.u8[2] = (databuf.u8[2] == 2) ? 1 : 0;
 #endif
-		data_buf [3] = 0;
+		databuf.u8[3] = 0;
 		if (temp & RH_A_PSM)	/* per-port power switching? */
-			data_buf [3] |= 0x1;
+			databuf.u8[3] |= 0x1;
 		if (temp & RH_A_NOCP)	/* no overcurrent reporting? */
-			data_buf [3] |= 0x10;
+			databuf.u8[3] |= 0x10;
 		else if (temp & RH_A_OCPM)/* per-port overcurrent reporting? */
-			data_buf [3] |= 0x8;
+			databuf.u8[3] |= 0x8;
 
-		/* corresponds to data_buf[4-7] */
-		datab [1] = 0;
-		data_buf [5] = (temp & RH_A_POTPGT) >> 24;
+		/* corresponds to databuf.u8[4-7] */
+		databuf.u8[1] = 0;
+		databuf.u8[5] = (temp & RH_A_POTPGT) >> 24;
 		temp = roothub_b(&gohci);
-		data_buf [7] = temp & RH_B_DR;
-		if (data_buf [2] < 7) {
-			data_buf [8] = 0xff;
+		databuf.u8[7] = temp & RH_B_DR;
+		if (databuf.u8[2] < 7) {
+			databuf.u8[8] = 0xff;
 		} else {
-			data_buf [0] += 2;
-			data_buf [8] = (temp & RH_B_DR) >> 8;
-			data_buf [10] = data_buf [9] = 0xff;
+			databuf.u8[0] += 2;
+			databuf.u8[8] = (temp & RH_B_DR) >> 8;
+			databuf.u8[10] = databuf.u8[9] = 0xff;
 		}
 
 		len = min_t(unsigned int, leni,
-			    min_t(unsigned int, data_buf [0], wLength));
+			    min_t(unsigned int, databuf.u8[0], wLength));
 		OK(len);
 	}
 
-	case RH_GET_CONFIGURATION:	*(__u8 *) data_buf = 0x01; OK(1);
+	case RH_GET_CONFIGURATION:
+		databuf.u8[0] = 0x01;
+		OK(1);
 
-	case RH_SET_CONFIGURATION:	WR_RH_STAT(0x10000); OK(0);
+	case RH_SET_CONFIGURATION:
+		WR_RH_STAT(0x10000);
+		OK(0);
 
 	default:
 		dbg("unsupported root hub command");
@@ -1458,8 +1469,8 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len,
 #endif
 
 	len = min_t(int, len, leni);
-	if (data != data_buf)
-	    memcpy(data, data_buf, len);
+	if (data != databuf.ptr)
+		memcpy(data, databuf.ptr, len);
 	dev->act_len = len;
 	dev->status = stat;
 

+ 44 - 0
drivers/usb/ulpi/Makefile

@@ -0,0 +1,44 @@
+#
+# Copyright (C) 2011 Jana Rapava <fermata7@gmail.com>
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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.
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	:= $(obj)libusb_ulpi.o
+
+COBJS-$(CONFIG_USB_ULPI)		+= ulpi.o
+COBJS-$(CONFIG_USB_ULPI_VIEWPORT)	+= ulpi-viewport.o
+
+COBJS	:= $(COBJS-y)
+SRCS	:= $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS))
+
+all:	$(LIB)
+
+$(LIB):	$(obj).depend $(OBJS)
+	$(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################

+ 118 - 0
drivers/usb/ulpi/ulpi-viewport.c

@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2011 Jana Rapava <fermata7@gmail.com>
+ * Copyright (C) 2011 CompuLab, Ltd. <www.compulab.co.il>
+ *
+ * Authors: Jana Rapava <fermata7@gmail.com>
+ *	    Igor Grinberg <grinberg@compulab.co.il>
+ *
+ * Based on:
+ * linux/drivers/usb/otg/ulpi_viewport.c
+ *
+ * Original Copyright follow:
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <usb/ulpi.h>
+
+/* ULPI viewport control bits */
+#define ULPI_SS		(1 << 27)
+#define ULPI_RWCTRL	(1 << 29)
+#define ULPI_RWRUN	(1 << 30)
+#define ULPI_WU		(1 << 31)
+
+/*
+ * Wait for the ULPI request to complete
+ *
+ * @ulpi_viewport	- the address of the viewport
+ * @mask		- expected value to wait for
+ *
+ * returns 0 on mask match, ULPI_ERROR on time out.
+ */
+static int ulpi_wait(u32 ulpi_viewport, u32 mask)
+{
+	int timeout = CONFIG_USB_ULPI_TIMEOUT;
+
+	/* Wait for the bits in mask to become zero. */
+	while (--timeout) {
+		if ((readl(ulpi_viewport) & mask) == 0)
+			return 0;
+
+		udelay(1);
+	}
+
+	return ULPI_ERROR;
+}
+
+/*
+ * Wake the ULPI PHY up for communication
+ *
+ * returns 0 on success.
+ */
+static int ulpi_wakeup(u32 ulpi_viewport)
+{
+	int err;
+
+	if (readl(ulpi_viewport) & ULPI_SS)
+		return 0; /* already awake */
+
+	writel(ULPI_WU, ulpi_viewport);
+
+	err = ulpi_wait(ulpi_viewport, ULPI_WU);
+	if (err)
+		printf("ULPI wakeup timed out\n");
+
+	return err;
+}
+
+/*
+ * Issue a ULPI read/write request
+ *
+ * @value - the ULPI request
+ */
+static int ulpi_request(u32 ulpi_viewport, u32 value)
+{
+	int err;
+
+	err = ulpi_wakeup(ulpi_viewport);
+	if (err)
+		return err;
+
+	writel(value, ulpi_viewport);
+
+	err = ulpi_wait(ulpi_viewport, ULPI_RWRUN);
+	if (err)
+		printf("ULPI request timed out\n");
+
+	return err;
+}
+
+u32 ulpi_write(u32 ulpi_viewport, u8 *reg, u32 value)
+{
+	u32 val = ULPI_RWRUN | ULPI_RWCTRL | ((u32)reg << 16) | (value & 0xff);
+
+	return ulpi_request(ulpi_viewport, val);
+}
+
+u32 ulpi_read(u32 ulpi_viewport, u8 *reg)
+{
+	u32 err;
+	u32 val = ULPI_RWRUN | ((u32)reg << 16);
+
+	err = ulpi_request(ulpi_viewport, val);
+	if (err)
+		return err;
+
+	return (readl(ulpi_viewport) >> 8) & 0xff;
+}

+ 227 - 0
drivers/usb/ulpi/ulpi.c

@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2011 Jana Rapava <fermata7@gmail.com>
+ * Copyright (C) 2011 CompuLab, Ltd. <www.compulab.co.il>
+ *
+ * Authors: Jana Rapava <fermata7@gmail.com>
+ *	    Igor Grinberg <grinberg@compulab.co.il>
+ *
+ * Based on:
+ * linux/drivers/usb/otg/ulpi.c
+ * Generic ULPI USB transceiver support
+ *
+ * Original Copyright follow:
+ * Copyright (C) 2009 Daniel Mack <daniel@caiaq.de>
+ *
+ * Based on sources from
+ *
+ *   Sascha Hauer <s.hauer@pengutronix.de>
+ *   Freescale Semiconductors
+ *
+ * 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.
+ */
+
+#include <common.h>
+#include <exports.h>
+#include <usb/ulpi.h>
+
+#define ULPI_ID_REGS_COUNT	4
+#define ULPI_TEST_VALUE		0x55	/* 0x55 == 0b01010101 */
+
+static struct ulpi_regs *ulpi = (struct ulpi_regs *)0;
+
+static int ulpi_integrity_check(u32 ulpi_viewport)
+{
+	u32 err, val, tval = ULPI_TEST_VALUE;
+	int i;
+
+	/* Use the 'special' test value to check all bits */
+	for (i = 0; i < 2; i++, tval <<= 1) {
+		err = ulpi_write(ulpi_viewport, &ulpi->scratch, tval);
+		if (err)
+			return err;
+
+		val = ulpi_read(ulpi_viewport, &ulpi->scratch);
+		if (val != tval) {
+			printf("ULPI integrity check failed\n");
+			return val;
+		}
+	}
+
+	return 0;
+}
+
+int ulpi_init(u32 ulpi_viewport)
+{
+	u32 val, id = 0;
+	u8 *reg = &ulpi->product_id_high;
+	int i;
+
+	/* Assemble ID from four ULPI ID registers (8 bits each). */
+	for (i = 0; i < ULPI_ID_REGS_COUNT; i++) {
+		val = ulpi_read(ulpi_viewport, reg - i);
+		if (val == ULPI_ERROR)
+			return val;
+
+		id = (id << 8) | val;
+	}
+
+	/* Split ID into vendor and product ID. */
+	debug("ULPI transceiver ID 0x%04x:0x%04x\n", id >> 16, id & 0xffff);
+
+	return ulpi_integrity_check(ulpi_viewport);
+}
+
+int ulpi_select_transceiver(u32 ulpi_viewport, u8 speed)
+{
+	u8 tspeed = ULPI_FC_FULL_SPEED;
+	u32 val;
+
+	switch (speed) {
+	case ULPI_FC_HIGH_SPEED:
+	case ULPI_FC_FULL_SPEED:
+	case ULPI_FC_LOW_SPEED:
+	case ULPI_FC_FS4LS:
+		tspeed = speed;
+		break;
+	default:
+		printf("ULPI: %s: wrong transceiver speed specified, "
+			"falling back to full speed\n", __func__);
+	}
+
+	val = ulpi_read(ulpi_viewport, &ulpi->function_ctrl);
+	if (val == ULPI_ERROR)
+		return val;
+
+	/* clear the previous speed setting */
+	val = (val & ~ULPI_FC_XCVRSEL_MASK) | tspeed;
+
+	return ulpi_write(ulpi_viewport, &ulpi->function_ctrl, val);
+}
+
+int ulpi_set_vbus(u32 ulpi_viewport, int on, int ext_power, int ext_ind)
+{
+	u32 flags = ULPI_OTG_DRVVBUS;
+	u8 *reg = on ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear;
+
+	if (ext_power)
+		flags |= ULPI_OTG_DRVVBUS_EXT;
+	if (ext_ind)
+		flags |= ULPI_OTG_EXTVBUSIND;
+
+	return ulpi_write(ulpi_viewport, reg, flags);
+}
+
+int ulpi_set_pd(u32 ulpi_viewport, int enable)
+{
+	u32 val = ULPI_OTG_DP_PULLDOWN | ULPI_OTG_DM_PULLDOWN;
+	u8 *reg = enable ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear;
+
+	return ulpi_write(ulpi_viewport, reg, val);
+}
+
+int ulpi_opmode_sel(u32 ulpi_viewport, u8 opmode)
+{
+	u8 topmode = ULPI_FC_OPMODE_NORMAL;
+	u32 val;
+
+	switch (opmode) {
+	case ULPI_FC_OPMODE_NORMAL:
+	case ULPI_FC_OPMODE_NONDRIVING:
+	case ULPI_FC_OPMODE_DISABLE_NRZI:
+	case ULPI_FC_OPMODE_NOSYNC_NOEOP:
+		topmode = opmode;
+		break;
+	default:
+		printf("ULPI: %s: wrong OpMode specified, "
+			"falling back to OpMode Normal\n", __func__);
+	}
+
+	val = ulpi_read(ulpi_viewport, &ulpi->function_ctrl);
+	if (val == ULPI_ERROR)
+		return val;
+
+	/* clear the previous opmode setting */
+	val = (val & ~ULPI_FC_OPMODE_MASK) | topmode;
+
+	return ulpi_write(ulpi_viewport, &ulpi->function_ctrl, val);
+}
+
+int ulpi_serial_mode_enable(u32 ulpi_viewport, u8 smode)
+{
+	switch (smode) {
+	case ULPI_IFACE_6_PIN_SERIAL_MODE:
+	case ULPI_IFACE_3_PIN_SERIAL_MODE:
+		break;
+	default:
+		printf("ULPI: %s: unrecognized Serial Mode specified\n",
+			__func__);
+		return ULPI_ERROR;
+	}
+
+	return ulpi_write(ulpi_viewport, &ulpi->iface_ctrl_set, smode);
+}
+
+int ulpi_suspend(u32 ulpi_viewport)
+{
+	u32 err;
+
+	err = ulpi_write(ulpi_viewport, &ulpi->function_ctrl_clear,
+			ULPI_FC_SUSPENDM);
+	if (err)
+		printf("ULPI: %s: failed writing the suspend bit\n", __func__);
+
+	return err;
+}
+
+/*
+ * Wait for ULPI PHY reset to complete.
+ * Actual wait for reset must be done in a view port specific way,
+ * because it involves checking the DIR line.
+ */
+static int __ulpi_reset_wait(u32 ulpi_viewport)
+{
+	u32 val;
+	int timeout = CONFIG_USB_ULPI_TIMEOUT;
+
+	/* Wait for the RESET bit to become zero */
+	while (--timeout) {
+		/*
+		 * This function is generic and suppose to work
+		 * with any viewport, so we cheat here and don't check
+		 * for the error of ulpi_read(), if there is one, then
+		 * there will be a timeout.
+		 */
+		val = ulpi_read(ulpi_viewport, &ulpi->function_ctrl);
+		if (!(val & ULPI_FC_RESET))
+			return 0;
+
+		udelay(1);
+	}
+
+	printf("ULPI: %s: reset timed out\n", __func__);
+
+	return ULPI_ERROR;
+}
+int ulpi_reset_wait(u32) __attribute__((weak, alias("__ulpi_reset_wait")));
+
+int ulpi_reset(u32 ulpi_viewport)
+{
+	u32 err;
+
+	err = ulpi_write(ulpi_viewport,
+			&ulpi->function_ctrl_set, ULPI_FC_RESET);
+	if (err) {
+		printf("ULPI: %s: failed writing reset bit\n", __func__);
+		return err;
+	}
+
+	return ulpi_reset_wait(ulpi_viewport);
+}

+ 41 - 6
include/configs/efikamx.h

@@ -44,6 +44,10 @@
 
 #define CONFIG_SYS_TEXT_BASE		0x97800000
 
+#define	CONFIG_L2_OFF
+#define	CONFIG_SYS_ICACHE_OFF
+#define	CONFIG_SYS_DCACHE_OFF
+
 /*
  * Bootloader Components Configuration
  */
@@ -53,6 +57,8 @@
 #define CONFIG_CMD_FAT
 #define CONFIG_CMD_EXT2
 #define CONFIG_CMD_IDE
+#define CONFIG_CMD_NET
+#define CONFIG_CMD_DATE
 #undef CONFIG_CMD_IMLS
 
 /*
@@ -174,18 +180,47 @@
 #define CONFIG_MXC_ATA_PIO_MODE		4
 #endif
 
+/*
+ * USB
+ */
+#define	CONFIG_CMD_USB
+#ifdef	CONFIG_CMD_USB
+#define	CONFIG_USB_EHCI			/* Enable EHCI USB support */
+#define	CONFIG_USB_EHCI_MX5
+#define	CONFIG_USB_ULPI
+#define	CONFIG_USB_ULPI_VIEWPORT
+#define	CONFIG_MXC_USB_PORT	1
+#if	(CONFIG_MXC_USB_PORT == 0)
+#define	CONFIG_MXC_USB_PORTSC	(1 << 28)
+#define	CONFIG_MXC_USB_FLAGS	MXC_EHCI_INTERNAL_PHY
+#else
+#define	CONFIG_MXC_USB_PORTSC	(2 << 30)
+#define	CONFIG_MXC_USB_FLAGS	0
+#endif
+#define	CONFIG_EHCI_IS_TDI
+#define	CONFIG_USB_STORAGE
+#define	CONFIG_USB_HOST_ETHER
+#define	CONFIG_USB_KEYBOARD
+#define	CONFIG_SYS_USB_EVENT_POLL_VIA_CONTROL_EP
+#define CONFIG_PREBOOT
+/* USB NET */
+#ifdef	CONFIG_CMD_NET
+#define	CONFIG_USB_ETHER_ASIX
+#define	CONFIG_NET_MULTI
+#define	CONFIG_CMD_PING
+#define	CONFIG_CMD_DHCP
+#endif
+#endif /* CONFIG_CMD_USB */
+
 /*
  * Filesystems
  */
 #ifdef CONFIG_CMD_FAT
 #define CONFIG_DOS_PARTITION
+#ifdef	CONFIG_CMD_NET
+#define	CONFIG_CMD_NFS
+#endif
 #endif
-
-#undef CONFIG_CMD_PING
-#undef CONFIG_CMD_DHCP
-#undef CONFIG_CMD_NET
-#undef CONFIG_CMD_NFS
-#define CONFIG_CMD_DATE
 
 /*
  * Miscellaneous configurable options

+ 13 - 0
include/configs/mx51evk.h

@@ -110,6 +110,19 @@
 #define CONFIG_CMD_MII
 #define CONFIG_CMD_NET
 
+/* USB Configs */
+#define CONFIG_CMD_USB
+#define CONFIG_CMD_FAT
+#define CONFIG_USB_EHCI
+#define CONFIG_USB_EHCI_MX5
+#define CONFIG_USB_STORAGE
+#define CONFIG_USB_HOST_ETHER
+#define CONFIG_USB_ETHER_ASIX
+#define CONFIG_USB_ETHER_SMSC95XX
+#define CONFIG_MXC_USB_PORT	1
+#define CONFIG_MXC_USB_PORTSC	PORT_PTS_ULPI
+#define CONFIG_MXC_USB_FLAGS	MXC_EHCI_POWER_PINS_ENABLED
+
 /* allow to overwrite serial and ethaddr */
 #define CONFIG_ENV_OVERWRITE
 #define CONFIG_CONS_INDEX		1

+ 13 - 0
include/configs/mx53loco.h

@@ -72,6 +72,19 @@
 #define CONFIG_CMD_MII
 #define CONFIG_CMD_NET
 
+/* USB Configs */
+#define CONFIG_CMD_USB
+#define CONFIG_CMD_FAT
+#define CONFIG_USB_EHCI
+#define CONFIG_USB_EHCI_MX5
+#define CONFIG_USB_STORAGE
+#define CONFIG_USB_HOST_ETHER
+#define CONFIG_USB_ETHER_ASIX
+#define CONFIG_USB_ETHER_SMSC95XX
+#define CONFIG_MXC_USB_PORT	1
+#define CONFIG_MXC_USB_PORTSC	(PORT_PTS_UTMI | PORT_PTS_PTW)
+#define CONFIG_MXC_USB_FLAGS	0
+
 /* allow to overwrite serial and ethaddr */
 #define CONFIG_ENV_OVERWRITE
 #define CONFIG_CONS_INDEX		1

+ 3 - 0
include/configs/s5p_goni.h

@@ -237,5 +237,8 @@
 #define CONFIG_SYS_I2C_SPEED	50000
 #define CONFIG_I2C_MULTI_BUS
 #define CONFIG_SYS_MAX_I2C_BUS	7
+#define CONFIG_USB_GADGET
+#define CONFIG_USB_GADGET_S3C_UDC_OTG
+#define CONFIG_USB_GADGET_DUALSPEED
 
 #endif	/* __CONFIG_H */

+ 29 - 12
include/usb/ehci-fsl.h

@@ -186,35 +186,36 @@ struct usb_ehci {
 	u32     gptimer1_ctrl;	/* 0x08C - General Purpose Timer 1 control */
 	u32	sbuscfg;	/* 0x090 - System Bus Interface Control */
 	u8	res2[0x6C];
-	u16	caplength;	/* 0x100 - Capability Register Length */
+	u8	caplength;	/* 0x100 - Capability Register Length */
+	u8	res3[0x1];
 	u16	hciversion;	/* 0x102 - Host Interface Version */
 	u32	hcsparams;	/* 0x104 - Host Structural Parameters */
 	u32	hccparams;	/* 0x108 - Host Capability Parameters */
-	u8	res3[0x14];
+	u8	res4[0x14];
 	u32	dciversion;	/* 0x120 - Device Interface Version */
 	u32	dciparams;	/* 0x124 - Device Controller Params */
-	u8	res4[0x18];
+	u8	res5[0x18];
 	u32	usbcmd;		/* 0x140 - USB Command */
 	u32	usbsts;		/* 0x144 - USB Status */
 	u32	usbintr;	/* 0x148 - USB Interrupt Enable */
 	u32	frindex;	/* 0x14C - USB Frame Index */
-	u8	res5[0x4];
+	u8	res6[0x4];
 	u32	perlistbase;	/* 0x154 - Periodic List Base
 					 - USB Device Address */
 	u32	ep_list_addr;	/* 0x158 - Next Asynchronous List
 					 - End Point Address */
-	u8	res6[0x4];
+	u8	res7[0x4];
 	u32	burstsize;	/* 0x160 - Programmable Burst Size */
 #define FSL_EHCI_TXPBURST(X)	((X) << 8)
 #define FSL_EHCI_RXPBURST(X)	(X)
 	u32	txfilltuning;	/* 0x164 - Host TT Transmit
 					   pre-buffer packet tuning */
-	u8	res7[0x8];
+	u8	res8[0x8];
 	u32	ulpi_viewpoint;	/* 0x170 - ULPI Reister Access */
-	u8	res8[0xc];
+	u8	res9[0xc];
 	u32	config_flag;	/* 0x180 - Configured Flag Register */
 	u32	portsc;		/* 0x184 - Port status/control */
-	u8	res9[0x1C];
+	u8	res10[0x1C];
 	u32	otgsc;		/* 0x1a4 - Oo-The-Go status and control */
 	u32	usbmode;	/* 0x1a8 - USB Device Mode */
 	u32	epsetupstat;	/* 0x1ac - End Point Setup Status */
@@ -228,18 +229,34 @@ struct usb_ehci {
 	u32	epctrl3;	/* 0x1cc - End Point Control 3 */
 	u32	epctrl4;	/* 0x1d0 - End Point Control 4 */
 	u32	epctrl5;	/* 0x1d4 - End Point Control 5 */
-	u8	res10[0x28];
+	u8	res11[0x28];
 	u32	usbgenctrl;	/* 0x200 - USB General Control */
 	u32	isiphyctrl;	/* 0x204 - On-Chip PHY Control */
-	u8	res11[0x1F8];
+	u8	res12[0x1F8];
 	u32	snoop1;		/* 0x400 - Snoop 1 */
 	u32	snoop2;		/* 0x404 - Snoop 2 */
 	u32	age_cnt_limit;	/* 0x408 - Age Count Threshold */
 	u32	prictrl;	/* 0x40c - Priority Control */
 	u32	sictrl;		/* 0x410 - System Interface Control */
-	u8	res12[0xEC];
+	u8	res13[0xEC];
 	u32	control;	/* 0x500 - Control */
-	u8	res13[0xafc];
+	u8	res14[0xafc];
 };
 
+/*
+ * For MXC SOCs
+ */
+#define MXC_EHCI_POWER_PINS_ENABLED	(1 << 5)
+#define MXC_EHCI_TTL_ENABLED		(1 << 6)
+#define MXC_EHCI_INTERNAL_PHY		(1 << 7)
+
+/* Board-specific initialization */
+int board_ehci_hcd_init(int port);
+
+/* CPU-specific abstracted-out IOMUX init */
+#ifdef CONFIG_MX51
+void setup_iomux_usb_h1(void);
+void setup_iomux_usb_h2(void);
+#endif
+
 #endif /* _EHCI_FSL_H */

+ 62 - 0
include/usb/lin_gadget_compat.h

@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2011 Samsung Electronics
+ * Lukasz Majewski <l.majewski@samsung.com>
+ *
+ * This is a Linux kernel compatibility layer for USB Gadget
+ *
+ * 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
+ */
+
+#ifndef __LIN_COMPAT_H__
+#define __LIN_COMPAT_H__
+
+/* common */
+#define spin_lock_init(...)
+#define spin_lock(...)
+#define spin_lock_irqsave(lock, flags) do {flags = 1; } while (0)
+#define spin_unlock(...)
+#define spin_unlock_irqrestore(lock, flags) do {flags = 0; } while (0)
+#define disable_irq(...)
+#define enable_irq(...)
+
+#define mutex_init(...)
+#define mutex_lock(...)
+#define mutex_unlock(...)
+
+#define WARN_ON(x) if (x) {printf("WARNING in %s line %d\n" \
+				  , __FILE__, __LINE__); }
+
+#define KERN_WARNING
+#define KERN_ERR
+#define KERN_NOTICE
+#define KERN_DEBUG
+
+#define GFP_KERNEL	0
+
+#define IRQ_HANDLED	1
+
+#define ENOTSUPP	524	/* Operation is not supported */
+
+#define kmalloc(size, type) memalign(CONFIG_SYS_CACHELINE_SIZE, size)
+#define kfree(addr) free(addr)
+#define mdelay(n) ({unsigned long msec = (n); while (msec--) udelay(1000); })
+
+#define __iomem
+#define min_t min
+#define dma_cache_maint(addr, size, mode) cache_flush()
+void cache_flush(void);
+
+#endif /* __LIN_COMPAT_H__ */

+ 151 - 0
include/usb/mv_udc.h

@@ -0,0 +1,151 @@
+/*
+ * Copyright 2011, Marvell Semiconductor Inc.
+ * Lei Wen <leiwen@marvell.com>
+ *
+ * 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
+ */
+
+
+#ifndef __MV_UDC_H__
+#define __MV_UDC_H__
+
+#include <asm/byteorder.h>
+#include <asm/errno.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+/* Endpoint 0 states */
+#define EP0_IDLE		0
+#define EP0_IN_DATA		1
+#define EP0_OUT_DATA		2
+#define EP0_XFER_COMPLETE	3
+
+
+/* Endpoint parameters */
+#define MAX_ENDPOINTS		4
+#define EP_MAX_PACKET_SIZE	0x200
+
+#define EP0_MAX_PACKET_SIZE	64
+#define UDC_OUT_ENDPOINT        0x02
+#define UDC_OUT_PACKET_SIZE	EP_MAX_PACKET_SIZE
+#define UDC_IN_ENDPOINT         0x01
+#define UDC_IN_PACKET_SIZE      EP_MAX_PACKET_SIZE
+#define UDC_INT_ENDPOINT        0x05
+#define UDC_INT_PACKET_SIZE     EP_MAX_PACKET_SIZE
+#define UDC_BULK_PACKET_SIZE    EP_MAX_PACKET_SIZE
+
+#define        NUM_ENDPOINTS   6
+#define		REQ_COUNT	12
+struct mv_ep {
+	struct usb_ep ep;
+	struct usb_request req;
+	struct list_head queue;
+	const struct usb_endpoint_descriptor *desc;
+};
+
+struct mv_udc {
+	u32 pad0[80];
+#define MICRO_8FRAME	0x8
+#define USBCMD_ITC(x)	(((x > 0xff) ? 0xff : x) << 16)
+#define USBCMD_FS2	(1 << 15)
+#define USBCMD_RST	(1 << 1)
+#define USBCMD_RUN	(1)
+	u32 usbcmd;		/* 0x140 */
+#define STS_SLI		(1 << 8)
+#define STS_URI		(1 << 6)
+#define STS_PCI		(1 << 2)
+#define STS_UEI		(1 << 1)
+#define STS_UI		(1 << 0)
+	u32 usbsts;		/* 0x144 */
+	u32 pad1[3];
+	u32 devaddr;		/* 0x154 */
+	u32 epinitaddr;		/* 0x158 */
+	u32 pad2[10];
+#define PTS_ENABLE	2
+#define PTS(x)		((x & 0x3) << 30)
+#define PFSC		(1 << 24)
+	u32 portsc;		/* 0x184 */
+	u32 pad3[8];
+#define USBMODE_DEVICE	2
+	u32 usbmode;		/* 0x1a8 */
+	u32 epstat;		/* 0x1ac */
+#define EPT_TX(x)	(1 << ((x & 0xffff) + 16))
+#define EPT_RX(x)	(1 << (x & 0xffff))
+	u32 epprime;		/* 0x1b0 */
+	u32 epflush;		/* 0x1b4 */
+	u32 pad4;
+	u32 epcomp;		/* 0x1bc */
+#define CTRL_TXE              (1 << 23)
+#define CTRL_TXR              (1 << 22)
+#define CTRL_RXE              (1 << 7)
+#define CTRL_RXR              (1 << 6)
+#define CTRL_TXT_BULK         (2 << 18)
+#define CTRL_RXT_BULK         (2 << 2)
+	u32 epctrl[16];		/* 0x1c0 */
+};
+
+struct mv_drv {
+	struct usb_gadget		gadget;
+	struct usb_gadget_driver		*driver;
+	struct mv_udc			*udc;
+};
+
+struct ept_queue_head {
+	unsigned config;
+	unsigned current; /* read-only */
+
+	unsigned next;
+	unsigned info;
+	unsigned page0;
+	unsigned page1;
+	unsigned page2;
+	unsigned page3;
+	unsigned page4;
+	unsigned reserved_0;
+
+	unsigned char setup_data[8];
+
+	unsigned reserved_1;
+	unsigned reserved_2;
+	unsigned reserved_3;
+	unsigned reserved_4;
+};
+
+#define CONFIG_MAX_PKT(n)     ((n) << 16)
+#define CONFIG_ZLT            (1 << 29)    /* stop on zero-len xfer */
+#define CONFIG_IOS            (1 << 15)    /* IRQ on setup */
+
+struct ept_queue_item {
+	unsigned next;
+	unsigned info;
+	unsigned page0;
+	unsigned page1;
+	unsigned page2;
+	unsigned page3;
+	unsigned page4;
+	unsigned reserved;
+};
+
+#define TERMINATE 1
+#define INFO_BYTES(n)         ((n) << 16)
+#define INFO_IOC              (1 << 15)
+#define INFO_ACTIVE           (1 << 7)
+#define INFO_HALTED           (1 << 6)
+#define INFO_BUFFER_ERROR     (1 << 5)
+#define INFO_TX_ERROR         (1 << 3)
+
+extern int usb_lowlevel_init(void);
+#endif /* __MV_UDC_H__ */

+ 175 - 0
include/usb/s3c_udc.h

@@ -0,0 +1,175 @@
+/*
+ * drivers/usb/gadget/s3c_udc.h
+ * Samsung S3C on-chip full/high speed USB device controllers
+ * Copyright (C) 2005 for Samsung Electronics
+ *
+ * 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
+ *
+ */
+
+#ifndef __S3C_USB_GADGET
+#define __S3C_USB_GADGET
+
+#include <asm/errno.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/list.h>
+#include <usb/lin_gadget_compat.h>
+
+#define PHY0_SLEEP              (1 << 5)
+
+/*-------------------------------------------------------------------------*/
+/* DMA bounce buffer size, 16K is enough even for mass storage */
+#define DMA_BUFFER_SIZE	(4096*4)
+
+#define EP0_FIFO_SIZE		64
+#define EP_FIFO_SIZE		512
+#define EP_FIFO_SIZE2		1024
+/* ep0-control, ep1in-bulk, ep2out-bulk, ep3in-int */
+#define S3C_MAX_ENDPOINTS	4
+#define S3C_MAX_HW_ENDPOINTS	16
+
+#define WAIT_FOR_SETUP          0
+#define DATA_STATE_XMIT         1
+#define DATA_STATE_NEED_ZLP     2
+#define WAIT_FOR_OUT_STATUS     3
+#define DATA_STATE_RECV         4
+#define WAIT_FOR_COMPLETE	5
+#define WAIT_FOR_OUT_COMPLETE	6
+#define WAIT_FOR_IN_COMPLETE	7
+#define WAIT_FOR_NULL_COMPLETE	8
+
+#define TEST_J_SEL		0x1
+#define TEST_K_SEL		0x2
+#define TEST_SE0_NAK_SEL	0x3
+#define TEST_PACKET_SEL		0x4
+#define TEST_FORCE_ENABLE_SEL	0x5
+
+/* ************************************************************************* */
+/* IO
+ */
+
+enum ep_type {
+	ep_control, ep_bulk_in, ep_bulk_out, ep_interrupt
+};
+
+struct s3c_ep {
+	struct usb_ep ep;
+	struct s3c_udc *dev;
+
+	const struct usb_endpoint_descriptor *desc;
+	struct list_head queue;
+	unsigned long pio_irqs;
+	int len;
+	void *dma_buf;
+
+	u8 stopped;
+	u8 bEndpointAddress;
+	u8 bmAttributes;
+
+	enum ep_type ep_type;
+	int fifo_num;
+};
+
+struct s3c_request {
+	struct usb_request req;
+	struct list_head queue;
+};
+
+struct s3c_udc {
+	struct usb_gadget gadget;
+	struct usb_gadget_driver *driver;
+
+	struct s3c_plat_otg_data *pdata;
+
+	void *dma_buf[S3C_MAX_ENDPOINTS+1];
+	dma_addr_t dma_addr[S3C_MAX_ENDPOINTS+1];
+
+	int ep0state;
+	struct s3c_ep ep[S3C_MAX_ENDPOINTS];
+
+	unsigned char usb_address;
+
+	unsigned req_pending:1, req_std:1, req_config:1;
+};
+
+extern struct s3c_udc *the_controller;
+
+#define ep_is_in(EP) (((EP)->bEndpointAddress&USB_DIR_IN) == USB_DIR_IN)
+#define ep_index(EP) ((EP)->bEndpointAddress&0xF)
+#define ep_maxpacket(EP) ((EP)->ep.maxpacket)
+
+/*-------------------------------------------------------------------------*/
+/* #define DEBUG_UDC */
+#ifdef DEBUG_UDC
+#define DBG(stuff...)		printf("udc: " stuff)
+#else
+#define DBG(stuff...)		do {} while (0)
+#endif
+
+#ifdef DEBUG_S3C_UDC_SETUP
+#define DEBUG_SETUP(fmt, args...) printk(fmt, ##args)
+#else
+#define DEBUG_SETUP(fmt, args...) do {} while (0)
+#endif
+
+#ifdef DEBUG_S3C_UDC_EP0
+#define DEBUG_EP0(fmt, args...) printk(fmt, ##args)
+#else
+#define DEBUG_EP0(fmt, args...) do {} while (0)
+#endif
+
+#ifdef DEBUG_S3C_UDC
+#define DEBUG(fmt, args...) printk(fmt, ##args)
+#else
+#define DEBUG(fmt, args...) do {} while (0)
+#endif
+
+#ifdef DEBUG_S3C_UDC_ISR
+#define DEBUG_ISR(fmt, args...) printk(fmt, ##args)
+#else
+#define DEBUG_ISR(fmt, args...) do {} while (0)
+#endif
+
+#ifdef DEBUG_S3C_UDC_OUT_EP
+#define DEBUG_OUT_EP(fmt, args...) printk(fmt, ##args)
+#else
+#define DEBUG_OUT_EP(fmt, args...) do {} while (0)
+#endif
+
+#ifdef DEBUG_S3C_UDC_IN_EP
+#define DEBUG_IN_EP(fmt, args...) printk(fmt, ##args)
+#else
+#define DEBUG_IN_EP(fmt, args...) do {} while (0)
+#endif
+
+#define ERR(stuff...)		printf("ERR udc: " stuff)
+#define WARN(stuff...)		printf("WARNING udc: " stuff)
+#define INFO(stuff...)		printf("INFO udc: " stuff)
+
+extern void otg_phy_init(struct s3c_udc *dev);
+extern void otg_phy_off(struct s3c_udc *dev);
+
+extern void s3c_udc_ep_set_stall(struct s3c_ep *ep);
+extern int s3c_udc_probe(struct s3c_plat_otg_data *pdata);
+
+struct s3c_plat_otg_data {
+	int		(*phy_control)(int on);
+	unsigned int	regs_phy;
+	unsigned int	regs_otg;
+	unsigned int    usb_phy_ctrl;
+	unsigned int    usb_flags;
+};
+#endif

+ 298 - 0
include/usb/ulpi.h

@@ -0,0 +1,298 @@
+/*
+ * Generic ULPI interface.
+ *
+ * Copyright (C) 2011 Jana Rapava <fermata7@gmail.com>
+ * Copyright (C) 2011 CompuLab, Ltd. <www.compulab.co.il>
+ *
+ * Authors: Jana Rapava <fermata7@gmail.com>
+ *	    Igor Grinberg <grinberg@compulab.co.il>
+ *
+ * Register offsets taken from:
+ * linux/include/linux/usb/ulpi.h
+ *
+ * Original Copyrights follow:
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * This software is distributed under the terms of the GNU General
+ * Public License ("GPL") as published by the Free Software Foundation,
+ * version 2 of that License.
+ */
+
+#ifndef __USB_ULPI_H__
+#define __USB_ULPI_H__
+
+#define ULPI_ERROR	(1 << 8) /* overflow from any register value */
+
+#ifndef CONFIG_USB_ULPI_TIMEOUT
+#define CONFIG_USB_ULPI_TIMEOUT 1000	/* timeout in us */
+#endif
+
+/*
+ * Initialize the ULPI transciever and check the interface integrity.
+ * @ulpi_viewport -  the address of the ULPI viewport register.
+ *
+ * returns 0 on success, ULPI_ERROR on failure.
+ */
+int ulpi_init(u32 ulpi_viewport);
+
+/*
+ * Select transceiver speed.
+ * @speed	- ULPI_FC_HIGH_SPEED, ULPI_FC_FULL_SPEED (default),
+ *                ULPI_FC_LOW_SPEED,  ULPI_FC_FS4LS
+ * returns 0 on success, ULPI_ERROR on failure.
+ */
+int ulpi_select_transceiver(u32 ulpi_viewport, u8 speed);
+
+/*
+ * Enable/disable VBUS.
+ * @ext_power		- external VBUS supply is used (default is false)
+ * @ext_indicator	- external VBUS over-current indicator is used
+ *
+ * returns 0 on success, ULPI_ERROR on failure.
+ */
+int ulpi_enable_vbus(u32 ulpi_viewport, int on, int ext_power, int ext_ind);
+
+/*
+ * Enable/disable pull-down resistors on D+ and D- USB lines.
+ *
+ * returns 0 on success, ULPI_ERROR on failure.
+ */
+int ulpi_set_pd(u32 ulpi_viewport, int enable);
+
+/*
+ * Select OpMode.
+ * @opmode	- ULPI_FC_OPMODE_NORMAL (default), ULPI_FC_OPMODE_NONDRIVING,
+ *		  ULPI_FC_OPMODE_DISABLE_NRZI,	   ULPI_FC_OPMODE_NOSYNC_NOEOP
+ *
+ * returns 0 on success, ULPI_ERROR on failure.
+ */
+int ulpi_opmode_sel(u32 ulpi_viewport, u8 opmode);
+
+/*
+ * Switch to Serial Mode.
+ * @smode	- ULPI_IFACE_6_PIN_SERIAL_MODE or ULPI_IFACE_3_PIN_SERIAL_MODE
+ *
+ * returns 0 on success, ULPI_ERROR on failure.
+ *
+ * Notes:
+ * Switches immediately to Serial Mode.
+ * To return from Serial Mode, STP line needs to be asserted.
+ */
+int ulpi_serial_mode_enable(u32 ulpi_viewport, u8 smode);
+
+/*
+ * Put PHY into low power mode.
+ *
+ * returns 0 on success, ULPI_ERROR on failure.
+ *
+ * Notes:
+ * STP line must be driven low to keep the PHY in suspend.
+ * To resume the PHY, STP line needs to be asserted.
+ */
+int ulpi_suspend(u32 ulpi_viewport);
+
+/*
+ * Reset the transceiver. ULPI interface and registers are not affected.
+ *
+ * returns 0 on success, ULPI_ERROR on failure.
+ */
+int ulpi_reset(u32 ulpi_viewport);
+
+
+/* ULPI access methods below must be implemented for each ULPI viewport. */
+
+/*
+ * Write to the ULPI PHY register via the viewport.
+ * @reg		- the ULPI register (one of the fields in struct ulpi_regs).
+ * @value	- the value - only 8 lower bits are used, others ignored.
+ *
+ * returns 0 on success, ULPI_ERROR on failure.
+ */
+u32 ulpi_write(u32 ulpi_viewport, u8 *reg, u32 value);
+
+/*
+ * Read the ULPI PHY register content via the viewport.
+ * @reg		- the ULPI register (one of the fields in struct ulpi_regs).
+ *
+ * returns register content on success, ULPI_ERROR on failure.
+ */
+u32 ulpi_read(u32 ulpi_viewport, u8 *reg);
+
+/*
+ * Wait for the reset to complete.
+ * The Link must not attempt to access the PHY until the reset has
+ * completed and DIR line is de-asserted.
+ */
+int ulpi_reset_wait(u32 ulpi_viewport);
+
+/* Access Extended Register Set (indicator) */
+#define ACCESS_EXT_REGS_OFFSET	0x2f	/* read-write */
+/* Vendor-specific */
+#define VENDOR_SPEC_OFFSET	0x30
+
+/*
+ * Extended Register Set
+ *
+ * Addresses 0x00-0x3F map directly to Immediate Register Set.
+ * Addresses 0x40-0x7F are reserved.
+ * Addresses 0x80-0xff are vendor-specific.
+ */
+#define EXT_VENDOR_SPEC_OFFSET	0x80
+
+/* ULPI registers, bits and offsets definitions */
+struct ulpi_regs {
+	/* Vendor ID and Product ID: 0x00 - 0x03 Read-only */
+	u8	vendor_id_low;
+	u8	vendor_id_high;
+	u8	product_id_low;
+	u8	product_id_high;
+	/* Function Control: 0x04 - 0x06 Read */
+	u8	function_ctrl;		/* 0x04 Write */
+	u8	function_ctrl_set;	/* 0x05 Set */
+	u8	function_ctrl_clear;	/* 0x06 Clear */
+	/* Interface Control: 0x07 - 0x09 Read */
+	u8	iface_ctrl;		/* 0x07 Write */
+	u8	iface_ctrl_set;		/* 0x08 Set */
+	u8	iface_ctrl_clear;	/* 0x09 Clear */
+	/* OTG Control: 0x0A - 0x0C Read */
+	u8	otg_ctrl;		/* 0x0A Write */
+	u8	otg_ctrl_set;		/* 0x0B Set */
+	u8	otg_ctrl_clear;		/* 0x0C Clear */
+	/* USB Interrupt Enable Rising: 0x0D - 0x0F Read */
+	u8	usb_ie_rising;		/* 0x0D Write */
+	u8	usb_ie_rising_set;	/* 0x0E Set */
+	u8	usb_ie_rising_clear;	/* 0x0F Clear */
+	/* USB Interrupt Enable Falling: 0x10 - 0x12 Read */
+	u8	usb_ie_falling;		/* 0x10 Write */
+	u8	usb_ie_falling_set;	/* 0x11 Set */
+	u8	usb_ie_falling_clear;	/* 0x12 Clear */
+	/* USB Interrupt Status: 0x13 Read-only */
+	u8	usb_int_status;
+	/* USB Interrupt Latch: 0x14 Read-only with auto-clear */
+	u8	usb_int_latch;
+	/* Debug: 0x15 Read-only */
+	u8	debug;
+	/* Scratch Register: 0x16 - 0x18 Read */
+	u8	scratch;		/* 0x16 Write */
+	u8	scratch_set;		/* 0x17 Set */
+	u8	scratch_clear;		/* 0x18 Clear */
+	/*
+	 * Optional Carkit registers:
+	 * Carkit Control: 0x19 - 0x1B Read
+	 */
+	u8	carkit_ctrl;		/* 0x19 Write */
+	u8	carkit_ctrl_set;	/* 0x1A Set */
+	u8	carkit_ctrl_clear;	/* 0x1B Clear */
+	/* Carkit Interrupt Delay: 0x1C Read, Write */
+	u8	carkit_int_delay;
+	/* Carkit Interrupt Enable: 0x1D - 0x1F Read */
+	u8	carkit_ie;		/* 0x1D Write */
+	u8	carkit_ie_set;		/* 0x1E Set */
+	u8	carkit_ie_clear;	/* 0x1F Clear */
+	/* Carkit Interrupt Status: 0x20 Read-only */
+	u8	carkit_int_status;
+	/* Carkit Interrupt Latch: 0x21 Read-only with auto-clear */
+	u8	carkit_int_latch;
+	/* Carkit Pulse Control: 0x22 - 0x24 Read */
+	u8	carkit_pulse_ctrl;		/* 0x22 Write */
+	u8	carkit_pulse_ctrl_set;		/* 0x23 Set */
+	u8	carkit_pulse_ctrl_clear;	/* 0x24 Clear */
+	/*
+	 * Other optional registers:
+	 * Transmit Positive Width: 0x25 Read, Write
+	 */
+	u8	transmit_pos_width;
+	/* Transmit Negative Width: 0x26 Read, Write */
+	u8	transmit_neg_width;
+	/* Receive Polarity Recovery: 0x27 Read, Write */
+	u8	recv_pol_recovery;
+	/*
+	 * Addresses 0x28 - 0x2E are reserved, so we use offsets
+	 * for immediate registers with higher addresses
+	 */
+};
+
+/*
+ * Register Bits
+ */
+
+/* Function Control */
+#define ULPI_FC_XCVRSEL_MASK		(3 << 0)
+#define ULPI_FC_HIGH_SPEED		(0 << 0)
+#define ULPI_FC_FULL_SPEED		(1 << 0)
+#define ULPI_FC_LOW_SPEED		(2 << 0)
+#define ULPI_FC_FS4LS			(3 << 0)
+#define ULPI_FC_TERMSELECT		(1 << 2)
+#define ULPI_FC_OPMODE_MASK		(3 << 3)
+#define ULPI_FC_OPMODE_NORMAL		(0 << 3)
+#define ULPI_FC_OPMODE_NONDRIVING	(1 << 3)
+#define ULPI_FC_OPMODE_DISABLE_NRZI	(2 << 3)
+#define ULPI_FC_OPMODE_NOSYNC_NOEOP	(3 << 3)
+#define ULPI_FC_RESET			(1 << 5)
+#define ULPI_FC_SUSPENDM		(1 << 6)
+
+/* Interface Control */
+#define ULPI_IFACE_6_PIN_SERIAL_MODE	(1 << 0)
+#define ULPI_IFACE_3_PIN_SERIAL_MODE	(1 << 1)
+#define ULPI_IFACE_CARKITMODE		(1 << 2)
+#define ULPI_IFACE_CLOCKSUSPENDM	(1 << 3)
+#define ULPI_IFACE_AUTORESUME		(1 << 4)
+#define ULPI_IFACE_EXTVBUS_COMPLEMENT	(1 << 5)
+#define ULPI_IFACE_PASSTHRU		(1 << 6)
+#define ULPI_IFACE_PROTECT_IFC_DISABLE	(1 << 7)
+
+/* OTG Control */
+#define ULPI_OTG_ID_PULLUP		(1 << 0)
+#define ULPI_OTG_DP_PULLDOWN		(1 << 1)
+#define ULPI_OTG_DM_PULLDOWN		(1 << 2)
+#define ULPI_OTG_DISCHRGVBUS		(1 << 3)
+#define ULPI_OTG_CHRGVBUS		(1 << 4)
+#define ULPI_OTG_DRVVBUS		(1 << 5)
+#define ULPI_OTG_DRVVBUS_EXT		(1 << 6)
+#define ULPI_OTG_EXTVBUSIND		(1 << 7)
+
+/*
+ * USB Interrupt Enable Rising,
+ * USB Interrupt Enable Falling,
+ * USB Interrupt Status and
+ * USB Interrupt Latch
+ */
+#define ULPI_INT_HOST_DISCONNECT	(1 << 0)
+#define ULPI_INT_VBUS_VALID		(1 << 1)
+#define ULPI_INT_SESS_VALID		(1 << 2)
+#define ULPI_INT_SESS_END		(1 << 3)
+#define ULPI_INT_IDGRD			(1 << 4)
+
+/* Debug */
+#define ULPI_DEBUG_LINESTATE0		(1 << 0)
+#define ULPI_DEBUG_LINESTATE1		(1 << 1)
+
+/* Carkit Control */
+#define ULPI_CARKIT_CTRL_CARKITPWR		(1 << 0)
+#define ULPI_CARKIT_CTRL_IDGNDDRV		(1 << 1)
+#define ULPI_CARKIT_CTRL_TXDEN			(1 << 2)
+#define ULPI_CARKIT_CTRL_RXDEN			(1 << 3)
+#define ULPI_CARKIT_CTRL_SPKLEFTEN		(1 << 4)
+#define ULPI_CARKIT_CTRL_SPKRIGHTEN		(1 << 5)
+#define ULPI_CARKIT_CTRL_MICEN			(1 << 6)
+
+/* Carkit Interrupt Enable */
+#define ULPI_CARKIT_INT_EN_IDFLOAT_RISE		(1 << 0)
+#define ULPI_CARKIT_INT_EN_IDFLOAT_FALL		(1 << 1)
+#define ULPI_CARKIT_INT_EN_CARINTDET		(1 << 2)
+#define ULPI_CARKIT_INT_EN_DP_RISE		(1 << 3)
+#define ULPI_CARKIT_INT_EN_DP_FALL		(1 << 4)
+
+/* Carkit Interrupt Status and Latch */
+#define ULPI_CARKIT_INT_IDFLOAT			(1 << 0)
+#define ULPI_CARKIT_INT_CARINTDET		(1 << 1)
+#define ULPI_CARKIT_INT_DP			(1 << 2)
+
+/* Carkit Pulse Control*/
+#define ULPI_CARKIT_PLS_CTRL_TXPLSEN		(1 << 0)
+#define ULPI_CARKIT_PLS_CTRL_RXPLSEN		(1 << 1)
+#define ULPI_CARKIT_PLS_CTRL_SPKRLEFT_BIASEN	(1 << 2)
+#define ULPI_CARKIT_PLS_CTRL_SPKRRIGHT_BIASEN	(1 << 3)
+
+
+#endif /* __USB_ULPI_H__ */

+ 1 - 1
include/usbdescriptors.h

@@ -199,7 +199,7 @@ struct usb_endpoint_descriptor {
 	u8 bmAttributes;
 	u16 wMaxPacketSize;
 	u8 bInterval;
-} __attribute__ ((packed));
+} __attribute__ ((packed)) __attribute__ ((aligned(2)));
 
 struct usb_interface_descriptor {
 	u8 bLength;