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