1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Renesas RCar Gen2 USB PHY driver 4 * 5 * Copyright (C) 2018 Marek Vasut <marek.vasut@gmail.com> 6 */ 7 8 #include <common.h> 9 #include <clk.h> 10 #include <div64.h> 11 #include <dm.h> 12 #include <fdtdec.h> 13 #include <generic-phy.h> 14 #include <reset.h> 15 #include <syscon.h> 16 #include <usb.h> 17 #include <asm/io.h> 18 #include <linux/bitops.h> 19 #include <power/regulator.h> 20 21 #define USBHS_LPSTS 0x02 22 #define USBHS_UGCTRL 0x80 23 #define USBHS_UGCTRL2 0x84 24 #define USBHS_UGSTS 0x88 /* From technical update */ 25 26 /* Low Power Status register (LPSTS) */ 27 #define USBHS_LPSTS_SUSPM 0x4000 28 29 /* USB General control register (UGCTRL) */ 30 #define USBHS_UGCTRL_CONNECT BIT(2) 31 #define USBHS_UGCTRL_PLLRESET BIT(0) 32 33 /* USB General control register 2 (UGCTRL2) */ 34 #define USBHS_UGCTRL2_USB2SEL 0x80000000 35 #define USBHS_UGCTRL2_USB2SEL_PCI 0x00000000 36 #define USBHS_UGCTRL2_USB2SEL_USB30 0x80000000 37 #define USBHS_UGCTRL2_USB0SEL 0x00000030 38 #define USBHS_UGCTRL2_USB0SEL_PCI 0x00000010 39 #define USBHS_UGCTRL2_USB0SEL_HS_USB 0x00000030 40 41 /* USB General status register (UGSTS) */ 42 #define USBHS_UGSTS_LOCK 0x00000100 /* From technical update */ 43 44 #define PHYS_PER_CHANNEL 2 45 46 struct rcar_gen2_phy { 47 fdt_addr_t regs; 48 struct clk clk; 49 }; 50 51 static int rcar_gen2_phy_phy_init(struct phy *phy) 52 { 53 struct rcar_gen2_phy *priv = dev_get_priv(phy->dev); 54 u16 chan = phy->id & 0xffff; 55 u16 mode = (phy->id >> 16) & 0xffff; 56 u32 clrmask, setmask; 57 58 if (chan == 0) { 59 clrmask = USBHS_UGCTRL2_USB0SEL; 60 setmask = mode ? USBHS_UGCTRL2_USB0SEL_HS_USB : 61 USBHS_UGCTRL2_USB0SEL_PCI; 62 } else { 63 clrmask = USBHS_UGCTRL2_USB2SEL; 64 setmask = mode ? USBHS_UGCTRL2_USB2SEL_USB30 : 65 USBHS_UGCTRL2_USB2SEL_PCI; 66 } 67 clrsetbits_le32(priv->regs + USBHS_UGCTRL2, clrmask, setmask); 68 69 return 0; 70 } 71 72 static int rcar_gen2_phy_phy_power_on(struct phy *phy) 73 { 74 struct rcar_gen2_phy *priv = dev_get_priv(phy->dev); 75 int i; 76 u32 value; 77 78 /* Power on USBHS PHY */ 79 clrbits_le32(priv->regs + USBHS_UGCTRL, USBHS_UGCTRL_PLLRESET); 80 81 setbits_le16(priv->regs + USBHS_LPSTS, USBHS_LPSTS_SUSPM); 82 83 for (i = 0; i < 20; i++) { 84 value = readl(priv->regs + USBHS_UGSTS); 85 if ((value & USBHS_UGSTS_LOCK) == USBHS_UGSTS_LOCK) { 86 setbits_le32(priv->regs + USBHS_UGCTRL, 87 USBHS_UGCTRL_CONNECT); 88 return 0; 89 } 90 udelay(1); 91 } 92 93 return -ETIMEDOUT; 94 } 95 96 static int rcar_gen2_phy_phy_power_off(struct phy *phy) 97 { 98 struct rcar_gen2_phy *priv = dev_get_priv(phy->dev); 99 100 /* Power off USBHS PHY */ 101 clrbits_le32(priv->regs + USBHS_UGCTRL, USBHS_UGCTRL_CONNECT); 102 103 clrbits_le16(priv->regs + USBHS_LPSTS, USBHS_LPSTS_SUSPM); 104 105 setbits_le32(priv->regs + USBHS_UGCTRL, USBHS_UGCTRL_PLLRESET); 106 107 return 0; 108 } 109 110 static int rcar_gen2_phy_of_xlate(struct phy *phy, 111 struct ofnode_phandle_args *args) 112 { 113 if (args->args_count != 2) { 114 dev_err(phy->dev, "Invalid DT PHY argument count: %d\n", 115 args->args_count); 116 return -EINVAL; 117 } 118 119 if (args->args[0] != 0 && args->args[0] != 2) { 120 dev_err(phy->dev, "Invalid DT PHY channel: %d\n", 121 args->args[0]); 122 return -EINVAL; 123 } 124 125 if (args->args[1] != 0 && args->args[1] != 1) { 126 dev_err(phy->dev, "Invalid DT PHY mode: %d\n", 127 args->args[1]); 128 return -EINVAL; 129 } 130 131 if (args->args_count) 132 phy->id = args->args[0] | (args->args[1] << 16); 133 else 134 phy->id = 0; 135 136 return 0; 137 } 138 139 static const struct phy_ops rcar_gen2_phy_phy_ops = { 140 .init = rcar_gen2_phy_phy_init, 141 .power_on = rcar_gen2_phy_phy_power_on, 142 .power_off = rcar_gen2_phy_phy_power_off, 143 .of_xlate = rcar_gen2_phy_of_xlate, 144 }; 145 146 static int rcar_gen2_phy_probe(struct udevice *dev) 147 { 148 struct rcar_gen2_phy *priv = dev_get_priv(dev); 149 int ret; 150 151 priv->regs = dev_read_addr(dev); 152 if (priv->regs == FDT_ADDR_T_NONE) 153 return -EINVAL; 154 155 /* Enable clock */ 156 ret = clk_get_by_index(dev, 0, &priv->clk); 157 if (ret) 158 return ret; 159 160 ret = clk_enable(&priv->clk); 161 if (ret) 162 return ret; 163 164 return 0; 165 } 166 167 static int rcar_gen2_phy_remove(struct udevice *dev) 168 { 169 struct rcar_gen2_phy *priv = dev_get_priv(dev); 170 171 clk_disable(&priv->clk); 172 clk_free(&priv->clk); 173 174 return 0; 175 } 176 177 static const struct udevice_id rcar_gen2_phy_of_match[] = { 178 { .compatible = "renesas,rcar-gen2-usb-phy", }, 179 { }, 180 }; 181 182 U_BOOT_DRIVER(rcar_gen2_phy) = { 183 .name = "rcar-gen2-phy", 184 .id = UCLASS_PHY, 185 .of_match = rcar_gen2_phy_of_match, 186 .ops = &rcar_gen2_phy_phy_ops, 187 .probe = rcar_gen2_phy_probe, 188 .remove = rcar_gen2_phy_remove, 189 .priv_auto_alloc_size = sizeof(struct rcar_gen2_phy), 190 }; 191