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/bus.h> 29 #include <sys/kernel.h> 30 #include <sys/module.h> 31 #include <sys/mutex.h> 32 #include <sys/rman.h> 33 34 #include <machine/bus.h> 35 #include <machine/fdt.h> 36 37 #include <dev/fdt/simplebus.h> 38 #include <dev/ofw/ofw_bus.h> 39 #include <dev/ofw/ofw_bus_subr.h> 40 #include <dev/clk/clk.h> 41 42 #include <arm/mv/mvwin.h> 43 #include <arm/mv/mvreg.h> 44 #include <arm/mv/mvvar.h> 45 46 #include <arm/mv/clk/armada38x_gen.h> 47 48 #include "clkdev_if.h" 49 50 #define ARMADA38X_CORECLK_MAXREG 0 51 52 static struct resource_spec armada38x_coreclk_specs[] = { 53 { SYS_RES_MEMORY, 0, RF_ACTIVE }, 54 { -1, 0 } 55 }; 56 57 struct armada38x_coreclk_softc { 58 struct resource *res; 59 struct clkdom *clkdom; 60 struct mtx mtx; 61 }; 62 63 static int armada38x_coreclk_attach(device_t dev); 64 static int armada38x_coreclk_probe(device_t dev); 65 66 static struct armada38x_gen_clknode_def gen_nodes[] = 67 { 68 { 69 .def = { 70 .name = "coreclk_0", 71 .id = 0, 72 .parent_cnt = 0, 73 }, 74 }, 75 { 76 .def = { 77 .name = "coreclk_2", 78 .id = 1, 79 .parent_cnt = 0, 80 }, 81 } 82 }; 83 84 static int 85 armada38x_coreclk_read_4(device_t dev, bus_addr_t addr, uint32_t *val) 86 { 87 struct armada38x_coreclk_softc *sc; 88 89 sc = device_get_softc(dev); 90 91 if (addr > ARMADA38X_CORECLK_MAXREG) 92 return (EINVAL); 93 94 *val = bus_read_4(sc->res, addr); 95 96 return (0); 97 } 98 99 static int 100 armada38x_coreclk_write_4(device_t dev, bus_addr_t addr, uint32_t val) 101 { 102 struct armada38x_coreclk_softc *sc; 103 104 sc = device_get_softc(dev); 105 106 if (addr > ARMADA38X_CORECLK_MAXREG) 107 return (EINVAL); 108 109 bus_write_4(sc->res, addr, val); 110 111 return (0); 112 } 113 114 static void 115 armada38x_coreclk_device_lock(device_t dev) 116 { 117 struct armada38x_coreclk_softc *sc; 118 119 sc = device_get_softc(dev); 120 mtx_lock(&sc->mtx); 121 } 122 123 static void 124 armada38x_coreclk_device_unlock(device_t dev) 125 { 126 struct armada38x_coreclk_softc *sc; 127 128 sc = device_get_softc(dev); 129 mtx_unlock(&sc->mtx); 130 } 131 132 static int 133 armada38x_coreclk_probe(device_t dev) 134 { 135 136 if (!ofw_bus_status_okay(dev)) 137 return (ENXIO); 138 139 if (!ofw_bus_is_compatible(dev, "marvell,armada-380-core-clock")) 140 return (ENXIO); 141 142 device_set_desc(dev, "ARMADA38X core-clock"); 143 144 return (BUS_PROBE_DEFAULT); 145 } 146 147 static int 148 armada38x_coreclk_create_coreclk(device_t dev) 149 { 150 struct armada38x_coreclk_softc *sc; 151 int rv, i; 152 153 sc = device_get_softc(dev); 154 155 for (i = 0; i < nitems(gen_nodes); ++i) { 156 rv = armada38x_gen_register(sc->clkdom, &gen_nodes[i]); 157 if (rv) 158 return (rv); 159 } 160 161 return (rv); 162 } 163 164 static int 165 armada38x_coreclk_attach(device_t dev) 166 { 167 struct armada38x_coreclk_softc *sc; 168 int error; 169 170 sc = device_get_softc(dev); 171 172 if (bus_alloc_resources(dev, armada38x_coreclk_specs, &sc->res) != 0) { 173 device_printf(dev, "Cannot allocate resources.\n"); 174 return (ENXIO); 175 } 176 177 mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF); 178 179 sc->clkdom = clkdom_create(dev); 180 if (NULL == sc->clkdom) { 181 device_printf(dev, "Cannot create clkdom\n"); 182 return (ENXIO); 183 } 184 185 error = armada38x_coreclk_create_coreclk(dev); 186 if (0 != error) { 187 device_printf(dev, "Cannot create coreclk.\n"); 188 return (error); 189 } 190 191 if (clkdom_finit(sc->clkdom) != 0) 192 panic("Cannot finalize clock domain initialization.\n"); 193 194 if (bootverbose) 195 clkdom_dump(sc->clkdom); 196 197 return (0); 198 } 199 200 static device_method_t amada38x_coreclk_methods[] = { 201 DEVMETHOD(clkdev_write_4, armada38x_coreclk_write_4), 202 DEVMETHOD(clkdev_read_4, armada38x_coreclk_read_4), 203 DEVMETHOD(clkdev_device_lock, armada38x_coreclk_device_lock), 204 DEVMETHOD(clkdev_device_unlock, armada38x_coreclk_device_unlock), 205 206 DEVMETHOD(device_attach, armada38x_coreclk_attach), 207 DEVMETHOD(device_probe, armada38x_coreclk_probe), 208 209 DEVMETHOD_END 210 }; 211 212 static driver_t armada38x_coreclk_driver = { 213 "armada38x_coreclk", 214 amada38x_coreclk_methods, 215 sizeof(struct armada38x_coreclk_softc), 216 }; 217 218 EARLY_DRIVER_MODULE(armada38x_coreclk, simplebus, armada38x_coreclk_driver, 0, 0, 219 BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); 220