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