reset: starfive-jh7110: Add StarFive JH7110 reset driver
authorsamin <samin.guo@starfivetech.com>
Thu, 16 Dec 2021 10:25:49 +0000 (18:25 +0800)
committersamin <samin.guo@starfivetech.com>
Wed, 22 Dec 2021 07:38:43 +0000 (15:38 +0800)
Add a driver for the StarFive JH7110 reset controller.

Signed-off-by: samin <samin.guo@starfivetech.com>
drivers/reset/Kconfig
drivers/reset/Makefile
drivers/reset/starfive/Kconfig [new file with mode: 0644]
drivers/reset/starfive/Makefile [new file with mode: 0644]
drivers/reset/starfive/reset-starfive-jh7110.c [new file with mode: 0644]
include/dt-bindings/reset/starfive-jh7110.h [new file with mode: 0644]

index b0056ae..5b23362 100644 (file)
@@ -275,6 +275,7 @@ config RESET_ZYNQ
        help
          This enables the reset controller driver for Xilinx Zynq SoCs.
 
+source "drivers/reset/starfive/Kconfig"
 source "drivers/reset/sti/Kconfig"
 source "drivers/reset/hisilicon/Kconfig"
 source "drivers/reset/tegra/Kconfig"
index 21d46d8..e7edddc 100644 (file)
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 obj-y += core.o
 obj-y += hisilicon/
+obj-y += starfive/
 obj-$(CONFIG_ARCH_STI) += sti/
 obj-$(CONFIG_ARCH_TEGRA) += tegra/
 obj-$(CONFIG_RESET_A10SR) += reset-a10sr.o
