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