diff mbox

[U-Boot,v5,4/4] Add USB support for Efika

Message ID 1317121296-17328-3-git-send-email-fermata7@gmail.com
State Changes Requested
Headers show

Commit Message

Jana Rapava Sept. 27, 2011, 11:01 a.m. UTC
This commit adds USB support for EfikaMX and EfikaSB.

Signed-off-by: Jana Rapava <fermata7@gmail.com>
Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
Cc: Remy Bohmer <linux@bohmer.net>
Cc: Stefano Babic <sbabic@denx.de>
---
Changes for v2:
     - changed to proper patch
Changes for v3:
     - merged other USB patches from u-boot-pxa/efikasb
     - offset-based access changed to struct-based access
     - use {clrset,clr,set}bits_le32() calls
     - CodingStyle and naming cleanup
Changes for v4:
      - split into patchset
      - CodingStyle and naming cleanup
      - remove endless loops
      - silence compiler warnings
Changes for v5:
	- change order of arguments in ulpi* functions
	- change type of reg argument
	- rename offset macro

 board/efikamx/Makefile      |    3 +
 board/efikamx/efikamx-usb.c |  391 +++++++++++++++++++++++++++++++++++++++++++
 board/efikamx/efikamx.c     |   10 +
 include/configs/efikamx.h   |   16 ++
 4 files changed, 420 insertions(+), 0 deletions(-)
 create mode 100644 board/efikamx/efikamx-usb.c

Comments

Marek Vasut Sept. 27, 2011, 11:50 a.m. UTC | #1
On Tuesday, September 27, 2011 01:01:36 PM Jana Rapava wrote:
> This commit adds USB support for EfikaMX and EfikaSB.
> 
> Signed-off-by: Jana Rapava <fermata7@gmail.com>
> Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
> Cc: Remy Bohmer <linux@bohmer.net>
> Cc: Stefano Babic <sbabic@denx.de>
> ---

[...]

> +
> +#ifdef	CONFIG_MACH_EFIKASB

Please update to mainline, use if (machine_is_efikasb()) { ... } .

> +	/*
> +	 * Configure USBH2 pads (used on EfikaSB)
> +	 */

[...]

