rk_usb.c revision 1.1 1 /* $NetBSD: rk_usb.c,v 1.1 2018/06/16 00:19:04 jmcneill Exp $ */
2
3 /*-
4 * Copyright (c) 2018 Jared McNeill <jmcneill (at) invisible.ca>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
30
31 __KERNEL_RCSID(0, "$NetBSD: rk_usb.c,v 1.1 2018/06/16 00:19:04 jmcneill Exp $");
32
33 #include <sys/param.h>
34 #include <sys/bus.h>
35 #include <sys/device.h>
36 #include <sys/intr.h>
37 #include <sys/systm.h>
38 #include <sys/time.h>
39 #include <sys/kmem.h>
40
41 #include <dev/clk/clk_backend.h>
42
43 #include <dev/fdt/fdtvar.h>
44
45 static int rk_usb_match(device_t, cfdata_t, void *);
46 static void rk_usb_attach(device_t, device_t, void *);
47
48 #define CON0_REG 0x00
49 #define CON1_REG 0x04
50 #define CON2_REG 0x08
51 #define USBPHY_COMMONONN __BIT(4)
52
53 enum rk_usb_type {
54 USB_RK3328 = 1,
55 };
56
57 static const struct of_compat_data compat_data[] = {
58 { "rockchip,rk3328-usb2phy", USB_RK3328 },
59 { NULL }
60 };
61
62 struct rk_usb_clk {
63 struct clk base;
64 bus_size_t reg;
65 };
66
67 struct rk_usb_softc {
68 device_t sc_dev;
69 bus_space_tag_t sc_bst;
70 bus_space_handle_t sc_bsh;
71 enum rk_usb_type sc_type;
72
73 struct clk_domain sc_clkdom;
74 struct rk_usb_clk sc_usbclk;
75 };
76
77 #define USB_READ(sc, reg) \
78 bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
79 #define USB_WRITE(sc, reg, val) \
80 bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
81
82 CFATTACH_DECL_NEW(rk_usb, sizeof(struct rk_usb_softc),
83 rk_usb_match, rk_usb_attach, NULL, NULL);
84
85 static struct clk *
86 rk_usb_clk_get(void *priv, const char *name)
87 {
88 struct rk_usb_softc * const sc = priv;
89
90 if (strcmp(name, sc->sc_usbclk.base.name) != 0)
91 return NULL;
92
93 return &sc->sc_usbclk.base;
94 }
95
96 static void
97 rk_usb_clk_put(void *priv, struct clk *clk)
98 {
99 }
100
101 static u_int
102 rk_usb_clk_get_rate(void *priv, struct clk *clk)
103 {
104 return 480000000;
105 }
106
107 static int
108 rk_usb_clk_enable(void *priv, struct clk *clk)
109 {
110 struct rk_usb_softc * const sc = priv;
111
112 const uint32_t write_mask = USBPHY_COMMONONN << 16;
113 const uint32_t write_val = 0;
114 USB_WRITE(sc, CON2_REG, write_mask | write_val);
115
116 return 0;
117 }
118
119 static int
120 rk_usb_clk_disable(void *priv, struct clk *clk)
121 {
122 struct rk_usb_softc * const sc = priv;
123
124 const uint32_t write_mask = USBPHY_COMMONONN << 16;
125 const uint32_t write_val = USBPHY_COMMONONN;
126 USB_WRITE(sc, CON2_REG, write_mask | write_val);
127
128 return 0;
129 }
130
131 static const struct clk_funcs rk_usb_clk_funcs = {
132 .get = rk_usb_clk_get,
133 .put = rk_usb_clk_put,
134 .get_rate = rk_usb_clk_get_rate,
135 .enable = rk_usb_clk_enable,
136 .disable = rk_usb_clk_disable,
137 };
138
139 static struct clk *
140 rk_usb_fdt_decode(device_t dev, const void *data, size_t len)
141 {
142 struct rk_usb_softc * const sc = device_private(dev);
143
144 if (len != 0)
145 return NULL;
146
147 return &sc->sc_usbclk.base;
148 }
149
150 static const struct fdtbus_clock_controller_func rk_usb_fdt_funcs = {
151 .decode = rk_usb_fdt_decode
152 };
153
154 static int
155 rk_usb_match(device_t parent, cfdata_t cf, void *aux)
156 {
157 struct fdt_attach_args * const faa = aux;
158
159 return of_match_compat_data(faa->faa_phandle, compat_data);
160 }
161
162 static void
163 rk_usb_attach(device_t parent, device_t self, void *aux)
164 {
165 struct rk_usb_softc * const sc = device_private(self);
166 struct fdt_attach_args * const faa = aux;
167 const int phandle = faa->faa_phandle;
168 bus_addr_t grf_addr, phy_addr, phy_size;
169 int child;
170
171 sc->sc_dev = self;
172 sc->sc_bst = faa->faa_bst;
173 sc->sc_type = of_search_compatible(phandle, compat_data)->data;
174
175 if (fdtbus_get_reg(OF_parent(phandle), 0, &grf_addr, NULL) != 0) {
176 aprint_error(": couldn't get grf registers\n");
177 }
178 if (fdtbus_get_reg(phandle, 0, &phy_addr, &phy_size) != 0) {
179 aprint_error(": couldn't get phy registers\n");
180 return;
181 }
182 if (bus_space_map(sc->sc_bst, grf_addr + phy_addr, phy_size, 0, &sc->sc_bsh) != 0) {
183 aprint_error(": couldn't map phy registers\n");
184 return;
185 }
186
187 const char *clkname = fdtbus_get_string(phandle, "clock-output-names");
188 if (clkname == NULL)
189 clkname = faa->faa_name;
190
191 sc->sc_clkdom.name = device_xname(self);
192 sc->sc_clkdom.funcs = &rk_usb_clk_funcs;
193 sc->sc_clkdom.priv = sc;
194 sc->sc_usbclk.base.domain = &sc->sc_clkdom;
195 sc->sc_usbclk.base.name = kmem_asprintf("%s", clkname);
196 clk_attach(&sc->sc_usbclk.base);
197
198 aprint_naive("\n");
199 aprint_normal(": USB2 PHY\n");
200
201 fdtbus_register_clock_controller(self, phandle, &rk_usb_fdt_funcs);
202
203 for (child = OF_child(phandle); child; child = OF_peer(child)) {
204 if (!fdtbus_status_okay(child))
205 continue;
206
207 struct fdt_attach_args cfaa = *faa;
208 cfaa.faa_phandle = child;
209 cfaa.faa_name = fdtbus_get_string(child, "name");
210 cfaa.faa_quiet = false;
211
212 config_found(self, &cfaa, NULL);
213 }
214 }
215
216 /*
217 * USB PHY
218 */
219
220 static int rk_usbphy_match(device_t, cfdata_t, void *);
221 static void rk_usbphy_attach(device_t, device_t, void *);
222
223 struct rk_usbphy_softc {
224 device_t sc_dev;
225 int sc_phandle;
226 };
227
228 CFATTACH_DECL_NEW(rk_usbphy, sizeof(struct rk_usbphy_softc),
229 rk_usbphy_match, rk_usbphy_attach, NULL, NULL);
230
231 static void *
232 rk_usbphy_acquire(device_t dev, const void *data, size_t len)
233 {
234 struct rk_usbphy_softc * const sc = device_private(dev);
235
236 if (len != 0)
237 return NULL;
238
239 return sc;
240 }
241
242 static void
243 rk_usbphy_release(device_t dev, void *priv)
244 {
245 }
246
247 static int
248 rk_usbphy_otg_enable(device_t dev, void *priv, bool enable)
249 {
250 struct rk_usb_softc * const usb_sc = device_private(device_parent(dev));
251
252 const uint32_t write_mask = 0x1ffU << 16;
253 const uint32_t write_val = enable ? 0 : 0x1d1;
254 USB_WRITE(usb_sc, CON0_REG, write_mask | write_val);
255
256 return 0;
257 }
258
259 static int
260 rk_usbphy_host_enable(device_t dev, void *priv, bool enable)
261 {
262 struct rk_usb_softc * const usb_sc = device_private(device_parent(dev));
263
264 const uint32_t write_mask = 0x1ffU << 16;
265 const uint32_t write_val = enable ? 0 : 0x1d1;
266 USB_WRITE(usb_sc, CON1_REG, write_mask | write_val);
267
268 return 0;
269 }
270
271 const struct fdtbus_phy_controller_func rk_usbphy_otg_funcs = {
272 .acquire = rk_usbphy_acquire,
273 .release = rk_usbphy_release,
274 .enable = rk_usbphy_otg_enable,
275 };
276
277 const struct fdtbus_phy_controller_func rk_usbphy_host_funcs = {
278 .acquire = rk_usbphy_acquire,
279 .release = rk_usbphy_release,
280 .enable = rk_usbphy_host_enable,
281 };
282
283 static int
284 rk_usbphy_match(device_t parent, cfdata_t cf, void *aux)
285 {
286 struct fdt_attach_args * const faa = aux;
287 const int phandle = faa->faa_phandle;
288 const char *name = fdtbus_get_string(phandle, "name");
289
290 if (strcmp(name, "otg-port") == 0 || strcmp(name, "host-port") == 0)
291 return 1;
292
293 return 0;
294 }
295
296 static void
297 rk_usbphy_attach(device_t parent, device_t self, void *aux)
298 {
299 struct rk_usbphy_softc * const sc = device_private(self);
300 struct fdt_attach_args * const faa = aux;
301 const int phandle = faa->faa_phandle;
302 const char *name = fdtbus_get_string(phandle, "name");
303
304 sc->sc_dev = self;
305 sc->sc_phandle = phandle;
306
307 aprint_naive("\n");
308
309 if (strcmp(name, "otg-port") == 0) {
310 aprint_normal(": USB2 OTG port\n");
311 fdtbus_register_phy_controller(self, phandle, &rk_usbphy_otg_funcs);
312 } else if (strcmp(name, "host-port") == 0) {
313 aprint_normal(": USB2 host port\n");
314 fdtbus_register_phy_controller(self, phandle, &rk_usbphy_host_funcs);
315 }
316 }
317