Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/arm64/rockchip/rk_usbphy.c
39478 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2019 Michal Meloun <[email protected]>
5
*
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
8
* are met:
9
* 1. Redistributions of source code must retain the above copyright
10
* notice, this list of conditions and the following disclaimer.
11
* 2. Redistributions in binary form must reproduce the above copyright
12
* notice, this list of conditions and the following disclaimer in the
13
* documentation and/or other materials provided with the distribution.
14
*
15
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25
* SUCH DAMAGE.
26
*/
27
28
#include <sys/param.h>
29
#include <sys/systm.h>
30
#include <sys/bus.h>
31
#include <sys/gpio.h>
32
#include <sys/kernel.h>
33
#include <sys/module.h>
34
#include <sys/malloc.h>
35
#include <sys/rman.h>
36
37
#include <machine/bus.h>
38
39
#include <dev/clk/clk.h>
40
#include <dev/hwreset/hwreset.h>
41
#include <dev/phy/phy_usb.h>
42
#include <dev/regulator/regulator.h>
43
#include <dev/syscon/syscon.h>
44
#include <dev/ofw/ofw_bus.h>
45
#include <dev/ofw/ofw_bus_subr.h>
46
47
#include <dev/syscon/syscon.h>
48
#include <dev/fdt/simple_mfd.h>
49
#include "phynode_if.h"
50
#include "phynode_usb_if.h"
51
#include "syscon_if.h"
52
53
54
55
/* Phy registers */
56
#define UOC_CON0 0x00
57
#define UOC_CON0_SIDDQ (1 << 13)
58
#define UOC_CON0_DISABLE (1 << 4)
59
#define UOC_CON0_COMMON_ON_N (1 << 0)
60
61
#define UOC_CON2 0x08
62
#define UOC_CON2_SOFT_CON_SEL (1 << 2)
63
64
#define UOC_CON3 0x0c
65
66
67
#define WR4(_sc, _r, _v) bus_write_4((_sc)->mem_res, (_r), (_v))
68
#define RD4(_sc, _r) bus_read_4((_sc)->mem_res, (_r))
69
70
71
static struct ofw_compat_data compat_data[] = {
72
{"rockchip,rk3288-usb-phy", 1},
73
{NULL, 0},
74
};
75
76
struct rk_usbphy_softc {
77
device_t dev;
78
};
79
80
struct rk_phynode_sc {
81
struct phynode_usb_sc usb_sc;
82
uint32_t base;
83
int mode;
84
clk_t clk;
85
hwreset_t hwreset;
86
regulator_t supply_vbus;
87
struct syscon *syscon;
88
};
89
90
static int
91
rk_phynode_phy_enable(struct phynode *phy, bool enable)
92
{
93
struct rk_phynode_sc *sc;
94
int rv;
95
96
sc = phynode_get_softc(phy);
97
98
rv = SYSCON_MODIFY_4(sc->syscon,
99
sc->base + UOC_CON0,
100
UOC_CON0_SIDDQ << 16 | UOC_CON0_SIDDQ,
101
enable ? 0 : UOC_CON0_SIDDQ);
102
103
return (rv);
104
105
}
106
107
static int
108
rk_phynode_get_mode(struct phynode *phynode, int *mode)
109
{
110
struct rk_phynode_sc *sc;
111
112
sc = phynode_get_softc(phynode);
113
*mode = sc->mode;
114
return (0);
115
}
116
117
static int
118
rk_phynode_set_mode(struct phynode *phynode, int mode)
119
{
120
struct rk_phynode_sc *sc;
121
122
sc = phynode_get_softc(phynode);
123
sc->mode = mode;
124
125
return (0);
126
}
127
128
129
/* Phy controller class and methods. */
130
static phynode_method_t rk_phynode_methods[] = {
131
PHYNODEUSBMETHOD(phynode_enable, rk_phynode_phy_enable),
132
PHYNODEMETHOD(phynode_usb_get_mode, rk_phynode_get_mode),
133
PHYNODEMETHOD(phynode_usb_set_mode, rk_phynode_set_mode),
134
PHYNODEUSBMETHOD_END
135
};
136
DEFINE_CLASS_1(rk_phynode, rk_phynode_class, rk_phynode_methods,
137
sizeof(struct rk_phynode_sc), phynode_usb_class);
138
139
static int
140
rk_usbphy_init_phy(struct rk_usbphy_softc *sc, phandle_t node)
141
{
142
struct phynode *phynode;
143
struct phynode_init_def phy_init;
144
struct rk_phynode_sc *phy_sc;
145
int rv;
146
uint32_t base;
147
clk_t clk;
148
hwreset_t hwreset;
149
regulator_t supply_vbus;
150
struct syscon *syscon;
151
152
clk = NULL;
153
hwreset = NULL;
154
supply_vbus = NULL;
155
156
rv = OF_getencprop(node, "reg", &base, sizeof(base));
157
if (rv <= 0) {
158
device_printf(sc->dev, "cannot get 'reg' property.\n");
159
goto fail;
160
}
161
162
/* FDT resources. All are optional. */
163
rv = clk_get_by_ofw_name(sc->dev, node, "phyclk", &clk);
164
if (rv != 0 && rv != ENOENT) {
165
device_printf(sc->dev, "cannot get 'phyclk' clock.\n");
166
goto fail;
167
}
168
rv = hwreset_get_by_ofw_name(sc->dev, node, "phy-reset", &hwreset);
169
if (rv != 0 && rv != ENOENT) {
170
device_printf(sc->dev, "Cannot get 'phy-reset' reset\n");
171
goto fail;
172
}
173
rv = regulator_get_by_ofw_property(sc->dev, node, "vbus-supply",
174
&supply_vbus);
175
if (rv != 0 && rv != ENOENT) {
176
device_printf(sc->dev, "Cannot get 'vbus' regulator.\n");
177
goto fail;
178
}
179
180
rv = SYSCON_GET_HANDLE(sc->dev, &syscon);
181
if (rv != 0) {
182
device_printf(sc->dev, "Cannot get parent syscon\n");
183
goto fail;
184
}
185
186
/* Init HW resources */
187
if (hwreset != NULL) {
188
rv = hwreset_assert(hwreset);
189
if (rv != 0) {
190
device_printf(sc->dev, "Cannot assert reset\n");
191
goto fail;
192
}
193
}
194
if (clk != NULL) {
195
rv = clk_enable(clk);
196
if (rv != 0) {
197
device_printf(sc->dev,
198
"Cannot enable 'phyclk' clock.\n");
199
goto fail;
200
}
201
}
202
203
if (hwreset != NULL) {
204
rv = hwreset_deassert(hwreset);
205
if (rv != 0) {
206
device_printf(sc->dev, "Cannot deassert reset\n");
207
goto fail;
208
}
209
}
210
211
/* Create and register phy. */
212
bzero(&phy_init, sizeof(phy_init));
213
phy_init.id = 1;
214
phy_init.ofw_node = node;
215
phynode = phynode_create(sc->dev, &rk_phynode_class, &phy_init);
216
if (phynode == NULL) {
217
device_printf(sc->dev, "Cannot create phy.\n");
218
return (ENXIO);
219
}
220
221
phy_sc = phynode_get_softc(phynode);
222
phy_sc->base = base;
223
phy_sc->clk = clk;
224
phy_sc->hwreset = hwreset;
225
phy_sc->supply_vbus = supply_vbus;
226
phy_sc->syscon = syscon;
227
if (phynode_register(phynode) == NULL) {
228
device_printf(sc->dev, "Cannot register phy.\n");
229
return (ENXIO);
230
}
231
/* XXX It breaks boot */
232
/* rk_phynode_phy_enable(phynode, 1); */
233
return (0);
234
235
fail:
236
if (supply_vbus != NULL)
237
regulator_release(supply_vbus);
238
if (clk != NULL)
239
clk_release(clk);
240
if (hwreset != NULL)
241
hwreset_release(hwreset);
242
243
return (ENXIO);
244
}
245
246
static int
247
rk_usbphy_probe(device_t dev)
248
{
249
250
if (!ofw_bus_status_okay(dev))
251
return (ENXIO);
252
253
if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
254
return (ENXIO);
255
256
device_set_desc(dev, "RockChip USB Phy");
257
return (BUS_PROBE_DEFAULT);
258
}
259
260
static int
261
rk_usbphy_attach(device_t dev)
262
{
263
struct rk_usbphy_softc *sc;
264
phandle_t node, child;
265
int rv;
266
267
sc = device_get_softc(dev);
268
sc->dev = dev;
269
node = ofw_bus_get_node(sc->dev);
270
271
/* Attach child devices */
272
for (child = OF_child(node); child > 0; child = OF_peer(child)) {
273
rv = rk_usbphy_init_phy(sc, child);
274
if (rv != 0)
275
goto fail;
276
}
277
bus_attach_children(dev);
278
return (0);
279
280
fail:
281
return (ENXIO);
282
}
283
284
static int
285
rk_usbphy_detach(device_t dev)
286
{
287
return (0);
288
}
289
290
static device_method_t rk_usbphy_methods[] = {
291
/* Device interface */
292
DEVMETHOD(device_probe, rk_usbphy_probe),
293
DEVMETHOD(device_attach, rk_usbphy_attach),
294
DEVMETHOD(device_detach, rk_usbphy_detach),
295
DEVMETHOD_END
296
};
297
298
static DEFINE_CLASS_0(rk_usbphy, rk_usbphy_driver, rk_usbphy_methods,
299
sizeof(struct rk_usbphy_softc));
300
EARLY_DRIVER_MODULE(rk_usbphy, simplebus, rk_usbphy_driver, NULL, NULL,
301
BUS_PASS_TIMER + BUS_PASS_ORDER_LAST);
302
303