blob: ee70b81d882a85279ec6787de3d71c59ef6d8298 [file] [log] [blame]
Marek Vasut66425882018-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>
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
46struct rcar_gen2_phy {
47 fdt_addr_t regs;
48 struct clk clk;
49};
50
51static 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
72static 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
96static 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
110static 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
139static 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
146static 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
167static 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
177static const struct udevice_id rcar_gen2_phy_of_match[] = {
178 { .compatible = "renesas,rcar-gen2-usb-phy", },
179 { },
180};
181
182U_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};