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 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; 108b9cd72b0SAndrew 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 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 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 480*18250ec6SJohn Baldwin bus_attach_children(dev); 481*18250ec6SJohn Baldwin return (0); 4829e88711fSEmmanuel Vadot } 4839e88711fSEmmanuel Vadot 4849e88711fSEmmanuel Vadot static device_method_t zynqmp_firmware_methods[] = { 4859e88711fSEmmanuel Vadot /* device_if */ 4869e88711fSEmmanuel Vadot DEVMETHOD(device_probe, zynqmp_firmware_probe), 4879e88711fSEmmanuel Vadot DEVMETHOD(device_attach, zynqmp_firmware_attach), 4889e88711fSEmmanuel Vadot 4899e88711fSEmmanuel Vadot /* zynqmp_firmware_if */ 4909e88711fSEmmanuel Vadot DEVMETHOD(zynqmp_firmware_clock_enable, zynqmp_firmware_clock_enable), 4919e88711fSEmmanuel Vadot DEVMETHOD(zynqmp_firmware_clock_disable, zynqmp_firmware_clock_disable), 4929e88711fSEmmanuel Vadot DEVMETHOD(zynqmp_firmware_clock_getstate, zynqmp_firmware_clock_getstate), 4939e88711fSEmmanuel Vadot DEVMETHOD(zynqmp_firmware_clock_setdivider, zynqmp_firmware_clock_setdivider), 4949e88711fSEmmanuel Vadot DEVMETHOD(zynqmp_firmware_clock_getdivider, zynqmp_firmware_clock_getdivider), 4959e88711fSEmmanuel Vadot DEVMETHOD(zynqmp_firmware_clock_setparent, zynqmp_firmware_clock_setparent), 4969e88711fSEmmanuel Vadot DEVMETHOD(zynqmp_firmware_clock_getparent, zynqmp_firmware_clock_getparent), 4979e88711fSEmmanuel Vadot DEVMETHOD(zynqmp_firmware_pll_get_mode, zynqmp_firmware_pll_get_mode), 4989e88711fSEmmanuel Vadot DEVMETHOD(zynqmp_firmware_pll_get_frac_data, zynqmp_firmware_pll_get_frac_data), 4999e88711fSEmmanuel Vadot DEVMETHOD(zynqmp_firmware_clock_get_fixedfactor, zynqmp_firmware_clock_get_fixedfactor), 5009e88711fSEmmanuel Vadot DEVMETHOD(zynqmp_firmware_query_data, zynqmp_firmware_query_data), 5019e88711fSEmmanuel Vadot DEVMETHOD(zynqmp_firmware_reset_assert, zynqmp_firmware_reset_assert), 5029e88711fSEmmanuel Vadot DEVMETHOD(zynqmp_firmware_reset_get_status, zynqmp_firmware_reset_get_status), 5039e88711fSEmmanuel Vadot 5049e88711fSEmmanuel Vadot DEVMETHOD_END 5059e88711fSEmmanuel Vadot }; 5069e88711fSEmmanuel Vadot 5079e88711fSEmmanuel Vadot DEFINE_CLASS_1(zynqmp_firmware, zynqmp_firmware_driver, zynqmp_firmware_methods, 5089e88711fSEmmanuel Vadot sizeof(struct zynqmp_firmware_softc), simplebus_driver); 5099e88711fSEmmanuel Vadot 5109e88711fSEmmanuel Vadot EARLY_DRIVER_MODULE(zynqmp_firmware, simplebus, zynqmp_firmware_driver, 0, 0, 5119e88711fSEmmanuel Vadot BUS_PASS_BUS + BUS_PASS_ORDER_LATE); 5129e88711fSEmmanuel Vadot MODULE_VERSION(zynqmp_firmware, 1); 513