reset: ast2500: Use SCU for reset control

The System Control Unit (SCU) controller of Aspeed
SoCs provides the reset control for each peripheral.

This patch refactors the reset method to leverage
the SCU reset control. Thus the driver dependency
on watchdog including dedicated WDT API and reset
flag encoding can be eliminated.

The Kconfig description is also updated accordingly.

Signed-off-by: Chia-Wei, Wang <chiawei_wang@aspeedtech.com>
Reviewed-by: Ryan Chen <ryan_chen@aspeedtech.com>
This commit is contained in:
Chia-Wei, Wang
2020-10-15 10:25:13 +08:00
committed by Tom Rini
parent fa181d1a95
commit 611a28ce27
4 changed files with 106 additions and 98 deletions

View File

@@ -74,13 +74,12 @@ config RESET_UNIPHIER
config AST2500_RESET
bool "Reset controller driver for AST2500 SoCs"
depends on DM_RESET && WDT_ASPEED
depends on DM_RESET
default y if ASPEED_AST2500
help
Support for reset controller on AST2500 SoC. This controller uses
watchdog to reset different peripherals and thus only supports
resets that are supported by watchdog. The main limitation though
is that some reset signals, like I2C or MISC reset multiple devices.
Support for reset controller on AST2500 SoC.
Say Y if you want to control reset signals of different peripherals
through System Control Unit (SCU).
config RESET_ROCKCHIP
bool "Reset controller driver for Rockchip SoCs"

View File

@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2017 Google, Inc
* Copyright 2020 ASPEED Technology Inc.
*/
#include <common.h>
@@ -9,63 +10,14 @@
#include <misc.h>
#include <reset.h>
#include <reset-uclass.h>
#include <wdt.h>
#include <linux/err.h>
#include <asm/io.h>
#include <asm/arch/scu_ast2500.h>
#include <asm/arch/wdt.h>
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,
@@ -74,11 +26,63 @@ static int ast2500_reset_request(struct reset_ctl *reset_ctl)
return 0;
}
static int ast2500_reset_free(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_assert(struct reset_ctl *reset_ctl)
{
struct ast2500_reset_priv *priv = dev_get_priv(reset_ctl->dev);
struct ast2500_scu *scu = priv->scu;
debug("%s: reset_ctl->id: %lu\n", __func__, reset_ctl->id);
if (reset_ctl->id < 32)
setbits_le32(&scu->sysreset_ctrl1, BIT(reset_ctl->id));
else
setbits_le32(&scu->sysreset_ctrl2, BIT(reset_ctl->id - 32));
return 0;
}
static int ast2500_reset_deassert(struct reset_ctl *reset_ctl)
{
struct ast2500_reset_priv *priv = dev_get_priv(reset_ctl->dev);
struct ast2500_scu *scu = priv->scu;
debug("%s: reset_ctl->id: %lu\n", __func__, reset_ctl->id);
if (reset_ctl->id < 32)
clrbits_le32(&scu->sysreset_ctrl1, BIT(reset_ctl->id));
else
clrbits_le32(&scu->sysreset_ctrl2, BIT(reset_ctl->id - 32));
return 0;
}
static int ast2500_reset_probe(struct udevice *dev)
{
int rc;
struct ast2500_reset_priv *priv = dev_get_priv(dev);
struct udevice *scu_dev;
priv->scu = ast_get_scu();
/* get SCU base from clock device */
rc = uclass_get_device_by_driver(UCLASS_CLK,
DM_GET_DRIVER(aspeed_ast2500_scu), &scu_dev);
if (rc) {
debug("%s: clock device not found, rc=%d\n", __func__, rc);
return rc;
}
priv->scu = devfdt_get_addr_ptr(scu_dev);
if (IS_ERR_OR_NULL(priv->scu)) {
debug("%s: invalid SCU base pointer\n", __func__);
return PTR_ERR(priv->scu);
}
return 0;
}
@@ -89,16 +93,17 @@ static const struct udevice_id ast2500_reset_ids[] = {
};
struct reset_ops ast2500_reset_ops = {
.rst_assert = ast2500_reset_assert,
.request = ast2500_reset_request,
.rfree = ast2500_reset_free,
.rst_assert = ast2500_reset_assert,
.rst_deassert = ast2500_reset_deassert,
};
U_BOOT_DRIVER(ast2500_reset) = {
.name = "ast2500_reset",
.id = UCLASS_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),
};