1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2021 Alstom Group.
5 * Copyright (c) 2021 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/clk/clk_fixed.h>
43
44 #include <arm64/qoriq/clk/qoriq_clkgen.h>
45
46 static uint8_t ls1028a_pltfrm_pll_divs[] = {
47 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0
48 };
49
50 static struct qoriq_clk_pll_def ls1028a_pltfrm_pll = {
51 .clkdef = {
52 .name = "ls1028a_platform_pll",
53 .id = QORIQ_CLK_ID(QORIQ_TYPE_PLATFORM_PLL, 0),
54 .flags = 0
55 },
56 .offset = 0x60080,
57 .shift = 1,
58 .mask = 0xFE,
59 .dividers = ls1028a_pltfrm_pll_divs,
60 .flags = QORIQ_CLK_PLL_HAS_KILL_BIT
61 };
62
63 static const uint8_t ls1028a_cga_pll_divs[] = {
64 2, 3, 4, 0
65 };
66
67 static struct qoriq_clk_pll_def ls1028a_cga_pll1 = {
68 .clkdef = {
69 .name = "ls1028a_cga_pll1",
70 .id = QORIQ_CLK_ID(QORIQ_TYPE_INTERNAL, 0),
71 .flags = 0
72 },
73 .offset = 0x80,
74 .shift = 1,
75 .mask = 0xFE,
76 .dividers = ls1028a_cga_pll_divs,
77 .flags = QORIQ_CLK_PLL_HAS_KILL_BIT
78 };
79
80 static struct qoriq_clk_pll_def ls1028a_cga_pll2 = {
81 .clkdef = {
82 .name = "ls1028a_cga_pll2",
83 .id = QORIQ_CLK_ID(QORIQ_TYPE_INTERNAL, 20),
84 .flags = 0
85 },
86 .offset = 0xA0,
87 .shift = 1,
88 .mask = 0xFE,
89 .dividers = ls1028a_cga_pll_divs,
90 .flags = QORIQ_CLK_PLL_HAS_KILL_BIT
91 };
92
93 static struct qoriq_clk_pll_def *ls1028a_cga_plls[] = {
94 &ls1028a_cga_pll1,
95 &ls1028a_cga_pll2
96 };
97
98 static const char *ls1028a_cmux0_parent_names[] = {
99 "ls1028a_cga_pll1",
100 "ls1028a_cga_pll1_div2",
101 "ls1028a_cga_pll1_div4",
102 NULL,
103 "ls1028a_cga_pll2",
104 "ls1028a_cga_pll2_div2",
105 "ls1028a_cga_pll2_div4"
106 };
107
108 static struct clk_mux_def ls1028a_cmux0 = {
109 .clkdef = {
110 .name = "ls1028a_cmux0",
111 .id = QORIQ_CLK_ID(QORIQ_TYPE_CMUX, 0),
112 .parent_names = ls1028a_cmux0_parent_names,
113 .parent_cnt = nitems(ls1028a_cmux0_parent_names),
114 .flags = 0
115 },
116 .offset = 0x70000,
117 .shift = 27,
118 .width = 4,
119 .mux_flags = 0
120 };
121
122 static struct clk_mux_def ls1028a_cmux1 = {
123 .clkdef = {
124 .name = "ls1028a_cmux1",
125 .id = QORIQ_CLK_ID(QORIQ_TYPE_CMUX, 1),
126 .parent_names = ls1028a_cmux0_parent_names,
127 .parent_cnt = nitems(ls1028a_cmux0_parent_names),
128 .flags = 0
129 },
130 .offset = 0x70020,
131 .shift = 27,
132 .width = 4,
133 .mux_flags = 0
134 };
135
136 static struct clk_mux_def ls1028a_cmux2 = {
137 .clkdef = {
138 .name = "ls1028a_cmux2",
139 .id = QORIQ_CLK_ID(QORIQ_TYPE_CMUX, 2),
140 .parent_names = ls1028a_cmux0_parent_names,
141 .parent_cnt = nitems(ls1028a_cmux0_parent_names),
142 .flags = 0
143 },
144 .offset = 0x70040,
145 .shift = 27,
146 .width = 4,
147 .mux_flags = 0
148 };
149
150 static struct clk_mux_def ls1028a_cmux3 = {
151 .clkdef = {
152 .name = "ls1028a_cmux3",
153 .id = QORIQ_CLK_ID(QORIQ_TYPE_CMUX, 3),
154 .parent_names = ls1028a_cmux0_parent_names,
155 .parent_cnt = nitems(ls1028a_cmux0_parent_names),
156 .flags = 0
157 },
158 .offset = 0x70060,
159 .shift = 27,
160 .width = 4,
161 .mux_flags = 0
162 };
163
164 static const char *ls1028a_hwaccel1_parent_names[] = {
165 "ls1028a_platform_pll",
166 "ls1028a_cga_pll1",
167 "ls1028a_cga_pll1_div2",
168 "ls1028a_cga_pll1_div3",
169 "ls1028a_cga_pll1_div4",
170 NULL,
171 "ls1028a_cga_pll2_div2",
172 "ls1028a_cga_pll2_div3"
173 };
174
175 static const char *ls1028a_hwaccel2_parent_names[] = {
176 "ls1028a_platform_pll",
177 "ls1028a_cga_pll2",
178 "ls1028a_cga_pll2_div2",
179 "ls1028a_cga_pll2_div3",
180 "ls1028a_cga_pll2_div4",
181 NULL,
182 "ls1028a_cga_pll1_div2",
183 "ls1028a_cga_pll1_div3"
184 };
185
186 static struct clk_mux_def ls1028a_hwaccel1 = {
187 .clkdef = {
188 .name = "ls1028a_hwaccel1",
189 .id = QORIQ_CLK_ID(QORIQ_TYPE_HWACCEL, 0),
190 .parent_names = ls1028a_hwaccel1_parent_names,
191 .parent_cnt = nitems(ls1028a_hwaccel1_parent_names),
192 .flags = 0
193 },
194 .offset = 0x10,
195 .shift = 27,
196 .width = 4,
197 .mux_flags = 0
198 };
199
200 static struct clk_mux_def ls1028a_hwaccel2 = {
201 .clkdef = {
202 .name = "ls1028a_hwaccel2",
203 .id = QORIQ_CLK_ID(QORIQ_TYPE_HWACCEL, 1),
204 .parent_names = ls1028a_hwaccel2_parent_names,
205 .parent_cnt = nitems(ls1028a_hwaccel2_parent_names),
206 .flags = 0
207 },
208 .offset = 0x30,
209 .shift = 27,
210 .width = 4,
211 .mux_flags = 0
212 };
213
214 static struct clk_mux_def ls1028a_hwaccel3 = {
215 .clkdef = {
216 .name = "ls1028a_hwaccel3",
217 .id = QORIQ_CLK_ID(QORIQ_TYPE_HWACCEL, 2),
218 .parent_names = ls1028a_hwaccel1_parent_names,
219 .parent_cnt = nitems(ls1028a_hwaccel1_parent_names),
220 .flags = 0
221 },
222 .offset = 0x50,
223 .shift = 27,
224 .width = 4,
225 .mux_flags = 0
226 };
227
228 static struct clk_mux_def ls1028a_hwaccel4 = {
229 .clkdef = {
230 .name = "ls1028a_hwaccel4",
231 .id = QORIQ_CLK_ID(QORIQ_TYPE_HWACCEL, 3),
232 .parent_names = ls1028a_hwaccel2_parent_names,
233 .parent_cnt = nitems(ls1028a_hwaccel2_parent_names),
234 .flags = 0
235 },
236 .offset = 0x70,
237 .shift = 27,
238 .width = 4,
239 .mux_flags = 0
240 };
241
242 static struct clk_mux_def *ls1028a_mux_nodes[] = {
243 &ls1028a_cmux0,
244 &ls1028a_cmux1,
245 &ls1028a_cmux2,
246 &ls1028a_cmux3,
247 &ls1028a_hwaccel1,
248 &ls1028a_hwaccel2,
249 &ls1028a_hwaccel3,
250 &ls1028a_hwaccel4
251 };
252
253 static int ls1028a_clkgen_probe(device_t);
254 static int ls1028a_clkgen_attach(device_t);
255
256 static device_method_t ls1028a_clkgen_methods[] = {
257 DEVMETHOD(device_probe, ls1028a_clkgen_probe),
258 DEVMETHOD(device_attach, ls1028a_clkgen_attach),
259
260 DEVMETHOD_END
261 };
262
263 DEFINE_CLASS_1(ls1028a_clkgen, ls1028a_clkgen_driver, ls1028a_clkgen_methods,
264 sizeof(struct qoriq_clkgen_softc), qoriq_clkgen_driver);
265
266 EARLY_DRIVER_MODULE(ls1028a_clkgen, simplebus, ls1028a_clkgen_driver, 0, 0,
267 BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);
268
269 static int
ls1028a_clkgen_probe(device_t dev)270 ls1028a_clkgen_probe(device_t dev)
271 {
272
273 if (!ofw_bus_status_okay(dev))
274 return (ENXIO);
275
276 if(!ofw_bus_is_compatible(dev, "fsl,ls1028a-clockgen"))
277 return (ENXIO);
278
279 device_set_desc(dev, "LS1028A clockgen");
280 return (BUS_PROBE_DEFAULT);
281 }
282
283 static int
ls1028a_clkgen_attach(device_t dev)284 ls1028a_clkgen_attach(device_t dev)
285 {
286 struct qoriq_clkgen_softc *sc;
287
288 sc = device_get_softc(dev);
289
290 sc->pltfrm_pll_def = &ls1028a_pltfrm_pll;
291 sc->cga_pll = ls1028a_cga_plls;
292 sc->cga_pll_num = nitems(ls1028a_cga_plls);
293 sc->mux = ls1028a_mux_nodes;
294 sc->mux_num = nitems(ls1028a_mux_nodes);
295 sc->flags = QORIQ_LITTLE_ENDIAN;
296
297 return (qoriq_clkgen_attach(dev));
298 }
299