diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/reset/Kconfig | 7 | ||||
-rw-r--r-- | drivers/reset/Makefile | 1 | ||||
-rw-r--r-- | drivers/reset/reset-hsdk.c | 116 |
3 files changed, 124 insertions, 0 deletions
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index cff00820e4..75ccd65799 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -91,6 +91,13 @@ config RESET_ROCKCHIP though is that some reset signals, like I2C or MISC reset multiple devices. +config RESET_HSDK + bool "Synopsys HSDK Reset Driver" + depends on DM_RESET && TARGET_HSDK + default y + help + This enables the reset controller driver for HSDK board. + config RESET_MESON bool "Reset controller driver for Amlogic Meson SoCs" depends on DM_RESET && ARCH_MESON diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 8102d8db29..0a044d5d8c 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_STM32_RESET) += stm32-reset.o obj-$(CONFIG_TEGRA_CAR_RESET) += tegra-car-reset.o obj-$(CONFIG_TEGRA186_RESET) += tegra186-reset.o obj-$(CONFIG_RESET_TI_SCI) += reset-ti-sci.o +obj-$(CONFIG_RESET_HSDK) += reset-hsdk.o obj-$(CONFIG_RESET_BCM6345) += reset-bcm6345.o obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o obj-$(CONFIG_AST2500_RESET) += ast2500-reset.o diff --git a/drivers/reset/reset-hsdk.c b/drivers/reset/reset-hsdk.c new file mode 100644 index 0000000000..213d6c87be --- /dev/null +++ b/drivers/reset/reset-hsdk.c @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * HSDK SoC Reset Controller driver + * + * Copyright (C) 2019 Synopsys, Inc. All rights reserved. + * Author: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com> + */ + +#include <asm/io.h> +#include <common.h> +#include <dm.h> +#include <linux/iopoll.h> +#include <reset-uclass.h> + +struct hsdk_rst { + void __iomem *regs_ctl; + void __iomem *regs_rst; +}; + +static const u32 rst_map[] = { + BIT(16), /* APB_RST */ + BIT(17), /* AXI_RST */ + BIT(18), /* ETH_RST */ + BIT(19), /* USB_RST */ + BIT(20), /* SDIO_RST */ + BIT(21), /* HDMI_RST */ + BIT(22), /* GFX_RST */ + BIT(25), /* DMAC_RST */ + BIT(31), /* EBI_RST */ +}; + +#define HSDK_MAX_RESETS ARRAY_SIZE(rst_map) + +#define CGU_SYS_RST_CTRL 0x0 +#define CGU_IP_SW_RESET 0x0 +#define CGU_IP_SW_RESET_DELAY_SHIFT 16 +#define CGU_IP_SW_RESET_DELAY_MASK GENMASK(31, CGU_IP_SW_RESET_DELAY_SHIFT) +#define CGU_IP_SW_RESET_DELAY 0 +#define CGU_IP_SW_RESET_RESET BIT(0) +#define SW_RESET_TIMEOUT 10000 + +static void hsdk_reset_config(struct hsdk_rst *rst, unsigned long id) +{ + writel(rst_map[id], rst->regs_ctl + CGU_SYS_RST_CTRL); +} + +static int hsdk_reset_do(struct hsdk_rst *rst) +{ + u32 reg; + + reg = readl(rst->regs_rst + CGU_IP_SW_RESET); + reg &= ~CGU_IP_SW_RESET_DELAY_MASK; + reg |= CGU_IP_SW_RESET_DELAY << CGU_IP_SW_RESET_DELAY_SHIFT; + reg |= CGU_IP_SW_RESET_RESET; + writel(reg, rst->regs_rst + CGU_IP_SW_RESET); + + /* wait till reset bit is back to 0 */ + return readl_poll_timeout(rst->regs_rst + CGU_IP_SW_RESET, reg, + !(reg & CGU_IP_SW_RESET_RESET), SW_RESET_TIMEOUT); +} + +static int hsdk_reset_reset(struct reset_ctl *rst_ctl) +{ + struct udevice *dev = rst_ctl->dev; + struct hsdk_rst *rst = dev_get_priv(dev); + + if (rst_ctl->id >= HSDK_MAX_RESETS) + return -EINVAL; + + debug("%s(reset_ctl=%p) (dev=%p, id=%lu)\n", __func__, rst_ctl, + rst_ctl->dev, rst_ctl->id); + + hsdk_reset_config(rst, rst_ctl->id); + return hsdk_reset_do(rst); +} + +static int hsdk_reset_noop(struct reset_ctl *rst_ctl) +{ + return 0; +} + +static const struct reset_ops hsdk_reset_ops = { + .request = hsdk_reset_noop, + .free = hsdk_reset_noop, + .rst_assert = hsdk_reset_noop, + .rst_deassert = hsdk_reset_reset, +}; + +static const struct udevice_id hsdk_reset_dt_match[] = { + { .compatible = "snps,hsdk-reset" }, + { }, +}; + +static int hsdk_reset_probe(struct udevice *dev) +{ + struct hsdk_rst *rst = dev_get_priv(dev); + + rst->regs_ctl = dev_remap_addr_index(dev, 0); + if (!rst->regs_ctl) + return -EINVAL; + + rst->regs_rst = dev_remap_addr_index(dev, 1); + if (!rst->regs_rst) + return -EINVAL; + + return 0; +} + +U_BOOT_DRIVER(hsdk_reset) = { + .name = "hsdk-reset", + .id = UCLASS_RESET, + .of_match = hsdk_reset_dt_match, + .ops = &hsdk_reset_ops, + .probe = hsdk_reset_probe, + .priv_auto_alloc_size = sizeof(struct hsdk_rst), +}; |