xref: /freebsd/sys/arm64/qoriq/clk/ls1088a_clkgen.c (revision 4e8d558c)
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 __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