xref: /freebsd/sys/dev/firmware/arm/scmi_clk.c (revision be82b3a0bf72ed3b5f01ac9fcd8dcd3802e3c742)
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 
38*be82b3a0SEmmanuel 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 
5819a7cf0cSMark Johnston static int __unused
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 {
15754b96380SRuslan Bukin 
15854b96380SRuslan Bukin 	return (0);
15954b96380SRuslan Bukin }
16054b96380SRuslan Bukin 
16154b96380SRuslan Bukin static int
16254b96380SRuslan Bukin scmi_clknode_set_freq(struct clknode *clk, uint64_t fin, uint64_t *fout,
16354b96380SRuslan Bukin     int flags, int *stop)
16454b96380SRuslan Bukin {
16554b96380SRuslan Bukin 	struct scmi_clknode_softc *clk_sc;
16654b96380SRuslan Bukin 	struct scmi_clk_softc *sc;
16754b96380SRuslan Bukin 
16854b96380SRuslan Bukin 	clk_sc = clknode_get_softc(clk);
16954b96380SRuslan Bukin 	sc = device_get_softc(clk_sc->dev);
17054b96380SRuslan Bukin 
17154b96380SRuslan Bukin 	dprintf("%s: %ld\n", __func__, *fout);
17254b96380SRuslan Bukin 
17354b96380SRuslan Bukin 	scmi_clk_set_rate(sc, clk_sc->clock_id, *fout);
17454b96380SRuslan Bukin 
17554b96380SRuslan Bukin 	*stop = 1;
17654b96380SRuslan Bukin 
17754b96380SRuslan Bukin 	return (0);
17854b96380SRuslan Bukin }
17954b96380SRuslan Bukin 
18054b96380SRuslan Bukin static clknode_method_t scmi_clknode_methods[] = {
18154b96380SRuslan Bukin 	/* Device interface */
18254b96380SRuslan Bukin 	CLKNODEMETHOD(clknode_init,		scmi_clknode_init),
18354b96380SRuslan Bukin 	CLKNODEMETHOD(clknode_recalc_freq,	scmi_clknode_recalc_freq),
18454b96380SRuslan Bukin 	CLKNODEMETHOD(clknode_set_freq,		scmi_clknode_set_freq),
18554b96380SRuslan Bukin 	CLKNODEMETHOD_END
18654b96380SRuslan Bukin };
18754b96380SRuslan Bukin 
18854b96380SRuslan Bukin DEFINE_CLASS_1(scmi_clknode, scmi_clknode_class, scmi_clknode_methods,
18954b96380SRuslan Bukin     sizeof(struct scmi_clknode_softc), clknode_class);
19054b96380SRuslan Bukin 
19154b96380SRuslan Bukin static int
19254b96380SRuslan Bukin scmi_clk_add_node(struct scmi_clk_softc *sc, int index, char *clock_name)
19354b96380SRuslan Bukin {
19454b96380SRuslan Bukin 	struct scmi_clknode_softc *clk_sc;
19554b96380SRuslan Bukin 	struct clknode_init_def def;
19654b96380SRuslan Bukin 	struct clknode *clk;
19754b96380SRuslan Bukin 
19854b96380SRuslan Bukin 	memset(&def, 0, sizeof(def));
19954b96380SRuslan Bukin 	def.id = index;
20054b96380SRuslan Bukin 	def.name = clock_name;
20154b96380SRuslan Bukin 	def.parent_names = NULL;
20254b96380SRuslan Bukin 	def.parent_cnt = 0;
20354b96380SRuslan Bukin 
20454b96380SRuslan Bukin 	clk = clknode_create(sc->clkdom, &scmi_clknode_class, &def);
20554b96380SRuslan Bukin 	if (clk == NULL) {
20654b96380SRuslan Bukin 		device_printf(sc->dev, "Cannot create clknode.\n");
20754b96380SRuslan Bukin 		return (ENXIO);
20854b96380SRuslan Bukin 	}
20954b96380SRuslan Bukin 
21054b96380SRuslan Bukin 	clk_sc = clknode_get_softc(clk);
21154b96380SRuslan Bukin 	clk_sc->dev = sc->dev;
21254b96380SRuslan Bukin 	clk_sc->clock_id = index;
21354b96380SRuslan Bukin 
21454b96380SRuslan Bukin 	if (clknode_register(sc->clkdom, clk) == NULL) {
21554b96380SRuslan Bukin 		device_printf(sc->dev, "Could not register clock '%s'.\n",
21654b96380SRuslan Bukin 		    def.name);
21754b96380SRuslan Bukin 		return (ENXIO);
21854b96380SRuslan Bukin 	}
21954b96380SRuslan Bukin 
22054b96380SRuslan Bukin 	device_printf(sc->dev, "Clock '%s' registered.\n", def.name);
22154b96380SRuslan Bukin 
22254b96380SRuslan Bukin 	return (0);
22354b96380SRuslan Bukin }
22454b96380SRuslan Bukin 
22554b96380SRuslan Bukin static int
22654b96380SRuslan Bukin scmi_clk_get_name(struct scmi_clk_softc *sc, int index, char **result)
22754b96380SRuslan Bukin {
22854b96380SRuslan Bukin 	struct scmi_clk_name_get_out out;
22954b96380SRuslan Bukin 	struct scmi_clk_name_get_in in;
23054b96380SRuslan Bukin 	struct scmi_req req;
23154b96380SRuslan Bukin 	char *clock_name;
23254b96380SRuslan Bukin 	int error;
23354b96380SRuslan Bukin 
23454b96380SRuslan Bukin 	req.protocol_id = SCMI_PROTOCOL_ID_CLOCK;
23554b96380SRuslan Bukin 	req.message_id = SCMI_CLOCK_NAME_GET;
23654b96380SRuslan Bukin 	req.in_buf = &in;
23754b96380SRuslan Bukin 	req.in_size = sizeof(struct scmi_clk_name_get_in);
23854b96380SRuslan Bukin 	req.out_buf = &out;
23954b96380SRuslan Bukin 	req.out_size = sizeof(struct scmi_clk_name_get_out);
24054b96380SRuslan Bukin 
24154b96380SRuslan Bukin 	in.clock_id = index;
24254b96380SRuslan Bukin 
24354b96380SRuslan Bukin 	error = scmi_request(sc->scmi, &req);
24454b96380SRuslan Bukin 	if (error != 0)
24554b96380SRuslan Bukin 		return (error);
24654b96380SRuslan Bukin 
24754b96380SRuslan Bukin 	if (out.status != 0)
24854b96380SRuslan Bukin 		return (ENXIO);
24954b96380SRuslan Bukin 
25054b96380SRuslan Bukin 	clock_name = malloc(sizeof(out.name), M_DEVBUF, M_WAITOK);
25154b96380SRuslan Bukin 	strncpy(clock_name, out.name, sizeof(out.name));
25254b96380SRuslan Bukin 
25354b96380SRuslan Bukin 	*result = clock_name;
25454b96380SRuslan Bukin 
25554b96380SRuslan Bukin 	return (0);
25654b96380SRuslan Bukin }
25754b96380SRuslan Bukin 
25854b96380SRuslan Bukin static int
25954b96380SRuslan Bukin scmi_clk_attrs(struct scmi_clk_softc *sc, int index)
26054b96380SRuslan Bukin {
26154b96380SRuslan Bukin 	struct scmi_clk_attrs_out out;
26254b96380SRuslan Bukin 	struct scmi_clk_attrs_in in;
26354b96380SRuslan Bukin 	struct scmi_req req;
26454b96380SRuslan Bukin 	int error;
26554b96380SRuslan Bukin 	char *clock_name;
26654b96380SRuslan Bukin 
26754b96380SRuslan Bukin 	req.protocol_id = SCMI_PROTOCOL_ID_CLOCK;
26854b96380SRuslan Bukin 	req.message_id = SCMI_CLOCK_ATTRIBUTES;
26954b96380SRuslan Bukin 	req.in_buf = &in;
27054b96380SRuslan Bukin 	req.in_size = sizeof(struct scmi_clk_attrs_in);
27154b96380SRuslan Bukin 	req.out_buf = &out;
27254b96380SRuslan Bukin 	req.out_size = sizeof(struct scmi_clk_attrs_out);
27354b96380SRuslan Bukin 
27454b96380SRuslan Bukin 	in.clock_id = index;
27554b96380SRuslan Bukin 
27654b96380SRuslan Bukin 	error = scmi_request(sc->scmi, &req);
27754b96380SRuslan Bukin 	if (error != 0)
27854b96380SRuslan Bukin 		return (error);
27954b96380SRuslan Bukin 
28054b96380SRuslan Bukin 	if (out.status != 0)
28154b96380SRuslan Bukin 		return (ENXIO);
28254b96380SRuslan Bukin 
28354b96380SRuslan Bukin 	if (out.attributes & CLK_ATTRS_EXT_CLK_NAME) {
28454b96380SRuslan Bukin 		error = scmi_clk_get_name(sc, index, &clock_name);
28554b96380SRuslan Bukin 		if (error)
28654b96380SRuslan Bukin 			return (error);
28754b96380SRuslan Bukin 	} else {
28854b96380SRuslan Bukin 		clock_name = malloc(sizeof(out.clock_name), M_DEVBUF, M_WAITOK);
28954b96380SRuslan Bukin 		strncpy(clock_name, out.clock_name, sizeof(out.clock_name));
29054b96380SRuslan Bukin 	}
29154b96380SRuslan Bukin 
29254b96380SRuslan Bukin 	error = scmi_clk_add_node(sc, index, clock_name);
29354b96380SRuslan Bukin 
29454b96380SRuslan Bukin 	return (error);
29554b96380SRuslan Bukin }
29654b96380SRuslan Bukin 
29754b96380SRuslan Bukin static int
29854b96380SRuslan Bukin scmi_clk_discover(struct scmi_clk_softc *sc)
29954b96380SRuslan Bukin {
30054b96380SRuslan Bukin 	struct scmi_clk_protocol_attrs_out out;
30154b96380SRuslan Bukin 	struct scmi_req req;
30254b96380SRuslan Bukin 	int nclocks;
30354b96380SRuslan Bukin 	int failing;
30454b96380SRuslan Bukin 	int error;
30554b96380SRuslan Bukin 	int i;
30654b96380SRuslan Bukin 
30754b96380SRuslan Bukin 	req.protocol_id = SCMI_PROTOCOL_ID_CLOCK;
30854b96380SRuslan Bukin 	req.message_id = SCMI_PROTOCOL_ATTRIBUTES;
30954b96380SRuslan Bukin 	req.in_buf = NULL;
31054b96380SRuslan Bukin 	req.in_size = 0;
31154b96380SRuslan Bukin 	req.out_buf = &out;
31254b96380SRuslan Bukin 	req.out_size = sizeof(struct scmi_clk_protocol_attrs_out);
31354b96380SRuslan Bukin 
31454b96380SRuslan Bukin 	error = scmi_request(sc->scmi, &req);
31554b96380SRuslan Bukin 	if (error != 0)
31654b96380SRuslan Bukin 		return (error);
31754b96380SRuslan Bukin 
31854b96380SRuslan Bukin 	if (out.status != 0)
31954b96380SRuslan Bukin 		return (ENXIO);
32054b96380SRuslan Bukin 
32154b96380SRuslan Bukin 	nclocks = (out.attributes & CLK_ATTRS_NCLOCKS_M) >>
32254b96380SRuslan Bukin 	    CLK_ATTRS_NCLOCKS_S;
32354b96380SRuslan Bukin 
32454b96380SRuslan Bukin 	device_printf(sc->dev, "Found %d clocks.\n", nclocks);
32554b96380SRuslan Bukin 
32654b96380SRuslan Bukin 	failing = 0;
32754b96380SRuslan Bukin 
32854b96380SRuslan Bukin 	for (i = 0; i < nclocks; i++) {
32954b96380SRuslan Bukin 		error = scmi_clk_attrs(sc, i);
33054b96380SRuslan Bukin 		if (error) {
33154b96380SRuslan Bukin 			device_printf(sc->dev,
33254b96380SRuslan Bukin 			    "Could not process clock index %d.\n", i);
33354b96380SRuslan Bukin 			failing++;
33454b96380SRuslan Bukin 		}
33554b96380SRuslan Bukin 	}
33654b96380SRuslan Bukin 
33754b96380SRuslan Bukin 	if (failing == nclocks)
33854b96380SRuslan Bukin 		return (ENXIO);
33954b96380SRuslan Bukin 
34054b96380SRuslan Bukin 	return (0);
34154b96380SRuslan Bukin }
34254b96380SRuslan Bukin 
34354b96380SRuslan Bukin static int
34454b96380SRuslan Bukin scmi_clk_init(struct scmi_clk_softc *sc)
34554b96380SRuslan Bukin {
34654b96380SRuslan Bukin 	int error;
34754b96380SRuslan Bukin 
34854b96380SRuslan Bukin 	/* Create clock domain */
34954b96380SRuslan Bukin 	sc->clkdom = clkdom_create(sc->dev);
35054b96380SRuslan Bukin 	if (sc->clkdom == NULL)
35154b96380SRuslan Bukin 		return (ENXIO);
35254b96380SRuslan Bukin 
35354b96380SRuslan Bukin 	error = scmi_clk_discover(sc);
35454b96380SRuslan Bukin 	if (error) {
35554b96380SRuslan Bukin 		device_printf(sc->dev, "Could not discover clocks.\n");
35654b96380SRuslan Bukin 		return (ENXIO);
35754b96380SRuslan Bukin 	}
35854b96380SRuslan Bukin 
35954b96380SRuslan Bukin 	error = clkdom_finit(sc->clkdom);
36054b96380SRuslan Bukin 	if (error) {
36154b96380SRuslan Bukin 		device_printf(sc->dev, "Failed to init clock domain.\n");
36254b96380SRuslan Bukin 		return (ENXIO);
36354b96380SRuslan Bukin 	}
36454b96380SRuslan Bukin 
36554b96380SRuslan Bukin 	return (0);
36654b96380SRuslan Bukin }
36754b96380SRuslan Bukin 
36854b96380SRuslan Bukin static int
36954b96380SRuslan Bukin scmi_clk_probe(device_t dev)
37054b96380SRuslan Bukin {
37154b96380SRuslan Bukin 	phandle_t node;
37254b96380SRuslan Bukin 	uint32_t reg;
37354b96380SRuslan Bukin 	int error;
37454b96380SRuslan Bukin 
37554b96380SRuslan Bukin 	node = ofw_bus_get_node(dev);
37654b96380SRuslan Bukin 
37754b96380SRuslan Bukin 	error = OF_getencprop(node, "reg", &reg, sizeof(uint32_t));
37854b96380SRuslan Bukin 	if (error < 0)
37954b96380SRuslan Bukin 		return (ENXIO);
38054b96380SRuslan Bukin 
38154b96380SRuslan Bukin 	if (reg != SCMI_PROTOCOL_ID_CLOCK)
38254b96380SRuslan Bukin 		return (ENXIO);
38354b96380SRuslan Bukin 
38454b96380SRuslan Bukin 	device_set_desc(dev, "SCMI Clock Management Unit");
38554b96380SRuslan Bukin 
38654b96380SRuslan Bukin 	return (BUS_PROBE_DEFAULT);
38754b96380SRuslan Bukin }
38854b96380SRuslan Bukin 
38954b96380SRuslan Bukin static int
39054b96380SRuslan Bukin scmi_clk_attach(device_t dev)
39154b96380SRuslan Bukin {
39254b96380SRuslan Bukin 	struct scmi_clk_softc *sc;
39354b96380SRuslan Bukin 	phandle_t node;
39454b96380SRuslan Bukin 
39554b96380SRuslan Bukin 	sc = device_get_softc(dev);
39654b96380SRuslan Bukin 	sc->dev = dev;
39754b96380SRuslan Bukin 	sc->scmi = device_get_parent(dev);
39854b96380SRuslan Bukin 
39954b96380SRuslan Bukin 	node = ofw_bus_get_node(sc->dev);
40054b96380SRuslan Bukin 
40154b96380SRuslan Bukin 	OF_device_register_xref(OF_xref_from_node(node), sc->dev);
40254b96380SRuslan Bukin 
40354b96380SRuslan Bukin 	scmi_clk_init(sc);
40454b96380SRuslan Bukin 
40554b96380SRuslan Bukin 	return (0);
40654b96380SRuslan Bukin }
40754b96380SRuslan Bukin 
40854b96380SRuslan Bukin static int
40954b96380SRuslan Bukin scmi_clk_detach(device_t dev)
41054b96380SRuslan Bukin {
41154b96380SRuslan Bukin 
41254b96380SRuslan Bukin 	return (0);
41354b96380SRuslan Bukin }
41454b96380SRuslan Bukin 
41554b96380SRuslan Bukin static device_method_t scmi_clk_methods[] = {
41654b96380SRuslan Bukin 	/* Device interface */
41754b96380SRuslan Bukin 	DEVMETHOD(device_probe,		scmi_clk_probe),
41854b96380SRuslan Bukin 	DEVMETHOD(device_attach,	scmi_clk_attach),
41954b96380SRuslan Bukin 	DEVMETHOD(device_detach,	scmi_clk_detach),
42054b96380SRuslan Bukin 	DEVMETHOD_END
42154b96380SRuslan Bukin };
42254b96380SRuslan Bukin 
42354b96380SRuslan Bukin static driver_t scmi_clk_driver = {
42454b96380SRuslan Bukin 	"scmi_clk",
42554b96380SRuslan Bukin 	scmi_clk_methods,
42654b96380SRuslan Bukin 	sizeof(struct scmi_clk_softc),
42754b96380SRuslan Bukin };
42854b96380SRuslan Bukin 
42954b96380SRuslan Bukin EARLY_DRIVER_MODULE(scmi_clk, scmi, scmi_clk_driver, 0, 0,
43054b96380SRuslan Bukin     BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
43154b96380SRuslan Bukin MODULE_VERSION(scmi_clk, 1);
432