summaryrefslogtreecommitdiff
path: root/drivers/reset/ast2500-reset.c
diff options
context:
space:
mode:
authormaxims@google.com <maxims@google.com>2017-04-17 12:00:24 -0700
committerTom Rini <trini@konsulko.com>2017-05-08 11:57:32 -0400
commit858d4976293f0b3d72e5dcf0e8a1a973efafeee3 (patch)
tree0921e2d6c21f12fa567b631e9f664e18fc6dd4ed /drivers/reset/ast2500-reset.c
parent413353b30b5d23c409b6a2fd70aa1cc28451a451 (diff)
aspeed: Reset Driver
Add Reset Driver for ast2500 SoC. This driver uses Watchdog Timer to perform resets and thus depends on it. The actual Watchdog device used needs to be configured in Device Tree using "aspeed,wdt" property, which must be WDT phandle, for example: rst: reset-controller { compatible = "aspeed,ast2500-reset"; aspeed,wdt = <&wdt1>; } Signed-off-by: Maxim Sloyko <maxims@google.com> Reviewed-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'drivers/reset/ast2500-reset.c')
-rw-r--r--drivers/reset/ast2500-reset.c106
1 files changed, 106 insertions, 0 deletions
diff --git a/drivers/reset/ast2500-reset.c b/drivers/reset/ast2500-reset.c
new file mode 100644
index 0000000000..b2c89e1f1e
--- /dev/null
+++ b/drivers/reset/ast2500-reset.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2017 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <misc.h>
+#include <reset.h>
+#include <reset-uclass.h>
+#include <wdt.h>
+#include <asm/io.h>
+#include <asm/arch/scu_ast2500.h>
+#include <asm/arch/wdt.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct ast2500_reset_priv {
+ /* WDT used to perform resets. */
+ struct udevice *wdt;
+ struct ast2500_scu *scu;
+};
+
+static int ast2500_ofdata_to_platdata(struct udevice *dev)
+{
+ struct ast2500_reset_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = uclass_get_device_by_phandle(UCLASS_WDT, dev, "aspeed,wdt",
+ &priv->wdt);
+ if (ret) {
+ debug("%s: can't find WDT for reset controller", __func__);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ast2500_reset_assert(struct reset_ctl *reset_ctl)
+{
+ struct ast2500_reset_priv *priv = dev_get_priv(reset_ctl->dev);
+ u32 reset_mode, reset_mask;
+ bool reset_sdram;
+ int ret;
+
+ /*
+ * To reset SDRAM, a specifal flag in SYSRESET register
+ * needs to be enabled first
+ */
+ reset_mode = ast_reset_mode_from_flags(reset_ctl->id);
+ reset_mask = ast_reset_mask_from_flags(reset_ctl->id);
+ reset_sdram = reset_mode == WDT_CTRL_RESET_SOC &&
+ (reset_mask & WDT_RESET_SDRAM);
+
+ if (reset_sdram) {
+ ast_scu_unlock(priv->scu);
+ setbits_le32(&priv->scu->sysreset_ctrl1,
+ SCU_SYSRESET_SDRAM_WDT);
+ ret = wdt_expire_now(priv->wdt, reset_ctl->id);
+ clrbits_le32(&priv->scu->sysreset_ctrl1,
+ SCU_SYSRESET_SDRAM_WDT);
+ ast_scu_lock(priv->scu);
+ } else {
+ ret = wdt_expire_now(priv->wdt, reset_ctl->id);
+ }
+
+ return ret;
+}
+
+static int ast2500_reset_request(struct reset_ctl *reset_ctl)
+{
+ debug("%s(reset_ctl=%p) (dev=%p, id=%lu)\n", __func__, reset_ctl,
+ reset_ctl->dev, reset_ctl->id);
+
+ return 0;
+}
+
+static int ast2500_reset_probe(struct udevice *dev)
+{
+ struct ast2500_reset_priv *priv = dev_get_priv(dev);
+
+ priv->scu = ast_get_scu();
+
+ return 0;
+}
+
+static const struct udevice_id ast2500_reset_ids[] = {
+ { .compatible = "aspeed,ast2500-reset" },
+ { }
+};
+
+struct reset_ops ast2500_reset_ops = {
+ .rst_assert = ast2500_reset_assert,
+ .request = ast2500_reset_request,
+};
+
+U_BOOT_DRIVER(ast2500_reset) = {
+ .name = "ast2500_reset",
+ .id = UCLASS_RESET,
+ .of_match = ast2500_reset_ids,
+ .probe = ast2500_reset_probe,
+ .ops = &ast2500_reset_ops,
+ .ofdata_to_platdata = ast2500_ofdata_to_platdata,
+ .priv_auto_alloc_size = sizeof(struct ast2500_reset_priv),
+};