diff --git a/drivers/reset/starfive/Kconfig b/drivers/reset/starfive/Kconfig
new file mode 100644 (file)
index 0000000..37c1088
--- /dev/null
@@ -0,0 +1,6 @@
+config RESET_STARFIVE_JH7110
+       bool "StarFive JH7110 Reset Driver"
+       depends on SOC_STARFIVE || COMPILE_TEST
+       default SOC_STARFIVE_JH7110
+       help
+         This enables the reset controller driver for the StarFive JH7110 SoC.
diff --git a/drivers/reset/starfive/Makefile b/drivers/reset/starfive/Makefile
new file mode 100644 (file)
index 0000000..a5b06a2
--- /dev/null
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_RESET_STARFIVE_JH7110) += reset-starfive-jh7110.o
diff --git a/drivers/reset/starfive/reset-starfive-jh7110.c b/drivers/reset/starfive/reset-starfive-jh7110.c
new file mode 100644 (file)
index 0000000..412c253
--- /dev/null
@@ -0,0 +1,260 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Reset driver for the StarFive JH7110 SoC
+ *
+ * Copyright (C) 2021 samin <samin.guo@starfivetech.com>
+ */
+
+#include <linux/bitmap.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+#include <linux/spinlock.h>
+
+#include <dt-bindings/reset/starfive-jh7110.h>
+
+/* register offsets */
+#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
+
+#define STGCRG_RESET_ASSERT0   0x74
+#define STGCRG_RESET_STATUS0   0x78
+
+#define AONCRG_RESET_ASSERT0   0x38
+#define AONCRG_RESET_STATUS0   0x3C
+
+struct reset_assert_t {
+       void *__iomem reg_assert;
+       void *__iomem reg_status;
+};
+
+enum JH7110_RESET_CRG_GROUP {
+       SYSCRG_0 = 0,
+       SYSCRG_1,
+       SYSCRG_2,
+       SYSCRG_3,
+       STGCRG_0,
+       AONCRG_0,
+};
+
+struct jh7110_reset {
+       struct reset_assert_t reset_assert[6];
+       struct reset_controller_dev rcdev;
+       /* protect registers against concurrent read-modify-write */
+       spinlock_t lock;
+       void __iomem *syscrg;
+       void __iomem *stgcrg;
+       void __iomem *aoncrg;
+       const u32 *asserted;
+};
+
+/*
+ * Writing a 1 to the n'th bit of the m'th ASSERT register asserts
+ * line 32m + n, and writing a 0 deasserts the same line.
+ * Most reset lines have their status inverted so a 0 bit in the STATUS
+ * register means the line is asserted and a 1 means it's deasserted. A few
+ * lines don't though, so store the expected value of the status registers when
+ * all lines are asserted.
+ */
+static const u32 jh7110_reset_asserted[6] = {
+       /* 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,
+};
+
+static inline struct jh7110_reset *
+jh7110_reset_from(struct reset_controller_dev *rcdev)
+{
+       return container_of(rcdev, struct jh7110_reset, rcdev);
+}
+
+static void jh7110_devm_reset_set(struct device *dev)
+{
+       struct jh7110_reset *data = dev->driver_data;
+
+       data->reset_assert[SYSCRG_0].reg_assert = data->syscrg + SYSCRG_RESET_ASSERT0;
+       data->reset_assert[SYSCRG_0].reg_status = data->syscrg + SYSCRG_RESET_STATUS0;
+
+       data->reset_assert[SYSCRG_1].reg_assert = data->syscrg + SYSCRG_RESET_ASSERT1;
+       data->reset_assert[SYSCRG_1].reg_status = data->syscrg + SYSCRG_RESET_STATUS1;
+
+       data->reset_assert[SYSCRG_2].reg_assert = data->syscrg + SYSCRG_RESET_ASSERT2;
+       data->reset_assert[SYSCRG_2].reg_status = data->syscrg + SYSCRG_RESET_STATUS2;
+
+       data->reset_assert[SYSCRG_3].reg_assert = data->syscrg + SYSCRG_RESET_ASSERT3;
+       data->reset_assert[SYSCRG_3].reg_status = data->syscrg + SYSCRG_RESET_STATUS3;
+
+       data->reset_assert[STGCRG_0].reg_assert = data->stgcrg + STGCRG_RESET_ASSERT0;
+       data->reset_assert[STGCRG_0].reg_status = data->stgcrg + STGCRG_RESET_STATUS0;
+
+       data->reset_assert[AONCRG_0].reg_assert = data->aoncrg + AONCRG_RESET_ASSERT0;
+       data->reset_assert[AONCRG_0].reg_status = data->aoncrg + AONCRG_RESET_STATUS0;
+}
+
+static int jh7110_reset_update(struct reset_controller_dev *rcdev,
+                              unsigned long id, bool assert)
+{
+       struct jh7110_reset *data = jh7110_reset_from(rcdev);
+       void __iomem *reg_assert, *reg_status;
+       unsigned long group, flags;
+       u32 mask, value, done;
+       int ret;
+
+       group = id / 32;
+       mask =  BIT(id % 32);
+       reg_assert = data->reset_assert[group].reg_assert;
+       reg_status = data->reset_assert[group].reg_status;
+
+       done = data->asserted[group] & mask;
+
+       if (!assert)
+               done ^= mask;
+
+       spin_lock_irqsave(&data->lock, flags);
+
+       value = readl(reg_assert);
+       if (assert)
+               value |= mask;
+       else
+               value &= ~mask;
+       writel(value, reg_assert);
+
+       /* if the associated clock is gated, deasserting might otherwise hang forever */
+       ret = readl_poll_timeout_atomic(reg_status, value, (value & mask) == done, 0, 1000);
+       if (ret)
+               dev_warn(rcdev->dev, "id:%ld group:%ld, mask:%#x assert:%#llx status:%#llx ret:%d\n",
+                               id, group, mask, (u64)reg_assert, (u64)reg_status, ret);
+
+       spin_unlock_irqrestore(&data->lock, flags);
+       return ret;
+}
+
+static int jh7110_reset_assert(struct reset_controller_dev *rcdev,
+                              unsigned long id)
+{
+       return jh7110_reset_update(rcdev, id, true);
+}
+
+static int jh7110_reset_deassert(struct reset_controller_dev *rcdev,
+                                unsigned long id)
+{
+       return jh7110_reset_update(rcdev, id, false);
+}
+
+static int jh7110_reset_reset(struct reset_controller_dev *rcdev,
+                             unsigned long id)
+{
+       int ret;
+
+       ret = jh7110_reset_assert(rcdev, id);
+       if (ret)
+               return ret;
+
+       return jh7110_reset_deassert(rcdev, id);
+}
+
+static int jh7110_reset_status(struct reset_controller_dev *rcdev,
+                              unsigned long id)
+{
+       struct jh7110_reset *data = jh7110_reset_from(rcdev);
+       void __iomem *reg_status;
+       unsigned long group;
+       u32 mask, val;
+
+       group = id / 32;
+       mask =  BIT(id % 32);
+       reg_status = data->reset_assert[group].reg_status;
+       val = readl(reg_status);
+
+       return !((val ^ data->asserted[group]) & mask);
+}
+
+static const struct reset_control_ops jh7110_reset_ops = {
+       .assert         = jh7110_reset_assert,
+       .deassert       = jh7110_reset_deassert,
+       .reset          = jh7110_reset_reset,
+       .status         = jh7110_reset_status,
+};
+
+int __init reset_starfive_jh7110_generic_probe(struct platform_device *pdev,
+                                       const u32 *asserted,
+                                       unsigned int nr_resets)
+{
+       struct jh7110_reset *data;
+       struct device *dev = &pdev->dev;
+
+       data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       dev->driver_data = data;
+
+       data->syscrg =  devm_platform_ioremap_resource_byname(pdev, "syscrg");
+       if (IS_ERR(data->syscrg))
+               return PTR_ERR(data->syscrg);
+
+       data->stgcrg =  devm_platform_ioremap_resource_byname(pdev, "stgcrg");
+       if (IS_ERR(data->stgcrg))
+               return PTR_ERR(data->stgcrg);
+
+       data->aoncrg =  devm_platform_ioremap_resource_byname(pdev, "aoncrg");
+       if (IS_ERR(data->aoncrg))
+               return PTR_ERR(data->aoncrg);
+
+       jh7110_devm_reset_set(dev);
+
+       data->rcdev.ops = &jh7110_reset_ops;
+       data->rcdev.owner = THIS_MODULE;
+       data->rcdev.nr_resets = nr_resets;
+       data->rcdev.dev = &pdev->dev;
+       data->rcdev.of_node = pdev->dev.of_node;
+       spin_lock_init(&data->lock);
+
+       data->asserted = asserted;
+
+       return devm_reset_controller_register(dev, &data->rcdev);
+}
+EXPORT_SYMBOL_GPL(reset_starfive_jh7110_generic_probe);
+
+static int __init jh7110_reset_probe(struct platform_device *pdev)
+{
+       return reset_starfive_jh7110_generic_probe(pdev, jh7110_reset_asserted,
+                                                       RSTN_JH7110_RESET_END);
+}
+
+static const struct of_device_id jh7110_reset_dt_ids[] = {
+       { .compatible = "starfive,jh7110-reset" },
+       { /* sentinel */ }
+};
+
+static struct platform_driver jh7110_reset_driver = {
+       .driver = {
+               .name = "jh7110-reset",
+               .of_match_table = jh7110_reset_dt_ids,
+               .suppress_bind_attrs = true,
+       },
+};
+builtin_platform_driver_probe(jh7110_reset_driver, jh7110_reset_probe);
diff --git a/include/dt-bindings/reset/starfive-jh7110.h b/include/dt-bindings/reset/starfive-jh7110.h
new file mode 100644 (file)
index 0000000..b8cddb2
--- /dev/null
@@ -0,0 +1,187 @@
+/* SPDX-License-Identifier: GPL-2.0 OR MIT */
+/*
+ *  Copyright (C) 2021 samin <samin.guo@starfivetech.com>
+ */
+
+#ifndef __DT_BINDINGS_RESET_STARFIVE_JH7110_H__
+#define __DT_BINDINGS_RESET_STARFIVE_JH7110_H__
+
+/*
+ * group[0]: syscrg: assert0
+ */
+#define RSTN_U0_JTAG2APB_PRESETN       0
+#define        RSTN_U0_SYS_SYSCON_PRESETN      1
+#define        RSTN_U0_SYS_IOMUX_PRESETN       2
+#define        RSTN_U0_U7MC_RST_BUS            3
+#define        RSTN_U0_U7MC_DEBUG              4
+#define        RSTN_U0_U7MC_CORE0              5
+#define        RSTN_U0_U7MC_CORE1              6
+#define        RSTN_U0_U7MC_CORE2              7
+#define        RSTN_U0_U7MC_CORE3              8
+#define        RSTN_U0_U7MC_CORE4              9
+#define        RSTN_U0_U7MC_CORE0_ST           10
+#define        RSTN_U0_U7MC_CORE1_ST           11
+#define        RSTN_U0_U7MC_CORE2_ST           12
+#define        RSTN_U0_U7MC_CORE3_ST           13
+#define        RSTN_U0_U7MC_CORE4_ST           14
+#define        RSTN_U0_U7MC_TRACE_RST0         15
+#define        RSTN_U0_U7MC_TRACE_RST1         16
+#define        RSTN_U0_U7MC_TRACE_RST2         17
+#define        RSTN_U0_U7MC_TRACE_RST3         18
+#define        RSTN_U0_U7MC_TRACE_RST4         19
+#define        RSTN_U0_U7MC_TRACE_COM          20
+#define        RSTN_U0_IMG_GPU_APB             21
+#define        RSTN_U0_IMG_GPU_DOMA            22
+#define        RSTN_U0_NOC_BUS_APB_BUS_N       23
+#define        RSTN_U0_NOC_BUS_AXICFG0_AXI_N   24
+#define        RSTN_U0_NOC_BUS_CPU_AXI_N       25
+#define        RSTN_U0_NOC_BUS_DISP_AXI_N      26
+#define        RSTN_U0_NOC_BUS_GPU_AXI_N       27
+#define        RSTN_U0_NOC_BUS_ISP_AXI_N       28
+#define        RSTN_U0_NOC_BUS_DDRC_N          29
+#define        RSTN_U0_NOC_BUS_STG_AXI_N       30
+#define        RSTN_U0_NOC_BUS_VDEC_AXI_N      31
+/*
+ * group[1]: syscrg: assert1
+ */
+#define        RSTN_U0_NOC_BUS_VENC_AXI_N      32
+#define        RSTN_U0_AXI_CFG1_DEC_AHB        33
+#define        RSTN_U0_AXI_CFG1_DEC_MAIN       34
+#define        RSTN_U0_AXI_CFG0_DEC_MAIN       35
+#define        RSTN_U0_AXI_CFG0_DEC_MAIN_DIV   36
+#define        RSTN_U0_AXI_CFG0_DEC_HIFI4      37
+#define        RSTN_U0_DDR_AXI                 38
+#define        RSTN_U0_DDR_OSC                 39
+#define        RSTN_U0_DDR_APB                 40
+#define        RSTN_U0_DOM_ISP_TOP_N           41
+#define        RSTN_U0_DOM_ISP_TOP_AXI         42
+#define        RSTN_U0_DOM_VOUT_TOP_SRC        43
+#define        RSTN_U0_CODAJ12_AXI             44
+#define        RSTN_U0_CODAJ12_CORE            45
+#define        RSTN_U0_CODAJ12_APB             46
+#define        RSTN_U0_WAVE511_AXI             47
+#define        RSTN_U0_WAVE511_BPU             48
+#define        RSTN_U0_WAVE511_VCE             49
+#define        RSTN_U0_WAVE511_APB             50
+#define        RSTN_U0_VDEC_JPG_ARB_JPG        51
+#define        RSTN_U0_VDEC_JPG_ARB_MAIN       52
+#define        RSTN_U0_AXIMEM_128B_AXI         53
+#define        RSTN_U0_WAVE420L_AXI            54
+#define        RSTN_U0_WAVE420L_BPU            55
+#define        RSTN_U0_WAVE420L_VCE            56
+#define        RSTN_U0_WAVE420L_APB            57
+#define        RSTN_U1_AXIMEM_128B_AXI         58
+#define        RSTN_U2_AXIMEM_128B_AXI         59
+#define        RSTN_U0_INTMEM_ROM_SRAM_ROM     60
+#define        RSTN_U0_CDNS_QSPI_AHB           61
+#define        RSTN_U0_CDNS_QSPI_APB           62
+#define        RSTN_U0_CDNS_QSPI_REF           63
+/*
+ * group[2]: syscrg: assert2
+ */
+#define        RSTN_U0_DW_SDIO_AHB             64
+#define        RSTN_U1_DW_SDIO_AHB             65
+#define        RSTN_U1_DW_GMAC5_AXI64_A_I      66
+#define        RSTN_U1_DW_GMAC5_AXI64_H_N      67
+#define        RSTN_U0_MAILBOX_RRESETN         68
+#define        RSTN_U0_SSP_SPI_APB             69
+#define        RSTN_U1_SSP_SPI_APB             70
+#define        RSTN_U2_SSP_SPI_APB             71
+#define        RSTN_U3_SSP_SPI_APB             72
+#define        RSTN_U4_SSP_SPI_APB             73
+#define        RSTN_U5_SSP_SPI_APB             74
+#define        RSTN_U6_SSP_SPI_APB             75
+#define        RSTN_U0_DW_I2C_APB              76
+#define        RSTN_U1_DW_I2C_APB              77
+#define        RSTN_U2_DW_I2C_APB              78
+#define        RSTN_U3_DW_I2C_APB              79
+#define        RSTN_U4_DW_I2C_APB              80
+#define        RSTN_U5_DW_I2C_APB              81
+#define        RSTN_U6_DW_I2C_APB              82
+#define        RSTN_U0_DW_UART_APB             83
+#define        RSTN_U0_DW_UART_CORE            84
+#define        RSTN_U1_DW_UART_APB             85
+#define        RSTN_U1_DW_UART_CORE            86
+#define        RSTN_U2_DW_UART_APB             87
+#define        RSTN_U2_DW_UART_CORE            88
+#define        RSTN_U3_DW_UART_APB             89
+#define        RSTN_U3_DW_UART_CORE            90
+#define        RSTN_U4_DW_UART_APB             91
+#define        RSTN_U4_DW_UART_CORE            92
+#define        RSTN_U5_DW_UART_APB             93
+#define        RSTN_U5_DW_UART_CORE            94
+#define        RSTN_U0_CDNS_SPDIF_APB          95
+/*
+ * group[3]: syscrg: assert3
+ */
+#define        RSTN_U0_PWMDAC_APB              96
+#define        RSTN_U0_PDM_4MIC_DMIC           97
+#define        RSTN_U0_PDM_4MIC_APB            98
+#define        RSTN_U0_I2SRX_3CH_APB           99
+#define        RSTN_U0_I2SRX_3CH_BCLK          100
+#define        RSTN_U0_I2STX_4CH_APB           101
+#define        RSTN_U0_I2STX_4CH_BCLK          102
+#define        RSTN_U1_I2STX_4CH_APB           103
+#define        RSTN_U1_I2STX_4CH_BCLK          104
+#define        RSTN_U0_TDM16SLOT_AHB           105
+#define        RSTN_U0_TDM16SLOT_TDM           106
+#define        RSTN_U0_TDM16SLOT_APB           107
+#define        RSTN_U0_PWM_8CH_APB             108
+#define        RSTN_U0_DSKIT_WDT_APB           109
+#define        RSTN_U0_DSKIT_WDT_CORE          110
+#define        RSTN_U0_CAN_CTRL_APB            111
+#define        RSTN_U0_CAN_CTRL_CORE           112
+#define        RSTN_U0_CAN_CTRL_TIMER          113
+#define        RSTN_U1_CAN_CTRL_APB            114
+#define        RSTN_U2_CAN_CTRL_CORE           115
+#define        RSTN_U3_CAN_CTRL_TIMER          116
+#define        RSTN_U0_SI5_TIMER_APB           117
+#define        RSTN_U0_SI5_TIMER_TIMER0        118
+#define        RSTN_U0_SI5_TIMER_TIMER1        119
+#define        RSTN_U0_SI5_TIMER_TIMER2        120
+#define        RSTN_U0_SI5_TIMER_TIMER3        121
+#define        RSTN_U0_INT_CTRL_APB            122
+#define        RSTN_U0_TEMP_SENSOR_APB         123
+#define        RSTN_U0_TEMP_SENSOR_TEMP        124
+#define        RSTN_U0_JTAG_CERTIFICATION_N    125
+/*
+ * group[4]: stgcrg
+ */
+#define        RSTN_U0_STG_SYSCON_PRESETN      128
+#define        RSTN_U0_HIFI4_CORE              129
+#define        RSTN_U0_HIFI4_AXI               130
+#define        RSTN_U0_SEC_TOP_HRESETN         131
+#define        RSTN_U0_E24_CORE                132
+#define        RSTN_U0_DW_DMA1P_AXI            133
+#define        RSTN_U0_DW_DMA1P_AHP            134
+#define        RSTN_U0_CDN_USB_AXI             135
+#define        RSTN_U0_CDN_USB_APB             136
+#define        RSTN_U0_CDN_USB_UTMI_APB        137
+#define        RSTN_U0_CDN_USB_PWEUP           138
+#define        RSTN_U0_PLDA_PCIE_AXI_MST0      139
+#define        RSTN_U0_PLDA_PCIE_AXI_SLV0      140
+#define        RSTN_U0_PLDA_PCIE_AXI_SLV       141
+#define        RSTN_U0_PLDA_PCIE_BRG           142
+#define        RSTN_U0_PLDA_PCIE_CORE          143
+#define        RSTN_U0_PLDA_PCIE_APB           144
+#define        RSTN_U1_PLDA_PCIE_AXI_MST0      145
+#define        RSTN_U1_PLDA_PCIE_AXI_SLV0      146
+#define        RSTN_U1_PLDA_PCIE_AXI_SLV       147
+#define        RSTN_U1_PLDA_PCIE_BRG           148
+#define        RSTN_U1_PLDA_PCIE_CORE          149
+#define        RSTN_U1_PLDA_PCIE_APB           150
+/*
+ * group[5]: aoncrg
+ */
+#define        RSTN_U0_DW_GMAC5_AXI64_AXI      160
+#define        RSTN_U0_DW_GMAC5_AXI64_AHB      161
+#define        RSTN_U0_AON_IOMUX_PRESETN       162
+#define        RSTN_U0_PMU_APB                 163
+#define        RSTN_U0_PMU_WKUP                164
+#define        RSTN_U0_RTC_HMS_APB             165
+#define        RSTN_U0_RTC_HMS_CAL             166
+#define        RSTN_U0_RTC_HMS_OSC32K          167
+
+#define        RSTN_JH7110_RESET_END           168
+
+#endif /* __DT_BINDINGS_RESET_STARFIVE_JH7110_H__ */