1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2021 Alstom Group. 5 * Copyright (c) 2021 Semihalf. 6 * Copyright (c) 2022 Bjoern A. Zeeb 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 /* 30 * Based on QorIQ LS1088A Reference Manual, Rev. 1, 11/2020. 31 * [LS1088ARM.pdf] 32 */ 33 34 #include <sys/cdefs.h> 35 __FBSDID("$FreeBSD$"); 36 37 #include <sys/param.h> 38 #include <sys/bus.h> 39 #include <sys/kernel.h> 40 #include <sys/module.h> 41 #include <sys/mutex.h> 42 #include <sys/rman.h> 43 #include <machine/bus.h> 44 45 #include <dev/fdt/simplebus.h> 46 47 #include <dev/ofw/ofw_bus.h> 48 #include <dev/ofw/ofw_bus_subr.h> 49 50 #include <dev/extres/clk/clk_fixed.h> 51 52 #include <arm64/qoriq/clk/qoriq_clkgen.h> 53 54 static uint8_t ls1088a_pltfrm_pll_divs[] = { 55 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0 56 }; 57 58 static struct qoriq_clk_pll_def ls1088a_pltfrm_pll = { 59 .clkdef = { 60 .name = "ls1088a_platform_pll", 61 .id = QORIQ_CLK_ID(QORIQ_TYPE_PLATFORM_PLL, 0), 62 .flags = 0 63 }, 64 .offset = 0x60080, 65 .shift = 1, 66 .mask = 0xFE, 67 .dividers = ls1088a_pltfrm_pll_divs, 68 .flags = QORIQ_CLK_PLL_HAS_KILL_BIT 69 }; 70 71 static const uint8_t ls1088a_cga_pll_divs[] = { 72 2, 3, 4, 0 73 }; 74 75 static struct qoriq_clk_pll_def ls1088a_cga_pll1 = { 76 .clkdef = { 77 .name = "ls1088a_cga_pll1", 78 .id = QORIQ_CLK_ID(QORIQ_TYPE_INTERNAL, 0), 79 .flags = 0 80 }, 81 .offset = 0x80, 82 .shift = 1, 83 .mask = 0xFE, 84 .dividers = ls1088a_cga_pll_divs, 85 .flags = QORIQ_CLK_PLL_HAS_KILL_BIT 86 }; 87 88 static struct qoriq_clk_pll_def ls1088a_cga_pll2 = { 89 .clkdef = { 90 .name = "ls1088a_cga_pll2", 91 .id = QORIQ_CLK_ID(QORIQ_TYPE_INTERNAL, 20), 92 .flags = 0 93 }, 94 .offset = 0xA0, 95 .shift = 1, 96 .mask = 0xFE, 97 .dividers = ls1088a_cga_pll_divs, 98 .flags = QORIQ_CLK_PLL_HAS_KILL_BIT 99 }; 100 101 static struct qoriq_clk_pll_def *ls1088a_cga_plls[] = { 102 &ls1088a_cga_pll1, 103 &ls1088a_cga_pll2 104 }; 105 106 107 /* 4.7.2 Core Cluster a Clock Control/Status Register (CLKC1CSR - CLKC2CSR) */ 108 static const char *ls1088a_cmux0_parent_names[] = { 109 "ls1088a_cga_pll1", 110 "ls1088a_cga_pll1_div2", 111 "ls1088a_cga_pll1_div4", 112 NULL, 113 "ls1088a_cga_pll2", 114 "ls1088a_cga_pll2_div2", 115 "ls1088a_cga_pll2_div4" 116 }; 117 118 static struct clk_mux_def ls1088a_cmux0 = { 119 .clkdef = { 120 .name = "ls1088a_cmux0", 121 .id = QORIQ_CLK_ID(QORIQ_TYPE_CMUX, 0), 122 .parent_names = ls1088a_cmux0_parent_names, 123 .parent_cnt = nitems(ls1088a_cmux0_parent_names), 124 .flags = 0 125 }, 126 .offset = 0x70000, 127 .shift = 27, 128 .width = 4, 129 .mux_flags = 0 130 }; 131 132 static struct clk_mux_def ls1088a_cmux1 = { 133 .clkdef = { 134 .name = "ls1088a_cmux1", 135 .id = QORIQ_CLK_ID(QORIQ_TYPE_CMUX, 1), 136 .parent_names = ls1088a_cmux0_parent_names, 137 .parent_cnt = nitems(ls1088a_cmux0_parent_names), 138 .flags = 0 139 }, 140 .offset = 0x70020, 141 .shift = 27, 142 .width = 4, 143 .mux_flags = 0 144 }; 145 146 /* 4.4.2 HWAaCSR (HWA1CSR - HWA3CSR) */ 147 static const char *ls1088a_hwaccel1_parent_names[] = { 148 "ls1088a_platform_pll", 149 "ls1088a_cga_pll1", 150 "ls1088a_cga_pll1_div2", 151 "ls1088a_cga_pll1_div3", 152 "ls1088a_cga_pll1_div4", 153 NULL, /* HWAMUX1 External Clock Source */ 154 "ls1088a_cga_pll2_div2", 155 "ls1088a_cga_pll2_div3" 156 }; 157 158 static const char *ls1088a_hwaccel2_parent_names[] = { 159 "ls1088a_platform_pll", 160 "ls1088a_cga_pll2", 161 "ls1088a_cga_pll2_div2", 162 "ls1088a_cga_pll2_div3", 163 "ls1088a_cga_pll2_div4", 164 NULL, /* HWAMUX2 External Clock Source */ 165 "ls1088a_cga_pll1_div2", 166 "ls1088a_cga_pll1_div3" 167 }; 168 169 static const char *ls1088a_hwaccel3_parent_names[] = { 170 "ls1088a_platform_pll", 171 NULL, 172 NULL, 173 NULL, 174 NULL, 175 NULL, /* HWAMUX3 External Clock Source */ 176 "ls1088a_cga_pll2_div2", 177 "ls1088a_cga_pll2_div3" 178 }; 179 180 static struct clk_mux_def ls1088a_hwaccel1 = { 181 .clkdef = { 182 .name = "ls1088a_hwaccel1", 183 .id = QORIQ_CLK_ID(QORIQ_TYPE_HWACCEL, 0), 184 .parent_names = ls1088a_hwaccel1_parent_names, 185 .parent_cnt = nitems(ls1088a_hwaccel1_parent_names), 186 .flags = 0 187 }, 188 .offset = 0x10, 189 .shift = 27, 190 .width = 4, 191 .mux_flags = 0 192 }; 193 194 static struct clk_mux_def ls1088a_hwaccel2 = { 195 .clkdef = { 196 .name = "ls1088a_hwaccel2", 197 .id = QORIQ_CLK_ID(QORIQ_TYPE_HWACCEL, 1), 198 .parent_names = ls1088a_hwaccel2_parent_names, 199 .parent_cnt = nitems(ls1088a_hwaccel2_parent_names), 200 .flags = 0 201 }, 202 .offset = 0x30, 203 .shift = 27, 204 .width = 4, 205 .mux_flags = 0 206 }; 207 208 static struct clk_mux_def ls1088a_hwaccel3 = { 209 .clkdef = { 210 .name = "ls1088a_hwaccel3", 211 .id = QORIQ_CLK_ID(QORIQ_TYPE_HWACCEL, 2), 212 .parent_names = ls1088a_hwaccel3_parent_names, 213 .parent_cnt = nitems(ls1088a_hwaccel3_parent_names), 214 .flags = 0 215 }, 216 .offset = 0x50, 217 .shift = 27, 218 .width = 4, 219 .mux_flags = 0 220 }; 221 222 223 static struct clk_mux_def *ls1088a_mux_nodes[] = { 224 &ls1088a_cmux0, 225 &ls1088a_cmux1, 226 &ls1088a_hwaccel1, 227 &ls1088a_hwaccel2, 228 &ls1088a_hwaccel3 229 }; 230 231 static int 232 ls1088a_clkgen_probe(device_t dev) 233 { 234 235 if (!ofw_bus_status_okay(dev)) 236 return (ENXIO); 237 238 if(!ofw_bus_is_compatible(dev, "fsl,ls1088a-clockgen")) 239 return (ENXIO); 240 241 device_set_desc(dev, "LS1088A clockgen"); 242 return (BUS_PROBE_DEFAULT); 243 } 244 245 static int 246 ls1088a_clkgen_attach(device_t dev) 247 { 248 struct qoriq_clkgen_softc *sc; 249 250 sc = device_get_softc(dev); 251 252 sc->pltfrm_pll_def = &ls1088a_pltfrm_pll; 253 sc->cga_pll = ls1088a_cga_plls; 254 sc->cga_pll_num = nitems(ls1088a_cga_plls); 255 sc->mux = ls1088a_mux_nodes; 256 sc->mux_num = nitems(ls1088a_mux_nodes); 257 sc->flags = QORIQ_LITTLE_ENDIAN; 258 259 return (qoriq_clkgen_attach(dev)); 260 } 261 262 static device_method_t ls1088a_clkgen_methods[] = { 263 DEVMETHOD(device_probe, ls1088a_clkgen_probe), 264 DEVMETHOD(device_attach, ls1088a_clkgen_attach), 265 266 DEVMETHOD_END 267 }; 268 269 DEFINE_CLASS_1(ls1088a_clkgen, ls1088a_clkgen_driver, ls1088a_clkgen_methods, 270 sizeof(struct qoriq_clkgen_softc), qoriq_clkgen_driver); 271 272 EARLY_DRIVER_MODULE(ls1088a_clkgen, simplebus, ls1088a_clkgen_driver, 0, 0, 273 BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); 274