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