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

Minkyu Kang mk7.kang at samsung.com
Tue Jan 7 06:30:49 CET 2014


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 at 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.


More information about the U-Boot mailing list