> +/*
> + * solve the VBUS reset problem on Efika
> + * by setting the CHRG_VBUS bit in the reset
> + */
> +void ehci_fixup(uint32_t *status_reg, uint32_t *reg_ref)
> +{
> +	struct usb_ehci *ehci = (struct usb_ehci *)(OTG_BASE_ADDR +
> +		(MX51_REGISTER_LAYOUT_LENGTH));

Too many parenthesis.

> +	struct mxc_ulpi_regs *ulpi = (struct mxc_ulpi_regs *)0;
> +
> +	u32 tmp = ulpi_read(ehci, (u32)&ulpi->otg_ctrl_write);
> +	tmp |= ULPI_OTG_CHRG_VBUS;
> +	ulpi_write(ehci, (u32)&ulpi->otg_ctrl_write, tmp);
> +
> +	/* usb 2.0 specification say 50 ms resets on root */
> +	wait_ms(50);
> +
> +	/* terminate the reset */

Write a whole sentence, which begins with a capital letter and ends with dot ... 
fix globally.


> +	*reg_ref = ehci_readl(status_reg);
> +	*reg_ref |= EHCI_PS_PE;
> +}
> +
> +void ehci0_init(struct usb_ehci *ehci)
> +{
> +	writel(MX51_16BIT_UTMI, &ehci->portsc);
> +}
> +
> +void ehci1_init(struct usb_ehci *ehci, struct mxc_ulpi_regs *ulpi)
> +{
> +	mxc_request_iomux(MX51_PIN_USBH1_STP, IOMUX_CONFIG_ALT2);
> +	mxc_iomux_set_pad(MX51_PIN_USBH1_STP, PAD_CTL_DRV_HIGH |
> +				PAD_CTL_PKE_ENABLE | PAD_CTL_SRE_FAST);
> +	gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_USBH1_STP), 0);
> +	udelay(1000);
> +	gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_USBH1_STP), 1);
> +	udelay(1000);
> +
> +	mxc_request_iomux(MX51_PIN_USBH1_STP, IOMUX_CONFIG_ALT0);
> +	mxc_iomux_set_pad(MX51_PIN_USBH1_STP, USB_PAD_CONFIG);
> +	udelay(10000);
> +
> +	clrbits_le32(&ehci->usbcmd, MX51_ITC_IMMEDIATE_MASK);
> +	udelay(10000);
> +
> +	writel(MX51_ULPI_MODE_MASK, &ehci->portsc);
> +	udelay(10000);
> +
> +	ulpi_init(ehci, ulpi);
> +}
> +
> +
> +void ehci2_init(struct usb_ehci *ehci, struct mxc_ulpi_regs *ulpi)
> +{
> +	mxc_request_iomux(MX51_PIN_EIM_A26, IOMUX_CONFIG_ALT1);
> +	mxc_iomux_set_pad(MX51_PIN_EIM_A26, PAD_CTL_DRV_HIGH |
> +				PAD_CTL_PKE_ENABLE | PAD_CTL_SRE_FAST);
> +	gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_EIM_A26), 0);
> +	udelay(1000);
> +	gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_EIM_A26), 1);
> +	udelay(1000);
> +
> +	mxc_request_iomux(MX51_PIN_EIM_A26, IOMUX_CONFIG_ALT2);
> +	mxc_iomux_set_pad(MX51_PIN_EIM_A26, USB_PAD_CONFIG);
> +
> +	writel(MX51_ULPI_MODE_MASK, &ehci->portsc);
> +	udelay(10000);
> +
> +	ulpi_init(ehci, ulpi);
> +}
> +
> +int ehci_hcd_init(void)
> +{
> +	struct usb_ehci *ehci;
> +	struct mx5_usb_control_regs *mx5_usb_control_regs;
> +	struct mxc_ulpi_regs *ulpi;
> +
> +	/* Init iMX51 EHCI */
> +	efika_usb_phy_reset();
> +	efika_usb_hub_reset();
> +	efika_usb_enable_devices();
> +
> +	mx5_usb_control_regs = (struct mx5_usb_control_regs *)(OTG_BASE_ADDR +
> +		 MX5_CTRL_REGS_OFFSET);
> +	control_regs_setup(mx5_usb_control_regs);
> +	ulpi = (struct mxc_ulpi_regs *)0;

Move this assignment at the begining.
> +
> +	/* Init EHCI core */
> +	ehci = (struct usb_ehci *)(OTG_BASE_ADDR +
> +		(MX51_REGISTER_LAYOUT_LENGTH * 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)));

DTTO

> +	setbits_le32(&ehci->usbmode, CM_HOST);
> +	setbits_le32(&ehci->control, USB_EN);
> +
> +	switch (CONFIG_MXC_USB_PORT) {
> +	case 0:
> +		ehci0_init(ehci);
> +		break;
> +	case 1:
> +		ehci1_init(ehci, ulpi);
> +		break;
> +#ifdef	MACH_EFIKASB
> +	case 2:
> +		ehci2_init(ehci, ulpi);
> +		break;
> +#endif
> +	};
> +
> +	/* EfikaMX USB has issues ... */
> +	udelay(10000);
> +
> +	return 0;
> +}
> +
> +int ehci_hcd_stop(void)
> +{
> +	return 0;
> +}
> diff --git a/board/efikamx/efikamx.c b/board/efikamx/efikamx.c
> index 5be1f6c..51c1854 100644
> --- a/board/efikamx/efikamx.c
> +++ b/board/efikamx/efikamx.c
> @@ -489,6 +489,15 @@ static inline void setup_iomux_ata(void) { }
>  #endif
> 
>  /*
> + * EHCI USB
> + */
> +#ifdef	CONFIG_CMD_USB
> +void setup_iomux_usb(void);
> +#else
> +static inline void setup_iomux_usb(void) { }
> +#endif
> +

Can you introduce efika.h header and move this to the header please.

