summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/firmware/firmware-zynqmp.c54
-rw-r--r--drivers/reset/reset-uclass.c34
-rw-r--r--drivers/reset/reset-zynqmp.c11
-rw-r--r--drivers/reset/sandbox-reset-test.c14
-rw-r--r--drivers/reset/sandbox-reset.c58
-rw-r--r--drivers/spi/cadence_qspi.c16
6 files changed, 174 insertions, 13 deletions
diff --git a/drivers/firmware/firmware-zynqmp.c b/drivers/firmware/firmware-zynqmp.c
index fb583580ebe..ea14ed4ef95 100644
--- a/drivers/firmware/firmware-zynqmp.c
+++ b/drivers/firmware/firmware-zynqmp.c
@@ -3,7 +3,7 @@
* 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>
@@ -197,6 +197,58 @@ int zynqmp_pm_ufs_cal_reg(u32 *value)
*value = readl(PMXC_EFUSE_CACHE_BASE_ADDRESS + PMXC_UFS_CAL_1_OFFSET);
return 0;
}
+#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
int zynqmp_pm_set_gem_config(u32 node, enum pm_gem_config_type config, u32 value)
diff --git a/drivers/reset/reset-uclass.c b/drivers/reset/reset-uclass.c
index fe4cebf54f1..c199e3e5da7 100644
--- a/drivers/reset/reset-uclass.c
+++ b/drivers/reset/reset-uclass.c
@@ -13,6 +13,7 @@
#include <reset-uclass.h>
#include <dm/devres.h>
#include <dm/lists.h>
+#include <linux/delay.h>
static inline struct reset_ops *reset_dev_ops(struct udevice *dev)
{
@@ -225,6 +226,39 @@ int reset_deassert_bulk(struct reset_ctl_bulk *bulk)
return 0;
}
+int reset_reset(struct reset_ctl *reset_ctl, ulong delay_us)
+{
+ struct reset_ops *ops = reset_dev_ops(reset_ctl->dev);
+ int ret;
+
+ debug("%s(reset_ctl=%p, delay_us=%lu)\n", __func__, reset_ctl,
+ delay_us);
+
+ if (ops->rst_reset)
+ return ops->rst_reset(reset_ctl, delay_us);
+
+ ret = reset_assert(reset_ctl);
+ if (ret < 0)
+ return ret;
+
+ udelay(delay_us);
+
+ return reset_deassert(reset_ctl);
+}
+
+int reset_reset_bulk(struct reset_ctl_bulk *bulk, ulong delay_us)
+{
+ int i, ret;
+
+ for (i = 0; i < bulk->count; i++) {
+ ret = reset_reset(&bulk->resets[i], delay_us);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
int reset_status(struct reset_ctl *reset_ctl)
{
struct reset_ops *ops = reset_dev_ops(reset_ctl->dev);
diff --git a/drivers/reset/reset-zynqmp.c b/drivers/reset/reset-zynqmp.c
index d04e8eef3bb..2b58f3a75b4 100644
--- a/drivers/reset/reset-zynqmp.c
+++ b/drivers/reset/reset-zynqmp.c
@@ -45,6 +45,16 @@ static int zynqmp_reset_deassert(struct reset_ctl *rst)
PM_RESET_ACTION_RELEASE);
}
+static int zynqmp_reset_reset(struct reset_ctl *rst, ulong delay_us)
+{
+ struct zynqmp_reset_priv *priv = dev_get_priv(rst->dev);
+
+ dev_dbg(rst->dev, "%s(rst=%p) (id=%lu)\n", __func__, rst, rst->id);
+
+ return zynqmp_pm_reset_assert(priv->reset_id + rst->id,
+ PM_RESET_ACTION_PULSE);
+}
+
static int zynqmp_reset_request(struct reset_ctl *rst)
{
struct zynqmp_reset_priv *priv = dev_get_priv(rst->dev);
@@ -74,6 +84,7 @@ const struct reset_ops zynqmp_reset_ops = {
.request = zynqmp_reset_request,
.rst_assert = zynqmp_reset_assert,
.rst_deassert = zynqmp_reset_deassert,
+ .rst_reset = zynqmp_reset_reset,
};
static const struct udevice_id zynqmp_reset_ids[] = {
diff --git a/drivers/reset/sandbox-reset-test.c b/drivers/reset/sandbox-reset-test.c
index dfacb764bc7..64c205596c5 100644
--- a/drivers/reset/sandbox-reset-test.c
+++ b/drivers/reset/sandbox-reset-test.c
@@ -96,6 +96,20 @@ int sandbox_reset_test_deassert_bulk(struct udevice *dev)
return reset_deassert_bulk(sbrt->bulkp);
}
+int sandbox_reset_test_reset(struct udevice *dev)
+{
+ struct sandbox_reset_test *sbrt = dev_get_priv(dev);
+
+ return reset_reset(sbrt->ctlp, 0);
+}
+
+int sandbox_reset_test_reset_bulk(struct udevice *dev)
+{
+ struct sandbox_reset_test *sbrt = dev_get_priv(dev);
+
+ return reset_reset_bulk(sbrt->bulkp, 0);
+}
+
int sandbox_reset_test_free(struct udevice *dev)
{
struct sandbox_reset_test *sbrt = dev_get_priv(dev);
diff --git a/drivers/reset/sandbox-reset.c b/drivers/reset/sandbox-reset.c
index 1c0ea7390df..12812f0f340 100644
--- a/drivers/reset/sandbox-reset.c
+++ b/drivers/reset/sandbox-reset.c
@@ -9,12 +9,14 @@
#include <reset-uclass.h>
#include <asm/io.h>
#include <asm/reset.h>
+#include <linux/delay.h>
#define SANDBOX_RESET_SIGNALS 101
struct sandbox_reset_signal {
bool asserted;
bool requested;
+ int reset_count;
};
struct sandbox_reset {
@@ -31,6 +33,7 @@ static int sandbox_reset_request(struct reset_ctl *reset_ctl)
return -EINVAL;
sbr->signals[reset_ctl->id].requested = true;
+ sbr->signals[reset_ctl->id].reset_count = 0;
return 0;
}
@@ -66,6 +69,21 @@ static int sandbox_reset_deassert(struct reset_ctl *reset_ctl)
return 0;
}
+static int sandbox_reset_reset(struct reset_ctl *reset_ctl, ulong delay_us)
+{
+ struct sandbox_reset *sbr = dev_get_priv(reset_ctl->dev);
+
+ debug("%s(reset_ctl=%p, delay_us=%lu)\n", __func__, reset_ctl,
+ delay_us);
+
+ sbr->signals[reset_ctl->id].asserted = true;
+ udelay(delay_us);
+ sbr->signals[reset_ctl->id].asserted = false;
+ sbr->signals[reset_ctl->id].reset_count++;
+
+ return 0;
+}
+
static int sandbox_reset_bind(struct udevice *dev)
{
debug("%s(dev=%p)\n", __func__, dev);
@@ -90,6 +108,7 @@ static const struct reset_ops sandbox_reset_reset_ops = {
.rfree = sandbox_reset_free,
.rst_assert = sandbox_reset_assert,
.rst_deassert = sandbox_reset_deassert,
+ .rst_reset = sandbox_reset_reset,
};
U_BOOT_DRIVER(sandbox_reset) = {
@@ -102,6 +121,33 @@ U_BOOT_DRIVER(sandbox_reset) = {
.ops = &sandbox_reset_reset_ops,
};
+/*
+ * Second sandbox reset controller for tests: same assert/deassert
+ * behaviour as sandbox_reset, but no rst_reset so reset_reset() uses
+ * the core assert / udelay / deassert fallback (reset_count never bumps).
+ */
+static const struct udevice_id sandbox_reset_fallback_ids[] = {
+ { .compatible = "sandbox,reset-ctl-fallback-only" },
+ { }
+};
+
+static const struct reset_ops sandbox_reset_fallback_reset_ops = {
+ .request = sandbox_reset_request,
+ .rfree = sandbox_reset_free,
+ .rst_assert = sandbox_reset_assert,
+ .rst_deassert = sandbox_reset_deassert,
+};
+
+U_BOOT_DRIVER(sandbox_reset_fallback) = {
+ .name = "sandbox_reset_fallback",
+ .id = UCLASS_RESET,
+ .of_match = sandbox_reset_fallback_ids,
+ .bind = sandbox_reset_bind,
+ .probe = sandbox_reset_probe,
+ .priv_auto = sizeof(struct sandbox_reset),
+ .ops = &sandbox_reset_fallback_reset_ops,
+};
+
int sandbox_reset_query(struct udevice *dev, unsigned long id)
{
struct sandbox_reset *sbr = dev_get_priv(dev);
@@ -125,3 +171,15 @@ int sandbox_reset_is_requested(struct udevice *dev, unsigned long id)
return sbr->signals[id].requested;
}
+
+int sandbox_reset_get_count(struct udevice *dev, unsigned long id)
+{
+ struct sandbox_reset *sbr = dev_get_priv(dev);
+
+ debug("%s(dev=%p, id=%ld)\n", __func__, dev, id);
+
+ if (id >= SANDBOX_RESET_SIGNALS)
+ return -EINVAL;
+
+ return sbr->signals[id].reset_count;
+}
diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c
index 2a4a49c5f1c..984d4a39ded 100644
--- a/drivers/spi/cadence_qspi.c
+++ b/drivers/spi/cadence_qspi.c
@@ -31,6 +31,8 @@
#define CQSPI_DISABLE_STIG_MODE BIT(0)
#define CQSPI_DMA_MODE BIT(1)
+#define CQSPI_RESET_DELAY_US 10
+
__weak int cadence_qspi_apb_dma_read(struct cadence_spi_priv *priv,
const struct spi_mem_op *op)
{
@@ -256,19 +258,9 @@ static int cadence_spi_probe(struct udevice *bus)
priv->resets = devm_reset_bulk_get_optional(bus);
if (priv->resets) {
- /* Assert all OSPI reset lines */
- ret = reset_assert_bulk(priv->resets);
- if (ret) {
- dev_err(bus, "Failed to assert OSPI reset: %d\n", ret);
- return ret;
- }
-
- udelay(10);
-
- /* Deassert all OSPI reset lines */
- ret = reset_deassert_bulk(priv->resets);
+ ret = reset_reset_bulk(priv->resets, CQSPI_RESET_DELAY_US);
if (ret) {
- dev_err(bus, "Failed to deassert OSPI reset: %d\n", ret);
+ dev_err(bus, "Failed to reset OSPI: %d\n", ret);
return ret;
}
}