diff options
author | Olof Johansson <olof@lixom.net> | 2020-01-10 22:20:36 -0800 |
---|---|---|
committer | Olof Johansson <olof@lixom.net> | 2020-01-10 22:20:37 -0800 |
commit | 3abda7cabe85e5631b21fbc0a75f9a393f598f9f (patch) | |
tree | 95c8bf58386a80ed0d9db922d85f154ae91d5a9a | |
parent | ef832e4cb9b14963635b230e967674779c81dfec (diff) | |
parent | e2d5e8332c9684ea254c84002bc1e13a42db9e54 (diff) | |
download | linux-3abda7cabe85e5631b21fbc0a75f9a393f598f9f.tar.gz linux-3abda7cabe85e5631b21fbc0a75f9a393f598f9f.tar.bz2 linux-3abda7cabe85e5631b21fbc0a75f9a393f598f9f.zip |
Merge tag 'reset-for-5.6' of git://git.pengutronix.de/pza/linux into arm/drivers
Reset controller updates for v5.6
This tag adds support for the Nuvoton NPCM, Intel Gatway SoC, and
Broadcom BCM7216 RESCAL reset controllers, adds missing SCSSI reset
controls for newer Uniphier SoCs, aligns the program flow in the
devm_reset_controller_register, __devm_reset_control_get, and
devm_reset_control_array_get functions for better consistency,
and allows to build the Qcom AOSS reset driver as a module.
This is based on v5.5-rc3 because the core patch depends on commit
db23808615e2 ("reset: Do not register resource data for missing
resets").
* tag 'reset-for-5.6' of git://git.pengutronix.de/pza/linux:
reset: qcom-aoss: Allow CONFIG_RESET_QCOM_AOSS to be a tristate
reset: Add Broadcom STB RESCAL reset controller
dt-bindings: reset: Document BCM7216 RESCAL reset controller
reset: intel: Add system reset controller driver
dt-bindings: reset: Add YAML schemas for the Intel Reset controller
reset: uniphier: Add SCSSI reset control for each channel
reset: Align logic and flow in managed helpers
reset: npcm: add NPCM reset controller driver
dt-bindings: reset: Add binding constants for NPCM7xx reset controller
dt-bindings: reset: add NPCM reset controller documentation
Link: https://lore.kernel.org/r/dbbb2ca7490a0146d9ba632fd4d9f38063e03e9f.camel@pengutronix.de
Signed-off-by: Olof Johansson <olof@lixom.net>
-rw-r--r-- | Documentation/devicetree/bindings/reset/brcm,bcm7216-pcie-sata-rescal.yaml | 37 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/reset/intel,rcu-gw.yaml | 63 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/reset/nuvoton,npcm-reset.txt | 32 | ||||
-rw-r--r-- | drivers/reset/Kconfig | 25 | ||||
-rw-r--r-- | drivers/reset/Makefile | 3 | ||||
-rw-r--r-- | drivers/reset/core.c | 33 | ||||
-rw-r--r-- | drivers/reset/reset-brcmstb-rescal.c | 107 | ||||
-rw-r--r-- | drivers/reset/reset-intel-gw.c | 262 | ||||
-rw-r--r-- | drivers/reset/reset-npcm.c | 291 | ||||
-rw-r--r-- | drivers/reset/reset-qcom-aoss.c | 3 | ||||
-rw-r--r-- | drivers/reset/reset-uniphier.c | 13 | ||||
-rw-r--r-- | include/dt-bindings/reset/nuvoton,npcm7xx-reset.h | 91 |
12 files changed, 937 insertions, 23 deletions
diff --git a/Documentation/devicetree/bindings/reset/brcm,bcm7216-pcie-sata-rescal.yaml b/Documentation/devicetree/bindings/reset/brcm,bcm7216-pcie-sata-rescal.yaml new file mode 100644 index 000000000000..411bd76f1b64 --- /dev/null +++ b/Documentation/devicetree/bindings/reset/brcm,bcm7216-pcie-sata-rescal.yaml @@ -0,0 +1,37 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +# Copyright 2020 Broadcom +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/reset/brcm,bcm7216-pcie-sata-rescal.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: BCM7216 RESCAL reset controller + +description: This document describes the BCM7216 RESCAL reset controller which is responsible for controlling the reset of the SATA and PCIe0/1 instances on BCM7216. + +maintainers: + - Florian Fainelli <f.fainelli@gmail.com> + - Jim Quinlan <jim2101024@gmail.com> + +properties: + compatible: + const: brcm,bcm7216-pcie-sata-rescal + + reg: + maxItems: 1 + + "#reset-cells": + const: 0 + +required: + - compatible + - reg + - "#reset-cells" + +examples: + - | + reset-controller@8b2c800 { + compatible = "brcm,bcm7216-pcie-sata-rescal"; + reg = <0x8b2c800 0x10>; + #reset-cells = <0>; + }; diff --git a/Documentation/devicetree/bindings/reset/intel,rcu-gw.yaml b/Documentation/devicetree/bindings/reset/intel,rcu-gw.yaml new file mode 100644 index 000000000000..246dea8a2ec9 --- /dev/null +++ b/Documentation/devicetree/bindings/reset/intel,rcu-gw.yaml @@ -0,0 +1,63 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/reset/intel,rcu-gw.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: System Reset Controller on Intel Gateway SoCs + +maintainers: + - Dilip Kota <eswara.kota@linux.intel.com> + +properties: + compatible: + enum: + - intel,rcu-lgm + - intel,rcu-xrx200 + + reg: + description: Reset controller registers. + maxItems: 1 + + intel,global-reset: + description: Global reset register offset and bit offset. + allOf: + - $ref: /schemas/types.yaml#/definitions/uint32-array + - maxItems: 2 + + "#reset-cells": + minimum: 2 + maximum: 3 + description: | + First cell is reset request register offset. + Second cell is bit offset in reset request register. + Third cell is bit offset in reset status register. + For LGM SoC, reset cell count is 2 as bit offset in + reset request and reset status registers is same. Whereas + 3 for legacy SoCs as bit offset differs. + +required: + - compatible + - reg + - intel,global-reset + - "#reset-cells" + +additionalProperties: false + +examples: + - | + rcu0: reset-controller@e0000000 { + compatible = "intel,rcu-lgm"; + reg = <0xe0000000 0x20000>; + intel,global-reset = <0x10 30>; + #reset-cells = <2>; + }; + + pwm: pwm@e0d00000 { + status = "disabled"; + compatible = "intel,lgm-pwm"; + reg = <0xe0d00000 0x30>; + clocks = <&cgu0 1>; + #pwm-cells = <2>; + resets = <&rcu0 0x30 21>; + }; diff --git a/Documentation/devicetree/bindings/reset/nuvoton,npcm-reset.txt b/Documentation/devicetree/bindings/reset/nuvoton,npcm-reset.txt new file mode 100644 index 000000000000..6e802703af60 --- /dev/null +++ b/Documentation/devicetree/bindings/reset/nuvoton,npcm-reset.txt @@ -0,0 +1,32 @@ +Nuvoton NPCM Reset controller + +Required properties: +- compatible : "nuvoton,npcm750-reset" for NPCM7XX BMC +- reg : specifies physical base address and size of the register. +- #reset-cells: must be set to 2 + +Optional property: +- nuvoton,sw-reset-number - Contains the software reset number to restart the SoC. + NPCM7xx contain four software reset that represent numbers 1 to 4. + + If 'nuvoton,sw-reset-number' is not specfied software reset is disabled. + +Example: + rstc: rstc@f0801000 { + compatible = "nuvoton,npcm750-reset"; + reg = <0xf0801000 0x70>; + #reset-cells = <2>; + nuvoton,sw-reset-number = <2>; + }; + +Specifying reset lines connected to IP NPCM7XX modules +====================================================== +example: + + spi0: spi@..... { + ... + resets = <&rstc NPCM7XX_RESET_IPSRST2 NPCM7XX_RESET_PSPI1>; + ... + }; + +The index could be found in <dt-bindings/reset/nuvoton,npcm7xx-reset.h>. diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 3ad7817ce1f0..461b0e506a26 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -49,6 +49,13 @@ config RESET_BRCMSTB This enables the reset controller driver for Broadcom STB SoCs using a SUN_TOP_CTRL_SW_INIT style controller. +config RESET_BRCMSTB_RESCAL + bool "Broadcom STB RESCAL reset controller" + default ARCH_BRCMSTB || COMPILE_TEST + help + This enables the RESCAL reset controller for SATA, PCIe0, or PCIe1 on + BCM7216. + config RESET_HSDK bool "Synopsys HSDK Reset Driver" depends on HAS_IOMEM @@ -64,6 +71,15 @@ config RESET_IMX7 help This enables the reset controller driver for i.MX7 SoCs. +config RESET_INTEL_GW + bool "Intel Reset Controller Driver" + depends on OF + select REGMAP_MMIO + help + This enables the reset controller driver for Intel Gateway SoCs. + Say Y to control the reset signals provided by reset controller. + Otherwise, say N. + config RESET_LANTIQ bool "Lantiq XWAY Reset Driver" if COMPILE_TEST default SOC_TYPE_XWAY @@ -89,6 +105,13 @@ config RESET_MESON_AUDIO_ARB This enables the reset driver for Audio Memory Arbiter of Amlogic's A113 based SoCs +config RESET_NPCM + bool "NPCM BMC Reset Driver" if COMPILE_TEST + default ARCH_NPCM + help + This enables the reset controller driver for Nuvoton NPCM + BMC SoCs. + config RESET_OXNAS bool @@ -99,7 +122,7 @@ config RESET_PISTACHIO This enables the reset driver for ImgTec Pistachio SoCs. config RESET_QCOM_AOSS - bool "Qcom AOSS Reset Driver" + tristate "Qcom AOSS Reset Driver" depends on ARCH_QCOM || COMPILE_TEST help This enables the AOSS (always on subsystem) reset driver diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index cf60ce526064..249ed357c997 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -8,12 +8,15 @@ obj-$(CONFIG_RESET_ATH79) += reset-ath79.o obj-$(CONFIG_RESET_AXS10X) += reset-axs10x.o obj-$(CONFIG_RESET_BERLIN) += reset-berlin.o obj-$(CONFIG_RESET_BRCMSTB) += reset-brcmstb.o +obj-$(CONFIG_RESET_BRCMSTB_RESCAL) += reset-brcmstb-rescal.o obj-$(CONFIG_RESET_HSDK) += reset-hsdk.o obj-$(CONFIG_RESET_IMX7) += reset-imx7.o +obj-$(CONFIG_RESET_INTEL_GW) += reset-intel-gw.o obj-$(CONFIG_RESET_LANTIQ) += reset-lantiq.o obj-$(CONFIG_RESET_LPC18XX) += reset-lpc18xx.o obj-$(CONFIG_RESET_MESON) += reset-meson.o obj-$(CONFIG_RESET_MESON_AUDIO_ARB) += reset-meson-audio-arb.o +obj-$(CONFIG_RESET_NPCM) += reset-npcm.o obj-$(CONFIG_RESET_OXNAS) += reset-oxnas.o obj-$(CONFIG_RESET_PISTACHIO) += reset-pistachio.o obj-$(CONFIG_RESET_QCOM_AOSS) += reset-qcom-aoss.o diff --git a/drivers/reset/core.c b/drivers/reset/core.c index 7597c70e04d5..01c0c7aa835c 100644 --- a/drivers/reset/core.c +++ b/drivers/reset/core.c @@ -150,13 +150,14 @@ int devm_reset_controller_register(struct device *dev, return -ENOMEM; ret = reset_controller_register(rcdev); - if (!ret) { - *rcdevp = rcdev; - devres_add(dev, rcdevp); - } else { + if (ret) { devres_free(rcdevp); + return ret; } + *rcdevp = rcdev; + devres_add(dev, rcdevp); + return ret; } EXPORT_SYMBOL_GPL(devm_reset_controller_register); @@ -787,13 +788,14 @@ struct reset_control *__devm_reset_control_get(struct device *dev, return ERR_PTR(-ENOMEM); rstc = __reset_control_get(dev, id, index, shared, optional, acquired); - if (!IS_ERR_OR_NULL(rstc)) { - *ptr = rstc; - devres_add(dev, ptr); - } else { + if (IS_ERR_OR_NULL(rstc)) { devres_free(ptr); + return rstc; } + *ptr = rstc; + devres_add(dev, ptr); + return rstc; } EXPORT_SYMBOL_GPL(__devm_reset_control_get); @@ -919,22 +921,21 @@ EXPORT_SYMBOL_GPL(of_reset_control_array_get); struct reset_control * devm_reset_control_array_get(struct device *dev, bool shared, bool optional) { - struct reset_control **devres; - struct reset_control *rstc; + struct reset_control **ptr, *rstc; - devres = devres_alloc(devm_reset_control_release, sizeof(*devres), - GFP_KERNEL); - if (!devres) + ptr = devres_alloc(devm_reset_control_release, sizeof(*ptr), + GFP_KERNEL); + if (!ptr) return ERR_PTR(-ENOMEM); rstc = of_reset_control_array_get(dev->of_node, shared, optional, true); if (IS_ERR_OR_NULL(rstc)) { - devres_free(devres); + devres_free(ptr); return rstc; } - *devres = rstc; - devres_add(dev, devres); + *ptr = rstc; + devres_add(dev, ptr); return rstc; } diff --git a/drivers/reset/reset-brcmstb-rescal.c b/drivers/reset/reset-brcmstb-rescal.c new file mode 100644 index 000000000000..b6f074d6a65f --- /dev/null +++ b/drivers/reset/reset-brcmstb-rescal.c @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2018-2020 Broadcom */ + +#include <linux/device.h> +#include <linux/iopoll.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/reset-controller.h> + +#define BRCM_RESCAL_START 0x0 +#define BRCM_RESCAL_START_BIT BIT(0) +#define BRCM_RESCAL_CTRL 0x4 +#define BRCM_RESCAL_STATUS 0x8 +#define BRCM_RESCAL_STATUS_BIT BIT(0) + +struct brcm_rescal_reset { + void __iomem *base; + struct device *dev; + struct reset_controller_dev rcdev; +}; + +static int brcm_rescal_reset_set(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct brcm_rescal_reset *data = + container_of(rcdev, struct brcm_rescal_reset, rcdev); + void __iomem *base = data->base; + u32 reg; + int ret; + + reg = readl(base + BRCM_RESCAL_START); + writel(reg | BRCM_RESCAL_START_BIT, base + BRCM_RESCAL_START); + reg = readl(base + BRCM_RESCAL_START); + if (!(reg & BRCM_RESCAL_START_BIT)) { + dev_err(data->dev, "failed to start SATA/PCIe rescal\n"); + return -EIO; + } + + ret = readl_poll_timeout(base + BRCM_RESCAL_STATUS, reg, + !(reg & BRCM_RESCAL_STATUS_BIT), 100, 1000); + if (ret) { + dev_err(data->dev, "time out on SATA/PCIe rescal\n"); + return ret; + } + + reg = readl(base + BRCM_RESCAL_START); + writel(reg & ~BRCM_RESCAL_START_BIT, base + BRCM_RESCAL_START); + + dev_dbg(data->dev, "SATA/PCIe rescal success\n"); + + return 0; +} + +static int brcm_rescal_reset_xlate(struct reset_controller_dev *rcdev, + const struct of_phandle_args *reset_spec) +{ + /* This is needed if #reset-cells == 0. */ + return 0; +} + +static const struct reset_control_ops brcm_rescal_reset_ops = { + .reset = brcm_rescal_reset_set, +}; + +static int brcm_rescal_reset_probe(struct platform_device *pdev) +{ + struct brcm_rescal_reset *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->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(data->base)) + return PTR_ERR(data->base); + + data->rcdev.owner = THIS_MODULE; + data->rcdev.nr_resets = 1; + data->rcdev.ops = &brcm_rescal_reset_ops; + data->rcdev.of_node = pdev->dev.of_node; + data->rcdev.of_xlate = brcm_rescal_reset_xlate; + data->dev = &pdev->dev; + + return devm_reset_controller_register(&pdev->dev, &data->rcdev); +} + +static const struct of_device_id brcm_rescal_reset_of_match[] = { + { .compatible = "brcm,bcm7216-pcie-sata-rescal" }, + { }, +}; +MODULE_DEVICE_TABLE(of, brcm_rescal_reset_of_match); + +static struct platform_driver brcm_rescal_reset_driver = { + .probe = brcm_rescal_reset_probe, + .driver = { + .name = "brcm-rescal-reset", + .of_match_table = brcm_rescal_reset_of_match, + } +}; +module_platform_driver(brcm_rescal_reset_driver); + +MODULE_AUTHOR("Broadcom"); +MODULE_DESCRIPTION("Broadcom SATA/PCIe rescal reset controller"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/reset/reset-intel-gw.c b/drivers/reset/reset-intel-gw.c new file mode 100644 index 000000000000..854238444616 --- /dev/null +++ b/drivers/reset/reset-intel-gw.c @@ -0,0 +1,262 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2019 Intel Corporation. + * Lei Chuanhua <Chuanhua.lei@intel.com> + */ + +#include <linux/bitfield.h> +#include <linux/init.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/reboot.h> +#include <linux/regmap.h> +#include <linux/reset-controller.h> + +#define RCU_RST_STAT 0x0024 +#define RCU_RST_REQ 0x0048 + +#define REG_OFFSET GENMASK(31, 16) +#define BIT_OFFSET GENMASK(15, 8) +#define STAT_BIT_OFFSET GENMASK(7, 0) + +#define to_reset_data(x) container_of(x, struct intel_reset_data, rcdev) + +struct intel_reset_soc { + bool legacy; + u32 reset_cell_count; +}; + +struct intel_reset_data { + struct reset_controller_dev rcdev; + struct notifier_block restart_nb; + const struct intel_reset_soc *soc_data; + struct regmap *regmap; + struct device *dev; + u32 reboot_id; +}; + +static const struct regmap_config intel_rcu_regmap_config = { + .name = "intel-reset", + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .fast_io = true, +}; + +/* + * Reset status register offset relative to + * the reset control register(X) is X + 4 + */ +static u32 id_to_reg_and_bit_offsets(struct intel_reset_data *data, + unsigned long id, u32 *rst_req, + u32 *req_bit, u32 *stat_bit) +{ + *rst_req = FIELD_GET(REG_OFFSET, id); + *req_bit = FIELD_GET(BIT_OFFSET, id); + + if (data->soc_data->legacy) + *stat_bit = FIELD_GET(STAT_BIT_OFFSET, id); + else + *stat_bit = *req_bit; + + if (data->soc_data->legacy && *rst_req == RCU_RST_REQ) + return RCU_RST_STAT; + else + return *rst_req + 0x4; +} + +static int intel_set_clr_bits(struct intel_reset_data *data, unsigned long id, + bool set) +{ + u32 rst_req, req_bit, rst_stat, stat_bit, val; + int ret; + + rst_stat = id_to_reg_and_bit_offsets(data, id, &rst_req, + &req_bit, &stat_bit); + + val = set ? BIT(req_bit) : 0; + ret = regmap_update_bits(data->regmap, rst_req, BIT(req_bit), val); + if (ret) + return ret; + + return regmap_read_poll_timeout(data->regmap, rst_stat, val, + set == !!(val & BIT(stat_bit)), 20, + 200); +} + +static int intel_assert_device(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct intel_reset_data *data = to_reset_data(rcdev); + int ret; + + ret = intel_set_clr_bits(data, id, true); + if (ret) + dev_err(data->dev, "Reset assert failed %d\n", ret); + + return ret; +} + +static int intel_deassert_device(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct intel_reset_data *data = to_reset_data(rcdev); + int ret; + + ret = intel_set_clr_bits(data, id, false); + if (ret) + dev_err(data->dev, "Reset deassert failed %d\n", ret); + + return ret; +} + +static int intel_reset_status(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct intel_reset_data *data = to_reset_data(rcdev); + u32 rst_req, req_bit, rst_stat, stat_bit, val; + int ret; + + rst_stat = id_to_reg_and_bit_offsets(data, id, &rst_req, + &req_bit, &stat_bit); + ret = regmap_read(data->regmap, rst_stat, &val); + if (ret) + return ret; + + return !!(val & BIT(stat_bit)); +} + +static const struct reset_control_ops intel_reset_ops = { + .assert = intel_assert_device, + .deassert = intel_deassert_device, + .status = intel_reset_status, +}; + +static int intel_reset_xlate(struct reset_controller_dev *rcdev, + const struct of_phandle_args *spec) +{ + struct intel_reset_data *data = to_reset_data(rcdev); + u32 id; + + if (spec->args[1] > 31) + return -EINVAL; + + id = FIELD_PREP(REG_OFFSET, spec->args[0]); + id |= FIELD_PREP(BIT_OFFSET, spec->args[1]); + + if (data->soc_data->legacy) { + if (spec->args[2] > 31) + return -EINVAL; + + id |= FIELD_PREP(STAT_BIT_OFFSET, spec->args[2]); + } + + return id; +} + +static int intel_reset_restart_handler(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct intel_reset_data *reset_data; + + reset_data = container_of(nb, struct intel_reset_data, restart_nb); + intel_assert_device(&reset_data->rcdev, reset_data->reboot_id); + + return NOTIFY_DONE; +} + +static int intel_reset_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; + struct intel_reset_data *data; + void __iomem *base; + u32 rb_id[3]; + int ret; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->soc_data = of_device_get_match_data(dev); + if (!data->soc_data) + return -ENODEV; + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return PTR_ERR(base); + + data->regmap = devm_regmap_init_mmio(dev, base, + &intel_rcu_regmap_config); + if (IS_ERR(data->regmap)) { + dev_err(dev, "regmap initialization failed\n"); + return PTR_ERR(data->regmap); + } + + ret = device_property_read_u32_array(dev, "intel,global-reset", rb_id, + data->soc_data->reset_cell_count); + if (ret) { + dev_err(dev, "Failed to get global reset offset!\n"); + return ret; + } + + data->dev = dev; + data->rcdev.of_node = np; + data->rcdev.owner = dev->driver->owner; + data->rcdev.ops = &intel_reset_ops; + data->rcdev.of_xlate = intel_reset_xlate; + data->rcdev.of_reset_n_cells = data->soc_data->reset_cell_count; + ret = devm_reset_controller_register(&pdev->dev, &data->rcdev); + if (ret) + return ret; + + data->reboot_id = FIELD_PREP(REG_OFFSET, rb_id[0]); + data->reboot_id |= FIELD_PREP(BIT_OFFSET, rb_id[1]); + + if (data->soc_data->legacy) + data->reboot_id |= FIELD_PREP(STAT_BIT_OFFSET, rb_id[2]); + + data->restart_nb.notifier_call = intel_reset_restart_handler; + data->restart_nb.priority = 128; + register_restart_handler(&data->restart_nb); + + return 0; +} + +static const struct intel_reset_soc xrx200_data = { + .legacy = true, + .reset_cell_count = 3, +}; + +static const struct intel_reset_soc lgm_data = { + .legacy = false, + .reset_cell_count = 2, +}; + +static const struct of_device_id intel_reset_match[] = { + { .compatible = "intel,rcu-lgm", .data = &lgm_data }, + { .compatible = "intel,rcu-xrx200", .data = &xrx200_data }, + {} +}; + +static struct platform_driver intel_reset_driver = { + .probe = intel_reset_probe, + .driver = { + .name = "intel-reset", + .of_match_table = intel_reset_match, + }, +}; + +static int __init intel_reset_init(void) +{ + return platform_driver_register(&intel_reset_driver); +} + +/* + * RCU is system core entity which is in Always On Domain whose clocks + * or resource initialization happens in system core initialization. + * Also, it is required for most of the platform or architecture + * specific devices to perform reset operation as part of initialization. + * So perform RCU as post core initialization. + */ +postcore_initcall(intel_reset_init); diff --git a/drivers/reset/reset-npcm.c b/drivers/reset/reset-npcm.c new file mode 100644 index 000000000000..2ea4d3136e15 --- /dev/null +++ b/drivers/reset/reset-npcm.c @@ -0,0 +1,291 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2019 Nuvoton Technology corporation. + +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/init.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/reboot.h> +#include <linux/reset-controller.h> +#include <linux/spinlock.h> +#include <linux/mfd/syscon.h> +#include <linux/regmap.h> +#include <linux/of_address.h> + +/* NPCM7xx GCR registers */ +#define NPCM_MDLR_OFFSET 0x7C +#define NPCM_MDLR_USBD0 BIT(9) +#define NPCM_MDLR_USBD1 BIT(8) +#define NPCM_MDLR_USBD2_4 BIT(21) +#define NPCM_MDLR_USBD5_9 BIT(22) + +#define NPCM_USB1PHYCTL_OFFSET 0x140 +#define NPCM_USB2PHYCTL_OFFSET 0x144 +#define NPCM_USBXPHYCTL_RS BIT(28) + +/* NPCM7xx Reset registers */ +#define NPCM_SWRSTR 0x14 +#define NPCM_SWRST BIT(2) + +#define NPCM_IPSRST1 0x20 +#define NPCM_IPSRST1_USBD1 BIT(5) +#define NPCM_IPSRST1_USBD2 BIT(8) +#define NPCM_IPSRST1_USBD3 BIT(25) +#define NPCM_IPSRST1_USBD4 BIT(22) +#define NPCM_IPSRST1_USBD5 BIT(23) +#define NPCM_IPSRST1_USBD6 BIT(24) + +#define NPCM_IPSRST2 0x24 +#define NPCM_IPSRST2_USB_HOST BIT(26) + +#define NPCM_IPSRST3 0x34 +#define NPCM_IPSRST3_USBD0 BIT(4) +#define NPCM_IPSRST3_USBD7 BIT(5) +#define NPCM_IPSRST3_USBD8 BIT(6) +#define NPCM_IPSRST3_USBD9 BIT(7) +#define NPCM_IPSRST3_USBPHY1 BIT(24) +#define NPCM_IPSRST3_USBPHY2 BIT(25) + +#define NPCM_RC_RESETS_PER_REG 32 +#define NPCM_MASK_RESETS GENMASK(4, 0) + +struct npcm_rc_data { + struct reset_controller_dev rcdev; + struct notifier_block restart_nb; + u32 sw_reset_number; + void __iomem *base; + spinlock_t lock; +}; + +#define to_rc_data(p) container_of(p, struct npcm_rc_data, rcdev) + +static int npcm_rc_restart(struct notifier_block *nb, unsigned long mode, + void *cmd) +{ + struct npcm_rc_data *rc = container_of(nb, struct npcm_rc_data, + restart_nb); + + writel(NPCM_SWRST << rc->sw_reset_number, rc->base + NPCM_SWRSTR); + mdelay(1000); + + pr_emerg("%s: unable to restart system\n", __func__); + + return NOTIFY_DONE; +} + +static int npcm_rc_setclear_reset(struct reset_controller_dev *rcdev, + unsigned long id, bool set) +{ + struct npcm_rc_data *rc = to_rc_data(rcdev); + unsigned int rst_bit = BIT(id & NPCM_MASK_RESETS); + unsigned int ctrl_offset = id >> 8; + unsigned long flags; + u32 stat; + + spin_lock_irqsave(&rc->lock, flags); + stat = readl(rc->base + ctrl_offset); + if (set) + writel(stat | rst_bit, rc->base + ctrl_offset); + else + writel(stat & ~rst_bit, rc->base + ctrl_offset); + spin_unlock_irqrestore(&rc->lock, flags); + + return 0; +} + +static int npcm_rc_assert(struct reset_controller_dev *rcdev, unsigned long id) +{ + return npcm_rc_setclear_reset(rcdev, id, true); +} + +static int npcm_rc_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return npcm_rc_setclear_reset(rcdev, id, false); +} + +static int npcm_rc_status(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct npcm_rc_data *rc = to_rc_data(rcdev); + unsigned int rst_bit = BIT(id & NPCM_MASK_RESETS); + unsigned int ctrl_offset = id >> 8; + + return (readl(rc->base + ctrl_offset) & rst_bit); +} + +static int npcm_reset_xlate(struct reset_controller_dev *rcdev, + const struct of_phandle_args *reset_spec) +{ + unsigned int offset, bit; + + offset = reset_spec->args[0]; + if (offset != NPCM_IPSRST1 && offset != NPCM_IPSRST2 && + offset != NPCM_IPSRST3) { + dev_err(rcdev->dev, "Error reset register (0x%x)\n", offset); + return -EINVAL; + } + bit = reset_spec->args[1]; + if (bit >= NPCM_RC_RESETS_PER_REG) { + dev_err(rcdev->dev, "Error reset number (%d)\n", bit); + return -EINVAL; + } + + return (offset << 8) | bit; +} + +static const struct of_device_id npcm_rc_match[] = { + { .compatible = "nuvoton,npcm750-reset", + .data = (void *)"nuvoton,npcm750-gcr" }, + { } +}; + +/* + * The following procedure should be observed in USB PHY, USB device and + * USB host initialization at BMC boot + */ +static int npcm_usb_reset(struct platform_device *pdev, struct npcm_rc_data *rc) +{ + u32 mdlr, iprst1, iprst2, iprst3; + struct device *dev = &pdev->dev; + struct regmap *gcr_regmap; + u32 ipsrst1_bits = 0; + u32 ipsrst2_bits = NPCM_IPSRST2_USB_HOST; + u32 ipsrst3_bits = 0; + const char *gcr_dt; + + gcr_dt = (const char *) + of_match_device(dev->driver->of_match_table, dev)->data; + + gcr_regmap = syscon_regmap_lookup_by_compatible(gcr_dt); + if (IS_ERR(gcr_regmap)) { + dev_err(&pdev->dev, "Failed to find %s\n", gcr_dt); + return PTR_ERR(gcr_regmap); + } + + /* checking which USB device is enabled */ + regmap_read(gcr_regmap, NPCM_MDLR_OFFSET, &mdlr); + if (!(mdlr & NPCM_MDLR_USBD0)) + ipsrst3_bits |= NPCM_IPSRST3_USBD0; + if (!(mdlr & NPCM_MDLR_USBD1)) + ipsrst1_bits |= NPCM_IPSRST1_USBD1; + if (!(mdlr & NPCM_MDLR_USBD2_4)) + ipsrst1_bits |= (NPCM_IPSRST1_USBD2 | + NPCM_IPSRST1_USBD3 | + NPCM_IPSRST1_USBD4); + if (!(mdlr & NPCM_MDLR_USBD0)) { + ipsrst1_bits |= (NPCM_IPSRST1_USBD5 | + NPCM_IPSRST1_USBD6); + ipsrst3_bits |= (NPCM_IPSRST3_USBD7 | + NPCM_IPSRST3_USBD8 | + NPCM_IPSRST3_USBD9); + } + + /* assert reset USB PHY and USB devices */ + iprst1 = readl(rc->base + NPCM_IPSRST1); + iprst2 = readl(rc->base + NPCM_IPSRST2); + iprst3 = readl(rc->base + NPCM_IPSRST3); + + iprst1 |= ipsrst1_bits; + iprst2 |= ipsrst2_bits; + iprst3 |= (ipsrst3_bits | NPCM_IPSRST3_USBPHY1 | + NPCM_IPSRST3_USBPHY2); + + writel(iprst1, rc->base + NPCM_IPSRST1); + writel(iprst2, rc->base + NPCM_IPSRST2); + writel(iprst3, rc->base + NPCM_IPSRST3); + + /* clear USB PHY RS bit */ + regmap_update_bits(gcr_regmap, NPCM_USB1PHYCTL_OFFSET, + NPCM_USBXPHYCTL_RS, 0); + regmap_update_bits(gcr_regmap, NPCM_USB2PHYCTL_OFFSET, + NPCM_USBXPHYCTL_RS, 0); + + /* deassert reset USB PHY */ + iprst3 &= ~(NPCM_IPSRST3_USBPHY1 | NPCM_IPSRST3_USBPHY2); + writel(iprst3, rc->base + NPCM_IPSRST3); + + udelay(50); + + /* set USB PHY RS bit */ + regmap_update_bits(gcr_regmap, NPCM_USB1PHYCTL_OFFSET, + NPCM_USBXPHYCTL_RS, NPCM_USBXPHYCTL_RS); + regmap_update_bits(gcr_regmap, NPCM_USB2PHYCTL_OFFSET, + NPCM_USBXPHYCTL_RS, NPCM_USBXPHYCTL_RS); + + /* deassert reset USB devices*/ + iprst1 &= ~ipsrst1_bits; + iprst2 &= ~ipsrst2_bits; + iprst3 &= ~ipsrst3_bits; + + writel(iprst1, rc->base + NPCM_IPSRST1); + writel(iprst2, rc->base + NPCM_IPSRST2); + writel(iprst3, rc->base + NPCM_IPSRST3); + + return 0; +} + +static const struct reset_control_ops npcm_rc_ops = { + .assert = npcm_rc_assert, + .deassert = npcm_rc_deassert, + .status = npcm_rc_status, +}; + +static int npcm_rc_probe(struct platform_device *pdev) +{ + struct npcm_rc_data *rc; + int ret; + + rc = devm_kzalloc(&pdev->dev, sizeof(*rc), GFP_KERNEL); + if (!rc) + return -ENOMEM; + + rc->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(rc->base)) + return PTR_ERR(rc->base); + + spin_lock_init(&rc->lock); + + rc->rcdev.owner = THIS_MODULE; + rc->rcdev.ops = &npcm_rc_ops; + rc->rcdev.of_node = pdev->dev.of_node; + rc->rcdev.of_reset_n_cells = 2; + rc->rcdev.of_xlate = npcm_reset_xlate; + + platform_set_drvdata(pdev, rc); + + ret = devm_reset_controller_register(&pdev->dev, &rc->rcdev); + if (ret) { + dev_err(&pdev->dev, "unable to register device\n"); + return ret; + } + + if (npcm_usb_reset(pdev, rc)) + dev_warn(&pdev->dev, "NPCM USB reset failed, can cause issues with UDC and USB host\n"); + + if (!of_property_read_u32(pdev->dev.of_node, "nuvoton,sw-reset-number", + &rc->sw_reset_number)) { + if (rc->sw_reset_number && rc->sw_reset_number < 5) { + rc->restart_nb.priority = 192, + rc->restart_nb.notifier_call = npcm_rc_restart, + ret = register_restart_handler(&rc->restart_nb); + if (ret) + dev_warn(&pdev->dev, "failed to register restart handler\n"); + } + } + + return ret; +} + +static struct platform_driver npcm_rc_driver = { + .probe = npcm_rc_probe, + .driver = { + .name = "npcm-reset", + .of_match_table = npcm_rc_match, + .suppress_bind_attrs = true, + }, +}; +builtin_platform_driver(npcm_rc_driver); diff --git a/drivers/reset/reset-qcom-aoss.c b/drivers/reset/reset-qcom-aoss.c index 36db96750450..9333b923dda0 100644 --- a/drivers/reset/reset-qcom-aoss.c +++ b/drivers/reset/reset-qcom-aoss.c @@ -118,6 +118,7 @@ static const struct of_device_id qcom_aoss_reset_of_match[] = { { .compatible = "qcom,sdm845-aoss-cc", .data = &sdm845_aoss_desc }, {} }; +MODULE_DEVICE_TABLE(of, qcom_aoss_reset_of_match); static struct platform_driver qcom_aoss_reset_driver = { .probe = qcom_aoss_reset_probe, @@ -127,7 +128,7 @@ static struct platform_driver qcom_aoss_reset_driver = { }, }; -builtin_platform_driver(qcom_aoss_reset_driver); +module_platform_driver(qcom_aoss_reset_driver); MODULE_DESCRIPTION("Qualcomm AOSS Reset Driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/reset/reset-uniphier.c b/drivers/reset/reset-uniphier.c index 74e589f5dd6a..279e535bf5d8 100644 --- a/drivers/reset/reset-uniphier.c +++ b/drivers/reset/reset-uniphier.c @@ -193,8 +193,8 @@ static const struct uniphier_reset_data uniphier_pro5_sd_reset_data[] = { #define UNIPHIER_PERI_RESET_FI2C(id, ch) \ UNIPHIER_RESETX((id), 0x114, 24 + (ch)) -#define UNIPHIER_PERI_RESET_SCSSI(id) \ - UNIPHIER_RESETX((id), 0x110, 17) +#define UNIPHIER_PERI_RESET_SCSSI(id, ch) \ + UNIPHIER_RESETX((id), 0x110, 17 + (ch)) #define UNIPHIER_PERI_RESET_MCSSI(id) \ UNIPHIER_RESETX((id), 0x114, 14) @@ -209,7 +209,7 @@ static const struct uniphier_reset_data uniphier_ld4_peri_reset_data[] = { UNIPHIER_PERI_RESET_I2C(6, 2), UNIPHIER_PERI_RESET_I2C(7, 3), UNIPHIER_PERI_RESET_I2C(8, 4), - UNIPHIER_PERI_RESET_SCSSI(11), + UNIPHIER_PERI_RESET_SCSSI(11, 0), UNIPHIER_RESET_END, }; @@ -225,8 +225,11 @@ static const struct uniphier_reset_data uniphier_pro4_peri_reset_data[] = { UNIPHIER_PERI_RESET_FI2C(8, 4), UNIPHIER_PERI_RESET_FI2C(9, 5), UNIPHIER_PERI_RESET_FI2C(10, 6), - UNIPHIER_PERI_RESET_SCSSI(11), - UNIPHIER_PERI_RESET_MCSSI(12), + UNIPHIER_PERI_RESET_SCSSI(11, 0), + UNIPHIER_PERI_RESET_SCSSI(12, 1), + UNIPHIER_PERI_RESET_SCSSI(13, 2), + UNIPHIER_PERI_RESET_SCSSI(14, 3), + UNIPHIER_PERI_RESET_MCSSI(15), UNIPHIER_RESET_END, }; diff --git a/include/dt-bindings/reset/nuvoton,npcm7xx-reset.h b/include/dt-bindings/reset/nuvoton,npcm7xx-reset.h new file mode 100644 index 000000000000..df088e68a9ba --- /dev/null +++ b/include/dt-bindings/reset/nuvoton,npcm7xx-reset.h @@ -0,0 +1,91 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +// Copyright (c) 2019 Nuvoton Technology corporation. + +#ifndef _DT_BINDINGS_NPCM7XX_RESET_H +#define _DT_BINDINGS_NPCM7XX_RESET_H + +#define NPCM7XX_RESET_IPSRST1 0x20 +#define NPCM7XX_RESET_IPSRST2 0x24 +#define NPCM7XX_RESET_IPSRST3 0x34 + +/* Reset lines on IP1 reset module (NPCM7XX_RESET_IPSRST1) */ +#define NPCM7XX_RESET_FIU3 1 +#define NPCM7XX_RESET_UDC1 5 +#define NPCM7XX_RESET_EMC1 6 +#define NPCM7XX_RESET_UART_2_3 7 +#define NPCM7XX_RESET_UDC2 8 +#define NPCM7XX_RESET_PECI 9 +#define NPCM7XX_RESET_AES 10 +#define NPCM7XX_RESET_UART_0_1 11 +#define NPCM7XX_RESET_MC 12 +#define NPCM7XX_RESET_SMB2 13 +#define NPCM7XX_RESET_SMB3 14 +#define NPCM7XX_RESET_SMB4 15 +#define NPCM7XX_RESET_SMB5 16 +#define NPCM7XX_RESET_PWM_M0 18 +#define NPCM7XX_RESET_TIMER_0_4 19 +#define NPCM7XX_RESET_TIMER_5_9 20 +#define NPCM7XX_RESET_EMC2 21 +#define NPCM7XX_RESET_UDC4 22 +#define NPCM7XX_RESET_UDC5 23 +#define NPCM7XX_RESET_UDC6 24 +#define NPCM7XX_RESET_UDC3 25 +#define NPCM7XX_RESET_ADC 27 +#define NPCM7XX_RESET_SMB6 28 +#define NPCM7XX_RESET_SMB7 29 +#define NPCM7XX_RESET_SMB0 30 +#define NPCM7XX_RESET_SMB1 31 + +/* Reset lines on IP2 reset module (NPCM7XX_RESET_IPSRST2) */ +#define NPCM7XX_RESET_MFT0 0 +#define NPCM7XX_RESET_MFT1 1 +#define NPCM7XX_RESET_MFT2 2 +#define NPCM7XX_RESET_MFT3 3 +#define NPCM7XX_RESET_MFT4 4 +#define NPCM7XX_RESET_MFT5 5 +#define NPCM7XX_RESET_MFT6 6 +#define NPCM7XX_RESET_MFT7 7 +#define NPCM7XX_RESET_MMC 8 +#define NPCM7XX_RESET_SDHC 9 +#define NPCM7XX_RESET_GFX_SYS 10 +#define NPCM7XX_RESET_AHB_PCIBRG 11 +#define NPCM7XX_RESET_VDMA 12 +#define NPCM7XX_RESET_ECE 13 +#define NPCM7XX_RESET_VCD 14 +#define NPCM7XX_RESET_OTP 16 +#define NPCM7XX_RESET_SIOX1 18 +#define NPCM7XX_RESET_SIOX2 19 +#define NPCM7XX_RESET_3DES 21 +#define NPCM7XX_RESET_PSPI1 22 +#define NPCM7XX_RESET_PSPI2 23 +#define NPCM7XX_RESET_GMAC2 25 +#define NPCM7XX_RESET_USB_HOST 26 +#define NPCM7XX_RESET_GMAC1 28 +#define NPCM7XX_RESET_CP 31 + +/* Reset lines on IP3 reset module (NPCM7XX_RESET_IPSRST3) */ +#define NPCM7XX_RESET_PWM_M1 0 +#define NPCM7XX_RESET_SMB12 1 +#define NPCM7XX_RESET_SPIX 2 +#define NPCM7XX_RESET_SMB13 3 +#define NPCM7XX_RESET_UDC0 4 +#define NPCM7XX_RESET_UDC7 5 +#define NPCM7XX_RESET_UDC8 6 +#define NPCM7XX_RESET_UDC9 7 +#define NPCM7XX_RESET_PCI_MAILBOX 9 +#define NPCM7XX_RESET_SMB14 12 +#define NPCM7XX_RESET_SHA 13 +#define NPCM7XX_RESET_SEC_ECC 14 +#define NPCM7XX_RESET_PCIE_RC 15 +#define NPCM7XX_RESET_TIMER_10_14 16 +#define NPCM7XX_RESET_RNG 17 +#define NPCM7XX_RESET_SMB15 18 +#define NPCM7XX_RESET_SMB8 19 +#define NPCM7XX_RESET_SMB9 20 +#define NPCM7XX_RESET_SMB10 21 +#define NPCM7XX_RESET_SMB11 22 +#define NPCM7XX_RESET_ESPI 23 +#define NPCM7XX_RESET_USB_PHY_1 24 +#define NPCM7XX_RESET_USB_PHY_2 25 + +#endif |