1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2020 Alstom Group. 5 * Copyright (c) 2020 Semihalf. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <sys/param.h> 33 #include <sys/bus.h> 34 #include <sys/kernel.h> 35 #include <sys/module.h> 36 #include <sys/mutex.h> 37 #include <sys/rman.h> 38 #include <machine/bus.h> 39 40 #include <dev/fdt/simplebus.h> 41 42 #include <dev/ofw/ofw_bus.h> 43 #include <dev/ofw/ofw_bus_subr.h> 44 45 #include <dev/extres/clk/clk_fixed.h> 46 47 #include <arm64/qoriq/clk/qoriq_clkgen.h> 48 49 static uint8_t ls1046a_pltfrm_pll_divs[] = { 50 2, 4, 0 51 }; 52 53 static struct qoriq_clk_pll_def ls1046a_pltfrm_pll = { 54 .clkdef = { 55 .name = "ls1046a_platform_pll", 56 .id = QORIQ_CLK_ID(QORIQ_TYPE_PLATFORM_PLL, 0), 57 .flags = 0 58 }, 59 .offset = 0xC00, 60 .shift = 1, 61 .mask = 0x7E, 62 .dividers = ls1046a_pltfrm_pll_divs, 63 .flags = 0 64 }; 65 66 static const uint8_t ls1046a_cga1_pll_divs[] = { 67 2, 3, 4, 0 68 }; 69 70 static struct qoriq_clk_pll_def ls1046a_cga1_pll = { 71 .clkdef = { 72 .name = "ls1046a_cga_pll1", 73 .id = QORIQ_CLK_ID(QORIQ_TYPE_INTERNAL, 0), 74 .flags = 0 75 }, 76 .offset = 0x800, 77 .shift = 1, 78 .mask = 0x1FE, 79 .dividers = ls1046a_cga1_pll_divs, 80 .flags = QORIQ_CLK_PLL_HAS_KILL_BIT 81 }; 82 83 static struct qoriq_clk_pll_def ls1046a_cga2_pll = { 84 .clkdef = { 85 .name = "ls1046a_cga_pll2", 86 .id = QORIQ_CLK_ID(QORIQ_TYPE_INTERNAL, 20), 87 .flags = 0 88 }, 89 .offset = 0x820, 90 .shift = 1, 91 .mask = 0x1FE, 92 .dividers = ls1046a_cga1_pll_divs, 93 .flags = QORIQ_CLK_PLL_HAS_KILL_BIT 94 }; 95 96 static struct qoriq_clk_pll_def *ls1046a_cga_plls[] = { 97 &ls1046a_cga1_pll, 98 &ls1046a_cga2_pll 99 }; 100 101 static const char *ls1046a_cmux0_parent_names[] = { 102 "ls1046a_cga_pll1", 103 NULL, 104 "ls1046a_cga_pll1_div2", 105 NULL, 106 "ls1046a_cga_pll2", 107 NULL, 108 "ls1046a_cga_pll2_div2" 109 }; 110 111 static struct clk_mux_def ls1046a_cmux0 = { 112 .clkdef = { 113 .name = "ls1046a_cmux0", 114 .id = QORIQ_CLK_ID(QORIQ_TYPE_CMUX, 0), 115 .parent_names = ls1046a_cmux0_parent_names, 116 .parent_cnt = nitems(ls1046a_cmux0_parent_names), 117 .flags = 0 118 }, 119 .offset = 0, 120 .shift = 27, 121 .width = 4, 122 .mux_flags = 0 123 }; 124 125 static const char *ls1046a_hwaccel1_parent_names[] = { 126 NULL, 127 NULL, 128 "ls1046a_cga_pll1_div2", 129 "ls1046a_cga_pll1_div3", 130 "ls1046a_cga_pll1_div4", 131 "ls1046a_platform_pll", 132 "ls1046a_cga_pll2_div2", 133 "ls1046a_cga_pll2_div3" 134 }; 135 136 static const char *ls1046a_hwaccel2_parent_names[] = { 137 NULL, 138 "ls1046a_cga_pll2", 139 "ls1046a_cga_pll2_div2", 140 "ls1046a_cga_pll2_div3", 141 NULL, 142 NULL, 143 "ls1046a_cga_pll1_div2" 144 }; 145 146 static struct clk_mux_def ls1046a_hwaccel1 = { 147 .clkdef = { 148 .name = "ls1046a_hwaccel1", 149 .id = QORIQ_CLK_ID(QORIQ_TYPE_HWACCEL, 0), 150 .parent_names = ls1046a_hwaccel1_parent_names, 151 .parent_cnt = nitems(ls1046a_hwaccel1_parent_names), 152 .flags = 0 153 }, 154 .offset = 0x10, 155 .shift = 27, 156 .width = 4, 157 .mux_flags = 0 158 }; 159 160 static struct clk_mux_def ls1046a_hwaccel2 = { 161 .clkdef = { 162 .name = "ls1046a_hwaccel2", 163 .id = QORIQ_CLK_ID(QORIQ_TYPE_HWACCEL, 1), 164 .parent_names = ls1046a_hwaccel2_parent_names, 165 .parent_cnt = nitems(ls1046a_hwaccel2_parent_names), 166 .flags = 0 167 }, 168 .offset = 0x30, 169 .shift = 27, 170 .width = 4, 171 .mux_flags = 0 172 }; 173 174 static struct clk_mux_def *ls1046a_mux_nodes[] = { 175 &ls1046a_cmux0, 176 &ls1046a_hwaccel1, 177 &ls1046a_hwaccel2 178 }; 179 180 const char *ls1046a_fman_srcs[] = { 181 "ls1046a_hwaccel1" 182 }; 183 184 static int ls1046a_clkgen_probe(device_t); 185 static int ls1046a_clkgen_attach(device_t); 186 187 static device_method_t ls1046a_clkgen_methods[] = { 188 DEVMETHOD(device_probe, ls1046a_clkgen_probe), 189 DEVMETHOD(device_attach, ls1046a_clkgen_attach), 190 191 DEVMETHOD_END 192 }; 193 194 DEFINE_CLASS_1(ls1046a_clkgen, ls1046a_clkgen_driver, ls1046a_clkgen_methods, 195 sizeof(struct qoriq_clkgen_softc), qoriq_clkgen_driver); 196 197 EARLY_DRIVER_MODULE(ls1046a_clkgen, simplebus, ls1046a_clkgen_driver, 0, 0, 198 BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); 199 200 static int 201 ls1046a_fman_init(device_t dev) 202 { 203 struct qoriq_clkgen_softc *sc; 204 struct clk_fixed_def def; 205 int error; 206 207 sc = device_get_softc(dev); 208 209 def.clkdef.name = "ls1046a_fman", 210 def.clkdef.id = QORIQ_CLK_ID(QORIQ_TYPE_FMAN, 0), 211 def.clkdef.parent_names = ls1046a_fman_srcs; 212 def.clkdef.parent_cnt = nitems(ls1046a_fman_srcs); 213 def.clkdef.flags = 0; 214 def.freq = 0; 215 def.mult = 1; 216 def.div = 1; 217 def.fixed_flags = 0; 218 219 error = clknode_fixed_register(sc->clkdom, &def); 220 return (error); 221 } 222 223 static int 224 ls1046a_clkgen_probe(device_t dev) 225 { 226 227 if (!ofw_bus_status_okay(dev)) 228 return (ENXIO); 229 230 if(!ofw_bus_is_compatible(dev, "fsl,ls1046a-clockgen")) 231 return (ENXIO); 232 233 device_set_desc(dev, "LS1046A clockgen"); 234 return (BUS_PROBE_DEFAULT); 235 } 236 237 static int 238 ls1046a_clkgen_attach(device_t dev) 239 { 240 struct qoriq_clkgen_softc *sc; 241 242 sc = device_get_softc(dev); 243 244 sc->pltfrm_pll_def = &ls1046a_pltfrm_pll; 245 sc->cga_pll = ls1046a_cga_plls; 246 sc->cga_pll_num = nitems(ls1046a_cga_plls); 247 sc->mux = ls1046a_mux_nodes; 248 sc->mux_num = nitems(ls1046a_mux_nodes); 249 sc->init_func = ls1046a_fman_init; 250 sc->flags = 0; 251 252 return (qoriq_clkgen_attach(dev)); 253 } 254