diff options
Diffstat (limited to 'drivers/reset')
-rw-r--r-- | drivers/reset/Kconfig | 6 | ||||
-rw-r--r-- | drivers/reset/Makefile | 1 | ||||
-rw-r--r-- | drivers/reset/reset-hisilicon.c | 103 | ||||
-rw-r--r-- | drivers/reset/reset-meson.c | 1 | ||||
-rw-r--r-- | drivers/reset/reset-rockchip.c | 2 | ||||
-rw-r--r-- | drivers/reset/reset-socfpga.c | 55 |
6 files changed, 162 insertions, 6 deletions
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index a81e767696..6ec6f39c85 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -121,4 +121,10 @@ config RESET_SUNXI This enables support for common reset driver for Allwinner SoCs. +config RESET_HISILICON + bool "Reset controller driver for HiSilicon SoCs" + depends on DM_RESET + help + Support for reset controller on HiSilicon SoCs. + endmenu diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 4fad7d4129..7fec75bb49 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -19,3 +19,4 @@ obj-$(CONFIG_RESET_MESON) += reset-meson.o obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o obj-$(CONFIG_RESET_MEDIATEK) += reset-mediatek.o obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o +obj-$(CONFIG_RESET_HISILICON) += reset-hisilicon.o diff --git a/drivers/reset/reset-hisilicon.c b/drivers/reset/reset-hisilicon.c new file mode 100644 index 0000000000..a9f052a0c5 --- /dev/null +++ b/drivers/reset/reset-hisilicon.c @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2019, Linaro Limited + */ + +#include <asm/io.h> +#include <common.h> +#include <dm.h> +#include <dt-bindings/reset/ti-syscon.h> +#include <reset-uclass.h> + +struct hisi_reset_priv { + void __iomem *base; +}; + +static int hisi_reset_deassert(struct reset_ctl *rst) +{ + struct hisi_reset_priv *priv = dev_get_priv(rst->dev); + u32 val; + + val = readl(priv->base + rst->data); + if (rst->polarity & DEASSERT_SET) + val |= BIT(rst->id); + else + val &= ~BIT(rst->id); + writel(val, priv->base + rst->data); + + return 0; +} + +static int hisi_reset_assert(struct reset_ctl *rst) +{ + struct hisi_reset_priv *priv = dev_get_priv(rst->dev); + u32 val; + + val = readl(priv->base + rst->data); + if (rst->polarity & ASSERT_SET) + val |= BIT(rst->id); + else + val &= ~BIT(rst->id); + writel(val, priv->base + rst->data); + + return 0; +} + +static int hisi_reset_free(struct reset_ctl *rst) +{ + return 0; +} + +static int hisi_reset_request(struct reset_ctl *rst) +{ + return 0; +} + +static int hisi_reset_of_xlate(struct reset_ctl *rst, + struct ofnode_phandle_args *args) +{ + if (args->args_count != 3) { + debug("Invalid args_count: %d\n", args->args_count); + return -EINVAL; + } + + /* Use .data field as register offset and .id field as bit shift */ + rst->data = args->args[0]; + rst->id = args->args[1]; + rst->polarity = args->args[2]; + + return 0; +} + +static const struct reset_ops hisi_reset_reset_ops = { + .of_xlate = hisi_reset_of_xlate, + .request = hisi_reset_request, + .free = hisi_reset_free, + .rst_assert = hisi_reset_assert, + .rst_deassert = hisi_reset_deassert, +}; + +static const struct udevice_id hisi_reset_ids[] = { + { .compatible = "hisilicon,hi3798cv200-reset" }, + { } +}; + +static int hisi_reset_probe(struct udevice *dev) +{ + struct hisi_reset_priv *priv = dev_get_priv(dev); + + priv->base = dev_remap_addr(dev); + if (!priv->base) + return -ENOMEM; + + return 0; +} + +U_BOOT_DRIVER(hisi_reset) = { + .name = "hisilicon_reset", + .id = UCLASS_RESET, + .of_match = hisi_reset_ids, + .ops = &hisi_reset_reset_ops, + .probe = hisi_reset_probe, + .priv_auto_alloc_size = sizeof(struct hisi_reset_priv), +}; diff --git a/drivers/reset/reset-meson.c b/drivers/reset/reset-meson.c index 92f04695ec..31aa4d41e8 100644 --- a/drivers/reset/reset-meson.c +++ b/drivers/reset/reset-meson.c @@ -69,6 +69,7 @@ struct reset_ops meson_reset_ops = { static const struct udevice_id meson_reset_ids[] = { { .compatible = "amlogic,meson-gxbb-reset" }, + { .compatible = "amlogic,meson-axg-reset" }, { } }; diff --git a/drivers/reset/reset-rockchip.c b/drivers/reset/reset-rockchip.c index af07134049..3871fc00d0 100644 --- a/drivers/reset/reset-rockchip.c +++ b/drivers/reset/reset-rockchip.c @@ -7,7 +7,7 @@ #include <dm.h> #include <reset-uclass.h> #include <linux/io.h> -#include <asm/arch/hardware.h> +#include <asm/arch-rockchip/hardware.h> #include <dm/lists.h> /* * Each reg has 16 bits reset signal for devices diff --git a/drivers/reset/reset-socfpga.c b/drivers/reset/reset-socfpga.c index b2acfcd2ec..cb8312619f 100644 --- a/drivers/reset/reset-socfpga.c +++ b/drivers/reset/reset-socfpga.c @@ -24,9 +24,39 @@ #define NR_BANKS 8 struct socfpga_reset_data { - void __iomem *membase; + void __iomem *modrst_base; }; +/* + * For compatibility with Kernels that don't support peripheral reset, this + * driver can keep the old behaviour of not asserting peripheral reset before + * starting the OS and deasserting all peripheral resets (enabling all + * peripherals). + * + * For that, the reset driver checks the environment variable + * "socfpga_legacy_reset_compat". If this variable is '1', perihperals are not + * reset again once taken out of reset and all peripherals in 'permodrst' are + * taken out of reset before booting into the OS. + * Note that this should be required for gen5 systems only that are running + * Linux kernels without proper peripheral reset support for all drivers used. + */ +static bool socfpga_reset_keep_enabled(void) +{ +#if !defined(CONFIG_SPL_BUILD) || CONFIG_IS_ENABLED(ENV_SUPPORT) + const char *env_str; + long val; + + env_str = env_get("socfpga_legacy_reset_compat"); + if (env_str) { + val = simple_strtol(env_str, NULL, 0); + if (val == 1) + return true; + } +#endif + + return false; +} + static int socfpga_reset_assert(struct reset_ctl *reset_ctl) { struct socfpga_reset_data *data = dev_get_priv(reset_ctl->dev); @@ -35,7 +65,7 @@ static int socfpga_reset_assert(struct reset_ctl *reset_ctl) int bank = id / (reg_width * BITS_PER_BYTE); int offset = id % (reg_width * BITS_PER_BYTE); - setbits_le32(data->membase + (bank * BANK_INCREMENT), BIT(offset)); + setbits_le32(data->modrst_base + (bank * BANK_INCREMENT), BIT(offset)); return 0; } @@ -47,7 +77,7 @@ static int socfpga_reset_deassert(struct reset_ctl *reset_ctl) int bank = id / (reg_width * BITS_PER_BYTE); int offset = id % (reg_width * BITS_PER_BYTE); - clrbits_le32(data->membase + (bank * BANK_INCREMENT), BIT(offset)); + clrbits_le32(data->modrst_base + (bank * BANK_INCREMENT), BIT(offset)); return 0; } @@ -80,11 +110,24 @@ static int socfpga_reset_probe(struct udevice *dev) const void *blob = gd->fdt_blob; int node = dev_of_offset(dev); u32 modrst_offset; + void __iomem *membase; - data->membase = devfdt_get_addr_ptr(dev); + membase = devfdt_get_addr_ptr(dev); modrst_offset = fdtdec_get_int(blob, node, "altr,modrst-offset", 0x10); - data->membase += modrst_offset; + data->modrst_base = membase + modrst_offset; + + return 0; +} + +static int socfpga_reset_remove(struct udevice *dev) +{ + struct socfpga_reset_data *data = dev_get_priv(dev); + + if (socfpga_reset_keep_enabled()) { + puts("Deasserting all peripheral resets\n"); + writel(0, data->modrst_base + 4); + } return 0; } @@ -101,4 +144,6 @@ U_BOOT_DRIVER(socfpga_reset) = { .probe = socfpga_reset_probe, .priv_auto_alloc_size = sizeof(struct socfpga_reset_data), .ops = &socfpga_reset_ops, + .remove = socfpga_reset_remove, + .flags = DM_FLAG_OS_PREPARE, }; |