diff --git a/sys/arm/qualcomm/qcom_scm_legacy.c b/sys/arm/qualcomm/qcom_scm_legacy.c index 24c62c8181c3..e1c375c922af 100644 --- a/sys/arm/qualcomm/qcom_scm_legacy.c +++ b/sys/arm/qualcomm/qcom_scm_legacy.c @@ -1,86 +1,86 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2021 Adrian Chadd * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "opt_platform.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * Set the cold boot address for (later) a mask of CPUs. * * Don't set it for CPU0, that CPU is the boot CPU and is already alive. * * For now it sets it on CPU1..3. * * This works on the IPQ4019 as tested; the retval is 0x0. */ uint32_t qcom_scm_legacy_mp_set_cold_boot_address(vm_offset_t mp_entry_func) { struct arm_smccc_res res; int ret; int context_id; uint32_t scm_arg0 = QCOM_SCM_LEGACY_ATOMIC_ID(QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_ADDR, 2); uint32_t scm_arg1 = QCOM_SCM_FLAG_COLDBOOT_CPU1 | QCOM_SCM_FLAG_COLDBOOT_CPU2 | QCOM_SCM_FLAG_COLDBOOT_CPU3; uint32_t scm_arg2 = pmap_kextract((vm_offset_t)mp_entry_func); - ret = arm_smccc_smc(scm_arg0, (uint32_t) &context_id, scm_arg1, - scm_arg2, 0, 0, 0, 0, &res); + ret = arm_smccc_invoke_smc(scm_arg0, (uint32_t) &context_id, scm_arg1, + scm_arg2, &res); if (ret == 0 && res.a0 == 0) return (0); printf("%s: called; error; ret=0x%08x; retval[0]=0x%08x\n", __func__, ret, res.a0); return (0); } diff --git a/sys/arm64/nvidia/tegra210/tegra210_pmc.c b/sys/arm64/nvidia/tegra210/tegra210_pmc.c index 5ae5c0e8092c..85c01d7ce7d6 100644 --- a/sys/arm64/nvidia/tegra210/tegra210_pmc.c +++ b/sys/arm64/nvidia/tegra210/tegra210_pmc.c @@ -1,625 +1,625 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright 2020 Michal Meloun * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define PMC_CNTRL 0x000 #define PMC_CNTRL_SHUTDOWN_OE (1 << 22) #define PMC_CNTRL_CPUPWRGOOD_SEL_MASK (0x3 << 20) #define PMC_CNTRL_CPUPWRGOOD_SEL_SHIFT 20 #define PMC_CNTRL_CPUPWRGOOD_EN (1 << 19) #define PMC_CNTRL_FUSE_OVERRIDE (1 << 18) #define PMC_CNTRL_INTR_POLARITY (1 << 17) #define PMC_CNTRL_CPU_PWRREQ_OE (1 << 16) #define PMC_CNTRL_CPU_PWRREQ_POLARITY (1 << 15) #define PMC_CNTRL_SIDE_EFFECT_LP0 (1 << 14) #define PMC_CNTRL_AOINIT (1 << 13) #define PMC_CNTRL_PWRGATE_DIS (1 << 12) #define PMC_CNTRL_SYSCLK_OE (1 << 11) #define PMC_CNTRL_SYSCLK_POLARITY (1 << 10) #define PMC_CNTRL_PWRREQ_OE (1 << 9) #define PMC_CNTRL_PWRREQ_POLARITY (1 << 8) #define PMC_CNTRL_BLINK_EN (1 << 7) #define PMC_CNTRL_GLITCHDET_DIS (1 << 6) #define PMC_CNTRL_LATCHWAKE_EN (1 << 5) #define PMC_CNTRL_MAIN_RST (1 << 4) #define PMC_CNTRL_KBC_RST (1 << 3) #define PMC_CNTRL_RTC_RST (1 << 2) #define PMC_CNTRL_RTC_CLK_DIS (1 << 1) #define PMC_CNTRL_KBC_CLK_DIS (1 << 0) #define PMC_DPD_SAMPLE 0x020 #define PMC_CLAMP_STATUS 0x02C #define PMC_CLAMP_STATUS_PARTID(x) (1 << ((x) & 0x1F)) #define PMC_PWRGATE_TOGGLE 0x030 #define PMC_PWRGATE_TOGGLE_START (1 << 8) #define PMC_PWRGATE_TOGGLE_PARTID(x) (((x) & 0x1F) << 0) #define PMC_REMOVE_CLAMPING_CMD 0x034 #define PMC_REMOVE_CLAMPING_CMD_PARTID(x) (1 << ((x) & 0x1F)) #define PMC_PWRGATE_STATUS 0x038 #define PMC_PWRGATE_STATUS_PARTID(x) (1 << ((x) & 0x1F)) #define PMC_SCRATCH0 0x050 #define PMC_SCRATCH0_MODE_RECOVERY (1 << 31) #define PMC_SCRATCH0_MODE_BOOTLOADER (1 << 30) #define PMC_SCRATCH0_MODE_RCM (1 << 1) #define PMC_SCRATCH0_MODE_MASK (PMC_SCRATCH0_MODE_RECOVERY | \ PMC_SCRATCH0_MODE_BOOTLOADER | \ PMC_SCRATCH0_MODE_RCM) #define PMC_CPUPWRGOOD_TIMER 0x0c8 #define PMC_CPUPWROFF_TIMER 0x0cc #define PMC_SCRATCH41 0x140 #define PMC_SENSOR_CTRL 0x1b0 #define PMC_SENSOR_CTRL_BLOCK_SCRATCH_WRITE (1 << 2) #define PMC_SENSOR_CTRL_ENABLE_RST (1 << 1) #define PMC_SENSOR_CTRL_ENABLE_PG (1 << 0) #define PMC_IO_DPD_REQ 0x1b8 #define PMC_IO_DPD_REQ_CODE_IDLE (0 << 30) #define PMC_IO_DPD_REQ_CODE_OFF (1 << 30) #define PMC_IO_DPD_REQ_CODE_ON (2 << 30) #define PMC_IO_DPD_REQ_CODE_MASK (3 << 30) #define PMC_IO_DPD_STATUS 0x1bc #define PMC_IO_DPD_STATUS_HDMI (1 << 28) #define PMC_IO_DPD2_REQ 0x1c0 #define PMC_IO_DPD2_STATUS 0x1c4 #define PMC_IO_DPD2_STATUS_HV (1 << 6) #define PMC_SEL_DPD_TIM 0x1c8 #define PMC_SCRATCH54 0x258 #define PMC_SCRATCH54_DATA_SHIFT 8 #define PMC_SCRATCH54_ADDR_SHIFT 0 #define PMC_SCRATCH55 0x25c #define PMC_SCRATCH55_RST_ENABLE (1 << 31) #define PMC_SCRATCH55_CNTRL_TYPE (1 << 30) #define PMC_SCRATCH55_CNTRL_ID_SHIFT 27 #define PMC_SCRATCH55_CNTRL_ID_MASK 0x07 #define PMC_SCRATCH55_PINMUX_SHIFT 24 #define PMC_SCRATCH55_PINMUX_MASK 0x07 #define PMC_SCRATCH55_CHECKSUM_SHIFT 16 #define PMC_SCRATCH55_CHECKSUM_MASK 0xFF #define PMC_SCRATCH55_16BITOP (1 << 15) #define PMC_SCRATCH55_I2CSLV1_SHIFT 0 #define PMC_SCRATCH55_I2CSLV1_MASK 0x7F #define PMC_GPU_RG_CNTRL 0x2d4 /* Secure access */ #define PMC_SMC 0xc2fffe00 #define PMC_SMC_READ 0xaa #define PMC_SMC_WRITE 0xbb #define PMC_LOCK(_sc) mtx_lock(&(_sc)->mtx) #define PMC_UNLOCK(_sc) mtx_unlock(&(_sc)->mtx) #define PMC_LOCK_INIT(_sc) mtx_init(&(_sc)->mtx, \ device_get_nameunit(_sc->dev), "tegra210_pmc", MTX_DEF) #define PMC_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->mtx); #define PMC_ASSERT_LOCKED(_sc) mtx_assert(&(_sc)->mtx, MA_OWNED); #define PMC_ASSERT_UNLOCKED(_sc) mtx_assert(&(_sc)->mtx, MA_NOTOWNED); struct tegra210_pmc_softc { device_t dev; struct resource *mem_res; clk_t clk; struct mtx mtx; bool secure_access; uint32_t rate; enum tegra_suspend_mode suspend_mode; uint32_t cpu_good_time; uint32_t cpu_off_time; uint32_t core_osc_time; uint32_t core_pmu_time; uint32_t core_off_time; int corereq_high; int sysclkreq_high; int combined_req; int cpu_pwr_good_en; uint32_t lp0_vec_phys; uint32_t lp0_vec_size; }; static struct ofw_compat_data compat_data[] = { {"nvidia,tegra210-pmc", 1}, {NULL, 0}, }; static struct tegra210_pmc_softc *pmc_sc; static inline struct tegra210_pmc_softc * tegra210_pmc_get_sc(void) { if (pmc_sc == NULL) panic("To early call to Tegra PMC driver.\n"); return (pmc_sc); } static void WR4(struct tegra210_pmc_softc *sc, bus_size_t r, uint32_t v) { struct arm_smccc_res res; if (sc->secure_access) { - arm_smccc_smc(PMC_SMC, PMC_SMC_WRITE, r, v, 0, 0, 0, 0, &res); + arm_smccc_invoke_smc(PMC_SMC, PMC_SMC_WRITE, r, v, &res); if (res.a0 != 0) device_printf(sc->dev," PMC SMC write failed: %lu\n", res.a0); } bus_write_4(sc->mem_res, r, v); } static uint32_t RD4(struct tegra210_pmc_softc *sc, bus_size_t r) { struct arm_smccc_res res; if (sc->secure_access) { - arm_smccc_smc(PMC_SMC, PMC_SMC_READ, r, 0, 0, 0, 0, 0, &res); + arm_smccc_invoke_smc(PMC_SMC, PMC_SMC_READ, r, &res); if (res.a0 != 0) device_printf(sc->dev," PMC SMC write failed: %lu\n", res.a0); return((uint32_t)res.a1); } return(bus_read_4(sc->mem_res, r)); } static int tegra210_pmc_set_powergate(struct tegra210_pmc_softc *sc, enum tegra_powergate_id id, int ena) { uint32_t reg; int i; PMC_LOCK(sc); reg = RD4(sc, PMC_PWRGATE_STATUS) & PMC_PWRGATE_STATUS_PARTID(id); if (((reg != 0) && ena) || ((reg == 0) && !ena)) { PMC_UNLOCK(sc); return (0); } for (i = 100; i > 0; i--) { reg = RD4(sc, PMC_PWRGATE_TOGGLE); if ((reg & PMC_PWRGATE_TOGGLE_START) == 0) break; DELAY(1); } if (i <= 0) device_printf(sc->dev, "Timeout when waiting for TOGGLE_START\n"); WR4(sc, PMC_PWRGATE_TOGGLE, PMC_PWRGATE_TOGGLE_START | PMC_PWRGATE_TOGGLE_PARTID(id)); for (i = 100; i > 0; i--) { reg = RD4(sc, PMC_PWRGATE_TOGGLE); if ((reg & PMC_PWRGATE_TOGGLE_START) == 0) break; DELAY(1); } if (i <= 0) device_printf(sc->dev, "Timeout when waiting for TOGGLE_START\n"); PMC_UNLOCK(sc); return (0); } int tegra_powergate_remove_clamping(enum tegra_powergate_id id) { struct tegra210_pmc_softc *sc; uint32_t reg; enum tegra_powergate_id swid; int i; sc = tegra210_pmc_get_sc(); if (id == TEGRA_POWERGATE_3D) { WR4(sc, PMC_GPU_RG_CNTRL, 0); return (0); } reg = RD4(sc, PMC_PWRGATE_STATUS); if ((reg & PMC_PWRGATE_STATUS_PARTID(id)) == 0) panic("Attempt to remove clamping for unpowered partition.\n"); if (id == TEGRA_POWERGATE_PCX) swid = TEGRA_POWERGATE_VDE; else if (id == TEGRA_POWERGATE_VDE) swid = TEGRA_POWERGATE_PCX; else swid = id; WR4(sc, PMC_REMOVE_CLAMPING_CMD, PMC_REMOVE_CLAMPING_CMD_PARTID(swid)); for (i = 100; i > 0; i--) { reg = RD4(sc, PMC_REMOVE_CLAMPING_CMD); if ((reg & PMC_REMOVE_CLAMPING_CMD_PARTID(swid)) == 0) break; DELAY(1); } if (i <= 0) device_printf(sc->dev, "Timeout when remove clamping\n"); reg = RD4(sc, PMC_CLAMP_STATUS); if ((reg & PMC_CLAMP_STATUS_PARTID(id)) != 0) panic("Cannot remove clamping\n"); return (0); } int tegra_powergate_is_powered(enum tegra_powergate_id id) { struct tegra210_pmc_softc *sc; uint32_t reg; sc = tegra210_pmc_get_sc(); reg = RD4(sc, PMC_PWRGATE_STATUS); return ((reg & PMC_PWRGATE_STATUS_PARTID(id)) ? 1 : 0); } int tegra_powergate_power_on(enum tegra_powergate_id id) { struct tegra210_pmc_softc *sc; int rv, i; sc = tegra210_pmc_get_sc(); rv = tegra210_pmc_set_powergate(sc, id, 1); if (rv != 0) { device_printf(sc->dev, "Cannot set powergate: %d\n", id); return (rv); } for (i = 100; i > 0; i--) { if (tegra_powergate_is_powered(id)) break; DELAY(1); } if (i <= 0) { device_printf(sc->dev, "Timeout when waiting on power up\n"); return(ETIMEDOUT); } return (rv); } int tegra_powergate_power_off(enum tegra_powergate_id id) { struct tegra210_pmc_softc *sc; int rv, i; sc = tegra210_pmc_get_sc(); rv = tegra210_pmc_set_powergate(sc, id, 0); if (rv != 0) { device_printf(sc->dev, "Cannot set powergate: %d\n", id); return (rv); } for (i = 100; i > 0; i--) { if (!tegra_powergate_is_powered(id)) break; DELAY(1); } if (i <= 0) device_printf(sc->dev, "Timeout when waiting on power off\n"); return (rv); } int tegra_powergate_sequence_power_up(enum tegra_powergate_id id, clk_t clk, hwreset_t rst) { struct tegra210_pmc_softc *sc; int rv; sc = tegra210_pmc_get_sc(); rv = hwreset_assert(rst); if (rv != 0) { device_printf(sc->dev, "Cannot assert reset\n"); return (rv); } rv = clk_stop(clk); if (rv != 0) { device_printf(sc->dev, "Cannot stop clock\n"); goto clk_fail; } rv = tegra_powergate_power_on(id); if (rv != 0) { device_printf(sc->dev, "Cannot power on powergate\n"); goto clk_fail; } rv = clk_enable(clk); if (rv != 0) { device_printf(sc->dev, "Cannot enable clock\n"); goto clk_fail; } DELAY(20); rv = tegra_powergate_remove_clamping(id); if (rv != 0) { device_printf(sc->dev, "Cannot remove clamping\n"); goto fail; } rv = hwreset_deassert(rst); if (rv != 0) { device_printf(sc->dev, "Cannot unreset reset\n"); goto fail; } return 0; fail: clk_disable(clk); clk_fail: hwreset_assert(rst); tegra_powergate_power_off(id); return (rv); } static int tegra210_pmc_parse_fdt(struct tegra210_pmc_softc *sc, phandle_t node) { int rv; uint32_t tmp; uint32_t tmparr[2]; rv = OF_getencprop(node, "nvidia,suspend-mode", &tmp, sizeof(tmp)); if (rv > 0) { switch (tmp) { case 0: sc->suspend_mode = TEGRA_SUSPEND_LP0; break; case 1: sc->suspend_mode = TEGRA_SUSPEND_LP1; break; case 2: sc->suspend_mode = TEGRA_SUSPEND_LP2; break; default: sc->suspend_mode = TEGRA_SUSPEND_NONE; break; } } rv = OF_getencprop(node, "nvidia,cpu-pwr-good-time", &tmp, sizeof(tmp)); if (rv > 0) { sc->cpu_good_time = tmp; sc->suspend_mode = TEGRA_SUSPEND_NONE; } rv = OF_getencprop(node, "nvidia,cpu-pwr-off-time", &tmp, sizeof(tmp)); if (rv > 0) { sc->cpu_off_time = tmp; sc->suspend_mode = TEGRA_SUSPEND_NONE; } rv = OF_getencprop(node, "nvidia,core-pwr-good-time", tmparr, sizeof(tmparr)); if (rv == sizeof(tmparr)) { sc->core_osc_time = tmparr[0]; sc->core_pmu_time = tmparr[1]; sc->suspend_mode = TEGRA_SUSPEND_NONE; } rv = OF_getencprop(node, "nvidia,core-pwr-off-time", &tmp, sizeof(tmp)); if (rv > 0) { sc->core_off_time = tmp; sc->suspend_mode = TEGRA_SUSPEND_NONE; } sc->corereq_high = OF_hasprop(node, "nvidia,core-power-req-active-high"); sc->sysclkreq_high = OF_hasprop(node, "nvidia,sys-clock-req-active-high"); sc->combined_req = OF_hasprop(node, "nvidia,combined-power-req"); sc->cpu_pwr_good_en = OF_hasprop(node, "nvidia,cpu-pwr-good-en"); rv = OF_getencprop(node, "nvidia,lp0-vec", tmparr, sizeof(tmparr)); if (rv == sizeof(tmparr)) { sc->lp0_vec_phys = tmparr[0]; sc->core_pmu_time = tmparr[1]; sc->lp0_vec_size = TEGRA_SUSPEND_NONE; if (sc->suspend_mode == TEGRA_SUSPEND_LP0) sc->suspend_mode = TEGRA_SUSPEND_LP1; } return 0; } static void tegra210_pmc_check_secure(struct tegra210_pmc_softc *sc) { uint32_t orig; sc->secure_access = false; /* * If PMC is coverd by secure trust zone, all reads returns 0, * Use scratch0 register acvcess test */ orig = RD4(sc, PMC_SCRATCH0); WR4(sc, PMC_SCRATCH0, 0xDEADBEEF); if (RD4(sc, PMC_SCRATCH0) == 0) { sc->secure_access = true; return; } WR4(sc, PMC_SCRATCH0, 0xBADC0DE); if (RD4(sc, PMC_SCRATCH0) == 0) { sc->secure_access = true; return; } WR4(sc, PMC_SCRATCH0, orig); } static int tegra210_pmc_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) return (ENXIO); device_set_desc(dev, "Tegra PMC"); return (BUS_PROBE_DEFAULT); } static int tegra210_pmc_detach(device_t dev) { /* This device is always present. */ return (EBUSY); } static int tegra210_pmc_attach(device_t dev) { struct tegra210_pmc_softc *sc; int rid, rv; uint32_t reg; phandle_t node; sc = device_get_softc(dev); sc->dev = dev; node = ofw_bus_get_node(dev); PMC_LOCK_INIT(sc); rv = tegra210_pmc_parse_fdt(sc, node); if (rv != 0) { device_printf(sc->dev, "Cannot parse FDT data\n"); return (rv); } rv = clk_get_by_ofw_name(sc->dev, 0, "pclk", &sc->clk); if (rv != 0) { device_printf(sc->dev, "Cannot get \"pclk\" clock\n"); return (ENXIO); } rid = 0; sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->mem_res == NULL) { device_printf(dev, "Cannot allocate memory resources\n"); return (ENXIO); } tegra210_pmc_check_secure(sc); /* Enable CPU power request. */ reg = RD4(sc, PMC_CNTRL); reg |= PMC_CNTRL_CPU_PWRREQ_OE; WR4(sc, PMC_CNTRL, reg); /* Set sysclk output polarity */ reg = RD4(sc, PMC_CNTRL); if (sc->sysclkreq_high) reg &= ~PMC_CNTRL_SYSCLK_POLARITY; else reg |= PMC_CNTRL_SYSCLK_POLARITY; WR4(sc, PMC_CNTRL, reg); /* Enable sysclk request. */ reg = RD4(sc, PMC_CNTRL); reg |= PMC_CNTRL_SYSCLK_OE; WR4(sc, PMC_CNTRL, reg); /* * Remove HDMI from deep power down mode. * XXX mote this to HDMI driver */ reg = RD4(sc, PMC_IO_DPD_STATUS); reg &= ~ PMC_IO_DPD_STATUS_HDMI; WR4(sc, PMC_IO_DPD_STATUS, reg); reg = RD4(sc, PMC_IO_DPD2_STATUS); reg &= ~ PMC_IO_DPD2_STATUS_HV; WR4(sc, PMC_IO_DPD2_STATUS, reg); if (pmc_sc != NULL) panic("tegra210_pmc: double driver attach"); pmc_sc = sc; return (0); } static device_method_t tegra210_pmc_methods[] = { /* Device interface */ DEVMETHOD(device_probe, tegra210_pmc_probe), DEVMETHOD(device_attach, tegra210_pmc_attach), DEVMETHOD(device_detach, tegra210_pmc_detach), DEVMETHOD_END }; static DEFINE_CLASS_0(pmc, tegra210_pmc_driver, tegra210_pmc_methods, sizeof(struct tegra210_pmc_softc)); EARLY_DRIVER_MODULE(tegra210_pmc, simplebus, tegra210_pmc_driver, NULL, NULL, 70); diff --git a/sys/dev/firmware/xilinx/zynqmp_firmware.c b/sys/dev/firmware/xilinx/zynqmp_firmware.c index 8ee6c9a21377..a6b55a3528a1 100644 --- a/sys/dev/firmware/xilinx/zynqmp_firmware.c +++ b/sys/dev/firmware/xilinx/zynqmp_firmware.c @@ -1,511 +1,511 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2023 Beckhoff Automation GmbH & Co. KG * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "zynqmp_firmware_if.h" enum { IOCTL_GET_RPU_OPER_MODE = 0, IOCTL_SET_RPU_OPER_MODE = 1, IOCTL_RPU_BOOT_ADDR_CONFIG = 2, IOCTL_TCM_COMB_CONFIG = 3, IOCTL_SET_TAPDELAY_BYPASS = 4, IOCTL_SET_SGMII_MODE = 5, IOCTL_SD_DLL_RESET = 6, IOCTL_SET_SD_TAPDELAY = 7, /* Ioctl for clock driver */ IOCTL_SET_PLL_FRAC_MODE = 8, IOCTL_GET_PLL_FRAC_MODE = 9, IOCTL_SET_PLL_FRAC_DATA = 10, IOCTL_GET_PLL_FRAC_DATA = 11, IOCTL_WRITE_GGS = 12, IOCTL_READ_GGS = 13, IOCTL_WRITE_PGGS = 14, IOCTL_READ_PGGS = 15, /* IOCTL for ULPI reset */ IOCTL_ULPI_RESET = 16, /* Set healthy bit value */ IOCTL_SET_BOOT_HEALTH_STATUS = 17, IOCTL_AFI = 18, /* Probe counter read/write */ IOCTL_PROBE_COUNTER_READ = 19, IOCTL_PROBE_COUNTER_WRITE = 20, IOCTL_OSPI_MUX_SELECT = 21, /* IOCTL for USB power request */ IOCTL_USB_SET_STATE = 22, /* IOCTL to get last reset reason */ IOCTL_GET_LAST_RESET_REASON = 23, /* AI engine NPI ISR clear */ IOCTL_AIE_ISR_CLEAR = 24, /* Register SGI to ATF */ IOCTL_REGISTER_SGI = 25, }; typedef int (*zynqmp_callfn_t)(register_t, register_t, register_t, uint32_t *payload); struct zynqmp_firmware_softc { struct simplebus_softc sc; device_t dev; zynqmp_callfn_t callfn; }; /* SMC calling methods */ #define PM_SIP_SVC 0xC2000000 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) { struct arm_smccc_res res; uint64_t args[3]; args[0] = id | PM_SIP_SVC; args[1] = ((uint64_t)a1 << 32) | a0; args[2] = ((uint64_t)a3 << 32) | a2; - arm_smccc_smc(args[0], args[1], args[2], 0, 0, 0, 0, 0, &res); + arm_smccc_invoke_smc(args[0], args[1], args[2], &res); if (payload != NULL) { payload[0] = res.a0 & 0xFFFFFFFF; payload[1] = res.a0 >> 32; payload[2] = res.a1 & 0xFFFFFFFF; payload[3] = res.a1 >> 32; if (!ignore_error && payload[0] != PM_RET_SUCCESS) { printf("%s: fail %x\n", __func__, payload[0]); return (EINVAL); } } return (0); } /* Firmware methods */ static int zynqmp_get_api_version(struct zynqmp_firmware_softc *sc) { uint32_t payload[4]; int rv; rv = zynqmp_call_smc(PM_GET_API_VERSION, 0, 0, 0, 0, payload, false); if (rv != 0) { device_printf(sc->dev, "SMC Call fail %d\n", rv); goto out; } device_printf(sc->dev, "API version = %d.%d\n", payload[1] >> 16, payload[1] & 0xFFFF); out: return (rv); } static int zynqmp_get_chipid(struct zynqmp_firmware_softc *sc) { uint32_t payload[4]; int rv; rv = zynqmp_call_smc(PM_GET_CHIPID, 0, 0, 0, 0, payload, false); if (rv != 0) { device_printf(sc->dev, "SMC Call fail %d\n", rv); goto out; } device_printf(sc->dev, "ID Code = %x Version = %x\n", payload[1], payload[2]); out: return (rv); } static int zynqmp_get_trustzone_version(struct zynqmp_firmware_softc *sc) { uint32_t payload[4]; int rv; rv = zynqmp_call_smc(PM_GET_TRUSTZONE_VERSION, 0, 0, 0, 0, payload, false); if (rv != 0) { device_printf(sc->dev, "SMC Call fail %d\n", rv); goto out; } device_printf(sc->dev, "Trustzone Version = %x\n", payload[1]); out: return (rv); } /* zynqmp_firmware methods */ static int zynqmp_firmware_clock_enable(device_t dev, uint32_t clkid) { struct zynqmp_firmware_softc *sc; uint32_t payload[4]; int rv; sc = device_get_softc(dev); rv = zynqmp_call_smc(PM_CLOCK_ENABLE, clkid, 0, 0, 0, payload, false); if (rv != 0) device_printf(sc->dev, "SMC Call fail %d\n", rv); return (rv); } static int zynqmp_firmware_clock_disable(device_t dev, uint32_t clkid) { struct zynqmp_firmware_softc *sc; uint32_t payload[4]; int rv; sc = device_get_softc(dev); rv = zynqmp_call_smc(PM_CLOCK_DISABLE, clkid, 0, 0, 0, payload, false); if (rv != 0) device_printf(sc->dev, "SMC Call fail %d\n", rv); return (rv); } static int zynqmp_firmware_clock_getstate(device_t dev, uint32_t clkid, bool *enabled) { struct zynqmp_firmware_softc *sc; uint32_t payload[4]; int rv; sc = device_get_softc(dev); rv = zynqmp_call_smc(PM_CLOCK_GETSTATE, clkid, 0, 0, 0, payload, false); if (rv != 0) { device_printf(sc->dev, "SMC Call fail %d\n", rv); goto out; } *enabled = payload[1] == 1 ? true : false; out: return (rv); } static int zynqmp_firmware_clock_setdivider(device_t dev, uint32_t clkid, uint32_t div) { struct zynqmp_firmware_softc *sc; uint32_t payload[4]; int rv; sc = device_get_softc(dev); rv = zynqmp_call_smc(PM_CLOCK_SETDIVIDER, clkid, div, 0, 0, payload, false); if (rv != 0) device_printf(sc->dev, "SMC Call fail %d\n", rv); return (rv); } static int zynqmp_firmware_clock_getdivider(device_t dev, uint32_t clkid, uint32_t *div) { struct zynqmp_firmware_softc *sc; uint32_t payload[4]; int rv; sc = device_get_softc(dev); rv = zynqmp_call_smc(PM_CLOCK_GETDIVIDER, clkid, 0, 0, 0, payload, false); if (rv != 0) { device_printf(sc->dev, "SMC Call fail %d\n", rv); goto out; } *div = payload[1]; out: return (rv); } static int zynqmp_firmware_clock_setparent(device_t dev, uint32_t clkid, uint32_t parentid) { struct zynqmp_firmware_softc *sc; uint32_t payload[4]; int rv; sc = device_get_softc(dev); rv = zynqmp_call_smc(PM_CLOCK_SETPARENT, clkid, parentid, 0, 0, payload, false); if (rv != 0) device_printf(sc->dev, "SMC Call fail %d\n", rv); return (rv); } static int zynqmp_firmware_clock_getparent(device_t dev, uint32_t clkid, uint32_t *parentid) { struct zynqmp_firmware_softc *sc; uint32_t payload[4]; int rv; sc = device_get_softc(dev); rv = zynqmp_call_smc(PM_CLOCK_GETPARENT, clkid, 0, 0, 0, payload, false); if (rv != 0) { device_printf(sc->dev, "SMC Call fail %d\n", rv); goto out; } *parentid = payload[1]; out: return (rv); } static int zynqmp_firmware_pll_get_mode(device_t dev, uint32_t pllid, uint32_t *mode) { struct zynqmp_firmware_softc *sc; uint32_t payload[4]; int rv; sc = device_get_softc(dev); rv = zynqmp_call_smc(PM_IOCTL, 0, IOCTL_GET_PLL_FRAC_MODE, pllid, 0, payload, false); if (rv != 0) { device_printf(sc->dev, "SMC Call fail %d\n", rv); goto out; } *mode = payload[1]; out: return (rv); } static int zynqmp_firmware_pll_get_frac_data(device_t dev, uint32_t pllid, uint32_t *data) { struct zynqmp_firmware_softc *sc; uint32_t payload[4]; int rv; sc = device_get_softc(dev); rv = zynqmp_call_smc(PM_IOCTL, 0, IOCTL_GET_PLL_FRAC_DATA, pllid, 0, payload, false); if (rv != 0) { device_printf(sc->dev, "SMC Call fail %d\n", rv); goto out; } *data = payload[1]; out: return (rv); } static int zynqmp_firmware_clock_get_fixedfactor(device_t dev, uint32_t clkid, uint32_t *mult, uint32_t *div) { struct zynqmp_firmware_softc *sc; uint32_t payload[4]; int rv; sc = device_get_softc(dev); rv = zynqmp_call_smc(PM_QUERY_DATA, PM_QID_CLOCK_GET_FIXEDFACTOR_PARAMS, clkid, 0, 0, payload, true); if (rv != 0) { device_printf(sc->dev, "SMC Call fail %d\n", rv); goto out; } *mult = payload[1]; *div = payload[2]; out: return (rv); } static int zynqmp_firmware_query_data(device_t dev, uint32_t qid, uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t *data) { struct zynqmp_firmware_softc *sc; int rv; sc = device_get_softc(dev); rv = zynqmp_call_smc(PM_QUERY_DATA, qid, arg1, arg2, arg3, data, true); /* * PM_QID_CLOCK_GET_NAME always success and if the clock name couldn't * be found the clock name will be all null byte */ if (qid == 1) rv = 0; if (rv != 0) device_printf(sc->dev, "SMC Call fail %d\n", rv); return (rv); } static int zynqmp_firmware_reset_assert(device_t dev, uint32_t resetid, bool enable) { struct zynqmp_firmware_softc *sc; int rv; sc = device_get_softc(dev); rv = zynqmp_call_smc(PM_RESET_ASSERT, resetid, enable, 0, 0, NULL, true); if (rv != 0) device_printf(sc->dev, "SMC Call fail %d\n", rv); return (rv); } static int zynqmp_firmware_reset_get_status(device_t dev, uint32_t resetid, bool *status) { struct zynqmp_firmware_softc *sc; uint32_t payload[4]; int rv; sc = device_get_softc(dev); rv = zynqmp_call_smc(PM_RESET_GET_STATUS, resetid, 0, 0, 0, payload, true); if (rv != 0) { device_printf(sc->dev, "SMC Call fail %d\n", rv); return (rv); } *status = payload[1]; return (rv); } /* Simplebus methods */ static struct simplebus_devinfo * zynqmp_firmware_setup_dinfo(device_t dev, phandle_t node, struct simplebus_devinfo *di) { struct simplebus_softc *sc; struct simplebus_devinfo *ndi; sc = device_get_softc(dev); if (di == NULL) ndi = malloc(sizeof(*ndi), M_DEVBUF, M_WAITOK | M_ZERO); else ndi = di; if (ofw_bus_gen_setup_devinfo(&ndi->obdinfo, node) != 0) { if (di == NULL) free(ndi, M_DEVBUF); return (NULL); } /* reg resources is from the parent but interrupts is on the node itself */ resource_list_init(&ndi->rl); ofw_bus_reg_to_rl(dev, OF_parent(node), sc->acells, sc->scells, &ndi->rl); ofw_bus_intr_to_rl(dev, node, &ndi->rl, NULL); return (ndi); } 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) { struct simplebus_devinfo *ndi; device_t cdev; if ((ndi = zynqmp_firmware_setup_dinfo(dev, node, di)) == NULL) return (NULL); cdev = device_add_child_ordered(dev, order, name, unit); if (cdev == NULL) { device_printf(dev, "<%s>: device_add_child failed\n", ndi->obdinfo.obd_name); resource_list_free(&ndi->rl); ofw_bus_gen_destroy_devinfo(&ndi->obdinfo); if (di == NULL) free(ndi, M_DEVBUF); return (NULL); } device_set_ivars(cdev, ndi); return(cdev); } static int zynqmp_firmware_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (!ofw_bus_is_compatible(dev, "xlnx,zynqmp-firmware")) return (ENXIO); device_set_desc(dev, "ZynqMP Firmware"); return (0); } static int zynqmp_firmware_attach(device_t dev) { struct zynqmp_firmware_softc *sc; phandle_t node, child; device_t cdev; sc = device_get_softc(dev); sc->dev = dev; if (bootverbose) { zynqmp_get_api_version(sc); zynqmp_get_chipid(sc); zynqmp_get_trustzone_version(sc); } /* Attach children */ node = ofw_bus_get_node(dev); for (child = OF_child(node); child != 0; child = OF_peer(child)) { cdev = zynqmp_firmware_add_device(dev, child, 0, NULL, -1, NULL); if (cdev != NULL) device_probe_and_attach(cdev); } return (bus_generic_attach(dev)); } static device_method_t zynqmp_firmware_methods[] = { /* device_if */ DEVMETHOD(device_probe, zynqmp_firmware_probe), DEVMETHOD(device_attach, zynqmp_firmware_attach), /* zynqmp_firmware_if */ DEVMETHOD(zynqmp_firmware_clock_enable, zynqmp_firmware_clock_enable), DEVMETHOD(zynqmp_firmware_clock_disable, zynqmp_firmware_clock_disable), DEVMETHOD(zynqmp_firmware_clock_getstate, zynqmp_firmware_clock_getstate), DEVMETHOD(zynqmp_firmware_clock_setdivider, zynqmp_firmware_clock_setdivider), DEVMETHOD(zynqmp_firmware_clock_getdivider, zynqmp_firmware_clock_getdivider), DEVMETHOD(zynqmp_firmware_clock_setparent, zynqmp_firmware_clock_setparent), DEVMETHOD(zynqmp_firmware_clock_getparent, zynqmp_firmware_clock_getparent), DEVMETHOD(zynqmp_firmware_pll_get_mode, zynqmp_firmware_pll_get_mode), DEVMETHOD(zynqmp_firmware_pll_get_frac_data, zynqmp_firmware_pll_get_frac_data), DEVMETHOD(zynqmp_firmware_clock_get_fixedfactor, zynqmp_firmware_clock_get_fixedfactor), DEVMETHOD(zynqmp_firmware_query_data, zynqmp_firmware_query_data), DEVMETHOD(zynqmp_firmware_reset_assert, zynqmp_firmware_reset_assert), DEVMETHOD(zynqmp_firmware_reset_get_status, zynqmp_firmware_reset_get_status), DEVMETHOD_END }; DEFINE_CLASS_1(zynqmp_firmware, zynqmp_firmware_driver, zynqmp_firmware_methods, sizeof(struct zynqmp_firmware_softc), simplebus_driver); EARLY_DRIVER_MODULE(zynqmp_firmware, simplebus, zynqmp_firmware_driver, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_LATE); MODULE_VERSION(zynqmp_firmware, 1); diff --git a/sys/dev/hyperv/vmbus/aarch64/hyperv_machdep.c b/sys/dev/hyperv/vmbus/aarch64/hyperv_machdep.c index dbb6aac2de31..e808cc081535 100644 --- a/sys/dev/hyperv/vmbus/aarch64/hyperv_machdep.c +++ b/sys/dev/hyperv/vmbus/aarch64/hyperv_machdep.c @@ -1,102 +1,101 @@ /*- SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2016-2017,2022 Microsoft Corp. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice unmodified, this list of conditions, and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #define HVCALL_SET_VP_REGISTERS 0x0051 #define HVCALL_GET_VP_REGISTERS 0x0050 #define BIT(A) (1 << (A)) #define HV_HYPERCALL_FAST_BIT BIT(16) #define BIT_ULL(a) (1ULL << (a)) #define HV_HYPERCALL_REP_COMP_1 BIT_ULL(32) #define HV_PARTITION_ID_SELF ((u64)-1) #define HV_VP_INDEX_SELF ((u32)-2) #define HV_SMCCC_FUNC_NUMBER 1 #define HV_FUNC_ID \ SMCCC_FUNC_ID(SMCCC_YIELDING_CALL, SMCCC_64BIT_CALL, \ SMCCC_VENDOR_HYP_SERVICE_CALLS, HV_SMCCC_FUNC_NUMBER) void arm_hv_set_vreg(u32 msr, u64 value) { - arm_smccc_hvc(HV_FUNC_ID, + arm_smccc_invoke_hvc(HV_FUNC_ID, HVCALL_SET_VP_REGISTERS | HV_HYPERCALL_FAST_BIT | HV_HYPERCALL_REP_COMP_1, - HV_PARTITION_ID_SELF, HV_VP_INDEX_SELF, msr, 0, value, 0, NULL); + HV_PARTITION_ID_SELF, HV_VP_INDEX_SELF, msr, 0, value, NULL); } void hv_get_vpreg_128(u32 msr, struct hv_get_vp_registers_output *result) { struct arm_smccc_1_2_regs args; struct arm_smccc_1_2_regs res; args.a0 = HV_FUNC_ID; args.a1 = HVCALL_GET_VP_REGISTERS | HV_HYPERCALL_FAST_BIT | HV_HYPERCALL_REP_COMP_1; args.a2 = HV_PARTITION_ID_SELF; args.a3 = HV_VP_INDEX_SELF; args.a4 = msr; /* * Use the SMCCC 1.2 interface because the results are in registers * beyond X0-X3. */ arm_smccc_1_2_hvc(&args, &res); result->as64.low = res.a6; result->as64.high = res.a7; } u64 arm_hv_get_vreg(u32 msr) { struct hv_get_vp_registers_output output; hv_get_vpreg_128(msr, &output); return (output.as64.low); } uint64_t hypercall_md(volatile void *hc_addr, uint64_t in_val, uint64_t in_paddr, uint64_t out_paddr) { struct arm_smccc_res res; - arm_smccc_hvc(HV_FUNC_ID, in_val, in_paddr, out_paddr, 0, 0, 0, 0, - &res); + arm_smccc_invoke_hvc(HV_FUNC_ID, in_val, in_paddr, out_paddr, &res); return (res.a0); } diff --git a/sys/dev/pci/pci_host_generic_den0115.c b/sys/dev/pci/pci_host_generic_den0115.c index cfef34824965..a14fe84039fe 100644 --- a/sys/dev/pci/pci_host_generic_den0115.c +++ b/sys/dev/pci/pci_host_generic_den0115.c @@ -1,261 +1,259 @@ /*- * Copyright (c) 2022 Andrew Turner * Copyright (c) 2023 Arm Ltd * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pcib_if.h" static device_probe_t pci_host_acpi_smccc_probe; static device_attach_t pci_host_acpi_smccc_attach; static pcib_read_config_t pci_host_acpi_smccc_read_config; static pcib_write_config_t pci_host_acpi_smccc_write_config; static bool pci_host_acpi_smccc_pci_version(uint32_t *); static int pci_host_acpi_smccc_probe(device_t dev) { ACPI_DEVICE_INFO *devinfo; struct resource *res; ACPI_HANDLE h; int rid, root; if (acpi_disabled("pcib") || (h = acpi_get_handle(dev)) == NULL || ACPI_FAILURE(AcpiGetObjectInfo(h, &devinfo))) return (ENXIO); root = (devinfo->Flags & ACPI_PCI_ROOT_BRIDGE) != 0; AcpiOsFree(devinfo); if (!root) return (ENXIO); /* * Check if we have memory resources. We may have a non-memory * mapped device, e.g. using the Arm PCI Configuration Space * Access Firmware Interface (DEN0115). */ rid = 0; res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 0); if (res != NULL) { bus_release_resource(dev, SYS_RES_MEMORY, rid, res); return (ENXIO); } /* Check for the PCI_VERSION call */ if (!pci_host_acpi_smccc_pci_version(NULL)) { return (ENXIO); } device_set_desc(dev, "ARM PCI Firmware config space host controller"); return (BUS_PROBE_SPECIFIC); } #define SMCCC_PCI_VERSION \ SMCCC_FUNC_ID(SMCCC_FAST_CALL, SMCCC_32BIT_CALL, \ SMCCC_STD_SECURE_SERVICE_CALLS, 0x130) #define SMCCC_PCI_FEATURES \ SMCCC_FUNC_ID(SMCCC_FAST_CALL, SMCCC_32BIT_CALL, \ SMCCC_STD_SECURE_SERVICE_CALLS, 0x131) #define SMCCC_PCI_READ \ SMCCC_FUNC_ID(SMCCC_FAST_CALL, SMCCC_32BIT_CALL, \ SMCCC_STD_SECURE_SERVICE_CALLS, 0x132) #define SMCCC_PCI_WRITE \ SMCCC_FUNC_ID(SMCCC_FAST_CALL, SMCCC_32BIT_CALL, \ SMCCC_STD_SECURE_SERVICE_CALLS, 0x133) #define SMCCC_PCI_GET_SEG_INFO \ SMCCC_FUNC_ID(SMCCC_FAST_CALL, SMCCC_32BIT_CALL, \ SMCCC_STD_SECURE_SERVICE_CALLS, 0x134) CTASSERT(SMCCC_PCI_VERSION == 0x84000130); CTASSERT(SMCCC_PCI_FEATURES == 0x84000131); CTASSERT(SMCCC_PCI_READ == 0x84000132); CTASSERT(SMCCC_PCI_WRITE == 0x84000133); CTASSERT(SMCCC_PCI_GET_SEG_INFO == 0x84000134); #define SMCCC_PCI_MAJOR(x) (((x) >> 16) & 0x7fff) #define SMCCC_PCI_MINOR(x) ((x) & 0xffff) #define SMCCC_PCI_SEG_END(x) (((x) >> 8) & 0xff) #define SMCCC_PCI_SEG_START(x) ((x) & 0xff) static bool pci_host_acpi_smccc_has_feature(uint32_t pci_func_id) { struct arm_smccc_res result; - if (psci_callfn(SMCCC_PCI_FEATURES, pci_func_id, 0, 0, 0, 0, 0, 0, - &result) < 0) { + if (arm_smccc_invoke(SMCCC_PCI_FEATURES, pci_func_id, &result) < 0) { return (false); } return (true); } static bool pci_host_acpi_smccc_pci_version(uint32_t *versionp) { struct arm_smccc_res result; - if (psci_callfn(SMCCC_PCI_VERSION, 0, 0, 0, 0, 0, 0, 0, &result) < 0) { + if (arm_smccc_invoke(SMCCC_PCI_VERSION, &result) < 0) { return (false); } if (versionp != NULL) { *versionp = result.a0; } return (true); } static int pci_host_acpi_smccc_attach(device_t dev) { struct generic_pcie_acpi_softc *sc; struct arm_smccc_res result; uint32_t version; int end, start; int error; sc = device_get_softc(dev); sc->base.quirks |= PCIE_CUSTOM_CONFIG_SPACE_QUIRK; MPASS(psci_callfn != NULL); /* Read the version */ if (!pci_host_acpi_smccc_pci_version(&version)) { device_printf(dev, "Failed to read the SMCCC PCI version\n"); return (ENXIO); } if (bootverbose) { device_printf(dev, "Firmware v%d.%d\n", SMCCC_PCI_MAJOR(version), SMCCC_PCI_MINOR(version)); } if (!pci_host_acpi_smccc_has_feature(SMCCC_PCI_READ) || !pci_host_acpi_smccc_has_feature(SMCCC_PCI_WRITE)) { device_printf(dev, "Missing read/write functions\n"); return (ENXIO); } error = pci_host_generic_acpi_init(dev); if (error != 0) return (error); if (pci_host_acpi_smccc_has_feature(SMCCC_PCI_GET_SEG_INFO) && - psci_callfn(SMCCC_PCI_GET_SEG_INFO, sc->base.ecam, 0, 0, 0, 0, 0, - 0, &result) == SMCCC_RET_SUCCESS) { + arm_smccc_invoke(SMCCC_PCI_GET_SEG_INFO, sc->base.ecam, + &result) == SMCCC_RET_SUCCESS) { start = SMCCC_PCI_SEG_START(result.a1); end = SMCCC_PCI_SEG_END(result.a1); sc->base.bus_start = MAX(sc->base.bus_start, start); sc->base.bus_end = MIN(sc->base.bus_end, end); } device_add_child(dev, "pci", -1); return (bus_generic_attach(dev)); } static uint32_t pci_host_acpi_smccc_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, int bytes) { struct generic_pcie_acpi_softc *sc; struct arm_smccc_res result; uint32_t addr; sc = device_get_softc(dev); if ((bus < sc->base.bus_start) || (bus > sc->base.bus_end)) return (~0U); if ((slot > PCI_SLOTMAX) || (func > PCI_FUNCMAX) || (reg > PCIE_REGMAX)) return (~0U); addr = (sc->base.ecam << 16) | (bus << 8) | (slot << 3) | (func << 0); - if (psci_callfn(SMCCC_PCI_READ, addr, reg, bytes, 0, 0, 0, 0, - &result) < 0) { + if (arm_smccc_invoke(SMCCC_PCI_READ, addr, reg, bytes, &result) < 0) { return (~0U); } return (result.a1); } static void pci_host_acpi_smccc_write_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, uint32_t val, int bytes) { struct generic_pcie_acpi_softc *sc; struct arm_smccc_res result; uint32_t addr; sc = device_get_softc(dev); if ((bus < sc->base.bus_start) || (bus > sc->base.bus_end)) return; if ((slot > PCI_SLOTMAX) || (func > PCI_FUNCMAX) || (reg > PCIE_REGMAX)) return; addr = (sc->base.ecam << 16) | (bus << 8) | (slot << 3) | (func << 0); - psci_callfn(SMCCC_PCI_WRITE, addr, reg, bytes, val, 0, 0, 0, &result); + arm_smccc_invoke(SMCCC_PCI_WRITE, addr, reg, bytes, val, &result); } static device_method_t generic_pcie_acpi_smccc_methods[] = { DEVMETHOD(device_probe, pci_host_acpi_smccc_probe), DEVMETHOD(device_attach, pci_host_acpi_smccc_attach), /* pcib interface */ DEVMETHOD(pcib_read_config, pci_host_acpi_smccc_read_config), DEVMETHOD(pcib_write_config, pci_host_acpi_smccc_write_config), DEVMETHOD_END }; DEFINE_CLASS_1(pcib, generic_pcie_acpi_smccc_driver, generic_pcie_acpi_smccc_methods, sizeof(struct generic_pcie_acpi_softc), generic_pcie_acpi_driver); DRIVER_MODULE(pcib_smccc, acpi, generic_pcie_acpi_smccc_driver, 0, 0); diff --git a/sys/dev/psci/smccc.c b/sys/dev/psci/smccc.c index 5c5e140abab1..e8a367bed7d6 100644 --- a/sys/dev/psci/smccc.c +++ b/sys/dev/psci/smccc.c @@ -1,105 +1,105 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2018 Andrew Turner * * This software was developed by SRI International and the University of * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237 * ("CTSRD"), as part of the DARPA CRASH research programme. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "opt_acpi.h" #include "opt_platform.h" #include #include #include #include #include #include #define SMCCC_VERSION_1_0 0x10000 /* Assume 1.0 until we detect a later version */ static uint32_t smccc_version = SMCCC_VERSION_1_0; void smccc_init(void) { int32_t features; uint32_t ret; features = psci_features(SMCCC_VERSION); if (features != PSCI_RETVAL_NOT_SUPPORTED) { ret = psci_call(SMCCC_VERSION, 0, 0, 0); /* This should always be the case as we checked it above */ if (ret > 0) smccc_version = ret; } if (bootverbose) { printf("Found SMCCC version %u.%u\n", SMCCC_VERSION_MAJOR(smccc_version), SMCCC_VERSION_MINOR(smccc_version)); } } uint32_t smccc_get_version(void) { return (smccc_version); } int32_t smccc_arch_features(uint32_t smccc_func_id) { if (smccc_version == SMCCC_VERSION_1_0) return (PSCI_RETVAL_NOT_SUPPORTED); - return (psci_call(SMCCC_ARCH_FEATURES, smccc_func_id, 0, 0)); + return (arm_smccc_invoke(SMCCC_ARCH_FEATURES, smccc_func_id, NULL)); } /* * The SMCCC handler for Spectre variant 2: Branch target injection. * (CVE-2017-5715) */ int smccc_arch_workaround_1(void) { KASSERT(smccc_version != SMCCC_VERSION_1_0, ("SMCCC arch workaround 1 called with an invalid SMCCC interface")); - return (psci_call(SMCCC_ARCH_WORKAROUND_1, 0, 0, 0)); + return (arm_smccc_invoke(SMCCC_ARCH_WORKAROUND_1, NULL)); } int smccc_arch_workaround_2(int enable) { KASSERT(smccc_version != SMCCC_VERSION_1_0, ("SMCCC arch workaround 2 called with an invalid SMCCC interface")); - return (psci_call(SMCCC_ARCH_WORKAROUND_2, enable, 0, 0)); + return (arm_smccc_invoke(SMCCC_ARCH_WORKAROUND_2, enable, NULL)); }