diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2021-09-02 01:25:28 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2021-09-02 01:25:28 +0300 |
commit | 866147b8fa59530812fc769027a94468d89401e7 (patch) | |
tree | 1d97cf66b7db6765570ba824c51bd3dc84b561fc /drivers/reset | |
parent | 634135a07b887a8ad8904da8c147407650747a38 (diff) | |
parent | 06779631d18ff2901af604eadea0d7b2193db7a1 (diff) | |
download | linux-866147b8fa59530812fc769027a94468d89401e7.tar.xz |
Merge tag 'drivers-5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
Pull ARM SoC driver updates from Arnd Bergmann:
"These are updates for drivers that are tied to a particular SoC,
including the correspondig device tree bindings:
- A couple of reset controller changes for unisoc, uniphier, renesas
and zte platforms
- memory controller driver fixes for omap and tegra
- Rockchip io domain driver updates
- Lots of updates for qualcomm platforms, mostly touching their
firmware and power management drivers
- Tegra FUSE and firmware driver updateѕ
- Support for virtio transports in the SCMI firmware framework
- cleanup of ixp4xx drivers, towards enabling multiplatform support
and bringing it up to date with modern platforms
- Minor updates for keystone, mediatek, omap, renesas"
* tag 'drivers-5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc: (96 commits)
reset: simple: remove ZTE details in Kconfig help
soc: rockchip: io-domain: Remove unneeded semicolon
soc: rockchip: io-domain: add rk3568 support
dt-bindings: power: add rk3568-pmu-io-domain support
bus: ixp4xx: return on error in ixp4xx_exp_probe()
soc: renesas: Prefer memcpy() over strcpy()
firmware: tegra: Stop using seq_get_buf()
soc/tegra: fuse: Enable fuse clock on suspend for Tegra124
soc/tegra: fuse: Add runtime PM support
soc/tegra: fuse: Clear fuse->clk on driver probe failure
soc/tegra: pmc: Prevent racing with cpuilde driver
soc/tegra: bpmp: Remove unused including <linux/version.h>
dt-bindings: soc: ti: pruss: Add dma-coherent property
soc: ti: Remove pm_runtime_irq_safe() usage for smartreflex
soc: ti: pruss: Enable support for ICSSG subsystems on K3 AM64x SoCs
dt-bindings: soc: ti: pruss: Update bindings for K3 AM64x SoCs
firmware: arm_scmi: Use WARN_ON() to check configured transports
firmware: arm_scmi: Fix boolconv.cocci warnings
soc: mediatek: mmsys: Fix missing UFOE component in mt8173 table routing
soc: mediatek: mmsys: add MT8365 support
...
Diffstat (limited to 'drivers/reset')
-rw-r--r-- | drivers/reset/Kconfig | 8 | ||||
-rw-r--r-- | drivers/reset/Makefile | 1 | ||||
-rw-r--r-- | drivers/reset/reset-qcom-pdc.c | 62 | ||||
-rw-r--r-- | drivers/reset/reset-rzg2l-usbphy-ctrl.c | 175 |
4 files changed, 234 insertions, 12 deletions
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 5656cac04b4c..be799a5abf8a 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -181,6 +181,13 @@ config RESET_RASPBERRYPI interfacing with RPi4's co-processor and model these firmware initialization routines as reset lines. +config RESET_RZG2L_USBPHY_CTRL + tristate "Renesas RZ/G2L USBPHY control driver" + depends on ARCH_R9A07G044 || COMPILE_TEST + help + Support for USBPHY Control found on RZ/G2L family. It mainly + controls reset and power down of the USB/PHY. + config RESET_SCMI tristate "Reset driver controlled via ARM SCMI interface" depends on ARM_SCMI_PROTOCOL || COMPILE_TEST @@ -207,7 +214,6 @@ config RESET_SIMPLE - Realtek SoCs - RCC reset controller in STM32 MCUs - Allwinner SoCs - - ZTE's zx2967 family - SiFive FU740 SoCs config RESET_SOCFPGA diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index ea8b8d9ca565..21d46d8869ff 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_RESET_PISTACHIO) += reset-pistachio.o obj-$(CONFIG_RESET_QCOM_AOSS) += reset-qcom-aoss.o obj-$(CONFIG_RESET_QCOM_PDC) += reset-qcom-pdc.o obj-$(CONFIG_RESET_RASPBERRYPI) += reset-raspberrypi.o +obj-$(CONFIG_RESET_RZG2L_USBPHY_CTRL) += reset-rzg2l-usbphy-ctrl.o obj-$(CONFIG_RESET_SCMI) += reset-scmi.o obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o diff --git a/drivers/reset/reset-qcom-pdc.c b/drivers/reset/reset-qcom-pdc.c index ab74bccd4a5b..f22bb49a4ac8 100644 --- a/drivers/reset/reset-qcom-pdc.c +++ b/drivers/reset/reset-qcom-pdc.c @@ -11,18 +11,26 @@ #include <dt-bindings/reset/qcom,sdm845-pdc.h> -#define RPMH_PDC_SYNC_RESET 0x100 +#define RPMH_SDM845_PDC_SYNC_RESET 0x100 +#define RPMH_SC7280_PDC_SYNC_RESET 0x1000 struct qcom_pdc_reset_map { u8 bit; }; +struct qcom_pdc_reset_desc { + const struct qcom_pdc_reset_map *resets; + size_t num_resets; + unsigned int offset; +}; + struct qcom_pdc_reset_data { struct reset_controller_dev rcdev; struct regmap *regmap; + const struct qcom_pdc_reset_desc *desc; }; -static const struct regmap_config sdm845_pdc_regmap_config = { +static const struct regmap_config pdc_regmap_config = { .name = "pdc-reset", .reg_bits = 32, .reg_stride = 4, @@ -44,6 +52,33 @@ static const struct qcom_pdc_reset_map sdm845_pdc_resets[] = { [PDC_MODEM_SYNC_RESET] = {9}, }; +static const struct qcom_pdc_reset_desc sdm845_pdc_reset_desc = { + .resets = sdm845_pdc_resets, + .num_resets = ARRAY_SIZE(sdm845_pdc_resets), + .offset = RPMH_SDM845_PDC_SYNC_RESET, +}; + +static const struct qcom_pdc_reset_map sc7280_pdc_resets[] = { + [PDC_APPS_SYNC_RESET] = {0}, + [PDC_SP_SYNC_RESET] = {1}, + [PDC_AUDIO_SYNC_RESET] = {2}, + [PDC_SENSORS_SYNC_RESET] = {3}, + [PDC_AOP_SYNC_RESET] = {4}, + [PDC_DEBUG_SYNC_RESET] = {5}, + [PDC_GPU_SYNC_RESET] = {6}, + [PDC_DISPLAY_SYNC_RESET] = {7}, + [PDC_COMPUTE_SYNC_RESET] = {8}, + [PDC_MODEM_SYNC_RESET] = {9}, + [PDC_WLAN_RF_SYNC_RESET] = {10}, + [PDC_WPSS_SYNC_RESET] = {11}, +}; + +static const struct qcom_pdc_reset_desc sc7280_pdc_reset_desc = { + .resets = sc7280_pdc_resets, + .num_resets = ARRAY_SIZE(sc7280_pdc_resets), + .offset = RPMH_SC7280_PDC_SYNC_RESET, +}; + static inline struct qcom_pdc_reset_data *to_qcom_pdc_reset_data( struct reset_controller_dev *rcdev) { @@ -54,19 +89,18 @@ static int qcom_pdc_control_assert(struct reset_controller_dev *rcdev, unsigned long idx) { struct qcom_pdc_reset_data *data = to_qcom_pdc_reset_data(rcdev); + u32 mask = BIT(data->desc->resets[idx].bit); - return regmap_update_bits(data->regmap, RPMH_PDC_SYNC_RESET, - BIT(sdm845_pdc_resets[idx].bit), - BIT(sdm845_pdc_resets[idx].bit)); + return regmap_update_bits(data->regmap, data->desc->offset, mask, mask); } static int qcom_pdc_control_deassert(struct reset_controller_dev *rcdev, unsigned long idx) { struct qcom_pdc_reset_data *data = to_qcom_pdc_reset_data(rcdev); + u32 mask = BIT(data->desc->resets[idx].bit); - return regmap_update_bits(data->regmap, RPMH_PDC_SYNC_RESET, - BIT(sdm845_pdc_resets[idx].bit), 0); + return regmap_update_bits(data->regmap, data->desc->offset, mask, 0); } static const struct reset_control_ops qcom_pdc_reset_ops = { @@ -76,22 +110,27 @@ static const struct reset_control_ops qcom_pdc_reset_ops = { static int qcom_pdc_reset_probe(struct platform_device *pdev) { + const struct qcom_pdc_reset_desc *desc; struct qcom_pdc_reset_data *data; struct device *dev = &pdev->dev; void __iomem *base; struct resource *res; + desc = device_get_match_data(&pdev->dev); + if (!desc) + return -EINVAL; + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; + data->desc = desc; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); base = devm_ioremap_resource(dev, res); if (IS_ERR(base)) return PTR_ERR(base); - data->regmap = devm_regmap_init_mmio(dev, base, - &sdm845_pdc_regmap_config); + data->regmap = devm_regmap_init_mmio(dev, base, &pdc_regmap_config); if (IS_ERR(data->regmap)) { dev_err(dev, "Unable to initialize regmap\n"); return PTR_ERR(data->regmap); @@ -99,14 +138,15 @@ static int qcom_pdc_reset_probe(struct platform_device *pdev) data->rcdev.owner = THIS_MODULE; data->rcdev.ops = &qcom_pdc_reset_ops; - data->rcdev.nr_resets = ARRAY_SIZE(sdm845_pdc_resets); + data->rcdev.nr_resets = desc->num_resets; data->rcdev.of_node = dev->of_node; return devm_reset_controller_register(dev, &data->rcdev); } static const struct of_device_id qcom_pdc_reset_of_match[] = { - { .compatible = "qcom,sdm845-pdc-global" }, + { .compatible = "qcom,sc7280-pdc-global", .data = &sc7280_pdc_reset_desc }, + { .compatible = "qcom,sdm845-pdc-global", .data = &sdm845_pdc_reset_desc }, {} }; MODULE_DEVICE_TABLE(of, qcom_pdc_reset_of_match); diff --git a/drivers/reset/reset-rzg2l-usbphy-ctrl.c b/drivers/reset/reset-rzg2l-usbphy-ctrl.c new file mode 100644 index 000000000000..e0704fd2b533 --- /dev/null +++ b/drivers/reset/reset-rzg2l-usbphy-ctrl.c @@ -0,0 +1,175 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas RZ/G2L USBPHY control driver + * + * Copyright (C) 2021 Renesas Electronics Corporation + */ + +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/reset.h> +#include <linux/reset-controller.h> + +#define RESET 0x000 + +#define RESET_SEL_PLLRESET BIT(12) +#define RESET_PLLRESET BIT(8) + +#define RESET_SEL_P2RESET BIT(5) +#define RESET_SEL_P1RESET BIT(4) +#define RESET_PHYRST_2 BIT(1) +#define RESET_PHYRST_1 BIT(0) + +#define PHY_RESET_PORT2 (RESET_SEL_P2RESET | RESET_PHYRST_2) +#define PHY_RESET_PORT1 (RESET_SEL_P1RESET | RESET_PHYRST_1) + +#define NUM_PORTS 2 + +struct rzg2l_usbphy_ctrl_priv { + struct reset_controller_dev rcdev; + struct reset_control *rstc; + void __iomem *base; + + spinlock_t lock; +}; + +#define rcdev_to_priv(x) container_of(x, struct rzg2l_usbphy_ctrl_priv, rcdev) + +static int rzg2l_usbphy_ctrl_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct rzg2l_usbphy_ctrl_priv *priv = rcdev_to_priv(rcdev); + u32 port_mask = PHY_RESET_PORT1 | PHY_RESET_PORT2; + void __iomem *base = priv->base; + unsigned long flags; + u32 val; + + spin_lock_irqsave(&priv->lock, flags); + val = readl(base + RESET); + val |= id ? PHY_RESET_PORT2 : PHY_RESET_PORT1; + if (port_mask == (val & port_mask)) + val |= RESET_PLLRESET; + writel(val, base + RESET); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +static int rzg2l_usbphy_ctrl_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct rzg2l_usbphy_ctrl_priv *priv = rcdev_to_priv(rcdev); + void __iomem *base = priv->base; + unsigned long flags; + u32 val; + + spin_lock_irqsave(&priv->lock, flags); + val = readl(base + RESET); + + val |= RESET_SEL_PLLRESET; + val &= ~(RESET_PLLRESET | (id ? PHY_RESET_PORT2 : PHY_RESET_PORT1)); + writel(val, base + RESET); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +static int rzg2l_usbphy_ctrl_status(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct rzg2l_usbphy_ctrl_priv *priv = rcdev_to_priv(rcdev); + u32 port_mask; + + port_mask = id ? PHY_RESET_PORT2 : PHY_RESET_PORT1; + + return !!(readl(priv->base + RESET) & port_mask); +} + +static const struct of_device_id rzg2l_usbphy_ctrl_match_table[] = { + { .compatible = "renesas,rzg2l-usbphy-ctrl" }, + { /* Sentinel */ } +}; +MODULE_DEVICE_TABLE(of, rzg2l_usbphy_ctrl_match_table); + +static const struct reset_control_ops rzg2l_usbphy_ctrl_reset_ops = { + .assert = rzg2l_usbphy_ctrl_assert, + .deassert = rzg2l_usbphy_ctrl_deassert, + .status = rzg2l_usbphy_ctrl_status, +}; + +static int rzg2l_usbphy_ctrl_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct rzg2l_usbphy_ctrl_priv *priv; + unsigned long flags; + int error; + u32 val; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + priv->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); + if (IS_ERR(priv->rstc)) + return dev_err_probe(dev, PTR_ERR(priv->rstc), + "failed to get reset\n"); + + reset_control_deassert(priv->rstc); + + priv->rcdev.ops = &rzg2l_usbphy_ctrl_reset_ops; + priv->rcdev.of_reset_n_cells = 1; + priv->rcdev.nr_resets = NUM_PORTS; + priv->rcdev.of_node = dev->of_node; + priv->rcdev.dev = dev; + + error = devm_reset_controller_register(dev, &priv->rcdev); + if (error) + return error; + + spin_lock_init(&priv->lock); + dev_set_drvdata(dev, priv); + + pm_runtime_enable(&pdev->dev); + pm_runtime_resume_and_get(&pdev->dev); + + /* put pll and phy into reset state */ + spin_lock_irqsave(&priv->lock, flags); + val = readl(priv->base + RESET); + val |= RESET_SEL_PLLRESET | RESET_PLLRESET | PHY_RESET_PORT2 | PHY_RESET_PORT1; + writel(val, priv->base + RESET); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +static int rzg2l_usbphy_ctrl_remove(struct platform_device *pdev) +{ + struct rzg2l_usbphy_ctrl_priv *priv = dev_get_drvdata(&pdev->dev); + + pm_runtime_put(&pdev->dev); + pm_runtime_disable(&pdev->dev); + reset_control_assert(priv->rstc); + + return 0; +} + +static struct platform_driver rzg2l_usbphy_ctrl_driver = { + .driver = { + .name = "rzg2l_usbphy_ctrl", + .of_match_table = rzg2l_usbphy_ctrl_match_table, + }, + .probe = rzg2l_usbphy_ctrl_probe, + .remove = rzg2l_usbphy_ctrl_remove, +}; +module_platform_driver(rzg2l_usbphy_ctrl_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Renesas RZ/G2L USBPHY Control"); +MODULE_AUTHOR("biju.das.jz@bp.renesas.com>"); |