1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 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/param.h> 30 #include <sys/bus.h> 31 #include <sys/kernel.h> 32 #include <sys/module.h> 33 #include <sys/mutex.h> 34 #include <sys/rman.h> 35 #include <machine/bus.h> 36 37 #include <dev/fdt/simplebus.h> 38 39 #include <dev/ofw/ofw_bus.h> 40 #include <dev/ofw/ofw_bus_subr.h> 41 42 #include <dev/extres/clk/clk_fixed.h> 43 44 #include <arm64/qoriq/clk/qoriq_clkgen.h> 45 46 static uint8_t ls1046a_pltfrm_pll_divs[] = { 47 2, 4, 0 48 }; 49 50 static struct qoriq_clk_pll_def ls1046a_pltfrm_pll = { 51 .clkdef = { 52 .name = "ls1046a_platform_pll", 53 .id = QORIQ_CLK_ID(QORIQ_TYPE_PLATFORM_PLL, 0), 54 .flags = 0 55 }, 56 .offset = 0xC00, 57 .shift = 1, 58 .mask = 0x7E, 59 .dividers = ls1046a_pltfrm_pll_divs, 60 .flags = 0 61 }; 62 63 static const uint8_t ls1046a_cga1_pll_divs[] = { 64 2, 3, 4, 0 65 }; 66 67 static struct qoriq_clk_pll_def ls1046a_cga1_pll = { 68 .clkdef = { 69 .name = "ls1046a_cga_pll1", 70 .id = QORIQ_CLK_ID(QORIQ_TYPE_INTERNAL, 0), 71 .flags = 0 72 }, 73 .offset = 0x800, 74 .shift = 1, 75 .mask = 0x1FE, 76 .dividers = ls1046a_cga1_pll_divs, 77 .flags = QORIQ_CLK_PLL_HAS_KILL_BIT 78 }; 79 80 static struct qoriq_clk_pll_def ls1046a_cga2_pll = { 81 .clkdef = { 82 .name = "ls1046a_cga_pll2", 83 .id = QORIQ_CLK_ID(QORIQ_TYPE_INTERNAL, 20), 84 .flags = 0 85 }, 86 .offset = 0x820, 87 .shift = 1, 88 .mask = 0x1FE, 89 .dividers = ls1046a_cga1_pll_divs, 90 .flags = QORIQ_CLK_PLL_HAS_KILL_BIT 91 }; 92 93 static struct qoriq_clk_pll_def *ls1046a_cga_plls[] = { 94 &ls1046a_cga1_pll, 95 &ls1046a_cga2_pll 96 }; 97 98 static const char *ls1046a_cmux0_parent_names[] = { 99 "ls1046a_cga_pll1", 100 NULL, 101 "ls1046a_cga_pll1_div2", 102 NULL, 103 "ls1046a_cga_pll2", 104 NULL, 105 "ls1046a_cga_pll2_div2" 106 }; 107 108 static struct clk_mux_def ls1046a_cmux0 = { 109 .clkdef = { 110 .name = "ls1046a_cmux0", 111 .id = QORIQ_CLK_ID(QORIQ_TYPE_CMUX, 0), 112 .parent_names = ls1046a_cmux0_parent_names, 113 .parent_cnt = nitems(ls1046a_cmux0_parent_names), 114 .flags = 0 115 }, 116 .offset = 0, 117 .shift = 27, 118 .width = 4, 119 .mux_flags = 0 120 }; 121 122 static const char *ls1046a_hwaccel1_parent_names[] = { 123 NULL, 124 NULL, 125 "ls1046a_cga_pll1_div2", 126 "ls1046a_cga_pll1_div3", 127 "ls1046a_cga_pll1_div4", 128 "ls1046a_platform_pll", 129 "ls1046a_cga_pll2_div2", 130 "ls1046a_cga_pll2_div3" 131 }; 132 133 static const char *ls1046a_hwaccel2_parent_names[] = { 134 NULL, 135 "ls1046a_cga_pll2", 136 "ls1046a_cga_pll2_div2", 137 "ls1046a_cga_pll2_div3", 138 NULL, 139 NULL, 140 "ls1046a_cga_pll1_div2" 141 }; 142 143 static struct clk_mux_def ls1046a_hwaccel1 = { 144 .clkdef = { 145 .name = "ls1046a_hwaccel1", 146 .id = QORIQ_CLK_ID(QORIQ_TYPE_HWACCEL, 0), 147 .parent_names = ls1046a_hwaccel1_parent_names, 148 .parent_cnt = nitems(ls1046a_hwaccel1_parent_names), 149 .flags = 0 150 }, 151 .offset = 0x10, 152 .shift = 27, 153 .width = 4, 154 .mux_flags = 0 155 }; 156 157 static struct clk_mux_def ls1046a_hwaccel2 = { 158 .clkdef = { 159 .name = "ls1046a_hwaccel2", 160 .id = QORIQ_CLK_ID(QORIQ_TYPE_HWACCEL, 1), 161 .parent_names = ls1046a_hwaccel2_parent_names, 162 .parent_cnt = nitems(ls1046a_hwaccel2_parent_names), 163 .flags = 0 164 }, 165 .offset = 0x30, 166 .shift = 27, 167 .width = 4, 168 .mux_flags = 0 169 }; 170 171 static struct clk_mux_def *ls1046a_mux_nodes[] = { 172 &ls1046a_cmux0, 173 &ls1046a_hwaccel1, 174 &ls1046a_hwaccel2 175 }; 176 177 const char *ls1046a_fman_srcs[] = { 178 "ls1046a_hwaccel1" 179 }; 180 181 static int ls1046a_clkgen_probe(device_t); 182 static int ls1046a_clkgen_attach(device_t); 183 184 static device_method_t ls1046a_clkgen_methods[] = { 185 DEVMETHOD(device_probe, ls1046a_clkgen_probe), 186 DEVMETHOD(device_attach, ls1046a_clkgen_attach), 187 188 DEVMETHOD_END 189 }; 190 191 DEFINE_CLASS_1(ls1046a_clkgen, ls1046a_clkgen_driver, ls1046a_clkgen_methods, 192 sizeof(struct qoriq_clkgen_softc), qoriq_clkgen_driver); 193 194 EARLY_DRIVER_MODULE(ls1046a_clkgen, simplebus, ls1046a_clkgen_driver, 0, 0, 195 BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); 196 197 static int 198 ls1046a_fman_init(device_t dev) 199 { 200 struct qoriq_clkgen_softc *sc; 201 struct clk_fixed_def def; 202 int error; 203 204 sc = device_get_softc(dev); 205 206 def.clkdef.name = "ls1046a_fman", 207 def.clkdef.id = QORIQ_CLK_ID(QORIQ_TYPE_FMAN, 0), 208 def.clkdef.parent_names = ls1046a_fman_srcs; 209 def.clkdef.parent_cnt = nitems(ls1046a_fman_srcs); 210 def.clkdef.flags = 0; 211 def.freq = 0; 212 def.mult = 1; 213 def.div = 1; 214 def.fixed_flags = 0; 215 216 error = clknode_fixed_register(sc->clkdom, &def); 217 return (error); 218 } 219 220 static int 221 ls1046a_clkgen_probe(device_t dev) 222 { 223 224 if (!ofw_bus_status_okay(dev)) 225 return (ENXIO); 226 227 if(!ofw_bus_is_compatible(dev, "fsl,ls1046a-clockgen")) 228 return (ENXIO); 229 230 device_set_desc(dev, "LS1046A clockgen"); 231 return (BUS_PROBE_DEFAULT); 232 } 233 234 static int 235 ls1046a_clkgen_attach(device_t dev) 236 { 237 struct qoriq_clkgen_softc *sc; 238 239 sc = device_get_softc(dev); 240 241 sc->pltfrm_pll_def = &ls1046a_pltfrm_pll; 242 sc->cga_pll = ls1046a_cga_plls; 243 sc->cga_pll_num = nitems(ls1046a_cga_plls); 244 sc->mux = ls1046a_mux_nodes; 245 sc->mux_num = nitems(ls1046a_mux_nodes); 246 sc->init_func = ls1046a_fman_init; 247 sc->flags = 0; 248 249 return (qoriq_clkgen_attach(dev)); 250 } 251