From d2e43986373b75cdc00332106e6cca8bb5db452c Mon Sep 17 00:00:00 2001 From: Sagar Shrikant Kadam Date: Wed, 29 Jul 2020 02:36:11 -0700 Subject: fu540: prci: use common reset indexes defined in binding header Indexes of reset signals available in PRCI driver are also defined in include/dt-bindings/reset/sifive-fu540-prci.h. So use those instead of defining new ones again within the fu540-prci driver. Signed-off-by: Sagar Shrikant Kadam Reviewed-by: Pragnesh Patel Reviewed-by: Bin Meng --- drivers/clk/sifive/fu540-prci.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/sifive/fu540-prci.c b/drivers/clk/sifive/fu540-prci.c index fe6e0d4..00c31fc 100644 --- a/drivers/clk/sifive/fu540-prci.c +++ b/drivers/clk/sifive/fu540-prci.c @@ -41,6 +41,7 @@ #include #include #include +#include /* * EXPECTED_CLK_PARENT_COUNT: how many parent clocks this driver expects: @@ -131,21 +132,17 @@ /* DEVICESRESETREG */ #define PRCI_DEVICESRESETREG_OFFSET 0x28 -#define PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_SHIFT 0 + #define PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_MASK \ - (0x1 << PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_SHIFT) -#define PRCI_DEVICESRESETREG_DDR_AXI_RST_N_SHIFT 1 + (0x1 << PRCI_RST_DDR_CTRL_N) #define PRCI_DEVICESRESETREG_DDR_AXI_RST_N_MASK \ - (0x1 << PRCI_DEVICESRESETREG_DDR_AXI_RST_N_SHIFT) -#define PRCI_DEVICESRESETREG_DDR_AHB_RST_N_SHIFT 2 + (0x1 << PRCI_RST_DDR_AXI_N) #define PRCI_DEVICESRESETREG_DDR_AHB_RST_N_MASK \ - (0x1 << PRCI_DEVICESRESETREG_DDR_AHB_RST_N_SHIFT) -#define PRCI_DEVICESRESETREG_DDR_PHY_RST_N_SHIFT 3 + (0x1 << PRCI_RST_DDR_AHB_N) #define PRCI_DEVICESRESETREG_DDR_PHY_RST_N_MASK \ - (0x1 << PRCI_DEVICESRESETREG_DDR_PHY_RST_N_SHIFT) -#define PRCI_DEVICESRESETREG_GEMGXL_RST_N_SHIFT 5 + (0x1 << PRCI_RST_DDR_PHY_N) #define PRCI_DEVICESRESETREG_GEMGXL_RST_N_MASK \ - (0x1 << PRCI_DEVICESRESETREG_GEMGXL_RST_N_SHIFT) + (0x1 << PRCI_RST_GEMGXL_N) /* CLKMUXSTATUSREG */ #define PRCI_CLKMUXSTATUSREG_OFFSET 0x2c -- cgit v1.1 From d04a46426b92cc175a73e5d2c5220503c428fc6c Mon Sep 17 00:00:00 2001 From: Sagar Shrikant Kadam Date: Wed, 29 Jul 2020 02:36:13 -0700 Subject: sifive: reset: add DM based reset driver for SiFive SoC's PRCI module within SiFive SoC's has register with which we can reset the sub-systems within the SoC. The resets to DDR and ethernet sub systems within FU540-C000 SoC are active low, and are hold low by default on power-up. Currently these are directly asserted within prci driver via register read/write. With the DM based reset driver support here, we bind the reset driver with clock (prci) driver and assert the reset signals of both sub-system's appropriately. Signed-off-by: Sagar Shrikant Kadam Reviewed-by: Pragnesh Patel Reviewed-by: Bin Meng Tested-by: Bin Meng --- drivers/clk/sifive/fu540-prci.c | 73 ++++++++++++++++++++----- drivers/reset/reset-sifive.c | 118 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 176 insertions(+), 15 deletions(-) create mode 100644 drivers/reset/reset-sifive.c (limited to 'drivers') diff --git a/drivers/clk/sifive/fu540-prci.c b/drivers/clk/sifive/fu540-prci.c index 00c31fc..c5148e9 100644 --- a/drivers/clk/sifive/fu540-prci.c +++ b/drivers/clk/sifive/fu540-prci.c @@ -30,11 +30,15 @@ #include #include +#include #include #include #include #include #include +#include +#include +#include #include #include @@ -132,6 +136,7 @@ /* DEVICESRESETREG */ #define PRCI_DEVICESRESETREG_OFFSET 0x28 +#define PRCI_DEVICERESETCNT 5 #define PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_MASK \ (0x1 << PRCI_RST_DDR_CTRL_N) @@ -525,6 +530,41 @@ static const struct __prci_clock_ops sifive_fu540_prci_tlclksel_clk_ops = { .recalc_rate = sifive_fu540_prci_tlclksel_recalc_rate, }; +static int __prci_consumer_reset(const char *rst_name, bool trigger) +{ + struct udevice *dev; + struct reset_ctl rst_sig; + int ret; + + ret = uclass_get_device_by_driver(UCLASS_RESET, + DM_GET_DRIVER(sifive_reset), + &dev); + if (ret) { + dev_err(dev, "Reset driver not found: %d\n", ret); + return ret; + } + + ret = reset_get_by_name(dev, rst_name, &rst_sig); + if (ret) { + dev_err(dev, "failed to get %s reset\n", rst_name); + return ret; + } + + if (reset_valid(&rst_sig)) { + if (trigger) + ret = reset_deassert(&rst_sig); + else + ret = reset_assert(&rst_sig); + if (ret) { + dev_err(dev, "failed to trigger reset id = %ld\n", + rst_sig.id); + return ret; + } + } + + return ret; +} + /** * __prci_ddr_release_reset() - Release DDR reset * @pd: struct __prci_data * for the PRCI containing the DDRCLK mux reg @@ -532,19 +572,20 @@ static const struct __prci_clock_ops sifive_fu540_prci_tlclksel_clk_ops = { */ static void __prci_ddr_release_reset(struct __prci_data *pd) { - u32 v; - - v = __prci_readl(pd, PRCI_DEVICESRESETREG_OFFSET); - v |= PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_MASK; - __prci_writel(v, PRCI_DEVICESRESETREG_OFFSET, pd); + /* Release DDR ctrl reset */ + __prci_consumer_reset("ddr_ctrl", true); /* HACK to get the '1 full controller clock cycle'. */ asm volatile ("fence"); - v = __prci_readl(pd, PRCI_DEVICESRESETREG_OFFSET); - v |= (PRCI_DEVICESRESETREG_DDR_AXI_RST_N_MASK | - PRCI_DEVICESRESETREG_DDR_AHB_RST_N_MASK | - PRCI_DEVICESRESETREG_DDR_PHY_RST_N_MASK); - __prci_writel(v, PRCI_DEVICESRESETREG_OFFSET, pd); + + /* Release DDR AXI reset */ + __prci_consumer_reset("ddr_axi", true); + + /* Release DDR AHB reset */ + __prci_consumer_reset("ddr_ahb", true); + + /* Release DDR PHY reset */ + __prci_consumer_reset("ddr_phy", true); /* HACK to get the '1 full controller clock cycle'. */ asm volatile ("fence"); @@ -564,12 +605,8 @@ static void __prci_ddr_release_reset(struct __prci_data *pd) */ static void __prci_ethernet_release_reset(struct __prci_data *pd) { - u32 v; - /* Release GEMGXL reset */ - v = __prci_readl(pd, PRCI_DEVICESRESETREG_OFFSET); - v |= PRCI_DEVICESRESETREG_GEMGXL_RST_N_MASK; - __prci_writel(v, PRCI_DEVICESRESETREG_OFFSET, pd); + __prci_consumer_reset("gemgxl_reset", true); /* Procmon => core clock */ __prci_writel(PRCI_PROCMONCFG_CORE_CLOCK_MASK, PRCI_PROCMONCFG_OFFSET, @@ -754,6 +791,11 @@ static struct clk_ops sifive_fu540_prci_ops = { .disable = sifive_fu540_prci_disable, }; +static int sifive_fu540_clk_bind(struct udevice *dev) +{ + return sifive_reset_bind(dev, PRCI_DEVICERESETCNT); +} + static const struct udevice_id sifive_fu540_prci_ids[] = { { .compatible = "sifive,fu540-c000-prci" }, { } @@ -766,4 +808,5 @@ U_BOOT_DRIVER(sifive_fu540_prci) = { .probe = sifive_fu540_prci_probe, .ops = &sifive_fu540_prci_ops, .priv_auto_alloc_size = sizeof(struct __prci_data), + .bind = sifive_fu540_clk_bind, }; diff --git a/drivers/reset/reset-sifive.c b/drivers/reset/reset-sifive.c new file mode 100644 index 0000000..527757f --- /dev/null +++ b/drivers/reset/reset-sifive.c @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2020 Sifive, Inc. + * Author: Sagar Kadam + */ + +#include +#include +#include +#include +#include +#include +#include + +#define PRCI_RESETREG_OFFSET 0x28 + +struct sifive_reset_priv { + void *base; + /* number of reset signals */ + int nr_reset; +}; + +static int sifive_rst_trigger(struct reset_ctl *rst, bool level) +{ + struct sifive_reset_priv *priv = dev_get_priv(rst->dev); + int id = rst->id; + int regval = readl(priv->base + PRCI_RESETREG_OFFSET); + + /* Derive bitposition from rst id */ + if (level) + /* Reset deassert */ + regval |= BIT(id); + else + /* Reset assert */ + regval &= ~BIT(id); + + writel(regval, priv->base + PRCI_RESETREG_OFFSET); + + return 0; +} + +static int sifive_reset_assert(struct reset_ctl *rst) +{ + return sifive_rst_trigger(rst, false); +} + +static int sifive_reset_deassert(struct reset_ctl *rst) +{ + return sifive_rst_trigger(rst, true); +} + +static int sifive_reset_request(struct reset_ctl *rst) +{ + struct sifive_reset_priv *priv = dev_get_priv(rst->dev); + + debug("%s(rst=%p) (dev=%p, id=%lu) (nr_reset=%d)\n", __func__, + rst, rst->dev, rst->id, priv->nr_reset); + + if (rst->id > priv->nr_reset) + return -EINVAL; + + return 0; +} + +static int sifive_reset_free(struct reset_ctl *rst) +{ + struct sifive_reset_priv *priv = dev_get_priv(rst->dev); + + debug("%s(rst=%p) (dev=%p, id=%lu) (nr_reset=%d)\n", __func__, + rst, rst->dev, rst->id, priv->nr_reset); + + return 0; +} + +static int sifive_reset_probe(struct udevice *dev) +{ + struct sifive_reset_priv *priv = dev_get_priv(dev); + + priv->base = dev_remap_addr(dev); + if (!priv->base) + return -ENOMEM; + + return 0; +} + +int sifive_reset_bind(struct udevice *dev, ulong count) +{ + struct udevice *rst_dev; + struct sifive_reset_priv *priv; + int ret; + + ret = device_bind_driver_to_node(dev, "sifive-reset", "reset", + dev_ofnode(dev), &rst_dev); + if (ret) { + dev_err(dev, "failed to bind sifive_reset driver (ret=%d)\n", ret); + return ret; + } + priv = malloc(sizeof(struct sifive_reset_priv)); + priv->nr_reset = count; + rst_dev->priv = priv; + + return 0; +} + +const struct reset_ops sifive_reset_ops = { + .request = sifive_reset_request, + .rfree = sifive_reset_free, + .rst_assert = sifive_reset_assert, + .rst_deassert = sifive_reset_deassert, +}; + +U_BOOT_DRIVER(sifive_reset) = { + .name = "sifive-reset", + .id = UCLASS_RESET, + .ops = &sifive_reset_ops, + .probe = sifive_reset_probe, + .priv_auto_alloc_size = sizeof(struct sifive_reset_priv), +}; -- cgit v1.1 From ed50d3fae49b9dad58674b6609913beeac824e42 Mon Sep 17 00:00:00 2001 From: Sagar Shrikant Kadam Date: Wed, 29 Jul 2020 02:36:14 -0700 Subject: configs: reset: fu540: enable dm reset framework for SiFive Add necessary defconfig and Kconfig entries to enable SiFive SoC's reset driver so as to utilise U-Boot's reset framework. Signed-off-by: Sagar Shrikant Kadam Reviewed-by: Pragnesh Patel Reviewed-by: Bin Meng Tested-by: Bin Meng --- drivers/reset/Kconfig | 9 +++++++++ drivers/reset/Makefile | 1 + 2 files changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 6d53561..253902f 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -148,6 +148,15 @@ config RESET_IMX7 help Support for reset controller on i.MX7/8 SoCs. +config RESET_SIFIVE + bool "Reset Driver for SiFive SoC's" + depends on DM_RESET && CLK_SIFIVE_FU540_PRCI && TARGET_SIFIVE_FU540 + default y + help + PRCI module within SiFive SoC's provides mechanism to reset + different hw blocks like DDR, gemgxl. With this driver we leverage + U-Boot's reset framework to reset these hardware blocks. + config RESET_SYSCON bool "Enable generic syscon reset driver support" depends on DM_RESET diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 8e0124b..3c7f066 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -23,5 +23,6 @@ obj-$(CONFIG_RESET_MTMIPS) += reset-mtmips.o obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o obj-$(CONFIG_RESET_HISILICON) += reset-hisilicon.o obj-$(CONFIG_RESET_IMX7) += reset-imx7.o +obj-$(CONFIG_RESET_SIFIVE) += reset-sifive.o obj-$(CONFIG_RESET_SYSCON) += reset-syscon.o obj-$(CONFIG_RESET_RASPBERRYPI) += reset-raspberrypi.o -- cgit v1.1