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