Hi,

(2014/06/13 23:25), Felipe Balbi wrote:
> Hi,
> 
> On Fri, Jun 13, 2014 at 09:20:31PM +0900, Yoshihiro Shimoda wrote:
>> The R-Car H2 and M2 SoCs come with an xHCI controller that requires
>> some specific initializations related to the firmware downloading and
>> some specific registers. This patch adds the support for this special
>> configuration as an xHCI quirk executed during probe and start.
>>
>> Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda...@renesas.com>
>> ---
>>  drivers/usb/host/Kconfig     |    8 +++
>>  drivers/usb/host/Makefile    |    3 +
>>  drivers/usb/host/xhci-plat.c |   19 ++++++
>>  drivers/usb/host/xhci-rcar.c |  148 
>> ++++++++++++++++++++++++++++++++++++++++++
>>  drivers/usb/host/xhci-rcar.h |   27 ++++++++
>>  5 files changed, 205 insertions(+)
>>  create mode 100644 drivers/usb/host/xhci-rcar.c
>>  create mode 100644 drivers/usb/host/xhci-rcar.h
>>
>> diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
>> index 61b7817..537d9e1 100644
>> --- a/drivers/usb/host/Kconfig
>> +++ b/drivers/usb/host/Kconfig
>> @@ -37,6 +37,14 @@ config USB_XHCI_MVEBU
>>        Say 'Y' to enable the support for the xHCI host controller
>>        found in Marvell Armada 375/38x ARM SOCs.
>>
>> +config USB_XHCI_RCAR
>> +    tristate "xHCI support for Renesas R-Car SoCs"
>> +    select USB_XHCI_PLATFORM
>> +    depends on ARCH_SHMOBILE || COMPILE_TEST
>> +    ---help---
>> +      Say 'Y' to enable the support for the xHCI host controller
>> +      found in Renesas R-Car ARM SoCs.
>> +
>>  endif # USB_XHCI_HCD
>>
>>  config USB_EHCI_HCD
>> diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
>> index af89a90..144c038 100644
>> --- a/drivers/usb/host/Makefile
>> +++ b/drivers/usb/host/Makefile
>> @@ -22,6 +22,9 @@ ifneq ($(CONFIG_USB_XHCI_PLATFORM), )
>>  ifneq ($(CONFIG_USB_XHCI_MVEBU), )
>>      xhci-hcd-y              += xhci-mvebu.o
>>  endif
>> +ifneq ($(CONFIG_USB_XHCI_RCAR), )
>> +    xhci-hcd-y              += xhci-rcar.o
>> +endif
>>  endif
>>
>>  obj-$(CONFIG_USB_WHCI_HCD)  += whci/
>> diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
>> index 29d8adb..b6f2b6b 100644
>> --- a/drivers/usb/host/xhci-plat.c
>> +++ b/drivers/usb/host/xhci-plat.c
>> @@ -20,6 +20,7 @@
>>
>>  #include "xhci.h"
>>  #include "xhci-mvebu.h"
>> +#include "xhci-rcar.h"
>>
>>  static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci)
>>  {
>> @@ -34,11 +35,27 @@ static void xhci_plat_quirks(struct device *dev, struct 
>> xhci_hcd *xhci)
>>  /* called during probe() after chip reset completes */
>>  static int xhci_plat_setup(struct usb_hcd *hcd)
>>  {
>> +    struct device_node *of_node = hcd->self.controller->of_node;
>> +    int ret;
>> +
>> +    if (of_device_is_compatible(of_node, "renesas,xhci-r8a7790") ||
>> +        of_device_is_compatible(of_node, "renesas,xhci-r8a7791")) {
>> +            ret = xhci_rcar_init_quirk(hcd);
>> +            if (ret)
>> +                    return ret;
>> +    }
>> +
>>      return xhci_gen_setup(hcd, xhci_plat_quirks);
>>  }
>>
>>  static int xhci_plat_start(struct usb_hcd *hcd)
>>  {
>> +    struct device_node *of_node = hcd->self.controller->of_node;
>> +
>> +    if (of_device_is_compatible(of_node, "renesas,xhci-r8a7790") ||
>> +        of_device_is_compatible(of_node, "renesas,xhci-r8a7791"))
>> +            xhci_rcar_start(hcd);
>> +
>>      return xhci_run(hcd);
>>  }
>>
>> @@ -270,6 +287,8 @@ static const struct of_device_id usb_xhci_of_match[] = {
>>      { .compatible = "xhci-platform" },
>>      { .compatible = "marvell,armada-375-xhci"},
>>      { .compatible = "marvell,armada-380-xhci"},
>> +    { .compatible = "renesas,xhci-r8a7790"},
>> +    { .compatible = "renesas,xhci-r8a7791"},
>>      { },
>>  };
>>  MODULE_DEVICE_TABLE(of, usb_xhci_of_match);
>> diff --git a/drivers/usb/host/xhci-rcar.c b/drivers/usb/host/xhci-rcar.c
>> new file mode 100644
>> index 0000000..ff0d1b4
>> --- /dev/null
>> +++ b/drivers/usb/host/xhci-rcar.c
>> @@ -0,0 +1,148 @@
>> +/*
>> + * xHCI host controller driver for R-Car SoCs
>> + *
>> + * Copyright (C) 2014 Renesas Electronics Corporation
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License
>> + * version 2 as published by the Free Software Foundation.
>> + */
>> +
>> +#include <linux/firmware.h>
>> +#include <linux/module.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/usb/phy.h>
>> +
>> +#include "xhci.h"
>> +#include "xhci-rcar.h"
>> +
>> +#define FIRMWARE_NAME               "r8a779x_usb3_v1.dlmem"
>> +MODULE_FIRMWARE(FIRMWARE_NAME);
>> +
>> +/*** Register Offset ***/
>> +#define RCAR_USB3_INT_ENA   0x224   /* Interrupt Enable */
>> +#define RCAR_USB3_DL_CTRL   0x250   /* FW Download Control & Status */
>> +#define RCAR_USB3_FW_DATA0  0x258   /* FW Data0 */
>> +
>> +#define RCAR_USB3_LCLK              0xa44   /* LCLK Select */
>> +#define RCAR_USB3_CONF1             0xa48   /* USB3.0 Configuration1 */
>> +#define RCAR_USB3_CONF2             0xa5c   /* USB3.0 Configuration2 */
>> +#define RCAR_USB3_CONF3             0xaa8   /* USB3.0 Configuration3 */
>> +#define RCAR_USB3_RX_POL    0xab0   /* USB3.0 RX Polarity */
>> +#define RCAR_USB3_TX_POL    0xab8   /* USB3.0 TX Polarity */
>> +
>> +/*** Register Settings ***/
>> +/* Interrupt Enable */
>> +#define RCAR_USB3_INT_XHC_ENA       0x00000001
>> +#define RCAR_USB3_INT_PME_ENA       0x00000002
>> +#define RCAR_USB3_INT_HSE_ENA       0x00000004
>> +#define RCAR_USB3_INT_ENA_VAL       (RCAR_USB3_INT_XHC_ENA | \
>> +                            RCAR_USB3_INT_PME_ENA | RCAR_USB3_INT_HSE_ENA)
>> +
>> +/* FW Download Control & Status */
>> +#define RCAR_USB3_DL_CTRL_ENABLE    0x00000001
>> +#define RCAR_USB3_DL_CTRL_FW_SUCCESS        0x00000010
>> +#define RCAR_USB3_DL_CTRL_FW_SET_DATA0      0x00000100
>> +
>> +/* LCLK Select */
>> +#define RCAR_USB3_LCLK_ENA_VAL      0x01030001
>> +
>> +/* USB3.0 Configuration */
>> +#define RCAR_USB3_CONF1_VAL 0x00030204
>> +#define RCAR_USB3_CONF2_VAL 0x00030300
>> +#define RCAR_USB3_CONF3_VAL 0x13802007
>> +
>> +/* USB3.0 Polarity */
>> +#define RCAR_USB3_RX_POL_VAL        BIT(21)
>> +#define RCAR_USB3_TX_POL_VAL        BIT(4)
>> +
>> +void xhci_rcar_start(struct usb_hcd *hcd)
>> +{
>> +    u32 temp;
>> +
>> +    if (hcd->regs != NULL) {
>> +            /* Interrupt Enable */
>> +            temp = readl(hcd->regs + RCAR_USB3_INT_ENA);
>> +            temp |= RCAR_USB3_INT_ENA_VAL;
>> +            writel(temp, hcd->regs + RCAR_USB3_INT_ENA);
>> +            /* LCLK Select */
>> +            writel(RCAR_USB3_LCLK_ENA_VAL, hcd->regs + RCAR_USB3_LCLK);
>> +            /* USB3.0 Configuration */
>> +            writel(RCAR_USB3_CONF1_VAL, hcd->regs + RCAR_USB3_CONF1);
>> +            writel(RCAR_USB3_CONF2_VAL, hcd->regs + RCAR_USB3_CONF2);
>> +            writel(RCAR_USB3_CONF3_VAL, hcd->regs + RCAR_USB3_CONF3);
>> +            /* USB3.0 Polarity */
>> +            writel(RCAR_USB3_RX_POL_VAL, hcd->regs + RCAR_USB3_RX_POL);
>> +            writel(RCAR_USB3_TX_POL_VAL, hcd->regs + RCAR_USB3_TX_POL);
>> +    }
>> +}
>> +
>> +static int xhci_rcar_download_firmware(struct device *dev, void __iomem 
>> *regs)
>> +{
>> +    const struct firmware *fw;
>> +    int retval, index, j, time;
>> +    int timeout = 10000;
>> +    u32 data, val, temp;
>> +
>> +    /* request R-Car USB3.0 firmware */
>> +    retval = request_firmware(&fw, FIRMWARE_NAME, dev);
>> +    if (retval)
>> +            return retval;
>> +
>> +    /* download R-Car USB3.0 firmware */
>> +    temp = readl(regs + RCAR_USB3_DL_CTRL);
>> +    temp |= RCAR_USB3_DL_CTRL_ENABLE;
>> +    writel(temp, regs + RCAR_USB3_DL_CTRL);
>> +
>> +    for (index = 0; index < fw->size; index += 4) {
>> +            /* to avoid reading beyond the end of the buffer */
>> +            for (data = 0, j = 3; j >= 0; j--) {
>> +                    if ((j + index) < fw->size)
>> +                            data |= fw->data[index + j] << (8 * j);
>> +            }
>> +            writel(data, regs + RCAR_USB3_FW_DATA0);
>> +            temp = readl(regs + RCAR_USB3_DL_CTRL);
>> +            temp |= RCAR_USB3_DL_CTRL_FW_SET_DATA0;
>> +            writel(temp, regs + RCAR_USB3_DL_CTRL);
>> +
>> +            for (time = 0; time < timeout; time++) {
>> +                    val = readl(regs + RCAR_USB3_DL_CTRL);
>> +                    if ((val & RCAR_USB3_DL_CTRL_FW_SET_DATA0) == 0)
>> +                            break;
>> +                    udelay(1);
>> +            }
>> +            if (time == timeout) {
>> +                    retval = -ETIMEDOUT;
>> +                    break;
>> +            }
>> +    }
>> +
>> +    temp = readl(regs + RCAR_USB3_DL_CTRL);
>> +    temp &= ~RCAR_USB3_DL_CTRL_ENABLE;
>> +    writel(temp, regs + RCAR_USB3_DL_CTRL);
>> +
>> +    for (time = 0; time < timeout; time++) {
>> +            val = readl(regs + RCAR_USB3_DL_CTRL);
>> +            if (val & RCAR_USB3_DL_CTRL_FW_SUCCESS) {
>> +                    retval = 0;
>> +                    break;
>> +            }
>> +            udelay(1);
>> +    }
>> +    if (time == timeout)
>> +            retval = -ETIMEDOUT;
>> +
>> +    release_firmware(fw);
>> +
>> +    return retval;
>> +}
>> +
>> +/* This function needs to initialize a "phy" of usb before */
> 
> initializing a PHY looks like something that the PHY layer should do.
> Why don't you write a PHY driver and teach xhci-core about PHYs ? Then,
> more people would benefit.

Sergei wrote a PHY driver for the controller, but it is not merged yet.
http://marc.info/?l=linux-sh&m=140088276126653&w=2

According to the manual, it just said:
"The USB3.0 host controller shall download FW via AXI to operate as a Host".
So, I don't think this is an initializing a PHY.
However, if I don't initialize a "phy" by the driver, I could not read/write
all of the USB 3.0 controller registers. (So, I added the comment.)

Should I move this function to the PHY driver?

Best regards,
Yoshihiro Shimoda

> cheers
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to