xref: /freebsd/sys/dev/firmware/arm/scmi_clk.c (revision 54b96380f5774c1754a0fcf25212fa8e01db74f6)
1*54b96380SRuslan Bukin /*-
2*54b96380SRuslan Bukin  * SPDX-License-Identifier: BSD-2-Clause
3*54b96380SRuslan Bukin  *
4*54b96380SRuslan Bukin  * Copyright (c) 2022 Ruslan Bukin <br@bsdpad.com>
5*54b96380SRuslan Bukin  *
6*54b96380SRuslan Bukin  * This work was supported by Innovate UK project 105694, "Digital Security
7*54b96380SRuslan Bukin  * by Design (DSbD) Technology Platform Prototype".
8*54b96380SRuslan Bukin  *
9*54b96380SRuslan Bukin  * Redistribution and use in source and binary forms, with or without
10*54b96380SRuslan Bukin  * modification, are permitted provided that the following conditions
11*54b96380SRuslan Bukin  * are met:
12*54b96380SRuslan Bukin  * 1. Redistributions of source code must retain the above copyright
13*54b96380SRuslan Bukin  *    notice, this list of conditions and the following disclaimer.
14*54b96380SRuslan Bukin  * 2. Redistributions in binary form must reproduce the above copyright
15*54b96380SRuslan Bukin  *    notice, this list of conditions and the following disclaimer in the
16*54b96380SRuslan Bukin  *    documentation and/or other materials provided with the distribution.
17*54b96380SRuslan Bukin  *
18*54b96380SRuslan Bukin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19*54b96380SRuslan Bukin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20*54b96380SRuslan Bukin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21*54b96380SRuslan Bukin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22*54b96380SRuslan Bukin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23*54b96380SRuslan Bukin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24*54b96380SRuslan Bukin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25*54b96380SRuslan Bukin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26*54b96380SRuslan Bukin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27*54b96380SRuslan Bukin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28*54b96380SRuslan Bukin  * SUCH DAMAGE.
29*54b96380SRuslan Bukin  */
30*54b96380SRuslan Bukin 
31*54b96380SRuslan Bukin #include <sys/cdefs.h>
32*54b96380SRuslan Bukin __FBSDID("$FreeBSD$");
33*54b96380SRuslan Bukin 
34*54b96380SRuslan Bukin #include <sys/param.h>
35*54b96380SRuslan Bukin #include <sys/systm.h>
36*54b96380SRuslan Bukin #include <sys/bus.h>
37*54b96380SRuslan Bukin #include <sys/cpu.h>
38*54b96380SRuslan Bukin #include <sys/kernel.h>
39*54b96380SRuslan Bukin #include <sys/module.h>
40*54b96380SRuslan Bukin 
41*54b96380SRuslan Bukin #include <dev/extres/clk/clk.h>
42*54b96380SRuslan Bukin #include <dev/fdt/simplebus.h>
43*54b96380SRuslan Bukin #include <dev/fdt/fdt_common.h>
44*54b96380SRuslan Bukin #include <dev/ofw/ofw_bus_subr.h>
45*54b96380SRuslan Bukin 
46*54b96380SRuslan Bukin #include "scmi.h"
47*54b96380SRuslan Bukin #include "scmi_protocols.h"
48*54b96380SRuslan Bukin #include "scmi_clk.h"
49*54b96380SRuslan Bukin 
50*54b96380SRuslan Bukin struct scmi_clk_softc {
51*54b96380SRuslan Bukin 	device_t	dev;
52*54b96380SRuslan Bukin 	device_t	scmi;
53*54b96380SRuslan Bukin 	struct clkdom	*clkdom;
54*54b96380SRuslan Bukin };
55*54b96380SRuslan Bukin 
56*54b96380SRuslan Bukin struct scmi_clknode_softc {
57*54b96380SRuslan Bukin 	device_t	dev;
58*54b96380SRuslan Bukin 	int		clock_id;
59*54b96380SRuslan Bukin };
60*54b96380SRuslan Bukin 
61*54b96380SRuslan Bukin static int
62*54b96380SRuslan Bukin scmi_clk_get_rate(struct scmi_clk_softc *sc, int clk_id, uint64_t *rate)
63*54b96380SRuslan Bukin {
64*54b96380SRuslan Bukin 	struct scmi_clk_rate_get_out out;
65*54b96380SRuslan Bukin 	struct scmi_clk_rate_get_in in;
66*54b96380SRuslan Bukin 	struct scmi_req req;
67*54b96380SRuslan Bukin 	int error;
68*54b96380SRuslan Bukin 
69*54b96380SRuslan Bukin 	req.protocol_id = SCMI_PROTOCOL_ID_CLOCK;
70*54b96380SRuslan Bukin 	req.message_id = SCMI_CLOCK_RATE_GET;
71*54b96380SRuslan Bukin 	req.in_buf = &in;
72*54b96380SRuslan Bukin 	req.in_size = sizeof(struct scmi_clk_rate_get_in);
73*54b96380SRuslan Bukin 	req.out_buf = &out;
74*54b96380SRuslan Bukin 	req.out_size = sizeof(struct scmi_clk_rate_get_out);
75*54b96380SRuslan Bukin 
76*54b96380SRuslan Bukin 	in.clock_id = clk_id;
77*54b96380SRuslan Bukin 
78*54b96380SRuslan Bukin 	error = scmi_request(sc->scmi, &req);
79*54b96380SRuslan Bukin 	if (error != 0)
80*54b96380SRuslan Bukin 		return (error);
81*54b96380SRuslan Bukin 
82*54b96380SRuslan Bukin 	if (out.status != 0)
83*54b96380SRuslan Bukin 		return (ENXIO);
84*54b96380SRuslan Bukin 
85*54b96380SRuslan Bukin 	*rate = out.rate_lsb | ((uint64_t)out.rate_msb << 32);
86*54b96380SRuslan Bukin 
87*54b96380SRuslan Bukin 	return (0);
88*54b96380SRuslan Bukin }
89*54b96380SRuslan Bukin 
90*54b96380SRuslan Bukin static int
91*54b96380SRuslan Bukin scmi_clk_set_rate(struct scmi_clk_softc *sc, int clk_id, uint64_t rate)
92*54b96380SRuslan Bukin {
93*54b96380SRuslan Bukin 	struct scmi_clk_rate_set_out out;
94*54b96380SRuslan Bukin 	struct scmi_clk_rate_set_in in;
95*54b96380SRuslan Bukin 	struct scmi_req req;
96*54b96380SRuslan Bukin 	int error;
97*54b96380SRuslan Bukin 
98*54b96380SRuslan Bukin 	req.protocol_id = SCMI_PROTOCOL_ID_CLOCK;
99*54b96380SRuslan Bukin 	req.message_id = SCMI_CLOCK_RATE_SET;
100*54b96380SRuslan Bukin 	req.in_buf = &in;
101*54b96380SRuslan Bukin 	req.in_size = sizeof(struct scmi_clk_rate_set_in);
102*54b96380SRuslan Bukin 	req.out_buf = &out;
103*54b96380SRuslan Bukin 	req.out_size = sizeof(struct scmi_clk_rate_set_out);
104*54b96380SRuslan Bukin 
105*54b96380SRuslan Bukin 	in.clock_id = clk_id;
106*54b96380SRuslan Bukin 	in.flags = SCMI_CLK_RATE_ROUND_CLOSEST;
107*54b96380SRuslan Bukin 	in.rate_lsb = (uint32_t)rate;
108*54b96380SRuslan Bukin 	in.rate_msb = (uint32_t)(rate >> 32);
109*54b96380SRuslan Bukin 
110*54b96380SRuslan Bukin 	error = scmi_request(sc->scmi, &req);
111*54b96380SRuslan Bukin 	if (error != 0)
112*54b96380SRuslan Bukin 		return (error);
113*54b96380SRuslan Bukin 
114*54b96380SRuslan Bukin 	if (out.status != 0)
115*54b96380SRuslan Bukin 		return (ENXIO);
116*54b96380SRuslan Bukin 
117*54b96380SRuslan Bukin 	return (0);
118*54b96380SRuslan Bukin }
119*54b96380SRuslan Bukin 
120*54b96380SRuslan Bukin static int
121*54b96380SRuslan Bukin scmi_clk_gate(struct scmi_clk_softc *sc, int clk_id, int enable)
122*54b96380SRuslan Bukin {
123*54b96380SRuslan Bukin 	struct scmi_clk_state_out out;
124*54b96380SRuslan Bukin 	struct scmi_clk_state_in in;
125*54b96380SRuslan Bukin 	struct scmi_req req;
126*54b96380SRuslan Bukin 	int error;
127*54b96380SRuslan Bukin 
128*54b96380SRuslan Bukin 	req.protocol_id = SCMI_PROTOCOL_ID_CLOCK;
129*54b96380SRuslan Bukin 	req.message_id = SCMI_CLOCK_CONFIG_SET;
130*54b96380SRuslan Bukin 	req.in_buf = &in;
131*54b96380SRuslan Bukin 	req.in_size = sizeof(struct scmi_clk_state_in);
132*54b96380SRuslan Bukin 	req.out_buf = &out;
133*54b96380SRuslan Bukin 	req.out_size = sizeof(struct scmi_clk_state_out);
134*54b96380SRuslan Bukin 
135*54b96380SRuslan Bukin 	in.clock_id = clk_id;
136*54b96380SRuslan Bukin 	in.attributes = enable;
137*54b96380SRuslan Bukin 
138*54b96380SRuslan Bukin 	error = scmi_request(sc->scmi, &req);
139*54b96380SRuslan Bukin 	if (error != 0)
140*54b96380SRuslan Bukin 		return (error);
141*54b96380SRuslan Bukin 
142*54b96380SRuslan Bukin 	if (out.status != 0)
143*54b96380SRuslan Bukin 		return (ENXIO);
144*54b96380SRuslan Bukin 
145*54b96380SRuslan Bukin 	return (0);
146*54b96380SRuslan Bukin }
147*54b96380SRuslan Bukin 
148*54b96380SRuslan Bukin static int
149*54b96380SRuslan Bukin scmi_clknode_init(struct clknode *clk, device_t dev)
150*54b96380SRuslan Bukin {
151*54b96380SRuslan Bukin 
152*54b96380SRuslan Bukin 	clknode_init_parent_idx(clk, 0);
153*54b96380SRuslan Bukin 
154*54b96380SRuslan Bukin 	return (0);
155*54b96380SRuslan Bukin }
156*54b96380SRuslan Bukin 
157*54b96380SRuslan Bukin static int
158*54b96380SRuslan Bukin scmi_clknode_recalc_freq(struct clknode *clk, uint64_t *freq)
159*54b96380SRuslan Bukin {
160*54b96380SRuslan Bukin 
161*54b96380SRuslan Bukin 	return (0);
162*54b96380SRuslan Bukin }
163*54b96380SRuslan Bukin 
164*54b96380SRuslan Bukin static int
165*54b96380SRuslan Bukin scmi_clknode_set_freq(struct clknode *clk, uint64_t fin, uint64_t *fout,
166*54b96380SRuslan Bukin     int flags, int *stop)
167*54b96380SRuslan Bukin {
168*54b96380SRuslan Bukin 	struct scmi_clknode_softc *clk_sc;
169*54b96380SRuslan Bukin 	struct scmi_clk_softc *sc;
170*54b96380SRuslan Bukin 
171*54b96380SRuslan Bukin 	clk_sc = clknode_get_softc(clk);
172*54b96380SRuslan Bukin 	sc = device_get_softc(clk_sc->dev);
173*54b96380SRuslan Bukin 
174*54b96380SRuslan Bukin 	dprintf("%s: %ld\n", __func__, *fout);
175*54b96380SRuslan Bukin 
176*54b96380SRuslan Bukin 	scmi_clk_set_rate(sc, clk_sc->clock_id, *fout);
177*54b96380SRuslan Bukin 
178*54b96380SRuslan Bukin 	*stop = 1;
179*54b96380SRuslan Bukin 
180*54b96380SRuslan Bukin 	return (0);
181*54b96380SRuslan Bukin }
182*54b96380SRuslan Bukin 
183*54b96380SRuslan Bukin static clknode_method_t scmi_clknode_methods[] = {
184*54b96380SRuslan Bukin 	/* Device interface */
185*54b96380SRuslan Bukin 	CLKNODEMETHOD(clknode_init,		scmi_clknode_init),
186*54b96380SRuslan Bukin 	CLKNODEMETHOD(clknode_recalc_freq,	scmi_clknode_recalc_freq),
187*54b96380SRuslan Bukin 	CLKNODEMETHOD(clknode_set_freq,		scmi_clknode_set_freq),
188*54b96380SRuslan Bukin 	CLKNODEMETHOD_END
189*54b96380SRuslan Bukin };
190*54b96380SRuslan Bukin 
191*54b96380SRuslan Bukin DEFINE_CLASS_1(scmi_clknode, scmi_clknode_class, scmi_clknode_methods,
192*54b96380SRuslan Bukin     sizeof(struct scmi_clknode_softc), clknode_class);
193*54b96380SRuslan Bukin 
194*54b96380SRuslan Bukin static int
195*54b96380SRuslan Bukin scmi_clk_add_node(struct scmi_clk_softc *sc, int index, char *clock_name)
196*54b96380SRuslan Bukin {
197*54b96380SRuslan Bukin 	struct scmi_clknode_softc *clk_sc;
198*54b96380SRuslan Bukin 	struct clknode_init_def def;
199*54b96380SRuslan Bukin 	struct clknode *clk;
200*54b96380SRuslan Bukin 
201*54b96380SRuslan Bukin 	memset(&def, 0, sizeof(def));
202*54b96380SRuslan Bukin 	def.id = index;
203*54b96380SRuslan Bukin 	def.name = clock_name;
204*54b96380SRuslan Bukin 	def.parent_names = NULL;
205*54b96380SRuslan Bukin 	def.parent_cnt = 0;
206*54b96380SRuslan Bukin 
207*54b96380SRuslan Bukin 	clk = clknode_create(sc->clkdom, &scmi_clknode_class, &def);
208*54b96380SRuslan Bukin 	if (clk == NULL) {
209*54b96380SRuslan Bukin 		device_printf(sc->dev, "Cannot create clknode.\n");
210*54b96380SRuslan Bukin 		return (ENXIO);
211*54b96380SRuslan Bukin 	}
212*54b96380SRuslan Bukin 
213*54b96380SRuslan Bukin 	clk_sc = clknode_get_softc(clk);
214*54b96380SRuslan Bukin 	clk_sc->dev = sc->dev;
215*54b96380SRuslan Bukin 	clk_sc->clock_id = index;
216*54b96380SRuslan Bukin 
217*54b96380SRuslan Bukin 	if (clknode_register(sc->clkdom, clk) == NULL) {
218*54b96380SRuslan Bukin 		device_printf(sc->dev, "Could not register clock '%s'.\n",
219*54b96380SRuslan Bukin 		    def.name);
220*54b96380SRuslan Bukin 		return (ENXIO);
221*54b96380SRuslan Bukin 	}
222*54b96380SRuslan Bukin 
223*54b96380SRuslan Bukin 	device_printf(sc->dev, "Clock '%s' registered.\n", def.name);
224*54b96380SRuslan Bukin 
225*54b96380SRuslan Bukin 	return (0);
226*54b96380SRuslan Bukin }
227*54b96380SRuslan Bukin 
228*54b96380SRuslan Bukin static int
229*54b96380SRuslan Bukin scmi_clk_get_name(struct scmi_clk_softc *sc, int index, char **result)
230*54b96380SRuslan Bukin {
231*54b96380SRuslan Bukin 	struct scmi_clk_name_get_out out;
232*54b96380SRuslan Bukin 	struct scmi_clk_name_get_in in;
233*54b96380SRuslan Bukin 	struct scmi_req req;
234*54b96380SRuslan Bukin 	char *clock_name;
235*54b96380SRuslan Bukin 	int error;
236*54b96380SRuslan Bukin 
237*54b96380SRuslan Bukin 	req.protocol_id = SCMI_PROTOCOL_ID_CLOCK;
238*54b96380SRuslan Bukin 	req.message_id = SCMI_CLOCK_NAME_GET;
239*54b96380SRuslan Bukin 	req.in_buf = &in;
240*54b96380SRuslan Bukin 	req.in_size = sizeof(struct scmi_clk_name_get_in);
241*54b96380SRuslan Bukin 	req.out_buf = &out;
242*54b96380SRuslan Bukin 	req.out_size = sizeof(struct scmi_clk_name_get_out);
243*54b96380SRuslan Bukin 
244*54b96380SRuslan Bukin 	in.clock_id = index;
245*54b96380SRuslan Bukin 
246*54b96380SRuslan Bukin 	error = scmi_request(sc->scmi, &req);
247*54b96380SRuslan Bukin 	if (error != 0)
248*54b96380SRuslan Bukin 		return (error);
249*54b96380SRuslan Bukin 
250*54b96380SRuslan Bukin 	if (out.status != 0)
251*54b96380SRuslan Bukin 		return (ENXIO);
252*54b96380SRuslan Bukin 
253*54b96380SRuslan Bukin 	clock_name = malloc(sizeof(out.name), M_DEVBUF, M_WAITOK);
254*54b96380SRuslan Bukin 	strncpy(clock_name, out.name, sizeof(out.name));
255*54b96380SRuslan Bukin 
256*54b96380SRuslan Bukin 	*result = clock_name;
257*54b96380SRuslan Bukin 
258*54b96380SRuslan Bukin 	return (0);
259*54b96380SRuslan Bukin }
260*54b96380SRuslan Bukin 
261*54b96380SRuslan Bukin static int
262*54b96380SRuslan Bukin scmi_clk_attrs(struct scmi_clk_softc *sc, int index)
263*54b96380SRuslan Bukin {
264*54b96380SRuslan Bukin 	struct scmi_clk_attrs_out out;
265*54b96380SRuslan Bukin 	struct scmi_clk_attrs_in in;
266*54b96380SRuslan Bukin 	struct scmi_req req;
267*54b96380SRuslan Bukin 	int error;
268*54b96380SRuslan Bukin 	char *clock_name;
269*54b96380SRuslan Bukin 
270*54b96380SRuslan Bukin 	req.protocol_id = SCMI_PROTOCOL_ID_CLOCK;
271*54b96380SRuslan Bukin 	req.message_id = SCMI_CLOCK_ATTRIBUTES;
272*54b96380SRuslan Bukin 	req.in_buf = &in;
273*54b96380SRuslan Bukin 	req.in_size = sizeof(struct scmi_clk_attrs_in);
274*54b96380SRuslan Bukin 	req.out_buf = &out;
275*54b96380SRuslan Bukin 	req.out_size = sizeof(struct scmi_clk_attrs_out);
276*54b96380SRuslan Bukin 
277*54b96380SRuslan Bukin 	in.clock_id = index;
278*54b96380SRuslan Bukin 
279*54b96380SRuslan Bukin 	error = scmi_request(sc->scmi, &req);
280*54b96380SRuslan Bukin 	if (error != 0)
281*54b96380SRuslan Bukin 		return (error);
282*54b96380SRuslan Bukin 
283*54b96380SRuslan Bukin 	if (out.status != 0)
284*54b96380SRuslan Bukin 		return (ENXIO);
285*54b96380SRuslan Bukin 
286*54b96380SRuslan Bukin 	if (out.attributes & CLK_ATTRS_EXT_CLK_NAME) {
287*54b96380SRuslan Bukin 		error = scmi_clk_get_name(sc, index, &clock_name);
288*54b96380SRuslan Bukin 		if (error)
289*54b96380SRuslan Bukin 			return (error);
290*54b96380SRuslan Bukin 	} else {
291*54b96380SRuslan Bukin 		clock_name = malloc(sizeof(out.clock_name), M_DEVBUF, M_WAITOK);
292*54b96380SRuslan Bukin 		strncpy(clock_name, out.clock_name, sizeof(out.clock_name));
293*54b96380SRuslan Bukin 	}
294*54b96380SRuslan Bukin 
295*54b96380SRuslan Bukin 	error = scmi_clk_add_node(sc, index, clock_name);
296*54b96380SRuslan Bukin 
297*54b96380SRuslan Bukin 	return (error);
298*54b96380SRuslan Bukin }
299*54b96380SRuslan Bukin 
300*54b96380SRuslan Bukin static int
301*54b96380SRuslan Bukin scmi_clk_discover(struct scmi_clk_softc *sc)
302*54b96380SRuslan Bukin {
303*54b96380SRuslan Bukin 	struct scmi_clk_protocol_attrs_out out;
304*54b96380SRuslan Bukin 	struct scmi_req req;
305*54b96380SRuslan Bukin 	int nclocks;
306*54b96380SRuslan Bukin 	int failing;
307*54b96380SRuslan Bukin 	int error;
308*54b96380SRuslan Bukin 	int i;
309*54b96380SRuslan Bukin 
310*54b96380SRuslan Bukin 	req.protocol_id = SCMI_PROTOCOL_ID_CLOCK;
311*54b96380SRuslan Bukin 	req.message_id = SCMI_PROTOCOL_ATTRIBUTES;
312*54b96380SRuslan Bukin 	req.in_buf = NULL;
313*54b96380SRuslan Bukin 	req.in_size = 0;
314*54b96380SRuslan Bukin 	req.out_buf = &out;
315*54b96380SRuslan Bukin 	req.out_size = sizeof(struct scmi_clk_protocol_attrs_out);
316*54b96380SRuslan Bukin 
317*54b96380SRuslan Bukin 	error = scmi_request(sc->scmi, &req);
318*54b96380SRuslan Bukin 	if (error != 0)
319*54b96380SRuslan Bukin 		return (error);
320*54b96380SRuslan Bukin 
321*54b96380SRuslan Bukin 	if (out.status != 0)
322*54b96380SRuslan Bukin 		return (ENXIO);
323*54b96380SRuslan Bukin 
324*54b96380SRuslan Bukin 	nclocks = (out.attributes & CLK_ATTRS_NCLOCKS_M) >>
325*54b96380SRuslan Bukin 	    CLK_ATTRS_NCLOCKS_S;
326*54b96380SRuslan Bukin 
327*54b96380SRuslan Bukin 	device_printf(sc->dev, "Found %d clocks.\n", nclocks);
328*54b96380SRuslan Bukin 
329*54b96380SRuslan Bukin 	failing = 0;
330*54b96380SRuslan Bukin 
331*54b96380SRuslan Bukin 	for (i = 0; i < nclocks; i++) {
332*54b96380SRuslan Bukin 		error = scmi_clk_attrs(sc, i);
333*54b96380SRuslan Bukin 		if (error) {
334*54b96380SRuslan Bukin 			device_printf(sc->dev,
335*54b96380SRuslan Bukin 			    "Could not process clock index %d.\n", i);
336*54b96380SRuslan Bukin 			failing++;
337*54b96380SRuslan Bukin 		}
338*54b96380SRuslan Bukin 	}
339*54b96380SRuslan Bukin 
340*54b96380SRuslan Bukin 	if (failing == nclocks)
341*54b96380SRuslan Bukin 		return (ENXIO);
342*54b96380SRuslan Bukin 
343*54b96380SRuslan Bukin 	return (0);
344*54b96380SRuslan Bukin }
345*54b96380SRuslan Bukin 
346*54b96380SRuslan Bukin static int
347*54b96380SRuslan Bukin scmi_clk_init(struct scmi_clk_softc *sc)
348*54b96380SRuslan Bukin {
349*54b96380SRuslan Bukin 	int error;
350*54b96380SRuslan Bukin 
351*54b96380SRuslan Bukin 	/* Create clock domain */
352*54b96380SRuslan Bukin 	sc->clkdom = clkdom_create(sc->dev);
353*54b96380SRuslan Bukin 	if (sc->clkdom == NULL)
354*54b96380SRuslan Bukin 		return (ENXIO);
355*54b96380SRuslan Bukin 
356*54b96380SRuslan Bukin 	error = scmi_clk_discover(sc);
357*54b96380SRuslan Bukin 	if (error) {
358*54b96380SRuslan Bukin 		device_printf(sc->dev, "Could not discover clocks.\n");
359*54b96380SRuslan Bukin 		return (ENXIO);
360*54b96380SRuslan Bukin 	}
361*54b96380SRuslan Bukin 
362*54b96380SRuslan Bukin 	error = clkdom_finit(sc->clkdom);
363*54b96380SRuslan Bukin 	if (error) {
364*54b96380SRuslan Bukin 		device_printf(sc->dev, "Failed to init clock domain.\n");
365*54b96380SRuslan Bukin 		return (ENXIO);
366*54b96380SRuslan Bukin 	}
367*54b96380SRuslan Bukin 
368*54b96380SRuslan Bukin 	return (0);
369*54b96380SRuslan Bukin }
370*54b96380SRuslan Bukin 
371*54b96380SRuslan Bukin static int
372*54b96380SRuslan Bukin scmi_clk_probe(device_t dev)
373*54b96380SRuslan Bukin {
374*54b96380SRuslan Bukin 	phandle_t node;
375*54b96380SRuslan Bukin 	uint32_t reg;
376*54b96380SRuslan Bukin 	int error;
377*54b96380SRuslan Bukin 
378*54b96380SRuslan Bukin 	node = ofw_bus_get_node(dev);
379*54b96380SRuslan Bukin 
380*54b96380SRuslan Bukin 	error = OF_getencprop(node, "reg", &reg, sizeof(uint32_t));
381*54b96380SRuslan Bukin 	if (error < 0)
382*54b96380SRuslan Bukin 		return (ENXIO);
383*54b96380SRuslan Bukin 
384*54b96380SRuslan Bukin 	if (reg != SCMI_PROTOCOL_ID_CLOCK)
385*54b96380SRuslan Bukin 		return (ENXIO);
386*54b96380SRuslan Bukin 
387*54b96380SRuslan Bukin 	device_set_desc(dev, "SCMI Clock Management Unit");
388*54b96380SRuslan Bukin 
389*54b96380SRuslan Bukin 	return (BUS_PROBE_DEFAULT);
390*54b96380SRuslan Bukin }
391*54b96380SRuslan Bukin 
392*54b96380SRuslan Bukin static int
393*54b96380SRuslan Bukin scmi_clk_attach(device_t dev)
394*54b96380SRuslan Bukin {
395*54b96380SRuslan Bukin 	struct scmi_clk_softc *sc;
396*54b96380SRuslan Bukin 	phandle_t node;
397*54b96380SRuslan Bukin 
398*54b96380SRuslan Bukin 	sc = device_get_softc(dev);
399*54b96380SRuslan Bukin 	sc->dev = dev;
400*54b96380SRuslan Bukin 	sc->scmi = device_get_parent(dev);
401*54b96380SRuslan Bukin 
402*54b96380SRuslan Bukin 	node = ofw_bus_get_node(sc->dev);
403*54b96380SRuslan Bukin 
404*54b96380SRuslan Bukin 	OF_device_register_xref(OF_xref_from_node(node), sc->dev);
405*54b96380SRuslan Bukin 
406*54b96380SRuslan Bukin 	scmi_clk_init(sc);
407*54b96380SRuslan Bukin 
408*54b96380SRuslan Bukin 	return (0);
409*54b96380SRuslan Bukin }
410*54b96380SRuslan Bukin 
411*54b96380SRuslan Bukin static int
412*54b96380SRuslan Bukin scmi_clk_detach(device_t dev)
413*54b96380SRuslan Bukin {
414*54b96380SRuslan Bukin 
415*54b96380SRuslan Bukin 	return (0);
416*54b96380SRuslan Bukin }
417*54b96380SRuslan Bukin 
418*54b96380SRuslan Bukin static device_method_t scmi_clk_methods[] = {
419*54b96380SRuslan Bukin 	/* Device interface */
420*54b96380SRuslan Bukin 	DEVMETHOD(device_probe,		scmi_clk_probe),
421*54b96380SRuslan Bukin 	DEVMETHOD(device_attach,	scmi_clk_attach),
422*54b96380SRuslan Bukin 	DEVMETHOD(device_detach,	scmi_clk_detach),
423*54b96380SRuslan Bukin 	DEVMETHOD_END
424*54b96380SRuslan Bukin };
425*54b96380SRuslan Bukin 
426*54b96380SRuslan Bukin static driver_t scmi_clk_driver = {
427*54b96380SRuslan Bukin 	"scmi_clk",
428*54b96380SRuslan Bukin 	scmi_clk_methods,
429*54b96380SRuslan Bukin 	sizeof(struct scmi_clk_softc),
430*54b96380SRuslan Bukin };
431*54b96380SRuslan Bukin 
432*54b96380SRuslan Bukin EARLY_DRIVER_MODULE(scmi_clk, scmi, scmi_clk_driver, 0, 0,
433*54b96380SRuslan Bukin     BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
434*54b96380SRuslan Bukin MODULE_VERSION(scmi_clk, 1);
435