From 56c86383dc88850ee2e5af197532939b861f573b Mon Sep 17 00:00:00 2001 From: "yanhong.wang" Date: Fri, 18 Mar 2022 18:21:46 +0800 Subject: Reset:Starfive-jh7110: Add reset driver for JH7110 Support for reset controller on starfive JH7110 SoCs. Signed-off-by: yanhong.wang --- drivers/reset/Kconfig | 8 ++ drivers/reset/Makefile | 1 + drivers/reset/reset-jh7110.c | 244 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 253 insertions(+) create mode 100644 drivers/reset/reset-jh7110.c (limited to 'drivers') diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index d73daf5e31..6c92a10a93 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -164,6 +164,14 @@ config RESET_IPQ419 Support for reset controller on Qualcomm IPQ40xx SoCs. +config RESET_JH7110 + bool "Reset driver for Starfive JH7110 SoC" + depends on DM_RESET && TARGET_STARFIVE_VISIONFIVE + default y + help + Support for reset controller on Starfive + JH7110 SoCs. + config RESET_SIFIVE bool "Reset Driver for SiFive SoC's" depends on DM_RESET && CLK_SIFIVE_PRCI && (TARGET_SIFIVE_UNLEASHED || TARGET_SIFIVE_UNMATCHED) diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index d69486bdeb..02c2812b0b 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -30,3 +30,4 @@ obj-$(CONFIG_RESET_SYSCON) += reset-syscon.o obj-$(CONFIG_RESET_RASPBERRYPI) += reset-raspberrypi.o obj-$(CONFIG_RESET_SCMI) += reset-scmi.o obj-$(CONFIG_RESET_ZYNQMP) += reset-zynqmp.o +obj-$(CONFIG_RESET_JH7110) += reset-jh7110.o diff --git a/drivers/reset/reset-jh7110.c b/drivers/reset/reset-jh7110.c new file mode 100644 index 0000000000..79d5c5cbb0 --- /dev/null +++ b/drivers/reset/reset-jh7110.c @@ -0,0 +1,244 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2022 Starfive, Inc. + * Author: samin + * yanhong + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define AONCRG_RESET_ASSERT 0x38 +#define AONCRG_RESET_STATUS 0x3C +#define ISPCRG_RESET_ASSERT 0x38 +#define ISPCRG_RESET_STATUS 0x3C +#define VOUTCRG_RESET_ASSERT 0x48 +#define VOUTCRG_RESET_STATUS 0x4C +#define STGCRG_RESET_ASSERT 0x74 +#define STGCRG_RESET_STATUS 0x78 +#define SYSCRG_RESET_ASSERT0 0x2F8 +#define SYSCRG_RESET_ASSERT1 0x2FC +#define SYSCRG_RESET_ASSERT2 0x300 +#define SYSCRG_RESET_ASSERT3 0x304 +#define SYSCRG_RESET_STATUS0 0x308 +#define SYSCRG_RESET_STATUS1 0x30C +#define SYSCRG_RESET_STATUS2 0x310 +#define SYSCRG_RESET_STATUS3 0x314 + +struct reset_assert_t { + void __iomem *assert; + void __iomem *status; +}; + +enum JH7110_RESET_CRG_GROUP { + SYSCRG_0 = 0, + SYSCRG_1, + SYSCRG_2, + SYSCRG_3, + STGCRG, + AONCRG, + ISPCRG, + VOUTCRG, +}; + +struct jh7110_reset_priv { + void __iomem *syscrg; + void __iomem *stgcrg; + void __iomem *aoncrg; + void __iomem *ispcrg; + void __iomem *voutcrg; +}; + +static const u32 jh7110_reset_asserted[8] = { + /* SYSCRG_STATUS0 */ + BIT(RSTN_U0_U7MC_RST_BUS % 32) | + BIT(RSTN_U0_U7MC_CORE0 % 32) | + BIT(RSTN_U0_U7MC_CORE1 % 32) | + BIT(RSTN_U0_U7MC_CORE2 % 32) | + BIT(RSTN_U0_U7MC_CORE3 % 32) | + BIT(RSTN_U0_U7MC_CORE4 % 32), + /* SYSCRG_STATUS1 */ + 0, + /* SYSCRG_STATUS2 */ + 0, + /* SYSCRG_STATUS3 */ + 0, + /* STGCRG */ + BIT(RSTN_U0_HIFI4_CORE % 32) | + BIT(RSTN_U0_E24_CORE % 32), + /* AONCRG */ + 0, + /* ISPCRG */ + 0, + /*VOUTCRG*/ + 0, +}; + +static int jh7110_get_reset(struct jh7110_reset_priv *priv, + struct reset_assert_t *reset, + unsigned long group) +{ + switch (group) { + case SYSCRG_0: + reset->assert = priv->syscrg + SYSCRG_RESET_ASSERT0; + reset->status = priv->syscrg + SYSCRG_RESET_STATUS0; + break; + case SYSCRG_1: + reset->assert = priv->syscrg + SYSCRG_RESET_ASSERT1; + reset->status = priv->syscrg + SYSCRG_RESET_STATUS1; + break; + case SYSCRG_2: + reset->assert = priv->syscrg + SYSCRG_RESET_ASSERT2; + reset->status = priv->syscrg + SYSCRG_RESET_STATUS2; + break; + case SYSCRG_3: + reset->assert = priv->syscrg + SYSCRG_RESET_ASSERT3; + reset->status = priv->syscrg + SYSCRG_RESET_STATUS3; + break; + case STGCRG: + reset->assert = priv->stgcrg + STGCRG_RESET_ASSERT; + reset->status = priv->stgcrg + STGCRG_RESET_STATUS; + break; + case AONCRG: + reset->assert = priv->aoncrg + AONCRG_RESET_ASSERT; + reset->status = priv->aoncrg + AONCRG_RESET_STATUS; + break; + + case ISPCRG: + reset->assert = priv->ispcrg + ISPCRG_RESET_ASSERT; + reset->status = priv->ispcrg + ISPCRG_RESET_STATUS; + break; + case VOUTCRG: + reset->assert = priv->voutcrg + VOUTCRG_RESET_ASSERT; + reset->status = priv->voutcrg + VOUTCRG_RESET_STATUS; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int jh7110_reset_trigger(struct jh7110_reset_priv *priv, + unsigned long id, bool assert) +{ + struct reset_assert_t reset; + unsigned long group; + u32 mask, value, done; + int ret; + + group = id / 32; + mask = BIT(id % 32); + ret = jh7110_get_reset(priv, &reset, group); + if (ret) { + debug("reset: bad reset id.\n"); + return ret; + } + + done = jh7110_reset_asserted[group] & mask; + + if (!assert) + done ^= mask; + + value = readl(reset.assert); + if (assert) + value |= mask; + else + value &= ~mask; + writel(value, reset.assert); + + /* if the associated clock is gated, deasserting might otherwise hang forever */ + ret = readl_poll_timeout(reset.status, value, (value & mask) == done, 100000); + if (ret) + debug("reset %ld: timeout.\n", id); + + return ret; +} + +static int jh7110_reset_assert(struct reset_ctl *rst) +{ + struct jh7110_reset_priv *priv = dev_get_priv(rst->dev); + + jh7110_reset_trigger(priv, rst->id, true); + + return 0; +} + +static int jh7110_reset_deassert(struct reset_ctl *rst) +{ + struct jh7110_reset_priv *priv = dev_get_priv(rst->dev); + + jh7110_reset_trigger(priv, rst->id, false); + + return 0; +} + +static int jh7110_reset_free(struct reset_ctl *rst) +{ + return 0; +} + +static int jh7110_reset_request(struct reset_ctl *rst) +{ + if (rst->id >= RSTN_JH7110_RESET_END) + return -EINVAL; + + return 0; +} + +struct reset_ops jh7110_reset_reset_ops = { + .rfree = jh7110_reset_free, + .request = jh7110_reset_request, + .rst_assert = jh7110_reset_assert, + .rst_deassert = jh7110_reset_deassert, +}; + +static const struct udevice_id jh7110_reset_ids[] = { + { .compatible = "starfive,jh7110-reset" }, + { /* sentinel */ } +}; + +static int jh7110_reset_probe(struct udevice *dev) +{ + struct jh7110_reset_priv *priv = dev_get_priv(dev); + + priv->syscrg = dev_remap_addr_name(dev, "syscrg"); + if (!priv->syscrg) + return -EINVAL; + + priv->stgcrg = dev_remap_addr_name(dev, "stgcrg"); + if (!priv->stgcrg) + return -EINVAL; + + priv->aoncrg = dev_remap_addr_name(dev, "aoncrg"); + if (!priv->aoncrg) + return -EINVAL; + + priv->ispcrg = dev_remap_addr_name(dev, "ispcrg"); + if (!priv->ispcrg) + return -EINVAL; + + priv->voutcrg = dev_remap_addr_name(dev, "voutcrg"); + if (!priv->voutcrg) + return -EINVAL; + + return 0; +} + +U_BOOT_DRIVER(jh7110_reset) = { + .name = "jh7110-reset", + .id = UCLASS_RESET, + .of_match = jh7110_reset_ids, + .ops = &jh7110_reset_reset_ops, + .probe = jh7110_reset_probe, + .priv_auto = sizeof(struct jh7110_reset_priv), +}; -- cgit v1.2.3