From 376349232a93645624426db782cafe688054e6d6 Mon Sep 17 00:00:00 2001 From: Eugeniy Paltsev Date: Thu, 14 Sep 2017 17:28:42 +0300 Subject: [PATCH 01/13] ARC: reset: introduce AXS10x reset driver ARC AXS10x boards support custom IP-block which allows to control reset signals of selected peripherals. For example DW GMAC, etc... This block is controlled via memory-mapped register (AKA CREG) which represents up-to 32 reset lines. This regiter is self-clearing so we don't need to deassert line after reset. As of today only the following lines are used: - DW GMAC - line 5 Signed-off-by: Eugeniy Paltsev Signed-off-by: Philipp Zabel --- .../bindings/reset/snps,axs10x-reset.txt | 33 ++++++++ MAINTAINERS | 6 ++ drivers/reset/Kconfig | 6 ++ drivers/reset/Makefile | 1 + drivers/reset/reset-axs10x.c | 83 +++++++++++++++++++ 5 files changed, 129 insertions(+) create mode 100644 Documentation/devicetree/bindings/reset/snps,axs10x-reset.txt create mode 100644 drivers/reset/reset-axs10x.c diff --git a/Documentation/devicetree/bindings/reset/snps,axs10x-reset.txt b/Documentation/devicetree/bindings/reset/snps,axs10x-reset.txt new file mode 100644 index 000000000000..32d8435a41df --- /dev/null +++ b/Documentation/devicetree/bindings/reset/snps,axs10x-reset.txt @@ -0,0 +1,33 @@ +Binding for the AXS10x reset controller + +This binding describes the ARC AXS10x boards custom IP-block which allows +to control reset signals of selected peripherals. For example DW GMAC, etc... +This block is controlled via memory-mapped register (AKA CREG) which +represents up-to 32 reset lines. + +As of today only the following lines are used: + - DW GMAC - line 5 + +This binding uses the common reset binding[1]. + +[1] Documentation/devicetree/bindings/reset/reset.txt + +Required properties: +- compatible: should be "snps,axs10x-reset". +- reg: should always contain pair address - length: for creg reset + bits register. +- #reset-cells: from common reset binding; Should always be set to 1. + +Example: + reset: reset-controller@11220 { + compatible = "snps,axs10x-reset"; + #reset-cells = <1>; + reg = <0x11220 0x4>; + }; + +Specifying reset lines connected to IP modules: + ethernet@.... { + .... + resets = <&reset 5>; + .... + }; diff --git a/MAINTAINERS b/MAINTAINERS index 2281af4b41b6..2cf502eeb774 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12883,6 +12883,12 @@ F: arch/arc/plat-axs10x F: arch/arc/boot/dts/ax* F: Documentation/devicetree/bindings/arc/axs10* +SYNOPSYS AXS10x RESET CONTROLLER DRIVER +M: Eugeniy Paltsev +S: Supported +F: drivers/reset/reset-axs10x.c +F: Documentation/devicetree/bindings/reset/snps,axs10x-reset.txt + SYNOPSYS DESIGNWARE DMAC DRIVER M: Viresh Kumar M: Andy Shevchenko diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index e0c393214264..23ec43f99d9a 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -28,6 +28,12 @@ config RESET_ATH79 This enables the ATH79 reset controller driver that supports the AR71xx SoC reset controller. +config RESET_AXS10X + bool "AXS10x Reset Driver" if COMPILE_TEST + default ARC_PLAT_AXS10X + help + This enables the reset controller driver for AXS10x. + config RESET_BERLIN bool "Berlin Reset Driver" if COMPILE_TEST default ARCH_BERLIN diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index d368367110e5..7579dba7b185 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_ARCH_STI) += sti/ obj-$(CONFIG_ARCH_TEGRA) += tegra/ obj-$(CONFIG_RESET_A10SR) += reset-a10sr.o obj-$(CONFIG_RESET_ATH79) += reset-ath79.o +obj-$(CONFIG_RESET_AXS10X) += reset-axs10x.o obj-$(CONFIG_RESET_BERLIN) += reset-berlin.o obj-$(CONFIG_RESET_HSDK_V1) += reset-hsdk-v1.o obj-$(CONFIG_RESET_IMX7) += reset-imx7.o diff --git a/drivers/reset/reset-axs10x.c b/drivers/reset/reset-axs10x.c new file mode 100644 index 000000000000..afb298e46bd9 --- /dev/null +++ b/drivers/reset/reset-axs10x.c @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2017 Synopsys. + * + * Synopsys AXS10x reset driver. + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include + +#define to_axs10x_rst(p) container_of((p), struct axs10x_rst, rcdev) + +#define AXS10X_MAX_RESETS 32 + +struct axs10x_rst { + void __iomem *regs_rst; + spinlock_t lock; + struct reset_controller_dev rcdev; +}; + +static int axs10x_reset_reset(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct axs10x_rst *rst = to_axs10x_rst(rcdev); + unsigned long flags; + + spin_lock_irqsave(&rst->lock, flags); + writel(BIT(id), rst->regs_rst); + spin_unlock_irqrestore(&rst->lock, flags); + + return 0; +} + +static const struct reset_control_ops axs10x_reset_ops = { + .reset = axs10x_reset_reset, +}; + +static int axs10x_reset_probe(struct platform_device *pdev) +{ + struct axs10x_rst *rst; + struct resource *mem; + + rst = devm_kzalloc(&pdev->dev, sizeof(*rst), GFP_KERNEL); + if (!rst) + return -ENOMEM; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + rst->regs_rst = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(rst->regs_rst)) + return PTR_ERR(rst->regs_rst); + + spin_lock_init(&rst->lock); + + rst->rcdev.owner = THIS_MODULE; + rst->rcdev.ops = &axs10x_reset_ops; + rst->rcdev.of_node = pdev->dev.of_node; + rst->rcdev.nr_resets = AXS10X_MAX_RESETS; + + return devm_reset_controller_register(&pdev->dev, &rst->rcdev); +} + +static const struct of_device_id axs10x_reset_dt_match[] = { + { .compatible = "snps,axs10x-reset" }, + { }, +}; + +static struct platform_driver axs10x_reset_driver = { + .probe = axs10x_reset_probe, + .driver = { + .name = "axs10x-reset", + .of_match_table = axs10x_reset_dt_match, + }, +}; +builtin_platform_driver(axs10x_reset_driver); + +MODULE_AUTHOR("Eugeniy Paltsev "); +MODULE_DESCRIPTION("Synopsys AXS10x reset driver"); +MODULE_LICENSE("GPL v2"); From f450f28e70a2378d9d6ded0932fe480055888cfa Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Fri, 22 Sep 2017 13:42:47 -0500 Subject: [PATCH 02/13] reset: socfpga: fix for 64-bit compilation The SoCFPGA Stratix10 reset controller has 32-bit registers. Thus, we cannot use BITS_PER_LONG in computing the register and bit offset. Instead, we should be using the width of the hardware register for the calculation. Signed-off-by: Dinh Nguyen Signed-off-by: Philipp Zabel --- drivers/reset/reset-socfpga.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/reset/reset-socfpga.c b/drivers/reset/reset-socfpga.c index c60904ff40b8..3907bbc9c6cf 100644 --- a/drivers/reset/reset-socfpga.c +++ b/drivers/reset/reset-socfpga.c @@ -40,8 +40,9 @@ static int socfpga_reset_assert(struct reset_controller_dev *rcdev, struct socfpga_reset_data *data = container_of(rcdev, struct socfpga_reset_data, rcdev); - int bank = id / BITS_PER_LONG; - int offset = id % BITS_PER_LONG; + int reg_width = sizeof(u32); + int bank = id / (reg_width * BITS_PER_BYTE); + int offset = id % (reg_width * BITS_PER_BYTE); unsigned long flags; u32 reg; @@ -61,8 +62,9 @@ static int socfpga_reset_deassert(struct reset_controller_dev *rcdev, struct socfpga_reset_data, rcdev); - int bank = id / BITS_PER_LONG; - int offset = id % BITS_PER_LONG; + int reg_width = sizeof(u32); + int bank = id / (reg_width * BITS_PER_BYTE); + int offset = id % (reg_width * BITS_PER_BYTE); unsigned long flags; u32 reg; @@ -81,8 +83,9 @@ static int socfpga_reset_status(struct reset_controller_dev *rcdev, { struct socfpga_reset_data *data = container_of(rcdev, struct socfpga_reset_data, rcdev); - int bank = id / BITS_PER_LONG; - int offset = id % BITS_PER_LONG; + int reg_width = sizeof(u32); + int bank = id / (reg_width * BITS_PER_BYTE); + int offset = id % (reg_width * BITS_PER_BYTE); u32 reg; reg = readl(data->membase + (bank * BANK_INCREMENT)); @@ -132,7 +135,7 @@ static int socfpga_reset_probe(struct platform_device *pdev) spin_lock_init(&data->lock); data->rcdev.owner = THIS_MODULE; - data->rcdev.nr_resets = NR_BANKS * BITS_PER_LONG; + data->rcdev.nr_resets = NR_BANKS * (sizeof(u32) * BITS_PER_BYTE); data->rcdev.ops = &socfpga_reset_ops; data->rcdev.of_node = pdev->dev.of_node; From 4c05c4a5ee64616583f836938ccf48dc01dd52cf Mon Sep 17 00:00:00 2001 From: Kunihiko Hayashi Date: Mon, 28 Aug 2017 18:59:38 +0900 Subject: [PATCH 03/13] reset: uniphier: add ethernet reset control support Add reset lines for ethernet controller on Pro4, PXs2, LD11 and LD20 SoCs. Signed-off-by: Kunihiko Hayashi Acked-by: Masahiro Yamada Signed-off-by: Philipp Zabel --- drivers/reset/reset-uniphier.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/reset/reset-uniphier.c b/drivers/reset/reset-uniphier.c index bda2dd196ae5..6e40f7db4243 100644 --- a/drivers/reset/reset-uniphier.c +++ b/drivers/reset/reset-uniphier.c @@ -58,6 +58,7 @@ static const struct uniphier_reset_data uniphier_ld4_sys_reset_data[] = { static const struct uniphier_reset_data uniphier_pro4_sys_reset_data[] = { UNIPHIER_RESETX(2, 0x2000, 2), /* NAND */ + UNIPHIER_RESETX(6, 0x2000, 12), /* Ether */ UNIPHIER_RESETX(8, 0x2000, 10), /* STDMAC (HSC, MIO, RLE) */ UNIPHIER_RESETX(12, 0x2000, 6), /* GIO (Ether, SATA, USB3) */ UNIPHIER_RESETX(14, 0x2000, 17), /* USB30 */ @@ -76,6 +77,7 @@ static const struct uniphier_reset_data uniphier_pro5_sys_reset_data[] = { static const struct uniphier_reset_data uniphier_pxs2_sys_reset_data[] = { UNIPHIER_RESETX(2, 0x2000, 2), /* NAND */ + UNIPHIER_RESETX(6, 0x2000, 12), /* Ether */ UNIPHIER_RESETX(8, 0x2000, 10), /* STDMAC (HSC, RLE) */ UNIPHIER_RESETX(14, 0x2000, 17), /* USB30 */ UNIPHIER_RESETX(15, 0x2004, 17), /* USB31 */ @@ -92,6 +94,7 @@ static const struct uniphier_reset_data uniphier_pxs2_sys_reset_data[] = { static const struct uniphier_reset_data uniphier_ld11_sys_reset_data[] = { UNIPHIER_RESETX(2, 0x200c, 0), /* NAND */ UNIPHIER_RESETX(4, 0x200c, 2), /* eMMC */ + UNIPHIER_RESETX(6, 0x200c, 6), /* Ether */ UNIPHIER_RESETX(8, 0x200c, 8), /* STDMAC (HSC, MIO) */ UNIPHIER_RESETX(40, 0x2008, 0), /* AIO */ UNIPHIER_RESETX(41, 0x2008, 1), /* EVEA */ @@ -102,6 +105,7 @@ static const struct uniphier_reset_data uniphier_ld11_sys_reset_data[] = { static const struct uniphier_reset_data uniphier_ld20_sys_reset_data[] = { UNIPHIER_RESETX(2, 0x200c, 0), /* NAND */ UNIPHIER_RESETX(4, 0x200c, 2), /* eMMC */ + UNIPHIER_RESETX(6, 0x200c, 6), /* Ether */ UNIPHIER_RESETX(8, 0x200c, 8), /* STDMAC (HSC) */ UNIPHIER_RESETX(12, 0x200c, 5), /* GIO (PCIe, USB3) */ UNIPHIER_RESETX(16, 0x200c, 12), /* USB30-PHY0 */ From db21f9cfd5adf7544f64573c1ea4c4f3876d898e Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Wed, 20 Sep 2017 10:25:41 -0500 Subject: [PATCH 04/13] reset: socfpga: build the reset-socfpga for Stratix10 SOC Enable the reset driver to get built for the Stratix10 platform. Signed-off-by: Dinh Nguyen Signed-off-by: Philipp Zabel --- drivers/reset/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index e2baecbb9dd3..1c88af294724 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -77,7 +77,7 @@ config RESET_PISTACHIO config RESET_SOCFPGA bool "SoCFPGA Reset Driver" if COMPILE_TEST - default ARCH_SOCFPGA + default ARCH_SOCFPGA || ARCH_STRATIX10 help This enables the reset controller driver for Altera SoCFPGAs. From 7f4fbf79f4d4c00466e1b4158b17c5a095c83f2c Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 20 Sep 2017 17:40:16 +0800 Subject: [PATCH 05/13] reset: mediatek: add reset controller dt-bindings required header for MT7622 SoC Add the reset controller dt-bindings exported from infracfg, pericfg, hifsys and ethsys which could be found on MT7622 SoC. So that we can reference them from within a device-tree file. Signed-off-by: Sean Wang Signed-off-by: Philipp Zabel --- include/dt-bindings/reset/mt7622-reset.h | 94 ++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 include/dt-bindings/reset/mt7622-reset.h diff --git a/include/dt-bindings/reset/mt7622-reset.h b/include/dt-bindings/reset/mt7622-reset.h new file mode 100644 index 000000000000..234052f80417 --- /dev/null +++ b/include/dt-bindings/reset/mt7622-reset.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2017 MediaTek Inc. + * Author: Sean Wang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _DT_BINDINGS_RESET_CONTROLLER_MT7622 +#define _DT_BINDINGS_RESET_CONTROLLER_MT7622 + +/* INFRACFG resets */ +#define MT7622_INFRA_EMI_REG_RST 0 +#define MT7622_INFRA_DRAMC0_A0_RST 1 +#define MT7622_INFRA_APCIRQ_EINT_RST 3 +#define MT7622_INFRA_APXGPT_RST 4 +#define MT7622_INFRA_SCPSYS_RST 5 +#define MT7622_INFRA_PMIC_WRAP_RST 7 +#define MT7622_INFRA_IRRX_RST 9 +#define MT7622_INFRA_EMI_RST 16 +#define MT7622_INFRA_WED0_RST 17 +#define MT7622_INFRA_DRAMC_RST 18 +#define MT7622_INFRA_CCI_INTF_RST 19 +#define MT7622_INFRA_TRNG_RST 21 +#define MT7622_INFRA_SYSIRQ_RST 22 +#define MT7622_INFRA_WED1_RST 25 + +/* PERICFG Subsystem resets */ +#define MT7622_PERI_UART0_SW_RST 0 +#define MT7622_PERI_UART1_SW_RST 1 +#define MT7622_PERI_UART2_SW_RST 2 +#define MT7622_PERI_UART3_SW_RST 3 +#define MT7622_PERI_UART4_SW_RST 4 +#define MT7622_PERI_BTIF_SW_RST 6 +#define MT7622_PERI_PWM_SW_RST 8 +#define MT7622_PERI_AUXADC_SW_RST 10 +#define MT7622_PERI_DMA_SW_RST 11 +#define MT7622_PERI_IRTX_SW_RST 13 +#define MT7622_PERI_NFI_SW_RST 14 +#define MT7622_PERI_THERM_SW_RST 16 +#define MT7622_PERI_MSDC0_SW_RST 19 +#define MT7622_PERI_MSDC1_SW_RST 20 +#define MT7622_PERI_I2C0_SW_RST 22 +#define MT7622_PERI_I2C1_SW_RST 23 +#define MT7622_PERI_I2C2_SW_RST 24 +#define MT7622_PERI_SPI0_SW_RST 33 +#define MT7622_PERI_SPI1_SW_RST 34 +#define MT7622_PERI_FLASHIF_SW_RST 36 + +/* TOPRGU resets */ +#define MT7622_TOPRGU_INFRA_RST 0 +#define MT7622_TOPRGU_ETHDMA_RST 1 +#define MT7622_TOPRGU_DDRPHY_RST 6 +#define MT7622_TOPRGU_INFRA_AO_RST 8 +#define MT7622_TOPRGU_CONN_RST 9 +#define MT7622_TOPRGU_APMIXED_RST 10 +#define MT7622_TOPRGU_CONN_MCU_RST 12 + +/* PCIe/SATA Subsystem resets */ +#define MT7622_SATA_PHY_REG_RST 12 +#define MT7622_SATA_PHY_SW_RST 13 +#define MT7622_SATA_AXI_BUS_RST 15 +#define MT7622_PCIE1_CORE_RST 19 +#define MT7622_PCIE1_MMIO_RST 20 +#define MT7622_PCIE1_HRST 21 +#define MT7622_PCIE1_USER_RST 22 +#define MT7622_PCIE1_PIPE_RST 23 +#define MT7622_PCIE0_CORE_RST 27 +#define MT7622_PCIE0_MMIO_RST 28 +#define MT7622_PCIE0_HRST 29 +#define MT7622_PCIE0_USER_RST 30 +#define MT7622_PCIE0_PIPE_RST 31 + +/* SSUSB Subsystem resets */ +#define MT7622_SSUSB_PHY_PWR_RST 3 +#define MT7622_SSUSB_MAC_PWR_RST 4 + +/* ETHSYS Subsystem resets */ +#define MT7622_ETHSYS_SYS_RST 0 +#define MT7622_ETHSYS_MCM_RST 2 +#define MT7622_ETHSYS_HSDMA_RST 5 +#define MT7622_ETHSYS_FE_RST 6 +#define MT7622_ETHSYS_GMAC_RST 23 +#define MT7622_ETHSYS_EPHY_RST 24 +#define MT7622_ETHSYS_CRYPTO_RST 29 +#define MT7622_ETHSYS_PPE_RST 31 + +#endif /* _DT_BINDINGS_RESET_CONTROLLER_MT7622 */ From 2a158f888853cb11140532be79883c8faf31c83d Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 5 Oct 2017 11:30:57 +0900 Subject: [PATCH 06/13] reset: uniphier: add PXs3 reset data Add basic reset data for Socionext's new SoC PXs3. Signed-off-by: Masahiro Yamada Signed-off-by: Philipp Zabel --- .../bindings/reset/uniphier-reset.txt | 3 +++ drivers/reset/reset-uniphier.c | 26 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/Documentation/devicetree/bindings/reset/uniphier-reset.txt b/Documentation/devicetree/bindings/reset/uniphier-reset.txt index 68a6f487c409..93efed629900 100644 --- a/Documentation/devicetree/bindings/reset/uniphier-reset.txt +++ b/Documentation/devicetree/bindings/reset/uniphier-reset.txt @@ -13,6 +13,7 @@ Required properties: "socionext,uniphier-pxs2-reset" - for PXs2/LD6b SoC "socionext,uniphier-ld11-reset" - for LD11 SoC "socionext,uniphier-ld20-reset" - for LD20 SoC + "socionext,uniphier-pxs3-reset" - for PXs3 SoC - #reset-cells: should be 1. Example: @@ -44,6 +45,7 @@ Required properties: "socionext,uniphier-ld11-mio-reset" - for LD11 SoC (MIO) "socionext,uniphier-ld11-sd-reset" - for LD11 SoC (SD) "socionext,uniphier-ld20-sd-reset" - for LD20 SoC + "socionext,uniphier-pxs3-sd-reset" - for PXs3 SoC - #reset-cells: should be 1. Example: @@ -74,6 +76,7 @@ Required properties: "socionext,uniphier-pxs2-peri-reset" - for PXs2/LD6b SoC "socionext,uniphier-ld11-peri-reset" - for LD11 SoC "socionext,uniphier-ld20-peri-reset" - for LD20 SoC + "socionext,uniphier-pxs3-peri-reset" - for PXs3 SoC - #reset-cells: should be 1. Example: diff --git a/drivers/reset/reset-uniphier.c b/drivers/reset/reset-uniphier.c index 6e40f7db4243..e8bb023ff15e 100644 --- a/drivers/reset/reset-uniphier.c +++ b/drivers/reset/reset-uniphier.c @@ -118,6 +118,20 @@ static const struct uniphier_reset_data uniphier_ld20_sys_reset_data[] = { UNIPHIER_RESET_END, }; +static const struct uniphier_reset_data uniphier_pxs3_sys_reset_data[] = { + UNIPHIER_RESETX(2, 0x200c, 0), /* NAND */ + UNIPHIER_RESETX(4, 0x200c, 2), /* eMMC */ + UNIPHIER_RESETX(8, 0x200c, 12), /* STDMAC */ + UNIPHIER_RESETX(12, 0x200c, 4), /* USB30 link (GIO0) */ + UNIPHIER_RESETX(13, 0x200c, 5), /* USB31 link (GIO1) */ + UNIPHIER_RESETX(16, 0x200c, 16), /* USB30-PHY0 */ + UNIPHIER_RESETX(17, 0x200c, 18), /* USB30-PHY1 */ + UNIPHIER_RESETX(18, 0x200c, 20), /* USB30-PHY2 */ + UNIPHIER_RESETX(20, 0x200c, 17), /* USB31-PHY0 */ + UNIPHIER_RESETX(21, 0x200c, 19), /* USB31-PHY1 */ + UNIPHIER_RESET_END, +}; + /* Media I/O reset data */ #define UNIPHIER_MIO_RESET_SD(id, ch) \ UNIPHIER_RESETX((id), 0x110 + 0x200 * (ch), 0) @@ -363,6 +377,10 @@ static const struct of_device_id uniphier_reset_match[] = { .compatible = "socionext,uniphier-ld20-reset", .data = uniphier_ld20_sys_reset_data, }, + { + .compatible = "socionext,uniphier-pxs3-reset", + .data = uniphier_pxs3_sys_reset_data, + }, /* Media I/O reset, SD reset */ { .compatible = "socionext,uniphier-ld4-mio-reset", @@ -396,6 +414,10 @@ static const struct of_device_id uniphier_reset_match[] = { .compatible = "socionext,uniphier-ld20-sd-reset", .data = uniphier_pro5_sd_reset_data, }, + { + .compatible = "socionext,uniphier-pxs3-sd-reset", + .data = uniphier_pro5_sd_reset_data, + }, /* Peripheral reset */ { .compatible = "socionext,uniphier-ld4-peri-reset", @@ -425,6 +447,10 @@ static const struct of_device_id uniphier_reset_match[] = { .compatible = "socionext,uniphier-ld20-peri-reset", .data = uniphier_pro4_peri_reset_data, }, + { + .compatible = "socionext,uniphier-pxs3-peri-reset", + .data = uniphier_pro4_peri_reset_data, + }, /* Analog signal amplifiers reset */ { .compatible = "socionext,uniphier-ld11-adamv-reset", From a5a10afe04efad46e8eec20f70b7b91a411fcd8e Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 17 Oct 2017 12:19:18 +0200 Subject: [PATCH 07/13] reset: meson: add level reset support for GX SoC family The Amlogic GX SoC family embeds alternate registers to drive the reset levels next to the pulse registers. This patch adds support for level reset handling on the GX family only. The Meson8 family has an alternate way to handle level reset. Signed-off-by: Neil Armstrong Signed-off-by: Philipp Zabel --- drivers/reset/reset-meson.c | 62 ++++++++++++++++++++++++++++++++++--- 1 file changed, 58 insertions(+), 4 deletions(-) diff --git a/drivers/reset/reset-meson.c b/drivers/reset/reset-meson.c index a8b915eb8b58..f3b9d6989267 100644 --- a/drivers/reset/reset-meson.c +++ b/drivers/reset/reset-meson.c @@ -62,13 +62,16 @@ #include #include #include +#include #define REG_COUNT 8 #define BITS_PER_REG 32 +#define LEVEL_OFFSET 0x7c struct meson_reset { void __iomem *reg_base; struct reset_controller_dev rcdev; + spinlock_t lock; }; static int meson_reset_reset(struct reset_controller_dev *rcdev, @@ -88,18 +91,63 @@ static int meson_reset_reset(struct reset_controller_dev *rcdev, return 0; } -static const struct reset_control_ops meson_reset_ops = { +static int meson_reset_level(struct reset_controller_dev *rcdev, + unsigned long id, bool assert) +{ + struct meson_reset *data = + container_of(rcdev, struct meson_reset, rcdev); + unsigned int bank = id / BITS_PER_REG; + unsigned int offset = id % BITS_PER_REG; + void __iomem *reg_addr = data->reg_base + LEVEL_OFFSET + (bank << 2); + unsigned long flags; + u32 reg; + + spin_lock_irqsave(&data->lock, flags); + + reg = readl(reg_addr); + if (assert) + writel(reg & ~BIT(offset), reg_addr); + else + writel(reg | BIT(offset), reg_addr); + + spin_unlock_irqrestore(&data->lock, flags); + + return 0; +} + +static int meson_reset_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return meson_reset_level(rcdev, id, true); +} + +static int meson_reset_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return meson_reset_level(rcdev, id, false); +} + +static const struct reset_control_ops meson_reset_meson8_ops = { .reset = meson_reset_reset, }; +static const struct reset_control_ops meson_reset_gx_ops = { + .reset = meson_reset_reset, + .assert = meson_reset_assert, + .deassert = meson_reset_deassert, +}; + static const struct of_device_id meson_reset_dt_ids[] = { - { .compatible = "amlogic,meson8b-reset", }, - { .compatible = "amlogic,meson-gxbb-reset", }, + { .compatible = "amlogic,meson8b-reset", + .data = &meson_reset_meson8_ops, }, + { .compatible = "amlogic,meson-gxbb-reset", + .data = &meson_reset_gx_ops, }, { /* sentinel */ }, }; static int meson_reset_probe(struct platform_device *pdev) { + const struct reset_control_ops *ops; struct meson_reset *data; struct resource *res; @@ -107,6 +155,10 @@ static int meson_reset_probe(struct platform_device *pdev) if (!data) return -ENOMEM; + ops = of_device_get_match_data(&pdev->dev); + if (!ops) + return -EINVAL; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); data->reg_base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(data->reg_base)) @@ -114,9 +166,11 @@ static int meson_reset_probe(struct platform_device *pdev) platform_set_drvdata(pdev, data); + spin_lock_init(&data->lock); + data->rcdev.owner = THIS_MODULE; data->rcdev.nr_resets = REG_COUNT * BITS_PER_REG; - data->rcdev.ops = &meson_reset_ops; + data->rcdev.ops = ops; data->rcdev.of_node = pdev->dev.of_node; return devm_reset_controller_register(&pdev->dev, &data->rcdev); From 7e8838fe59515860823233353227e89b82b8794e Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 17 Oct 2017 12:19:34 +0200 Subject: [PATCH 08/13] reset: meson: remove unneeded check in meson_reset_reset The if (bank >= REG_COUNT) is not need since already checked by the default rcdev->of_xlate implementation which guarantees that id < rcdev->nr_resets. Suggested-by: Philipp Zabel Signed-off-by: Neil Armstrong Signed-off-by: Philipp Zabel --- drivers/reset/reset-meson.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/reset/reset-meson.c b/drivers/reset/reset-meson.c index f3b9d6989267..c419a3753d00 100644 --- a/drivers/reset/reset-meson.c +++ b/drivers/reset/reset-meson.c @@ -83,9 +83,6 @@ static int meson_reset_reset(struct reset_controller_dev *rcdev, unsigned int offset = id % BITS_PER_REG; void __iomem *reg_addr = data->reg_base + (bank << 2); - if (bank >= REG_COUNT) - return -EINVAL; - writel(BIT(offset), reg_addr); return 0; From 81c22ad0cc7db056408d6089c9303b2f6e486518 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 11 Aug 2017 12:58:43 +0200 Subject: [PATCH 09/13] reset: add reset-simple to unify socfpga, stm32, sunxi, and zx2967 Copy reusable parts from the sunxi driver, to add a driver for simple reset controllers with reset lines that can be controlled by toggling bits in exclusive, contiguous register ranges using read-modify-write cycles under a spinlock. The following patches will replace compatible reset drivers with reset-simple, extending it where necessary. Signed-off-by: Philipp Zabel Reviewed-by: Alexandru Gagniuc Reviewed-by: Chen-Yu Tsai --- drivers/reset/Kconfig | 10 +++ drivers/reset/Makefile | 1 + drivers/reset/reset-simple.c | 134 +++++++++++++++++++++++++++++++++++ drivers/reset/reset-simple.h | 41 +++++++++++ 4 files changed, 186 insertions(+) create mode 100644 drivers/reset/reset-simple.c create mode 100644 drivers/reset/reset-simple.h diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 1c88af294724..392e65187cd5 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -75,6 +75,16 @@ config RESET_PISTACHIO help This enables the reset driver for ImgTec Pistachio SoCs. +config RESET_SIMPLE + bool "Simple Reset Controller Driver" if COMPILE_TEST + default ARCH_SUNXI + help + This enables a simple reset controller driver for reset lines that + that can be asserted and deasserted by toggling bits in a contiguous, + exclusive register space. + + Currently this driver supports Allwinner SoCs. + config RESET_SOCFPGA bool "SoCFPGA Reset Driver" if COMPILE_TEST default ARCH_SOCFPGA || ARCH_STRATIX10 diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index af1c15c330b3..ddd3eeb19356 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_RESET_LPC18XX) += reset-lpc18xx.o obj-$(CONFIG_RESET_MESON) += reset-meson.o obj-$(CONFIG_RESET_OXNAS) += reset-oxnas.o obj-$(CONFIG_RESET_PISTACHIO) += reset-pistachio.o +obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o obj-$(CONFIG_RESET_STM32) += reset-stm32.o obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o diff --git a/drivers/reset/reset-simple.c b/drivers/reset/reset-simple.c new file mode 100644 index 000000000000..a5119457cec6 --- /dev/null +++ b/drivers/reset/reset-simple.c @@ -0,0 +1,134 @@ +/* + * Simple Reset Controller Driver + * + * Copyright (C) 2017 Pengutronix, Philipp Zabel + * + * Based on Allwinner SoCs Reset Controller driver + * + * Copyright 2013 Maxime Ripard + * + * Maxime Ripard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "reset-simple.h" + +static inline struct reset_simple_data * +to_reset_simple_data(struct reset_controller_dev *rcdev) +{ + return container_of(rcdev, struct reset_simple_data, rcdev); +} + +static int reset_simple_update(struct reset_controller_dev *rcdev, + unsigned long id, bool assert) +{ + struct reset_simple_data *data = to_reset_simple_data(rcdev); + int reg_width = sizeof(u32); + int bank = id / (reg_width * BITS_PER_BYTE); + int offset = id % (reg_width * BITS_PER_BYTE); + unsigned long flags; + u32 reg; + + spin_lock_irqsave(&data->lock, flags); + + reg = readl(data->membase + (bank * reg_width)); + if (assert ^ data->active_low) + reg |= BIT(offset); + else + reg &= ~BIT(offset); + writel(reg, data->membase + (bank * reg_width)); + + spin_unlock_irqrestore(&data->lock, flags); + + return 0; +} + +static int reset_simple_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return reset_simple_update(rcdev, id, true); +} + +static int reset_simple_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return reset_simple_update(rcdev, id, false); +} + +const struct reset_control_ops reset_simple_ops = { + .assert = reset_simple_assert, + .deassert = reset_simple_deassert, +}; + +/** + * struct reset_simple_devdata - simple reset controller properties + * @active_low: if true, bits are cleared to assert the reset. Otherwise, bits + * are set to assert the reset. + */ +struct reset_simple_devdata { + bool active_low; +}; + +static const struct reset_simple_devdata reset_simple_active_low = { + .active_low = true, +}; + +static const struct of_device_id reset_simple_dt_ids[] = { + { .compatible = "allwinner,sun6i-a31-clock-reset", + .data = &reset_simple_active_low }, + { /* sentinel */ }, +}; + +static int reset_simple_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct reset_simple_devdata *devdata; + struct reset_simple_data *data; + void __iomem *membase; + struct resource *res; + + devdata = of_device_get_match_data(dev); + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + membase = devm_ioremap_resource(dev, res); + if (IS_ERR(membase)) + return PTR_ERR(membase); + + spin_lock_init(&data->lock); + data->membase = membase; + data->rcdev.owner = THIS_MODULE; + data->rcdev.nr_resets = resource_size(res) * BITS_PER_BYTE; + data->rcdev.ops = &reset_simple_ops; + data->rcdev.of_node = dev->of_node; + + if (devdata) + data->active_low = devdata->active_low; + + return devm_reset_controller_register(dev, &data->rcdev); +} + +static struct platform_driver reset_simple_driver = { + .probe = reset_simple_probe, + .driver = { + .name = "simple-reset", + .of_match_table = reset_simple_dt_ids, + }, +}; +builtin_platform_driver(reset_simple_driver); diff --git a/drivers/reset/reset-simple.h b/drivers/reset/reset-simple.h new file mode 100644 index 000000000000..39af2014b5f1 --- /dev/null +++ b/drivers/reset/reset-simple.h @@ -0,0 +1,41 @@ +/* + * Simple Reset Controller ops + * + * Based on Allwinner SoCs Reset Controller driver + * + * Copyright 2013 Maxime Ripard + * + * Maxime Ripard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __RESET_SIMPLE_H__ +#define __RESET_SIMPLE_H__ + +#include +#include +#include + +/** + * struct reset_simple_data - driver data for simple reset controllers + * @lock: spinlock to protect registers during read-modify-write cycles + * @membase: memory mapped I/O register range + * @rcdev: reset controller device base structure + * @active_low: if true, bits are cleared to assert the reset. Otherwise, bits + * are set to assert the reset. Note that this says nothing about + * the voltage level of the actual reset line. + */ +struct reset_simple_data { + spinlock_t lock; + void __iomem *membase; + struct reset_controller_dev rcdev; + bool active_low; +}; + +extern const struct reset_control_ops reset_simple_ops; + +#endif /* __RESET_SIMPLE_H__ */ From e13c205ac358d4c956c36572b6b660b9e45b3bda Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 11 Aug 2017 12:58:43 +0200 Subject: [PATCH 10/13] reset: sunxi: use reset-simple driver Use the newly created copies in the reset-simple driver to replace the sunxi platform driver code and reset operations. The separate sunxi driver still remains to register the early reset controllers, but it reuses the reset operations in reset-simple. Signed-off-by: Philipp Zabel Reviewed-by: Alexandru Gagniuc Reviewed-by: Chen-Yu Tsai --- drivers/reset/Kconfig | 1 + drivers/reset/reset-sunxi.c | 104 +++--------------------------------- 2 files changed, 7 insertions(+), 98 deletions(-) diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 392e65187cd5..a14c0fe49877 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -100,6 +100,7 @@ config RESET_STM32 config RESET_SUNXI bool "Allwinner SoCs Reset Driver" if COMPILE_TEST && !ARCH_SUNXI default ARCH_SUNXI + select RESET_SIMPLE help This enables the reset driver for Allwinner SoCs. diff --git a/drivers/reset/reset-sunxi.c b/drivers/reset/reset-sunxi.c index 2c7dd1fd08df..db9a1a75523f 100644 --- a/drivers/reset/reset-sunxi.c +++ b/drivers/reset/reset-sunxi.c @@ -22,64 +22,11 @@ #include #include -struct sunxi_reset_data { - spinlock_t lock; - void __iomem *membase; - struct reset_controller_dev rcdev; -}; - -static int sunxi_reset_assert(struct reset_controller_dev *rcdev, - unsigned long id) -{ - struct sunxi_reset_data *data = container_of(rcdev, - struct sunxi_reset_data, - rcdev); - int reg_width = sizeof(u32); - int bank = id / (reg_width * BITS_PER_BYTE); - int offset = id % (reg_width * BITS_PER_BYTE); - unsigned long flags; - u32 reg; - - spin_lock_irqsave(&data->lock, flags); - - reg = readl(data->membase + (bank * reg_width)); - writel(reg & ~BIT(offset), data->membase + (bank * reg_width)); - - spin_unlock_irqrestore(&data->lock, flags); - - return 0; -} - -static int sunxi_reset_deassert(struct reset_controller_dev *rcdev, - unsigned long id) -{ - struct sunxi_reset_data *data = container_of(rcdev, - struct sunxi_reset_data, - rcdev); - int reg_width = sizeof(u32); - int bank = id / (reg_width * BITS_PER_BYTE); - int offset = id % (reg_width * BITS_PER_BYTE); - unsigned long flags; - u32 reg; - - spin_lock_irqsave(&data->lock, flags); - - reg = readl(data->membase + (bank * reg_width)); - writel(reg | BIT(offset), data->membase + (bank * reg_width)); - - spin_unlock_irqrestore(&data->lock, flags); - - return 0; -} - -static const struct reset_control_ops sunxi_reset_ops = { - .assert = sunxi_reset_assert, - .deassert = sunxi_reset_deassert, -}; +#include "reset-simple.h" static int sunxi_reset_init(struct device_node *np) { - struct sunxi_reset_data *data; + struct reset_simple_data *data; struct resource res; resource_size_t size; int ret; @@ -108,8 +55,9 @@ static int sunxi_reset_init(struct device_node *np) data->rcdev.owner = THIS_MODULE; data->rcdev.nr_resets = size * 8; - data->rcdev.ops = &sunxi_reset_ops; + data->rcdev.ops = &reset_simple_ops; data->rcdev.of_node = np; + data->active_low = true; return reset_controller_register(&data->rcdev); @@ -122,6 +70,8 @@ err_alloc: * These are the reset controller we need to initialize early on in * our system, before we can even think of using a regular device * driver for it. + * The controllers that we can register through the regular device + * model are handled by the simple reset driver directly. */ static const struct of_device_id sunxi_early_reset_dt_ids[] __initconst = { { .compatible = "allwinner,sun6i-a31-ahb1-reset", }, @@ -135,45 +85,3 @@ void __init sun6i_reset_init(void) for_each_matching_node(np, sunxi_early_reset_dt_ids) sunxi_reset_init(np); } - -/* - * And these are the controllers we can register through the regular - * device model. - */ -static const struct of_device_id sunxi_reset_dt_ids[] = { - { .compatible = "allwinner,sun6i-a31-clock-reset", }, - { /* sentinel */ }, -}; - -static int sunxi_reset_probe(struct platform_device *pdev) -{ - struct sunxi_reset_data *data; - struct resource *res; - - data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); - if (!data) - return -ENOMEM; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - data->membase = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(data->membase)) - return PTR_ERR(data->membase); - - spin_lock_init(&data->lock); - - data->rcdev.owner = THIS_MODULE; - data->rcdev.nr_resets = resource_size(res) * 8; - data->rcdev.ops = &sunxi_reset_ops; - data->rcdev.of_node = pdev->dev.of_node; - - return devm_reset_controller_register(&pdev->dev, &data->rcdev); -} - -static struct platform_driver sunxi_reset_driver = { - .probe = sunxi_reset_probe, - .driver = { - .name = "sunxi-reset", - .of_match_table = sunxi_reset_dt_ids, - }, -}; -builtin_platform_driver(sunxi_reset_driver); From adf20d7ce7c3591e049910c7760edd9c7da4a246 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 11 Aug 2017 13:02:19 +0200 Subject: [PATCH 11/13] reset: socfpga: use the reset-simple driver Add reset line status readback, inverted status support, and socfpga device tree quirks to the simple reset driver, and use it to replace the socfpga driver. Signed-off-by: Philipp Zabel --- drivers/reset/Kconfig | 10 +-- drivers/reset/Makefile | 1 - drivers/reset/reset-simple.c | 51 ++++++++++- drivers/reset/reset-simple.h | 4 + drivers/reset/reset-socfpga.c | 157 ---------------------------------- 5 files changed, 56 insertions(+), 167 deletions(-) delete mode 100644 drivers/reset/reset-socfpga.c diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index a14c0fe49877..2d6770b210ed 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -77,19 +77,13 @@ config RESET_PISTACHIO config RESET_SIMPLE bool "Simple Reset Controller Driver" if COMPILE_TEST - default ARCH_SUNXI + default ARCH_SOCFPGA || ARCH_STRATIX10 || ARCH_SUNXI help This enables a simple reset controller driver for reset lines that that can be asserted and deasserted by toggling bits in a contiguous, exclusive register space. - Currently this driver supports Allwinner SoCs. - -config RESET_SOCFPGA - bool "SoCFPGA Reset Driver" if COMPILE_TEST - default ARCH_SOCFPGA || ARCH_STRATIX10 - help - This enables the reset controller driver for Altera SoCFPGAs. + Currently this driver supports Altera SoCFPGAs and Allwinner SoCs. config RESET_STM32 bool "STM32 Reset Driver" if COMPILE_TEST diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index ddd3eeb19356..3bf3b4e6a9fd 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -13,7 +13,6 @@ obj-$(CONFIG_RESET_MESON) += reset-meson.o obj-$(CONFIG_RESET_OXNAS) += reset-oxnas.o obj-$(CONFIG_RESET_PISTACHIO) += reset-pistachio.o obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o -obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o obj-$(CONFIG_RESET_STM32) += reset-stm32.o obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o obj-$(CONFIG_RESET_TI_SCI) += reset-ti-sci.o diff --git a/drivers/reset/reset-simple.c b/drivers/reset/reset-simple.c index a5119457cec6..1b320c280ca8 100644 --- a/drivers/reset/reset-simple.c +++ b/drivers/reset/reset-simple.c @@ -68,25 +68,58 @@ static int reset_simple_deassert(struct reset_controller_dev *rcdev, return reset_simple_update(rcdev, id, false); } +static int reset_simple_status(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct reset_simple_data *data = to_reset_simple_data(rcdev); + int reg_width = sizeof(u32); + int bank = id / (reg_width * BITS_PER_BYTE); + int offset = id % (reg_width * BITS_PER_BYTE); + u32 reg; + + reg = readl(data->membase + (bank * reg_width)); + + return !(reg & BIT(offset)) ^ !data->status_active_low; +} + const struct reset_control_ops reset_simple_ops = { .assert = reset_simple_assert, .deassert = reset_simple_deassert, + .status = reset_simple_status, }; /** * struct reset_simple_devdata - simple reset controller properties + * @reg_offset: offset between base address and first reset register. + * @nr_resets: number of resets. If not set, default to resource size in bits. * @active_low: if true, bits are cleared to assert the reset. Otherwise, bits * are set to assert the reset. + * @status_active_low: if true, bits read back as cleared while the reset is + * asserted. Otherwise, bits read back as set while the + * reset is asserted. */ struct reset_simple_devdata { + u32 reg_offset; + u32 nr_resets; bool active_low; + bool status_active_low; +}; + +#define SOCFPGA_NR_BANKS 8 + +static const struct reset_simple_devdata reset_simple_socfpga = { + .reg_offset = 0x10, + .nr_resets = SOCFPGA_NR_BANKS * 32, + .status_active_low = true, }; static const struct reset_simple_devdata reset_simple_active_low = { .active_low = true, + .status_active_low = true, }; static const struct of_device_id reset_simple_dt_ids[] = { + { .compatible = "altr,rst-mgr", .data = &reset_simple_socfpga }, { .compatible = "allwinner,sun6i-a31-clock-reset", .data = &reset_simple_active_low }, { /* sentinel */ }, @@ -99,6 +132,7 @@ static int reset_simple_probe(struct platform_device *pdev) struct reset_simple_data *data; void __iomem *membase; struct resource *res; + u32 reg_offset = 0; devdata = of_device_get_match_data(dev); @@ -118,8 +152,23 @@ static int reset_simple_probe(struct platform_device *pdev) data->rcdev.ops = &reset_simple_ops; data->rcdev.of_node = dev->of_node; - if (devdata) + if (devdata) { + reg_offset = devdata->reg_offset; + if (devdata->nr_resets) + data->rcdev.nr_resets = devdata->nr_resets; data->active_low = devdata->active_low; + data->status_active_low = devdata->status_active_low; + } + + if (of_device_is_compatible(dev->of_node, "altr,rst-mgr") && + of_property_read_u32(dev->of_node, "altr,modrst-offset", + ®_offset)) { + dev_warn(dev, + "missing altr,modrst-offset property, assuming 0x%x!\n", + reg_offset); + } + + data->membase += reg_offset; return devm_reset_controller_register(dev, &data->rcdev); } diff --git a/drivers/reset/reset-simple.h b/drivers/reset/reset-simple.h index 39af2014b5f1..8a496022baef 100644 --- a/drivers/reset/reset-simple.h +++ b/drivers/reset/reset-simple.h @@ -28,12 +28,16 @@ * @active_low: if true, bits are cleared to assert the reset. Otherwise, bits * are set to assert the reset. Note that this says nothing about * the voltage level of the actual reset line. + * @status_active_low: if true, bits read back as cleared while the reset is + * asserted. Otherwise, bits read back as set while the + * reset is asserted. */ struct reset_simple_data { spinlock_t lock; void __iomem *membase; struct reset_controller_dev rcdev; bool active_low; + bool status_active_low; }; extern const struct reset_control_ops reset_simple_ops; diff --git a/drivers/reset/reset-socfpga.c b/drivers/reset/reset-socfpga.c deleted file mode 100644 index 3907bbc9c6cf..000000000000 --- a/drivers/reset/reset-socfpga.c +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Socfpga Reset Controller Driver - * - * Copyright 2014 Steffen Trumtrar - * - * based on - * Allwinner SoCs Reset Controller driver - * - * Copyright 2013 Maxime Ripard - * - * Maxime Ripard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#define BANK_INCREMENT 4 -#define NR_BANKS 8 - -struct socfpga_reset_data { - spinlock_t lock; - void __iomem *membase; - struct reset_controller_dev rcdev; -}; - -static int socfpga_reset_assert(struct reset_controller_dev *rcdev, - unsigned long id) -{ - struct socfpga_reset_data *data = container_of(rcdev, - struct socfpga_reset_data, - rcdev); - int reg_width = sizeof(u32); - int bank = id / (reg_width * BITS_PER_BYTE); - int offset = id % (reg_width * BITS_PER_BYTE); - unsigned long flags; - u32 reg; - - spin_lock_irqsave(&data->lock, flags); - - reg = readl(data->membase + (bank * BANK_INCREMENT)); - writel(reg | BIT(offset), data->membase + (bank * BANK_INCREMENT)); - spin_unlock_irqrestore(&data->lock, flags); - - return 0; -} - -static int socfpga_reset_deassert(struct reset_controller_dev *rcdev, - unsigned long id) -{ - struct socfpga_reset_data *data = container_of(rcdev, - struct socfpga_reset_data, - rcdev); - - int reg_width = sizeof(u32); - int bank = id / (reg_width * BITS_PER_BYTE); - int offset = id % (reg_width * BITS_PER_BYTE); - unsigned long flags; - u32 reg; - - spin_lock_irqsave(&data->lock, flags); - - reg = readl(data->membase + (bank * BANK_INCREMENT)); - writel(reg & ~BIT(offset), data->membase + (bank * BANK_INCREMENT)); - - spin_unlock_irqrestore(&data->lock, flags); - - return 0; -} - -static int socfpga_reset_status(struct reset_controller_dev *rcdev, - unsigned long id) -{ - struct socfpga_reset_data *data = container_of(rcdev, - struct socfpga_reset_data, rcdev); - int reg_width = sizeof(u32); - int bank = id / (reg_width * BITS_PER_BYTE); - int offset = id % (reg_width * BITS_PER_BYTE); - u32 reg; - - reg = readl(data->membase + (bank * BANK_INCREMENT)); - - return !(reg & BIT(offset)); -} - -static const struct reset_control_ops socfpga_reset_ops = { - .assert = socfpga_reset_assert, - .deassert = socfpga_reset_deassert, - .status = socfpga_reset_status, -}; - -static int socfpga_reset_probe(struct platform_device *pdev) -{ - struct socfpga_reset_data *data; - struct resource *res; - struct device *dev = &pdev->dev; - struct device_node *np = dev->of_node; - u32 modrst_offset; - - /* - * The binding was mainlined without the required property. - * Do not continue, when we encounter an old DT. - */ - if (!of_find_property(pdev->dev.of_node, "#reset-cells", NULL)) { - dev_err(&pdev->dev, "%pOF missing #reset-cells property\n", - pdev->dev.of_node); - return -EINVAL; - } - - data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); - if (!data) - return -ENOMEM; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - data->membase = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(data->membase)) - return PTR_ERR(data->membase); - - if (of_property_read_u32(np, "altr,modrst-offset", &modrst_offset)) { - dev_warn(dev, "missing altr,modrst-offset property, assuming 0x10!\n"); - modrst_offset = 0x10; - } - data->membase += modrst_offset; - - spin_lock_init(&data->lock); - - data->rcdev.owner = THIS_MODULE; - data->rcdev.nr_resets = NR_BANKS * (sizeof(u32) * BITS_PER_BYTE); - data->rcdev.ops = &socfpga_reset_ops; - data->rcdev.of_node = pdev->dev.of_node; - - return devm_reset_controller_register(dev, &data->rcdev); -} - -static const struct of_device_id socfpga_reset_dt_ids[] = { - { .compatible = "altr,rst-mgr", }, - { /* sentinel */ }, -}; - -static struct platform_driver socfpga_reset_driver = { - .probe = socfpga_reset_probe, - .driver = { - .name = "socfpga-reset", - .of_match_table = socfpga_reset_dt_ids, - }, -}; -builtin_platform_driver(socfpga_reset_driver); From 0af8a137361330af644ae9a3475b328a1dfb7945 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 11 Aug 2017 13:02:47 +0200 Subject: [PATCH 12/13] reset: stm32: use the reset-simple driver The reset-simple driver can be used without changes. Signed-off-by: Philipp Zabel Acked-by: Gabriel Fernandez --- drivers/reset/Kconfig | 11 +--- drivers/reset/Makefile | 1 - drivers/reset/reset-simple.c | 1 + drivers/reset/reset-stm32.c | 108 ----------------------------------- 4 files changed, 4 insertions(+), 117 deletions(-) delete mode 100644 drivers/reset/reset-stm32.c diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 2d6770b210ed..9bdb4fe1b03e 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -77,19 +77,14 @@ config RESET_PISTACHIO config RESET_SIMPLE bool "Simple Reset Controller Driver" if COMPILE_TEST - default ARCH_SOCFPGA || ARCH_STRATIX10 || ARCH_SUNXI + default ARCH_SOCFPGA || ARCH_STM32 || ARCH_STRATIX10 || ARCH_SUNXI help This enables a simple reset controller driver for reset lines that that can be asserted and deasserted by toggling bits in a contiguous, exclusive register space. - Currently this driver supports Altera SoCFPGAs and Allwinner SoCs. - -config RESET_STM32 - bool "STM32 Reset Driver" if COMPILE_TEST - default ARCH_STM32 - help - This enables the RCC reset controller driver for STM32 MCUs. + Currently this driver supports Altera SoCFPGAs, the RCC reset + controller in STM32 MCUs, and Allwinner SoCs. config RESET_SUNXI bool "Allwinner SoCs Reset Driver" if COMPILE_TEST && !ARCH_SUNXI diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 3bf3b4e6a9fd..98dd1eccc820 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -13,7 +13,6 @@ obj-$(CONFIG_RESET_MESON) += reset-meson.o obj-$(CONFIG_RESET_OXNAS) += reset-oxnas.o obj-$(CONFIG_RESET_PISTACHIO) += reset-pistachio.o obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o -obj-$(CONFIG_RESET_STM32) += reset-stm32.o obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o obj-$(CONFIG_RESET_TI_SCI) += reset-ti-sci.o obj-$(CONFIG_RESET_TI_SYSCON) += reset-ti-syscon.o diff --git a/drivers/reset/reset-simple.c b/drivers/reset/reset-simple.c index 1b320c280ca8..79c6ae3b743f 100644 --- a/drivers/reset/reset-simple.c +++ b/drivers/reset/reset-simple.c @@ -120,6 +120,7 @@ static const struct reset_simple_devdata reset_simple_active_low = { static const struct of_device_id reset_simple_dt_ids[] = { { .compatible = "altr,rst-mgr", .data = &reset_simple_socfpga }, + { .compatible = "st,stm32-rcc", }, { .compatible = "allwinner,sun6i-a31-clock-reset", .data = &reset_simple_active_low }, { /* sentinel */ }, diff --git a/drivers/reset/reset-stm32.c b/drivers/reset/reset-stm32.c deleted file mode 100644 index 3a7c8527e66a..000000000000 --- a/drivers/reset/reset-stm32.c +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (C) Maxime Coquelin 2015 - * Author: Maxime Coquelin - * License terms: GNU General Public License (GPL), version 2 - * - * Heavily based on sunxi driver from Maxime Ripard. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct stm32_reset_data { - spinlock_t lock; - void __iomem *membase; - struct reset_controller_dev rcdev; -}; - -static int stm32_reset_assert(struct reset_controller_dev *rcdev, - unsigned long id) -{ - struct stm32_reset_data *data = container_of(rcdev, - struct stm32_reset_data, - rcdev); - int bank = id / BITS_PER_LONG; - int offset = id % BITS_PER_LONG; - unsigned long flags; - u32 reg; - - spin_lock_irqsave(&data->lock, flags); - - reg = readl(data->membase + (bank * 4)); - writel(reg | BIT(offset), data->membase + (bank * 4)); - - spin_unlock_irqrestore(&data->lock, flags); - - return 0; -} - -static int stm32_reset_deassert(struct reset_controller_dev *rcdev, - unsigned long id) -{ - struct stm32_reset_data *data = container_of(rcdev, - struct stm32_reset_data, - rcdev); - int bank = id / BITS_PER_LONG; - int offset = id % BITS_PER_LONG; - unsigned long flags; - u32 reg; - - spin_lock_irqsave(&data->lock, flags); - - reg = readl(data->membase + (bank * 4)); - writel(reg & ~BIT(offset), data->membase + (bank * 4)); - - spin_unlock_irqrestore(&data->lock, flags); - - return 0; -} - -static const struct reset_control_ops stm32_reset_ops = { - .assert = stm32_reset_assert, - .deassert = stm32_reset_deassert, -}; - -static const struct of_device_id stm32_reset_dt_ids[] = { - { .compatible = "st,stm32-rcc", }, - { /* sentinel */ }, -}; - -static int stm32_reset_probe(struct platform_device *pdev) -{ - struct stm32_reset_data *data; - struct resource *res; - - data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); - if (!data) - return -ENOMEM; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - data->membase = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(data->membase)) - return PTR_ERR(data->membase); - - spin_lock_init(&data->lock); - - data->rcdev.owner = THIS_MODULE; - data->rcdev.nr_resets = resource_size(res) * 8; - data->rcdev.ops = &stm32_reset_ops; - data->rcdev.of_node = pdev->dev.of_node; - - return devm_reset_controller_register(&pdev->dev, &data->rcdev); -} - -static struct platform_driver stm32_reset_driver = { - .probe = stm32_reset_probe, - .driver = { - .name = "stm32-rcc-reset", - .of_match_table = stm32_reset_dt_ids, - }, -}; -builtin_platform_driver(stm32_reset_driver); From f0e0ada67dfd8342fd411da6e3bff10ff9bcc97b Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 11 Aug 2017 13:03:05 +0200 Subject: [PATCH 13/13] reset: zx2967: use the reset-simple driver The reset-simple driver can be used without changes. Signed-off-by: Philipp Zabel Reviewed-by: Alexandru Gagniuc --- MAINTAINERS | 1 - drivers/reset/Kconfig | 10 +--- drivers/reset/Makefile | 1 - drivers/reset/reset-simple.c | 2 + drivers/reset/reset-zx2967.c | 99 ------------------------------------ 5 files changed, 4 insertions(+), 109 deletions(-) delete mode 100644 drivers/reset/reset-zx2967.c diff --git a/MAINTAINERS b/MAINTAINERS index 3b9887b3644e..d48d8a238fae 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2124,7 +2124,6 @@ F: drivers/gpio/gpio-zx.c F: drivers/i2c/busses/i2c-zx2967.c F: drivers/mmc/host/dw_mmc-zx.* F: drivers/pinctrl/zte/ -F: drivers/reset/reset-zx2967.c F: drivers/soc/zte/ F: drivers/thermal/zx2967_thermal.c F: drivers/watchdog/zx2967_wdt.c diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 9bdb4fe1b03e..de0090c911cd 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -77,14 +77,14 @@ config RESET_PISTACHIO config RESET_SIMPLE bool "Simple Reset Controller Driver" if COMPILE_TEST - default ARCH_SOCFPGA || ARCH_STM32 || ARCH_STRATIX10 || ARCH_SUNXI + default ARCH_SOCFPGA || ARCH_STM32 || ARCH_STRATIX10 || ARCH_SUNXI || ARCH_ZX help This enables a simple reset controller driver for reset lines that that can be asserted and deasserted by toggling bits in a contiguous, exclusive register space. Currently this driver supports Altera SoCFPGAs, the RCC reset - controller in STM32 MCUs, and Allwinner SoCs. + controller in STM32 MCUs, Allwinner SoCs, and ZTE's zx2967 family. config RESET_SUNXI bool "Allwinner SoCs Reset Driver" if COMPILE_TEST && !ARCH_SUNXI @@ -121,12 +121,6 @@ config RESET_UNIPHIER Say Y if you want to control reset signals provided by System Control block, Media I/O block, Peripheral Block. -config RESET_ZX2967 - bool "ZTE ZX2967 Reset Driver" - depends on ARCH_ZX || COMPILE_TEST - help - This enables the reset controller driver for ZTE's zx2967 family. - config RESET_ZYNQ bool "ZYNQ Reset Driver" if COMPILE_TEST default ARCH_ZYNQ diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 98dd1eccc820..48b64d63b75a 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -17,6 +17,5 @@ obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o obj-$(CONFIG_RESET_TI_SCI) += reset-ti-sci.o obj-$(CONFIG_RESET_TI_SYSCON) += reset-ti-syscon.o obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o -obj-$(CONFIG_RESET_ZX2967) += reset-zx2967.o obj-$(CONFIG_RESET_ZYNQ) += reset-zynq.o diff --git a/drivers/reset/reset-simple.c b/drivers/reset/reset-simple.c index 79c6ae3b743f..2d4f362ef025 100644 --- a/drivers/reset/reset-simple.c +++ b/drivers/reset/reset-simple.c @@ -123,6 +123,8 @@ static const struct of_device_id reset_simple_dt_ids[] = { { .compatible = "st,stm32-rcc", }, { .compatible = "allwinner,sun6i-a31-clock-reset", .data = &reset_simple_active_low }, + { .compatible = "zte,zx296718-reset", + .data = &reset_simple_active_low }, { /* sentinel */ }, }; diff --git a/drivers/reset/reset-zx2967.c b/drivers/reset/reset-zx2967.c deleted file mode 100644 index 4f319f7753d4..000000000000 --- a/drivers/reset/reset-zx2967.c +++ /dev/null @@ -1,99 +0,0 @@ -/* - * ZTE's zx2967 family reset controller driver - * - * Copyright (C) 2017 ZTE Ltd. - * - * Author: Baoyou Xie - * - * License terms: GNU General Public License (GPL) version 2 - */ - -#include -#include -#include - -struct zx2967_reset { - void __iomem *reg_base; - spinlock_t lock; - struct reset_controller_dev rcdev; -}; - -static int zx2967_reset_act(struct reset_controller_dev *rcdev, - unsigned long id, bool assert) -{ - struct zx2967_reset *reset = NULL; - int bank = id / 32; - int offset = id % 32; - u32 reg; - unsigned long flags; - - reset = container_of(rcdev, struct zx2967_reset, rcdev); - - spin_lock_irqsave(&reset->lock, flags); - - reg = readl_relaxed(reset->reg_base + (bank * 4)); - if (assert) - reg &= ~BIT(offset); - else - reg |= BIT(offset); - writel_relaxed(reg, reset->reg_base + (bank * 4)); - - spin_unlock_irqrestore(&reset->lock, flags); - - return 0; -} - -static int zx2967_reset_assert(struct reset_controller_dev *rcdev, - unsigned long id) -{ - return zx2967_reset_act(rcdev, id, true); -} - -static int zx2967_reset_deassert(struct reset_controller_dev *rcdev, - unsigned long id) -{ - return zx2967_reset_act(rcdev, id, false); -} - -static const struct reset_control_ops zx2967_reset_ops = { - .assert = zx2967_reset_assert, - .deassert = zx2967_reset_deassert, -}; - -static int zx2967_reset_probe(struct platform_device *pdev) -{ - struct zx2967_reset *reset; - struct resource *res; - - reset = devm_kzalloc(&pdev->dev, sizeof(*reset), GFP_KERNEL); - if (!reset) - return -ENOMEM; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - reset->reg_base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(reset->reg_base)) - return PTR_ERR(reset->reg_base); - - spin_lock_init(&reset->lock); - - reset->rcdev.owner = THIS_MODULE; - reset->rcdev.nr_resets = resource_size(res) * 8; - reset->rcdev.ops = &zx2967_reset_ops; - reset->rcdev.of_node = pdev->dev.of_node; - - return devm_reset_controller_register(&pdev->dev, &reset->rcdev); -} - -static const struct of_device_id zx2967_reset_dt_ids[] = { - { .compatible = "zte,zx296718-reset", }, - {}, -}; - -static struct platform_driver zx2967_reset_driver = { - .probe = zx2967_reset_probe, - .driver = { - .name = "zx2967-reset", - .of_match_table = zx2967_reset_dt_ids, - }, -}; -builtin_platform_driver(zx2967_reset_driver);