1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2019 Emmanuel Vadot <manu@FreeBSD.Org> 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 /* 29 * Rockchip USB2PHY 30 */ 31 32 #include <sys/cdefs.h> 33 #include <sys/param.h> 34 #include <sys/systm.h> 35 #include <sys/bus.h> 36 #include <sys/rman.h> 37 #include <sys/kernel.h> 38 #include <sys/module.h> 39 #include <sys/gpio.h> 40 #include <machine/bus.h> 41 42 #include <dev/fdt/fdt_common.h> 43 #include <dev/ofw/ofw_bus.h> 44 #include <dev/ofw/ofw_bus_subr.h> 45 #include <dev/ofw/ofw_subr.h> 46 47 #include <dev/extres/clk/clk.h> 48 #include <dev/extres/phy/phy_usb.h> 49 #include <dev/extres/regulator/regulator.h> 50 #include <dev/extres/syscon/syscon.h> 51 52 #include "clkdev_if.h" 53 #include "syscon_if.h" 54 55 struct rk_usb2phy_reg { 56 uint32_t offset; 57 uint32_t enable_mask; 58 uint32_t disable_mask; 59 }; 60 61 struct rk_usb2phy_regs { 62 struct rk_usb2phy_reg clk_ctl; 63 }; 64 65 struct rk_usb2phy_regs rk3399_regs = { 66 .clk_ctl = { 67 .offset = 0x0000, 68 /* bit 4 put pll in suspend */ 69 .enable_mask = 0x100000, 70 .disable_mask = 0x100010, 71 } 72 }; 73 74 struct rk_usb2phy_regs rk3568_regs = { 75 .clk_ctl = { 76 .offset = 0x0008, 77 .enable_mask = 0x100000, 78 /* bit 4 put pll in suspend */ 79 .disable_mask = 0x100010, 80 } 81 }; 82 83 static struct ofw_compat_data compat_data[] = { 84 { "rockchip,rk3399-usb2phy", (uintptr_t)&rk3399_regs }, 85 { "rockchip,rk3568-usb2phy", (uintptr_t)&rk3568_regs }, 86 { NULL, 0 } 87 }; 88 89 struct rk_usb2phy_softc { 90 device_t dev; 91 struct syscon *grf; 92 regulator_t phy_supply; 93 clk_t clk; 94 int mode; 95 }; 96 97 /* Phy class and methods. */ 98 static int rk_usb2phy_enable(struct phynode *phynode, bool enable); 99 static int rk_usb2phy_get_mode(struct phynode *phy, int *mode); 100 static int rk_usb2phy_set_mode(struct phynode *phy, int mode); 101 static phynode_method_t rk_usb2phy_phynode_methods[] = { 102 PHYNODEMETHOD(phynode_enable, rk_usb2phy_enable), 103 PHYNODEMETHOD(phynode_usb_get_mode, rk_usb2phy_get_mode), 104 PHYNODEMETHOD(phynode_usb_set_mode, rk_usb2phy_set_mode), 105 106 PHYNODEMETHOD_END 107 }; 108 109 DEFINE_CLASS_1(rk_usb2phy_phynode, rk_usb2phy_phynode_class, 110 rk_usb2phy_phynode_methods, 111 sizeof(struct phynode_usb_sc), phynode_usb_class); 112 113 enum RK_USBPHY { 114 RK_USBPHY_HOST = 0, 115 RK_USBPHY_OTG, 116 }; 117 118 static int 119 rk_usb2phy_enable(struct phynode *phynode, bool enable) 120 { 121 struct rk_usb2phy_softc *sc; 122 device_t dev; 123 intptr_t phy; 124 int error; 125 126 dev = phynode_get_device(phynode); 127 phy = phynode_get_id(phynode); 128 sc = device_get_softc(dev); 129 130 if (phy != RK_USBPHY_HOST) 131 return (ERANGE); 132 133 if (sc->phy_supply) { 134 if (enable) 135 error = regulator_enable(sc->phy_supply); 136 else 137 error = regulator_disable(sc->phy_supply); 138 if (error != 0) { 139 device_printf(dev, "Cannot %sable the regulator\n", 140 enable ? "En" : "Dis"); 141 goto fail; 142 } 143 } 144 145 return (0); 146 fail: 147 return (ENXIO); 148 } 149 150 static int 151 rk_usb2phy_get_mode(struct phynode *phynode, int *mode) 152 { 153 struct rk_usb2phy_softc *sc; 154 intptr_t phy; 155 device_t dev; 156 157 dev = phynode_get_device(phynode); 158 phy = phynode_get_id(phynode); 159 sc = device_get_softc(dev); 160 161 if (phy != RK_USBPHY_HOST) 162 return (ERANGE); 163 164 *mode = sc->mode; 165 166 return (0); 167 } 168 169 static int 170 rk_usb2phy_set_mode(struct phynode *phynode, int mode) 171 { 172 struct rk_usb2phy_softc *sc; 173 intptr_t phy; 174 device_t dev; 175 176 dev = phynode_get_device(phynode); 177 phy = phynode_get_id(phynode); 178 sc = device_get_softc(dev); 179 180 if (phy != RK_USBPHY_HOST) 181 return (ERANGE); 182 183 sc->mode = mode; 184 185 return (0); 186 } 187 188 /* Clock class and method */ 189 struct rk_usb2phy_clk_sc { 190 device_t clkdev; 191 struct syscon *grf; 192 struct rk_usb2phy_regs *regs; 193 }; 194 195 static int 196 rk_usb2phy_clk_init(struct clknode *clk, device_t dev) 197 { 198 199 clknode_init_parent_idx(clk, 0); 200 return (0); 201 } 202 203 static int 204 rk_usb2phy_clk_set_gate(struct clknode *clk, bool enable) 205 { 206 struct rk_usb2phy_clk_sc *sc; 207 208 sc = clknode_get_softc(clk); 209 210 if (enable) 211 SYSCON_WRITE_4(sc->grf, sc->regs->clk_ctl.offset, 212 sc->regs->clk_ctl.enable_mask); 213 else 214 SYSCON_WRITE_4(sc->grf, sc->regs->clk_ctl.offset, 215 sc->regs->clk_ctl.disable_mask); 216 return (0); 217 } 218 219 static int 220 rk_usb2phy_clk_recalc(struct clknode *clk, uint64_t *freq) 221 { 222 223 *freq = 480000000; 224 225 return (0); 226 } 227 228 static clknode_method_t rk_usb2phy_clk_clknode_methods[] = { 229 /* Device interface */ 230 231 CLKNODEMETHOD(clknode_init, rk_usb2phy_clk_init), 232 CLKNODEMETHOD(clknode_set_gate, rk_usb2phy_clk_set_gate), 233 CLKNODEMETHOD(clknode_recalc_freq, rk_usb2phy_clk_recalc), 234 CLKNODEMETHOD_END 235 }; 236 237 DEFINE_CLASS_1(rk_usb2phy_clk_clknode, rk_usb2phy_clk_clknode_class, 238 rk_usb2phy_clk_clknode_methods, sizeof(struct rk_usb2phy_clk_sc), 239 clknode_class); 240 241 static int 242 rk_usb2phy_clk_ofw_map(struct clkdom *clkdom, uint32_t ncells, 243 phandle_t *cells, struct clknode **clk) 244 { 245 246 if (ncells != 0) 247 return (ERANGE); 248 249 *clk = clknode_find_by_id(clkdom, 0); 250 251 if (*clk == NULL) 252 return (ENXIO); 253 return (0); 254 } 255 256 static int 257 rk_usb2phy_export_clock(struct rk_usb2phy_softc *devsc) 258 { 259 struct clknode_init_def def; 260 struct rk_usb2phy_clk_sc *sc; 261 const char **clknames; 262 struct clkdom *clkdom; 263 struct clknode *clk; 264 clk_t clk_parent; 265 phandle_t node; 266 phandle_t regs[2]; 267 int i, nclocks, ncells, error; 268 269 node = ofw_bus_get_node(devsc->dev); 270 271 error = ofw_bus_parse_xref_list_get_length(node, "clocks", 272 "#clock-cells", &ncells); 273 if (error != 0 || ncells != 1) { 274 device_printf(devsc->dev, "couldn't find parent clock\n"); 275 return (ENXIO); 276 } 277 278 nclocks = ofw_bus_string_list_to_array(node, "clock-output-names", 279 &clknames); 280 if (nclocks != 1) 281 return (ENXIO); 282 283 clkdom = clkdom_create(devsc->dev); 284 clkdom_set_ofw_mapper(clkdom, rk_usb2phy_clk_ofw_map); 285 286 memset(&def, 0, sizeof(def)); 287 def.id = 0; 288 def.name = clknames[0]; 289 def.parent_names = malloc(sizeof(char *) * ncells, M_OFWPROP, M_WAITOK); 290 for (i = 0; i < ncells; i++) { 291 error = clk_get_by_ofw_index(devsc->dev, 0, i, &clk_parent); 292 if (error != 0) { 293 device_printf(devsc->dev, "cannot get clock %d\n", error); 294 return (ENXIO); 295 } 296 def.parent_names[i] = clk_get_name(clk_parent); 297 clk_release(clk_parent); 298 } 299 def.parent_cnt = ncells; 300 301 clk = clknode_create(clkdom, &rk_usb2phy_clk_clknode_class, &def); 302 if (clk == NULL) { 303 device_printf(devsc->dev, "cannot create clknode\n"); 304 return (ENXIO); 305 } 306 307 sc = clknode_get_softc(clk); 308 sc->clkdev = device_get_parent(devsc->dev); 309 sc->grf = devsc->grf; 310 sc->regs = (struct rk_usb2phy_regs *)ofw_bus_search_compatible(devsc->dev, compat_data)->ocd_data; 311 if (sc->regs->clk_ctl.offset == 0) { 312 OF_getencprop(node, "reg", regs, sizeof(regs)); 313 sc->regs->clk_ctl.offset = regs[0]; 314 } 315 clknode_register(clkdom, clk); 316 317 if (clkdom_finit(clkdom) != 0) { 318 device_printf(devsc->dev, "cannot finalize clkdom initialization\n"); 319 return (ENXIO); 320 } 321 322 if (bootverbose) 323 clkdom_dump(clkdom); 324 325 return (0); 326 } 327 328 static int 329 rk_usb2phy_probe(device_t dev) 330 { 331 332 if (!ofw_bus_status_okay(dev)) 333 return (ENXIO); 334 335 if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 336 return (ENXIO); 337 338 device_set_desc(dev, "Rockchip USB2PHY"); 339 return (BUS_PROBE_DEFAULT); 340 } 341 342 static int 343 rk_usb2phy_attach(device_t dev) 344 { 345 struct rk_usb2phy_softc *sc; 346 struct phynode_init_def phy_init; 347 struct phynode *phynode; 348 phandle_t node, host; 349 int err; 350 351 sc = device_get_softc(dev); 352 sc->dev = dev; 353 node = ofw_bus_get_node(dev); 354 355 if (OF_hasprop(node, "rockchip,usbgrf")) { 356 if (syscon_get_by_ofw_property(dev, node, "rockchip,usbgrf", 357 &sc->grf)) { 358 device_printf(dev, "Cannot get syscon handle\n"); 359 return (ENXIO); 360 } 361 } 362 else { 363 if (syscon_get_handle_default(dev, &sc->grf)) { 364 device_printf(dev, "Cannot get syscon handle\n"); 365 return (ENXIO); 366 } 367 } 368 369 if (clk_get_by_ofw_name(dev, 0, "phyclk", &sc->clk) != 0) { 370 device_printf(dev, "Cannot get clock\n"); 371 return (ENXIO); 372 } 373 err = clk_enable(sc->clk); 374 if (err != 0) { 375 device_printf(dev, "Could not enable clock %s\n", 376 clk_get_name(sc->clk)); 377 return (ENXIO); 378 } 379 380 err = rk_usb2phy_export_clock(sc); 381 if (err != 0) 382 return (err); 383 384 /* Only host is supported right now */ 385 386 host = ofw_bus_find_child(node, "host-port"); 387 if (host == 0) { 388 device_printf(dev, "Cannot find host-port child node\n"); 389 return (ENXIO); 390 } 391 392 if (!ofw_bus_node_status_okay(host)) { 393 device_printf(dev, "host-port isn't okay\n"); 394 return (0); 395 } 396 397 regulator_get_by_ofw_property(dev, host, "phy-supply", &sc->phy_supply); 398 phy_init.id = RK_USBPHY_HOST; 399 phy_init.ofw_node = host; 400 phynode = phynode_create(dev, &rk_usb2phy_phynode_class, &phy_init); 401 if (phynode == NULL) { 402 device_printf(dev, "failed to create host USB2PHY\n"); 403 return (ENXIO); 404 } 405 if (phynode_register(phynode) == NULL) { 406 device_printf(dev, "failed to register host USB2PHY\n"); 407 return (ENXIO); 408 } 409 410 OF_device_register_xref(OF_xref_from_node(host), dev); 411 412 return (0); 413 } 414 415 static device_method_t rk_usb2phy_methods[] = { 416 /* Device interface */ 417 DEVMETHOD(device_probe, rk_usb2phy_probe), 418 DEVMETHOD(device_attach, rk_usb2phy_attach), 419 420 DEVMETHOD_END 421 }; 422 423 static driver_t rk_usb2phy_driver = { 424 "rk_usb2phy", 425 rk_usb2phy_methods, 426 sizeof(struct rk_usb2phy_softc) 427 }; 428 429 EARLY_DRIVER_MODULE(rk_usb2phy, simplebus, rk_usb2phy_driver, 0, 0, 430 BUS_PASS_SUPPORTDEV + BUS_PASS_ORDER_MIDDLE); 431 MODULE_VERSION(rk_usb2phy, 1); 432