diff options
-rw-r--r-- | arch/arm/include/asm/arch-aspeed/scu_ast2500.h | 28 | ||||
-rw-r--r-- | drivers/reset/Kconfig | 10 | ||||
-rw-r--r-- | drivers/reset/Makefile | 1 | ||||
-rw-r--r-- | drivers/reset/ast2500-reset.c | 106 |
4 files changed, 145 insertions, 0 deletions
diff --git a/arch/arm/include/asm/arch-aspeed/scu_ast2500.h b/arch/arm/include/asm/arch-aspeed/scu_ast2500.h index 0fa3ecb9b9..e2556f920d 100644 --- a/arch/arm/include/asm/arch-aspeed/scu_ast2500.h +++ b/arch/arm/include/asm/arch-aspeed/scu_ast2500.h @@ -31,6 +31,34 @@ #define SCU_MISC_UARTCLK_DIV13 (1 << 12) +/* + * SYSRESET is actually more like a Power register, + * except that corresponding bit set to 1 means that + * the peripheral is off. + */ +#define SCU_SYSRESET_XDMA (1 << 25) +#define SCU_SYSRESET_MCTP (1 << 24) +#define SCU_SYSRESET_ADC (1 << 23) +#define SCU_SYSRESET_JTAG (1 << 22) +#define SCU_SYSRESET_MIC (1 << 18) +#define SCU_SYSRESET_SDIO (1 << 16) +#define SCU_SYSRESET_USB11HOST (1 << 15) +#define SCU_SYSRESET_USBHUB (1 << 14) +#define SCU_SYSRESET_CRT (1 << 13) +#define SCU_SYSRESET_MAC2 (1 << 12) +#define SCU_SYSRESET_MAC1 (1 << 11) +#define SCU_SYSRESET_PECI (1 << 10) +#define SCU_SYSRESET_PWM (1 << 9) +#define SCU_SYSRESET_PCI_VGA (1 << 8) +#define SCU_SYSRESET_2D (1 << 7) +#define SCU_SYSRESET_VIDEO (1 << 6) +#define SCU_SYSRESET_LPC (1 << 5) +#define SCU_SYSRESET_HAC (1 << 4) +#define SCU_SYSRESET_USBHID (1 << 3) +#define SCU_SYSRESET_I2C (1 << 2) +#define SCU_SYSRESET_AHB (1 << 1) +#define SCU_SYSRESET_SDRAM_WDT (1 << 0) + #ifndef __ASSEMBLY__ struct ast2500_clk_priv { diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index fa77ee4ada..80f4646a79 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -51,4 +51,14 @@ config RESET_UNIPHIER Say Y if you want to control reset signals provided by System Control block, Media I/O block, Peripheral Block. +config AST2500_RESET + bool "Reset controller driver for AST2500 SoCs" + depends on DM_RESET && WDT_ASPEED + 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. + endmenu diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 2b963961d6..630b4b4e54 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -9,3 +9,4 @@ obj-$(CONFIG_STI_RESET) += sti-reset.o obj-$(CONFIG_TEGRA_CAR_RESET) += tegra-car-reset.o obj-$(CONFIG_TEGRA186_RESET) += tegra186-reset.o obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o +obj-$(CONFIG_AST2500_RESET) += ast2500-reset.o 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), +}; |