diff options
Diffstat (limited to 'drivers/firmware')
| -rw-r--r-- | drivers/firmware/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/firmware/firmware-zynqmp.c | 247 | ||||
| -rw-r--r-- | drivers/firmware/psci.c | 4 | ||||
| -rw-r--r-- | drivers/firmware/scmi/Kconfig | 3 | ||||
| -rw-r--r-- | drivers/firmware/scmi/scmi_agent-uclass.c | 10 |
5 files changed, 247 insertions, 19 deletions
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index 220de731950..f524f741e54 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -14,7 +14,7 @@ config ARM_PSCI_FW select FIRMWARE config TI_SCI_PROTOCOL - tristate "TI System Control Interface (TISCI) Message Protocol" + bool "TI System Control Interface (TISCI) Message Protocol" depends on K3_SEC_PROXY select DEVRES select FIRMWARE diff --git a/drivers/firmware/firmware-zynqmp.c b/drivers/firmware/firmware-zynqmp.c index fb583580ebe..fae66ccb3d8 100644 --- a/drivers/firmware/firmware-zynqmp.c +++ b/drivers/firmware/firmware-zynqmp.c @@ -3,10 +3,11 @@ * Xilinx Zynq MPSoC Firmware driver * * Copyright (C) 2018-2019 Xilinx, Inc. - * Copyright (C) 2022 - 2025, Advanced Micro Devices, Inc. + * Copyright (C) 2022 - 2026, Advanced Micro Devices, Inc. */ #include <asm/arch/hardware.h> +#include <asm/arch/sys_proto.h> #include <asm/io.h> #include <cpu_func.h> #include <dm.h> @@ -16,11 +17,12 @@ #include <zynqmp_firmware.h> #include <asm/cache.h> #include <asm/ptrace.h> +#include <asm/system.h> #include <linux/bitfield.h> +#include <linux/delay.h> #if defined(CONFIG_ZYNQMP_IPI) #include <mailbox.h> -#include <asm/arch/sys_proto.h> #define PMUFW_PAYLOAD_ARG_CNT 8 @@ -174,28 +176,158 @@ unsigned int zynqmp_firmware_version(void) }; #if defined(CONFIG_ARCH_VERSAL2) -int zynqmp_pm_ufs_get_txrx_cfgrdy(u32 *value) +/* + * Poll the M-PHY TX/RX config-ready status until it settles or @timeout_us + * elapses. Legacy EEMI firmware only offers the per-read status primitive, so + * the poll loop lives here rather than in the UFS driver; the timeout budget is + * owned by the caller. + */ +int zynqmp_pm_wait_mphy_tx_rx_config_ready(u32 timeout_us) { - *value = readl(PMXC_SLCR_BASE_ADDRESS + PMXC_TX_RX_CFG_RDY); - return 0; + u32 ret_payload[PAYLOAD_ARG_CNT]; + int ret; + + while (timeout_us--) { + ret = xilinx_pm_request(PM_IOCTL, PM_REGNODE_PMC_IOU_SLCR, + IOCTL_READ_REG, TXRX_CFGRDY_OFFSET, 0, 0, + 0, ret_payload); + if (ret) + return ret; + + if (!(ret_payload[1] & TX_RX_CFG_RDY_MASK)) + return 0; + + udelay(1); + } + + return -ETIMEDOUT; } -int zynqmp_pm_ufs_sram_csr_read(u32 *value) +int zynqmp_pm_wait_sram_init_done(u32 timeout_us) { - *value = readl(PMXC_SLCR_BASE_ADDRESS + PMXC_SRAM_CSR); - return 0; + u32 ret_payload[PAYLOAD_ARG_CNT]; + int ret; + + while (timeout_us--) { + ret = xilinx_pm_request(PM_IOCTL, PM_REGNODE_PMC_IOU_SLCR, + IOCTL_READ_REG, SRAM_CSR_OFFSET, 0, 0, + 0, ret_payload); + if (ret) + return ret; + + if (ret_payload[1] & SRAM_CSR_INIT_DONE_MASK) + return 0; + + udelay(1); + } + + return -ETIMEDOUT; } -int zynqmp_pm_ufs_sram_csr_write(u32 *value) +int zynqmp_pm_set_sram_bypass(void) { - writel(*value, PMXC_SLCR_BASE_ADDRESS + PMXC_SRAM_CSR); - return 0; + u32 ret_payload[PAYLOAD_ARG_CNT]; + u32 sram_csr; + int ret; + + ret = zynqmp_pm_is_function_supported(PM_IOCTL, IOCTL_MASK_WRITE_REG); + if (ret) { + printf("%s: IOCTL_MASK_WRITE_REG is not supported : %d\n" + , __func__, ret); + return 0; + } + + ret = xilinx_pm_request(PM_IOCTL, PM_REGNODE_PMC_IOU_SLCR, + IOCTL_READ_REG, SRAM_CSR_OFFSET, 0, 0, + 0, ret_payload); + if (ret) + return ret; + + sram_csr = ret_payload[1]; + sram_csr &= ~SRAM_CSR_EXT_LD_DONE_MASK; + sram_csr |= SRAM_CSR_BYPASS_MASK; + + return xilinx_pm_request(PM_IOCTL, PM_REGNODE_PMC_IOU_SLCR, + IOCTL_MASK_WRITE_REG, SRAM_CSR_OFFSET, + GENMASK(2, 1), sram_csr, 0, NULL); } -int zynqmp_pm_ufs_cal_reg(u32 *value) +int zynqmp_pm_get_ufs_calibration_values(u32 *value) { - *value = readl(PMXC_EFUSE_CACHE_BASE_ADDRESS + PMXC_UFS_CAL_1_OFFSET); - return 0; + u32 ret_payload[PAYLOAD_ARG_CNT]; + int ret; + + if (!value) + return -EINVAL; + + ret = zynqmp_pm_is_function_supported(PM_IOCTL, IOCTL_READ_REG); + if (ret) { + printf("%s: IOCTL_READ_REG is not supported : %d\n" + , __func__, ret); + return 0; + } + + ret = xilinx_pm_request(PM_IOCTL, PM_REGNODE_EFUSE_CACHE, + IOCTL_READ_REG, UFS_CAL_1_OFFSET, 0, 0, + 0, ret_payload); + if (ret) + return ret; + + *value = ret_payload[1]; + + return ret; +} +#endif /* CONFIG_ARCH_VERSAL2 */ + +#if defined(CONFIG_ARCH_VERSAL) || defined(CONFIG_ARCH_VERSAL2) +u32 zynqmp_pm_get_pmc_global_pggs_reg(u32 reg_addr) +{ + int ret; + u32 value = 0; + u32 ret_payload[PAYLOAD_ARG_CNT]; + + if (reg_addr == PMC_GLOBAL_PGGS3_REG) { + value = 0; + } else if (reg_addr == PMC_GLOBAL_PGGS4_REG) { + value = 1; + } else { + printf("%s: not supported pggs register 0x%x\n", + __func__, reg_addr); + return 0; + } + + ret = zynqmp_pm_is_function_supported(PM_IOCTL, IOCTL_READ_PGGS); + if (ret) { + ret = zynqmp_pm_is_function_supported(PM_IOCTL, IOCTL_READ_REG); + if (ret) { + printf("%s: IOCTL_READ_REG is not supported : %d\n" + , __func__, ret); + return 0; + } + + /* find node ID from the pggs3 offset */ + value = PM_REG_PGGS3 + value; + + ret = xilinx_pm_request(PM_IOCTL, value, + IOCTL_READ_REG, 0, 0, 0, 0, + ret_payload); + if (ret) { + printf("%s: node 0x%x get pggs register failed\n", + __func__, value); + return 0; + } + } else { + ret = xilinx_pm_request(PM_IOCTL, PMC_GLOBAL_PGGS3_REG_NODE, + IOCTL_READ_PGGS, value, 0, 0, 0, + ret_payload); + if (ret) { + printf("%s: node 0x%x get pggs register failed\n", + __func__, PMC_GLOBAL_PGGS3_REG_NODE); + return 0; + } + } + + return ret_payload[1]; } #endif @@ -274,6 +406,93 @@ u32 zynqmp_pm_get_pmc_multi_boot_reg(void) } #endif +#if defined(CONFIG_ARCH_VERSAL) +u32 versal_pmc_multi_boot(void) +{ + /* At EL3 the SMC path to firmware is unavailable, read directly */ + if (current_el() == 3) + return versal_multi_boot_reg(); + + return zynqmp_pm_get_pmc_multi_boot_reg() & PMC_MULTI_BOOT_MASK; +} + +u8 versal_get_bootmode(void) +{ + u32 reg; + + /* At EL3 the SMC path to firmware is unavailable, read directly */ + if (current_el() == 3) + reg = versal_bootmode_reg(); + else + reg = zynqmp_pm_get_bootmode_reg(); + + if (reg >> BOOT_MODE_ALT_SHIFT) + reg >>= BOOT_MODE_ALT_SHIFT; + + return reg & BOOT_MODES_MASK; +} +#endif + +#if defined(CONFIG_ARCH_VERSAL_NET) +u8 versal_net_get_bootmode(void) +{ + u32 reg; + + /* At EL3 the SMC path to firmware is unavailable, read directly */ + if (current_el() == 3) + reg = versal_net_bootmode_reg(); + else + reg = zynqmp_pm_get_bootmode_reg(); + + if (reg >> BOOT_MODE_ALT_SHIFT) + reg >>= BOOT_MODE_ALT_SHIFT; + + return reg & BOOT_MODES_MASK; +} +#endif + +#if defined(CONFIG_ARCH_ZYNQMP) +int zynqmp_mmio_write(const u32 address, const u32 mask, const u32 value) +{ + /* At EL3 or in SPL the firmware (SMC) path is unavailable */ + if (IS_ENABLED(CONFIG_XPL_BUILD) || current_el() == 3) + return zynqmp_mmio_rawwrite(address, mask, value); + + return xilinx_pm_request(PM_MMIO_WRITE, address, mask, value, + 0, 0, 0, NULL); +} + +int zynqmp_mmio_read(const u32 address, u32 *value) +{ + u32 ret_payload[PAYLOAD_ARG_CNT]; + int ret; + + if (!value) + return -EINVAL; + + /* At EL3 or in SPL the firmware (SMC) path is unavailable */ + if (IS_ENABLED(CONFIG_XPL_BUILD) || current_el() == 3) + return zynqmp_mmio_rawread(address, value); + + ret = xilinx_pm_request(PM_MMIO_READ, address, 0, 0, 0, 0, 0, + ret_payload); + *value = ret_payload[1]; + + return ret; +} +#endif + +#if defined(CONFIG_ARCH_VERSAL2) +u32 versal2_pmc_multi_boot(void) +{ + /* At EL3 the SMC path to firmware is unavailable, read directly */ + if (current_el() == 3) + return versal2_multi_boot_reg(); + + return zynqmp_pm_get_pmc_multi_boot_reg() & PMC_MULTI_BOOT_MASK; +} +#endif + int zynqmp_pm_feature(const u32 api_id) { int ret; diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c index b6838a244d2..2e3223e1c32 100644 --- a/drivers/firmware/psci.c +++ b/drivers/firmware/psci.c @@ -186,10 +186,6 @@ static int psci_bind(struct udevice *dev) NULL); if (ret) pr_debug("PSCI System Reset was not bound.\n"); - if (IS_ENABLED(CONFIG_SYSRESET_QCOM_PSCI) && - device_bind_driver(dev, "qcom_psci-sysreset", - "qcom_psci-sysreset", NULL)) - pr_debug("QCOM PSCI System Reset was not bound.\n"); } /* From PSCI v1.0 onward we can discover services through ARM_SMCCC_FEATURE */ diff --git a/drivers/firmware/scmi/Kconfig b/drivers/firmware/scmi/Kconfig index cd912ebe409..64bc9aef5af 100644 --- a/drivers/firmware/scmi/Kconfig +++ b/drivers/firmware/scmi/Kconfig @@ -46,6 +46,9 @@ config SCMI_AGENT_OPTEE config SCMI_ID_VENDOR_80 bool +config SCMI_ID_VENDOR_81 + bool + config SCMI_ID_VENDOR_82 bool diff --git a/drivers/firmware/scmi/scmi_agent-uclass.c b/drivers/firmware/scmi/scmi_agent-uclass.c index cd458a7f458..9159e59385b 100644 --- a/drivers/firmware/scmi/scmi_agent-uclass.c +++ b/drivers/firmware/scmi/scmi_agent-uclass.c @@ -116,6 +116,11 @@ struct udevice *scmi_get_protocol(struct udevice *dev, proto = priv->vendor_dev_80; break; #endif +#if IS_ENABLED(CONFIG_SCMI_ID_VENDOR_81) + case SCMI_PROTOCOL_ID_VENDOR_81: + proto = priv->vendor_dev_81; + break; +#endif #if IS_ENABLED(CONFIG_SCMI_ID_VENDOR_82) case SCMI_PROTOCOL_ID_VENDOR_82: proto = priv->vendor_dev_82; @@ -189,6 +194,11 @@ static int scmi_add_protocol(struct udevice *dev, priv->vendor_dev_80 = proto; break; #endif +#if IS_ENABLED(CONFIG_SCMI_ID_VENDOR_81) + case SCMI_PROTOCOL_ID_VENDOR_81: + priv->vendor_dev_81 = proto; + break; +#endif #if IS_ENABLED(CONFIG_SCMI_ID_VENDOR_82) case SCMI_PROTOCOL_ID_VENDOR_82: priv->vendor_dev_82 = proto; |
