From 5338073561bea23363e5552b647dad75bc7d0f11 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Fri, 20 Jul 2018 17:26:32 +0200 Subject: reset: meson: add dt-bindings for meson-axg audio arb Add dt-bindings for the audio memory arbiter found on Amlogic's A113 based SoCs Reviewed-by: Rob Herring Signed-off-by: Jerome Brunet Signed-off-by: Philipp Zabel --- .../bindings/reset/amlogic,meson-axg-audio-arb.txt | 21 +++++++++++++++++++++ .../dt-bindings/reset/amlogic,meson-axg-audio-arb.h | 17 +++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 Documentation/devicetree/bindings/reset/amlogic,meson-axg-audio-arb.txt create mode 100644 include/dt-bindings/reset/amlogic,meson-axg-audio-arb.h diff --git a/Documentation/devicetree/bindings/reset/amlogic,meson-axg-audio-arb.txt b/Documentation/devicetree/bindings/reset/amlogic,meson-axg-audio-arb.txt new file mode 100644 index 0000000..26e542e --- /dev/null +++ b/Documentation/devicetree/bindings/reset/amlogic,meson-axg-audio-arb.txt @@ -0,0 +1,21 @@ +* Amlogic audio memory arbiter controller + +The Amlogic Audio ARB is a simple device which enables or +disables the access of Audio FIFOs to DDR on AXG based SoC. + +Required properties: +- compatible: 'amlogic,meson-axg-audio-arb' +- reg: physical base address of the controller and length of memory + mapped region. +- clocks: phandle to the fifo peripheral clock provided by the audio + clock controller. +- #reset-cells: must be 1. + +Example on the A113 SoC: + +arb: reset-controller@280 { + compatible = "amlogic,meson-axg-audio-arb"; + reg = <0x0 0x280 0x0 0x4>; + #reset-cells = <1>; + clocks = <&clkc_audio AUD_CLKID_DDR_ARB>; +}; diff --git a/include/dt-bindings/reset/amlogic,meson-axg-audio-arb.h b/include/dt-bindings/reset/amlogic,meson-axg-audio-arb.h new file mode 100644 index 0000000..05c3636 --- /dev/null +++ b/include/dt-bindings/reset/amlogic,meson-axg-audio-arb.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR MIT) + * + * Copyright (c) 2018 Baylibre SAS. + * Author: Jerome Brunet + */ + +#ifndef _DT_BINDINGS_AMLOGIC_MESON_AXG_AUDIO_ARB_H +#define _DT_BINDINGS_AMLOGIC_MESON_AXG_AUDIO_ARB_H + +#define AXG_ARB_TODDR_A 0 +#define AXG_ARB_TODDR_B 1 +#define AXG_ARB_TODDR_C 2 +#define AXG_ARB_FRDDR_A 3 +#define AXG_ARB_FRDDR_B 4 +#define AXG_ARB_FRDDR_C 5 + +#endif /* _DT_BINDINGS_AMLOGIC_MESON_AXG_AUDIO_ARB_H */ -- cgit v1.1 From d903779b58be442f3afd2c51c46c7cf19c97684e Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Fri, 20 Jul 2018 17:26:33 +0200 Subject: reset: meson: add meson audio arb driver The Amlogic Audio ARB is a simple device which enables or disables the access of Audio FIFOs to DDR on AXG based SoC. Signed-off-by: Jerome Brunet Signed-off-by: Philipp Zabel --- drivers/reset/Kconfig | 7 ++ drivers/reset/Makefile | 1 + drivers/reset/reset-meson-audio-arb.c | 168 ++++++++++++++++++++++++++++++++++ 3 files changed, 176 insertions(+) create mode 100644 drivers/reset/reset-meson-audio-arb.c diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index a70262c..13d28fd 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -73,6 +73,13 @@ config RESET_MESON help This enables the reset driver for Amlogic Meson SoCs. +config RESET_MESON_AUDIO_ARB + tristate "Meson Audio Memory Arbiter Reset Driver" + depends on ARCH_MESON || COMPILE_TEST + help + This enables the reset driver for Audio Memory Arbiter of + Amlogic's A113 based SoCs + config RESET_OXNAS bool diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 0676b6b..4243c38 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_RESET_IMX7) += reset-imx7.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_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/reset-meson-audio-arb.c b/drivers/reset/reset-meson-audio-arb.c new file mode 100644 index 0000000..9175161 --- /dev/null +++ b/drivers/reset/reset-meson-audio-arb.c @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +// Copyright (c) 2018 BayLibre, SAS. +// Author: Jerome Brunet + +#include +#include +#include +#include +#include +#include + +#include + +struct meson_audio_arb_data { + struct reset_controller_dev rstc; + void __iomem *regs; + struct clk *clk; + const unsigned int *reset_bits; + spinlock_t lock; +}; + +#define ARB_GENERAL_BIT 31 + +static const unsigned int axg_audio_arb_reset_bits[] = { + [AXG_ARB_TODDR_A] = 0, + [AXG_ARB_TODDR_B] = 1, + [AXG_ARB_TODDR_C] = 2, + [AXG_ARB_FRDDR_A] = 4, + [AXG_ARB_FRDDR_B] = 5, + [AXG_ARB_FRDDR_C] = 6, +}; + +static int meson_audio_arb_update(struct reset_controller_dev *rcdev, + unsigned long id, bool assert) +{ + u32 val; + struct meson_audio_arb_data *arb = + container_of(rcdev, struct meson_audio_arb_data, rstc); + + spin_lock(&arb->lock); + val = readl(arb->regs); + + if (assert) + val &= ~BIT(arb->reset_bits[id]); + else + val |= BIT(arb->reset_bits[id]); + + writel(val, arb->regs); + spin_unlock(&arb->lock); + + return 0; +} + +static int meson_audio_arb_status(struct reset_controller_dev *rcdev, + unsigned long id) +{ + u32 val; + struct meson_audio_arb_data *arb = + container_of(rcdev, struct meson_audio_arb_data, rstc); + + val = readl(arb->regs); + + return !(val & BIT(arb->reset_bits[id])); +} + +static int meson_audio_arb_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return meson_audio_arb_update(rcdev, id, true); +} + +static int meson_audio_arb_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return meson_audio_arb_update(rcdev, id, false); +} + +static const struct reset_control_ops meson_audio_arb_rstc_ops = { + .assert = meson_audio_arb_assert, + .deassert = meson_audio_arb_deassert, + .status = meson_audio_arb_status, +}; + +static const struct of_device_id meson_audio_arb_of_match[] = { + { .compatible = "amlogic,meson-axg-audio-arb", }, + {} +}; +MODULE_DEVICE_TABLE(of, meson_audio_arb_of_match); + +static int meson_audio_arb_remove(struct platform_device *pdev) +{ + struct meson_audio_arb_data *arb = platform_get_drvdata(pdev); + + /* Disable all access */ + spin_lock(&arb->lock); + writel(0, arb->regs); + spin_unlock(&arb->lock); + + clk_disable_unprepare(arb->clk); + + return 0; +} + +static int meson_audio_arb_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct meson_audio_arb_data *arb; + struct resource *res; + int ret; + + arb = devm_kzalloc(dev, sizeof(*arb), GFP_KERNEL); + if (!arb) + return -ENOMEM; + platform_set_drvdata(pdev, arb); + + arb->clk = devm_clk_get(dev, NULL); + if (IS_ERR(arb->clk)) { + if (PTR_ERR(arb->clk) != -EPROBE_DEFER) + dev_err(dev, "failed to get clock\n"); + return PTR_ERR(arb->clk); + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + arb->regs = devm_ioremap_resource(dev, res); + if (IS_ERR(arb->regs)) + return PTR_ERR(arb->regs); + + spin_lock_init(&arb->lock); + arb->reset_bits = axg_audio_arb_reset_bits; + arb->rstc.nr_resets = ARRAY_SIZE(axg_audio_arb_reset_bits); + arb->rstc.ops = &meson_audio_arb_rstc_ops; + arb->rstc.of_node = dev->of_node; + + /* + * Enable general : + * In the initial state, all memory interfaces are disabled + * and the general bit is on + */ + ret = clk_prepare_enable(arb->clk); + if (ret) { + dev_err(dev, "failed to enable arb clock\n"); + return ret; + } + writel(BIT(ARB_GENERAL_BIT), arb->regs); + + /* Register reset controller */ + ret = devm_reset_controller_register(dev, &arb->rstc); + if (ret) { + dev_err(dev, "failed to register arb reset controller\n"); + meson_audio_arb_remove(pdev); + } + + return ret; +} + +static struct platform_driver meson_audio_arb_pdrv = { + .probe = meson_audio_arb_probe, + .remove = meson_audio_arb_remove, + .driver = { + .name = "meson-audio-arb-reset", + .of_match_table = meson_audio_arb_of_match, + }, +}; +module_platform_driver(meson_audio_arb_pdrv); + +MODULE_DESCRIPTION("Amlogic A113 Audio Memory Arbiter"); +MODULE_AUTHOR("Jerome Brunet "); +MODULE_LICENSE("GPL v2"); -- cgit v1.1 From 26fce0557fa639fb7bbc33e31a57cff7df25c3a0 Mon Sep 17 00:00:00 2001 From: Leonard Crestez Date: Fri, 20 Jul 2018 15:47:43 +0300 Subject: reset: imx7: Fix always writing bits as 0 Right now the only user of reset-imx7 is pci-imx6 and the reset_control_assert and deassert calls on pciephy_reset don't toggle the PCIEPHY_BTN and PCIEPHY_G_RST bits as expected. Fix this by writing 1 or 0 respectively. The reference manual is not very clear regarding SRC_PCIEPHY_RCR but for other registers like MIPIPHY and HSICPHY the bits are explicitly documented as "1 means assert, 0 means deassert". The values are still reversed for IMX7_RESET_PCIE_CTRL_APPS_EN. Signed-off-by: Leonard Crestez Reviewed-by: Lucas Stach Signed-off-by: Philipp Zabel --- drivers/reset/reset-imx7.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/reset/reset-imx7.c b/drivers/reset/reset-imx7.c index 4db177b..fdeac19 100644 --- a/drivers/reset/reset-imx7.c +++ b/drivers/reset/reset-imx7.c @@ -80,7 +80,7 @@ static int imx7_reset_set(struct reset_controller_dev *rcdev, { struct imx7_src *imx7src = to_imx7_src(rcdev); const struct imx7_src_signal *signal = &imx7_src_signals[id]; - unsigned int value = 0; + unsigned int value = assert ? signal->bit : 0; switch (id) { case IMX7_RESET_PCIEPHY: -- cgit v1.1 From e9880240e4f4efe40bb47aba3b6602cff2a76b1e Mon Sep 17 00:00:00 2001 From: Amit Kucheria Date: Thu, 23 Aug 2018 14:23:29 +0530 Subject: arm64: dts: Fix various entry-method properties to reflect documentation The idle-states binding documentation[1] mentions that the 'entry-method' property is required on 64-bit platforms and must be set to "psci". commit a13f18f59d26 ("Documentation: arm: Fix typo in the idle-states bindings examples") attempted to fix this earlier but clearly more is needed. Fix the cpu-capacity.txt documentation that uses the incorrect value so we don't get copy-paste errors like these. Clarify the language in idle-states.txt by removing the reference to the psci bindings that might be causing this confusion. Finally, fix devicetrees of various boards to reflect current documentation. [1] Documentation/devicetree/bindings/arm/idle-states.txt (see idle-states node) Signed-off-by: Amit Kucheria Acked-by: Sudeep Holla Acked-by: Li Yang Signed-off-by: Olof Johansson --- Documentation/devicetree/bindings/arm/cpu-capacity.txt | 2 +- Documentation/devicetree/bindings/arm/idle-states.txt | 4 ++-- arch/arm64/boot/dts/arm/juno-r1.dts | 2 +- arch/arm64/boot/dts/arm/juno-r2.dts | 2 +- arch/arm64/boot/dts/arm/juno.dts | 2 +- arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi | 2 +- arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 2 +- arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi | 2 +- arch/arm64/boot/dts/mediatek/mt2712e.dtsi | 2 +- arch/arm64/boot/dts/sprd/sc9860.dtsi | 2 +- arch/arm64/boot/dts/xilinx/zynqmp.dtsi | 2 +- 11 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Documentation/devicetree/bindings/arm/cpu-capacity.txt b/Documentation/devicetree/bindings/arm/cpu-capacity.txt index 7809fbe..9b5685a 100644 --- a/Documentation/devicetree/bindings/arm/cpu-capacity.txt +++ b/Documentation/devicetree/bindings/arm/cpu-capacity.txt @@ -94,7 +94,7 @@ cpus { }; idle-states { - entry-method = "arm,psci"; + entry-method = "psci"; CPU_SLEEP_0: cpu-sleep-0 { compatible = "arm,idle-state"; diff --git a/Documentation/devicetree/bindings/arm/idle-states.txt b/Documentation/devicetree/bindings/arm/idle-states.txt index 7a59133..2c73847 100644 --- a/Documentation/devicetree/bindings/arm/idle-states.txt +++ b/Documentation/devicetree/bindings/arm/idle-states.txt @@ -237,8 +237,8 @@ processor idle states, defined as device tree nodes, are listed. Value type: Usage and definition depend on ARM architecture version. # On ARM v8 64-bit this property is required and must - be one of: - - "psci" (see bindings in [2]) + be: + - "psci" # On ARM 32-bit systems this property is optional The nodes describing the idle states (state) can only be defined within the diff --git a/arch/arm64/boot/dts/arm/juno-r1.dts b/arch/arm64/boot/dts/arm/juno-r1.dts index 2c5db03..b2b7ced 100644 --- a/arch/arm64/boot/dts/arm/juno-r1.dts +++ b/arch/arm64/boot/dts/arm/juno-r1.dts @@ -63,7 +63,7 @@ }; idle-states { - entry-method = "arm,psci"; + entry-method = "psci"; CPU_SLEEP_0: cpu-sleep-0 { compatible = "arm,idle-state"; diff --git a/arch/arm64/boot/dts/arm/juno-r2.dts b/arch/arm64/boot/dts/arm/juno-r2.dts index c51950f..ab77adb 100644 --- a/arch/arm64/boot/dts/arm/juno-r2.dts +++ b/arch/arm64/boot/dts/arm/juno-r2.dts @@ -63,7 +63,7 @@ }; idle-states { - entry-method = "arm,psci"; + entry-method = "psci"; CPU_SLEEP_0: cpu-sleep-0 { compatible = "arm,idle-state"; diff --git a/arch/arm64/boot/dts/arm/juno.dts b/arch/arm64/boot/dts/arm/juno.dts index 2b2bf39..1fb5c5a 100644 --- a/arch/arm64/boot/dts/arm/juno.dts +++ b/arch/arm64/boot/dts/arm/juno.dts @@ -62,7 +62,7 @@ }; idle-states { - entry-method = "arm,psci"; + entry-method = "psci"; CPU_SLEEP_0: cpu-sleep-0 { compatible = "arm,idle-state"; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi index 205f0f4..3a27841 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi @@ -79,7 +79,7 @@ * PSCI node is not added default, U-boot will add missing * parts if it determines to use PSCI. */ - entry-method = "arm,psci"; + entry-method = "psci"; CPU_PH20: cpu-ph20 { compatible = "arm,idle-state"; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi index 1109f22..e238b86 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi @@ -121,7 +121,7 @@ * PSCI node is not added default, U-boot will add missing * parts if it determines to use PSCI. */ - entry-method = "arm,psci"; + entry-method = "psci"; CPU_PH20: cpu-ph20 { compatible = "arm,idle-state"; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi index 136ebfa..1b200f7 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi @@ -117,7 +117,7 @@ * PSCI node is not added default, U-boot will add missing * parts if it determines to use PSCI. */ - entry-method = "arm,psci"; + entry-method = "psci"; CPU_PH20: cpu-ph20 { compatible = "arm,idle-state"; diff --git a/arch/arm64/boot/dts/mediatek/mt2712e.dtsi b/arch/arm64/boot/dts/mediatek/mt2712e.dtsi index 6d8532a..75cc0f7 100644 --- a/arch/arm64/boot/dts/mediatek/mt2712e.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt2712e.dtsi @@ -119,7 +119,7 @@ }; idle-states { - entry-method = "arm,psci"; + entry-method = "psci"; CPU_SLEEP_0: cpu-sleep-0 { compatible = "arm,idle-state"; diff --git a/arch/arm64/boot/dts/sprd/sc9860.dtsi b/arch/arm64/boot/dts/sprd/sc9860.dtsi index 3f5160d2..48f5928 100644 --- a/arch/arm64/boot/dts/sprd/sc9860.dtsi +++ b/arch/arm64/boot/dts/sprd/sc9860.dtsi @@ -114,7 +114,7 @@ }; idle-states{ - entry-method = "arm,psci"; + entry-method = "psci"; CORE_PD: core_pd { compatible = "arm,idle-state"; diff --git a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi index a091e6f..29ce234 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi +++ b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi @@ -58,7 +58,7 @@ }; idle-states { - entry-method = "arm,psci"; + entry-method = "psci"; CPU_SLEEP_0: cpu-sleep-0 { compatible = "arm,idle-state"; -- cgit v1.1 From d1558dfd9f22c99a5b8e1354ad881ee40749da89 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Fri, 24 Aug 2018 16:06:34 +0100 Subject: ARM: rockchip: Force CONFIG_PM on Rockchip systems A number of the Rockchip-specific drivers (IOMMU, display controllers) are now assuming that CONFIG_PM is set, and may completely misbehave if that's not the case. Since there is hardly any reason for this configuration option not to be selected anyway, let's require it (in the same way Tegra already does). Signed-off-by: Marc Zyngier Signed-off-by: Olof Johansson --- arch/arm/mach-rockchip/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-rockchip/Kconfig b/arch/arm/mach-rockchip/Kconfig index fafd3d7..8ca9265 100644 --- a/arch/arm/mach-rockchip/Kconfig +++ b/arch/arm/mach-rockchip/Kconfig @@ -17,6 +17,7 @@ config ARCH_ROCKCHIP select ARM_GLOBAL_TIMER select CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK select ZONE_DMA if ARM_LPAE + select PM help Support for Rockchip's Cortex-A9 Single-to-Quad-Core-SoCs containing the RK2928, RK30xx and RK31xx series. -- cgit v1.1 From 7db7a8f5638a2ffe0c0c0d55b5186b6191fd6af7 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Fri, 24 Aug 2018 16:06:35 +0100 Subject: arm64: rockchip: Force CONFIG_PM on Rockchip systems A number of the Rockchip-specific drivers (IOMMU, display controllers) are now assuming that CONFIG_PM is set, and may completely misbehave if that's not the case. Since there is hardly any reason for this configuration option not to be selected anyway, let's require it (in the same way Tegra already does). Signed-off-by: Marc Zyngier Signed-off-by: Olof Johansson --- arch/arm64/Kconfig.platforms | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms index d5aeac3..21a715a 100644 --- a/arch/arm64/Kconfig.platforms +++ b/arch/arm64/Kconfig.platforms @@ -151,6 +151,7 @@ config ARCH_ROCKCHIP select GPIOLIB select PINCTRL select PINCTRL_ROCKCHIP + select PM select ROCKCHIP_TIMER help This enables support for the ARMv8 based Rockchip chipsets, -- cgit v1.1 From 3fc7c5c0cff3150e471f5fd12f59971c6d2c6513 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Fri, 24 Aug 2018 16:06:36 +0100 Subject: iommu/rockchip: Handle errors returned from PM framework pm_runtime_get_if_in_use can fail: either PM has been disabled altogether (-EINVAL), or the device hasn't been enabled yet (0). Sadly, the Rockchip IOMMU driver tends to conflate the two things by considering a non-zero return value as successful. This has the consequence of hiding other bugs, so let's handle this case throughout the driver, with a WARN_ON_ONCE so that we can try and work out what happened. Fixes: 0f181d3cf7d98 ("iommu/rockchip: Add runtime PM support") Reviewed-by: Heiko Stuebner Signed-off-by: Marc Zyngier Signed-off-by: Olof Johansson --- drivers/iommu/rockchip-iommu.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c index 054cd2c..4e0f9b6 100644 --- a/drivers/iommu/rockchip-iommu.c +++ b/drivers/iommu/rockchip-iommu.c @@ -521,10 +521,11 @@ static irqreturn_t rk_iommu_irq(int irq, void *dev_id) u32 int_status; dma_addr_t iova; irqreturn_t ret = IRQ_NONE; - int i; + int i, err; - if (WARN_ON(!pm_runtime_get_if_in_use(iommu->dev))) - return 0; + err = pm_runtime_get_if_in_use(iommu->dev); + if (WARN_ON_ONCE(err <= 0)) + return ret; if (WARN_ON(clk_bulk_enable(iommu->num_clocks, iommu->clocks))) goto out; @@ -620,11 +621,15 @@ static void rk_iommu_zap_iova(struct rk_iommu_domain *rk_domain, spin_lock_irqsave(&rk_domain->iommus_lock, flags); list_for_each(pos, &rk_domain->iommus) { struct rk_iommu *iommu; + int ret; iommu = list_entry(pos, struct rk_iommu, node); /* Only zap TLBs of IOMMUs that are powered on. */ - if (pm_runtime_get_if_in_use(iommu->dev)) { + ret = pm_runtime_get_if_in_use(iommu->dev); + if (WARN_ON_ONCE(ret < 0)) + continue; + if (ret) { WARN_ON(clk_bulk_enable(iommu->num_clocks, iommu->clocks)); rk_iommu_zap_lines(iommu, iova, size); @@ -891,6 +896,7 @@ static void rk_iommu_detach_device(struct iommu_domain *domain, struct rk_iommu *iommu; struct rk_iommu_domain *rk_domain = to_rk_domain(domain); unsigned long flags; + int ret; /* Allow 'virtual devices' (eg drm) to detach from domain */ iommu = rk_iommu_from_dev(dev); @@ -909,7 +915,9 @@ static void rk_iommu_detach_device(struct iommu_domain *domain, list_del_init(&iommu->node); spin_unlock_irqrestore(&rk_domain->iommus_lock, flags); - if (pm_runtime_get_if_in_use(iommu->dev)) { + ret = pm_runtime_get_if_in_use(iommu->dev); + WARN_ON_ONCE(ret < 0); + if (ret > 0) { rk_iommu_disable(iommu); pm_runtime_put(iommu->dev); } @@ -946,7 +954,8 @@ static int rk_iommu_attach_device(struct iommu_domain *domain, list_add_tail(&iommu->node, &rk_domain->iommus); spin_unlock_irqrestore(&rk_domain->iommus_lock, flags); - if (!pm_runtime_get_if_in_use(iommu->dev)) + ret = pm_runtime_get_if_in_use(iommu->dev); + if (!ret || WARN_ON_ONCE(ret < 0)) return 0; ret = rk_iommu_enable(iommu); -- cgit v1.1 From 1aa55ca9b14af6cfd987ce4fdaf548f7067a5d07 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Fri, 24 Aug 2018 16:06:37 +0100 Subject: iommu/rockchip: Move irq request past pm_runtime_enable Enabling the interrupt early, before power has been applied to the device, can result in an interrupt being delivered too early if: - the IOMMU shares an interrupt with a VOP - the VOP has a pending interrupt (after a kexec, for example) In these conditions, we end-up taking the interrupt without the IOMMU being ready to handle the interrupt (not powered on). Moving the interrupt request past the pm_runtime_enable() call makes sure we can at least access the IOMMU registers. Note that this is only a partial fix, and that the VOP interrupt will still be screaming until the VOP driver kicks in, which advocates for a more synchronized interrupt enabling/disabling approach. Fixes: 0f181d3cf7d98 ("iommu/rockchip: Add runtime PM support") Reviewed-by: Heiko Stuebner Signed-off-by: Marc Zyngier Signed-off-by: Olof Johansson --- drivers/iommu/rockchip-iommu.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c index 4e0f9b6..2b1724e 100644 --- a/drivers/iommu/rockchip-iommu.c +++ b/drivers/iommu/rockchip-iommu.c @@ -1161,17 +1161,6 @@ static int rk_iommu_probe(struct platform_device *pdev) if (iommu->num_mmu == 0) return PTR_ERR(iommu->bases[0]); - i = 0; - while ((irq = platform_get_irq(pdev, i++)) != -ENXIO) { - if (irq < 0) - return irq; - - err = devm_request_irq(iommu->dev, irq, rk_iommu_irq, - IRQF_SHARED, dev_name(dev), iommu); - if (err) - return err; - } - iommu->reset_disabled = device_property_read_bool(dev, "rockchip,disable-mmu-reset"); @@ -1228,6 +1217,19 @@ static int rk_iommu_probe(struct platform_device *pdev) pm_runtime_enable(dev); + i = 0; + while ((irq = platform_get_irq(pdev, i++)) != -ENXIO) { + if (irq < 0) + return irq; + + err = devm_request_irq(iommu->dev, irq, rk_iommu_irq, + IRQF_SHARED, dev_name(dev), iommu); + if (err) { + pm_runtime_disable(dev); + goto err_remove_sysfs; + } + } + return 0; err_remove_sysfs: iommu_device_sysfs_remove(&iommu->iommu); -- cgit v1.1