mbox series

[v2,00/15] usb: Add host and device support for RZ/A2

Message ID 20190509201142.10543-1-chris.brandt@renesas.com
Headers show
Series usb: Add host and device support for RZ/A2 | expand

Message

Chris Brandt May 9, 2019, 8:11 p.m. UTC
For the most part, the RZ/A2 has the same USB 2.0 host and device
HW as the R-Car Gen3, so we can reuse a lot of the code.

However, there are a couple extra register bits, and the CFIFO
register 8-bit access works a little different..

There is a dedicated DMAC for the RZ/A2 USB Device HW, but we
have not been able to reliably get that working yet, so device
operation is pio only at the moment.

On the RZ/A2M eval board, both USB channels can be used as either
host or device. But, it's not set up for otg (ie, there are jumpers
and separate connectors). Therefore, below is an example of what it
would look like to enable USB channel 0 as a device instead of a host.

&usb2_phy0 {
	pinctrl-names = "default";
	pinctrl-0 = <&usb0_pins>;
	dr_mode = "peripheral";
	status = "okay";
};

&usbhs0 {
	status = "okay";
};






Chris Brandt (15):
  ARM: dts: r7s9210: Add USB clock
  ARM: dts: rza2mevb: Add 48MHz USB clock
  phy: renesas: rcar-gen3-usb2: detect usb_x1 clock
  dt-bindings: rcar-gen3-phy-usb2: Document use of usb_x1
  phy: renesas: rcar-gen3-usb2: Check dr_mode when not using OTG
  dt-bindings: rcar-gen3-phy-usb2: Document dr_mode
  dt-bindings: rcar-gen3-phy-usb2: Add r7s9210 support
  usb: renesas_usbhs: move flags macros
  usb: renesas_usbhs: add support for CNEN bit
  usb: renesas_usbhs: support byte addressable CFIFO
  usb: renesas_usbhs: Add support for RZ/A2
  dt-bindings: usb: renesas_usbhs: Add support for r7s9210
  ARM: dts: r7s9210: Add USB Host support
  ARM: dts: r7s9210: Add USB Device support
  ARM: dts: rza2mevb: Add USB host support

 .../devicetree/bindings/phy/rcar-gen3-phy-usb2.txt | 17 ++--
 .../devicetree/bindings/usb/renesas_usbhs.txt      |  2 +
 arch/arm/boot/dts/r7s9210-rza2mevb.dts             | 42 ++++++++++
 arch/arm/boot/dts/r7s9210.dtsi                     | 95 ++++++++++++++++++++++
 drivers/phy/renesas/phy-rcar-gen3-usb2.c           | 22 +++++
 drivers/usb/renesas_usbhs/Makefile                 |  2 +-
 drivers/usb/renesas_usbhs/common.c                 | 25 ++++--
 drivers/usb/renesas_usbhs/common.h                 | 13 +++
 drivers/usb/renesas_usbhs/fifo.c                   |  9 +-
 drivers/usb/renesas_usbhs/rza.h                    |  1 +
 drivers/usb/renesas_usbhs/rza2.c                   | 79 ++++++++++++++++++
 include/linux/usb/renesas_usbhs.h                  |  1 +
 12 files changed, 292 insertions(+), 16 deletions(-)
 create mode 100644 drivers/usb/renesas_usbhs/rza2.c

Comments