> +/*
>   * LED configuration
>   */
>  void setup_iomux_led(void)
> @@ -621,6 +630,7 @@ int board_late_init(void)
> 
>  	setup_iomux_led();
>  	setup_iomux_ata();
> +	setup_iomux_usb();
> 
>  	efikamx_toggle_led(EFIKAMX_LED_BLUE);
> 
> diff --git a/include/configs/efikamx.h b/include/configs/efikamx.h
> index fdd0a14..9632b5d 100644
> --- a/include/configs/efikamx.h
> +++ b/include/configs/efikamx.h
> @@ -40,6 +40,10 @@
> 
>  #define CONFIG_SYS_TEXT_BASE		0x97800000
> 
> +#define	CONFIG_L2_OFF
> +#define	CONFIG_SYS_ICACHE_OFF
> +#define	CONFIG_SYS_DCACHE_OFF
> +
>  /*
>   * Bootloader Components Configuration
>   */
> @@ -168,6 +172,18 @@
>  #endif
> 
>  /*
> + * USB
> + */
> +#define CONFIG_CMD_USB
> +#ifdef CONFIG_CMD_USB
> +#define CONFIG_USB_EHCI			/* Enable EHCI USB support */
> +#define CONFIG_MXC_USB_PORT	1
> +#define CONFIG_EHCI_IS_TDI
> +#define CONFIG_USB_STORAGE
> +#define	CONFIG_USB_KEYBOARD

The indent looks wrong, please fix.

> +#endif /* CONFIG_CMD_USB */
> +
> +/*
>   * Filesystems
>   */
>  #ifdef CONFIG_CMD_FAT

Cheers
Jana Rapava Sept. 27, 2011, 2:12 p.m. UTC | #2
2011/9/27 Marek Vasut <marek.vasut@gmail.com>

>
> >  /*
> > + * EHCI USB
> > + */
> > +#ifdef       CONFIG_CMD_USB
> > +void setup_iomux_usb(void);
> > +#else
> > +static inline void setup_iomux_usb(void) { }
> > +#endif
> > +
>
> Can you introduce efika.h header and move this to the header please.
>

Should I move all #define's and #ifdef's, or only this?

Regards,
Jana Rapava
Marek Vasut Sept. 27, 2011, 2:55 p.m. UTC | #3
On Tuesday, September 27, 2011 04:12:18 PM Jana Rapava wrote:
> 2011/9/27 Marek Vasut <marek.vasut@gmail.com>
> 
> > >  /*
> > > 
> > > + * EHCI USB
> > > + */
> > > +#ifdef       CONFIG_CMD_USB
> > > +void setup_iomux_usb(void);
> > > +#else
> > > +static inline void setup_iomux_usb(void) { }
> > > +#endif
> > > +
> > 
> > Can you introduce efika.h header and move this to the header please.
> 
> Should I move all #define's and #ifdef's, or only this?

The defines are local, move only this
> 
> Regards,
> Jana Rapava
Jana Rapava Sept. 27, 2011, 6:17 p.m. UTC | #4
> > +
> > +#ifdef       CONFIG_MACH_EFIKASB

Please update to mainline, use if (machine_is_efikasb()) { ... } .
>

To get macro machine_is_efikasb() working, I have to get into mainline these
two of your patches in u-boot-marex:

430eacfcf35b1f54b0a1ead989aefe63e2996846  EfikaMX: Add imximage config for
Efika SB

 da3e51089d2b899a8b487b40fa63a04919927351 EfikaSB: Add preliminary EfikaSB
support

I don't know if they should be part of this patchset, but I don't think so.
I would like to try to get them into mainline - with your permission of
course, but they would probably need some changes and I can't test them
because I haven't EfikaSB.
Regards,
Jana Rapava
Marek Vasut Sept. 27, 2011, 6:20 p.m. UTC | #5
On Tuesday, September 27, 2011 08:17:27 PM Jana Rapava wrote:
> > > +
> > > +#ifdef       CONFIG_MACH_EFIKASB
> 
> Please update to mainline, use if (machine_is_efikasb()) { ... } .
> 
> 
> To get macro machine_is_efikasb() working, I have to get into mainline
> these two of your patches in u-boot-marex:
> 
> 430eacfcf35b1f54b0a1ead989aefe63e2996846  EfikaMX: Add imximage config for
> Efika SB
> 
>  da3e51089d2b899a8b487b40fa63a04919927351 EfikaSB: Add preliminary EfikaSB
> support
> 
> I don't know if they should be part of this patchset, but I don't think so.
> I would like to try to get them into mainline - with your permission of
> course, but they would probably need some changes and I can't test them
> because I haven't EfikaSB.

