1*9e88711fSEmmanuel Vadot /*-
2*9e88711fSEmmanuel Vadot  * SPDX-License-Identifier: BSD-2-Clause
3*9e88711fSEmmanuel Vadot  *
4*9e88711fSEmmanuel Vadot  * Copyright (c) 2023 Beckhoff Automation GmbH & Co. KG
5*9e88711fSEmmanuel Vadot  *
6*9e88711fSEmmanuel Vadot  * Redistribution and use in source and binary forms, with or without
7*9e88711fSEmmanuel Vadot  * modification, are permitted provided that the following conditions
8*9e88711fSEmmanuel Vadot  * are met:
9*9e88711fSEmmanuel Vadot  * 1. Redistributions of source code must retain the above copyright
10*9e88711fSEmmanuel Vadot  *    notice, this list of conditions and the following disclaimer.
11*9e88711fSEmmanuel Vadot  * 2. Redistributions in binary form must reproduce the above copyright
12*9e88711fSEmmanuel Vadot  *    notice, this list of conditions and the following disclaimer in the
13*9e88711fSEmmanuel Vadot  *    documentation and/or other materials provided with the distribution.
14*9e88711fSEmmanuel Vadot  *
15*9e88711fSEmmanuel Vadot  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16*9e88711fSEmmanuel Vadot  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17*9e88711fSEmmanuel Vadot  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18*9e88711fSEmmanuel Vadot  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19*9e88711fSEmmanuel Vadot  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20*9e88711fSEmmanuel Vadot  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21*9e88711fSEmmanuel Vadot  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22*9e88711fSEmmanuel Vadot  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23*9e88711fSEmmanuel Vadot  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24*9e88711fSEmmanuel Vadot  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25*9e88711fSEmmanuel Vadot  * SUCH DAMAGE.
26*9e88711fSEmmanuel Vadot  */
27*9e88711fSEmmanuel Vadot 
28*9e88711fSEmmanuel Vadot #include <sys/cdefs.h>
29*9e88711fSEmmanuel Vadot 
30*9e88711fSEmmanuel Vadot #include <sys/param.h>
31*9e88711fSEmmanuel Vadot #include <sys/systm.h>
32*9e88711fSEmmanuel Vadot #include <sys/kernel.h>
33*9e88711fSEmmanuel Vadot #include <sys/module.h>
34*9e88711fSEmmanuel Vadot #include <sys/malloc.h>
35*9e88711fSEmmanuel Vadot #include <sys/bus.h>
36*9e88711fSEmmanuel Vadot #include <sys/cpu.h>
37*9e88711fSEmmanuel Vadot #include <machine/bus.h>
38*9e88711fSEmmanuel Vadot 
39*9e88711fSEmmanuel Vadot #include <dev/fdt/simplebus.h>
40*9e88711fSEmmanuel Vadot 
41*9e88711fSEmmanuel Vadot #include <dev/ofw/openfirm.h>
42*9e88711fSEmmanuel Vadot #include <dev/ofw/ofw_bus.h>
43*9e88711fSEmmanuel Vadot #include <dev/ofw/ofw_bus_subr.h>
44*9e88711fSEmmanuel Vadot 
45*9e88711fSEmmanuel Vadot #include <dev/psci/smccc.h>
46*9e88711fSEmmanuel Vadot 
47*9e88711fSEmmanuel Vadot #include <dev/firmware/xilinx/pm_defs.h>
48*9e88711fSEmmanuel Vadot 
49*9e88711fSEmmanuel Vadot #include "zynqmp_firmware_if.h"
50*9e88711fSEmmanuel Vadot 
51*9e88711fSEmmanuel Vadot enum {
52*9e88711fSEmmanuel Vadot 	IOCTL_GET_RPU_OPER_MODE = 0,
53*9e88711fSEmmanuel Vadot 	IOCTL_SET_RPU_OPER_MODE = 1,
54*9e88711fSEmmanuel Vadot 	IOCTL_RPU_BOOT_ADDR_CONFIG = 2,
55*9e88711fSEmmanuel Vadot 	IOCTL_TCM_COMB_CONFIG = 3,
56*9e88711fSEmmanuel Vadot 	IOCTL_SET_TAPDELAY_BYPASS = 4,
57*9e88711fSEmmanuel Vadot 	IOCTL_SET_SGMII_MODE = 5,
58*9e88711fSEmmanuel Vadot 	IOCTL_SD_DLL_RESET = 6,
59*9e88711fSEmmanuel Vadot 	IOCTL_SET_SD_TAPDELAY = 7,
60*9e88711fSEmmanuel Vadot 	 /* Ioctl for clock driver */
61*9e88711fSEmmanuel Vadot 	IOCTL_SET_PLL_FRAC_MODE = 8,
62*9e88711fSEmmanuel Vadot 	IOCTL_GET_PLL_FRAC_MODE = 9,
63*9e88711fSEmmanuel Vadot 	IOCTL_SET_PLL_FRAC_DATA = 10,
64*9e88711fSEmmanuel Vadot 	IOCTL_GET_PLL_FRAC_DATA = 11,
65*9e88711fSEmmanuel Vadot 	IOCTL_WRITE_GGS = 12,
66*9e88711fSEmmanuel Vadot 	IOCTL_READ_GGS = 13,
67*9e88711fSEmmanuel Vadot 	IOCTL_WRITE_PGGS = 14,
68*9e88711fSEmmanuel Vadot 	IOCTL_READ_PGGS = 15,
69*9e88711fSEmmanuel Vadot 	/* IOCTL for ULPI reset */
70*9e88711fSEmmanuel Vadot 	IOCTL_ULPI_RESET = 16,
71*9e88711fSEmmanuel Vadot 	/* Set healthy bit value */
72*9e88711fSEmmanuel Vadot 	IOCTL_SET_BOOT_HEALTH_STATUS = 17,
73*9e88711fSEmmanuel Vadot 	IOCTL_AFI = 18,
74*9e88711fSEmmanuel Vadot 	/* Probe counter read/write */
75*9e88711fSEmmanuel Vadot 	IOCTL_PROBE_COUNTER_READ = 19,
76*9e88711fSEmmanuel Vadot 	IOCTL_PROBE_COUNTER_WRITE = 20,
77*9e88711fSEmmanuel Vadot 	IOCTL_OSPI_MUX_SELECT = 21,
78*9e88711fSEmmanuel Vadot 	/* IOCTL for USB power request */
79*9e88711fSEmmanuel Vadot 	IOCTL_USB_SET_STATE = 22,
80*9e88711fSEmmanuel Vadot 	/* IOCTL to get last reset reason */
81*9e88711fSEmmanuel Vadot 	IOCTL_GET_LAST_RESET_REASON = 23,
82*9e88711fSEmmanuel Vadot 	/* AI engine NPI ISR clear */
83*9e88711fSEmmanuel Vadot 	IOCTL_AIE_ISR_CLEAR = 24,
84*9e88711fSEmmanuel Vadot 	/* Register SGI to ATF */
85*9e88711fSEmmanuel Vadot 	IOCTL_REGISTER_SGI = 25,
86*9e88711fSEmmanuel Vadot };
87*9e88711fSEmmanuel Vadot 
88*9e88711fSEmmanuel Vadot typedef int (*zynqmp_callfn_t)(register_t, register_t, register_t, uint32_t *payload);
89*9e88711fSEmmanuel Vadot 
90*9e88711fSEmmanuel Vadot struct zynqmp_firmware_softc {
91*9e88711fSEmmanuel Vadot 	struct simplebus_softc	sc;
92*9e88711fSEmmanuel Vadot 	device_t		dev;
93*9e88711fSEmmanuel Vadot 	zynqmp_callfn_t		callfn;
94*9e88711fSEmmanuel Vadot };
95*9e88711fSEmmanuel Vadot 
96*9e88711fSEmmanuel Vadot /* SMC calling methods */
97*9e88711fSEmmanuel Vadot #define	PM_SIP_SVC	0xC2000000
98*9e88711fSEmmanuel Vadot 
99*9e88711fSEmmanuel Vadot static int
zynqmp_call_smc(uint32_t id,uint32_t a0,uint32_t a1,uint32_t a2,uint32_t a3,uint32_t * payload,bool ignore_error)100*9e88711fSEmmanuel Vadot zynqmp_call_smc(uint32_t id, uint32_t a0, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t *payload, bool ignore_error)
101*9e88711fSEmmanuel Vadot {
102*9e88711fSEmmanuel Vadot 	struct arm_smccc_res res;
103*9e88711fSEmmanuel Vadot 	uint64_t args[3];
104*9e88711fSEmmanuel Vadot 
105*9e88711fSEmmanuel Vadot 	args[0] = id | PM_SIP_SVC;
106*9e88711fSEmmanuel Vadot 	args[1] = ((uint64_t)a1 << 32) | a0;
107*9e88711fSEmmanuel Vadot 	args[2] = ((uint64_t)a3 << 32) | a2;
108*9e88711fSEmmanuel Vadot 	arm_smccc_smc(args[0], args[1], args[2], 0, 0, 0, 0, 0, &res);
109*9e88711fSEmmanuel Vadot 	if (payload != NULL) {
110*9e88711fSEmmanuel Vadot 		payload[0] = res.a0 & 0xFFFFFFFF;
111*9e88711fSEmmanuel Vadot 		payload[1] = res.a0 >> 32;
112*9e88711fSEmmanuel Vadot 		payload[2] = res.a1 & 0xFFFFFFFF;
113*9e88711fSEmmanuel Vadot 		payload[3] = res.a1 >> 32;
114*9e88711fSEmmanuel Vadot 		if (!ignore_error && payload[0] != PM_RET_SUCCESS) {
115*9e88711fSEmmanuel Vadot 			printf("%s: fail %x\n", __func__, payload[0]);
116*9e88711fSEmmanuel Vadot 			return (EINVAL);
117*9e88711fSEmmanuel Vadot 		}
118*9e88711fSEmmanuel Vadot 	}
119*9e88711fSEmmanuel Vadot 	return (0);
120*9e88711fSEmmanuel Vadot }
121*9e88711fSEmmanuel Vadot 
122*9e88711fSEmmanuel Vadot /* Firmware methods */
123*9e88711fSEmmanuel Vadot static int
zynqmp_get_api_version(struct zynqmp_firmware_softc * sc)124*9e88711fSEmmanuel Vadot zynqmp_get_api_version(struct zynqmp_firmware_softc *sc)
125*9e88711fSEmmanuel Vadot {
126*9e88711fSEmmanuel Vadot 	uint32_t payload[4];
127*9e88711fSEmmanuel Vadot 	int rv;
128*9e88711fSEmmanuel Vadot 
129*9e88711fSEmmanuel Vadot 	rv = zynqmp_call_smc(PM_GET_API_VERSION, 0, 0, 0, 0, payload, false);
130*9e88711fSEmmanuel Vadot 	if (rv != 0) {
131*9e88711fSEmmanuel Vadot 		device_printf(sc->dev, "SMC Call fail %d\n", rv);
132*9e88711fSEmmanuel Vadot 		goto out;
133*9e88711fSEmmanuel Vadot 	}
134*9e88711fSEmmanuel Vadot 	device_printf(sc->dev, "API version = %d.%d\n",
135*9e88711fSEmmanuel Vadot 	    payload[1] >> 16, payload[1] & 0xFFFF);
136*9e88711fSEmmanuel Vadot out:
137*9e88711fSEmmanuel Vadot 	return (rv);
138*9e88711fSEmmanuel Vadot }
139*9e88711fSEmmanuel Vadot 
140*9e88711fSEmmanuel Vadot static int
zynqmp_get_chipid(struct zynqmp_firmware_softc * sc)141*9e88711fSEmmanuel Vadot zynqmp_get_chipid(struct zynqmp_firmware_softc *sc)
142*9e88711fSEmmanuel Vadot {
143*9e88711fSEmmanuel Vadot 	uint32_t payload[4];
144*9e88711fSEmmanuel Vadot 	int rv;
145*9e88711fSEmmanuel Vadot 
146*9e88711fSEmmanuel Vadot 	rv = zynqmp_call_smc(PM_GET_CHIPID, 0, 0, 0, 0, payload, false);
147*9e88711fSEmmanuel Vadot 	if (rv != 0) {
148*9e88711fSEmmanuel Vadot 		device_printf(sc->dev, "SMC Call fail %d\n", rv);
149*9e88711fSEmmanuel Vadot 		goto out;
150*9e88711fSEmmanuel Vadot 	}
151*9e88711fSEmmanuel Vadot 	device_printf(sc->dev, "ID Code = %x Version = %x\n",
152*9e88711fSEmmanuel Vadot 	    payload[1], payload[2]);
153*9e88711fSEmmanuel Vadot out:
154*9e88711fSEmmanuel Vadot 	return (rv);
155*9e88711fSEmmanuel Vadot }
156*9e88711fSEmmanuel Vadot 
157*9e88711fSEmmanuel Vadot static int
zynqmp_get_trustzone_version(struct zynqmp_firmware_softc * sc)158*9e88711fSEmmanuel Vadot zynqmp_get_trustzone_version(struct zynqmp_firmware_softc *sc)
159*9e88711fSEmmanuel Vadot {
160*9e88711fSEmmanuel Vadot 	uint32_t payload[4];
161*9e88711fSEmmanuel Vadot 	int rv;
162*9e88711fSEmmanuel Vadot 
163*9e88711fSEmmanuel Vadot 	rv = zynqmp_call_smc(PM_GET_TRUSTZONE_VERSION, 0, 0, 0, 0, payload, false);
164*9e88711fSEmmanuel Vadot 	if (rv != 0) {
165*9e88711fSEmmanuel Vadot 		device_printf(sc->dev, "SMC Call fail %d\n", rv);
166*9e88711fSEmmanuel Vadot 		goto out;
167*9e88711fSEmmanuel Vadot 	}
168*9e88711fSEmmanuel Vadot 	device_printf(sc->dev, "Trustzone Version = %x\n",
169*9e88711fSEmmanuel Vadot 	    payload[1]);
170*9e88711fSEmmanuel Vadot out:
171*9e88711fSEmmanuel Vadot 	return (rv);
172*9e88711fSEmmanuel Vadot }
173*9e88711fSEmmanuel Vadot 
174*9e88711fSEmmanuel Vadot /* zynqmp_firmware methods */
175*9e88711fSEmmanuel Vadot static int
zynqmp_firmware_clock_enable(device_t dev,uint32_t clkid)176*9e88711fSEmmanuel Vadot zynqmp_firmware_clock_enable(device_t dev, uint32_t clkid)
177*9e88711fSEmmanuel Vadot {
178*9e88711fSEmmanuel Vadot 	struct zynqmp_firmware_softc *sc;
179*9e88711fSEmmanuel Vadot 	uint32_t payload[4];
180*9e88711fSEmmanuel Vadot 	int rv;
181*9e88711fSEmmanuel Vadot 
182*9e88711fSEmmanuel Vadot 	sc = device_get_softc(dev);
183*9e88711fSEmmanuel Vadot 	rv = zynqmp_call_smc(PM_CLOCK_ENABLE, clkid, 0, 0, 0, payload, false);
184*9e88711fSEmmanuel Vadot 	if (rv != 0)
185*9e88711fSEmmanuel Vadot 		device_printf(sc->dev, "SMC Call fail %d\n", rv);
186*9e88711fSEmmanuel Vadot 	return (rv);
187*9e88711fSEmmanuel Vadot }
188*9e88711fSEmmanuel Vadot 
189*9e88711fSEmmanuel Vadot static int
zynqmp_firmware_clock_disable(device_t dev,uint32_t clkid)190*9e88711fSEmmanuel Vadot zynqmp_firmware_clock_disable(device_t dev, uint32_t clkid)
191*9e88711fSEmmanuel Vadot {
192*9e88711fSEmmanuel Vadot 	struct zynqmp_firmware_softc *sc;
193*9e88711fSEmmanuel Vadot 	uint32_t payload[4];
194*9e88711fSEmmanuel Vadot 	int rv;
195*9e88711fSEmmanuel Vadot 
196*9e88711fSEmmanuel Vadot 	sc = device_get_softc(dev);
197*9e88711fSEmmanuel Vadot 	rv = zynqmp_call_smc(PM_CLOCK_DISABLE, clkid, 0, 0, 0, payload, false);
198*9e88711fSEmmanuel Vadot 	if (rv != 0)
199*9e88711fSEmmanuel Vadot 		device_printf(sc->dev, "SMC Call fail %d\n", rv);
200*9e88711fSEmmanuel Vadot 	return (rv);
201*9e88711fSEmmanuel Vadot }
202*9e88711fSEmmanuel Vadot 
203*9e88711fSEmmanuel Vadot static int
zynqmp_firmware_clock_getstate(device_t dev,uint32_t clkid,bool * enabled)204*9e88711fSEmmanuel Vadot zynqmp_firmware_clock_getstate(device_t dev, uint32_t clkid, bool *enabled)
205*9e88711fSEmmanuel Vadot {
206*9e88711fSEmmanuel Vadot 	struct zynqmp_firmware_softc *sc;
207*9e88711fSEmmanuel Vadot 	uint32_t payload[4];
208*9e88711fSEmmanuel Vadot 	int rv;
209*9e88711fSEmmanuel Vadot 
210*9e88711fSEmmanuel Vadot 	sc = device_get_softc(dev);
211*9e88711fSEmmanuel Vadot 	rv = zynqmp_call_smc(PM_CLOCK_GETSTATE, clkid, 0, 0, 0, payload, false);
212*9e88711fSEmmanuel Vadot 	if (rv != 0) {
213*9e88711fSEmmanuel Vadot 		device_printf(sc->dev, "SMC Call fail %d\n", rv);
214*9e88711fSEmmanuel Vadot 		goto out;
215*9e88711fSEmmanuel Vadot 	}
216*9e88711fSEmmanuel Vadot 	*enabled = payload[1] == 1 ? true : false;
217*9e88711fSEmmanuel Vadot 
218*9e88711fSEmmanuel Vadot out:
219*9e88711fSEmmanuel Vadot 	return (rv);
220*9e88711fSEmmanuel Vadot }
221*9e88711fSEmmanuel Vadot 
222*9e88711fSEmmanuel Vadot static int
zynqmp_firmware_clock_setdivider(device_t dev,uint32_t clkid,uint32_t div)223*9e88711fSEmmanuel Vadot zynqmp_firmware_clock_setdivider(device_t dev, uint32_t clkid, uint32_t div)
224*9e88711fSEmmanuel Vadot {
225*9e88711fSEmmanuel Vadot 	struct zynqmp_firmware_softc *sc;
226*9e88711fSEmmanuel Vadot 	uint32_t payload[4];
227*9e88711fSEmmanuel Vadot 	int rv;
228*9e88711fSEmmanuel Vadot 
229*9e88711fSEmmanuel Vadot 	sc = device_get_softc(dev);
230*9e88711fSEmmanuel Vadot 	rv = zynqmp_call_smc(PM_CLOCK_SETDIVIDER, clkid, div, 0, 0, payload, false);
231*9e88711fSEmmanuel Vadot 	if (rv != 0)
232*9e88711fSEmmanuel Vadot 		device_printf(sc->dev, "SMC Call fail %d\n", rv);
233*9e88711fSEmmanuel Vadot 	return (rv);
234*9e88711fSEmmanuel Vadot }
235*9e88711fSEmmanuel Vadot 
236*9e88711fSEmmanuel Vadot static int
zynqmp_firmware_clock_getdivider(device_t dev,uint32_t clkid,uint32_t * div)237*9e88711fSEmmanuel Vadot zynqmp_firmware_clock_getdivider(device_t dev, uint32_t clkid, uint32_t *div)
238*9e88711fSEmmanuel Vadot {
239*9e88711fSEmmanuel Vadot 	struct zynqmp_firmware_softc *sc;
240*9e88711fSEmmanuel Vadot 	uint32_t payload[4];
241*9e88711fSEmmanuel Vadot 	int rv;
242*9e88711fSEmmanuel Vadot 
243*9e88711fSEmmanuel Vadot 	sc = device_get_softc(dev);
244*9e88711fSEmmanuel Vadot 	rv = zynqmp_call_smc(PM_CLOCK_GETDIVIDER, clkid, 0, 0, 0, payload, false);
245*9e88711fSEmmanuel Vadot 	if (rv != 0) {
246*9e88711fSEmmanuel Vadot 		device_printf(sc->dev, "SMC Call fail %d\n", rv);
247*9e88711fSEmmanuel Vadot 		goto out;
248*9e88711fSEmmanuel Vadot 	}
249*9e88711fSEmmanuel Vadot 	*div = payload[1];
250*9e88711fSEmmanuel Vadot 
251*9e88711fSEmmanuel Vadot out:
252*9e88711fSEmmanuel Vadot 	return (rv);
253*9e88711fSEmmanuel Vadot }
254*9e88711fSEmmanuel Vadot 
255*9e88711fSEmmanuel Vadot static int
zynqmp_firmware_clock_setparent(device_t dev,uint32_t clkid,uint32_t parentid)256*9e88711fSEmmanuel Vadot zynqmp_firmware_clock_setparent(device_t dev, uint32_t clkid, uint32_t parentid)
257*9e88711fSEmmanuel Vadot {
258*9e88711fSEmmanuel Vadot 	struct zynqmp_firmware_softc *sc;
259*9e88711fSEmmanuel Vadot 	uint32_t payload[4];
260*9e88711fSEmmanuel Vadot 	int rv;
261*9e88711fSEmmanuel Vadot 
262*9e88711fSEmmanuel Vadot 	sc = device_get_softc(dev);
263*9e88711fSEmmanuel Vadot 	rv = zynqmp_call_smc(PM_CLOCK_SETPARENT, clkid, parentid, 0, 0, payload, false);
264*9e88711fSEmmanuel Vadot 	if (rv != 0)
265*9e88711fSEmmanuel Vadot 		device_printf(sc->dev, "SMC Call fail %d\n", rv);
266*9e88711fSEmmanuel Vadot 	return (rv);
267*9e88711fSEmmanuel Vadot }
268*9e88711fSEmmanuel Vadot 
269*9e88711fSEmmanuel Vadot static int
zynqmp_firmware_clock_getparent(device_t dev,uint32_t clkid,uint32_t * parentid)270*9e88711fSEmmanuel Vadot zynqmp_firmware_clock_getparent(device_t dev, uint32_t clkid, uint32_t *parentid)
271*9e88711fSEmmanuel Vadot {
272*9e88711fSEmmanuel Vadot 	struct zynqmp_firmware_softc *sc;
273*9e88711fSEmmanuel Vadot 	uint32_t payload[4];
274*9e88711fSEmmanuel Vadot 	int rv;
275*9e88711fSEmmanuel Vadot 
276*9e88711fSEmmanuel Vadot 	sc = device_get_softc(dev);
277*9e88711fSEmmanuel Vadot 	rv = zynqmp_call_smc(PM_CLOCK_GETPARENT, clkid, 0, 0, 0, payload, false);
278*9e88711fSEmmanuel Vadot 	if (rv != 0) {
279*9e88711fSEmmanuel Vadot 		device_printf(sc->dev, "SMC Call fail %d\n", rv);
280*9e88711fSEmmanuel Vadot 		goto out;
281*9e88711fSEmmanuel Vadot 	}
282*9e88711fSEmmanuel Vadot 	*parentid = payload[1];
283*9e88711fSEmmanuel Vadot out:
284*9e88711fSEmmanuel Vadot 	return (rv);
285*9e88711fSEmmanuel Vadot }
286*9e88711fSEmmanuel Vadot 
287*9e88711fSEmmanuel Vadot static int
zynqmp_firmware_pll_get_mode(device_t dev,uint32_t pllid,uint32_t * mode)288*9e88711fSEmmanuel Vadot zynqmp_firmware_pll_get_mode(device_t dev, uint32_t pllid, uint32_t *mode)
289*9e88711fSEmmanuel Vadot {
290*9e88711fSEmmanuel Vadot 	struct zynqmp_firmware_softc *sc;
291*9e88711fSEmmanuel Vadot 	uint32_t payload[4];
292*9e88711fSEmmanuel Vadot 	int rv;
293*9e88711fSEmmanuel Vadot 
294*9e88711fSEmmanuel Vadot 	sc = device_get_softc(dev);
295*9e88711fSEmmanuel Vadot 	rv = zynqmp_call_smc(PM_IOCTL, 0, IOCTL_GET_PLL_FRAC_MODE, pllid, 0, payload, false);
296*9e88711fSEmmanuel Vadot 	if (rv != 0) {
297*9e88711fSEmmanuel Vadot 		device_printf(sc->dev, "SMC Call fail %d\n", rv);
298*9e88711fSEmmanuel Vadot 		goto out;
299*9e88711fSEmmanuel Vadot 	}
300*9e88711fSEmmanuel Vadot 	*mode = payload[1];
301*9e88711fSEmmanuel Vadot out:
302*9e88711fSEmmanuel Vadot 	return (rv);
303*9e88711fSEmmanuel Vadot }
304*9e88711fSEmmanuel Vadot 
305*9e88711fSEmmanuel Vadot static int
zynqmp_firmware_pll_get_frac_data(device_t dev,uint32_t pllid,uint32_t * data)306*9e88711fSEmmanuel Vadot zynqmp_firmware_pll_get_frac_data(device_t dev, uint32_t pllid, uint32_t *data)
307*9e88711fSEmmanuel Vadot {
308*9e88711fSEmmanuel Vadot 	struct zynqmp_firmware_softc *sc;
309*9e88711fSEmmanuel Vadot 	uint32_t payload[4];
310*9e88711fSEmmanuel Vadot 	int rv;
311*9e88711fSEmmanuel Vadot 
312*9e88711fSEmmanuel Vadot 	sc = device_get_softc(dev);
313*9e88711fSEmmanuel Vadot 	rv = zynqmp_call_smc(PM_IOCTL, 0, IOCTL_GET_PLL_FRAC_DATA, pllid, 0, payload, false);
314*9e88711fSEmmanuel Vadot 	if (rv != 0) {
315*9e88711fSEmmanuel Vadot 		device_printf(sc->dev, "SMC Call fail %d\n", rv);
316*9e88711fSEmmanuel Vadot 		goto out;
317*9e88711fSEmmanuel Vadot 	}
318*9e88711fSEmmanuel Vadot 	*data = payload[1];
319*9e88711fSEmmanuel Vadot out:
320*9e88711fSEmmanuel Vadot 	return (rv);
321*9e88711fSEmmanuel Vadot }
322*9e88711fSEmmanuel Vadot 
323*9e88711fSEmmanuel Vadot static int
zynqmp_firmware_clock_get_fixedfactor(device_t dev,uint32_t clkid,uint32_t * mult,uint32_t * div)324*9e88711fSEmmanuel Vadot zynqmp_firmware_clock_get_fixedfactor(device_t dev, uint32_t clkid, uint32_t *mult, uint32_t *div)
325*9e88711fSEmmanuel Vadot {
326*9e88711fSEmmanuel Vadot 	struct zynqmp_firmware_softc *sc;
327*9e88711fSEmmanuel Vadot 	uint32_t payload[4];
328*9e88711fSEmmanuel Vadot 	int rv;
329*9e88711fSEmmanuel Vadot 
330*9e88711fSEmmanuel Vadot 	sc = device_get_softc(dev);
331*9e88711fSEmmanuel Vadot 	rv = zynqmp_call_smc(PM_QUERY_DATA, PM_QID_CLOCK_GET_FIXEDFACTOR_PARAMS, clkid, 0, 0, payload, true);
332*9e88711fSEmmanuel Vadot 	if (rv != 0) {
333*9e88711fSEmmanuel Vadot 		device_printf(sc->dev, "SMC Call fail %d\n", rv);
334*9e88711fSEmmanuel Vadot 		goto out;
335*9e88711fSEmmanuel Vadot 	}
336*9e88711fSEmmanuel Vadot 	*mult = payload[1];
337*9e88711fSEmmanuel Vadot 	*div = payload[2];
338*9e88711fSEmmanuel Vadot out:
339*9e88711fSEmmanuel Vadot 	return (rv);
340*9e88711fSEmmanuel Vadot }
341*9e88711fSEmmanuel Vadot 
342*9e88711fSEmmanuel Vadot static int
zynqmp_firmware_query_data(device_t dev,uint32_t qid,uint32_t arg1,uint32_t arg2,uint32_t arg3,uint32_t * data)343*9e88711fSEmmanuel Vadot zynqmp_firmware_query_data(device_t dev, uint32_t qid, uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t *data)
344*9e88711fSEmmanuel Vadot {
345*9e88711fSEmmanuel Vadot 	struct zynqmp_firmware_softc *sc;
346*9e88711fSEmmanuel Vadot 	int rv;
347*9e88711fSEmmanuel Vadot 
348*9e88711fSEmmanuel Vadot 	sc = device_get_softc(dev);
349*9e88711fSEmmanuel Vadot 	rv = zynqmp_call_smc(PM_QUERY_DATA, qid, arg1, arg2, arg3, data, true);
350*9e88711fSEmmanuel Vadot 	/*
351*9e88711fSEmmanuel Vadot 	 * PM_QID_CLOCK_GET_NAME always success and if the clock name couldn't
352*9e88711fSEmmanuel Vadot 	 * be found the clock name will be all null byte
353*9e88711fSEmmanuel Vadot 	 */
354*9e88711fSEmmanuel Vadot 	if (qid == 1)
355*9e88711fSEmmanuel Vadot 		rv = 0;
356*9e88711fSEmmanuel Vadot 	if (rv != 0)
357*9e88711fSEmmanuel Vadot 		device_printf(sc->dev, "SMC Call fail %d\n", rv);
358*9e88711fSEmmanuel Vadot 	return (rv);
359*9e88711fSEmmanuel Vadot }
360*9e88711fSEmmanuel Vadot 
361*9e88711fSEmmanuel Vadot static int
zynqmp_firmware_reset_assert(device_t dev,uint32_t resetid,bool enable)362*9e88711fSEmmanuel Vadot zynqmp_firmware_reset_assert(device_t dev, uint32_t resetid, bool enable)
363*9e88711fSEmmanuel Vadot {
364*9e88711fSEmmanuel Vadot 	struct zynqmp_firmware_softc *sc;
365*9e88711fSEmmanuel Vadot 	int rv;
366*9e88711fSEmmanuel Vadot 
367*9e88711fSEmmanuel Vadot 	sc = device_get_softc(dev);
368*9e88711fSEmmanuel Vadot 	rv = zynqmp_call_smc(PM_RESET_ASSERT, resetid, enable, 0, 0, NULL, true);
369*9e88711fSEmmanuel Vadot 	if (rv != 0)
370*9e88711fSEmmanuel Vadot 		device_printf(sc->dev, "SMC Call fail %d\n", rv);
371*9e88711fSEmmanuel Vadot 
372*9e88711fSEmmanuel Vadot 	return (rv);
373*9e88711fSEmmanuel Vadot }
374*9e88711fSEmmanuel Vadot 
375*9e88711fSEmmanuel Vadot static int
zynqmp_firmware_reset_get_status(device_t dev,uint32_t resetid,bool * status)376*9e88711fSEmmanuel Vadot zynqmp_firmware_reset_get_status(device_t dev, uint32_t resetid, bool *status)
377*9e88711fSEmmanuel Vadot {
378*9e88711fSEmmanuel Vadot 	struct zynqmp_firmware_softc *sc;
379*9e88711fSEmmanuel Vadot 	uint32_t payload[4];
380*9e88711fSEmmanuel Vadot 	int rv;
381*9e88711fSEmmanuel Vadot 
382*9e88711fSEmmanuel Vadot 	sc = device_get_softc(dev);
383*9e88711fSEmmanuel Vadot 	rv = zynqmp_call_smc(PM_RESET_GET_STATUS, resetid, 0, 0, 0, payload, true);
384*9e88711fSEmmanuel Vadot 	if (rv != 0) {
385*9e88711fSEmmanuel Vadot 		device_printf(sc->dev, "SMC Call fail %d\n", rv);
386*9e88711fSEmmanuel Vadot 		return (rv);
387*9e88711fSEmmanuel Vadot 	}
388*9e88711fSEmmanuel Vadot 	*status = payload[1];
389*9e88711fSEmmanuel Vadot 
390*9e88711fSEmmanuel Vadot 	return (rv);
391*9e88711fSEmmanuel Vadot }
392*9e88711fSEmmanuel Vadot 
393*9e88711fSEmmanuel Vadot /* Simplebus methods */
394*9e88711fSEmmanuel Vadot static struct simplebus_devinfo *
zynqmp_firmware_setup_dinfo(device_t dev,phandle_t node,struct simplebus_devinfo * di)395*9e88711fSEmmanuel Vadot zynqmp_firmware_setup_dinfo(device_t dev, phandle_t node,
396*9e88711fSEmmanuel Vadot     struct simplebus_devinfo *di)
397*9e88711fSEmmanuel Vadot {
398*9e88711fSEmmanuel Vadot 	struct simplebus_softc *sc;
399*9e88711fSEmmanuel Vadot 	struct simplebus_devinfo *ndi;
400*9e88711fSEmmanuel Vadot 
401*9e88711fSEmmanuel Vadot 	sc = device_get_softc(dev);
402*9e88711fSEmmanuel Vadot 	if (di == NULL)
403*9e88711fSEmmanuel Vadot 		ndi = malloc(sizeof(*ndi), M_DEVBUF, M_WAITOK | M_ZERO);
404*9e88711fSEmmanuel Vadot 	else
405*9e88711fSEmmanuel Vadot 		ndi = di;
406*9e88711fSEmmanuel Vadot 	if (ofw_bus_gen_setup_devinfo(&ndi->obdinfo, node) != 0) {
407*9e88711fSEmmanuel Vadot 		if (di == NULL)
408*9e88711fSEmmanuel Vadot 			free(ndi, M_DEVBUF);
409*9e88711fSEmmanuel Vadot 		return (NULL);
410*9e88711fSEmmanuel Vadot 	}
411*9e88711fSEmmanuel Vadot 
412*9e88711fSEmmanuel Vadot 	/* reg resources is from the parent but interrupts is on the node itself */
413*9e88711fSEmmanuel Vadot 	resource_list_init(&ndi->rl);
414*9e88711fSEmmanuel Vadot 	ofw_bus_reg_to_rl(dev, OF_parent(node), sc->acells, sc->scells, &ndi->rl);
415*9e88711fSEmmanuel Vadot 	ofw_bus_intr_to_rl(dev, node, &ndi->rl, NULL);
416*9e88711fSEmmanuel Vadot 
417*9e88711fSEmmanuel Vadot 	return (ndi);
418*9e88711fSEmmanuel Vadot }
419*9e88711fSEmmanuel Vadot 
420*9e88711fSEmmanuel Vadot static device_t
zynqmp_firmware_add_device(device_t dev,phandle_t node,u_int order,const char * name,int unit,struct simplebus_devinfo * di)421*9e88711fSEmmanuel Vadot zynqmp_firmware_add_device(device_t dev, phandle_t node, u_int order,
422*9e88711fSEmmanuel Vadot     const char *name, int unit, struct simplebus_devinfo *di)
423*9e88711fSEmmanuel Vadot {
424*9e88711fSEmmanuel Vadot 	struct simplebus_devinfo *ndi;
425*9e88711fSEmmanuel Vadot 	device_t cdev;
426*9e88711fSEmmanuel Vadot 
427*9e88711fSEmmanuel Vadot 	if ((ndi = zynqmp_firmware_setup_dinfo(dev, node, di)) == NULL)
428*9e88711fSEmmanuel Vadot 		return (NULL);
429*9e88711fSEmmanuel Vadot 	cdev = device_add_child_ordered(dev, order, name, unit);
430*9e88711fSEmmanuel Vadot 	if (cdev == NULL) {
431*9e88711fSEmmanuel Vadot 		device_printf(dev, "<%s>: device_add_child failed\n",
432*9e88711fSEmmanuel Vadot 		    ndi->obdinfo.obd_name);
433*9e88711fSEmmanuel Vadot 		resource_list_free(&ndi->rl);
434*9e88711fSEmmanuel Vadot 		ofw_bus_gen_destroy_devinfo(&ndi->obdinfo);
435*9e88711fSEmmanuel Vadot 		if (di == NULL)
436*9e88711fSEmmanuel Vadot 			free(ndi, M_DEVBUF);
437*9e88711fSEmmanuel Vadot 		return (NULL);
438*9e88711fSEmmanuel Vadot 	}
439*9e88711fSEmmanuel Vadot 	device_set_ivars(cdev, ndi);
440*9e88711fSEmmanuel Vadot 
441*9e88711fSEmmanuel Vadot 	return(cdev);
442*9e88711fSEmmanuel Vadot }
443*9e88711fSEmmanuel Vadot 
444*9e88711fSEmmanuel Vadot static int
zynqmp_firmware_probe(device_t dev)445*9e88711fSEmmanuel Vadot zynqmp_firmware_probe(device_t dev)
446*9e88711fSEmmanuel Vadot {
447*9e88711fSEmmanuel Vadot 
448*9e88711fSEmmanuel Vadot 	if (!ofw_bus_status_okay(dev))
449*9e88711fSEmmanuel Vadot 		return (ENXIO);
450*9e88711fSEmmanuel Vadot 	if (!ofw_bus_is_compatible(dev, "xlnx,zynqmp-firmware"))
451*9e88711fSEmmanuel Vadot 		return (ENXIO);
452*9e88711fSEmmanuel Vadot 	device_set_desc(dev, "ZynqMP Firmware");
453*9e88711fSEmmanuel Vadot 	return (0);
454*9e88711fSEmmanuel Vadot }
455*9e88711fSEmmanuel Vadot 
456*9e88711fSEmmanuel Vadot static int
zynqmp_firmware_attach(device_t dev)457*9e88711fSEmmanuel Vadot zynqmp_firmware_attach(device_t dev)
458*9e88711fSEmmanuel Vadot {
459*9e88711fSEmmanuel Vadot 	struct zynqmp_firmware_softc *sc;
460*9e88711fSEmmanuel Vadot 	phandle_t node, child;
461*9e88711fSEmmanuel Vadot 	device_t cdev;
462*9e88711fSEmmanuel Vadot 
463*9e88711fSEmmanuel Vadot 	sc = device_get_softc(dev);
464*9e88711fSEmmanuel Vadot 	sc->dev = dev;
465*9e88711fSEmmanuel Vadot 
466*9e88711fSEmmanuel Vadot 	if (bootverbose) {
467*9e88711fSEmmanuel Vadot 		zynqmp_get_api_version(sc);
468*9e88711fSEmmanuel Vadot 		zynqmp_get_chipid(sc);
469*9e88711fSEmmanuel Vadot 		zynqmp_get_trustzone_version(sc);
470*9e88711fSEmmanuel Vadot 	}
471*9e88711fSEmmanuel Vadot 
472*9e88711fSEmmanuel Vadot 	/* Attach children */
473*9e88711fSEmmanuel Vadot 	node = ofw_bus_get_node(dev);
474*9e88711fSEmmanuel Vadot 	for (child = OF_child(node); child != 0; child = OF_peer(child)) {
475*9e88711fSEmmanuel Vadot 		cdev = zynqmp_firmware_add_device(dev, child, 0, NULL, -1, NULL);
476*9e88711fSEmmanuel Vadot 		if (cdev != NULL)
477*9e88711fSEmmanuel Vadot 			device_probe_and_attach(cdev);
478*9e88711fSEmmanuel Vadot 	}
479*9e88711fSEmmanuel Vadot 
480*9e88711fSEmmanuel Vadot 	return (bus_generic_attach(dev));
481*9e88711fSEmmanuel Vadot }
482*9e88711fSEmmanuel Vadot 
483*9e88711fSEmmanuel Vadot static device_method_t zynqmp_firmware_methods[] = {
484*9e88711fSEmmanuel Vadot 	/* device_if */
485*9e88711fSEmmanuel Vadot 	DEVMETHOD(device_probe, 	zynqmp_firmware_probe),
486*9e88711fSEmmanuel Vadot 	DEVMETHOD(device_attach, 	zynqmp_firmware_attach),
487*9e88711fSEmmanuel Vadot 
488*9e88711fSEmmanuel Vadot 	/* zynqmp_firmware_if */
489*9e88711fSEmmanuel Vadot 	DEVMETHOD(zynqmp_firmware_clock_enable, zynqmp_firmware_clock_enable),
490*9e88711fSEmmanuel Vadot 	DEVMETHOD(zynqmp_firmware_clock_disable, zynqmp_firmware_clock_disable),
491*9e88711fSEmmanuel Vadot 	DEVMETHOD(zynqmp_firmware_clock_getstate, zynqmp_firmware_clock_getstate),
492*9e88711fSEmmanuel Vadot 	DEVMETHOD(zynqmp_firmware_clock_setdivider, zynqmp_firmware_clock_setdivider),
493*9e88711fSEmmanuel Vadot 	DEVMETHOD(zynqmp_firmware_clock_getdivider, zynqmp_firmware_clock_getdivider),
494*9e88711fSEmmanuel Vadot 	DEVMETHOD(zynqmp_firmware_clock_setparent, zynqmp_firmware_clock_setparent),
495*9e88711fSEmmanuel Vadot 	DEVMETHOD(zynqmp_firmware_clock_getparent, zynqmp_firmware_clock_getparent),
496*9e88711fSEmmanuel Vadot 	DEVMETHOD(zynqmp_firmware_pll_get_mode, zynqmp_firmware_pll_get_mode),
497*9e88711fSEmmanuel Vadot 	DEVMETHOD(zynqmp_firmware_pll_get_frac_data, zynqmp_firmware_pll_get_frac_data),
498*9e88711fSEmmanuel Vadot 	DEVMETHOD(zynqmp_firmware_clock_get_fixedfactor, zynqmp_firmware_clock_get_fixedfactor),
499*9e88711fSEmmanuel Vadot 	DEVMETHOD(zynqmp_firmware_query_data, zynqmp_firmware_query_data),
500*9e88711fSEmmanuel Vadot 	DEVMETHOD(zynqmp_firmware_reset_assert, zynqmp_firmware_reset_assert),
501*9e88711fSEmmanuel Vadot 	DEVMETHOD(zynqmp_firmware_reset_get_status, zynqmp_firmware_reset_get_status),
502*9e88711fSEmmanuel Vadot 
503*9e88711fSEmmanuel Vadot 	DEVMETHOD_END
504*9e88711fSEmmanuel Vadot };
505*9e88711fSEmmanuel Vadot 
506*9e88711fSEmmanuel Vadot DEFINE_CLASS_1(zynqmp_firmware, zynqmp_firmware_driver, zynqmp_firmware_methods,
507*9e88711fSEmmanuel Vadot   sizeof(struct zynqmp_firmware_softc), simplebus_driver);
508*9e88711fSEmmanuel Vadot 
509*9e88711fSEmmanuel Vadot EARLY_DRIVER_MODULE(zynqmp_firmware, simplebus, zynqmp_firmware_driver, 0, 0,
510*9e88711fSEmmanuel Vadot     BUS_PASS_BUS + BUS_PASS_ORDER_LATE);
511*9e88711fSEmmanuel Vadot MODULE_VERSION(zynqmp_firmware, 1);
512