1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2018 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 ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 20 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 22 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * 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 Clock and Reset Unit 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/lock.h> 38 #include <sys/module.h> 39 #include <sys/mutex.h> 40 #include <machine/bus.h> 41 42 #include <dev/fdt/simplebus.h> 43 44 #include <dev/ofw/ofw_bus.h> 45 #include <dev/ofw/ofw_bus_subr.h> 46 47 #include <dev/clk/clk.h> 48 #include <dev/clk/clk_gate.h> 49 #include <dev/clk/clk_fixed.h> 50 #include <dev/clk/clk_link.h> 51 #include <dev/hwreset/hwreset.h> 52 53 #include <dev/clk/rockchip/rk_clk_composite.h> 54 #include <dev/clk/rockchip/rk_clk_gate.h> 55 #include <dev/clk/rockchip/rk_clk_mux.h> 56 #include <dev/clk/rockchip/rk_clk_pll.h> 57 #include <dev/clk/rockchip/rk_cru.h> 58 59 #include "clkdev_if.h" 60 #include "hwreset_if.h" 61 62 static struct resource_spec rk_cru_spec[] = { 63 { SYS_RES_MEMORY, 0, RF_ACTIVE }, 64 { -1, 0 } 65 }; 66 67 #define CCU_READ4(sc, reg) bus_read_4((sc)->res, (reg)) 68 #define CCU_WRITE4(sc, reg, val) bus_write_4((sc)->res, (reg), (val)) 69 70 void rk3328_cru_register_clocks(struct rk_cru_softc *sc); 71 72 static int 73 rk_cru_write_4(device_t dev, bus_addr_t addr, uint32_t val) 74 { 75 struct rk_cru_softc *sc; 76 77 sc = device_get_softc(dev); 78 CCU_WRITE4(sc, addr, val); 79 return (0); 80 } 81 82 static int 83 rk_cru_read_4(device_t dev, bus_addr_t addr, uint32_t *val) 84 { 85 struct rk_cru_softc *sc; 86 87 sc = device_get_softc(dev); 88 89 *val = CCU_READ4(sc, addr); 90 return (0); 91 } 92 93 static int 94 rk_cru_modify_4(device_t dev, bus_addr_t addr, uint32_t clr, uint32_t set) 95 { 96 struct rk_cru_softc *sc; 97 uint32_t reg; 98 99 sc = device_get_softc(dev); 100 101 reg = CCU_READ4(sc, addr); 102 reg &= ~clr; 103 reg |= set; 104 CCU_WRITE4(sc, addr, reg); 105 106 return (0); 107 } 108 109 static int 110 rk_cru_reset_assert(device_t dev, intptr_t id, bool reset) 111 { 112 struct rk_cru_softc *sc; 113 uint32_t reg; 114 int bit; 115 uint32_t val; 116 117 sc = device_get_softc(dev); 118 119 if (id > sc->reset_num) 120 return (ENXIO); 121 122 reg = sc->reset_offset + id / 16 * 4; 123 bit = id % 16; 124 125 mtx_lock(&sc->mtx); 126 val = 0; 127 if (reset) 128 val = (1 << bit); 129 CCU_WRITE4(sc, reg, val | ((1 << bit) << 16)); 130 mtx_unlock(&sc->mtx); 131 132 return (0); 133 } 134 135 static int 136 rk_cru_reset_is_asserted(device_t dev, intptr_t id, bool *reset) 137 { 138 struct rk_cru_softc *sc; 139 uint32_t reg; 140 int bit; 141 uint32_t val; 142 143 sc = device_get_softc(dev); 144 145 if (id > sc->reset_num) 146 return (ENXIO); 147 reg = sc->reset_offset + id / 16 * 4; 148 bit = id % 16; 149 150 mtx_lock(&sc->mtx); 151 val = CCU_READ4(sc, reg); 152 mtx_unlock(&sc->mtx); 153 154 *reset = false; 155 if (val & (1 << bit)) 156 *reset = true; 157 158 return (0); 159 } 160 161 static void 162 rk_cru_device_lock(device_t dev) 163 { 164 struct rk_cru_softc *sc; 165 166 sc = device_get_softc(dev); 167 mtx_lock(&sc->mtx); 168 } 169 170 static void 171 rk_cru_device_unlock(device_t dev) 172 { 173 struct rk_cru_softc *sc; 174 175 sc = device_get_softc(dev); 176 mtx_unlock(&sc->mtx); 177 } 178 179 static int 180 rk_cru_register_gates(struct rk_cru_softc *sc) 181 { 182 struct rk_clk_gate_def def; 183 int i; 184 185 for (i = 0; i < sc->ngates; i++) { 186 if (sc->gates[i].name == NULL) 187 continue; 188 memset(&def, 0, sizeof(def)); 189 def.clkdef.id = sc->gates[i].id; 190 def.clkdef.name = sc->gates[i].name; 191 def.clkdef.parent_names = &sc->gates[i].parent_name; 192 def.clkdef.parent_cnt = 1; 193 def.offset = sc->gates[i].offset; 194 def.shift = sc->gates[i].shift; 195 def.mask = 1; 196 def.on_value = 0; 197 def.off_value = 1; 198 rk_clk_gate_register(sc->clkdom, &def); 199 } 200 201 return (0); 202 } 203 204 int 205 rk_cru_attach(device_t dev) 206 { 207 struct rk_cru_softc *sc; 208 phandle_t node; 209 int i; 210 211 sc = device_get_softc(dev); 212 sc->dev = dev; 213 214 node = ofw_bus_get_node(dev); 215 216 if (bus_alloc_resources(dev, rk_cru_spec, &sc->res) != 0) { 217 device_printf(dev, "cannot allocate resources for device\n"); 218 return (ENXIO); 219 } 220 221 mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF); 222 223 sc->clkdom = clkdom_create(dev); 224 if (sc->clkdom == NULL) 225 panic("Cannot create clkdom\n"); 226 227 for (i = 0; i < sc->nclks; i++) { 228 switch (sc->clks[i].type) { 229 case RK_CLK_UNDEFINED: 230 break; 231 case RK3066_CLK_PLL: 232 rk3066_clk_pll_register(sc->clkdom, 233 sc->clks[i].clk.pll); 234 break; 235 case RK3328_CLK_PLL: 236 rk3328_clk_pll_register(sc->clkdom, 237 sc->clks[i].clk.pll); 238 break; 239 case RK3399_CLK_PLL: 240 rk3399_clk_pll_register(sc->clkdom, 241 sc->clks[i].clk.pll); 242 break; 243 case RK_CLK_COMPOSITE: 244 rk_clk_composite_register(sc->clkdom, 245 sc->clks[i].clk.composite); 246 break; 247 case RK_CLK_MUX: 248 rk_clk_mux_register(sc->clkdom, sc->clks[i].clk.mux); 249 break; 250 case RK_CLK_ARMCLK: 251 rk_clk_armclk_register(sc->clkdom, 252 sc->clks[i].clk.armclk); 253 break; 254 case RK_CLK_FIXED: 255 clknode_fixed_register(sc->clkdom, 256 sc->clks[i].clk.fixed); 257 break; 258 case RK_CLK_FRACT: 259 rk_clk_fract_register(sc->clkdom, 260 sc->clks[i].clk.fract); 261 break; 262 case RK_CLK_LINK: 263 clknode_link_register(sc->clkdom, 264 sc->clks[i].clk.link); 265 break; 266 default: 267 device_printf(dev, "Unknown clock type\n"); 268 return (ENXIO); 269 } 270 } 271 272 if (sc->gates) 273 rk_cru_register_gates(sc); 274 275 if (clkdom_finit(sc->clkdom) != 0) 276 panic("cannot finalize clkdom initialization\n"); 277 278 if (bootverbose) 279 clkdom_dump(sc->clkdom); 280 281 clk_set_assigned(dev, node); 282 283 /* register our self as a reset provider */ 284 hwreset_register_ofw_provider(dev); 285 286 return (0); 287 } 288 289 static device_method_t rk_cru_methods[] = { 290 /* clkdev interface */ 291 DEVMETHOD(clkdev_write_4, rk_cru_write_4), 292 DEVMETHOD(clkdev_read_4, rk_cru_read_4), 293 DEVMETHOD(clkdev_modify_4, rk_cru_modify_4), 294 DEVMETHOD(clkdev_device_lock, rk_cru_device_lock), 295 DEVMETHOD(clkdev_device_unlock, rk_cru_device_unlock), 296 297 /* Reset interface */ 298 DEVMETHOD(hwreset_assert, rk_cru_reset_assert), 299 DEVMETHOD(hwreset_is_asserted, rk_cru_reset_is_asserted), 300 301 DEVMETHOD_END 302 }; 303 304 DEFINE_CLASS_0(rk_cru, rk_cru_driver, rk_cru_methods, 305 sizeof(struct rk_cru_softc)); 306