Re: [PATCH v6 1/1] usb: host: xhci-plat: add support for the R-Car H2 and M2 xHCI controllers

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




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.uh@xxxxxxxxxxx>
>> ---
>>  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 devicetree" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]
  Powered by Linux