They were already added to u-boot-imx/next:

http://git.denx.de/?p=u-boot/u-boot-imx.git;a=shortlog;h=refs/heads/next

You should rebase your patchset on top of u-boot-imx/next.

> Regards,
> Jana Rapava
Stefano Babic Sept. 28, 2011, 10:26 a.m. UTC | #6
On 09/27/2011 08:17 PM, Jana Rapava wrote:
> 
>     > +
>     > +#ifdef       CONFIG_MACH_EFIKASB 
> 
>     Please update to mainline, use if (machine_is_efikasb()) { ... } .
> 
> 
> To get macro machine_is_efikasb() working, I have to get into mainline
> these two of your patches in u-boot-marex:
> 
> 430eacfcf35b1f54b0a1ead989aefe63e2996846  EfikaMX: Add imximage config
> for Efika SB
> 
>  da3e51089d2b899a8b487b40fa63a04919927351 EfikaSB: Add preliminary
> EfikaSB support

This two patches are already accepted and integrated into
u-boot-imx/next and in u-boot-arm/next.
You can take u-boot-imx/next as reference for your patchset

> 
> I don't know if they should be part of this patchset,

No, they don't

Best regards,
Stefano Babic
Jana Rapava Sept. 28, 2011, 12:12 p.m. UTC | #7
2011/9/28 Stefano Babic <sbabic@denx.de>

> This two patches are already accepted and integrated into
> u-boot-imx/next and in u-boot-arm/next.
> You can take u-boot-imx/next as reference for your patchset
>
> >
> > I don't know if they should be part of this patchset,
>
> No, they don't
>

Thanks, Marek already told me.

Regards,
Jana Rapava


> Best regards,
> Stefano Babic
>
> --
> =====================================================================
> DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
> HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
> Phone: +49-8142-66989-0 Fax: +49-8142-66989-80  Email: office@denx.de
> =====================================================================
>
diff mbox

Patch

diff --git a/board/efikamx/Makefile b/board/efikamx/Makefile
index ee4a16e..860e4d2 100644
--- a/board/efikamx/Makefile
+++ b/board/efikamx/Makefile
@@ -28,6 +28,9 @@  include $(TOPDIR)/config.mk
 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))
