1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2020 Oleksandr Tymoshenko <gonzo@FreeBSD.org> 5 * Copyright (c) 2024 The FreeBSD Foundation 6 * 7 * Portions of this software were developed by Tom Jones <thj@freebsd.org> 8 * under sponsorship from the FreeBSD Foundation. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 34 /* 35 * Clock Control Module driver for Freescale i.MX 8M SoC family. 36 */ 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/kernel.h> 41 #include <sys/module.h> 42 #include <sys/mutex.h> 43 #include <sys/bus.h> 44 #include <sys/rman.h> 45 46 #include <dev/ofw/ofw_bus.h> 47 #include <dev/ofw/ofw_bus_subr.h> 48 49 #include <machine/bus.h> 50 51 #include <arm64/freescale/imx/imx_ccm.h> 52 #include <arm64/freescale/imx/clk/imx_clk_gate.h> 53 #include <arm64/freescale/imx/clk/imx_clk_mux.h> 54 #include <arm64/freescale/imx/clk/imx_clk_composite.h> 55 #include <arm64/freescale/imx/clk/imx_clk_sscg_pll.h> 56 #include <arm64/freescale/imx/clk/imx_clk_frac_pll.h> 57 58 #include "clkdev_if.h" 59 60 static inline uint32_t 61 CCU_READ4(struct imx_ccm_softc *sc, bus_size_t off) 62 { 63 64 return (bus_read_4(sc->mem_res, off)); 65 } 66 67 static inline void 68 CCU_WRITE4(struct imx_ccm_softc *sc, bus_size_t off, uint32_t val) 69 { 70 71 bus_write_4(sc->mem_res, off, val); 72 } 73 74 int 75 imx_ccm_detach(device_t dev) 76 { 77 struct imx_ccm_softc *sc; 78 79 sc = device_get_softc(dev); 80 81 if (sc->mem_res != NULL) 82 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res); 83 84 return (0); 85 } 86 87 int 88 imx_ccm_attach(device_t dev) 89 { 90 struct imx_ccm_softc *sc; 91 int err, rid; 92 phandle_t node; 93 int i; 94 95 sc = device_get_softc(dev); 96 sc->dev = dev; 97 err = 0; 98 99 /* Allocate bus_space resources. */ 100 rid = 0; 101 sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 102 RF_ACTIVE); 103 if (sc->mem_res == NULL) { 104 device_printf(dev, "Cannot allocate memory resources\n"); 105 err = ENXIO; 106 goto out; 107 } 108 109 mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF); 110 111 sc->clkdom = clkdom_create(dev); 112 if (sc->clkdom == NULL) 113 panic("Cannot create clkdom\n"); 114 115 for (i = 0; i < sc->nclks; i++) { 116 switch (sc->clks[i].type) { 117 case IMX_CLK_UNDEFINED: 118 break; 119 case IMX_CLK_LINK: 120 clknode_link_register(sc->clkdom, 121 sc->clks[i].clk.link); 122 break; 123 case IMX_CLK_FIXED: 124 clknode_fixed_register(sc->clkdom, 125 sc->clks[i].clk.fixed); 126 break; 127 case IMX_CLK_MUX: 128 imx_clk_mux_register(sc->clkdom, sc->clks[i].clk.mux); 129 break; 130 case IMX_CLK_GATE: 131 imx_clk_gate_register(sc->clkdom, sc->clks[i].clk.gate); 132 break; 133 case IMX_CLK_COMPOSITE: 134 imx_clk_composite_register(sc->clkdom, sc->clks[i].clk.composite); 135 break; 136 case IMX_CLK_SSCG_PLL: 137 imx_clk_sscg_pll_register(sc->clkdom, sc->clks[i].clk.sscg_pll); 138 break; 139 case IMX_CLK_FRAC_PLL: 140 imx_clk_frac_pll_register(sc->clkdom, sc->clks[i].clk.frac_pll); 141 break; 142 case IMX_CLK_DIV: 143 clknode_div_register(sc->clkdom, sc->clks[i].clk.div); 144 break; 145 default: 146 device_printf(dev, "Unknown clock type %d\n", sc->clks[i].type); 147 return (ENXIO); 148 } 149 } 150 151 if (clkdom_finit(sc->clkdom) != 0) 152 panic("cannot finalize clkdom initialization\n"); 153 154 if (bootverbose) 155 clkdom_dump(sc->clkdom); 156 157 node = ofw_bus_get_node(dev); 158 clk_set_assigned(dev, node); 159 160 err = 0; 161 162 out: 163 164 if (err != 0) 165 imx_ccm_detach(dev); 166 167 return (err); 168 } 169 170 static int 171 imx_ccm_write_4(device_t dev, bus_addr_t addr, uint32_t val) 172 { 173 struct imx_ccm_softc *sc; 174 175 sc = device_get_softc(dev); 176 CCU_WRITE4(sc, addr, val); 177 return (0); 178 } 179 180 static int 181 imx_ccm_read_4(device_t dev, bus_addr_t addr, uint32_t *val) 182 { 183 struct imx_ccm_softc *sc; 184 185 sc = device_get_softc(dev); 186 187 *val = CCU_READ4(sc, addr); 188 return (0); 189 } 190 191 static int 192 imx_ccm_modify_4(device_t dev, bus_addr_t addr, uint32_t clr, uint32_t set) 193 { 194 struct imx_ccm_softc *sc; 195 uint32_t reg; 196 197 sc = device_get_softc(dev); 198 199 reg = CCU_READ4(sc, addr); 200 reg &= ~clr; 201 reg |= set; 202 CCU_WRITE4(sc, addr, reg); 203 204 return (0); 205 } 206 207 static void 208 imx_ccm_device_lock(device_t dev) 209 { 210 struct imx_ccm_softc *sc; 211 212 sc = device_get_softc(dev); 213 mtx_lock(&sc->mtx); 214 } 215 216 static void 217 imx_ccm_device_unlock(device_t dev) 218 { 219 struct imx_ccm_softc *sc; 220 221 sc = device_get_softc(dev); 222 mtx_unlock(&sc->mtx); 223 } 224 225 static device_method_t imx_ccm_methods[] = { 226 /* clkdev interface */ 227 DEVMETHOD(clkdev_write_4, imx_ccm_write_4), 228 DEVMETHOD(clkdev_read_4, imx_ccm_read_4), 229 DEVMETHOD(clkdev_modify_4, imx_ccm_modify_4), 230 DEVMETHOD(clkdev_device_lock, imx_ccm_device_lock), 231 DEVMETHOD(clkdev_device_unlock, imx_ccm_device_unlock), 232 233 DEVMETHOD_END 234 }; 235 236 DEFINE_CLASS_0(imx_ccm, imx_ccm_driver, imx_ccm_methods, 237 sizeof(struct imx_ccm_softc)); 238