xref: /freebsd/sys/dev/firmware/arm/scmi_clk.c (revision ecd8cc84dcee7d08be8663f721f0502dc5b65808)
154b96380SRuslan Bukin /*-
254b96380SRuslan Bukin  * SPDX-License-Identifier: BSD-2-Clause
354b96380SRuslan Bukin  *
454b96380SRuslan Bukin  * Copyright (c) 2022 Ruslan Bukin <br@bsdpad.com>
554b96380SRuslan Bukin  *
654b96380SRuslan Bukin  * This work was supported by Innovate UK project 105694, "Digital Security
754b96380SRuslan Bukin  * by Design (DSbD) Technology Platform Prototype".
854b96380SRuslan Bukin  *
954b96380SRuslan Bukin  * Redistribution and use in source and binary forms, with or without
1054b96380SRuslan Bukin  * modification, are permitted provided that the following conditions
1154b96380SRuslan Bukin  * are met:
1254b96380SRuslan Bukin  * 1. Redistributions of source code must retain the above copyright
1354b96380SRuslan Bukin  *    notice, this list of conditions and the following disclaimer.
1454b96380SRuslan Bukin  * 2. Redistributions in binary form must reproduce the above copyright
1554b96380SRuslan Bukin  *    notice, this list of conditions and the following disclaimer in the
1654b96380SRuslan Bukin  *    documentation and/or other materials provided with the distribution.
1754b96380SRuslan Bukin  *
1854b96380SRuslan Bukin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1954b96380SRuslan Bukin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2054b96380SRuslan Bukin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2154b96380SRuslan Bukin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2254b96380SRuslan Bukin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2354b96380SRuslan Bukin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2454b96380SRuslan Bukin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2554b96380SRuslan Bukin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2654b96380SRuslan Bukin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2754b96380SRuslan Bukin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2854b96380SRuslan Bukin  * SUCH DAMAGE.
2954b96380SRuslan Bukin  */
3054b96380SRuslan Bukin 
3154b96380SRuslan Bukin #include <sys/param.h>
3254b96380SRuslan Bukin #include <sys/systm.h>
3354b96380SRuslan Bukin #include <sys/bus.h>
3454b96380SRuslan Bukin #include <sys/cpu.h>
3554b96380SRuslan Bukin #include <sys/kernel.h>
3654b96380SRuslan Bukin #include <sys/module.h>
3754b96380SRuslan Bukin 
38be82b3a0SEmmanuel Vadot #include <dev/clk/clk.h>
3954b96380SRuslan Bukin #include <dev/fdt/simplebus.h>
4054b96380SRuslan Bukin #include <dev/fdt/fdt_common.h>
4154b96380SRuslan Bukin #include <dev/ofw/ofw_bus_subr.h>
4254b96380SRuslan Bukin 
4354b96380SRuslan Bukin #include "scmi.h"
4454b96380SRuslan Bukin #include "scmi_protocols.h"
4554b96380SRuslan Bukin #include "scmi_clk.h"
4654b96380SRuslan Bukin 
4754b96380SRuslan Bukin struct scmi_clk_softc {
4854b96380SRuslan Bukin 	device_t	dev;
4954b96380SRuslan Bukin 	device_t	scmi;
5054b96380SRuslan Bukin 	struct clkdom	*clkdom;
5154b96380SRuslan Bukin };
5254b96380SRuslan Bukin 
5354b96380SRuslan Bukin struct scmi_clknode_softc {
5454b96380SRuslan Bukin 	device_t	dev;
5554b96380SRuslan Bukin 	int		clock_id;
5654b96380SRuslan Bukin };
5754b96380SRuslan Bukin 
58*ecd8cc84SCristian Marussi static int
5954b96380SRuslan Bukin scmi_clk_get_rate(struct scmi_clk_softc *sc, int clk_id, uint64_t *rate)
6054b96380SRuslan Bukin {
6154b96380SRuslan Bukin 	struct scmi_clk_rate_get_out out;
6254b96380SRuslan Bukin 	struct scmi_clk_rate_get_in in;
6354b96380SRuslan Bukin 	struct scmi_req req;
6454b96380SRuslan Bukin 	int error;
6554b96380SRuslan Bukin 
6654b96380SRuslan Bukin 	req.protocol_id = SCMI_PROTOCOL_ID_CLOCK;
6754b96380SRuslan Bukin 	req.message_id = SCMI_CLOCK_RATE_GET;
6854b96380SRuslan Bukin 	req.in_buf = &in;
6954b96380SRuslan Bukin 	req.in_size = sizeof(struct scmi_clk_rate_get_in);
7054b96380SRuslan Bukin 	req.out_buf = &out;
7154b96380SRuslan Bukin 	req.out_size = sizeof(struct scmi_clk_rate_get_out);
7254b96380SRuslan Bukin 
7354b96380SRuslan Bukin 	in.clock_id = clk_id;
7454b96380SRuslan Bukin 
7554b96380SRuslan Bukin 	error = scmi_request(sc->scmi, &req);
7654b96380SRuslan Bukin 	if (error != 0)
7754b96380SRuslan Bukin 		return (error);
7854b96380SRuslan Bukin 
7954b96380SRuslan Bukin 	if (out.status != 0)
8054b96380SRuslan Bukin 		return (ENXIO);
8154b96380SRuslan Bukin 
8254b96380SRuslan Bukin 	*rate = out.rate_lsb | ((uint64_t)out.rate_msb << 32);
8354b96380SRuslan Bukin 
8454b96380SRuslan Bukin 	return (0);
8554b96380SRuslan Bukin }
8654b96380SRuslan Bukin 
8754b96380SRuslan Bukin static int
8854b96380SRuslan Bukin scmi_clk_set_rate(struct scmi_clk_softc *sc, int clk_id, uint64_t rate)
8954b96380SRuslan Bukin {
9054b96380SRuslan Bukin 	struct scmi_clk_rate_set_out out;
9154b96380SRuslan Bukin 	struct scmi_clk_rate_set_in in;
9254b96380SRuslan Bukin 	struct scmi_req req;
9354b96380SRuslan Bukin 	int error;
9454b96380SRuslan Bukin 
9554b96380SRuslan Bukin 	req.protocol_id = SCMI_PROTOCOL_ID_CLOCK;
9654b96380SRuslan Bukin 	req.message_id = SCMI_CLOCK_RATE_SET;
9754b96380SRuslan Bukin 	req.in_buf = &in;
9854b96380SRuslan Bukin 	req.in_size = sizeof(struct scmi_clk_rate_set_in);
9954b96380SRuslan Bukin 	req.out_buf = &out;
10054b96380SRuslan Bukin 	req.out_size = sizeof(struct scmi_clk_rate_set_out);
10154b96380SRuslan Bukin 
10254b96380SRuslan Bukin 	in.clock_id = clk_id;
10354b96380SRuslan Bukin 	in.flags = SCMI_CLK_RATE_ROUND_CLOSEST;
10454b96380SRuslan Bukin 	in.rate_lsb = (uint32_t)rate;
10554b96380SRuslan Bukin 	in.rate_msb = (uint32_t)(rate >> 32);
10654b96380SRuslan Bukin 
10754b96380SRuslan Bukin 	error = scmi_request(sc->scmi, &req);
10854b96380SRuslan Bukin 	if (error != 0)
10954b96380SRuslan Bukin 		return (error);
11054b96380SRuslan Bukin 
11154b96380SRuslan Bukin 	if (out.status != 0)
11254b96380SRuslan Bukin 		return (ENXIO);
11354b96380SRuslan Bukin 
11454b96380SRuslan Bukin 	return (0);
11554b96380SRuslan Bukin }
11654b96380SRuslan Bukin 
11719a7cf0cSMark Johnston static int __unused
11854b96380SRuslan Bukin scmi_clk_gate(struct scmi_clk_softc *sc, int clk_id, int enable)
11954b96380SRuslan Bukin {
12054b96380SRuslan Bukin 	struct scmi_clk_state_out out;
12154b96380SRuslan Bukin 	struct scmi_clk_state_in in;
12254b96380SRuslan Bukin 	struct scmi_req req;
12354b96380SRuslan Bukin 	int error;
12454b96380SRuslan Bukin 
12554b96380SRuslan Bukin 	req.protocol_id = SCMI_PROTOCOL_ID_CLOCK;
12654b96380SRuslan Bukin 	req.message_id = SCMI_CLOCK_CONFIG_SET;
12754b96380SRuslan Bukin 	req.in_buf = &in;
12854b96380SRuslan Bukin 	req.in_size = sizeof(struct scmi_clk_state_in);
12954b96380SRuslan Bukin 	req.out_buf = &out;
13054b96380SRuslan Bukin 	req.out_size = sizeof(struct scmi_clk_state_out);
13154b96380SRuslan Bukin 
13254b96380SRuslan Bukin 	in.clock_id = clk_id;
13354b96380SRuslan Bukin 	in.attributes = enable;
13454b96380SRuslan Bukin 
13554b96380SRuslan Bukin 	error = scmi_request(sc->scmi, &req);
13654b96380SRuslan Bukin 	if (error != 0)
13754b96380SRuslan Bukin 		return (error);
13854b96380SRuslan Bukin 
13954b96380SRuslan Bukin 	if (out.status != 0)
14054b96380SRuslan Bukin 		return (ENXIO);
14154b96380SRuslan Bukin 
14254b96380SRuslan Bukin 	return (0);
14354b96380SRuslan Bukin }
14454b96380SRuslan Bukin 
14554b96380SRuslan Bukin static int
14654b96380SRuslan Bukin scmi_clknode_init(struct clknode *clk, device_t dev)
14754b96380SRuslan Bukin {
14854b96380SRuslan Bukin 
14954b96380SRuslan Bukin 	clknode_init_parent_idx(clk, 0);
15054b96380SRuslan Bukin 
15154b96380SRuslan Bukin 	return (0);
15254b96380SRuslan Bukin }
15354b96380SRuslan Bukin 
15454b96380SRuslan Bukin static int
15554b96380SRuslan Bukin scmi_clknode_recalc_freq(struct clknode *clk, uint64_t *freq)
15654b96380SRuslan Bukin {
157*ecd8cc84SCristian Marussi 	struct scmi_clknode_softc *clk_sc;
158*ecd8cc84SCristian Marussi 	struct scmi_clk_softc *sc;
159*ecd8cc84SCristian Marussi 	uint64_t rate;
160*ecd8cc84SCristian Marussi 	int ret;
16154b96380SRuslan Bukin 
162*ecd8cc84SCristian Marussi 	clk_sc = clknode_get_softc(clk);
163*ecd8cc84SCristian Marussi 	sc = device_get_softc(clk_sc->dev);
164*ecd8cc84SCristian Marussi 	ret = scmi_clk_get_rate(sc, clk_sc->clock_id, &rate);
165*ecd8cc84SCristian Marussi 	if (ret == 0)
166*ecd8cc84SCristian Marussi 		*freq = rate;
167*ecd8cc84SCristian Marussi 
168*ecd8cc84SCristian Marussi 	return (ret);
16954b96380SRuslan Bukin }
17054b96380SRuslan Bukin 
17154b96380SRuslan Bukin static int
17254b96380SRuslan Bukin scmi_clknode_set_freq(struct clknode *clk, uint64_t fin, uint64_t *fout,
17354b96380SRuslan Bukin     int flags, int *stop)
17454b96380SRuslan Bukin {
17554b96380SRuslan Bukin 	struct scmi_clknode_softc *clk_sc;
17654b96380SRuslan Bukin 	struct scmi_clk_softc *sc;
17754b96380SRuslan Bukin 
17854b96380SRuslan Bukin 	clk_sc = clknode_get_softc(clk);
17954b96380SRuslan Bukin 	sc = device_get_softc(clk_sc->dev);
18054b96380SRuslan Bukin 
18154b96380SRuslan Bukin 	dprintf("%s: %ld\n", __func__, *fout);
18254b96380SRuslan Bukin 
18354b96380SRuslan Bukin 	scmi_clk_set_rate(sc, clk_sc->clock_id, *fout);
18454b96380SRuslan Bukin 
18554b96380SRuslan Bukin 	*stop = 1;
18654b96380SRuslan Bukin 
18754b96380SRuslan Bukin 	return (0);
18854b96380SRuslan Bukin }
18954b96380SRuslan Bukin 
19054b96380SRuslan Bukin static clknode_method_t scmi_clknode_methods[] = {
19154b96380SRuslan Bukin 	/* Device interface */
19254b96380SRuslan Bukin 	CLKNODEMETHOD(clknode_init,		scmi_clknode_init),
19354b96380SRuslan Bukin 	CLKNODEMETHOD(clknode_recalc_freq,	scmi_clknode_recalc_freq),
19454b96380SRuslan Bukin 	CLKNODEMETHOD(clknode_set_freq,		scmi_clknode_set_freq),
19554b96380SRuslan Bukin 	CLKNODEMETHOD_END
19654b96380SRuslan Bukin };
19754b96380SRuslan Bukin 
19854b96380SRuslan Bukin DEFINE_CLASS_1(scmi_clknode, scmi_clknode_class, scmi_clknode_methods,
19954b96380SRuslan Bukin     sizeof(struct scmi_clknode_softc), clknode_class);
20054b96380SRuslan Bukin 
20154b96380SRuslan Bukin static int
20254b96380SRuslan Bukin scmi_clk_add_node(struct scmi_clk_softc *sc, int index, char *clock_name)
20354b96380SRuslan Bukin {
20454b96380SRuslan Bukin 	struct scmi_clknode_softc *clk_sc;
20554b96380SRuslan Bukin 	struct clknode_init_def def;
20654b96380SRuslan Bukin 	struct clknode *clk;
20754b96380SRuslan Bukin 
20854b96380SRuslan Bukin 	memset(&def, 0, sizeof(def));
20954b96380SRuslan Bukin 	def.id = index;
21054b96380SRuslan Bukin 	def.name = clock_name;
21154b96380SRuslan Bukin 	def.parent_names = NULL;
21254b96380SRuslan Bukin 	def.parent_cnt = 0;
21354b96380SRuslan Bukin 
21454b96380SRuslan Bukin 	clk = clknode_create(sc->clkdom, &scmi_clknode_class, &def);
21554b96380SRuslan Bukin 	if (clk == NULL) {
21654b96380SRuslan Bukin 		device_printf(sc->dev, "Cannot create clknode.\n");
21754b96380SRuslan Bukin 		return (ENXIO);
21854b96380SRuslan Bukin 	}
21954b96380SRuslan Bukin 
22054b96380SRuslan Bukin 	clk_sc = clknode_get_softc(clk);
22154b96380SRuslan Bukin 	clk_sc->dev = sc->dev;
22254b96380SRuslan Bukin 	clk_sc->clock_id = index;
22354b96380SRuslan Bukin 
22454b96380SRuslan Bukin 	if (clknode_register(sc->clkdom, clk) == NULL) {
22554b96380SRuslan Bukin 		device_printf(sc->dev, "Could not register clock '%s'.\n",
22654b96380SRuslan Bukin 		    def.name);
22754b96380SRuslan Bukin 		return (ENXIO);
22854b96380SRuslan Bukin 	}
22954b96380SRuslan Bukin 
23054b96380SRuslan Bukin 	device_printf(sc->dev, "Clock '%s' registered.\n", def.name);
23154b96380SRuslan Bukin 
23254b96380SRuslan Bukin 	return (0);
23354b96380SRuslan Bukin }
23454b96380SRuslan Bukin 
23554b96380SRuslan Bukin static int
23654b96380SRuslan Bukin scmi_clk_get_name(struct scmi_clk_softc *sc, int index, char **result)
23754b96380SRuslan Bukin {
23854b96380SRuslan Bukin 	struct scmi_clk_name_get_out out;
23954b96380SRuslan Bukin 	struct scmi_clk_name_get_in in;
24054b96380SRuslan Bukin 	struct scmi_req req;
24154b96380SRuslan Bukin 	char *clock_name;
24254b96380SRuslan Bukin 	int error;
24354b96380SRuslan Bukin 
24454b96380SRuslan Bukin 	req.protocol_id = SCMI_PROTOCOL_ID_CLOCK;
24554b96380SRuslan Bukin 	req.message_id = SCMI_CLOCK_NAME_GET;
24654b96380SRuslan Bukin 	req.in_buf = &in;
24754b96380SRuslan Bukin 	req.in_size = sizeof(struct scmi_clk_name_get_in);
24854b96380SRuslan Bukin 	req.out_buf = &out;
24954b96380SRuslan Bukin 	req.out_size = sizeof(struct scmi_clk_name_get_out);
25054b96380SRuslan Bukin 
25154b96380SRuslan Bukin 	in.clock_id = index;
25254b96380SRuslan Bukin 
25354b96380SRuslan Bukin 	error = scmi_request(sc->scmi, &req);
25454b96380SRuslan Bukin 	if (error != 0)
25554b96380SRuslan Bukin 		return (error);
25654b96380SRuslan Bukin 
25754b96380SRuslan Bukin 	if (out.status != 0)
25854b96380SRuslan Bukin 		return (ENXIO);
25954b96380SRuslan Bukin 
26054b96380SRuslan Bukin 	clock_name = malloc(sizeof(out.name), M_DEVBUF, M_WAITOK);
26154b96380SRuslan Bukin 	strncpy(clock_name, out.name, sizeof(out.name));
26254b96380SRuslan Bukin 
26354b96380SRuslan Bukin 	*result = clock_name;
26454b96380SRuslan Bukin 
26554b96380SRuslan Bukin 	return (0);
26654b96380SRuslan Bukin }
26754b96380SRuslan Bukin 
26854b96380SRuslan Bukin static int
26954b96380SRuslan Bukin scmi_clk_attrs(struct scmi_clk_softc *sc, int index)
27054b96380SRuslan Bukin {
27154b96380SRuslan Bukin 	struct scmi_clk_attrs_out out;
27254b96380SRuslan Bukin 	struct scmi_clk_attrs_in in;
27354b96380SRuslan Bukin 	struct scmi_req req;
27454b96380SRuslan Bukin 	int error;
27554b96380SRuslan Bukin 	char *clock_name;
27654b96380SRuslan Bukin 
27754b96380SRuslan Bukin 	req.protocol_id = SCMI_PROTOCOL_ID_CLOCK;
27854b96380SRuslan Bukin 	req.message_id = SCMI_CLOCK_ATTRIBUTES;
27954b96380SRuslan Bukin 	req.in_buf = &in;
28054b96380SRuslan Bukin 	req.in_size = sizeof(struct scmi_clk_attrs_in);
28154b96380SRuslan Bukin 	req.out_buf = &out;
28254b96380SRuslan Bukin 	req.out_size = sizeof(struct scmi_clk_attrs_out);
28354b96380SRuslan Bukin 
28454b96380SRuslan Bukin 	in.clock_id = index;
28554b96380SRuslan Bukin 
28654b96380SRuslan Bukin 	error = scmi_request(sc->scmi, &req);
28754b96380SRuslan Bukin 	if (error != 0)
28854b96380SRuslan Bukin 		return (error);
28954b96380SRuslan Bukin 
29054b96380SRuslan Bukin 	if (out.status != 0)
29154b96380SRuslan Bukin 		return (ENXIO);
29254b96380SRuslan Bukin 
29354b96380SRuslan Bukin 	if (out.attributes & CLK_ATTRS_EXT_CLK_NAME) {
29454b96380SRuslan Bukin 		error = scmi_clk_get_name(sc, index, &clock_name);
29554b96380SRuslan Bukin 		if (error)
29654b96380SRuslan Bukin 			return (error);
29754b96380SRuslan Bukin 	} else {
29854b96380SRuslan Bukin 		clock_name = malloc(sizeof(out.clock_name), M_DEVBUF, M_WAITOK);
29954b96380SRuslan Bukin 		strncpy(clock_name, out.clock_name, sizeof(out.clock_name));
30054b96380SRuslan Bukin 	}
30154b96380SRuslan Bukin 
30254b96380SRuslan Bukin 	error = scmi_clk_add_node(sc, index, clock_name);
30354b96380SRuslan Bukin 
30454b96380SRuslan Bukin 	return (error);
30554b96380SRuslan Bukin }
30654b96380SRuslan Bukin 
30754b96380SRuslan Bukin static int
30854b96380SRuslan Bukin scmi_clk_discover(struct scmi_clk_softc *sc)
30954b96380SRuslan Bukin {
31054b96380SRuslan Bukin 	struct scmi_clk_protocol_attrs_out out;
31154b96380SRuslan Bukin 	struct scmi_req req;
31254b96380SRuslan Bukin 	int nclocks;
31354b96380SRuslan Bukin 	int failing;
31454b96380SRuslan Bukin 	int error;
31554b96380SRuslan Bukin 	int i;
31654b96380SRuslan Bukin 
31754b96380SRuslan Bukin 	req.protocol_id = SCMI_PROTOCOL_ID_CLOCK;
31854b96380SRuslan Bukin 	req.message_id = SCMI_PROTOCOL_ATTRIBUTES;
31954b96380SRuslan Bukin 	req.in_buf = NULL;
32054b96380SRuslan Bukin 	req.in_size = 0;
32154b96380SRuslan Bukin 	req.out_buf = &out;
32254b96380SRuslan Bukin 	req.out_size = sizeof(struct scmi_clk_protocol_attrs_out);
32354b96380SRuslan Bukin 
32454b96380SRuslan Bukin 	error = scmi_request(sc->scmi, &req);
32554b96380SRuslan Bukin 	if (error != 0)
32654b96380SRuslan Bukin 		return (error);
32754b96380SRuslan Bukin 
32854b96380SRuslan Bukin 	if (out.status != 0)
32954b96380SRuslan Bukin 		return (ENXIO);
33054b96380SRuslan Bukin 
33154b96380SRuslan Bukin 	nclocks = (out.attributes & CLK_ATTRS_NCLOCKS_M) >>
33254b96380SRuslan Bukin 	    CLK_ATTRS_NCLOCKS_S;
33354b96380SRuslan Bukin 
33454b96380SRuslan Bukin 	device_printf(sc->dev, "Found %d clocks.\n", nclocks);
33554b96380SRuslan Bukin 
33654b96380SRuslan Bukin 	failing = 0;
33754b96380SRuslan Bukin 
33854b96380SRuslan Bukin 	for (i = 0; i < nclocks; i++) {
33954b96380SRuslan Bukin 		error = scmi_clk_attrs(sc, i);
34054b96380SRuslan Bukin 		if (error) {
34154b96380SRuslan Bukin 			device_printf(sc->dev,
34254b96380SRuslan Bukin 			    "Could not process clock index %d.\n", i);
34354b96380SRuslan Bukin 			failing++;
34454b96380SRuslan Bukin 		}
34554b96380SRuslan Bukin 	}
34654b96380SRuslan Bukin 
34754b96380SRuslan Bukin 	if (failing == nclocks)
34854b96380SRuslan Bukin 		return (ENXIO);
34954b96380SRuslan Bukin 
35054b96380SRuslan Bukin 	return (0);
35154b96380SRuslan Bukin }
35254b96380SRuslan Bukin 
35354b96380SRuslan Bukin static int
35454b96380SRuslan Bukin scmi_clk_init(struct scmi_clk_softc *sc)
35554b96380SRuslan Bukin {
35654b96380SRuslan Bukin 	int error;
35754b96380SRuslan Bukin 
35854b96380SRuslan Bukin 	/* Create clock domain */
35954b96380SRuslan Bukin 	sc->clkdom = clkdom_create(sc->dev);
36054b96380SRuslan Bukin 	if (sc->clkdom == NULL)
36154b96380SRuslan Bukin 		return (ENXIO);
36254b96380SRuslan Bukin 
36354b96380SRuslan Bukin 	error = scmi_clk_discover(sc);
36454b96380SRuslan Bukin 	if (error) {
36554b96380SRuslan Bukin 		device_printf(sc->dev, "Could not discover clocks.\n");
36654b96380SRuslan Bukin 		return (ENXIO);
36754b96380SRuslan Bukin 	}
36854b96380SRuslan Bukin 
36954b96380SRuslan Bukin 	error = clkdom_finit(sc->clkdom);
37054b96380SRuslan Bukin 	if (error) {
37154b96380SRuslan Bukin 		device_printf(sc->dev, "Failed to init clock domain.\n");
37254b96380SRuslan Bukin 		return (ENXIO);
37354b96380SRuslan Bukin 	}
37454b96380SRuslan Bukin 
37554b96380SRuslan Bukin 	return (0);
37654b96380SRuslan Bukin }
37754b96380SRuslan Bukin 
37854b96380SRuslan Bukin static int
37954b96380SRuslan Bukin scmi_clk_probe(device_t dev)
38054b96380SRuslan Bukin {
38154b96380SRuslan Bukin 	phandle_t node;
38254b96380SRuslan Bukin 	uint32_t reg;
38354b96380SRuslan Bukin 	int error;
38454b96380SRuslan Bukin 
38554b96380SRuslan Bukin 	node = ofw_bus_get_node(dev);
38654b96380SRuslan Bukin 
38754b96380SRuslan Bukin 	error = OF_getencprop(node, "reg", &reg, sizeof(uint32_t));
38854b96380SRuslan Bukin 	if (error < 0)
38954b96380SRuslan Bukin 		return (ENXIO);
39054b96380SRuslan Bukin 
39154b96380SRuslan Bukin 	if (reg != SCMI_PROTOCOL_ID_CLOCK)
39254b96380SRuslan Bukin 		return (ENXIO);
39354b96380SRuslan Bukin 
39454b96380SRuslan Bukin 	device_set_desc(dev, "SCMI Clock Management Unit");
39554b96380SRuslan Bukin 
39654b96380SRuslan Bukin 	return (BUS_PROBE_DEFAULT);
39754b96380SRuslan Bukin }
39854b96380SRuslan Bukin 
39954b96380SRuslan Bukin static int
40054b96380SRuslan Bukin scmi_clk_attach(device_t dev)
40154b96380SRuslan Bukin {
40254b96380SRuslan Bukin 	struct scmi_clk_softc *sc;
40354b96380SRuslan Bukin 	phandle_t node;
40454b96380SRuslan Bukin 
40554b96380SRuslan Bukin 	sc = device_get_softc(dev);
40654b96380SRuslan Bukin 	sc->dev = dev;
40754b96380SRuslan Bukin 	sc->scmi = device_get_parent(dev);
40854b96380SRuslan Bukin 
40954b96380SRuslan Bukin 	node = ofw_bus_get_node(sc->dev);
41054b96380SRuslan Bukin 
41154b96380SRuslan Bukin 	OF_device_register_xref(OF_xref_from_node(node), sc->dev);
41254b96380SRuslan Bukin 
41354b96380SRuslan Bukin 	scmi_clk_init(sc);
41454b96380SRuslan Bukin 
41554b96380SRuslan Bukin 	return (0);
41654b96380SRuslan Bukin }
41754b96380SRuslan Bukin 
41854b96380SRuslan Bukin static int
41954b96380SRuslan Bukin scmi_clk_detach(device_t dev)
42054b96380SRuslan Bukin {
42154b96380SRuslan Bukin 
42254b96380SRuslan Bukin 	return (0);
42354b96380SRuslan Bukin }
42454b96380SRuslan Bukin 
42554b96380SRuslan Bukin static device_method_t scmi_clk_methods[] = {
42654b96380SRuslan Bukin 	/* Device interface */
42754b96380SRuslan Bukin 	DEVMETHOD(device_probe,		scmi_clk_probe),
42854b96380SRuslan Bukin 	DEVMETHOD(device_attach,	scmi_clk_attach),
42954b96380SRuslan Bukin 	DEVMETHOD(device_detach,	scmi_clk_detach),
43054b96380SRuslan Bukin 	DEVMETHOD_END
43154b96380SRuslan Bukin };
43254b96380SRuslan Bukin 
43354b96380SRuslan Bukin static driver_t scmi_clk_driver = {
43454b96380SRuslan Bukin 	"scmi_clk",
43554b96380SRuslan Bukin 	scmi_clk_methods,
43654b96380SRuslan Bukin 	sizeof(struct scmi_clk_softc),
43754b96380SRuslan Bukin };
43854b96380SRuslan Bukin 
43954b96380SRuslan Bukin EARLY_DRIVER_MODULE(scmi_clk, scmi, scmi_clk_driver, 0, 0,
44054b96380SRuslan Bukin     BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
44154b96380SRuslan Bukin MODULE_VERSION(scmi_clk, 1);
442