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