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