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

Vivek Gautam gautamvivek1987 at gmail.com
Tue Jan 7 10:15:20 CET 2014


Hi Minkyu Kang,


On Tue, Jan 7, 2014 at 11:00 AM, Minkyu Kang <mk7.kang at 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 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.

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  :-)



-- 
Best Regards
Vivek Gautam
Samsung R&D Institute, Bangalore
India


More information about the U-Boot mailing list