xref: /freebsd/sys/dev/clk/xilinx/zynqmp_clock.c (revision be82b3a0bf72ed3b5f01ac9fcd8dcd3802e3c742)
14e579ad0SEmmanuel Vadot /*-
24e579ad0SEmmanuel Vadot  * SPDX-License-Identifier: BSD-2-Clause
34e579ad0SEmmanuel Vadot  *
44e579ad0SEmmanuel Vadot  * Copyright (c) 2023 Beckhoff Automation GmbH & Co. KG
54e579ad0SEmmanuel Vadot  *
64e579ad0SEmmanuel Vadot  * Redistribution and use in source and binary forms, with or without
74e579ad0SEmmanuel Vadot  * modification, are permitted provided that the following conditions
84e579ad0SEmmanuel Vadot  * are met:
94e579ad0SEmmanuel Vadot  * 1. Redistributions of source code must retain the above copyright
104e579ad0SEmmanuel Vadot  *    notice, this list of conditions and the following disclaimer.
114e579ad0SEmmanuel Vadot  * 2. Redistributions in binary form must reproduce the above copyright
124e579ad0SEmmanuel Vadot  *    notice, this list of conditions and the following disclaimer in the
134e579ad0SEmmanuel Vadot  *    documentation and/or other materials provided with the distribution.
144e579ad0SEmmanuel Vadot  *
154e579ad0SEmmanuel Vadot  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
164e579ad0SEmmanuel Vadot  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
174e579ad0SEmmanuel Vadot  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
184e579ad0SEmmanuel Vadot  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
194e579ad0SEmmanuel Vadot  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
204e579ad0SEmmanuel Vadot  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
214e579ad0SEmmanuel Vadot  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
224e579ad0SEmmanuel Vadot  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
234e579ad0SEmmanuel Vadot  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
244e579ad0SEmmanuel Vadot  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
254e579ad0SEmmanuel Vadot  * SUCH DAMAGE.
264e579ad0SEmmanuel Vadot  */
274e579ad0SEmmanuel Vadot 
284e579ad0SEmmanuel Vadot #include <sys/cdefs.h>
294e579ad0SEmmanuel Vadot 
304e579ad0SEmmanuel Vadot #include <sys/param.h>
314e579ad0SEmmanuel Vadot #include <sys/systm.h>
324e579ad0SEmmanuel Vadot #include <sys/kernel.h>
334e579ad0SEmmanuel Vadot #include <sys/module.h>
344e579ad0SEmmanuel Vadot #include <sys/malloc.h>
354e579ad0SEmmanuel Vadot #include <sys/bus.h>
364e579ad0SEmmanuel Vadot #include <sys/cpu.h>
374e579ad0SEmmanuel Vadot #include <machine/bus.h>
384e579ad0SEmmanuel Vadot #include <sys/queue.h>
394e579ad0SEmmanuel Vadot 
404e579ad0SEmmanuel Vadot #include <dev/ofw/openfirm.h>
414e579ad0SEmmanuel Vadot #include <dev/ofw/ofw_bus.h>
424e579ad0SEmmanuel Vadot #include <dev/ofw/ofw_bus_subr.h>
434e579ad0SEmmanuel Vadot 
44*be82b3a0SEmmanuel Vadot #include <dev/clk/clk.h>
45*be82b3a0SEmmanuel Vadot #include <dev/clk/clk_fixed.h>
464e579ad0SEmmanuel Vadot 
474e579ad0SEmmanuel Vadot #include <dev/clk/xilinx/zynqmp_clk_mux.h>
484e579ad0SEmmanuel Vadot #include <dev/clk/xilinx/zynqmp_clk_pll.h>
494e579ad0SEmmanuel Vadot #include <dev/clk/xilinx/zynqmp_clk_fixed.h>
504e579ad0SEmmanuel Vadot #include <dev/clk/xilinx/zynqmp_clk_div.h>
514e579ad0SEmmanuel Vadot #include <dev/clk/xilinx/zynqmp_clk_gate.h>
524e579ad0SEmmanuel Vadot 
534e579ad0SEmmanuel Vadot #include <dev/firmware/xilinx/pm_defs.h>
544e579ad0SEmmanuel Vadot 
554e579ad0SEmmanuel Vadot #include "clkdev_if.h"
564e579ad0SEmmanuel Vadot #include "zynqmp_firmware_if.h"
574e579ad0SEmmanuel Vadot 
584e579ad0SEmmanuel Vadot #define	ZYNQMP_MAX_NAME_LEN	16
594e579ad0SEmmanuel Vadot #define	ZYNQMP_MAX_NODES	6
604e579ad0SEmmanuel Vadot #define	ZYNQMP_MAX_PARENTS	100
614e579ad0SEmmanuel Vadot 
624e579ad0SEmmanuel Vadot #define	ZYNQMP_CLK_IS_VALID	(1 << 0)
634e579ad0SEmmanuel Vadot #define	ZYNQMP_CLK_IS_EXT	(1 << 2)
644e579ad0SEmmanuel Vadot 
654e579ad0SEmmanuel Vadot #define	ZYNQMP_GET_NODE_TYPE(x)		(x & 0x7)
664e579ad0SEmmanuel Vadot #define	ZYNQMP_GET_NODE_CLKFLAGS(x)	((x >> 8) & 0xFF)
674e579ad0SEmmanuel Vadot #define	ZYNQMP_GET_NODE_TYPEFLAGS(x)	((x >> 24) & 0xF)
684e579ad0SEmmanuel Vadot 
694e579ad0SEmmanuel Vadot enum ZYNQMP_NODE_TYPE {
704e579ad0SEmmanuel Vadot 	CLK_NODE_TYPE_NULL = 0,
714e579ad0SEmmanuel Vadot 	CLK_NODE_TYPE_MUX,
724e579ad0SEmmanuel Vadot 	CLK_NODE_TYPE_PLL,
734e579ad0SEmmanuel Vadot 	CLK_NODE_TYPE_FIXED,
744e579ad0SEmmanuel Vadot 	CLK_NODE_TYPE_DIV0,
754e579ad0SEmmanuel Vadot 	CLK_NODE_TYPE_DIV1,
764e579ad0SEmmanuel Vadot 	CLK_NODE_TYPE_GATE,
774e579ad0SEmmanuel Vadot };
784e579ad0SEmmanuel Vadot 
794e579ad0SEmmanuel Vadot /*
804e579ad0SEmmanuel Vadot  * Clock IDs in the firmware starts at 0 but
814e579ad0SEmmanuel Vadot  * exported clocks (and so clock exposed by the clock framework)
824e579ad0SEmmanuel Vadot  * starts at 1
834e579ad0SEmmanuel Vadot  */
844e579ad0SEmmanuel Vadot #define	ZYNQMP_ID_TO_CLK(x)	((x) + 1)
854e579ad0SEmmanuel Vadot #define	CLK_ID_TO_ZYNQMP(x)	((x) - 1)
864e579ad0SEmmanuel Vadot 
874e579ad0SEmmanuel Vadot struct zynqmp_clk {
884e579ad0SEmmanuel Vadot 	TAILQ_ENTRY(zynqmp_clk)	next;
894e579ad0SEmmanuel Vadot 	struct clknode_init_def	clkdef;
904e579ad0SEmmanuel Vadot 	uint32_t		id;
914e579ad0SEmmanuel Vadot 	uint32_t		parentids[ZYNQMP_MAX_PARENTS];
924e579ad0SEmmanuel Vadot 	uint32_t		topology[ZYNQMP_MAX_NODES];
934e579ad0SEmmanuel Vadot 	uint32_t		attributes;
944e579ad0SEmmanuel Vadot };
954e579ad0SEmmanuel Vadot 
964e579ad0SEmmanuel Vadot struct zynqmp_clock_softc {
974e579ad0SEmmanuel Vadot 	device_t			dev;
984e579ad0SEmmanuel Vadot 	device_t			parent;
994e579ad0SEmmanuel Vadot 	phandle_t			node;
1004e579ad0SEmmanuel Vadot 	clk_t				clk_pss_ref;
1014e579ad0SEmmanuel Vadot 	clk_t				clk_video;
1024e579ad0SEmmanuel Vadot 	clk_t				clk_pss_alt_ref;
1034e579ad0SEmmanuel Vadot 	clk_t				clk_aux_ref;
1044e579ad0SEmmanuel Vadot 	clk_t				clk_gt_crx_ref;
1054e579ad0SEmmanuel Vadot 	struct clkdom			*clkdom;
1064e579ad0SEmmanuel Vadot };
1074e579ad0SEmmanuel Vadot 
1084e579ad0SEmmanuel Vadot struct name_resp {
1094e579ad0SEmmanuel Vadot 	char name[16];
1104e579ad0SEmmanuel Vadot };
1114e579ad0SEmmanuel Vadot 
1124e579ad0SEmmanuel Vadot struct zynqmp_clk_softc {
1134e579ad0SEmmanuel Vadot 	struct zynqmp_clk	*clk;
1144e579ad0SEmmanuel Vadot 	device_t		firmware;
1154e579ad0SEmmanuel Vadot 	uint32_t		id;
1164e579ad0SEmmanuel Vadot };
1174e579ad0SEmmanuel Vadot 
1184e579ad0SEmmanuel Vadot static int
zynqmp_clk_init(struct clknode * clk,device_t dev)1194e579ad0SEmmanuel Vadot zynqmp_clk_init(struct clknode *clk, device_t dev)
1204e579ad0SEmmanuel Vadot {
1214e579ad0SEmmanuel Vadot 
1224e579ad0SEmmanuel Vadot 	clknode_init_parent_idx(clk, 0);
1234e579ad0SEmmanuel Vadot 	return (0);
1244e579ad0SEmmanuel Vadot }
1254e579ad0SEmmanuel Vadot 
1264e579ad0SEmmanuel Vadot static clknode_method_t zynqmp_clk_clknode_methods[] = {
1274e579ad0SEmmanuel Vadot 	/* Device interface */
1284e579ad0SEmmanuel Vadot 	CLKNODEMETHOD(clknode_init,		zynqmp_clk_init),
1294e579ad0SEmmanuel Vadot 	CLKNODEMETHOD_END
1304e579ad0SEmmanuel Vadot };
1314e579ad0SEmmanuel Vadot 
1324e579ad0SEmmanuel Vadot DEFINE_CLASS_1(zynqmp_clk_clknode, zynqmp_clk_clknode_class,
1334e579ad0SEmmanuel Vadot     zynqmp_clk_clknode_methods, sizeof(struct zynqmp_clk_softc), clknode_class);
1344e579ad0SEmmanuel Vadot 
1354e579ad0SEmmanuel Vadot static int
zynqmp_clk_register(struct clkdom * clkdom,device_t fw,struct zynqmp_clk * clkdef)1364e579ad0SEmmanuel Vadot zynqmp_clk_register(struct clkdom *clkdom, device_t fw, struct zynqmp_clk *clkdef)
1374e579ad0SEmmanuel Vadot {
1384e579ad0SEmmanuel Vadot 	struct clknode *clknode;
1394e579ad0SEmmanuel Vadot 	struct zynqmp_clk_softc *sc;
1404e579ad0SEmmanuel Vadot 	char *prev_clock_name = NULL;
1414e579ad0SEmmanuel Vadot 	char *clkname, *parent_name;
1424e579ad0SEmmanuel Vadot 	struct clknode_init_def *zynqclk;
1434e579ad0SEmmanuel Vadot 	int i;
1444e579ad0SEmmanuel Vadot 
1454e579ad0SEmmanuel Vadot 	for (i = 0; i < ZYNQMP_MAX_NODES; i++) {
1464e579ad0SEmmanuel Vadot 		/* Bail early if we have no node */
1474e579ad0SEmmanuel Vadot 		if (ZYNQMP_GET_NODE_TYPE(clkdef->topology[i]) == CLK_NODE_TYPE_NULL)
1484e579ad0SEmmanuel Vadot 			break;
1494e579ad0SEmmanuel Vadot 		zynqclk = malloc(sizeof(*zynqclk), M_DEVBUF, M_WAITOK | M_ZERO);
1504e579ad0SEmmanuel Vadot 		zynqclk->id = clkdef->clkdef.id;
1514e579ad0SEmmanuel Vadot 		/* For the first node in the topology we use the main clock parents */
1524e579ad0SEmmanuel Vadot 		if (i == 0) {
1534e579ad0SEmmanuel Vadot 			zynqclk->parent_cnt = clkdef->clkdef.parent_cnt;
1544e579ad0SEmmanuel Vadot 			zynqclk->parent_names = clkdef->clkdef.parent_names;
1554e579ad0SEmmanuel Vadot 		} else {
1564e579ad0SEmmanuel Vadot 			zynqclk->parent_cnt = 1;
1574e579ad0SEmmanuel Vadot 			zynqclk->parent_names = malloc(sizeof(char *) * zynqclk->parent_cnt, M_DEVBUF, M_ZERO | M_WAITOK);
1584e579ad0SEmmanuel Vadot 			parent_name = strdup(prev_clock_name, M_DEVBUF);
1594e579ad0SEmmanuel Vadot 			zynqclk->parent_names[0] = (const char *)parent_name;
1604e579ad0SEmmanuel Vadot 		}
1614e579ad0SEmmanuel Vadot 		/* Register the clock node based on the topology type */
1624e579ad0SEmmanuel Vadot 		switch (ZYNQMP_GET_NODE_TYPE(clkdef->topology[i])) {
1634e579ad0SEmmanuel Vadot 		case CLK_NODE_TYPE_MUX:
1644e579ad0SEmmanuel Vadot 			asprintf(&clkname, M_DEVBUF, "%s_mux", clkdef->clkdef.name);
1654e579ad0SEmmanuel Vadot 			zynqclk->name = (const char *)clkname;
1664e579ad0SEmmanuel Vadot 			zynqmp_clk_mux_register(clkdom, fw, zynqclk);
1674e579ad0SEmmanuel Vadot 			break;
1684e579ad0SEmmanuel Vadot 		case CLK_NODE_TYPE_PLL:
1694e579ad0SEmmanuel Vadot 			asprintf(&clkname, M_DEVBUF, "%s_pll", clkdef->clkdef.name);
1704e579ad0SEmmanuel Vadot 			zynqclk->name = (const char *)clkname;
1714e579ad0SEmmanuel Vadot 			zynqmp_clk_pll_register(clkdom, fw, zynqclk);
1724e579ad0SEmmanuel Vadot 			break;
1734e579ad0SEmmanuel Vadot 		case CLK_NODE_TYPE_FIXED:
1744e579ad0SEmmanuel Vadot 			asprintf(&clkname, M_DEVBUF, "%s_fixed", clkdef->clkdef.name);
1754e579ad0SEmmanuel Vadot 			zynqclk->name = (const char *)clkname;
1764e579ad0SEmmanuel Vadot 			zynqmp_clk_fixed_register(clkdom, fw, zynqclk);
1774e579ad0SEmmanuel Vadot 			break;
1784e579ad0SEmmanuel Vadot 		case CLK_NODE_TYPE_DIV0:
1794e579ad0SEmmanuel Vadot 			asprintf(&clkname, M_DEVBUF, "%s_div0", clkdef->clkdef.name);
1804e579ad0SEmmanuel Vadot 			zynqclk->name = (const char *)clkname;
1814e579ad0SEmmanuel Vadot 			zynqmp_clk_div_register(clkdom, fw, zynqclk, CLK_DIV_TYPE_DIV0);
1824e579ad0SEmmanuel Vadot 			break;
1834e579ad0SEmmanuel Vadot 		case CLK_NODE_TYPE_DIV1:
1844e579ad0SEmmanuel Vadot 			asprintf(&clkname, M_DEVBUF, "%s_div1", clkdef->clkdef.name);
1854e579ad0SEmmanuel Vadot 			zynqclk->name = (const char *)clkname;
1864e579ad0SEmmanuel Vadot 			zynqmp_clk_div_register(clkdom, fw, zynqclk, CLK_DIV_TYPE_DIV1);
1874e579ad0SEmmanuel Vadot 			break;
1884e579ad0SEmmanuel Vadot 		case CLK_NODE_TYPE_GATE:
1894e579ad0SEmmanuel Vadot 			asprintf(&clkname, M_DEVBUF, "%s_gate", clkdef->clkdef.name);
1904e579ad0SEmmanuel Vadot 			zynqclk->name = (const char *)clkname;
1914e579ad0SEmmanuel Vadot 			zynqmp_clk_gate_register(clkdom, fw, zynqclk);
1924e579ad0SEmmanuel Vadot 			break;
1934e579ad0SEmmanuel Vadot 		case CLK_NODE_TYPE_NULL:
1944e579ad0SEmmanuel Vadot 		default:
1954e579ad0SEmmanuel Vadot 			clkname = NULL;
1964e579ad0SEmmanuel Vadot 			break;
1974e579ad0SEmmanuel Vadot 		}
1984e579ad0SEmmanuel Vadot 		if (i != 0) {
1994e579ad0SEmmanuel Vadot 			free(parent_name, M_DEVBUF);
2004e579ad0SEmmanuel Vadot 			free(zynqclk->parent_names, M_DEVBUF);
2014e579ad0SEmmanuel Vadot 		}
2024e579ad0SEmmanuel Vadot 		if (clkname != NULL)
2034e579ad0SEmmanuel Vadot 			prev_clock_name = strdup(clkname, M_DEVBUF);
2044e579ad0SEmmanuel Vadot 		free(clkname, M_DEVBUF);
2054e579ad0SEmmanuel Vadot 		free(zynqclk, M_DEVBUF);
2064e579ad0SEmmanuel Vadot 	}
2074e579ad0SEmmanuel Vadot 
2084e579ad0SEmmanuel Vadot 	/* Register main clock */
2094e579ad0SEmmanuel Vadot 	clkdef->clkdef.name = clkdef->clkdef.name;
2104e579ad0SEmmanuel Vadot 	clkdef->clkdef.parent_cnt = 1;
2114e579ad0SEmmanuel Vadot 	clkdef->clkdef.parent_names = malloc(sizeof(char *) * clkdef->clkdef.parent_cnt, M_DEVBUF, M_ZERO | M_WAITOK);
2124e579ad0SEmmanuel Vadot 	clkdef->clkdef.parent_names[0] = strdup(prev_clock_name, M_DEVBUF);
2134e579ad0SEmmanuel Vadot 	clknode = clknode_create(clkdom, &zynqmp_clk_clknode_class, &clkdef->clkdef);
2144e579ad0SEmmanuel Vadot 	if (clknode == NULL)
2154e579ad0SEmmanuel Vadot 		return (1);
2164e579ad0SEmmanuel Vadot 	sc = clknode_get_softc(clknode);
2174e579ad0SEmmanuel Vadot 	sc->id = clkdef->clkdef.id - 1;
2184e579ad0SEmmanuel Vadot 	sc->firmware = fw;
2194e579ad0SEmmanuel Vadot 	sc->clk = clkdef;
2204e579ad0SEmmanuel Vadot 	clknode_register(clkdom, clknode);
2214e579ad0SEmmanuel Vadot 	return (0);
2224e579ad0SEmmanuel Vadot }
2234e579ad0SEmmanuel Vadot 
2244e579ad0SEmmanuel Vadot static int
zynqmp_fw_clk_get_name(struct zynqmp_clock_softc * sc,struct zynqmp_clk * clk,uint32_t id)2254e579ad0SEmmanuel Vadot zynqmp_fw_clk_get_name(struct zynqmp_clock_softc *sc, struct zynqmp_clk *clk, uint32_t id)
2264e579ad0SEmmanuel Vadot {
2274e579ad0SEmmanuel Vadot 	char *clkname;
2284e579ad0SEmmanuel Vadot 	uint32_t query_data[4];
2294e579ad0SEmmanuel Vadot 	int rv;
2304e579ad0SEmmanuel Vadot 
2314e579ad0SEmmanuel Vadot 	rv = ZYNQMP_FIRMWARE_QUERY_DATA(sc->parent, PM_QID_CLOCK_GET_NAME, id, 0, 0, query_data);
2324e579ad0SEmmanuel Vadot 	if (rv != 0)
2334e579ad0SEmmanuel Vadot 		return (rv);
2344e579ad0SEmmanuel Vadot 	if (query_data[0] == '\0')
2354e579ad0SEmmanuel Vadot 		return (EINVAL);
2364e579ad0SEmmanuel Vadot 	clkname = malloc(ZYNQMP_MAX_NAME_LEN, M_DEVBUF, M_ZERO | M_WAITOK);
2374e579ad0SEmmanuel Vadot 	memcpy(clkname, query_data, ZYNQMP_MAX_NAME_LEN);
2384e579ad0SEmmanuel Vadot 	clk->clkdef.name = clkname;
2394e579ad0SEmmanuel Vadot 	return (0);
2404e579ad0SEmmanuel Vadot }
2414e579ad0SEmmanuel Vadot 
2424e579ad0SEmmanuel Vadot static int
zynqmp_fw_clk_get_attributes(struct zynqmp_clock_softc * sc,struct zynqmp_clk * clk,uint32_t id)2434e579ad0SEmmanuel Vadot zynqmp_fw_clk_get_attributes(struct zynqmp_clock_softc *sc, struct zynqmp_clk *clk, uint32_t id)
2444e579ad0SEmmanuel Vadot {
2454e579ad0SEmmanuel Vadot 	uint32_t query_data[4];
2464e579ad0SEmmanuel Vadot 	int rv;
2474e579ad0SEmmanuel Vadot 
2484e579ad0SEmmanuel Vadot 	rv = ZYNQMP_FIRMWARE_QUERY_DATA(sc->parent, PM_QID_CLOCK_GET_ATTRIBUTES, id, 0, 0, query_data);
2494e579ad0SEmmanuel Vadot 	if (rv != 0)
2504e579ad0SEmmanuel Vadot 		return (rv);
2514e579ad0SEmmanuel Vadot 	clk->attributes = query_data[1];
2524e579ad0SEmmanuel Vadot 	return (0);
2534e579ad0SEmmanuel Vadot }
2544e579ad0SEmmanuel Vadot 
2554e579ad0SEmmanuel Vadot static int
zynqmp_fw_clk_get_parents(struct zynqmp_clock_softc * sc,struct zynqmp_clk * clk,uint32_t id)2564e579ad0SEmmanuel Vadot zynqmp_fw_clk_get_parents(struct zynqmp_clock_softc *sc, struct zynqmp_clk *clk, uint32_t id)
2574e579ad0SEmmanuel Vadot {
2584e579ad0SEmmanuel Vadot 	int rv, i;
2594e579ad0SEmmanuel Vadot 	uint32_t query_data[4];
2604e579ad0SEmmanuel Vadot 
2614e579ad0SEmmanuel Vadot 	for (i = 0; i < ZYNQMP_MAX_PARENTS; i += 3) {
2624e579ad0SEmmanuel Vadot 		clk->parentids[i] = -1;
2634e579ad0SEmmanuel Vadot 		clk->parentids[i + 1] = -1;
2644e579ad0SEmmanuel Vadot 		clk->parentids[i + 2] = -1;
2654e579ad0SEmmanuel Vadot 		rv = ZYNQMP_FIRMWARE_QUERY_DATA(sc->parent, PM_QID_CLOCK_GET_PARENTS, id, i, 0, query_data);
2664e579ad0SEmmanuel Vadot 		clk->parentids[i] = query_data[1] & 0xFFFF;
2674e579ad0SEmmanuel Vadot 		clk->parentids[i + 1] = query_data[2] & 0xFFFF;
2684e579ad0SEmmanuel Vadot 		clk->parentids[i + 2] = query_data[3] & 0xFFFF;
2694e579ad0SEmmanuel Vadot 		if ((int32_t)query_data[1] == -1) {
2704e579ad0SEmmanuel Vadot 			clk->parentids[i] = -1;
2714e579ad0SEmmanuel Vadot 			break;
2724e579ad0SEmmanuel Vadot 		}
2734e579ad0SEmmanuel Vadot 		clk->parentids[i] += 1;
2744e579ad0SEmmanuel Vadot 		clk->clkdef.parent_cnt++;
2754e579ad0SEmmanuel Vadot 		if ((int32_t)query_data[2] == -1) {
2764e579ad0SEmmanuel Vadot 			clk->parentids[i + 1] = -1;
2774e579ad0SEmmanuel Vadot 			break;
2784e579ad0SEmmanuel Vadot 		}
2794e579ad0SEmmanuel Vadot 		clk->parentids[i + 1] += 1;
2804e579ad0SEmmanuel Vadot 		clk->clkdef.parent_cnt++;
2814e579ad0SEmmanuel Vadot 		if ((int32_t)query_data[3] == -1) {
2824e579ad0SEmmanuel Vadot 			clk->parentids[i + 2] = -1;
2834e579ad0SEmmanuel Vadot 			break;
2844e579ad0SEmmanuel Vadot 		}
2854e579ad0SEmmanuel Vadot 		clk->parentids[i + 2] += 1;
2864e579ad0SEmmanuel Vadot 		clk->clkdef.parent_cnt++;
2874e579ad0SEmmanuel Vadot 		if ((int32_t)query_data[1] == -2)
2884e579ad0SEmmanuel Vadot 			clk->parentids[i] = -2;
2894e579ad0SEmmanuel Vadot 		if ((int32_t)query_data[2] == -2)
2904e579ad0SEmmanuel Vadot 			clk->parentids[i + 1] = -2;
2914e579ad0SEmmanuel Vadot 		if ((int32_t)query_data[3] == -2)
2924e579ad0SEmmanuel Vadot 			clk->parentids[i + 2] = -2;
2934e579ad0SEmmanuel Vadot 		if (rv != 0)
2944e579ad0SEmmanuel Vadot 			break;
2954e579ad0SEmmanuel Vadot 	}
2964e579ad0SEmmanuel Vadot 	return (0);
2974e579ad0SEmmanuel Vadot }
2984e579ad0SEmmanuel Vadot 
2994e579ad0SEmmanuel Vadot static int
zynqmp_fw_clk_get_topology(struct zynqmp_clock_softc * sc,struct zynqmp_clk * clk,uint32_t id)3004e579ad0SEmmanuel Vadot zynqmp_fw_clk_get_topology(struct zynqmp_clock_softc *sc, struct zynqmp_clk *clk, uint32_t id)
3014e579ad0SEmmanuel Vadot {
3024e579ad0SEmmanuel Vadot 	uint32_t query_data[4];
3034e579ad0SEmmanuel Vadot 	int rv;
3044e579ad0SEmmanuel Vadot 
3054e579ad0SEmmanuel Vadot 	rv = ZYNQMP_FIRMWARE_QUERY_DATA(sc->parent, PM_QID_CLOCK_GET_TOPOLOGY, id, 0, 0, query_data);
3064e579ad0SEmmanuel Vadot 	if (rv != 0)
3074e579ad0SEmmanuel Vadot 		return (rv);
3084e579ad0SEmmanuel Vadot 	clk->topology[0] = query_data[1];
3094e579ad0SEmmanuel Vadot 	clk->topology[1] = query_data[2];
3104e579ad0SEmmanuel Vadot 	clk->topology[2] = query_data[3];
3114e579ad0SEmmanuel Vadot 	if (query_data[3] == '\0')
3124e579ad0SEmmanuel Vadot 		goto out;
3134e579ad0SEmmanuel Vadot 	rv = ZYNQMP_FIRMWARE_QUERY_DATA(sc->parent, PM_QID_CLOCK_GET_TOPOLOGY, id, 3, 0, query_data);
3144e579ad0SEmmanuel Vadot 	if (rv != 0)
3154e579ad0SEmmanuel Vadot 		return (rv);
3164e579ad0SEmmanuel Vadot 	clk->topology[3] = query_data[1];
3174e579ad0SEmmanuel Vadot 	clk->topology[4] = query_data[2];
3184e579ad0SEmmanuel Vadot 	clk->topology[5] = query_data[3];
3194e579ad0SEmmanuel Vadot 
3204e579ad0SEmmanuel Vadot out:
3214e579ad0SEmmanuel Vadot 	return (0);
3224e579ad0SEmmanuel Vadot }
3234e579ad0SEmmanuel Vadot 
3244e579ad0SEmmanuel Vadot static int
zynqmp_clock_ofw_map(struct clkdom * clkdom,uint32_t ncells,phandle_t * cells,struct clknode ** clk)3254e579ad0SEmmanuel Vadot zynqmp_clock_ofw_map(struct clkdom *clkdom, uint32_t ncells,
3264e579ad0SEmmanuel Vadot     phandle_t *cells, struct clknode **clk)
3274e579ad0SEmmanuel Vadot {
3284e579ad0SEmmanuel Vadot 
3294e579ad0SEmmanuel Vadot 	if (ncells != 1)
3304e579ad0SEmmanuel Vadot 		return (ERANGE);
3314e579ad0SEmmanuel Vadot 	*clk = clknode_find_by_id(clkdom, ZYNQMP_ID_TO_CLK(cells[0]));
3324e579ad0SEmmanuel Vadot 	if (*clk == NULL)
3334e579ad0SEmmanuel Vadot 		return (ENXIO);
3344e579ad0SEmmanuel Vadot 	return (0);
3354e579ad0SEmmanuel Vadot }
3364e579ad0SEmmanuel Vadot 
3374e579ad0SEmmanuel Vadot static int
zynqmp_fw_clk_get_all(struct zynqmp_clock_softc * sc)3384e579ad0SEmmanuel Vadot zynqmp_fw_clk_get_all(struct zynqmp_clock_softc *sc)
3394e579ad0SEmmanuel Vadot {
3404e579ad0SEmmanuel Vadot 	TAILQ_HEAD(tailhead, zynqmp_clk)	clk_list;
3414e579ad0SEmmanuel Vadot 	struct zynqmp_clk *clk, *tmp, *tmp2;
3424e579ad0SEmmanuel Vadot 	char *clkname;
3434e579ad0SEmmanuel Vadot 	int rv, i;
3444e579ad0SEmmanuel Vadot 	uint32_t query_data[4], num_clock;
3454e579ad0SEmmanuel Vadot 
3464e579ad0SEmmanuel Vadot 	TAILQ_INIT(&clk_list);
3474e579ad0SEmmanuel Vadot 	rv = ZYNQMP_FIRMWARE_QUERY_DATA(sc->parent,
3484e579ad0SEmmanuel Vadot 	    PM_QID_CLOCK_GET_NUM_CLOCKS,
3494e579ad0SEmmanuel Vadot 	    0,
3504e579ad0SEmmanuel Vadot 	    0,
3514e579ad0SEmmanuel Vadot 	    0,
3524e579ad0SEmmanuel Vadot 	    query_data);
3534e579ad0SEmmanuel Vadot 	if (rv != 0) {
3544e579ad0SEmmanuel Vadot 		device_printf(sc->dev, "Cannot get clock details from the firmware\n");
3554e579ad0SEmmanuel Vadot 		return (ENXIO);
3564e579ad0SEmmanuel Vadot 	}
3574e579ad0SEmmanuel Vadot 
3584e579ad0SEmmanuel Vadot 	num_clock = query_data[1];
3594e579ad0SEmmanuel Vadot 	for (i = 0; i < num_clock; i++) {
3604e579ad0SEmmanuel Vadot 		clk = malloc(sizeof(*clk), M_DEVBUF, M_WAITOK | M_ZERO);
3614e579ad0SEmmanuel Vadot 		clk->clkdef.id = ZYNQMP_ID_TO_CLK(i);
3624e579ad0SEmmanuel Vadot 		zynqmp_fw_clk_get_name(sc, clk, i);
3634e579ad0SEmmanuel Vadot 		zynqmp_fw_clk_get_attributes(sc, clk, i);
3644e579ad0SEmmanuel Vadot 		if ((clk->attributes & ZYNQMP_CLK_IS_VALID) == 0) {
3654e579ad0SEmmanuel Vadot 			free(clk, M_DEVBUF);
3664e579ad0SEmmanuel Vadot 			continue;
3674e579ad0SEmmanuel Vadot 		}
3684e579ad0SEmmanuel Vadot 		if (clk->attributes & ZYNQMP_CLK_IS_EXT)
3694e579ad0SEmmanuel Vadot 			goto skip_ext;
3704e579ad0SEmmanuel Vadot 		/* Get parents id */
3714e579ad0SEmmanuel Vadot 		rv = zynqmp_fw_clk_get_parents(sc, clk, i);
3724e579ad0SEmmanuel Vadot 		if (rv != 0) {
3734e579ad0SEmmanuel Vadot 			device_printf(sc->dev, "Cannot get parent for %s\n", clk->clkdef.name);
3744e579ad0SEmmanuel Vadot 			free(clk, M_DEVBUF);
3754e579ad0SEmmanuel Vadot 			continue;
3764e579ad0SEmmanuel Vadot 		}
3774e579ad0SEmmanuel Vadot 		/* Get topology */
3784e579ad0SEmmanuel Vadot 		rv = zynqmp_fw_clk_get_topology(sc, clk, i);
3794e579ad0SEmmanuel Vadot 		if (rv != 0) {
3804e579ad0SEmmanuel Vadot 			device_printf(sc->dev, "Cannot get topology for %s\n", clk->clkdef.name);
3814e579ad0SEmmanuel Vadot 			free(clk, M_DEVBUF);
3824e579ad0SEmmanuel Vadot 			continue;
3834e579ad0SEmmanuel Vadot 		}
3844e579ad0SEmmanuel Vadot 	skip_ext:
3854e579ad0SEmmanuel Vadot 		TAILQ_INSERT_TAIL(&clk_list, clk, next);
3864e579ad0SEmmanuel Vadot 	}
3874e579ad0SEmmanuel Vadot 
3884e579ad0SEmmanuel Vadot 	/* Add a dummy clock */
3894e579ad0SEmmanuel Vadot 	clk = malloc(sizeof(*clk), M_DEVBUF, M_WAITOK | M_ZERO);
3904e579ad0SEmmanuel Vadot 	clkname = strdup("dummy", M_DEVBUF);
3914e579ad0SEmmanuel Vadot 	clk->clkdef.name = (const char *)clkname;
3924e579ad0SEmmanuel Vadot 	clk->clkdef.id = i;
3934e579ad0SEmmanuel Vadot 	clk->attributes = ZYNQMP_CLK_IS_EXT;
3944e579ad0SEmmanuel Vadot 	TAILQ_INSERT_TAIL(&clk_list, clk, next);
3954e579ad0SEmmanuel Vadot 
3964e579ad0SEmmanuel Vadot 	/* Map parents id to name */
3974e579ad0SEmmanuel Vadot 	TAILQ_FOREACH_SAFE(clk, &clk_list, next, tmp) {
3984e579ad0SEmmanuel Vadot 		if (clk->attributes & ZYNQMP_CLK_IS_EXT)
3994e579ad0SEmmanuel Vadot 			continue;
4004e579ad0SEmmanuel Vadot 		clk->clkdef.parent_names = malloc(sizeof(char *) * clk->clkdef.parent_cnt, M_DEVBUF, M_ZERO | M_WAITOK);
4014e579ad0SEmmanuel Vadot 		for (i = 0; i < ZYNQMP_MAX_PARENTS; i++) {
4024e579ad0SEmmanuel Vadot 			if (clk->parentids[i] == -1)
4034e579ad0SEmmanuel Vadot 				break;
4044e579ad0SEmmanuel Vadot 			if (clk->parentids[i] == -2) {
4054e579ad0SEmmanuel Vadot 				clk->clkdef.parent_names[i] = strdup("dummy", M_DEVBUF);
4064e579ad0SEmmanuel Vadot 				continue;
4074e579ad0SEmmanuel Vadot 			}
4084e579ad0SEmmanuel Vadot 			TAILQ_FOREACH(tmp2, &clk_list, next) {
4094e579ad0SEmmanuel Vadot 				if (tmp2->clkdef.id == clk->parentids[i]) {
4104e579ad0SEmmanuel Vadot 					if (tmp2->attributes & ZYNQMP_CLK_IS_EXT) {
4114e579ad0SEmmanuel Vadot 						int idx;
4124e579ad0SEmmanuel Vadot 
4134e579ad0SEmmanuel Vadot 						if (ofw_bus_find_string_index( sc->node,
4144e579ad0SEmmanuel Vadot 						    "clock-names", tmp2->clkdef.name, &idx) == ENOENT)
4154e579ad0SEmmanuel Vadot 							clk->clkdef.parent_names[i] = strdup("dummy", M_DEVBUF);
4164e579ad0SEmmanuel Vadot 						else
4174e579ad0SEmmanuel Vadot 							clk->clkdef.parent_names[i] = strdup(tmp2->clkdef.name, M_DEVBUF);
4184e579ad0SEmmanuel Vadot 					}
4194e579ad0SEmmanuel Vadot 					else
4204e579ad0SEmmanuel Vadot 						clk->clkdef.parent_names[i] = strdup(tmp2->clkdef.name, M_DEVBUF);
4214e579ad0SEmmanuel Vadot 					break;
4224e579ad0SEmmanuel Vadot 				}
4234e579ad0SEmmanuel Vadot 			}
4244e579ad0SEmmanuel Vadot 		}
4254e579ad0SEmmanuel Vadot 	}
4264e579ad0SEmmanuel Vadot 
4274e579ad0SEmmanuel Vadot 	sc->clkdom = clkdom_create(sc->dev);
4284e579ad0SEmmanuel Vadot 	if (sc->clkdom == NULL)
4294e579ad0SEmmanuel Vadot 		panic("Cannot create clkdom\n");
4304e579ad0SEmmanuel Vadot 	clkdom_set_ofw_mapper(sc->clkdom, zynqmp_clock_ofw_map);
4314e579ad0SEmmanuel Vadot 
4324e579ad0SEmmanuel Vadot 	/* Register the clocks */
4334e579ad0SEmmanuel Vadot 	TAILQ_FOREACH_SAFE(clk, &clk_list, next, tmp) {
4344e579ad0SEmmanuel Vadot 		if (clk->attributes & ZYNQMP_CLK_IS_EXT) {
4354e579ad0SEmmanuel Vadot 			if (strcmp(clk->clkdef.name, "dummy") == 0) {
4364e579ad0SEmmanuel Vadot 				struct clk_fixed_def dummy;
4374e579ad0SEmmanuel Vadot 
4384e579ad0SEmmanuel Vadot 				bzero(&dummy, sizeof(dummy));
4394e579ad0SEmmanuel Vadot 				dummy.clkdef.id = clk->clkdef.id;
4404e579ad0SEmmanuel Vadot 				dummy.clkdef.name = strdup("dummy", M_DEVBUF);
4414e579ad0SEmmanuel Vadot 				clknode_fixed_register(sc->clkdom, &dummy);
4424e579ad0SEmmanuel Vadot 				free(__DECONST(char *, dummy.clkdef.name), M_DEVBUF);
4434e579ad0SEmmanuel Vadot 			}
4444e579ad0SEmmanuel Vadot 		} else
4454e579ad0SEmmanuel Vadot 			zynqmp_clk_register(sc->clkdom, sc->parent, clk);
4464e579ad0SEmmanuel Vadot 
4474e579ad0SEmmanuel Vadot 		TAILQ_REMOVE(&clk_list, clk, next);
4484e579ad0SEmmanuel Vadot 		for (i = 0; i < clk->clkdef.parent_cnt; i++)
4494e579ad0SEmmanuel Vadot 			free(__DECONST(char *, clk->clkdef.parent_names[i]), M_DEVBUF);
4504e579ad0SEmmanuel Vadot 		free(clk->clkdef.parent_names, M_DEVBUF);
4514e579ad0SEmmanuel Vadot 		free(__DECONST(char *, clk->clkdef.name), M_DEVBUF);
4524e579ad0SEmmanuel Vadot 		free(clk, M_DEVBUF);
4534e579ad0SEmmanuel Vadot 	}
4544e579ad0SEmmanuel Vadot 
4554e579ad0SEmmanuel Vadot 	if (clkdom_finit(sc->clkdom) != 0)
4564e579ad0SEmmanuel Vadot 		panic("cannot finalize clkdom initialization\n");
4574e579ad0SEmmanuel Vadot 
4584e579ad0SEmmanuel Vadot 	if (bootverbose)
4594e579ad0SEmmanuel Vadot 		clkdom_dump(sc->clkdom);
4604e579ad0SEmmanuel Vadot 
4614e579ad0SEmmanuel Vadot 	return (0);
4624e579ad0SEmmanuel Vadot }
4634e579ad0SEmmanuel Vadot 
4644e579ad0SEmmanuel Vadot static int
zynqmp_clock_probe(device_t dev)4654e579ad0SEmmanuel Vadot zynqmp_clock_probe(device_t dev)
4664e579ad0SEmmanuel Vadot {
4674e579ad0SEmmanuel Vadot 
4684e579ad0SEmmanuel Vadot 	if (!ofw_bus_status_okay(dev))
4694e579ad0SEmmanuel Vadot 		return (ENXIO);
4704e579ad0SEmmanuel Vadot 	if (!ofw_bus_is_compatible(dev, "xlnx,zynqmp-clk"))
4714e579ad0SEmmanuel Vadot 		return (ENXIO);
4724e579ad0SEmmanuel Vadot 	device_set_desc(dev, "ZynqMP Clock Controller");
4734e579ad0SEmmanuel Vadot 
4744e579ad0SEmmanuel Vadot 	return (BUS_PROBE_DEFAULT);
4754e579ad0SEmmanuel Vadot }
4764e579ad0SEmmanuel Vadot 
4774e579ad0SEmmanuel Vadot static int
zynqmp_clock_attach(device_t dev)4784e579ad0SEmmanuel Vadot zynqmp_clock_attach(device_t dev)
4794e579ad0SEmmanuel Vadot {
4804e579ad0SEmmanuel Vadot 	struct zynqmp_clock_softc *sc;
4814e579ad0SEmmanuel Vadot 	int rv;
4824e579ad0SEmmanuel Vadot 
4834e579ad0SEmmanuel Vadot 	sc = device_get_softc(dev);
4844e579ad0SEmmanuel Vadot 	sc->dev = dev;
4854e579ad0SEmmanuel Vadot 	sc->parent = device_get_parent(dev);
4864e579ad0SEmmanuel Vadot 	sc->node = ofw_bus_get_node(dev);
4874e579ad0SEmmanuel Vadot 
4884e579ad0SEmmanuel Vadot 	/* Enable all clocks */
4894e579ad0SEmmanuel Vadot 	if (clk_get_by_ofw_name(dev, 0, "pss_ref_clk", &sc->clk_pss_ref) != 0) {
4904e579ad0SEmmanuel Vadot 		device_printf(dev, "Cannot get pss_ref_clk clock\n");
4914e579ad0SEmmanuel Vadot 		return (ENXIO);
4924e579ad0SEmmanuel Vadot 	}
4934e579ad0SEmmanuel Vadot 	rv = clk_enable(sc->clk_pss_ref);
4944e579ad0SEmmanuel Vadot 	if (rv != 0) {
4954e579ad0SEmmanuel Vadot 		device_printf(dev, "Could not enable clock pss_ref_clk\n");
4964e579ad0SEmmanuel Vadot 		return (ENXIO);
4974e579ad0SEmmanuel Vadot 	}
4984e579ad0SEmmanuel Vadot 	if (clk_get_by_ofw_name(dev, 0, "video_clk", &sc->clk_video) != 0) {
4994e579ad0SEmmanuel Vadot 		device_printf(dev, "Cannot get video_clk clock\n");
5004e579ad0SEmmanuel Vadot 		return (ENXIO);
5014e579ad0SEmmanuel Vadot 	}
5024e579ad0SEmmanuel Vadot 	rv = clk_enable(sc->clk_video);
5034e579ad0SEmmanuel Vadot 	if (rv != 0) {
5044e579ad0SEmmanuel Vadot 		device_printf(dev, "Could not enable clock video_clk\n");
5054e579ad0SEmmanuel Vadot 		return (ENXIO);
5064e579ad0SEmmanuel Vadot 	}
5074e579ad0SEmmanuel Vadot 	if (clk_get_by_ofw_name(dev, 0, "pss_alt_ref_clk", &sc->clk_pss_alt_ref) != 0) {
5084e579ad0SEmmanuel Vadot 		device_printf(dev, "Cannot get pss_alt_ref_clk clock\n");
5094e579ad0SEmmanuel Vadot 		return (ENXIO);
5104e579ad0SEmmanuel Vadot 	}
5114e579ad0SEmmanuel Vadot 	rv = clk_enable(sc->clk_pss_alt_ref);
5124e579ad0SEmmanuel Vadot 	if (rv != 0) {
5134e579ad0SEmmanuel Vadot 		device_printf(dev, "Could not enable clock pss_alt_ref_clk\n");
5144e579ad0SEmmanuel Vadot 		return (ENXIO);
5154e579ad0SEmmanuel Vadot 	}
5164e579ad0SEmmanuel Vadot 	if (clk_get_by_ofw_name(dev, 0, "aux_ref_clk", &sc->clk_aux_ref) != 0) {
5174e579ad0SEmmanuel Vadot 		device_printf(dev, "Cannot get pss_aux_clk clock\n");
5184e579ad0SEmmanuel Vadot 		return (ENXIO);
5194e579ad0SEmmanuel Vadot 	}
5204e579ad0SEmmanuel Vadot 	rv = clk_enable(sc->clk_aux_ref);
5214e579ad0SEmmanuel Vadot 	if (rv != 0) {
5224e579ad0SEmmanuel Vadot 		device_printf(dev, "Could not enable clock pss_aux_clk\n");
5234e579ad0SEmmanuel Vadot 		return (ENXIO);
5244e579ad0SEmmanuel Vadot 	}
5254e579ad0SEmmanuel Vadot 	if (clk_get_by_ofw_name(dev, 0, "gt_crx_ref_clk", &sc->clk_gt_crx_ref) != 0) {
5264e579ad0SEmmanuel Vadot 		device_printf(dev, "Cannot get gt_crx_ref_clk clock\n");
5274e579ad0SEmmanuel Vadot 		return (ENXIO);
5284e579ad0SEmmanuel Vadot 	}
5294e579ad0SEmmanuel Vadot 	rv = clk_enable(sc->clk_gt_crx_ref);
5304e579ad0SEmmanuel Vadot 	if (rv != 0) {
5314e579ad0SEmmanuel Vadot 		device_printf(dev, "Could not enable clock gt_crx_ref_clk\n");
5324e579ad0SEmmanuel Vadot 		return (ENXIO);
5334e579ad0SEmmanuel Vadot 	}
5344e579ad0SEmmanuel Vadot 
5354e579ad0SEmmanuel Vadot 	rv = zynqmp_fw_clk_get_all(sc);
5364e579ad0SEmmanuel Vadot 	if (rv != 0) {
5374e579ad0SEmmanuel Vadot 		clk_disable(sc->clk_gt_crx_ref);
5384e579ad0SEmmanuel Vadot 		clk_disable(sc->clk_aux_ref);
5394e579ad0SEmmanuel Vadot 		clk_disable(sc->clk_pss_alt_ref);
5404e579ad0SEmmanuel Vadot 		clk_disable(sc->clk_video);
5414e579ad0SEmmanuel Vadot 		clk_disable(sc->clk_pss_ref);
5424e579ad0SEmmanuel Vadot 		return (rv);
5434e579ad0SEmmanuel Vadot 	}
5444e579ad0SEmmanuel Vadot 	return (0);
5454e579ad0SEmmanuel Vadot }
5464e579ad0SEmmanuel Vadot 
5474e579ad0SEmmanuel Vadot static device_method_t zynqmp_clock_methods[] = {
5484e579ad0SEmmanuel Vadot 	/* device_if */
5494e579ad0SEmmanuel Vadot 	DEVMETHOD(device_probe, 	zynqmp_clock_probe),
5504e579ad0SEmmanuel Vadot 	DEVMETHOD(device_attach, 	zynqmp_clock_attach),
5514e579ad0SEmmanuel Vadot 
5524e579ad0SEmmanuel Vadot 	DEVMETHOD_END
5534e579ad0SEmmanuel Vadot };
5544e579ad0SEmmanuel Vadot 
5554e579ad0SEmmanuel Vadot static driver_t zynqmp_clock_driver = {
5564e579ad0SEmmanuel Vadot 	"zynqmp_clock",
5574e579ad0SEmmanuel Vadot 	zynqmp_clock_methods,
5584e579ad0SEmmanuel Vadot 	sizeof(struct zynqmp_clock_softc),
5594e579ad0SEmmanuel Vadot };
5604e579ad0SEmmanuel Vadot 
5614e579ad0SEmmanuel Vadot EARLY_DRIVER_MODULE(zynqmp_clock, simplebus, zynqmp_clock_driver, 0, 0,
5624e579ad0SEmmanuel Vadot     BUS_PASS_BUS + BUS_PASS_ORDER_LAST);
563