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);
Cache object: 44c3f472c73723d5ddc716a3bbc8f956
|