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