summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorTom Rini <[email protected]>2025-12-19 10:30:53 -0600
committerTom Rini <[email protected]>2025-12-19 10:30:53 -0600
commit2aeaa3c4f53b11b97e2797eb3a0a7b603f60dc72 (patch)
treef815ca39666d1bb8b5be752afcf1f400695ed93b /drivers
parentadbbf5982d26801224b10cd847dc468f8b5e4095 (diff)
parent0b880fc95dbaed88dd55060730857b8f52765c57 (diff)
Merge tag 'xilinx-for-v2026.04-rc1' of https://source.denx.de/u-boot/custodians/u-boot-microblaze into next
AMD/Xilinx/FPGA changes for v2026.04-rc1 xilinx: - Sync ESRT with detected GUID - DT cleanups - Add logic for FRU information multiple times - Enable more drivers pca9541, usb5744 - Enable more commands - Cleanup firmware DT bindings firmware: - Add enhancement SMC format support clk/versal: - Various cleanups - Add support for Versal Gen 2 i2c: - cdns: Add timeout for RXDV status bit polling spi: - cadence: Remove cdns,is-dma DT property - cadence: Remove duplicated return - cadence_versal: Update flash reset delay memtop: - Update max memory reserved spaces to 64 Versal Gen 2: - Aligned addresses with default memory map - Add support for reading multiboot value MB-V: - Make SPL smaller - Add support for SPI - Move SPL to run out of BRAM ZynqMP: - Change default load address for BL32
Diffstat (limited to 'drivers')
-rw-r--r--drivers/clk/Kconfig2
-rw-r--r--drivers/clk/clk_versal.c49
-rw-r--r--drivers/firmware/firmware-zynqmp.c36
-rw-r--r--drivers/i2c/i2c-cdns.c11
-rw-r--r--drivers/spi/cadence_ospi_versal.c7
-rw-r--r--drivers/spi/cadence_qspi.c23
-rw-r--r--drivers/spi/cadence_qspi.h2
7 files changed, 104 insertions, 26 deletions
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index b884a02bdeb..85cc472b4cb 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -224,7 +224,7 @@ config CLK_VERSACLOCK
config CLK_VERSAL
bool "Enable clock driver support for Versal"
- depends on (ARCH_VERSAL || ARCH_VERSAL_NET)
+ depends on (ARCH_VERSAL || ARCH_VERSAL_NET || ARCH_VERSAL2)
depends on ZYNQMP_FIRMWARE
help
This clock driver adds support for clock realted settings for
diff --git a/drivers/clk/clk_versal.c b/drivers/clk/clk_versal.c
index c62a747036d..78a2410ca21 100644
--- a/drivers/clk/clk_versal.c
+++ b/drivers/clk/clk_versal.c
@@ -106,8 +106,8 @@ struct versal_clk_priv {
struct versal_clock *clk;
};
-static ulong pl_alt_ref_clk __section(".data");
-static ulong ref_clk __section(".data");
+static ulong __data pl_alt_ref_clk;
+static ulong __data ref_clk;
struct versal_pm_query_data {
u32 qid;
@@ -116,8 +116,8 @@ struct versal_pm_query_data {
u32 arg3;
};
-static struct versal_clock *clock __section(".data");
-static unsigned int clock_max_idx __section(".data");
+static struct versal_clock __data *clock;
+static unsigned int __data clock_max_idx;
#define PM_QUERY_DATA 35
@@ -136,6 +136,25 @@ static int versal_pm_query_legacy(struct versal_pm_query_data qdata,
return qdata.qid == PM_QID_CLOCK_GET_NAME ? 0 : ret;
}
+static int versal_pm_query_enhanced(struct versal_pm_query_data qdata,
+ u32 *ret_payload)
+{
+ int ret;
+
+ ret = smc_call_handler(PM_QUERY_DATA, qdata.qid, qdata.arg1, qdata.arg2,
+ qdata.arg3, 0, 0, ret_payload);
+
+ if (qdata.qid == PM_QID_CLOCK_GET_NAME) {
+ ret_payload[0] = ret_payload[1];
+ ret_payload[1] = ret_payload[2];
+ ret_payload[2] = ret_payload[3];
+ ret_payload[3] = ret_payload[4];
+ ret_payload[4] = 0;
+ }
+
+ return ret;
+}
+
static inline int versal_is_valid_clock(u32 clk_id)
{
if (clk_id >= clock_max_idx)
@@ -712,11 +731,12 @@ static int versal_clk_probe(struct udevice *dev)
static ulong versal_clk_get_rate(struct clk *clk)
{
struct versal_clk_priv *priv = dev_get_priv(clk->dev);
- u32 id = clk->id;
+ u32 id = clk_get_id(clk);
u32 clk_id;
u64 clk_rate = 0;
- debug("%s\n", __func__);
+ if (id >= clock_max_idx)
+ return -ENODEV;
clk_id = priv->clk[id].clk_id;
@@ -728,13 +748,14 @@ static ulong versal_clk_get_rate(struct clk *clk)
static ulong versal_clk_set_rate(struct clk *clk, ulong rate)
{
struct versal_clk_priv *priv = dev_get_priv(clk->dev);
- u32 id = clk->id;
+ u32 id = clk_get_id(clk);
u32 clk_id;
u64 clk_rate = 0;
u32 div;
int ret;
- debug("%s\n", __func__);
+ if (id >= clock_max_idx)
+ return -ENODEV;
clk_id = priv->clk[id].clk_id;
@@ -758,7 +779,7 @@ static ulong versal_clk_set_rate(struct clk *clk, ulong rate)
} while (((clk_id >> NODE_SUBCLASS_SHIFT) &
NODE_CLASS_MASK) != NODE_SUBCLASS_CLOCK_REF);
- printf("Clock didn't has Divisors:0x%x\n", priv->clk[id].clk_id);
+ printf("Clock has no divider: 0x%x\n", clk_id);
return clk_rate;
}
@@ -766,14 +787,17 @@ static ulong versal_clk_set_rate(struct clk *clk, ulong rate)
static int versal_clk_enable(struct clk *clk)
{
struct versal_clk_priv *priv = dev_get_priv(clk->dev);
+ u32 id = clk_get_id(clk);
u32 clk_id;
- clk_id = priv->clk[clk->id].clk_id;
+ if (id >= clock_max_idx)
+ return -ENODEV;
+
+ clk_id = priv->clk[id].clk_id;
- if (versal_clock_gate(clk_id)) {
+ if (versal_clock_gate(clk_id))
return xilinx_pm_request(PM_CLOCK_ENABLE, clk_id, 0, 0, 0,
0, 0, NULL);
- }
return 0;
}
@@ -789,6 +813,7 @@ static struct clk_ops versal_clk_ops = {
static const struct udevice_id versal_clk_ids[] = {
{ .compatible = "xlnx,versal-clk", .data = (ulong)versal_pm_query_legacy },
+ { .compatible = "xlnx,versal2-clk", .data = (ulong)versal_pm_query_enhanced },
{ }
};
diff --git a/drivers/firmware/firmware-zynqmp.c b/drivers/firmware/firmware-zynqmp.c
index 3742467caee..f8a9945c1da 100644
--- a/drivers/firmware/firmware-zynqmp.c
+++ b/drivers/firmware/firmware-zynqmp.c
@@ -16,6 +16,7 @@
#include <zynqmp_firmware.h>
#include <asm/cache.h>
#include <asm/ptrace.h>
+#include <linux/bitfield.h>
#if defined(CONFIG_ZYNQMP_IPI)
#include <mailbox.h>
@@ -247,6 +248,7 @@ u32 zynqmp_pm_get_bootmode_reg(void)
return ret_payload[1];
}
+#if defined(CONFIG_ARCH_VERSAL) || defined(CONFIG_ARCH_VERSAL2)
u32 zynqmp_pm_get_pmc_multi_boot_reg(void)
{
int ret;
@@ -270,6 +272,7 @@ u32 zynqmp_pm_get_pmc_multi_boot_reg(void)
return ret_payload[1];
}
+#endif
int zynqmp_pm_feature(const u32 api_id)
{
@@ -451,6 +454,38 @@ static int smc_call_legacy(u32 api_id, u32 arg0, u32 arg1, u32 arg2,
return (ret_payload) ? ret_payload[0] : 0;
}
+static int smc_call_enhanced(u32 api_id, u32 arg0, u32 arg1, u32 arg2,
+ u32 arg3, u32 arg4, u32 arg5, u32 *ret_payload)
+{
+ struct pt_regs regs;
+ u32 module_id = FIELD_GET(PLM_MODULE_ID_MASK, api_id);
+
+ if (module_id == 0)
+ module_id = PM_MODULE_ID;
+
+ regs.regs[0] = PM_SIP_SVC | PASS_THROUGH_FW_CMD_ID;
+ regs.regs[1] = ((u64)arg0 << 32U) |
+ FIELD_PREP(PLM_MODULE_ID_MASK, module_id) |
+ (api_id & API_ID_MASK);
+ regs.regs[2] = arg1 | ((u64)arg2 << 32);
+ regs.regs[3] = arg3 | ((u64)arg4 << 32);
+ regs.regs[4] = arg5;
+
+ smc_call(&regs);
+
+ if (ret_payload) {
+ ret_payload[0] = regs.regs[0];
+ ret_payload[1] = upper_32_bits(regs.regs[0]);
+ ret_payload[2] = (u32)regs.regs[1];
+ ret_payload[3] = upper_32_bits(regs.regs[1]);
+ ret_payload[4] = (u32)regs.regs[2];
+ ret_payload[5] = upper_32_bits((u32)regs.regs[2]);
+ ret_payload[6] = (u32)regs.regs[3];
+ }
+
+ return regs.regs[0];
+}
+
int __maybe_unused xilinx_pm_request(u32 api_id, u32 arg0, u32 arg1, u32 arg2,
u32 arg3, u32 arg4, u32 arg5, u32 *ret_payload)
{
@@ -494,6 +529,7 @@ static const struct udevice_id zynqmp_firmware_ids[] = {
{ .compatible = "xlnx,zynqmp-firmware", .data = (ulong)smc_call_legacy },
{ .compatible = "xlnx,versal-firmware", .data = (ulong)smc_call_legacy},
{ .compatible = "xlnx,versal-net-firmware", .data = (ulong)smc_call_legacy },
+ { .compatible = "xlnx,versal2-firmware", .data = (ulong)smc_call_enhanced},
{ }
};
diff --git a/drivers/i2c/i2c-cdns.c b/drivers/i2c/i2c-cdns.c
index 3f7cf8533ec..4e9d4e44899 100644
--- a/drivers/i2c/i2c-cdns.c
+++ b/drivers/i2c/i2c-cdns.c
@@ -85,6 +85,8 @@ struct cdns_i2c_regs {
#define CDNS_I2C_ARB_LOST_MAX_RETRIES 10
+#define CDNS_I2C_RXDV_TIMEOUT_MS 1000
+
#ifdef DEBUG
static void cdns_i2c_debug_status(struct cdns_i2c_regs *cdns_i2c)
{
@@ -349,6 +351,11 @@ static int cdns_i2c_read_data(struct i2c_cdns_bus *i2c_bus, u32 addr, u8 *data,
hold_quirk = (i2c_bus->quirks & CDNS_I2C_BROKEN_HOLD_BIT) && updatetx;
while (recv_count && !is_arbitration_lost(regs)) {
+ int err = wait_for_bit_le32(&regs->status, CDNS_I2C_STATUS_RXDV,
+ true, CDNS_I2C_RXDV_TIMEOUT_MS, false);
+ if (err)
+ return err;
+
while (readl(&regs->status) & CDNS_I2C_STATUS_RXDV) {
if (recv_count < i2c_bus->fifo_depth &&
!i2c_bus->hold_flag) {
@@ -452,6 +459,10 @@ static int cdns_i2c_xfer(struct udevice *dev, struct i2c_msg *msg,
ret = cdns_i2c_write_data(i2c_bus, msg->addr, msg->buf,
msg->len);
}
+
+ if (ret == -ETIMEDOUT)
+ return ret;
+
if (ret == -EAGAIN) {
msg = message;
nmsgs = num_msgs;
diff --git a/drivers/spi/cadence_ospi_versal.c b/drivers/spi/cadence_ospi_versal.c
index 0efbbf56a5e..a00642d09d3 100644
--- a/drivers/spi/cadence_ospi_versal.c
+++ b/drivers/spi/cadence_ospi_versal.c
@@ -15,7 +15,6 @@
#include <zynqmp_firmware.h>
#include <asm/arch/hardware.h>
#include "cadence_qspi.h"
-#include <dt-bindings/power/xlnx-versal-power.h>
int cadence_qspi_apb_dma_read(struct cadence_spi_priv *priv,
const struct spi_mem_op *op)
@@ -178,15 +177,15 @@ int cadence_qspi_flash_reset(struct udevice *dev)
/* Disable Tri-state */
writel((readl(BANK0_TRI) & ~BIT(FLASH_RESET_GPIO)), BANK0_TRI);
- udelay(1);
+ udelay(5);
/* Set value 0 to pin */
writel((readl(BANK0_OUTPUT) & ~BIT(FLASH_RESET_GPIO)), BANK0_OUTPUT);
- udelay(10);
+ udelay(150);
/* Set value 1 to pin */
writel((readl(BANK0_OUTPUT) | BIT(FLASH_RESET_GPIO)), BANK0_OUTPUT);
- udelay(10);
+ udelay(1200);
return 0;
}
diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c
index 9b45cab9c04..d1404e13810 100644
--- a/drivers/spi/cadence_qspi.c
+++ b/drivers/spi/cadence_qspi.c
@@ -20,7 +20,6 @@
#include <linux/time.h>
#include <zynqmp_firmware.h>
#include "cadence_qspi.h"
-#include <dt-bindings/power/xlnx-versal-power.h>
#define CQSPI_STIG_READ 0
#define CQSPI_STIG_WRITE 1
@@ -29,6 +28,7 @@
/* Quirks */
#define CQSPI_DISABLE_STIG_MODE BIT(0)
+#define CQSPI_DMA_MODE BIT(1)
__weak int cadence_qspi_apb_dma_read(struct cadence_spi_priv *priv,
const struct spi_mem_op *op)
@@ -210,7 +210,6 @@ static int cadence_spi_probe(struct udevice *bus)
priv->regbase = plat->regbase;
priv->ahbbase = plat->ahbbase;
- priv->is_dma = plat->is_dma;
priv->is_decoded_cs = plat->is_decoded_cs;
priv->fifo_depth = plat->fifo_depth;
priv->fifo_width = plat->fifo_width;
@@ -227,6 +226,11 @@ static int cadence_spi_probe(struct udevice *bus)
priv->tslch_ns = plat->tslch_ns;
priv->quirks = plat->quirks;
+ if (priv->quirks & CQSPI_DMA_MODE) {
+ priv->is_dma = true;
+ debug("Cadence QSPI: DMA mode enabled\n");
+ }
+
if (IS_ENABLED(CONFIG_ZYNQMP_FIRMWARE))
xilinx_pm_request(PM_REQUEST_NODE, PM_DEV_OSPI,
ZYNQMP_PM_CAPABILITY_ACCESS, ZYNQMP_PM_MAX_QOS,
@@ -265,8 +269,6 @@ static int cadence_spi_probe(struct udevice *bus)
/* Reset ospi flash device */
return cadence_qspi_flash_reset(bus);
-
- return 0;
}
static int cadence_spi_remove(struct udevice *dev)
@@ -412,8 +414,6 @@ static int cadence_spi_of_to_plat(struct udevice *bus)
if (plat->ahbsize >= SZ_8M)
priv->use_dac_mode = true;
- plat->is_dma = dev_read_bool(bus, "cdns,is-dma");
-
/* All other parameters are embedded in the child node */
subnode = cadence_qspi_get_subnode(bus);
if (!ofnode_valid(subnode)) {
@@ -473,6 +473,10 @@ static const struct cqspi_driver_platdata cdns_qspi = {
.quirks = CQSPI_DISABLE_STIG_MODE,
};
+static const struct cqspi_driver_platdata cdns_xilinx_qspi = {
+ .quirks = CQSPI_DMA_MODE,
+};
+
static const struct udevice_id cadence_spi_ids[] = {
{
.compatible = "cdns,qspi-nor",
@@ -482,7 +486,12 @@ static const struct udevice_id cadence_spi_ids[] = {
.compatible = "ti,am654-ospi"
},
{
- .compatible = "amd,versal2-ospi"
+ .compatible = "amd,versal2-ospi",
+ .data = (ulong)&cdns_xilinx_qspi,
+ },
+ {
+ .compatible = "xlnx,versal-ospi-1.0",
+ .data = (ulong)&cdns_xilinx_qspi,
},
{ }
};
diff --git a/drivers/spi/cadence_qspi.h b/drivers/spi/cadence_qspi.h
index 879e7f8dbfb..1e9081c2d17 100644
--- a/drivers/spi/cadence_qspi.h
+++ b/drivers/spi/cadence_qspi.h
@@ -223,8 +223,6 @@ struct cadence_spi_plat {
u32 tchsh_ns;
u32 tslch_ns;
u32 quirks;
-
- bool is_dma;
};
struct cadence_spi_priv {