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