1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2022 Semihalf. 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, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 #include <sys/param.h> 29 #include <sys/systm.h> 30 #include <sys/bus.h> 31 #include <sys/rman.h> 32 #include <sys/kernel.h> 33 #include <sys/lock.h> 34 #include <sys/module.h> 35 #include <sys/mutex.h> 36 37 #include <machine/bus.h> 38 39 #include <dev/fdt/simplebus.h> 40 #include <dev/ofw/ofw_bus.h> 41 #include <dev/ofw/ofw_bus_subr.h> 42 #include <dev/extres/clk/clk.h> 43 #include <dev/extres/clk/clk_gate.h> 44 45 #include "clkdev_if.h" 46 47 struct armada38x_gateclk_softc 48 { 49 struct clkdom *clkdom; 50 struct mtx mtx; 51 const char* parent; 52 }; 53 54 static struct clk_gate_def gateclk_nodes[] = 55 { 56 { 57 .clkdef = { 58 .name = "gateclk-audio", 59 .id = 0, 60 .parent_cnt = 1, 61 .flags = 0, 62 }, 63 .shift = 0, 64 }, 65 { 66 .clkdef = { 67 .name = "gateclk-eth2", 68 .id = 2, 69 .parent_cnt = 1, 70 .flags = 0, 71 }, 72 .shift = 2, 73 }, 74 { 75 .clkdef = { 76 .name = "gateclk-eth1", 77 .id = 3, 78 .parent_cnt = 1, 79 .flags = 0, 80 }, 81 .shift = 3, 82 }, 83 { 84 .clkdef = { 85 .name = "gateclk-eth0", 86 .id = 4, 87 .parent_cnt = 1, 88 .flags = 0, 89 }, 90 .shift = 4, 91 }, 92 { 93 .clkdef = { 94 .name = "gateclk-mdio", 95 .id = 4, 96 .parent_cnt = 1, 97 .flags = 0, 98 }, 99 .shift = 4, 100 }, 101 { 102 .clkdef = { 103 .name = "gateclk-usb3h0", 104 .id = 9, 105 .parent_cnt = 1, 106 .flags = 0, 107 }, 108 .shift = 9, 109 }, 110 { 111 .clkdef = { 112 .name = "gateclk-usb3h1", 113 .id = 10, 114 .parent_cnt = 1, 115 .flags = 0, 116 }, 117 .shift = 10, 118 }, 119 { 120 .clkdef = { 121 .name = "gateclk-bm", 122 .id = 13, 123 .parent_cnt = 1, 124 .flags = 0, 125 }, 126 .shift = 13, 127 }, 128 { 129 .clkdef = { 130 .name = "gateclk-crypto0z", 131 .id = 14, 132 .parent_cnt = 1, 133 .flags = 0, 134 }, 135 .shift = 14, 136 }, 137 { 138 .clkdef = { 139 .name = "gateclk-sata0", 140 .id = 15, 141 .parent_cnt = 1, 142 .flags = 0, 143 }, 144 .shift = 15, 145 }, 146 { 147 .clkdef = { 148 .name = "gateclk-crypto1z", 149 .id = 16, 150 .parent_cnt = 1, 151 .flags = 0, 152 }, 153 .shift = 16, 154 }, 155 { 156 .clkdef = { 157 .name = "gateclk-sdio", 158 .id = 17, 159 .parent_cnt = 1, 160 .flags = 0, 161 }, 162 .shift = 17, 163 }, 164 { 165 .clkdef = { 166 .name = "gateclk-usb2", 167 .id = 18, 168 .parent_cnt = 1, 169 .flags = 0, 170 }, 171 .shift = 18, 172 }, 173 { 174 .clkdef = { 175 .name = "gateclk-crypto1", 176 .id = 21, 177 .parent_cnt = 1, 178 .flags = 0, 179 }, 180 .shift = 21, 181 }, 182 { 183 .clkdef = { 184 .name = "gateclk-xor0", 185 .id = 22, 186 .parent_cnt = 1, 187 .flags = 0, 188 }, 189 .shift = 22, 190 }, 191 { 192 .clkdef = { 193 .name = "gateclk-crypto0", 194 .id = 23, 195 .parent_cnt = 1, 196 .flags = 0, 197 }, 198 .shift = 23, 199 }, 200 { 201 .clkdef = { 202 .name = "gateclk-xor1", 203 .id = 28, 204 .parent_cnt = 1, 205 .flags = 0, 206 }, 207 .shift = 28, 208 }, 209 { 210 .clkdef = { 211 .name = "gateclk-sata1", 212 .id = 30, 213 .parent_cnt = 1, 214 .flags = 0, 215 }, 216 .shift = 30, 217 } 218 }; 219 220 static int armada38x_gateclk_probe(device_t dev); 221 static int armada38x_gateclk_attach(device_t dev); 222 223 static device_method_t armada38x_gateclk_methods[] = { 224 DEVMETHOD(device_probe, armada38x_gateclk_probe), 225 DEVMETHOD(device_attach, armada38x_gateclk_attach), 226 227 DEVMETHOD_END 228 }; 229 230 static driver_t armada38x_gateclk_driver = { 231 "armada38x_gateclk", 232 armada38x_gateclk_methods, 233 sizeof(struct armada38x_gateclk_softc), 234 }; 235 236 EARLY_DRIVER_MODULE(armada38x_gateclk, simplebus, armada38x_gateclk_driver, 0, 0, 237 BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE + 1); 238 239 static int 240 armada38x_gateclk_probe(device_t dev) 241 { 242 243 if (!ofw_bus_status_okay(dev)) 244 return (ENXIO); 245 246 if(!ofw_bus_is_compatible(dev, "marvell,armada-380-gating-clock")) 247 return (ENXIO); 248 249 device_set_desc(dev, "ARMADA38X gateclk"); 250 251 return (BUS_PROBE_DEFAULT); 252 } 253 254 static int 255 armada38x_gateclk_attach(device_t dev) 256 { 257 struct armada38x_gateclk_softc *sc; 258 phandle_t node; 259 int i, error; 260 clk_t clock; 261 262 sc = device_get_softc(dev); 263 node = ofw_bus_get_node(dev); 264 265 mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF); 266 267 sc->clkdom = clkdom_create(dev); 268 if (sc->clkdom == NULL) { 269 device_printf(dev, "Cannot create clock domain.\n"); 270 return (ENXIO); 271 } 272 273 error = clk_get_by_ofw_index(dev, node, 0, &clock); 274 if (error > 0) 275 return (error); 276 277 sc->parent = clk_get_name(clock); 278 279 for (i = 0; i < nitems(gateclk_nodes); ++i) { 280 gateclk_nodes[i].clkdef.parent_names = &sc->parent; 281 error = clknode_gate_register(sc->clkdom, &gateclk_nodes[i]); 282 if (error != 0) { 283 device_printf(dev, "Cannot create gate nodes\n"); 284 return (error); 285 } 286 } 287 288 if (clkdom_finit(sc->clkdom) != 0) 289 panic("Cannot finalize clock domain initialization.\n"); 290 291 return (0); 292 } 293