summaryrefslogtreecommitdiff
path: root/drivers/reset
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/reset')
-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
4 files changed, 117 insertions, 0 deletions
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;
+}