diff --git a/board/efikamx/efikamx-usb.c b/board/efikamx/efikamx-usb.c
new file mode 100644
index 0000000..c91a08b
--- /dev/null
+++ b/board/efikamx/efikamx-usb.c
@@ -0,0 +1,391 @@ 
+#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 <errno.h>
+#include <watchdog.h>
+
+#include <usb/ehci.h>
+#include <usb/ehci-core.h>
+
+/*
+ * Configure the USB H1 and USB H2 IOMUX
+ */
+#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)
+void setup_iomux_usb(void)
+{
+	/*
+	 * Configure USBH1 pads
+	 */
+	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 USBH1 control pads
+	 */
+
+	/* 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);
+
+
+#ifdef	CONFIG_MACH_EFIKASB
+	/*
+	 * Configure USBH2 pads (used on EfikaSB)
+	 */
+	/* USBH2_DATA */
+	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);
+
+	/* USBH2_CLK */
+	mxc_request_iomux(MX51_PIN_EIM_A24, IOMUX_CONFIG_ALT2);
+	mxc_iomux_set_pad(MX51_PIN_EIM_A24, USB_PAD_CONFIG);
+	/* USBH2_DIR */
+	mxc_request_iomux(MX51_PIN_EIM_A25, IOMUX_CONFIG_ALT2);
+	mxc_iomux_set_pad(MX51_PIN_EIM_A25, USB_PAD_CONFIG);
+	/* USBH2_STP */
+	mxc_request_iomux(MX51_PIN_EIM_A26, IOMUX_CONFIG_ALT2);
+	mxc_iomux_set_pad(MX51_PIN_EIM_A26, USB_PAD_CONFIG);
+	/* USBH2_NXT */
+	mxc_request_iomux(MX51_PIN_EIM_A27, IOMUX_CONFIG_ALT2);
+	mxc_iomux_set_pad(MX51_PIN_EIM_A27, USB_PAD_CONFIG);
+#endif
+
+	/* 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
+ */
+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)
+ */
+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)
+ */
+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);
+}
+
+/*
+ * Configure control registers of the USB controller
+ */
+void control_regs_setup(struct mx5_usb_control_regs *control)
+{
+	clrsetbits_le32(&control->usbctrl,
+		(MXC_OTG_WUE | MXC_OTG_PM | MX51_H1_ULPI_IE | MX51_H1_WUE),
+		MX51_H1_PM);
+
+	clrsetbits_le32(&control->phyctrl0,
+			MX51_OTG_OVERCURD,
+			MX51_EHCI_POWERPINSE);
+
+	clrsetbits_le32(&control->phyctrl1,
+			MX51_SYSCLOCK_MASK,
+			MX51_SYSCLOCK_24_MHZ);
+
+	setbits_le32(&control->usbctrl1, MX51_H1_EXTCLKE);
+
+	clrsetbits_le32(&control->uh2ctrl,
+			(MX51_H2_ULPI_IE | MX51_H2_WUE),
+			MX51_H2_PM);
+
+	udelay(10000);
+}
+
+#define ULPI_ADDR_SHIFT		16
+#define ulpi_write_mask(value)	((value) & 0xff)
+#define ulpi_read_mask(value)	(((value) >> 8) & 0xff)
+
+u32 ulpi_wait(struct usb_ehci *ehci, u32 ulpi_bit, const char *operation)
+{
+	int timeout = ULPI_TIMEOUT;
+	u32 tmp;
+
+	/* wait for the ulpi_bit to become zero */
+	while (--timeout) {
+		tmp = readl(&ehci->ulpi_viewpoint);
+		if (!(tmp & ulpi_bit))
+			break;
+		WATCHDOG_RESET();
+	}
+
+	if (!timeout) {
+		printf("ULPI %s timed out\n", operation);
+		return 0;
+	}
+	return tmp;
+}
+
+void ulpi_write(struct usb_ehci *ehci, u32 reg, u32 value)
+{
+	if (!(readl(&ehci->ulpi_viewpoint) & ULPI_SS)) {
+		writel(ULPI_WU, &ehci->ulpi_viewpoint);
+		ulpi_wait(ehci, ULPI_WU, "wakeup");
+	}
+
+	writel(ULPI_RWRUN | ULPI_RWCTRL |
+		reg << ULPI_ADDR_SHIFT | ulpi_write_mask(value),
+		&ehci->ulpi_viewpoint);
+	ulpi_wait(ehci, ULPI_RWRUN, "write");
+}
+
+u32 ulpi_read(struct usb_ehci *ehci, u32 reg)
+{
+	if (!(readl(&ehci->ulpi_viewpoint) & ULPI_SS)) {
+		writel(ULPI_WU, &ehci->ulpi_viewpoint);
+		ulpi_wait(ehci, ULPI_WU, "wakeup");
+	}
+
+	writel(ULPI_RWRUN | reg << ULPI_ADDR_SHIFT, &ehci->ulpi_viewpoint);
+	return ulpi_read_mask(ulpi_wait(ehci, ULPI_RWRUN, "read"));
+}
+
+void ulpi_init(struct usb_ehci *ehci, struct mxc_ulpi_regs *ulpi)
+{
+	u32 tmp = 0;
+	int reg, i;
+
+	/* get ID from ULPI immediate registers */
+	for (reg = ULPI_ID_REGS_COUNT - 1; reg >= 0; reg--)
+		tmp |= ulpi_read(ehci, (u32)reg) << (reg * 8);
+	/* split into vendor and product ID */
+	debug("Found ULPI TX, ID %04x:%04x\n", tmp >> 16, tmp & 0xffff);
+
+	/* ULPI check integrity */
+	for (i = 0; i < 2; i++) {
+		ulpi_write(ehci, (u32)&ulpi->scratch_write,
+			ULPI_TEST_VALUE << i);
+		tmp = ulpi_read(ehci, (u32)&ulpi->scratch_write);
+
+		if (tmp != (ULPI_TEST_VALUE << i)) {
+			printf("ULPI integrity check failed\n");
+			return;
+		}
+	}
+
+	/* ULPI set flags */
+	ulpi_write(ehci, (u32)&ulpi->otg_ctrl_write,
+		ULPI_OTG_EXT_VBUS_IND |
+		ULPI_OTG_DM_PULLDOWN | ULPI_OTG_DP_PULLDOWN);
+	ulpi_write(ehci, (u32)&ulpi->function_ctrl_write,
+		ULPI_FC_XCVR_SELECT | ULPI_FC_OPMODE_NORMAL |
+		ULPI_FC_SUSPENDM_PWRED);
+	ulpi_write(ehci, (u32)&ulpi->iface_ctrl_write, 0);
+	ulpi_write(ehci, (u32)&ulpi->otg_ctrl_set,
+		ULPI_OTG_DRV_VBUS | ULPI_OTG_DRV_VBUS_EXT);
+
+	/*
+	 * NOTE: This violates USB specification, but otherwise, USB on Efika
+	 * doesn't charge VBUS and as a result, USB doesn't work.
+	 */
+	ulpi_write(ehci, (u32)&ulpi->otg_ctrl_set, ULPI_OTG_CHRG_VBUS);
+}
+
+/*
+ * solve the VBUS reset problem on Efika
+ * by setting the CHRG_VBUS bit in the reset
+ */
+void ehci_fixup(uint32_t *status_reg, uint32_t *reg_ref)
+{
+	struct usb_ehci *ehci = (struct usb_ehci *)(OTG_BASE_ADDR +
+		(MX51_REGISTER_LAYOUT_LENGTH));
+	struct mxc_ulpi_regs *ulpi = (struct mxc_ulpi_regs *)0;
+
+	u32 tmp = ulpi_read(ehci, (u32)&ulpi->otg_ctrl_write);
+	tmp |= ULPI_OTG_CHRG_VBUS;
+	ulpi_write(ehci, (u32)&ulpi->otg_ctrl_write, tmp);
+
+	/* usb 2.0 specification say 50 ms resets on root */
+	wait_ms(50);
+
+	/* terminate the reset */
+	*reg_ref = ehci_readl(status_reg);
+	*reg_ref |= EHCI_PS_PE;
+}
+
+void ehci0_init(struct usb_ehci *ehci)
+{
+	writel(MX51_16BIT_UTMI, &ehci->portsc);
+}
+
+void ehci1_init(struct usb_ehci *ehci, struct mxc_ulpi_regs *ulpi)
+{
+	mxc_request_iomux(MX51_PIN_USBH1_STP, IOMUX_CONFIG_ALT2);
+	mxc_iomux_set_pad(MX51_PIN_USBH1_STP, PAD_CTL_DRV_HIGH |
+				PAD_CTL_PKE_ENABLE | PAD_CTL_SRE_FAST);
+	gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_USBH1_STP), 0);
+	udelay(1000);
+	gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_USBH1_STP), 1);
+	udelay(1000);
+
+	mxc_request_iomux(MX51_PIN_USBH1_STP, IOMUX_CONFIG_ALT0);
+	mxc_iomux_set_pad(MX51_PIN_USBH1_STP, USB_PAD_CONFIG);
+	udelay(10000);
+
+	clrbits_le32(&ehci->usbcmd, MX51_ITC_IMMEDIATE_MASK);
+	udelay(10000);
+
+	writel(MX51_ULPI_MODE_MASK, &ehci->portsc);
+	udelay(10000);
+
+	ulpi_init(ehci, ulpi);
+}
+
+
+void ehci2_init(struct usb_ehci *ehci, struct mxc_ulpi_regs *ulpi)
+{
+	mxc_request_iomux(MX51_PIN_EIM_A26, IOMUX_CONFIG_ALT1);
+	mxc_iomux_set_pad(MX51_PIN_EIM_A26, PAD_CTL_DRV_HIGH |
+				PAD_CTL_PKE_ENABLE | PAD_CTL_SRE_FAST);
+	gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_EIM_A26), 0);
+	udelay(1000);
+	gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_EIM_A26), 1);
+	udelay(1000);
+
+	mxc_request_iomux(MX51_PIN_EIM_A26, IOMUX_CONFIG_ALT2);
+	mxc_iomux_set_pad(MX51_PIN_EIM_A26, USB_PAD_CONFIG);
+
+	writel(MX51_ULPI_MODE_MASK, &ehci->portsc);
+	udelay(10000);
+
+	ulpi_init(ehci, ulpi);
+}
+
+int ehci_hcd_init(void)
+{
+	struct usb_ehci *ehci;
+	struct mx5_usb_control_regs *mx5_usb_control_regs;
+	struct mxc_ulpi_regs *ulpi;
+
+	/* Init iMX51 EHCI */
+	efika_usb_phy_reset();
+	efika_usb_hub_reset();
+	efika_usb_enable_devices();
+
+	mx5_usb_control_regs = (struct mx5_usb_control_regs *)(OTG_BASE_ADDR +
+		 MX5_CTRL_REGS_OFFSET);
+	control_regs_setup(mx5_usb_control_regs);
+	ulpi = (struct mxc_ulpi_regs *)0;
+
+	/* Init EHCI core */
+	ehci = (struct usb_ehci *)(OTG_BASE_ADDR +
+		(MX51_REGISTER_LAYOUT_LENGTH * 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);
+	setbits_le32(&ehci->control, USB_EN);
+
+	switch (CONFIG_MXC_USB_PORT) {
+	case 0:
+		ehci0_init(ehci);
+		break;
+	case 1:
+		ehci1_init(ehci, ulpi);
+		break;
+#ifdef	MACH_EFIKASB
+	case 2:
+		ehci2_init(ehci, ulpi);
+		break;
+#endif
+	};
+
+	/* EfikaMX USB has issues ... */
+	udelay(10000);
+
+	return 0;
+}
+
+int ehci_hcd_stop(void)
+{
+	return 0;
+}
diff --git a/board/efikamx/efikamx.c b/board/efikamx/efikamx.c
index 5be1f6c..51c1854 100644
--- a/board/efikamx/efikamx.c
+++ b/board/efikamx/efikamx.c
@@ -489,6 +489,15 @@  static inline void setup_iomux_ata(void) { }
 #endif
 
 /*
+ * EHCI USB
+ */
+#ifdef	CONFIG_CMD_USB
+void setup_iomux_usb(void);
+#else
+static inline void setup_iomux_usb(void) { }
+#endif
+
+/*
  * LED configuration
  */
 void setup_iomux_led(void)
@@ -621,6 +630,7 @@  int board_late_init(void)
 
 	setup_iomux_led();
 	setup_iomux_ata();
+	setup_iomux_usb();
 
 	efikamx_toggle_led(EFIKAMX_LED_BLUE);
 
diff --git a/include/configs/efikamx.h b/include/configs/efikamx.h
index fdd0a14..9632b5d 100644
--- a/include/configs/efikamx.h
+++ b/include/configs/efikamx.h
@@ -40,6 +40,10 @@ 
 
 #define CONFIG_SYS_TEXT_BASE		0x97800000
 
+#define	CONFIG_L2_OFF
+#define	CONFIG_SYS_ICACHE_OFF
+#define	CONFIG_SYS_DCACHE_OFF
+
 /*
  * Bootloader Components Configuration
  */
@@ -168,6 +172,18 @@ 
 #endif
 
 /*
+ * USB
+ */
+#define CONFIG_CMD_USB
+#ifdef CONFIG_CMD_USB
+#define CONFIG_USB_EHCI			/* Enable EHCI USB support */
+#define CONFIG_MXC_USB_PORT	1
+#define CONFIG_EHCI_IS_TDI
+#define CONFIG_USB_STORAGE
+#define	CONFIG_USB_KEYBOARD
+#endif /* CONFIG_CMD_USB */
+
+/*
  * Filesystems
  */
 #ifdef CONFIG_CMD_FAT