diff mbox

[U-Boot,5/8] usb: xhci-exynos5: Add support for multiple USB 3.0 controllers

Message ID 1389000583-20758-6-git-send-email-gautam.vivek@samsung.com
State Changes Requested
Delegated to: Minkyu Kang
Headers show

Commit Message

Vivek Gautam Jan. 6, 2014, 9:29 a.m. UTC
Add required support to use multiple USB 3.0 controllers available
on exynos5420 SoC.

Signed-off-by: Vivek Gautam <gautam.vivek@samsung.com>
---
 arch/arm/cpu/armv7/exynos/power.c        |   18 ++++--
 arch/arm/include/asm/arch-exynos/cpu.h   |   10 ++++
 arch/arm/include/asm/arch-exynos/power.h |    2 +-
 drivers/usb/host/xhci-exynos5.c          |   91 +++++++++++++++++++++---------
 drivers/usb/host/xhci.c                  |    4 --
 drivers/usb/host/xhci.h                  |    4 ++
 6 files changed, 91 insertions(+), 38 deletions(-)

Comments

Marek Vasut Jan. 6, 2014, 3:51 p.m. UTC | #1
On Monday, January 06, 2014 at 10:29:40 AM, Vivek Gautam wrote:
> Add required support to use multiple USB 3.0 controllers available
> on exynos5420 SoC.
> 
> Signed-off-by: Vivek Gautam <gautam.vivek@samsung.com>
> ---
>  arch/arm/cpu/armv7/exynos/power.c        |   18 ++++--
>  arch/arm/include/asm/arch-exynos/cpu.h   |   10 ++++
>  arch/arm/include/asm/arch-exynos/power.h |    2 +-
>  drivers/usb/host/xhci-exynos5.c          |   91
> +++++++++++++++++++++--------- drivers/usb/host/xhci.c                  | 
>   4 --
>  drivers/usb/host/xhci.h                  |    4 ++
>  6 files changed, 91 insertions(+), 38 deletions(-)
> 
> diff --git a/arch/arm/cpu/armv7/exynos/power.c
> b/arch/arm/cpu/armv7/exynos/power.c index 563abd7..0f8aa98 100644
> --- a/arch/arm/cpu/armv7/exynos/power.c
> +++ b/arch/arm/cpu/armv7/exynos/power.c
> @@ -59,26 +59,34 @@ void set_usbhost_phy_ctrl(unsigned int enable)
>  		exynos5_set_usbhost_phy_ctrl(enable);
>  }
> 
> -static void exynos5_set_usbdrd_phy_ctrl(unsigned int enable)
> +static void exynos5_set_usbdrd_phy_ctrl(unsigned int enable, int
> dev_index) {
>  	struct exynos5_power *power =
>  		(struct exynos5_power *)samsung_get_base_power();
> 
> +	/*
> +	 * Assuming here that the DRD_PHY_CONTROL registers
> +	 * are contiguous, so that :
> +	 * addressof(DRD_PHY1_CONTROL) = addressof(DRD_PHY_CONTROL) + 0x4;
> +	 * which is the case with exynos5420.
> +	 * For exynos5250 this should work out of box, since dev_index will
> +	 * always be '0' in that case
> +	 */

Why don't you convert the entry for usbdrd_phy_control into an array in the 
'struct exynos5_power' structure instead ? Then you could index it with 
dev_index.

[...]

Do you think it'd be possible to split this patch into drivers/usb/ specific 
part and CPU-specific part ? I'd like to see that to prevent merge conflicts.

[...]

Best regards,
Marek Vasut
Minkyu Kang Jan. 7, 2014, 5:30 a.m. UTC | #2
Dear Vivek Gautam,

On 06/01/14 18:29, Vivek Gautam wrote:
> Add required support to use multiple USB 3.0 controllers available
> on exynos5420 SoC.
> 
> Signed-off-by: Vivek Gautam <gautam.vivek@samsung.com>
> ---
>  arch/arm/cpu/armv7/exynos/power.c        |   18 ++++--
>  arch/arm/include/asm/arch-exynos/cpu.h   |   10 ++++
>  arch/arm/include/asm/arch-exynos/power.h |    2 +-
>  drivers/usb/host/xhci-exynos5.c          |   91 +++++++++++++++++++++---------
>  drivers/usb/host/xhci.c                  |    4 --
>  drivers/usb/host/xhci.h                  |    4 ++
>  6 files changed, 91 insertions(+), 38 deletions(-)
> 
> diff --git a/arch/arm/cpu/armv7/exynos/power.c b/arch/arm/cpu/armv7/exynos/power.c
> index 563abd7..0f8aa98 100644
> --- a/arch/arm/cpu/armv7/exynos/power.c
> +++ b/arch/arm/cpu/armv7/exynos/power.c
> @@ -59,26 +59,34 @@ void set_usbhost_phy_ctrl(unsigned int enable)
>  		exynos5_set_usbhost_phy_ctrl(enable);
>  }
>  
> -static void exynos5_set_usbdrd_phy_ctrl(unsigned int enable)
> +static void exynos5_set_usbdrd_phy_ctrl(unsigned int enable, int dev_index)
>  {
>  	struct exynos5_power *power =
>  		(struct exynos5_power *)samsung_get_base_power();
>  
> +	/*
> +	 * Assuming here that the DRD_PHY_CONTROL registers
> +	 * are contiguous, so that :
> +	 * addressof(DRD_PHY1_CONTROL) = addressof(DRD_PHY_CONTROL) + 0x4;
> +	 * which is the case with exynos5420.
> +	 * For exynos5250 this should work out of box, since dev_index will
> +	 * always be '0' in that case
> +	 */
>  	if (enable) {
>  		/* Enabling USBDRD_PHY */
> -		setbits_le32(&power->usbdrd_phy_control,
> +		setbits_le32(&power->usbdrd_phy_control + dev_index,
>  				POWER_USB_DRD_PHY_CTRL_EN);
>  	} else {
>  		/* Disabling USBDRD_PHY */
> -		clrbits_le32(&power->usbdrd_phy_control,
> +		clrbits_le32(&power->usbdrd_phy_control + dev_index,
>  				POWER_USB_DRD_PHY_CTRL_EN);
>  	}
>  }
>  
> -void set_usbdrd_phy_ctrl(unsigned int enable)
> +void set_usbdrd_phy_ctrl(unsigned int enable, int dev_index)
>  {
>  	if (cpu_is_exynos5())
> -		exynos5_set_usbdrd_phy_ctrl(enable);
> +		exynos5_set_usbdrd_phy_ctrl(enable, dev_index);
>  }
>  
>  static void exynos5_dp_phy_control(unsigned int enable)
> diff --git a/arch/arm/include/asm/arch-exynos/cpu.h b/arch/arm/include/asm/arch-exynos/cpu.h
> index 718940b..d93cba9 100644
> --- a/arch/arm/include/asm/arch-exynos/cpu.h
> +++ b/arch/arm/include/asm/arch-exynos/cpu.h
> @@ -54,6 +54,8 @@
>  #define EXYNOS4_USB_HOST_XHCI_BASE	DEVICE_NOT_AVAILABLE
>  #define EXYNOS4_USB3PHY_BASE		DEVICE_NOT_AVAILABLE
>  #define EXYNOS4_DMC_TZASC_BASE		DEVICE_NOT_AVAILABLE
> +#define EXYNOS4_USB_HOST_XHCI_1_BASE	DEVICE_NOT_AVAILABLE
> +#define EXYNOS4_USB3PHY_1_BASE		DEVICE_NOT_AVAILABLE
>  
>  /* EXYNOS4X12 */
>  #define EXYNOS4X12_GPIO_PART3_BASE	0x03860000
> @@ -93,6 +95,8 @@
>  #define EXYNOS4X12_USB_HOST_XHCI_BASE	DEVICE_NOT_AVAILABLE
>  #define EXYNOS4X12_USB3PHY_BASE		DEVICE_NOT_AVAILABLE
>  #define EXYNOS4X12_DMC_TZASC_BASE	DEVICE_NOT_AVAILABLE
> +#define EXYNOS4X12_USB_HOST_XHCI_1_BASE	DEVICE_NOT_AVAILABLE
> +#define EXYNOS4X12_USB3PHY_1_BASE	DEVICE_NOT_AVAILABLE
>  
>  /* EXYNOS5 */
>  #define EXYNOS5_I2C_SPACING		0x10000
> @@ -132,6 +136,8 @@
>  #define EXYNOS5_ADC_BASE		DEVICE_NOT_AVAILABLE
>  #define EXYNOS5_MODEM_BASE		DEVICE_NOT_AVAILABLE
>  #define EXYNOS5_DMC_TZASC_BASE		DEVICE_NOT_AVAILABLE
> +#define EXYNOS5_USB_HOST_XHCI_1_BASE	DEVICE_NOT_AVAILABLE
> +#define EXYNOS5_USB3PHY_1_BASE		DEVICE_NOT_AVAILABLE
>  
>  /* EXYNOS5420 */
>  #define EXYNOS5420_AUDIOSS_BASE		0x03810000
> @@ -153,6 +159,8 @@
>  #define EXYNOS5420_USBPHY_BASE		0x12130000
>  #define EXYNOS5420_MMC_BASE		0x12200000
>  #define EXYNOS5420_SROMC_BASE		0x12250000
> +#define EXYNOS5420_USB_HOST_XHCI_1_BASE	0x12400000
> +#define EXYNOS5420_USB3PHY_1_BASE	0x12500000

No. we don't have to add phy_1 and xhci_1.
It looks weird.
please access phy1 and xhci1 by offset.

>  #define EXYNOS5420_UART_BASE		0x12C00000
>  #define EXYNOS5420_I2C_BASE		0x12C60000
>  #define EXYNOS5420_I2C_8910_BASE	0x12E00000
> @@ -276,8 +284,10 @@ SAMSUNG_BASE(timer, PWMTIMER_BASE)
>  SAMSUNG_BASE(uart, UART_BASE)
>  SAMSUNG_BASE(usb_phy, USBPHY_BASE)
>  SAMSUNG_BASE(usb3_phy, USB3PHY_BASE)
> +SAMSUNG_BASE(usb3_phy_1, USB3PHY_1_BASE)
>  SAMSUNG_BASE(usb_ehci, USB_HOST_EHCI_BASE)
>  SAMSUNG_BASE(usb_xhci, USB_HOST_XHCI_BASE)
> +SAMSUNG_BASE(usb_xhci_1, USB_HOST_XHCI_1_BASE)
>  SAMSUNG_BASE(usb_otg, USBOTG_BASE)
>  SAMSUNG_BASE(watchdog, WATCHDOG_BASE)
>  SAMSUNG_BASE(power, POWER_BASE)
> diff --git a/arch/arm/include/asm/arch-exynos/power.h b/arch/arm/include/asm/arch-exynos/power.h
> index c9609a2..c3f2ef0 100644
> --- a/arch/arm/include/asm/arch-exynos/power.h
> +++ b/arch/arm/include/asm/arch-exynos/power.h
> @@ -1684,7 +1684,7 @@ void set_hw_thermal_trip(void);
>  #define POWER_USB_HOST_PHY_CTRL_EN		(1 << 0)
>  #define POWER_USB_HOST_PHY_CTRL_DISABLE		(0 << 0)
>  
> -void set_usbdrd_phy_ctrl(unsigned int enable);
> +void set_usbdrd_phy_ctrl(unsigned int enable, int dev_index);
>  
>  #define POWER_USB_DRD_PHY_CTRL_EN		(1 << 0)
>  #define POWER_USB_DRD_PHY_CTRL_DISABLE		(0 << 0)
> diff --git a/drivers/usb/host/xhci-exynos5.c b/drivers/usb/host/xhci-exynos5.c
> index 1146d10..b5fce40 100644
> --- a/drivers/usb/host/xhci-exynos5.c
> +++ b/drivers/usb/host/xhci-exynos5.c
> @@ -43,18 +43,30 @@ struct exynos_xhci {
>  	struct fdt_gpio_state vbus_gpio;
>  };
>  
> -static struct exynos_xhci exynos;
> +static struct exynos_xhci reg_bases[CONFIG_USB_MAX_CONTROLLER_COUNT];
>  
>  #ifdef CONFIG_OF_CONTROL
> -static int exynos_usb3_parse_dt(const void *blob, struct exynos_xhci *exynos)
> +static int exynos_usb3_parse_dt(const void *blob,
> +				struct exynos_xhci *base,
> +				int index)
>  {
>  	fdt_addr_t addr;
> -	unsigned int node;
> -	int depth;
> +	int depth, count;
> +	unsigned int node = 0;

= 0; unnecessary.

> +	int nodes[CONFIG_USB_MAX_CONTROLLER_COUNT];
> +
> +	/* First find all the compatible nodes */
> +	count = fdtdec_find_aliases_for_id(blob, "xhci",
> +			COMPAT_SAMSUNG_EXYNOS5_XHCI, nodes,
> +			CONFIG_USB_MAX_CONTROLLER_COUNT);
> +	if (count < 0) {
> +		printf("XHCI: Can't get device node for xhci\n");
> +		return -ENODEV;
> +	}
>  
> -	node = fdtdec_next_compatible(blob, 0, COMPAT_SAMSUNG_EXYNOS5_XHCI);
> +	node = nodes[index];
>  	if (node <= 0) {
> -		debug("XHCI: Can't get device node for xhci\n");
> +		printf("XHCI: Can't get device node for xhci\n");
>  		return -ENODEV;
>  	}
>  
> @@ -66,10 +78,10 @@ static int exynos_usb3_parse_dt(const void *blob, struct exynos_xhci *exynos)
>  		debug("Can't get the XHCI register base address\n");
>  		return -ENXIO;
>  	}
> -	exynos->hcd = (struct xhci_hccr *)addr;
> +	base->hcd = (struct xhci_hccr *)addr;
>  
>  	/* Vbus gpio */
> -	fdtdec_decode_gpio(blob, node, "samsung,vbus-gpio", &exynos->vbus_gpio);
> +	fdtdec_decode_gpio(blob, node, "samsung,vbus-gpio", &base->vbus_gpio);
>  
>  	depth = 0;
>  	node = fdtdec_next_compatible_subnode(blob, node,
> @@ -82,9 +94,9 @@ static int exynos_usb3_parse_dt(const void *blob, struct exynos_xhci *exynos)
>  	/*
>  	 * Get the base address for usbphy from the device node
>  	 */
> -	exynos->usb3_phy = (struct exynos_usb3_phy *)fdtdec_get_addr(blob, node,
> +	base->usb3_phy = (struct exynos_usb3_phy *)fdtdec_get_addr(blob, node,
>  								"reg");
> -	if (exynos->usb3_phy == NULL) {
> +	if (base->usb3_phy == NULL) {
>  		debug("Can't get the usbphy register address\n");
>  		return -ENXIO;
>  	}
> @@ -97,9 +109,6 @@ static void exynos5_usb3_phy_init(struct exynos_usb3_phy *phy)
>  {
>  	u32 reg;
>  
> -	/* enabling usb_drd phy */
> -	set_usbdrd_phy_ctrl(POWER_USB_DRD_PHY_CTRL_EN);
> -
>  	/* Reset USB 3.0 PHY */
>  	writel(0x0, &phy->phy_reg0);
>  
> @@ -176,9 +185,6 @@ static void exynos5_usb3_phy_exit(struct exynos_usb3_phy *phy)
>  	setbits_le32(&phy->phy_test,
>  			PHYTEST_POWERDOWN_SSP |
>  			PHYTEST_POWERDOWN_HSP);
> -
> -	/* disabling usb_drd phy */
> -	set_usbdrd_phy_ctrl(POWER_USB_DRD_PHY_CTRL_DISABLE);
>  }
>  
>  void dwc3_set_mode(struct dwc3 *dwc3_reg, u32 mode)
> @@ -259,41 +265,64 @@ static int dwc3_core_init(struct dwc3 *dwc3_reg)
>  	return 0;
>  }
>  
> -static int exynos_xhci_core_init(struct exynos_xhci *exynos)
> +static int exynos_xhci_core_init(struct exynos_xhci *base)
>  {
>  	int ret;
>  
> -	exynos5_usb3_phy_init(exynos->usb3_phy);
> +	exynos5_usb3_phy_init(base->usb3_phy);
>  
> -	ret = dwc3_core_init(exynos->dwc3_reg);
> +	ret = dwc3_core_init(base->dwc3_reg);
>  	if (ret) {
>  		debug("failed to initialize core\n");
>  		return -EINVAL;
>  	}
>  
> -	/* We are hard-coding DWC3 core to Host Mode */
> -	dwc3_set_mode(exynos->dwc3_reg, DWC3_GCTL_PRTCAP_HOST);
> +	/*
> +	 * TODO: We are hard-coding DWC3 core to Host Mode;
> +	 * when we have complete DWC3 support we may want to
> +	 * have both device as well as host mode, so this will
> +	 * vanish off then.
> +	 */
> +	dwc3_set_mode(base->dwc3_reg, DWC3_GCTL_PRTCAP_HOST);
>  
>  	return 0;
>  }
>  
> -static void exynos_xhci_core_exit(struct exynos_xhci *exynos)
> +static void exynos_xhci_core_exit(struct exynos_xhci *base)
>  {
> -	exynos5_usb3_phy_exit(exynos->usb3_phy);
> +	exynos5_usb3_phy_exit(base->usb3_phy);
>  }
>  
>  int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor)
>  {
> -	struct exynos_xhci *ctx = &exynos;
> +	struct exynos_xhci *ctx = &reg_bases[index];
>  	int ret;
>  
>  #ifdef CONFIG_OF_CONTROL
> -	exynos_usb3_parse_dt(gd->fdt_blob, ctx);
> +	exynos_usb3_parse_dt(gd->fdt_blob, ctx, index);
>  #else
> -	ctx->usb3_phy = (struct exynos_usb3_phy *)samsung_get_base_usb3_phy();
> -	ctx->hcd = (struct xhci_hccr *)samsung_get_base_usb_xhci();
> +	/*
> +	 * right now we only have h/w with 2 controllers, so limiting the
> +	 * index to two here: either 0 or 1.
> +	 */
> +	if (index == 0) {
> +		ctx->usb3_phy = (struct exynos_usb3_phy *)
> +					samsung_get_base_usb3_phy();
> +		ctx->hcd = (struct xhci_hccr *)
> +					samsung_get_base_usb_xhci();
> +	} else if (index == 1) {
> +		ctx->usb3_phy = (struct exynos_usb3_phy *)
> +					samsung_get_base_usb3_phy_1();
> +		ctx->hcd = (struct xhci_hccr *)
> +					samsung_get_base_usb_xhci_1();
> +	}
>  #endif
>  
> +	if (!ctx->hcd || !ctx->usb3_phy) {
> +		printf("XHCI: Unable to find Host controller\n");
> +		return -ENODEV;
> +	}
> +
>  	ctx->dwc3_reg = (struct dwc3 *)((char *)(ctx->hcd) + DWC3_REG_OFFSET);
>  
>  #ifdef CONFIG_OF_CONTROL
> @@ -302,6 +331,9 @@ int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor)
>  		gpio_direction_output(ctx->vbus_gpio.gpio, 1);
>  #endif
>  
> +	/* Power-on usb_drd phy */
> +	set_usbdrd_phy_ctrl(POWER_USB_DRD_PHY_CTRL_EN, index);
> +
>  	ret = exynos_xhci_core_init(ctx);
>  	if (ret) {
>  		puts("XHCI: failed to initialize controller\n");
> @@ -321,7 +353,10 @@ int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor)
>  
>  void xhci_hcd_stop(int index)
>  {
> -	struct exynos_xhci *ctx = &exynos;
> +	struct exynos_xhci *ctx = &reg_bases[index];
>  
>  	exynos_xhci_core_exit(ctx);
> +
> +	/* Power-off usb_drd phy */
> +	set_usbdrd_phy_ctrl(POWER_USB_DRD_PHY_CTRL_DISABLE, index);
>  }
> diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
> index d1c2e5c..24175e6 100644
> --- a/drivers/usb/host/xhci.c
> +++ b/drivers/usb/host/xhci.c
> @@ -30,10 +30,6 @@
>  #include <asm-generic/errno.h>
>  #include "xhci.h"
>  
> -#ifndef CONFIG_USB_MAX_CONTROLLER_COUNT
> -#define CONFIG_USB_MAX_CONTROLLER_COUNT 1
> -#endif
> -
>  static struct descriptor {
>  	struct usb_hub_descriptor hub;
>  	struct usb_device_descriptor device;
> diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
> index ceb1573..612bf79 100644
> --- a/drivers/usb/host/xhci.h
> +++ b/drivers/usb/host/xhci.h
> @@ -21,6 +21,10 @@
>  #include <asm/io.h>
>  #include <linux/list.h>
>  
> +#ifndef CONFIG_USB_MAX_CONTROLLER_COUNT
> +#define CONFIG_USB_MAX_CONTROLLER_COUNT 1
> +#endif
> +
>  #define upper_32_bits(n) (u32)((n) >> 32)
>  #define lower_32_bits(n) (u32)(n)
>  
> 

Thanks,
Minkyu Kang.
Vivek Gautam Jan. 7, 2014, 9:15 a.m. UTC | #3
Hi Minkyu Kang,


On Tue, Jan 7, 2014 at 11:00 AM, Minkyu Kang <mk7.kang@samsung.com> wrote:
> Dear Vivek Gautam,
>
> On 06/01/14 18:29, Vivek Gautam wrote:
>> Add required support to use multiple USB 3.0 controllers available
>> on exynos5420 SoC.
>>
>> Signed-off-by: Vivek Gautam <gautam.vivek@samsung.com>
>> ---
>>  arch/arm/cpu/armv7/exynos/power.c        |   18 ++++--
>>  arch/arm/include/asm/arch-exynos/cpu.h   |   10 ++++
>>  arch/arm/include/asm/arch-exynos/power.h |    2 +-
>>  drivers/usb/host/xhci-exynos5.c          |   91 +++++++++++++++++++++---------
>>  drivers/usb/host/xhci.c                  |    4 --
>>  drivers/usb/host/xhci.h                  |    4 ++
>>  6 files changed, 91 insertions(+), 38 deletions(-)
>>
>> diff --git a/arch/arm/cpu/armv7/exynos/power.c b/arch/arm/cpu/armv7/exynos/power.c
>> index 563abd7..0f8aa98 100644
>> --- a/arch/arm/cpu/armv7/exynos/power.c
>> +++ b/arch/arm/cpu/armv7/exynos/power.c
>> @@ -59,26 +59,34 @@ void set_usbhost_phy_ctrl(unsigned int enable)
>>               exynos5_set_usbhost_phy_ctrl(enable);
>>  }
>>
>> -static void exynos5_set_usbdrd_phy_ctrl(unsigned int enable)
>> +static void exynos5_set_usbdrd_phy_ctrl(unsigned int enable, int dev_index)
>>  {
>>       struct exynos5_power *power =
>>               (struct exynos5_power *)samsung_get_base_power();
>>
>> +     /*
>> +      * Assuming here that the DRD_PHY_CONTROL registers
>> +      * are contiguous, so that :
>> +      * addressof(DRD_PHY1_CONTROL) = addressof(DRD_PHY_CONTROL) + 0x4;
>> +      * which is the case with exynos5420.
>> +      * For exynos5250 this should work out of box, since dev_index will
>> +      * always be '0' in that case
>> +      */
>>       if (enable) {
>>               /* Enabling USBDRD_PHY */
>> -             setbits_le32(&power->usbdrd_phy_control,
>> +             setbits_le32(&power->usbdrd_phy_control + dev_index,
>>                               POWER_USB_DRD_PHY_CTRL_EN);
>>       } else {
>>               /* Disabling USBDRD_PHY */
>> -             clrbits_le32(&power->usbdrd_phy_control,
>> +             clrbits_le32(&power->usbdrd_phy_control + dev_index,
>>                               POWER_USB_DRD_PHY_CTRL_EN);
>>       }
>>  }
>>
>> -void set_usbdrd_phy_ctrl(unsigned int enable)
>> +void set_usbdrd_phy_ctrl(unsigned int enable, int dev_index)
>>  {
>>       if (cpu_is_exynos5())
>> -             exynos5_set_usbdrd_phy_ctrl(enable);
>> +             exynos5_set_usbdrd_phy_ctrl(enable, dev_index);
>>  }
>>
>>  static void exynos5_dp_phy_control(unsigned int enable)
>> diff --git a/arch/arm/include/asm/arch-exynos/cpu.h b/arch/arm/include/asm/arch-exynos/cpu.h
>> index 718940b..d93cba9 100644
>> --- a/arch/arm/include/asm/arch-exynos/cpu.h
>> +++ b/arch/arm/include/asm/arch-exynos/cpu.h
>> @@ -54,6 +54,8 @@
>>  #define EXYNOS4_USB_HOST_XHCI_BASE   DEVICE_NOT_AVAILABLE
>>  #define EXYNOS4_USB3PHY_BASE         DEVICE_NOT_AVAILABLE
>>  #define EXYNOS4_DMC_TZASC_BASE               DEVICE_NOT_AVAILABLE
>> +#define EXYNOS4_USB_HOST_XHCI_1_BASE DEVICE_NOT_AVAILABLE
>> +#define EXYNOS4_USB3PHY_1_BASE               DEVICE_NOT_AVAILABLE
>>
>>  /* EXYNOS4X12 */
>>  #define EXYNOS4X12_GPIO_PART3_BASE   0x03860000
>> @@ -93,6 +95,8 @@
>>  #define EXYNOS4X12_USB_HOST_XHCI_BASE        DEVICE_NOT_AVAILABLE
>>  #define EXYNOS4X12_USB3PHY_BASE              DEVICE_NOT_AVAILABLE
>>  #define EXYNOS4X12_DMC_TZASC_BASE    DEVICE_NOT_AVAILABLE
>> +#define EXYNOS4X12_USB_HOST_XHCI_1_BASE      DEVICE_NOT_AVAILABLE
>> +#define EXYNOS4X12_USB3PHY_1_BASE    DEVICE_NOT_AVAILABLE
>>
>>  /* EXYNOS5 */
>>  #define EXYNOS5_I2C_SPACING          0x10000
>> @@ -132,6 +136,8 @@
>>  #define EXYNOS5_ADC_BASE             DEVICE_NOT_AVAILABLE
>>  #define EXYNOS5_MODEM_BASE           DEVICE_NOT_AVAILABLE
>>  #define EXYNOS5_DMC_TZASC_BASE               DEVICE_NOT_AVAILABLE
>> +#define EXYNOS5_USB_HOST_XHCI_1_BASE DEVICE_NOT_AVAILABLE
>> +#define EXYNOS5_USB3PHY_1_BASE               DEVICE_NOT_AVAILABLE
>>
>>  /* EXYNOS5420 */
>>  #define EXYNOS5420_AUDIOSS_BASE              0x03810000
>> @@ -153,6 +159,8 @@
>>  #define EXYNOS5420_USBPHY_BASE               0x12130000
>>  #define EXYNOS5420_MMC_BASE          0x12200000
>>  #define EXYNOS5420_SROMC_BASE                0x12250000
>> +#define EXYNOS5420_USB_HOST_XHCI_1_BASE      0x12400000
>> +#define EXYNOS5420_USB3PHY_1_BASE    0x12500000
>
> No. we don't have to add phy_1 and xhci_1.
> It looks weird.
> please access phy1 and xhci1 by offset.

Ok, so you mean i should add offsets definitions for phy1 and xhci1
may be in the driver file or in
"arch/arm/include/asm/arch-exynos/xhci-exynos.h" file, and add these
offsets to xhci_base and
phy_base addresses ?
That should be fine, i will modify this accordingly.

>
>>  #define EXYNOS5420_UART_BASE         0x12C00000
>>  #define EXYNOS5420_I2C_BASE          0x12C60000
>>  #define EXYNOS5420_I2C_8910_BASE     0x12E00000
>> @@ -276,8 +284,10 @@ SAMSUNG_BASE(timer, PWMTIMER_BASE)
>>  SAMSUNG_BASE(uart, UART_BASE)
>>  SAMSUNG_BASE(usb_phy, USBPHY_BASE)
>>  SAMSUNG_BASE(usb3_phy, USB3PHY_BASE)
>> +SAMSUNG_BASE(usb3_phy_1, USB3PHY_1_BASE)
>>  SAMSUNG_BASE(usb_ehci, USB_HOST_EHCI_BASE)
>>  SAMSUNG_BASE(usb_xhci, USB_HOST_XHCI_BASE)
>> +SAMSUNG_BASE(usb_xhci_1, USB_HOST_XHCI_1_BASE)
>>  SAMSUNG_BASE(usb_otg, USBOTG_BASE)
>>  SAMSUNG_BASE(watchdog, WATCHDOG_BASE)
>>  SAMSUNG_BASE(power, POWER_BASE)
>> diff --git a/arch/arm/include/asm/arch-exynos/power.h b/arch/arm/include/asm/arch-exynos/power.h
>> index c9609a2..c3f2ef0 100644
>> --- a/arch/arm/include/asm/arch-exynos/power.h
>> +++ b/arch/arm/include/asm/arch-exynos/power.h
>> @@ -1684,7 +1684,7 @@ void set_hw_thermal_trip(void);
>>  #define POWER_USB_HOST_PHY_CTRL_EN           (1 << 0)
>>  #define POWER_USB_HOST_PHY_CTRL_DISABLE              (0 << 0)
>>
>> -void set_usbdrd_phy_ctrl(unsigned int enable);
>> +void set_usbdrd_phy_ctrl(unsigned int enable, int dev_index);
>>
>>  #define POWER_USB_DRD_PHY_CTRL_EN            (1 << 0)
>>  #define POWER_USB_DRD_PHY_CTRL_DISABLE               (0 << 0)
>> diff --git a/drivers/usb/host/xhci-exynos5.c b/drivers/usb/host/xhci-exynos5.c
>> index 1146d10..b5fce40 100644
>> --- a/drivers/usb/host/xhci-exynos5.c
>> +++ b/drivers/usb/host/xhci-exynos5.c
>> @@ -43,18 +43,30 @@ struct exynos_xhci {
>>       struct fdt_gpio_state vbus_gpio;
>>  };
>>
>> -static struct exynos_xhci exynos;
>> +static struct exynos_xhci reg_bases[CONFIG_USB_MAX_CONTROLLER_COUNT];
>>
>>  #ifdef CONFIG_OF_CONTROL
>> -static int exynos_usb3_parse_dt(const void *blob, struct exynos_xhci *exynos)
>> +static int exynos_usb3_parse_dt(const void *blob,
>> +                             struct exynos_xhci *base,
>> +                             int index)
>>  {
>>       fdt_addr_t addr;
>> -     unsigned int node;
>> -     int depth;
>> +     int depth, count;
>> +     unsigned int node = 0;
>
> = 0; unnecessary.
Ok, will remove this.

>
>> +     int nodes[CONFIG_USB_MAX_CONTROLLER_COUNT];
>> +
>> +     /* First find all the compatible nodes */
>> +     count = fdtdec_find_aliases_for_id(blob, "xhci",
>> +                     COMPAT_SAMSUNG_EXYNOS5_XHCI, nodes,
>> +                     CONFIG_USB_MAX_CONTROLLER_COUNT);
>> +     if (count < 0) {
>> +             printf("XHCI: Can't get device node for xhci\n");
>> +             return -ENODEV;
>> +     }
>>
>> -     node = fdtdec_next_compatible(blob, 0, COMPAT_SAMSUNG_EXYNOS5_XHCI);
>> +     node = nodes[index];
>>       if (node <= 0) {
>> -             debug("XHCI: Can't get device node for xhci\n");
>> +             printf("XHCI: Can't get device node for xhci\n");
>>               return -ENODEV;
>>       }
>>
>> @@ -66,10 +78,10 @@ static int exynos_usb3_parse_dt(const void *blob, struct exynos_xhci *exynos)
>>               debug("Can't get the XHCI register base address\n");
>>               return -ENXIO;
>>       }
>> -     exynos->hcd = (struct xhci_hccr *)addr;
>> +     base->hcd = (struct xhci_hccr *)addr;
>>
>>       /* Vbus gpio */
>> -     fdtdec_decode_gpio(blob, node, "samsung,vbus-gpio", &exynos->vbus_gpio);
>> +     fdtdec_decode_gpio(blob, node, "samsung,vbus-gpio", &base->vbus_gpio);
>>
>>       depth = 0;
>>       node = fdtdec_next_compatible_subnode(blob, node,
>> @@ -82,9 +94,9 @@ static int exynos_usb3_parse_dt(const void *blob, struct exynos_xhci *exynos)
>>       /*
>>        * Get the base address for usbphy from the device node
>>        */
>> -     exynos->usb3_phy = (struct exynos_usb3_phy *)fdtdec_get_addr(blob, node,
>> +     base->usb3_phy = (struct exynos_usb3_phy *)fdtdec_get_addr(blob, node,
>>                                                               "reg");
>> -     if (exynos->usb3_phy == NULL) {
>> +     if (base->usb3_phy == NULL) {
>>               debug("Can't get the usbphy register address\n");
>>               return -ENXIO;
>>       }
>> @@ -97,9 +109,6 @@ static void exynos5_usb3_phy_init(struct exynos_usb3_phy *phy)
>>  {
>>       u32 reg;
>>
>> -     /* enabling usb_drd phy */
>> -     set_usbdrd_phy_ctrl(POWER_USB_DRD_PHY_CTRL_EN);
>> -
>>       /* Reset USB 3.0 PHY */
>>       writel(0x0, &phy->phy_reg0);
>>
>> @@ -176,9 +185,6 @@ static void exynos5_usb3_phy_exit(struct exynos_usb3_phy *phy)
>>       setbits_le32(&phy->phy_test,
>>                       PHYTEST_POWERDOWN_SSP |
>>                       PHYTEST_POWERDOWN_HSP);
>> -
>> -     /* disabling usb_drd phy */
>> -     set_usbdrd_phy_ctrl(POWER_USB_DRD_PHY_CTRL_DISABLE);
>>  }
>>
>>  void dwc3_set_mode(struct dwc3 *dwc3_reg, u32 mode)
>> @@ -259,41 +265,64 @@ static int dwc3_core_init(struct dwc3 *dwc3_reg)
>>       return 0;
>>  }
>>
>> -static int exynos_xhci_core_init(struct exynos_xhci *exynos)
>> +static int exynos_xhci_core_init(struct exynos_xhci *base)
>>  {
>>       int ret;
>>
>> -     exynos5_usb3_phy_init(exynos->usb3_phy);
>> +     exynos5_usb3_phy_init(base->usb3_phy);
>>
>> -     ret = dwc3_core_init(exynos->dwc3_reg);
>> +     ret = dwc3_core_init(base->dwc3_reg);
>>       if (ret) {
>>               debug("failed to initialize core\n");
>>               return -EINVAL;
>>       }
>>
>> -     /* We are hard-coding DWC3 core to Host Mode */
>> -     dwc3_set_mode(exynos->dwc3_reg, DWC3_GCTL_PRTCAP_HOST);
>> +     /*
>> +      * TODO: We are hard-coding DWC3 core to Host Mode;
>> +      * when we have complete DWC3 support we may want to
>> +      * have both device as well as host mode, so this will
>> +      * vanish off then.
>> +      */
>> +     dwc3_set_mode(base->dwc3_reg, DWC3_GCTL_PRTCAP_HOST);
>>
>>       return 0;
>>  }
>>
>> -static void exynos_xhci_core_exit(struct exynos_xhci *exynos)
>> +static void exynos_xhci_core_exit(struct exynos_xhci *base)
>>  {
>> -     exynos5_usb3_phy_exit(exynos->usb3_phy);
>> +     exynos5_usb3_phy_exit(base->usb3_phy);
>>  }
>>
>>  int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor)
>>  {
>> -     struct exynos_xhci *ctx = &exynos;
>> +     struct exynos_xhci *ctx = &reg_bases[index];
>>       int ret;
>>
>>  #ifdef CONFIG_OF_CONTROL
>> -     exynos_usb3_parse_dt(gd->fdt_blob, ctx);
>> +     exynos_usb3_parse_dt(gd->fdt_blob, ctx, index);
>>  #else
>> -     ctx->usb3_phy = (struct exynos_usb3_phy *)samsung_get_base_usb3_phy();
>> -     ctx->hcd = (struct xhci_hccr *)samsung_get_base_usb_xhci();
>> +     /*
>> +      * right now we only have h/w with 2 controllers, so limiting the
>> +      * index to two here: either 0 or 1.
>> +      */
>> +     if (index == 0) {
>> +             ctx->usb3_phy = (struct exynos_usb3_phy *)
>> +                                     samsung_get_base_usb3_phy();
>> +             ctx->hcd = (struct xhci_hccr *)
>> +                                     samsung_get_base_usb_xhci();
>> +     } else if (index == 1) {
>> +             ctx->usb3_phy = (struct exynos_usb3_phy *)
>> +                                     samsung_get_base_usb3_phy_1();
>> +             ctx->hcd = (struct xhci_hccr *)
>> +                                     samsung_get_base_usb_xhci_1();
>> +     }
>>  #endif
>>
>> +     if (!ctx->hcd || !ctx->usb3_phy) {
>> +             printf("XHCI: Unable to find Host controller\n");
>> +             return -ENODEV;
>> +     }
>> +
>>       ctx->dwc3_reg = (struct dwc3 *)((char *)(ctx->hcd) + DWC3_REG_OFFSET);
>>
>>  #ifdef CONFIG_OF_CONTROL
>> @@ -302,6 +331,9 @@ int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor)
>>               gpio_direction_output(ctx->vbus_gpio.gpio, 1);
>>  #endif
>>
>> +     /* Power-on usb_drd phy */
>> +     set_usbdrd_phy_ctrl(POWER_USB_DRD_PHY_CTRL_EN, index);
>> +
>>       ret = exynos_xhci_core_init(ctx);
>>       if (ret) {
>>               puts("XHCI: failed to initialize controller\n");
>> @@ -321,7 +353,10 @@ int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor)
>>
>>  void xhci_hcd_stop(int index)
>>  {
>> -     struct exynos_xhci *ctx = &exynos;
>> +     struct exynos_xhci *ctx = &reg_bases[index];
>>
>>       exynos_xhci_core_exit(ctx);
>> +
>> +     /* Power-off usb_drd phy */
>> +     set_usbdrd_phy_ctrl(POWER_USB_DRD_PHY_CTRL_DISABLE, index);
>>  }
>> diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
>> index d1c2e5c..24175e6 100644
>> --- a/drivers/usb/host/xhci.c
>> +++ b/drivers/usb/host/xhci.c
>> @@ -30,10 +30,6 @@
>>  #include <asm-generic/errno.h>
>>  #include "xhci.h"
>>
>> -#ifndef CONFIG_USB_MAX_CONTROLLER_COUNT
>> -#define CONFIG_USB_MAX_CONTROLLER_COUNT 1
>> -#endif
>> -
>>  static struct descriptor {
>>       struct usb_hub_descriptor hub;
>>       struct usb_device_descriptor device;
>> diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
>> index ceb1573..612bf79 100644
>> --- a/drivers/usb/host/xhci.h
>> +++ b/drivers/usb/host/xhci.h
>> @@ -21,6 +21,10 @@
>>  #include <asm/io.h>
>>  #include <linux/list.h>
>>
>> +#ifndef CONFIG_USB_MAX_CONTROLLER_COUNT
>> +#define CONFIG_USB_MAX_CONTROLLER_COUNT 1
>> +#endif
>> +
>>  #define upper_32_bits(n) (u32)((n) >> 32)
>>  #define lower_32_bits(n) (u32)(n)
>>
>>
>
> Thanks,
> Minkyu Kang.
Thanks for reviewing  :-)
Vivek Gautam Jan. 7, 2014, 9:48 a.m. UTC | #4
On Mon, Jan 6, 2014 at 9:21 PM, Marek Vasut <marex@denx.de> wrote:
> On Monday, January 06, 2014 at 10:29:40 AM, Vivek Gautam wrote:
>> Add required support to use multiple USB 3.0 controllers available
>> on exynos5420 SoC.
>>
>> Signed-off-by: Vivek Gautam <gautam.vivek@samsung.com>
>> ---
>>  arch/arm/cpu/armv7/exynos/power.c        |   18 ++++--
>>  arch/arm/include/asm/arch-exynos/cpu.h   |   10 ++++
>>  arch/arm/include/asm/arch-exynos/power.h |    2 +-
>>  drivers/usb/host/xhci-exynos5.c          |   91
>> +++++++++++++++++++++--------- drivers/usb/host/xhci.c                  |
>>   4 --
>>  drivers/usb/host/xhci.h                  |    4 ++
>>  6 files changed, 91 insertions(+), 38 deletions(-)
>>
>> diff --git a/arch/arm/cpu/armv7/exynos/power.c
>> b/arch/arm/cpu/armv7/exynos/power.c index 563abd7..0f8aa98 100644
>> --- a/arch/arm/cpu/armv7/exynos/power.c
>> +++ b/arch/arm/cpu/armv7/exynos/power.c
>> @@ -59,26 +59,34 @@ void set_usbhost_phy_ctrl(unsigned int enable)
>>               exynos5_set_usbhost_phy_ctrl(enable);
>>  }
>>
>> -static void exynos5_set_usbdrd_phy_ctrl(unsigned int enable)
>> +static void exynos5_set_usbdrd_phy_ctrl(unsigned int enable, int
>> dev_index) {
>>       struct exynos5_power *power =
>>               (struct exynos5_power *)samsung_get_base_power();
>>
>> +     /*
>> +      * Assuming here that the DRD_PHY_CONTROL registers
>> +      * are contiguous, so that :
>> +      * addressof(DRD_PHY1_CONTROL) = addressof(DRD_PHY_CONTROL) + 0x4;
>> +      * which is the case with exynos5420.
>> +      * For exynos5250 this should work out of box, since dev_index will
>> +      * always be '0' in that case
>> +      */
>
> Why don't you convert the entry for usbdrd_phy_control into an array in the
> 'struct exynos5_power' structure instead ? Then you could index it with
> dev_index.

Aah, i should have been more careful here. There's already a structure
available for exynos5420 "exynos5420_power",
which i can use. I just would need to use api "proid_is_exynos5420()"
or "proid_is_exynos5250()" to differentiate between
the two.

>
> [...]
>
> Do you think it'd be possible to split this patch into drivers/usb/ specific
> part and CPU-specific part ? I'd like to see that to prevent merge conflicts.

Ok, i'll separate out the two parts.

>
> [...]
>
> Best regards,
> Marek Vasut
> _______________________________________________
> U-Boot mailing list
> U-Boot@lists.denx.de
> http://lists.denx.de/mailman/listinfo/u-boot
Marek Vasut Jan. 7, 2014, 10:59 a.m. UTC | #5
On Tuesday, January 07, 2014 at 10:15:20 AM, Vivek Gautam wrote:

[...]

> >> diff --git a/arch/arm/include/asm/arch-exynos/cpu.h
> >> b/arch/arm/include/asm/arch-exynos/cpu.h index 718940b..d93cba9 100644
> >> --- a/arch/arm/include/asm/arch-exynos/cpu.h
> >> +++ b/arch/arm/include/asm/arch-exynos/cpu.h

[...]

> >> @@ -153,6 +159,8 @@
> >> 
> >>  #define EXYNOS5420_USBPHY_BASE               0x12130000
> >>  #define EXYNOS5420_MMC_BASE          0x12200000
> >>  #define EXYNOS5420_SROMC_BASE                0x12250000
> >> 
> >> +#define EXYNOS5420_USB_HOST_XHCI_1_BASE      0x12400000
> >> +#define EXYNOS5420_USB3PHY_1_BASE    0x12500000
> > 
> > No. we don't have to add phy_1 and xhci_1.
> > It looks weird.
> > please access phy1 and xhci1 by offset.
> 
> Ok, so you mean i should add offsets definitions for phy1 and xhci1
> may be in the driver file or in
> "arch/arm/include/asm/arch-exynos/xhci-exynos.h" file, and add these
> offsets to xhci_base and
> phy_base addresses ?
> That should be fine, i will modify this accordingly.
> 
> >>  #define EXYNOS5420_UART_BASE         0x12C00000
> >>  #define EXYNOS5420_I2C_BASE          0x12C60000
> >>  #define EXYNOS5420_I2C_8910_BASE     0x12E00000
> >> 
[...]

Minor rant, please trim the email when replying so it contains only the relevant 
parts. Otherwise, the irrelevant noise might cause some of the relevant replies 
to get lost.

Best regards,
Marek Vasut
Vivek Gautam Jan. 7, 2014, 11:41 a.m. UTC | #6
On Tue, Jan 7, 2014 at 4:29 PM, Marek Vasut <marex@denx.de> wrote:
> On Tuesday, January 07, 2014 at 10:15:20 AM, Vivek Gautam wrote:
>
> [...]
>
> Minor rant, please trim the email when replying so it contains only the relevant
> parts. Otherwise, the irrelevant noise might cause some of the relevant replies
> to get lost.

Sure, will keep that in mind.
diff mbox

Patch

diff --git a/arch/arm/cpu/armv7/exynos/power.c b/arch/arm/cpu/armv7/exynos/power.c
index 563abd7..0f8aa98 100644
--- a/arch/arm/cpu/armv7/exynos/power.c
+++ b/arch/arm/cpu/armv7/exynos/power.c
@@ -59,26 +59,34 @@  void set_usbhost_phy_ctrl(unsigned int enable)
 		exynos5_set_usbhost_phy_ctrl(enable);
 }
 
-static void exynos5_set_usbdrd_phy_ctrl(unsigned int enable)
+static void exynos5_set_usbdrd_phy_ctrl(unsigned int enable, int dev_index)
 {
 	struct exynos5_power *power =
 		(struct exynos5_power *)samsung_get_base_power();
 
+	/*
+	 * Assuming here that the DRD_PHY_CONTROL registers
+	 * are contiguous, so that :
+	 * addressof(DRD_PHY1_CONTROL) = addressof(DRD_PHY_CONTROL) + 0x4;
+	 * which is the case with exynos5420.
+	 * For exynos5250 this should work out of box, since dev_index will
+	 * always be '0' in that case
+	 */
 	if (enable) {
 		/* Enabling USBDRD_PHY */
-		setbits_le32(&power->usbdrd_phy_control,
+		setbits_le32(&power->usbdrd_phy_control + dev_index,
 				POWER_USB_DRD_PHY_CTRL_EN);
 	} else {
 		/* Disabling USBDRD_PHY */
-		clrbits_le32(&power->usbdrd_phy_control,
+		clrbits_le32(&power->usbdrd_phy_control + dev_index,
 				POWER_USB_DRD_PHY_CTRL_EN);
 	}
 }
 
-void set_usbdrd_phy_ctrl(unsigned int enable)
+void set_usbdrd_phy_ctrl(unsigned int enable, int dev_index)
 {
 	if (cpu_is_exynos5())
-		exynos5_set_usbdrd_phy_ctrl(enable);
+		exynos5_set_usbdrd_phy_ctrl(enable, dev_index);
 }
 
 static void exynos5_dp_phy_control(unsigned int enable)
diff --git a/arch/arm/include/asm/arch-exynos/cpu.h b/arch/arm/include/asm/arch-exynos/cpu.h
index 718940b..d93cba9 100644
--- a/arch/arm/include/asm/arch-exynos/cpu.h
+++ b/arch/arm/include/asm/arch-exynos/cpu.h
@@ -54,6 +54,8 @@ 
 #define EXYNOS4_USB_HOST_XHCI_BASE	DEVICE_NOT_AVAILABLE
 #define EXYNOS4_USB3PHY_BASE		DEVICE_NOT_AVAILABLE
 #define EXYNOS4_DMC_TZASC_BASE		DEVICE_NOT_AVAILABLE
+#define EXYNOS4_USB_HOST_XHCI_1_BASE	DEVICE_NOT_AVAILABLE
+#define EXYNOS4_USB3PHY_1_BASE		DEVICE_NOT_AVAILABLE
 
 /* EXYNOS4X12 */
 #define EXYNOS4X12_GPIO_PART3_BASE	0x03860000
@@ -93,6 +95,8 @@ 
 #define EXYNOS4X12_USB_HOST_XHCI_BASE	DEVICE_NOT_AVAILABLE
 #define EXYNOS4X12_USB3PHY_BASE		DEVICE_NOT_AVAILABLE
 #define EXYNOS4X12_DMC_TZASC_BASE	DEVICE_NOT_AVAILABLE
+#define EXYNOS4X12_USB_HOST_XHCI_1_BASE	DEVICE_NOT_AVAILABLE
+#define EXYNOS4X12_USB3PHY_1_BASE	DEVICE_NOT_AVAILABLE
 
 /* EXYNOS5 */
 #define EXYNOS5_I2C_SPACING		0x10000
@@ -132,6 +136,8 @@ 
 #define EXYNOS5_ADC_BASE		DEVICE_NOT_AVAILABLE
 #define EXYNOS5_MODEM_BASE		DEVICE_NOT_AVAILABLE
 #define EXYNOS5_DMC_TZASC_BASE		DEVICE_NOT_AVAILABLE
+#define EXYNOS5_USB_HOST_XHCI_1_BASE	DEVICE_NOT_AVAILABLE
+#define EXYNOS5_USB3PHY_1_BASE		DEVICE_NOT_AVAILABLE
 
 /* EXYNOS5420 */
 #define EXYNOS5420_AUDIOSS_BASE		0x03810000
@@ -153,6 +159,8 @@ 
 #define EXYNOS5420_USBPHY_BASE		0x12130000
 #define EXYNOS5420_MMC_BASE		0x12200000
 #define EXYNOS5420_SROMC_BASE		0x12250000
+#define EXYNOS5420_USB_HOST_XHCI_1_BASE	0x12400000
+#define EXYNOS5420_USB3PHY_1_BASE	0x12500000
 #define EXYNOS5420_UART_BASE		0x12C00000
 #define EXYNOS5420_I2C_BASE		0x12C60000
 #define EXYNOS5420_I2C_8910_BASE	0x12E00000
@@ -276,8 +284,10 @@  SAMSUNG_BASE(timer, PWMTIMER_BASE)
 SAMSUNG_BASE(uart, UART_BASE)
 SAMSUNG_BASE(usb_phy, USBPHY_BASE)
 SAMSUNG_BASE(usb3_phy, USB3PHY_BASE)
+SAMSUNG_BASE(usb3_phy_1, USB3PHY_1_BASE)
 SAMSUNG_BASE(usb_ehci, USB_HOST_EHCI_BASE)
 SAMSUNG_BASE(usb_xhci, USB_HOST_XHCI_BASE)
+SAMSUNG_BASE(usb_xhci_1, USB_HOST_XHCI_1_BASE)
 SAMSUNG_BASE(usb_otg, USBOTG_BASE)
 SAMSUNG_BASE(watchdog, WATCHDOG_BASE)
 SAMSUNG_BASE(power, POWER_BASE)
diff --git a/arch/arm/include/asm/arch-exynos/power.h b/arch/arm/include/asm/arch-exynos/power.h
index c9609a2..c3f2ef0 100644
--- a/arch/arm/include/asm/arch-exynos/power.h
+++ b/arch/arm/include/asm/arch-exynos/power.h
@@ -1684,7 +1684,7 @@  void set_hw_thermal_trip(void);
 #define POWER_USB_HOST_PHY_CTRL_EN		(1 << 0)
 #define POWER_USB_HOST_PHY_CTRL_DISABLE		(0 << 0)
 
-void set_usbdrd_phy_ctrl(unsigned int enable);
+void set_usbdrd_phy_ctrl(unsigned int enable, int dev_index);
 
 #define POWER_USB_DRD_PHY_CTRL_EN		(1 << 0)
 #define POWER_USB_DRD_PHY_CTRL_DISABLE		(0 << 0)
diff --git a/drivers/usb/host/xhci-exynos5.c b/drivers/usb/host/xhci-exynos5.c
index 1146d10..b5fce40 100644
--- a/drivers/usb/host/xhci-exynos5.c
+++ b/drivers/usb/host/xhci-exynos5.c
@@ -43,18 +43,30 @@  struct exynos_xhci {
 	struct fdt_gpio_state vbus_gpio;
 };
 
-static struct exynos_xhci exynos;
+static struct exynos_xhci reg_bases[CONFIG_USB_MAX_CONTROLLER_COUNT];
 
 #ifdef CONFIG_OF_CONTROL
-static int exynos_usb3_parse_dt(const void *blob, struct exynos_xhci *exynos)
+static int exynos_usb3_parse_dt(const void *blob,
+				struct exynos_xhci *base,
+				int index)
 {
 	fdt_addr_t addr;
-	unsigned int node;
-	int depth;
+	int depth, count;
+	unsigned int node = 0;
+	int nodes[CONFIG_USB_MAX_CONTROLLER_COUNT];
+
+	/* First find all the compatible nodes */
+	count = fdtdec_find_aliases_for_id(blob, "xhci",
+			COMPAT_SAMSUNG_EXYNOS5_XHCI, nodes,
+			CONFIG_USB_MAX_CONTROLLER_COUNT);
+	if (count < 0) {
+		printf("XHCI: Can't get device node for xhci\n");
+		return -ENODEV;
+	}
 
-	node = fdtdec_next_compatible(blob, 0, COMPAT_SAMSUNG_EXYNOS5_XHCI);
+	node = nodes[index];
 	if (node <= 0) {
-		debug("XHCI: Can't get device node for xhci\n");
+		printf("XHCI: Can't get device node for xhci\n");
 		return -ENODEV;
 	}
 
@@ -66,10 +78,10 @@  static int exynos_usb3_parse_dt(const void *blob, struct exynos_xhci *exynos)
 		debug("Can't get the XHCI register base address\n");
 		return -ENXIO;
 	}
-	exynos->hcd = (struct xhci_hccr *)addr;
+	base->hcd = (struct xhci_hccr *)addr;
 
 	/* Vbus gpio */
-	fdtdec_decode_gpio(blob, node, "samsung,vbus-gpio", &exynos->vbus_gpio);
+	fdtdec_decode_gpio(blob, node, "samsung,vbus-gpio", &base->vbus_gpio);
 
 	depth = 0;
 	node = fdtdec_next_compatible_subnode(blob, node,
@@ -82,9 +94,9 @@  static int exynos_usb3_parse_dt(const void *blob, struct exynos_xhci *exynos)
 	/*
 	 * Get the base address for usbphy from the device node
 	 */
-	exynos->usb3_phy = (struct exynos_usb3_phy *)fdtdec_get_addr(blob, node,
+	base->usb3_phy = (struct exynos_usb3_phy *)fdtdec_get_addr(blob, node,
 								"reg");
-	if (exynos->usb3_phy == NULL) {
+	if (base->usb3_phy == NULL) {
 		debug("Can't get the usbphy register address\n");
 		return -ENXIO;
 	}
@@ -97,9 +109,6 @@  static void exynos5_usb3_phy_init(struct exynos_usb3_phy *phy)
 {
 	u32 reg;
 
-	/* enabling usb_drd phy */
-	set_usbdrd_phy_ctrl(POWER_USB_DRD_PHY_CTRL_EN);
-
 	/* Reset USB 3.0 PHY */
 	writel(0x0, &phy->phy_reg0);
 
@@ -176,9 +185,6 @@  static void exynos5_usb3_phy_exit(struct exynos_usb3_phy *phy)
 	setbits_le32(&phy->phy_test,
 			PHYTEST_POWERDOWN_SSP |
 			PHYTEST_POWERDOWN_HSP);
-
-	/* disabling usb_drd phy */
-	set_usbdrd_phy_ctrl(POWER_USB_DRD_PHY_CTRL_DISABLE);
 }
 
 void dwc3_set_mode(struct dwc3 *dwc3_reg, u32 mode)
@@ -259,41 +265,64 @@  static int dwc3_core_init(struct dwc3 *dwc3_reg)
 	return 0;
 }
 
-static int exynos_xhci_core_init(struct exynos_xhci *exynos)
+static int exynos_xhci_core_init(struct exynos_xhci *base)
 {
 	int ret;
 
-	exynos5_usb3_phy_init(exynos->usb3_phy);
+	exynos5_usb3_phy_init(base->usb3_phy);
 
-	ret = dwc3_core_init(exynos->dwc3_reg);
+	ret = dwc3_core_init(base->dwc3_reg);
 	if (ret) {
 		debug("failed to initialize core\n");
 		return -EINVAL;
 	}
 
-	/* We are hard-coding DWC3 core to Host Mode */
-	dwc3_set_mode(exynos->dwc3_reg, DWC3_GCTL_PRTCAP_HOST);
+	/*
+	 * TODO: We are hard-coding DWC3 core to Host Mode;
+	 * when we have complete DWC3 support we may want to
+	 * have both device as well as host mode, so this will
+	 * vanish off then.
+	 */
+	dwc3_set_mode(base->dwc3_reg, DWC3_GCTL_PRTCAP_HOST);
 
 	return 0;
 }
 
-static void exynos_xhci_core_exit(struct exynos_xhci *exynos)
+static void exynos_xhci_core_exit(struct exynos_xhci *base)
 {
-	exynos5_usb3_phy_exit(exynos->usb3_phy);
+	exynos5_usb3_phy_exit(base->usb3_phy);
 }
 
 int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor)
 {
-	struct exynos_xhci *ctx = &exynos;
+	struct exynos_xhci *ctx = &reg_bases[index];
 	int ret;
 
 #ifdef CONFIG_OF_CONTROL
-	exynos_usb3_parse_dt(gd->fdt_blob, ctx);
+	exynos_usb3_parse_dt(gd->fdt_blob, ctx, index);
 #else
-	ctx->usb3_phy = (struct exynos_usb3_phy *)samsung_get_base_usb3_phy();
-	ctx->hcd = (struct xhci_hccr *)samsung_get_base_usb_xhci();
+	/*
+	 * right now we only have h/w with 2 controllers, so limiting the
+	 * index to two here: either 0 or 1.
+	 */
+	if (index == 0) {
+		ctx->usb3_phy = (struct exynos_usb3_phy *)
+					samsung_get_base_usb3_phy();
+		ctx->hcd = (struct xhci_hccr *)
+					samsung_get_base_usb_xhci();
+	} else if (index == 1) {
+		ctx->usb3_phy = (struct exynos_usb3_phy *)
+					samsung_get_base_usb3_phy_1();
+		ctx->hcd = (struct xhci_hccr *)
+					samsung_get_base_usb_xhci_1();
+	}
 #endif
 
+	if (!ctx->hcd || !ctx->usb3_phy) {
+		printf("XHCI: Unable to find Host controller\n");
+		return -ENODEV;
+	}
+
 	ctx->dwc3_reg = (struct dwc3 *)((char *)(ctx->hcd) + DWC3_REG_OFFSET);
 
 #ifdef CONFIG_OF_CONTROL
@@ -302,6 +331,9 @@  int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor)
 		gpio_direction_output(ctx->vbus_gpio.gpio, 1);
 #endif
 
+	/* Power-on usb_drd phy */
+	set_usbdrd_phy_ctrl(POWER_USB_DRD_PHY_CTRL_EN, index);
+
 	ret = exynos_xhci_core_init(ctx);
 	if (ret) {
 		puts("XHCI: failed to initialize controller\n");
@@ -321,7 +353,10 @@  int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor)
 
 void xhci_hcd_stop(int index)
 {
-	struct exynos_xhci *ctx = &exynos;
+	struct exynos_xhci *ctx = &reg_bases[index];
 
 	exynos_xhci_core_exit(ctx);
+
+	/* Power-off usb_drd phy */
+	set_usbdrd_phy_ctrl(POWER_USB_DRD_PHY_CTRL_DISABLE, index);
 }
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index d1c2e5c..24175e6 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -30,10 +30,6 @@ 
 #include <asm-generic/errno.h>
 #include "xhci.h"
 
-#ifndef CONFIG_USB_MAX_CONTROLLER_COUNT
-#define CONFIG_USB_MAX_CONTROLLER_COUNT 1
-#endif
-
 static struct descriptor {
 	struct usb_hub_descriptor hub;
 	struct usb_device_descriptor device;
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index ceb1573..612bf79 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -21,6 +21,10 @@ 
 #include <asm/io.h>
 #include <linux/list.h>
 
+#ifndef CONFIG_USB_MAX_CONTROLLER_COUNT
+#define CONFIG_USB_MAX_CONTROLLER_COUNT 1
+#endif
+
 #define upper_32_bits(n) (u32)((n) >> 32)
 #define lower_32_bits(n) (u32)(n)