19e88711fSEmmanuel Vadot /*-
29e88711fSEmmanuel Vadot * SPDX-License-Identifier: BSD-2-Clause
39e88711fSEmmanuel Vadot *
49e88711fSEmmanuel Vadot * Copyright (c) 2023 Beckhoff Automation GmbH & Co. KG
59e88711fSEmmanuel Vadot *
69e88711fSEmmanuel Vadot * Redistribution and use in source and binary forms, with or without
79e88711fSEmmanuel Vadot * modification, are permitted provided that the following conditions
89e88711fSEmmanuel Vadot * are met:
99e88711fSEmmanuel Vadot * 1. Redistributions of source code must retain the above copyright
109e88711fSEmmanuel Vadot * notice, this list of conditions and the following disclaimer.
119e88711fSEmmanuel Vadot * 2. Redistributions in binary form must reproduce the above copyright
129e88711fSEmmanuel Vadot * notice, this list of conditions and the following disclaimer in the
139e88711fSEmmanuel Vadot * documentation and/or other materials provided with the distribution.
149e88711fSEmmanuel Vadot *
159e88711fSEmmanuel Vadot * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
169e88711fSEmmanuel Vadot * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
179e88711fSEmmanuel Vadot * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
189e88711fSEmmanuel Vadot * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
199e88711fSEmmanuel Vadot * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
209e88711fSEmmanuel Vadot * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
219e88711fSEmmanuel Vadot * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
229e88711fSEmmanuel Vadot * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
239e88711fSEmmanuel Vadot * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
249e88711fSEmmanuel Vadot * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
259e88711fSEmmanuel Vadot * SUCH DAMAGE.
269e88711fSEmmanuel Vadot */
279e88711fSEmmanuel Vadot
289e88711fSEmmanuel Vadot #include <sys/cdefs.h>
299e88711fSEmmanuel Vadot
309e88711fSEmmanuel Vadot #include <sys/param.h>
319e88711fSEmmanuel Vadot #include <sys/systm.h>
329e88711fSEmmanuel Vadot #include <sys/kernel.h>
339e88711fSEmmanuel Vadot #include <sys/module.h>
349e88711fSEmmanuel Vadot #include <sys/malloc.h>
359e88711fSEmmanuel Vadot #include <sys/bus.h>
369e88711fSEmmanuel Vadot #include <sys/cpu.h>
379e88711fSEmmanuel Vadot #include <machine/bus.h>
389e88711fSEmmanuel Vadot
399e88711fSEmmanuel Vadot #include <dev/fdt/simplebus.h>
409e88711fSEmmanuel Vadot
419e88711fSEmmanuel Vadot #include <dev/ofw/openfirm.h>
429e88711fSEmmanuel Vadot #include <dev/ofw/ofw_bus.h>
439e88711fSEmmanuel Vadot #include <dev/ofw/ofw_bus_subr.h>
449e88711fSEmmanuel Vadot
459e88711fSEmmanuel Vadot #include <dev/psci/smccc.h>
469e88711fSEmmanuel Vadot
479e88711fSEmmanuel Vadot #include <dev/firmware/xilinx/pm_defs.h>
489e88711fSEmmanuel Vadot
499e88711fSEmmanuel Vadot #include "zynqmp_firmware_if.h"
509e88711fSEmmanuel Vadot
519e88711fSEmmanuel Vadot enum {
529e88711fSEmmanuel Vadot IOCTL_GET_RPU_OPER_MODE = 0,
539e88711fSEmmanuel Vadot IOCTL_SET_RPU_OPER_MODE = 1,
549e88711fSEmmanuel Vadot IOCTL_RPU_BOOT_ADDR_CONFIG = 2,
559e88711fSEmmanuel Vadot IOCTL_TCM_COMB_CONFIG = 3,
569e88711fSEmmanuel Vadot IOCTL_SET_TAPDELAY_BYPASS = 4,
579e88711fSEmmanuel Vadot IOCTL_SET_SGMII_MODE = 5,
589e88711fSEmmanuel Vadot IOCTL_SD_DLL_RESET = 6,
599e88711fSEmmanuel Vadot IOCTL_SET_SD_TAPDELAY = 7,
609e88711fSEmmanuel Vadot /* Ioctl for clock driver */
619e88711fSEmmanuel Vadot IOCTL_SET_PLL_FRAC_MODE = 8,
629e88711fSEmmanuel Vadot IOCTL_GET_PLL_FRAC_MODE = 9,
639e88711fSEmmanuel Vadot IOCTL_SET_PLL_FRAC_DATA = 10,
649e88711fSEmmanuel Vadot IOCTL_GET_PLL_FRAC_DATA = 11,
659e88711fSEmmanuel Vadot IOCTL_WRITE_GGS = 12,
669e88711fSEmmanuel Vadot IOCTL_READ_GGS = 13,
679e88711fSEmmanuel Vadot IOCTL_WRITE_PGGS = 14,
689e88711fSEmmanuel Vadot IOCTL_READ_PGGS = 15,
699e88711fSEmmanuel Vadot /* IOCTL for ULPI reset */
709e88711fSEmmanuel Vadot IOCTL_ULPI_RESET = 16,
719e88711fSEmmanuel Vadot /* Set healthy bit value */
729e88711fSEmmanuel Vadot IOCTL_SET_BOOT_HEALTH_STATUS = 17,
739e88711fSEmmanuel Vadot IOCTL_AFI = 18,
749e88711fSEmmanuel Vadot /* Probe counter read/write */
759e88711fSEmmanuel Vadot IOCTL_PROBE_COUNTER_READ = 19,
769e88711fSEmmanuel Vadot IOCTL_PROBE_COUNTER_WRITE = 20,
779e88711fSEmmanuel Vadot IOCTL_OSPI_MUX_SELECT = 21,
789e88711fSEmmanuel Vadot /* IOCTL for USB power request */
799e88711fSEmmanuel Vadot IOCTL_USB_SET_STATE = 22,
809e88711fSEmmanuel Vadot /* IOCTL to get last reset reason */
819e88711fSEmmanuel Vadot IOCTL_GET_LAST_RESET_REASON = 23,
829e88711fSEmmanuel Vadot /* AI engine NPI ISR clear */
839e88711fSEmmanuel Vadot IOCTL_AIE_ISR_CLEAR = 24,
849e88711fSEmmanuel Vadot /* Register SGI to ATF */
859e88711fSEmmanuel Vadot IOCTL_REGISTER_SGI = 25,
869e88711fSEmmanuel Vadot };
879e88711fSEmmanuel Vadot
889e88711fSEmmanuel Vadot typedef int (*zynqmp_callfn_t)(register_t, register_t, register_t, uint32_t *payload);
899e88711fSEmmanuel Vadot
909e88711fSEmmanuel Vadot struct zynqmp_firmware_softc {
919e88711fSEmmanuel Vadot struct simplebus_softc sc;
929e88711fSEmmanuel Vadot device_t dev;
939e88711fSEmmanuel Vadot zynqmp_callfn_t callfn;
949e88711fSEmmanuel Vadot };
959e88711fSEmmanuel Vadot
969e88711fSEmmanuel Vadot /* SMC calling methods */
979e88711fSEmmanuel Vadot #define PM_SIP_SVC 0xC2000000
989e88711fSEmmanuel Vadot
999e88711fSEmmanuel 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)1009e88711fSEmmanuel 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)
1019e88711fSEmmanuel Vadot {
1029e88711fSEmmanuel Vadot struct arm_smccc_res res;
1039e88711fSEmmanuel Vadot uint64_t args[3];
1049e88711fSEmmanuel Vadot
1059e88711fSEmmanuel Vadot args[0] = id | PM_SIP_SVC;
1069e88711fSEmmanuel Vadot args[1] = ((uint64_t)a1 << 32) | a0;
1079e88711fSEmmanuel Vadot args[2] = ((uint64_t)a3 << 32) | a2;
108*b9cd72b0SAndrew Turner arm_smccc_invoke_smc(args[0], args[1], args[2], &res);
1099e88711fSEmmanuel Vadot if (payload != NULL) {
1109e88711fSEmmanuel Vadot payload[0] = res.a0 & 0xFFFFFFFF;
1119e88711fSEmmanuel Vadot payload[1] = res.a0 >> 32;
1129e88711fSEmmanuel Vadot payload[2] = res.a1 & 0xFFFFFFFF;
1139e88711fSEmmanuel Vadot payload[3] = res.a1 >> 32;
1149e88711fSEmmanuel Vadot if (!ignore_error && payload[0] != PM_RET_SUCCESS) {
1159e88711fSEmmanuel Vadot printf("%s: fail %x\n", __func__, payload[0]);
1169e88711fSEmmanuel Vadot return (EINVAL);
1179e88711fSEmmanuel Vadot }
1189e88711fSEmmanuel Vadot }
1199e88711fSEmmanuel Vadot return (0);
1209e88711fSEmmanuel Vadot }
1219e88711fSEmmanuel Vadot
1229e88711fSEmmanuel Vadot /* Firmware methods */
1239e88711fSEmmanuel Vadot static int
zynqmp_get_api_version(struct zynqmp_firmware_softc * sc)1249e88711fSEmmanuel Vadot zynqmp_get_api_version(struct zynqmp_firmware_softc *sc)
1259e88711fSEmmanuel Vadot {
1269e88711fSEmmanuel Vadot uint32_t payload[4];
1279e88711fSEmmanuel Vadot int rv;
1289e88711fSEmmanuel Vadot
1299e88711fSEmmanuel Vadot rv = zynqmp_call_smc(PM_GET_API_VERSION, 0, 0, 0, 0, payload, false);
1309e88711fSEmmanuel Vadot if (rv != 0) {
1319e88711fSEmmanuel Vadot device_printf(sc->dev, "SMC Call fail %d\n", rv);
1329e88711fSEmmanuel Vadot goto out;
1339e88711fSEmmanuel Vadot }
1349e88711fSEmmanuel Vadot device_printf(sc->dev, "API version = %d.%d\n",
1359e88711fSEmmanuel Vadot payload[1] >> 16, payload[1] & 0xFFFF);
1369e88711fSEmmanuel Vadot out:
1379e88711fSEmmanuel Vadot return (rv);
1389e88711fSEmmanuel Vadot }
1399e88711fSEmmanuel Vadot
1409e88711fSEmmanuel Vadot static int
zynqmp_get_chipid(struct zynqmp_firmware_softc * sc)1419e88711fSEmmanuel Vadot zynqmp_get_chipid(struct zynqmp_firmware_softc *sc)
1429e88711fSEmmanuel Vadot {
1439e88711fSEmmanuel Vadot uint32_t payload[4];
1449e88711fSEmmanuel Vadot int rv;
1459e88711fSEmmanuel Vadot
1469e88711fSEmmanuel Vadot rv = zynqmp_call_smc(PM_GET_CHIPID, 0, 0, 0, 0, payload, false);
1479e88711fSEmmanuel Vadot if (rv != 0) {
1489e88711fSEmmanuel Vadot device_printf(sc->dev, "SMC Call fail %d\n", rv);
1499e88711fSEmmanuel Vadot goto out;
1509e88711fSEmmanuel Vadot }
1519e88711fSEmmanuel Vadot device_printf(sc->dev, "ID Code = %x Version = %x\n",
1529e88711fSEmmanuel Vadot payload[1], payload[2]);
1539e88711fSEmmanuel Vadot out:
1549e88711fSEmmanuel Vadot return (rv);
1559e88711fSEmmanuel Vadot }
1569e88711fSEmmanuel Vadot
1579e88711fSEmmanuel Vadot static int
zynqmp_get_trustzone_version(struct zynqmp_firmware_softc * sc)1589e88711fSEmmanuel Vadot zynqmp_get_trustzone_version(struct zynqmp_firmware_softc *sc)
1599e88711fSEmmanuel Vadot {
1609e88711fSEmmanuel Vadot uint32_t payload[4];
1619e88711fSEmmanuel Vadot int rv;
1629e88711fSEmmanuel Vadot
1639e88711fSEmmanuel Vadot rv = zynqmp_call_smc(PM_GET_TRUSTZONE_VERSION, 0, 0, 0, 0, payload, false);
1649e88711fSEmmanuel Vadot if (rv != 0) {
1659e88711fSEmmanuel Vadot device_printf(sc->dev, "SMC Call fail %d\n", rv);
1669e88711fSEmmanuel Vadot goto out;
1679e88711fSEmmanuel Vadot }
1689e88711fSEmmanuel Vadot device_printf(sc->dev, "Trustzone Version = %x\n",
1699e88711fSEmmanuel Vadot payload[1]);
1709e88711fSEmmanuel Vadot out:
1719e88711fSEmmanuel Vadot return (rv);
1729e88711fSEmmanuel Vadot }
1739e88711fSEmmanuel Vadot
1749e88711fSEmmanuel Vadot /* zynqmp_firmware methods */
1759e88711fSEmmanuel Vadot static int
zynqmp_firmware_clock_enable(device_t dev,uint32_t clkid)1769e88711fSEmmanuel Vadot zynqmp_firmware_clock_enable(device_t dev, uint32_t clkid)
1779e88711fSEmmanuel Vadot {
1789e88711fSEmmanuel Vadot struct zynqmp_firmware_softc *sc;
1799e88711fSEmmanuel Vadot uint32_t payload[4];
1809e88711fSEmmanuel Vadot int rv;
1819e88711fSEmmanuel Vadot
1829e88711fSEmmanuel Vadot sc = device_get_softc(dev);
1839e88711fSEmmanuel Vadot rv = zynqmp_call_smc(PM_CLOCK_ENABLE, clkid, 0, 0, 0, payload, false);
1849e88711fSEmmanuel Vadot if (rv != 0)
1859e88711fSEmmanuel Vadot device_printf(sc->dev, "SMC Call fail %d\n", rv);
1869e88711fSEmmanuel Vadot return (rv);
1879e88711fSEmmanuel Vadot }
1889e88711fSEmmanuel Vadot
1899e88711fSEmmanuel Vadot static int
zynqmp_firmware_clock_disable(device_t dev,uint32_t clkid)1909e88711fSEmmanuel Vadot zynqmp_firmware_clock_disable(device_t dev, uint32_t clkid)
1919e88711fSEmmanuel Vadot {
1929e88711fSEmmanuel Vadot struct zynqmp_firmware_softc *sc;
1939e88711fSEmmanuel Vadot uint32_t payload[4];
1949e88711fSEmmanuel Vadot int rv;
1959e88711fSEmmanuel Vadot
1969e88711fSEmmanuel Vadot sc = device_get_softc(dev);
1979e88711fSEmmanuel Vadot rv = zynqmp_call_smc(PM_CLOCK_DISABLE, clkid, 0, 0, 0, payload, false);
1989e88711fSEmmanuel Vadot if (rv != 0)
1999e88711fSEmmanuel Vadot device_printf(sc->dev, "SMC Call fail %d\n", rv);
2009e88711fSEmmanuel Vadot return (rv);
2019e88711fSEmmanuel Vadot }
2029e88711fSEmmanuel Vadot
2039e88711fSEmmanuel Vadot static int
zynqmp_firmware_clock_getstate(device_t dev,uint32_t clkid,bool * enabled)2049e88711fSEmmanuel Vadot zynqmp_firmware_clock_getstate(device_t dev, uint32_t clkid, bool *enabled)
2059e88711fSEmmanuel Vadot {
2069e88711fSEmmanuel Vadot struct zynqmp_firmware_softc *sc;
2079e88711fSEmmanuel Vadot uint32_t payload[4];
2089e88711fSEmmanuel Vadot int rv;
2099e88711fSEmmanuel Vadot
2109e88711fSEmmanuel Vadot sc = device_get_softc(dev);
2119e88711fSEmmanuel Vadot rv = zynqmp_call_smc(PM_CLOCK_GETSTATE, clkid, 0, 0, 0, payload, false);
2129e88711fSEmmanuel Vadot if (rv != 0) {
2139e88711fSEmmanuel Vadot device_printf(sc->dev, "SMC Call fail %d\n", rv);
2149e88711fSEmmanuel Vadot goto out;
2159e88711fSEmmanuel Vadot }
2169e88711fSEmmanuel Vadot *enabled = payload[1] == 1 ? true : false;
2179e88711fSEmmanuel Vadot
2189e88711fSEmmanuel Vadot out:
2199e88711fSEmmanuel Vadot return (rv);
2209e88711fSEmmanuel Vadot }
2219e88711fSEmmanuel Vadot
2229e88711fSEmmanuel Vadot static int
zynqmp_firmware_clock_setdivider(device_t dev,uint32_t clkid,uint32_t div)2239e88711fSEmmanuel Vadot zynqmp_firmware_clock_setdivider(device_t dev, uint32_t clkid, uint32_t div)
2249e88711fSEmmanuel Vadot {
2259e88711fSEmmanuel Vadot struct zynqmp_firmware_softc *sc;
2269e88711fSEmmanuel Vadot uint32_t payload[4];
2279e88711fSEmmanuel Vadot int rv;
2289e88711fSEmmanuel Vadot
2299e88711fSEmmanuel Vadot sc = device_get_softc(dev);
2309e88711fSEmmanuel Vadot rv = zynqmp_call_smc(PM_CLOCK_SETDIVIDER, clkid, div, 0, 0, payload, false);
2319e88711fSEmmanuel Vadot if (rv != 0)
2329e88711fSEmmanuel Vadot device_printf(sc->dev, "SMC Call fail %d\n", rv);
2339e88711fSEmmanuel Vadot return (rv);
2349e88711fSEmmanuel Vadot }
2359e88711fSEmmanuel Vadot
2369e88711fSEmmanuel Vadot static int
zynqmp_firmware_clock_getdivider(device_t dev,uint32_t clkid,uint32_t * div)2379e88711fSEmmanuel Vadot zynqmp_firmware_clock_getdivider(device_t dev, uint32_t clkid, uint32_t *div)
2389e88711fSEmmanuel Vadot {
2399e88711fSEmmanuel Vadot struct zynqmp_firmware_softc *sc;
2409e88711fSEmmanuel Vadot uint32_t payload[4];
2419e88711fSEmmanuel Vadot int rv;
2429e88711fSEmmanuel Vadot
2439e88711fSEmmanuel Vadot sc = device_get_softc(dev);
2449e88711fSEmmanuel Vadot rv = zynqmp_call_smc(PM_CLOCK_GETDIVIDER, clkid, 0, 0, 0, payload, false);
2459e88711fSEmmanuel Vadot if (rv != 0) {
2469e88711fSEmmanuel Vadot device_printf(sc->dev, "SMC Call fail %d\n", rv);
2479e88711fSEmmanuel Vadot goto out;
2489e88711fSEmmanuel Vadot }
2499e88711fSEmmanuel Vadot *div = payload[1];
2509e88711fSEmmanuel Vadot
2519e88711fSEmmanuel Vadot out:
2529e88711fSEmmanuel Vadot return (rv);
2539e88711fSEmmanuel Vadot }
2549e88711fSEmmanuel Vadot
2559e88711fSEmmanuel Vadot static int
zynqmp_firmware_clock_setparent(device_t dev,uint32_t clkid,uint32_t parentid)2569e88711fSEmmanuel Vadot zynqmp_firmware_clock_setparent(device_t dev, uint32_t clkid, uint32_t parentid)
2579e88711fSEmmanuel Vadot {
2589e88711fSEmmanuel Vadot struct zynqmp_firmware_softc *sc;
2599e88711fSEmmanuel Vadot uint32_t payload[4];
2609e88711fSEmmanuel Vadot int rv;
2619e88711fSEmmanuel Vadot
2629e88711fSEmmanuel Vadot sc = device_get_softc(dev);
2639e88711fSEmmanuel Vadot rv = zynqmp_call_smc(PM_CLOCK_SETPARENT, clkid, parentid, 0, 0, payload, false);
2649e88711fSEmmanuel Vadot if (rv != 0)
2659e88711fSEmmanuel Vadot device_printf(sc->dev, "SMC Call fail %d\n", rv);
2669e88711fSEmmanuel Vadot return (rv);
2679e88711fSEmmanuel Vadot }
2689e88711fSEmmanuel Vadot
2699e88711fSEmmanuel Vadot static int
zynqmp_firmware_clock_getparent(device_t dev,uint32_t clkid,uint32_t * parentid)2709e88711fSEmmanuel Vadot zynqmp_firmware_clock_getparent(device_t dev, uint32_t clkid, uint32_t *parentid)
2719e88711fSEmmanuel Vadot {
2729e88711fSEmmanuel Vadot struct zynqmp_firmware_softc *sc;
2739e88711fSEmmanuel Vadot uint32_t payload[4];
2749e88711fSEmmanuel Vadot int rv;
2759e88711fSEmmanuel Vadot
2769e88711fSEmmanuel Vadot sc = device_get_softc(dev);
2779e88711fSEmmanuel Vadot rv = zynqmp_call_smc(PM_CLOCK_GETPARENT, clkid, 0, 0, 0, payload, false);
2789e88711fSEmmanuel Vadot if (rv != 0) {
2799e88711fSEmmanuel Vadot device_printf(sc->dev, "SMC Call fail %d\n", rv);
2809e88711fSEmmanuel Vadot goto out;
2819e88711fSEmmanuel Vadot }
2829e88711fSEmmanuel Vadot *parentid = payload[1];
2839e88711fSEmmanuel Vadot out:
2849e88711fSEmmanuel Vadot return (rv);
2859e88711fSEmmanuel Vadot }
2869e88711fSEmmanuel Vadot
2879e88711fSEmmanuel Vadot static int
zynqmp_firmware_pll_get_mode(device_t dev,uint32_t pllid,uint32_t * mode)2889e88711fSEmmanuel Vadot zynqmp_firmware_pll_get_mode(device_t dev, uint32_t pllid, uint32_t *mode)
2899e88711fSEmmanuel Vadot {
2909e88711fSEmmanuel Vadot struct zynqmp_firmware_softc *sc;
2919e88711fSEmmanuel Vadot uint32_t payload[4];
2929e88711fSEmmanuel Vadot int rv;
2939e88711fSEmmanuel Vadot
2949e88711fSEmmanuel Vadot sc = device_get_softc(dev);
2959e88711fSEmmanuel Vadot rv = zynqmp_call_smc(PM_IOCTL, 0, IOCTL_GET_PLL_FRAC_MODE, pllid, 0, payload, false);
2969e88711fSEmmanuel Vadot if (rv != 0) {
2979e88711fSEmmanuel Vadot device_printf(sc->dev, "SMC Call fail %d\n", rv);
2989e88711fSEmmanuel Vadot goto out;
2999e88711fSEmmanuel Vadot }
3009e88711fSEmmanuel Vadot *mode = payload[1];
3019e88711fSEmmanuel Vadot out:
3029e88711fSEmmanuel Vadot return (rv);
3039e88711fSEmmanuel Vadot }
3049e88711fSEmmanuel Vadot
3059e88711fSEmmanuel Vadot static int
zynqmp_firmware_pll_get_frac_data(device_t dev,uint32_t pllid,uint32_t * data)3069e88711fSEmmanuel Vadot zynqmp_firmware_pll_get_frac_data(device_t dev, uint32_t pllid, uint32_t *data)
3079e88711fSEmmanuel Vadot {
3089e88711fSEmmanuel Vadot struct zynqmp_firmware_softc *sc;
3099e88711fSEmmanuel Vadot uint32_t payload[4];
3109e88711fSEmmanuel Vadot int rv;
3119e88711fSEmmanuel Vadot
3129e88711fSEmmanuel Vadot sc = device_get_softc(dev);
3139e88711fSEmmanuel Vadot rv = zynqmp_call_smc(PM_IOCTL, 0, IOCTL_GET_PLL_FRAC_DATA, pllid, 0, payload, false);
3149e88711fSEmmanuel Vadot if (rv != 0) {
3159e88711fSEmmanuel Vadot device_printf(sc->dev, "SMC Call fail %d\n", rv);
3169e88711fSEmmanuel Vadot goto out;
3179e88711fSEmmanuel Vadot }
3189e88711fSEmmanuel Vadot *data = payload[1];
3199e88711fSEmmanuel Vadot out:
3209e88711fSEmmanuel Vadot return (rv);
3219e88711fSEmmanuel Vadot }
3229e88711fSEmmanuel Vadot
3239e88711fSEmmanuel Vadot static int
zynqmp_firmware_clock_get_fixedfactor(device_t dev,uint32_t clkid,uint32_t * mult,uint32_t * div)3249e88711fSEmmanuel Vadot zynqmp_firmware_clock_get_fixedfactor(device_t dev, uint32_t clkid, uint32_t *mult, uint32_t *div)
3259e88711fSEmmanuel Vadot {
3269e88711fSEmmanuel Vadot struct zynqmp_firmware_softc *sc;
3279e88711fSEmmanuel Vadot uint32_t payload[4];
3289e88711fSEmmanuel Vadot int rv;
3299e88711fSEmmanuel Vadot
3309e88711fSEmmanuel Vadot sc = device_get_softc(dev);
3319e88711fSEmmanuel Vadot rv = zynqmp_call_smc(PM_QUERY_DATA, PM_QID_CLOCK_GET_FIXEDFACTOR_PARAMS, clkid, 0, 0, payload, true);
3329e88711fSEmmanuel Vadot if (rv != 0) {
3339e88711fSEmmanuel Vadot device_printf(sc->dev, "SMC Call fail %d\n", rv);
3349e88711fSEmmanuel Vadot goto out;
3359e88711fSEmmanuel Vadot }
3369e88711fSEmmanuel Vadot *mult = payload[1];
3379e88711fSEmmanuel Vadot *div = payload[2];
3389e88711fSEmmanuel Vadot out:
3399e88711fSEmmanuel Vadot return (rv);
3409e88711fSEmmanuel Vadot }
3419e88711fSEmmanuel Vadot
3429e88711fSEmmanuel 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)3439e88711fSEmmanuel Vadot zynqmp_firmware_query_data(device_t dev, uint32_t qid, uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t *data)
3449e88711fSEmmanuel Vadot {
3459e88711fSEmmanuel Vadot struct zynqmp_firmware_softc *sc;
3469e88711fSEmmanuel Vadot int rv;
3479e88711fSEmmanuel Vadot
3489e88711fSEmmanuel Vadot sc = device_get_softc(dev);
3499e88711fSEmmanuel Vadot rv = zynqmp_call_smc(PM_QUERY_DATA, qid, arg1, arg2, arg3, data, true);
3509e88711fSEmmanuel Vadot /*
3519e88711fSEmmanuel Vadot * PM_QID_CLOCK_GET_NAME always success and if the clock name couldn't
3529e88711fSEmmanuel Vadot * be found the clock name will be all null byte
3539e88711fSEmmanuel Vadot */
3549e88711fSEmmanuel Vadot if (qid == 1)
3559e88711fSEmmanuel Vadot rv = 0;
3569e88711fSEmmanuel Vadot if (rv != 0)
3579e88711fSEmmanuel Vadot device_printf(sc->dev, "SMC Call fail %d\n", rv);
3589e88711fSEmmanuel Vadot return (rv);
3599e88711fSEmmanuel Vadot }
3609e88711fSEmmanuel Vadot
3619e88711fSEmmanuel Vadot static int
zynqmp_firmware_reset_assert(device_t dev,uint32_t resetid,bool enable)3629e88711fSEmmanuel Vadot zynqmp_firmware_reset_assert(device_t dev, uint32_t resetid, bool enable)
3639e88711fSEmmanuel Vadot {
3649e88711fSEmmanuel Vadot struct zynqmp_firmware_softc *sc;
3659e88711fSEmmanuel Vadot int rv;
3669e88711fSEmmanuel Vadot
3679e88711fSEmmanuel Vadot sc = device_get_softc(dev);
3689e88711fSEmmanuel Vadot rv = zynqmp_call_smc(PM_RESET_ASSERT, resetid, enable, 0, 0, NULL, true);
3699e88711fSEmmanuel Vadot if (rv != 0)
3709e88711fSEmmanuel Vadot device_printf(sc->dev, "SMC Call fail %d\n", rv);
3719e88711fSEmmanuel Vadot
3729e88711fSEmmanuel Vadot return (rv);
3739e88711fSEmmanuel Vadot }
3749e88711fSEmmanuel Vadot
3759e88711fSEmmanuel Vadot static int
zynqmp_firmware_reset_get_status(device_t dev,uint32_t resetid,bool * status)3769e88711fSEmmanuel Vadot zynqmp_firmware_reset_get_status(device_t dev, uint32_t resetid, bool *status)
3779e88711fSEmmanuel Vadot {
3789e88711fSEmmanuel Vadot struct zynqmp_firmware_softc *sc;
3799e88711fSEmmanuel Vadot uint32_t payload[4];
3809e88711fSEmmanuel Vadot int rv;
3819e88711fSEmmanuel Vadot
3829e88711fSEmmanuel Vadot sc = device_get_softc(dev);
3839e88711fSEmmanuel Vadot rv = zynqmp_call_smc(PM_RESET_GET_STATUS, resetid, 0, 0, 0, payload, true);
3849e88711fSEmmanuel Vadot if (rv != 0) {
3859e88711fSEmmanuel Vadot device_printf(sc->dev, "SMC Call fail %d\n", rv);
3869e88711fSEmmanuel Vadot return (rv);
3879e88711fSEmmanuel Vadot }
3889e88711fSEmmanuel Vadot *status = payload[1];
3899e88711fSEmmanuel Vadot
3909e88711fSEmmanuel Vadot return (rv);
3919e88711fSEmmanuel Vadot }
3929e88711fSEmmanuel Vadot
3939e88711fSEmmanuel Vadot /* Simplebus methods */
3949e88711fSEmmanuel Vadot static struct simplebus_devinfo *
zynqmp_firmware_setup_dinfo(device_t dev,phandle_t node,struct simplebus_devinfo * di)3959e88711fSEmmanuel Vadot zynqmp_firmware_setup_dinfo(device_t dev, phandle_t node,
3969e88711fSEmmanuel Vadot struct simplebus_devinfo *di)
3979e88711fSEmmanuel Vadot {
3989e88711fSEmmanuel Vadot struct simplebus_softc *sc;
3999e88711fSEmmanuel Vadot struct simplebus_devinfo *ndi;
4009e88711fSEmmanuel Vadot
4019e88711fSEmmanuel Vadot sc = device_get_softc(dev);
4029e88711fSEmmanuel Vadot if (di == NULL)
4039e88711fSEmmanuel Vadot ndi = malloc(sizeof(*ndi), M_DEVBUF, M_WAITOK | M_ZERO);
4049e88711fSEmmanuel Vadot else
4059e88711fSEmmanuel Vadot ndi = di;
4069e88711fSEmmanuel Vadot if (ofw_bus_gen_setup_devinfo(&ndi->obdinfo, node) != 0) {
4079e88711fSEmmanuel Vadot if (di == NULL)
4089e88711fSEmmanuel Vadot free(ndi, M_DEVBUF);
4099e88711fSEmmanuel Vadot return (NULL);
4109e88711fSEmmanuel Vadot }
4119e88711fSEmmanuel Vadot
4129e88711fSEmmanuel Vadot /* reg resources is from the parent but interrupts is on the node itself */
4139e88711fSEmmanuel Vadot resource_list_init(&ndi->rl);
4149e88711fSEmmanuel Vadot ofw_bus_reg_to_rl(dev, OF_parent(node), sc->acells, sc->scells, &ndi->rl);
4159e88711fSEmmanuel Vadot ofw_bus_intr_to_rl(dev, node, &ndi->rl, NULL);
4169e88711fSEmmanuel Vadot
4179e88711fSEmmanuel Vadot return (ndi);
4189e88711fSEmmanuel Vadot }
4199e88711fSEmmanuel Vadot
4209e88711fSEmmanuel 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)4219e88711fSEmmanuel Vadot zynqmp_firmware_add_device(device_t dev, phandle_t node, u_int order,
4229e88711fSEmmanuel Vadot const char *name, int unit, struct simplebus_devinfo *di)
4239e88711fSEmmanuel Vadot {
4249e88711fSEmmanuel Vadot struct simplebus_devinfo *ndi;
4259e88711fSEmmanuel Vadot device_t cdev;
4269e88711fSEmmanuel Vadot
4279e88711fSEmmanuel Vadot if ((ndi = zynqmp_firmware_setup_dinfo(dev, node, di)) == NULL)
4289e88711fSEmmanuel Vadot return (NULL);
4299e88711fSEmmanuel Vadot cdev = device_add_child_ordered(dev, order, name, unit);
4309e88711fSEmmanuel Vadot if (cdev == NULL) {
4319e88711fSEmmanuel Vadot device_printf(dev, "<%s>: device_add_child failed\n",
4329e88711fSEmmanuel Vadot ndi->obdinfo.obd_name);
4339e88711fSEmmanuel Vadot resource_list_free(&ndi->rl);
4349e88711fSEmmanuel Vadot ofw_bus_gen_destroy_devinfo(&ndi->obdinfo);
4359e88711fSEmmanuel Vadot if (di == NULL)
4369e88711fSEmmanuel Vadot free(ndi, M_DEVBUF);
4379e88711fSEmmanuel Vadot return (NULL);
4389e88711fSEmmanuel Vadot }
4399e88711fSEmmanuel Vadot device_set_ivars(cdev, ndi);
4409e88711fSEmmanuel Vadot
4419e88711fSEmmanuel Vadot return(cdev);
4429e88711fSEmmanuel Vadot }
4439e88711fSEmmanuel Vadot
4449e88711fSEmmanuel Vadot static int
zynqmp_firmware_probe(device_t dev)4459e88711fSEmmanuel Vadot zynqmp_firmware_probe(device_t dev)
4469e88711fSEmmanuel Vadot {
4479e88711fSEmmanuel Vadot
4489e88711fSEmmanuel Vadot if (!ofw_bus_status_okay(dev))
4499e88711fSEmmanuel Vadot return (ENXIO);
4509e88711fSEmmanuel Vadot if (!ofw_bus_is_compatible(dev, "xlnx,zynqmp-firmware"))
4519e88711fSEmmanuel Vadot return (ENXIO);
4529e88711fSEmmanuel Vadot device_set_desc(dev, "ZynqMP Firmware");
4539e88711fSEmmanuel Vadot return (0);
4549e88711fSEmmanuel Vadot }
4559e88711fSEmmanuel Vadot
4569e88711fSEmmanuel Vadot static int
zynqmp_firmware_attach(device_t dev)4579e88711fSEmmanuel Vadot zynqmp_firmware_attach(device_t dev)
4589e88711fSEmmanuel Vadot {
4599e88711fSEmmanuel Vadot struct zynqmp_firmware_softc *sc;
4609e88711fSEmmanuel Vadot phandle_t node, child;
4619e88711fSEmmanuel Vadot device_t cdev;
4629e88711fSEmmanuel Vadot
4639e88711fSEmmanuel Vadot sc = device_get_softc(dev);
4649e88711fSEmmanuel Vadot sc->dev = dev;
4659e88711fSEmmanuel Vadot
4669e88711fSEmmanuel Vadot if (bootverbose) {
4679e88711fSEmmanuel Vadot zynqmp_get_api_version(sc);
4689e88711fSEmmanuel Vadot zynqmp_get_chipid(sc);
4699e88711fSEmmanuel Vadot zynqmp_get_trustzone_version(sc);
4709e88711fSEmmanuel Vadot }
4719e88711fSEmmanuel Vadot
4729e88711fSEmmanuel Vadot /* Attach children */
4739e88711fSEmmanuel Vadot node = ofw_bus_get_node(dev);
4749e88711fSEmmanuel Vadot for (child = OF_child(node); child != 0; child = OF_peer(child)) {
4759e88711fSEmmanuel Vadot cdev = zynqmp_firmware_add_device(dev, child, 0, NULL, -1, NULL);
4769e88711fSEmmanuel Vadot if (cdev != NULL)
4779e88711fSEmmanuel Vadot device_probe_and_attach(cdev);
4789e88711fSEmmanuel Vadot }
4799e88711fSEmmanuel Vadot
4809e88711fSEmmanuel Vadot return (bus_generic_attach(dev));
4819e88711fSEmmanuel Vadot }
4829e88711fSEmmanuel Vadot
4839e88711fSEmmanuel Vadot static device_method_t zynqmp_firmware_methods[] = {
4849e88711fSEmmanuel Vadot /* device_if */
4859e88711fSEmmanuel Vadot DEVMETHOD(device_probe, zynqmp_firmware_probe),
4869e88711fSEmmanuel Vadot DEVMETHOD(device_attach, zynqmp_firmware_attach),
4879e88711fSEmmanuel Vadot
4889e88711fSEmmanuel Vadot /* zynqmp_firmware_if */
4899e88711fSEmmanuel Vadot DEVMETHOD(zynqmp_firmware_clock_enable, zynqmp_firmware_clock_enable),
4909e88711fSEmmanuel Vadot DEVMETHOD(zynqmp_firmware_clock_disable, zynqmp_firmware_clock_disable),
4919e88711fSEmmanuel Vadot DEVMETHOD(zynqmp_firmware_clock_getstate, zynqmp_firmware_clock_getstate),
4929e88711fSEmmanuel Vadot DEVMETHOD(zynqmp_firmware_clock_setdivider, zynqmp_firmware_clock_setdivider),
4939e88711fSEmmanuel Vadot DEVMETHOD(zynqmp_firmware_clock_getdivider, zynqmp_firmware_clock_getdivider),
4949e88711fSEmmanuel Vadot DEVMETHOD(zynqmp_firmware_clock_setparent, zynqmp_firmware_clock_setparent),
4959e88711fSEmmanuel Vadot DEVMETHOD(zynqmp_firmware_clock_getparent, zynqmp_firmware_clock_getparent),
4969e88711fSEmmanuel Vadot DEVMETHOD(zynqmp_firmware_pll_get_mode, zynqmp_firmware_pll_get_mode),
4979e88711fSEmmanuel Vadot DEVMETHOD(zynqmp_firmware_pll_get_frac_data, zynqmp_firmware_pll_get_frac_data),
4989e88711fSEmmanuel Vadot DEVMETHOD(zynqmp_firmware_clock_get_fixedfactor, zynqmp_firmware_clock_get_fixedfactor),
4999e88711fSEmmanuel Vadot DEVMETHOD(zynqmp_firmware_query_data, zynqmp_firmware_query_data),
5009e88711fSEmmanuel Vadot DEVMETHOD(zynqmp_firmware_reset_assert, zynqmp_firmware_reset_assert),
5019e88711fSEmmanuel Vadot DEVMETHOD(zynqmp_firmware_reset_get_status, zynqmp_firmware_reset_get_status),
5029e88711fSEmmanuel Vadot
5039e88711fSEmmanuel Vadot DEVMETHOD_END
5049e88711fSEmmanuel Vadot };
5059e88711fSEmmanuel Vadot
5069e88711fSEmmanuel Vadot DEFINE_CLASS_1(zynqmp_firmware, zynqmp_firmware_driver, zynqmp_firmware_methods,
5079e88711fSEmmanuel Vadot sizeof(struct zynqmp_firmware_softc), simplebus_driver);
5089e88711fSEmmanuel Vadot
5099e88711fSEmmanuel Vadot EARLY_DRIVER_MODULE(zynqmp_firmware, simplebus, zynqmp_firmware_driver, 0, 0,
5109e88711fSEmmanuel Vadot BUS_PASS_BUS + BUS_PASS_ORDER_LATE);
5119e88711fSEmmanuel Vadot MODULE_VERSION(zynqmp_firmware, 1);
512