From 5e50adf6679831bc34a567a1bf20ff1642c418dd Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Tue, 7 Aug 2018 12:24:35 +0200 Subject: [PATCH 1/3] phy: Fix off-by-one error when parsing DT PHY bindings The code fails to copy the last PHY phandle argument, so it is missing from the adjusted phandle args and the consumer cannot use it to determine what the PHY should do. Signed-off-by: Marek Vasut Cc: Patrice Chotard --- drivers/phy/phy-uclass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/phy-uclass.c b/drivers/phy/phy-uclass.c index 6162395..a0ac30a 100644 --- a/drivers/phy/phy-uclass.c +++ b/drivers/phy/phy-uclass.c @@ -64,7 +64,7 @@ int generic_phy_get_by_index(struct udevice *dev, int index, return ret; /* insert phy idx at first position into args array */ - for (i = args.args_count; i > 1 ; i--) + for (i = args.args_count; i >= 1 ; i--) args.args[i] = args.args[i - 1]; args.args_count++; From 664258887ded6cb3a3e4414dd1d4ea34abc0a7d7 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 5 Aug 2018 15:22:19 +0200 Subject: [PATCH 2/3] phy: rcar: Add R-Car Gen2 PHY driver Add a PHY driver for the R-Car Gen2 which allows configuring the mux connected to the EHCI controllers and USBHS controller. Signed-off-by: Marek Vasut Cc: Nobuhiro Iwamatsu --- drivers/phy/Kconfig | 8 ++ drivers/phy/Makefile | 1 + drivers/phy/phy-rcar-gen2.c | 190 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 199 insertions(+) create mode 100644 drivers/phy/phy-rcar-gen2.c diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 8fc2295..e0822bb 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -110,6 +110,14 @@ config STI_USB_PHY used by USB2 and USB3 Host controllers available on STiH407 SoC families. +config PHY_RCAR_GEN2 + tristate "Renesas R-Car Gen2 USB PHY" + depends on PHY && RCAR_GEN2 + help + Support for the Renesas R-Car Gen2 USB PHY. This driver operates the + PHY connected to USBHS module, PCI EHCI module and USB3.0 module and + allows configuring the module multiplexing. + config PHY_STM32_USBPHYC tristate "STMicroelectronics STM32 SoC USB HS PHY driver" depends on PHY && ARCH_STM32MP diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index ba0803c..178fb45 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -12,5 +12,6 @@ obj-$(CONFIG_BCM6368_USBH_PHY) += bcm6368-usbh-phy.o obj-$(CONFIG_PHY_SANDBOX) += sandbox-phy.o obj-$(CONFIG_$(SPL_)PIPE3_PHY) += ti-pipe3-phy.o obj-$(CONFIG_STI_USB_PHY) += sti_usb_phy.o +obj-$(CONFIG_PHY_RCAR_GEN2) += phy-rcar-gen2.o obj-$(CONFIG_PHY_STM32_USBPHYC) += phy-stm32-usbphyc.o obj-$(CONFIG_MESON_GXL_USB_PHY) += meson-gxl-usb2.o meson-gxl-usb3.o diff --git a/drivers/phy/phy-rcar-gen2.c b/drivers/phy/phy-rcar-gen2.c new file mode 100644 index 0000000..ee70b81 --- /dev/null +++ b/drivers/phy/phy-rcar-gen2.c @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas RCar Gen2 USB PHY driver + * + * Copyright (C) 2018 Marek Vasut + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define USBHS_LPSTS 0x02 +#define USBHS_UGCTRL 0x80 +#define USBHS_UGCTRL2 0x84 +#define USBHS_UGSTS 0x88 /* From technical update */ + +/* Low Power Status register (LPSTS) */ +#define USBHS_LPSTS_SUSPM 0x4000 + +/* USB General control register (UGCTRL) */ +#define USBHS_UGCTRL_CONNECT BIT(2) +#define USBHS_UGCTRL_PLLRESET BIT(0) + +/* USB General control register 2 (UGCTRL2) */ +#define USBHS_UGCTRL2_USB2SEL 0x80000000 +#define USBHS_UGCTRL2_USB2SEL_PCI 0x00000000 +#define USBHS_UGCTRL2_USB2SEL_USB30 0x80000000 +#define USBHS_UGCTRL2_USB0SEL 0x00000030 +#define USBHS_UGCTRL2_USB0SEL_PCI 0x00000010 +#define USBHS_UGCTRL2_USB0SEL_HS_USB 0x00000030 + +/* USB General status register (UGSTS) */ +#define USBHS_UGSTS_LOCK 0x00000100 /* From technical update */ + +#define PHYS_PER_CHANNEL 2 + +struct rcar_gen2_phy { + fdt_addr_t regs; + struct clk clk; +}; + +static int rcar_gen2_phy_phy_init(struct phy *phy) +{ + struct rcar_gen2_phy *priv = dev_get_priv(phy->dev); + u16 chan = phy->id & 0xffff; + u16 mode = (phy->id >> 16) & 0xffff; + u32 clrmask, setmask; + + if (chan == 0) { + clrmask = USBHS_UGCTRL2_USB0SEL; + setmask = mode ? USBHS_UGCTRL2_USB0SEL_HS_USB : + USBHS_UGCTRL2_USB0SEL_PCI; + } else { + clrmask = USBHS_UGCTRL2_USB2SEL; + setmask = mode ? USBHS_UGCTRL2_USB2SEL_USB30 : + USBHS_UGCTRL2_USB2SEL_PCI; + } + clrsetbits_le32(priv->regs + USBHS_UGCTRL2, clrmask, setmask); + + return 0; +} + +static int rcar_gen2_phy_phy_power_on(struct phy *phy) +{ + struct rcar_gen2_phy *priv = dev_get_priv(phy->dev); + int i; + u32 value; + + /* Power on USBHS PHY */ + clrbits_le32(priv->regs + USBHS_UGCTRL, USBHS_UGCTRL_PLLRESET); + + setbits_le16(priv->regs + USBHS_LPSTS, USBHS_LPSTS_SUSPM); + + for (i = 0; i < 20; i++) { + value = readl(priv->regs + USBHS_UGSTS); + if ((value & USBHS_UGSTS_LOCK) == USBHS_UGSTS_LOCK) { + setbits_le32(priv->regs + USBHS_UGCTRL, + USBHS_UGCTRL_CONNECT); + return 0; + } + udelay(1); + } + + return -ETIMEDOUT; +} + +static int rcar_gen2_phy_phy_power_off(struct phy *phy) +{ + struct rcar_gen2_phy *priv = dev_get_priv(phy->dev); + + /* Power off USBHS PHY */ + clrbits_le32(priv->regs + USBHS_UGCTRL, USBHS_UGCTRL_CONNECT); + + clrbits_le16(priv->regs + USBHS_LPSTS, USBHS_LPSTS_SUSPM); + + setbits_le32(priv->regs + USBHS_UGCTRL, USBHS_UGCTRL_PLLRESET); + + return 0; +} + +static int rcar_gen2_phy_of_xlate(struct phy *phy, + struct ofnode_phandle_args *args) +{ + if (args->args_count != 2) { + dev_err(phy->dev, "Invalid DT PHY argument count: %d\n", + args->args_count); + return -EINVAL; + } + + if (args->args[0] != 0 && args->args[0] != 2) { + dev_err(phy->dev, "Invalid DT PHY channel: %d\n", + args->args[0]); + return -EINVAL; + } + + if (args->args[1] != 0 && args->args[1] != 1) { + dev_err(phy->dev, "Invalid DT PHY mode: %d\n", + args->args[1]); + return -EINVAL; + } + + if (args->args_count) + phy->id = args->args[0] | (args->args[1] << 16); + else + phy->id = 0; + + return 0; +} + +static const struct phy_ops rcar_gen2_phy_phy_ops = { + .init = rcar_gen2_phy_phy_init, + .power_on = rcar_gen2_phy_phy_power_on, + .power_off = rcar_gen2_phy_phy_power_off, + .of_xlate = rcar_gen2_phy_of_xlate, +}; + +static int rcar_gen2_phy_probe(struct udevice *dev) +{ + struct rcar_gen2_phy *priv = dev_get_priv(dev); + int ret; + + priv->regs = dev_read_addr(dev); + if (priv->regs == FDT_ADDR_T_NONE) + return -EINVAL; + + /* Enable clock */ + ret = clk_get_by_index(dev, 0, &priv->clk); + if (ret) + return ret; + + ret = clk_enable(&priv->clk); + if (ret) + return ret; + + return 0; +} + +static int rcar_gen2_phy_remove(struct udevice *dev) +{ + struct rcar_gen2_phy *priv = dev_get_priv(dev); + + clk_disable(&priv->clk); + clk_free(&priv->clk); + + return 0; +} + +static const struct udevice_id rcar_gen2_phy_of_match[] = { + { .compatible = "renesas,rcar-gen2-usb-phy", }, + { }, +}; + +U_BOOT_DRIVER(rcar_gen2_phy) = { + .name = "rcar-gen2-phy", + .id = UCLASS_PHY, + .of_match = rcar_gen2_phy_of_match, + .ops = &rcar_gen2_phy_phy_ops, + .probe = rcar_gen2_phy_probe, + .remove = rcar_gen2_phy_remove, + .priv_auto_alloc_size = sizeof(struct rcar_gen2_phy), +}; From 4f10989280bb91f0981ffe2ffabe936bb2a92364 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 8 Aug 2018 15:06:03 +0200 Subject: [PATCH 3/3] ARM: rmobile: Enable USB PHY on Gen2 Enable support for USB PHY on the R-Car Gen2. This allows for both of the USB host ports to be used on such boards. Signed-off-by: Marek Vasut Cc: Nobuhiro Iwamatsu --- arch/arm/mach-rmobile/Kconfig.32 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/mach-rmobile/Kconfig.32 b/arch/arm/mach-rmobile/Kconfig.32 index bdca9bb..076a019 100644 --- a/arch/arm/mach-rmobile/Kconfig.32 +++ b/arch/arm/mach-rmobile/Kconfig.32 @@ -6,6 +6,8 @@ config ARCH_RMOBILE_BOARD_STRING config RCAR_GEN2 bool "Renesas RCar Gen2" + select PHY + select PHY_RCAR_GEN2 config R8A7740 bool "Renesas SoC R8A7740"