diff options
| author | Wolfgang Grandegger <wg@denx.de> | 2011-11-11 14:03:36 +0100 | 
|---|---|---|
| committer | Remy Bohmer <linux@bohmer.net> | 2011-12-11 14:49:31 +0100 | 
| commit | 1ca56202532395f26fc59a87e62c9cab1541f9f3 (patch) | |
| tree | 8c45f9927def3111f9982ea04791bc443eb682de /drivers/usb/host/ehci-mx5.c | |
| parent | 5d2947a3fc8d130cfa39fccdefb87082abbf0e9b (diff) | |
| download | olio-uboot-2014.01-1ca56202532395f26fc59a87e62c9cab1541f9f3.tar.xz olio-uboot-2014.01-1ca56202532395f26fc59a87e62c9cab1541f9f3.zip | |
USB: MX5: add generic USB EHCI support for mx51 and mx53
It's derived from ehci-mxc and uses the header files of the
ehci-fsl interface. The callback board_ehci_hcd_init() has
been introduced to allow for board-specific setup when USB
is started.
Signed-off-by: Wolfgang Grandegger <wg@denx.de>
CC: Stefano Babic <sbabic@denx.de>
CC: Remy Bohmer <linux@bohmer.net>
Diffstat (limited to 'drivers/usb/host/ehci-mx5.c')
| -rw-r--r-- | drivers/usb/host/ehci-mx5.c | 174 | 
1 files changed, 174 insertions, 0 deletions
| diff --git a/drivers/usb/host/ehci-mx5.c b/drivers/usb/host/ehci-mx5.c new file mode 100644 index 000000000..4c961d345 --- /dev/null +++ b/drivers/usb/host/ehci-mx5.c @@ -0,0 +1,174 @@ +/* + * 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 "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) + +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; +} + +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); + +	return 0; +} + +int ehci_hcd_stop(void) +{ +	return 0; +} + + |