Chunfeng Yun (云春峰) May 10, 2019, 1:53 a.m. UTC | #1
On Thu, 2019-05-09 at 15:11 -0500, Chris Brandt wrote:
> The RZ/A2 is similar to the R-Car Gen3 with some small differences.
> 
> Signed-off-by: Chris Brandt <chris.brandt@renesas.com>
> ---
> v2:
>  * combined RZA1 and RZA2 for fifo setting
>  * added braces to make code easier to read
>  * fixed and clean up usbhs_rza2_power_ctrl()
> ---
>  drivers/usb/renesas_usbhs/Makefile |  2 +-
>  drivers/usb/renesas_usbhs/common.c | 12 +++++-
>  drivers/usb/renesas_usbhs/rza.h    |  1 +
>  drivers/usb/renesas_usbhs/rza2.c   | 79 ++++++++++++++++++++++++++++++++++++++
>  include/linux/usb/renesas_usbhs.h  |  1 +
>  5 files changed, 93 insertions(+), 2 deletions(-)
>  create mode 100644 drivers/usb/renesas_usbhs/rza2.c
> 
> diff --git a/drivers/usb/renesas_usbhs/Makefile b/drivers/usb/renesas_usbhs/Makefile
> index 5c5b51bb48ef..a1fed56b0957 100644
> --- a/drivers/usb/renesas_usbhs/Makefile
> +++ b/drivers/usb/renesas_usbhs/Makefile
> @@ -5,7 +5,7 @@
>  
>  obj-$(CONFIG_USB_RENESAS_USBHS)	+= renesas_usbhs.o
>  
> -renesas_usbhs-y			:= common.o mod.o pipe.o fifo.o rcar2.o rcar3.o rza.o
> +renesas_usbhs-y			:= common.o mod.o pipe.o fifo.o rcar2.o rcar3.o rza.o rza2.o
>  
>  ifneq ($(CONFIG_USB_RENESAS_USBHS_HCD),)
>  	renesas_usbhs-y		+= mod_host.o
> diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c
> index 820636fc4dc9..35d2298c03a0 100644
> --- a/drivers/usb/renesas_usbhs/common.c
> +++ b/drivers/usb/renesas_usbhs/common.c
> @@ -582,6 +582,10 @@ static const struct of_device_id usbhs_of_match[] = {
>  		.compatible = "renesas,rza1-usbhs",
>  		.data = (void *)USBHS_TYPE_RZA1,
>  	},
> +	{
> +		.compatible = "renesas,rza2-usbhs",
> +		.data = (void *)USBHS_TYPE_RZA2,
> +	},
>  	{ },
>  };
>  MODULE_DEVICE_TABLE(of, usbhs_of_match);
> @@ -614,7 +618,8 @@ static struct renesas_usbhs_platform_info *usbhs_parse_dt(struct device *dev)
>  		dparam->pipe_size = ARRAY_SIZE(usbhsc_new_pipe);
>  	}
>  
> -	if (dparam->type == USBHS_TYPE_RZA1) {
> +	if (dparam->type == USBHS_TYPE_RZA1 ||
> +	    dparam->type == USBHS_TYPE_RZA2) {
>  		dparam->pipe_configs = usbhsc_new_pipe;
>  		dparam->pipe_size = ARRAY_SIZE(usbhsc_new_pipe);
>  	}
> @@ -688,6 +693,11 @@ static int usbhs_probe(struct platform_device *pdev)
>  	case USBHS_TYPE_RZA1:
>  		priv->pfunc = usbhs_rza1_ops;
>  		break;
> +	case USBHS_TYPE_RZA2:
> +		priv->pfunc = usbhs_rza2_ops;
> +		usbhsc_flags_set(priv, USBHSF_HAS_CNEN);
> +		usbhsc_flags_set(priv, USBHSF_CFIFO_BYTE_ADDR);
> +		break;
>  	default:
>  		if (!info->platform_callback.get_id) {
>  			dev_err(&pdev->dev, "no platform callbacks");
> diff --git a/drivers/usb/renesas_usbhs/rza.h b/drivers/usb/renesas_usbhs/rza.h
> index ca917ca54f6d..073a53d1d442 100644
> --- a/drivers/usb/renesas_usbhs/rza.h
> +++ b/drivers/usb/renesas_usbhs/rza.h
> @@ -2,3 +2,4 @@
>  #include "common.h"
>  
>  extern const struct renesas_usbhs_platform_callback usbhs_rza1_ops;
> +extern const struct renesas_usbhs_platform_callback usbhs_rza2_ops;
> diff --git a/drivers/usb/renesas_usbhs/rza2.c b/drivers/usb/renesas_usbhs/rza2.c
> new file mode 100644
> index 000000000000..a1d9eb2d40cf
> --- /dev/null
> +++ b/drivers/usb/renesas_usbhs/rza2.c
> @@ -0,0 +1,79 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Renesas USB driver RZ/A2 initialization and power control
> + *
> + * Copyright (C) 2019 Chris Brandt
> + * Copyright (C) 2019 Renesas Electronics Corporation
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/io.h>
> +#include <linux/of_device.h>
> +#include <linux/phy/phy.h>
> +#include "common.h"
> +#include "rza.h"
> +
> +
> +static int usbhs_rza2_hardware_init(struct platform_device *pdev)
> +{
> +	struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
> +
> +	if (IS_ENABLED(CONFIG_GENERIC_PHY)) {
no need check it, if it's not enabled, phy_get() will return an error
number.

> +		struct phy *phy = phy_get(&pdev->dev, "usb");
use devm_phy_get??
> +
> +		if (IS_ERR(phy))
> +			return PTR_ERR(phy);
> +
> +		priv->phy = phy;
> +		return 0;
> +	}
> +	return -ENXIO;
> +}
> +
> +static int usbhs_rza2_hardware_exit(struct platform_device *pdev)
> +{
> +	struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
> +
> +	if (priv->phy) {
> +		phy_put(priv->phy);
> +		priv->phy = NULL;
> +	}
> +
> +	return 0;
> +}
> +
> +static int usbhs_rza2_power_ctrl(struct platform_device *pdev,
> +				void __iomem *base, int enable)
> +{
> +	struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
> +	int retval = 0;
> +
> +	if (!priv->phy)
> +		return -ENODEV;
> +
> +	if (enable) {
> +		retval = phy_init(priv->phy);
> +		usbhs_bset(priv, SUSPMODE, SUSPM, SUSPM);
> +		udelay(100);	/* Wait for PLL to become stable */
> +		if (!retval)
> +			retval = phy_power_on(priv->phy);
> +	} else {
> +		usbhs_bset(priv, SUSPMODE, SUSPM, 0);
> +		phy_power_off(priv->phy);
> +		phy_exit(priv->phy);
> +	}
> +
> +	return retval;
> +}
> +
> +static int usbhs_rza2_get_id(struct platform_device *pdev)
> +{
> +	return USBHS_GADGET;
> +}
> +
> +const struct renesas_usbhs_platform_callback usbhs_rza2_ops = {
> +	.hardware_init = usbhs_rza2_hardware_init,
> +	.hardware_exit = usbhs_rza2_hardware_exit,
> +	.power_ctrl = usbhs_rza2_power_ctrl,
> +	.get_id = usbhs_rza2_get_id,
> +};
> diff --git a/include/linux/usb/renesas_usbhs.h b/include/linux/usb/renesas_usbhs.h
> index 53924f8e840c..39604c8b1eed 100644
> --- a/include/linux/usb/renesas_usbhs.h
> +++ b/include/linux/usb/renesas_usbhs.h
> @@ -196,6 +196,7 @@ struct renesas_usbhs_driver_param {
>  #define USBHS_TYPE_RCAR_GEN3		2
>  #define USBHS_TYPE_RCAR_GEN3_WITH_PLL	3
>  #define USBHS_TYPE_RZA1			4
> +#define USBHS_TYPE_RZA2			5
>  
>  /*
>   * option:
Chunfeng Yun (云春峰) May 10, 2019, 1:57 a.m. UTC | #2
On Thu, 2019-05-09 at 15:11 -0500, Chris Brandt wrote:
> The RZ/A2 has an optional dedicated 48MHz clock input for the PLL.
> If a clock node named 'usb_x1' exists and set to non-zero, then we can
> assume we want it use it.
> 
> Signed-off-by: Chris Brandt <chris.brandt@renesas.com>
> ---
> v2:
>  * use 'usb_x1' clock node instead of 'renesas,uses_usb_x1' property
> ---
>  drivers/phy/renesas/phy-rcar-gen3-usb2.c | 14 ++++++++++++++
>  1 file changed, 14 insertions(+)
> 
> diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c
> index 1322185a00a2..1ebb08f8323f 100644
> --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c
> +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c
> @@ -34,6 +34,7 @@
>  #define USB2_VBCTRL		0x60c
>  #define USB2_LINECTRL1		0x610
>  #define USB2_ADPCTRL		0x630
> +#define USB2_PHYCLK_CTRL	0x644
>  
>  /* INT_ENABLE */
>  #define USB2_INT_ENABLE_UCOM_INTEN	BIT(3)
> @@ -110,6 +111,7 @@ struct rcar_gen3_chan {
>  	bool extcon_host;
>  	bool is_otg_channel;
>  	bool uses_otg_pins;
> +	bool uses_usb_x1;
>  };
>  
>  /*
> @@ -391,6 +393,9 @@ static int rcar_gen3_phy_usb2_init(struct phy *p)
>  	void __iomem *usb2_base = channel->base;
>  	u32 val;
>  
> +	if (channel->uses_usb_x1)
> +		writel(0x00000001, usb2_base + USB2_PHYCLK_CTRL);
                         ^^^^ avoid magic number?
> +
>  	/* Initialize USB2 part */
>  	val = readl(usb2_base + USB2_INT_ENABLE);
>  	val |= USB2_INT_ENABLE_UCOM_INTEN | rphy->int_enable_bits;
> @@ -582,10 +587,12 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
>  {
>  	struct device *dev = &pdev->dev;
>  	struct rcar_gen3_chan *channel;
> +	struct device_node *usb_x1_clk;
>  	struct phy_provider *provider;
>  	struct resource *res;
>  	const struct phy_ops *phy_usb2_ops;
>  	int irq, ret = 0, i;
> +	u32 freq_usb = 0;
>  
>  	if (!dev->of_node) {
>  		dev_err(dev, "This driver needs device tree\n");
> @@ -630,6 +637,13 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
>  		}
>  	}
>  
> +	usb_x1_clk = of_find_node_by_name(NULL, "usb_x1");
> +	if (usb_x1_clk) {
> +		of_property_read_u32(usb_x1_clk, "clock-frequency", &freq_usb);
> +		if (freq_usb)
> +			channel->uses_usb_x1 = true;
> +	}
> +
>  	/*
>  	 * devm_phy_create() will call pm_runtime_enable(&phy->dev);
>  	 * And then, phy-core will manage runtime pm for this device.
Chunfeng Yun (云春峰) May 10, 2019, 1:59 a.m. UTC | #3
On Thu, 2019-05-09 at 15:11 -0500, Chris Brandt wrote:
> Move flags macros to header file so they can be used by other files.
> 
> Signed-off-by: Chris Brandt <chris.brandt@renesas.com>
> ---
>  drivers/usb/renesas_usbhs/common.c |  7 -------
>  drivers/usb/renesas_usbhs/common.h | 10 ++++++++++
>  2 files changed, 10 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c
> index 249fbee97f3f..efb26ffd9809 100644
> --- a/drivers/usb/renesas_usbhs/common.c
> +++ b/drivers/usb/renesas_usbhs/common.c
> @@ -44,13 +44,6 @@
>   */
>  
> 
> -#define USBHSF_RUNTIME_PWCTRL	(1 << 0)
> -
> -/* status */
> -#define usbhsc_flags_init(p)   do {(p)->flags = 0; } while (0)
> -#define usbhsc_flags_set(p, b) ((p)->flags |=  (b))
> -#define usbhsc_flags_clr(p, b) ((p)->flags &= ~(b))
> -#define usbhsc_flags_has(p, b) ((p)->flags &   (b))
>  
>  /*
>   * platform call back
> diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h
> index 3777af848a35..1ca94b8f5508 100644
> --- a/drivers/usb/renesas_usbhs/common.h
> +++ b/drivers/usb/renesas_usbhs/common.h
> @@ -339,4 +339,14 @@ struct usbhs_priv *usbhs_pdev_to_priv(struct platform_device *pdev);
>  #define usbhs_priv_to_dev(priv)		(&priv->pdev->dev)
>  #define usbhs_priv_to_lock(priv)	(&priv->lock)
>  
> +/*
> + * flags
> + */
> +#define USBHSF_RUNTIME_PWCTRL	(1 << 0)
BIT(0)?
> +
> +#define usbhsc_flags_init(p)   ((p)->flags = 0)
> +#define usbhsc_flags_set(p, b) ((p)->flags |=  (b))
> +#define usbhsc_flags_clr(p, b) ((p)->flags &= ~(b))
> +#define usbhsc_flags_has(p, b) ((p)->flags &   (b))
> +
>  #endif /* RENESAS_USB_DRIVER_H */
Chris Brandt May 10, 2019, 1:10 p.m. UTC | #4
On Thu, May 09, 2019, Chunfeng Yun wrote:
> > +	if (IS_ENABLED(CONFIG_GENERIC_PHY)) {
> no need check it, if it's not enabled, phy_get() will return an error
> number.

Good point.
Thank you.

Chris
Chris Brandt May 10, 2019, 1:17 p.m. UTC | #5
On Thu, May 09, 2019, Chunfeng Yun wrote:
> > +	if (channel->uses_usb_x1)
> > +		writel(0x00000001, usb2_base + USB2_PHYCLK_CTRL);
>                          ^^^^ avoid magic number?

OK.

Chris