xref: /freebsd/sys/arm/mv/clk/periph_clk_d.c (revision cc68614da8232d8baaca0ae0d0dd8f890f06623e)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2021 Semihalf.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30 
31 #include <sys/param.h>
32 #include <sys/bus.h>
33 #include <sys/kernel.h>
34 #include <sys/module.h>
35 #include <sys/mutex.h>
36 #include <sys/rman.h>
37 #include <machine/bus.h>
38 
39 #include <dev/fdt/simplebus.h>
40 
41 #include <dev/extres/clk/clk.h>
42 #include <dev/extres/clk/clk_div.h>
43 #include <dev/extres/clk/clk_fixed.h>
44 #include <dev/extres/clk/clk_gate.h>
45 #include <dev/extres/clk/clk_mux.h>
46 
47 #include <dev/ofw/ofw_bus.h>
48 #include <dev/ofw/ofw_bus_subr.h>
49 
50 #include "clkdev_if.h"
51 #include "periph.h"
52 
53 #define PARENT_CNT	2
54 
55 /*
56  * Register chain: mux (select proper TBG) -> div1 (first frequency divider) ->
57  * div2 (second frequency divider) -> mux (select divided freq.
58  * or xtal output) -> gate (enable or disable clock), which is also final node
59  */
60 
61 int
62 a37x0_periph_d_register_full_clk_dd(struct clkdom *clkdom,
63     struct a37x0_periph_clknode_def *device_def)
64 {
65 	const char *parent_names[PARENT_CNT];
66 	struct clk_mux_def *clk_mux;
67 	struct clk_mux_def *tbg_mux;
68 	struct clk_gate_def *gate;
69 	struct clk_div_def *div1;
70 	struct clk_div_def *div2;
71 	const char *dev_name;
72 	int error, dev_id;
73 
74 	dev_id = device_def->common_def.device_id;
75 	dev_name = device_def->common_def.device_name;
76 	tbg_mux = &device_def->clk_def.full_dd.tbg_mux;
77 	div1 = &device_def->clk_def.full_dd.div1;
78 	div2 = &device_def->clk_def.full_dd.div2;
79 	gate = &device_def->clk_def.full_dd.gate;
80 	clk_mux = &device_def->clk_def.full_dd.clk_mux;
81 
82 	a37x0_periph_set_props(&tbg_mux->clkdef, device_def->common_def.tbgs,
83 	    device_def->common_def.tbg_cnt);
84 
85 	error = a37x0_periph_create_mux(clkdom,
86 	    tbg_mux, A37x0_INTERNAL_CLK_ID(dev_id, MUX_POS));
87 	if (error)
88 		goto fail;
89 
90 	a37x0_periph_set_props(&div1->clkdef, &tbg_mux->clkdef.name, 1);
91 	error = a37x0_periph_create_div(clkdom, div1,
92 	    A37x0_INTERNAL_CLK_ID(dev_id, DIV1_POS));
93 	if (error)
94 		goto fail;
95 
96 	a37x0_periph_set_props(&div2->clkdef, &div1->clkdef.name, 1);
97 	error = a37x0_periph_create_div(clkdom, div2,
98 	    A37x0_INTERNAL_CLK_ID(dev_id, DIV2_POS));
99 	if (error)
100 		goto fail;
101 
102 	parent_names[0] = device_def->common_def.xtal;
103 	parent_names[1] = div2->clkdef.name;
104 
105 	a37x0_periph_set_props(&clk_mux->clkdef, parent_names, PARENT_CNT);
106 	error = a37x0_periph_create_mux(clkdom, clk_mux,
107 	    A37x0_INTERNAL_CLK_ID(dev_id, CLK_MUX_POS));
108 	if (error)
109 		goto fail;
110 
111 	a37x0_periph_set_props(&gate->clkdef, &clk_mux->clkdef.name, 1);
112 	error = a37x0_periph_create_gate(clkdom, gate,
113 	    dev_id);
114 	if (error)
115 		goto fail;
116 
117 fail:
118 
119 	return (error);
120 }
121 
122 /*
123  * Register chain: mux (select proper TBG) -> div1 (first frequency divider) ->
124  * mux (select divided freq. or xtal output) -> gate (enable or disable clock),
125  * which is also final node
126  */
127 
128 int
129 a37x0_periph_d_register_full_clk(struct clkdom *clkdom,
130     struct a37x0_periph_clknode_def *device_def)
131 {
132 	const char *parent_names[PARENT_CNT];
133 	struct clk_mux_def *tbg_mux;
134 	struct clk_mux_def *clk_mux;
135 	struct clk_gate_def *gate;
136 	struct clk_div_def *div;
137 	const char *dev_name;
138 	int error, dev_id;
139 
140 	dev_id = device_def->common_def.device_id;
141 	dev_name = device_def->common_def.device_name;
142 	tbg_mux = &device_def->clk_def.full_d.tbg_mux;
143 	div = &device_def->clk_def.full_d.div;
144 	gate = &device_def->clk_def.full_d.gate;
145 	clk_mux = &device_def->clk_def.full_d. clk_mux;
146 
147 	a37x0_periph_set_props(&tbg_mux->clkdef, device_def->common_def.tbgs,
148 	    device_def->common_def.tbg_cnt);
149 	error = a37x0_periph_create_mux(clkdom, tbg_mux,
150 	    A37x0_INTERNAL_CLK_ID(device_def->common_def.device_id, MUX_POS));
151 	if (error)
152 		goto fail;
153 
154 	a37x0_periph_set_props(&div->clkdef, &tbg_mux->clkdef.name, 1);
155 	error = a37x0_periph_create_div(clkdom, div,
156 	    A37x0_INTERNAL_CLK_ID(device_def->common_def.device_id, DIV1_POS));
157 	if (error)
158 		goto fail;
159 
160 	parent_names[0] = device_def->common_def.xtal;
161 	parent_names[1] = div->clkdef.name;
162 
163 	a37x0_periph_set_props(&clk_mux->clkdef, parent_names, PARENT_CNT);
164 	error = a37x0_periph_create_mux(clkdom, clk_mux,
165 	    A37x0_INTERNAL_CLK_ID(dev_id, CLK_MUX_POS));
166 	if (error)
167 		goto fail;
168 
169 	a37x0_periph_set_props(&gate->clkdef, &clk_mux->clkdef.name, 1);
170 	error = a37x0_periph_create_gate(clkdom, gate,
171 	    dev_id);
172 	if (error)
173 		goto fail;
174 
175 fail:
176 
177 	return (error);
178 }
179 
180 /*
181  * Register CPU clock. It consists of mux (select proper TBG) -> div (frequency
182  * divider) -> mux (choose divided or xtal output).
183  */
184 
185 int
186 a37x0_periph_d_register_periph_cpu(struct clkdom *clkdom,
187     struct a37x0_periph_clknode_def *device_def)
188 {
189 	const char *parent_names[PARENT_CNT];
190 	struct clk_mux_def *clk_mux;
191 	struct clk_mux_def *tbg_mux;
192 	struct clk_div_def *div;
193 	const char *dev_name;
194 	int error, dev_id;
195 
196 	dev_name = device_def->common_def.device_name;
197 	dev_id = device_def->common_def.device_id;
198 	tbg_mux = &device_def->clk_def.cpu.tbg_mux;
199 	div = &device_def->clk_def.cpu.div;
200 	clk_mux = &device_def->clk_def.cpu.clk_mux;
201 
202 	a37x0_periph_set_props(&tbg_mux->clkdef, device_def->common_def.tbgs,
203 	    device_def->common_def.tbg_cnt);
204 	error = a37x0_periph_create_mux(clkdom, tbg_mux,
205 	    A37x0_INTERNAL_CLK_ID(dev_id, MUX_POS));
206 	if (error)
207 		goto fail;
208 
209 	a37x0_periph_set_props(&div->clkdef, &tbg_mux->clkdef.name, 1);
210 	error = a37x0_periph_create_div(clkdom, div,
211 	    A37x0_INTERNAL_CLK_ID(dev_id, DIV1_POS));
212 	if (error)
213 		goto fail;
214 
215 	parent_names[0] = device_def->common_def.xtal;
216 	parent_names[1] = div->clkdef.name;
217 
218 	a37x0_periph_set_props(&clk_mux->clkdef, parent_names, PARENT_CNT);
219 	error = a37x0_periph_create_mux(clkdom, clk_mux,
220 	    dev_id);
221 
222 fail:
223 
224 	return (error);
225 }
226 
227 /*
228  * Register chain: mux (choose proper TBG) -> div1 (first frequency divider) ->
229  * div2 (second frequency divider) -> mux (choose divided or xtal output).
230  */
231 int
232 a37x0_periph_d_register_mdd(struct clkdom *clkdom,
233     struct a37x0_periph_clknode_def *device_def)
234 {
235 	const char *parent_names[PARENT_CNT];
236 	struct clk_mux_def *tbg_mux;
237 	struct clk_mux_def *clk_mux;
238 	struct clk_div_def *div1;
239 	struct clk_div_def *div2;
240 	const char * dev_name;
241 	int error, dev_id;
242 
243 	dev_name = device_def->common_def.device_name;
244 	dev_id = device_def->common_def.device_id;
245 	tbg_mux = &device_def->clk_def.mdd.tbg_mux;
246 	div1 = &device_def->clk_def.mdd.div1;
247 	div2 = &device_def->clk_def.mdd.div2;
248 	clk_mux = &device_def->clk_def.mdd.clk_mux;
249 
250 	a37x0_periph_set_props(&tbg_mux->clkdef, device_def->common_def.tbgs,
251 	    device_def->common_def.tbg_cnt);
252 	error = a37x0_periph_create_mux(clkdom, tbg_mux,
253 	    A37x0_INTERNAL_CLK_ID(dev_id, MUX_POS));
254 	if (error)
255 		goto fail;
256 
257 	a37x0_periph_set_props(&div1->clkdef, &tbg_mux->clkdef.name, 1);
258 	error = a37x0_periph_create_div(clkdom, div1,
259 	    A37x0_INTERNAL_CLK_ID(dev_id, DIV1_POS));
260 	if (error)
261 		goto fail;
262 
263 	a37x0_periph_set_props(&div2->clkdef, &div1->clkdef.name, 1);
264 	error = a37x0_periph_create_div(clkdom, div2,
265 	    A37x0_INTERNAL_CLK_ID(dev_id, DIV2_POS));
266 
267 	if (error)
268 		goto fail;
269 
270 	parent_names[0] = device_def->common_def.xtal;
271 	parent_names[1] = div2->clkdef.name;
272 
273 	a37x0_periph_set_props(&clk_mux->clkdef, parent_names, PARENT_CNT);
274 	error = a37x0_periph_create_mux(clkdom, clk_mux,
275 	    dev_id);
276 	if (error)
277 		goto fail;
278 
279 fail:
280 
281 	return (error);
282 }
283