1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 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 #include <sys/param.h> 36 #include <sys/bus.h> 37 #include <sys/kernel.h> 38 #include <sys/module.h> 39 #include <sys/mutex.h> 40 #include <sys/rman.h> 41 #include <machine/bus.h> 42 43 #include <dev/fdt/simplebus.h> 44 45 #include <dev/ofw/ofw_bus.h> 46 #include <dev/ofw/ofw_bus_subr.h> 47 48 #include <dev/extres/clk/clk_fixed.h> 49 50 #include <arm64/qoriq/clk/qoriq_clkgen.h> 51 52 static uint8_t ls1088a_pltfrm_pll_divs[] = { 53 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0 54 }; 55 56 static struct qoriq_clk_pll_def ls1088a_pltfrm_pll = { 57 .clkdef = { 58 .name = "ls1088a_platform_pll", 59 .id = QORIQ_CLK_ID(QORIQ_TYPE_PLATFORM_PLL, 0), 60 .flags = 0 61 }, 62 .offset = 0x60080, 63 .shift = 1, 64 .mask = 0xFE, 65 .dividers = ls1088a_pltfrm_pll_divs, 66 .flags = QORIQ_CLK_PLL_HAS_KILL_BIT 67 }; 68 69 static const uint8_t ls1088a_cga_pll_divs[] = { 70 2, 3, 4, 0 71 }; 72 73 static struct qoriq_clk_pll_def ls1088a_cga_pll1 = { 74 .clkdef = { 75 .name = "ls1088a_cga_pll1", 76 .id = QORIQ_CLK_ID(QORIQ_TYPE_INTERNAL, 0), 77 .flags = 0 78 }, 79 .offset = 0x80, 80 .shift = 1, 81 .mask = 0xFE, 82 .dividers = ls1088a_cga_pll_divs, 83 .flags = QORIQ_CLK_PLL_HAS_KILL_BIT 84 }; 85 86 static struct qoriq_clk_pll_def ls1088a_cga_pll2 = { 87 .clkdef = { 88 .name = "ls1088a_cga_pll2", 89 .id = QORIQ_CLK_ID(QORIQ_TYPE_INTERNAL, 20), 90 .flags = 0 91 }, 92 .offset = 0xA0, 93 .shift = 1, 94 .mask = 0xFE, 95 .dividers = ls1088a_cga_pll_divs, 96 .flags = QORIQ_CLK_PLL_HAS_KILL_BIT 97 }; 98 99 static struct qoriq_clk_pll_def *ls1088a_cga_plls[] = { 100 &ls1088a_cga_pll1, 101 &ls1088a_cga_pll2 102 }; 103 104 105 /* 4.7.2 Core Cluster a Clock Control/Status Register (CLKC1CSR - CLKC2CSR) */ 106 static const char *ls1088a_cmux0_parent_names[] = { 107 "ls1088a_cga_pll1", 108 "ls1088a_cga_pll1_div2", 109 "ls1088a_cga_pll1_div4", 110 NULL, 111 "ls1088a_cga_pll2", 112 "ls1088a_cga_pll2_div2", 113 "ls1088a_cga_pll2_div4" 114 }; 115 116 static struct clk_mux_def ls1088a_cmux0 = { 117 .clkdef = { 118 .name = "ls1088a_cmux0", 119 .id = QORIQ_CLK_ID(QORIQ_TYPE_CMUX, 0), 120 .parent_names = ls1088a_cmux0_parent_names, 121 .parent_cnt = nitems(ls1088a_cmux0_parent_names), 122 .flags = 0 123 }, 124 .offset = 0x70000, 125 .shift = 27, 126 .width = 4, 127 .mux_flags = 0 128 }; 129 130 static struct clk_mux_def ls1088a_cmux1 = { 131 .clkdef = { 132 .name = "ls1088a_cmux1", 133 .id = QORIQ_CLK_ID(QORIQ_TYPE_CMUX, 1), 134 .parent_names = ls1088a_cmux0_parent_names, 135 .parent_cnt = nitems(ls1088a_cmux0_parent_names), 136 .flags = 0 137 }, 138 .offset = 0x70020, 139 .shift = 27, 140 .width = 4, 141 .mux_flags = 0 142 }; 143 144 /* 4.4.2 HWAaCSR (HWA1CSR - HWA3CSR) */ 145 static const char *ls1088a_hwaccel1_parent_names[] = { 146 "ls1088a_platform_pll", 147 "ls1088a_cga_pll1", 148 "ls1088a_cga_pll1_div2", 149 "ls1088a_cga_pll1_div3", 150 "ls1088a_cga_pll1_div4", 151 NULL, /* HWAMUX1 External Clock Source */ 152 "ls1088a_cga_pll2_div2", 153 "ls1088a_cga_pll2_div3" 154 }; 155 156 static const char *ls1088a_hwaccel2_parent_names[] = { 157 "ls1088a_platform_pll", 158 "ls1088a_cga_pll2", 159 "ls1088a_cga_pll2_div2", 160 "ls1088a_cga_pll2_div3", 161 "ls1088a_cga_pll2_div4", 162 NULL, /* HWAMUX2 External Clock Source */ 163 "ls1088a_cga_pll1_div2", 164 "ls1088a_cga_pll1_div3" 165 }; 166 167 static const char *ls1088a_hwaccel3_parent_names[] = { 168 "ls1088a_platform_pll", 169 NULL, 170 NULL, 171 NULL, 172 NULL, 173 NULL, /* HWAMUX3 External Clock Source */ 174 "ls1088a_cga_pll2_div2", 175 "ls1088a_cga_pll2_div3" 176 }; 177 178 static struct clk_mux_def ls1088a_hwaccel1 = { 179 .clkdef = { 180 .name = "ls1088a_hwaccel1", 181 .id = QORIQ_CLK_ID(QORIQ_TYPE_HWACCEL, 0), 182 .parent_names = ls1088a_hwaccel1_parent_names, 183 .parent_cnt = nitems(ls1088a_hwaccel1_parent_names), 184 .flags = 0 185 }, 186 .offset = 0x10, 187 .shift = 27, 188 .width = 4, 189 .mux_flags = 0 190 }; 191 192 static struct clk_mux_def ls1088a_hwaccel2 = { 193 .clkdef = { 194 .name = "ls1088a_hwaccel2", 195 .id = QORIQ_CLK_ID(QORIQ_TYPE_HWACCEL, 1), 196 .parent_names = ls1088a_hwaccel2_parent_names, 197 .parent_cnt = nitems(ls1088a_hwaccel2_parent_names), 198 .flags = 0 199 }, 200 .offset = 0x30, 201 .shift = 27, 202 .width = 4, 203 .mux_flags = 0 204 }; 205 206 static struct clk_mux_def ls1088a_hwaccel3 = { 207 .clkdef = { 208 .name = "ls1088a_hwaccel3", 209 .id = QORIQ_CLK_ID(QORIQ_TYPE_HWACCEL, 2), 210 .parent_names = ls1088a_hwaccel3_parent_names, 211 .parent_cnt = nitems(ls1088a_hwaccel3_parent_names), 212 .flags = 0 213 }, 214 .offset = 0x50, 215 .shift = 27, 216 .width = 4, 217 .mux_flags = 0 218 }; 219 220 221 static struct clk_mux_def *ls1088a_mux_nodes[] = { 222 &ls1088a_cmux0, 223 &ls1088a_cmux1, 224 &ls1088a_hwaccel1, 225 &ls1088a_hwaccel2, 226 &ls1088a_hwaccel3 227 }; 228 229 static int 230 ls1088a_clkgen_probe(device_t dev) 231 { 232 233 if (!ofw_bus_status_okay(dev)) 234 return (ENXIO); 235 236 if(!ofw_bus_is_compatible(dev, "fsl,ls1088a-clockgen")) 237 return (ENXIO); 238 239 device_set_desc(dev, "LS1088A clockgen"); 240 return (BUS_PROBE_DEFAULT); 241 } 242 243 static int 244 ls1088a_clkgen_attach(device_t dev) 245 { 246 struct qoriq_clkgen_softc *sc; 247 248 sc = device_get_softc(dev); 249 250 sc->pltfrm_pll_def = &ls1088a_pltfrm_pll; 251 sc->cga_pll = ls1088a_cga_plls; 252 sc->cga_pll_num = nitems(ls1088a_cga_plls); 253 sc->mux = ls1088a_mux_nodes; 254 sc->mux_num = nitems(ls1088a_mux_nodes); 255 sc->flags = QORIQ_LITTLE_ENDIAN; 256 257 return (qoriq_clkgen_attach(dev)); 258 } 259 260 static device_method_t ls1088a_clkgen_methods[] = { 261 DEVMETHOD(device_probe, ls1088a_clkgen_probe), 262 DEVMETHOD(device_attach, ls1088a_clkgen_attach), 263 264 DEVMETHOD_END 265 }; 266 267 DEFINE_CLASS_1(ls1088a_clkgen, ls1088a_clkgen_driver, ls1088a_clkgen_methods, 268 sizeof(struct qoriq_clkgen_softc), qoriq_clkgen_driver); 269 270 EARLY_DRIVER_MODULE(ls1088a_clkgen, simplebus, ls1088a_clkgen_driver, 0, 0, 271 BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); 272