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