Merge tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 8 Feb 2020 22:04:19 +0000 (14:04 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 8 Feb 2020 22:04:19 +0000 (14:04 -0800)
Pull ARM SoC-related driver updates from Olof Johansson:
 "Various driver updates for platforms:

   - Nvidia: Fuse support for Tegra194, continued memory controller
     pieces for Tegra30

   - NXP/FSL: Refactorings of QuickEngine drivers to support
     ARM/ARM64/PPC

   - NXP/FSL: i.MX8MP SoC driver pieces

   - TI Keystone: ring accelerator driver

   - Qualcomm: SCM driver cleanup/refactoring + support for new SoCs.

   - Xilinx ZynqMP: feature checking interface for firmware. Mailbox
     communication for power management

   - Overall support patch set for cpuidle on more complex hierarchies
     (PSCI-based)

  and misc cleanups, refactorings of Marvell, TI, other platforms"

* tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc: (166 commits)
  drivers: soc: xilinx: Use mailbox IPI callback
  dt-bindings: power: reset: xilinx: Add bindings for ipi mailbox
  drivers: soc: ti: knav_qmss_queue: Pass lockdep expression to RCU lists
  MAINTAINERS: Add brcmstb PCIe controller entry
  soc/tegra: fuse: Unmap registers once they are not needed anymore
  soc/tegra: fuse: Correct straps' address for older Tegra124 device trees
  soc/tegra: fuse: Warn if straps are not ready
  soc/tegra: fuse: Cache values of straps and Chip ID registers
  memory: tegra30-emc: Correct error message for timed out auto calibration
  memory: tegra30-emc: Firm up hardware programming sequence
  memory: tegra30-emc: Firm up suspend/resume sequence
  soc/tegra: regulators: Do nothing if voltage is unchanged
  memory: tegra: Correct reset value of xusb_hostr
  soc/tegra: fuse: Add APB DMA dependency for Tegra20
  bus: tegra-aconnect: Remove PM_CLK dependency
  dt-bindings: mediatek: add MT6765 power dt-bindings
  soc: mediatek: cmdq: delete not used define
  memory: tegra: Add support for the Tegra194 memory controller
  memory: tegra: Only include support for enabled SoCs
  memory: tegra: Support DVFS on Tegra186 and later
  ...

142 files changed:
Documentation/devicetree/bindings/arm/cpus.yaml
Documentation/devicetree/bindings/arm/msm/qcom,llcc.yaml
Documentation/devicetree/bindings/arm/psci.yaml
Documentation/devicetree/bindings/power/qcom,rpmpd.txt [deleted file]
Documentation/devicetree/bindings/power/qcom,rpmpd.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/power/reset/xlnx,zynqmp-power.txt
Documentation/devicetree/bindings/reset/brcm,bcm7216-pcie-sata-rescal.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/reset/intel,rcu-gw.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/reset/nuvoton,npcm-reset.txt [new file with mode: 0644]
Documentation/devicetree/bindings/soc/mediatek/scpsys.txt
MAINTAINERS
arch/arm64/boot/dts/qcom/msm8916.dtsi
arch/powerpc/include/asm/cpm.h
arch/powerpc/platforms/83xx/km83xx.c
arch/powerpc/platforms/83xx/misc.c
arch/powerpc/platforms/83xx/mpc832x_mds.c
arch/powerpc/platforms/83xx/mpc832x_rdb.c
arch/powerpc/platforms/83xx/mpc836x_mds.c
arch/powerpc/platforms/83xx/mpc836x_rdk.c
arch/powerpc/platforms/83xx/mpc83xx.h
arch/powerpc/platforms/85xx/corenet_generic.c
arch/powerpc/platforms/85xx/mpc85xx_mds.c
arch/powerpc/platforms/85xx/mpc85xx_rdb.c
arch/powerpc/platforms/85xx/twr_p102x.c
drivers/base/power/domain.c
drivers/bus/Kconfig
drivers/bus/moxtet.c
drivers/bus/ti-sysc.c
drivers/clk/clk-scmi.c
drivers/cpufreq/scmi-cpufreq.c
drivers/cpuidle/Makefile
drivers/cpuidle/cpuidle-psci-domain.c [new file with mode: 0644]
drivers/cpuidle/cpuidle-psci.c
drivers/cpuidle/cpuidle-psci.h [new file with mode: 0644]
drivers/cpuidle/dt_idle_states.c
drivers/firmware/Kconfig
drivers/firmware/Makefile
drivers/firmware/arm_scmi/bus.c
drivers/firmware/arm_scmi/clock.c
drivers/firmware/arm_scmi/common.h
drivers/firmware/arm_scmi/driver.c
drivers/firmware/arm_scmi/perf.c
drivers/firmware/arm_scmi/power.c
drivers/firmware/arm_scmi/reset.c
drivers/firmware/arm_scmi/scmi_pm_domain.c
drivers/firmware/arm_scmi/sensors.c
drivers/firmware/imx/Kconfig
drivers/firmware/psci/psci.c
drivers/firmware/qcom_scm-32.c [deleted file]
drivers/firmware/qcom_scm-64.c [deleted file]
drivers/firmware/qcom_scm-legacy.c [new file with mode: 0644]
drivers/firmware/qcom_scm-smc.c [new file with mode: 0644]
drivers/firmware/qcom_scm.c
drivers/firmware/qcom_scm.h
drivers/firmware/turris-mox-rwtm.c
drivers/firmware/xilinx/zynqmp.c
drivers/hwmon/scmi-hwmon.c
drivers/mailbox/armada-37xx-rwtm-mailbox.c
drivers/memory/mvebu-devbus.c
drivers/memory/samsung/Kconfig
drivers/memory/samsung/exynos-srom.c
drivers/memory/samsung/exynos5422-dmc.c
drivers/memory/tegra/Makefile
drivers/memory/tegra/tegra124-emc.c
drivers/memory/tegra/tegra186-emc.c [new file with mode: 0644]
drivers/memory/tegra/tegra186.c
drivers/memory/tegra/tegra20-emc.c
drivers/memory/tegra/tegra210.c
drivers/memory/tegra/tegra30-emc.c
drivers/net/ethernet/freescale/Kconfig
drivers/net/wan/fsl_ucc_hdlc.c
drivers/net/wan/fsl_ucc_hdlc.h
drivers/of/base.c
drivers/reset/Kconfig
drivers/reset/Makefile
drivers/reset/core.c
drivers/reset/reset-brcmstb-rescal.c [new file with mode: 0644]
drivers/reset/reset-intel-gw.c [new file with mode: 0644]
drivers/reset/reset-npcm.c [new file with mode: 0644]
drivers/reset/reset-qcom-aoss.c
drivers/reset/reset-scmi.c
drivers/reset/reset-uniphier.c
drivers/soc/bcm/brcmstb/biuctrl.c
drivers/soc/fsl/qe/Kconfig
drivers/soc/fsl/qe/gpio.c
drivers/soc/fsl/qe/qe.c
drivers/soc/fsl/qe/qe_common.c
drivers/soc/fsl/qe/qe_ic.c
drivers/soc/fsl/qe/qe_ic.h [deleted file]
drivers/soc/fsl/qe/qe_io.c
drivers/soc/fsl/qe/qe_tdm.c
drivers/soc/fsl/qe/ucc.c
drivers/soc/fsl/qe/ucc_fast.c
drivers/soc/fsl/qe/ucc_slow.c
drivers/soc/fsl/qe/usb.c
drivers/soc/imx/Kconfig
drivers/soc/imx/soc-imx8.c
drivers/soc/mediatek/mtk-cmdq-helper.c
drivers/soc/qcom/Kconfig
drivers/soc/qcom/qmi_interface.c
drivers/soc/qcom/rpmhpd.c
drivers/soc/renesas/Kconfig
drivers/soc/renesas/rcar-rst.c
drivers/soc/samsung/Kconfig
drivers/soc/samsung/exynos-chipid.c
drivers/soc/samsung/exynos-pmu.c
drivers/soc/samsung/exynos-pmu.h
drivers/soc/samsung/exynos3250-pmu.c
drivers/soc/samsung/exynos4-pmu.c
drivers/soc/samsung/exynos5250-pmu.c
drivers/soc/samsung/exynos5420-pmu.c
drivers/soc/tegra/Kconfig
drivers/soc/tegra/fuse/fuse-tegra.c
drivers/soc/tegra/fuse/fuse-tegra30.c
drivers/soc/tegra/fuse/fuse.h
drivers/soc/tegra/fuse/tegra-apbmisc.c
drivers/soc/tegra/regulators-tegra20.c
drivers/soc/tegra/regulators-tegra30.c
drivers/soc/ti/knav_qmss_queue.c
drivers/soc/xilinx/Kconfig
drivers/soc/xilinx/zynqmp_power.c
drivers/tee/optee/core.c
drivers/tty/serial/ucc_uart.c
include/dt-bindings/power/mt6765-power.h [new file with mode: 0644]
include/dt-bindings/power/qcom-rpmpd.h
include/dt-bindings/reset/nuvoton,npcm7xx-reset.h [new file with mode: 0644]
include/linux/cpuhotplug.h
include/linux/firmware/xlnx-zynqmp.h
include/linux/of.h
include/linux/platform_data/ti-sysc.h
include/linux/pm_domain.h
include/linux/psci.h
include/linux/qcom_scm.h
include/linux/scmi_protocol.h
include/linux/soc/samsung/exynos-pmu.h
include/linux/soc/samsung/exynos-regs-pmu.h
include/soc/fsl/cpm.h [new file with mode: 0644]
include/soc/fsl/qe/qe.h
include/soc/fsl/qe/qe_ic.h [deleted file]
include/soc/fsl/qe/ucc_fast.h
include/soc/fsl/qe/ucc_slow.h
include/trace/events/scmi.h [new file with mode: 0644]

index c23c24ff757535f3178864ebfc0b7ac6990d3109..7a9c3ce2dbef991d87c2111609c0aff4db40ca57 100644 (file)
@@ -242,6 +242,21 @@ properties:
 
       where voltage is in V, frequency is in MHz.
 
+  power-domains:
+    $ref: '/schemas/types.yaml#/definitions/phandle-array'
+    description:
+      List of phandles and PM domain specifiers, as defined by bindings of the
+      PM domain provider (see also ../power_domain.txt).
+
+  power-domain-names:
+    $ref: '/schemas/types.yaml#/definitions/string-array'
+    description:
+      A list of power domain name strings sorted in the same order as the
+      power-domains property.
+
+      For PSCI based platforms, the name corresponding to the index of the PSCI
+      PM domain provider, must be "psci".
+
   qcom,saw:
     $ref: '/schemas/types.yaml#/definitions/phandle'
     description: |
index 558749065b9773717fae3dfb7d825c0c288c74ca..79902f470e4b47574a87416b6059de30dd01bd99 100644 (file)
@@ -47,7 +47,7 @@ examples:
   - |
     #include <dt-bindings/interrupt-controller/arm-gic.h>
 
-    cache-controller@1100000 {
+    system-cache-controller@1100000 {
       compatible = "qcom,sdm845-llcc";
       reg = <0x1100000 0x200000>, <0x1300000 0x50000> ;
       reg-names = "llcc_base", "llcc_broadcast_base";
index 7abdf58b335eb82b493b3ee7fe105f551e1db4c3..8ef85420b2ab1913786fc69dd5fbfda86c8c1f0b 100644 (file)
@@ -102,6 +102,34 @@ properties:
       [1] Kernel documentation - ARM idle states bindings
         Documentation/devicetree/bindings/arm/idle-states.txt
 
+  "#power-domain-cells":
+    description:
+      The number of cells in a PM domain specifier as per binding in [3].
+      Must be 0 as to represent a single PM domain.
+
+      ARM systems can have multiple cores, sometimes in an hierarchical
+      arrangement. This often, but not always, maps directly to the processor
+      power topology of the system. Individual nodes in a topology have their
+      own specific power states and can be better represented hierarchically.
+
+      For these cases, the definitions of the idle states for the CPUs and the
+      CPU topology, must conform to the binding in [3]. The idle states
+      themselves must conform to the binding in [4] and must specify the
+      arm,psci-suspend-param property.
+
+      It should also be noted that, in PSCI firmware v1.0 the OS-Initiated
+      (OSI) CPU suspend mode is introduced. Using a hierarchical representation
+      helps to implement support for OSI mode and OS implementations may choose
+      to mandate it.
+
+      [3] Documentation/devicetree/bindings/power/power_domain.txt
+      [4] Documentation/devicetree/bindings/power/domain-idle-state.txt
+
+  power-domains:
+    $ref: '/schemas/types.yaml#/definitions/phandle-array'
+    description:
+      List of phandles and PM domain specifiers, as defined by bindings of the
+      PM domain provider.
 
 required:
   - compatible
@@ -160,4 +188,80 @@ examples:
       cpu_on = <0x95c10002>;
       cpu_off = <0x95c10001>;
     };
+
+  - |+
+
+    // Case 4: CPUs and CPU idle states described using the hierarchical model.
+
+    cpus {
+      #size-cells = <0>;
+      #address-cells = <1>;
+
+      CPU0: cpu@0 {
+        device_type = "cpu";
+        compatible = "arm,cortex-a53", "arm,armv8";
+        reg = <0x0>;
+        enable-method = "psci";
+        power-domains = <&CPU_PD0>;
+        power-domain-names = "psci";
+      };
+
+      CPU1: cpu@1 {
+        device_type = "cpu";
+        compatible = "arm,cortex-a57", "arm,armv8";
+        reg = <0x100>;
+        enable-method = "psci";
+        power-domains = <&CPU_PD1>;
+        power-domain-names = "psci";
+      };
+
+      idle-states {
+
+        CPU_PWRDN: cpu-power-down {
+          compatible = "arm,idle-state";
+          arm,psci-suspend-param = <0x0000001>;
+          entry-latency-us = <10>;
+          exit-latency-us = <10>;
+          min-residency-us = <100>;
+        };
+
+        CLUSTER_RET: cluster-retention {
+          compatible = "domain-idle-state";
+          arm,psci-suspend-param = <0x1000011>;
+          entry-latency-us = <500>;
+          exit-latency-us = <500>;
+          min-residency-us = <2000>;
+        };
+
+        CLUSTER_PWRDN: cluster-power-down {
+          compatible = "domain-idle-state";
+          arm,psci-suspend-param = <0x1000031>;
+          entry-latency-us = <2000>;
+          exit-latency-us = <2000>;
+          min-residency-us = <6000>;
+        };
+      };
+    };
+
+    psci {
+      compatible = "arm,psci-1.0";
+      method = "smc";
+
+      CPU_PD0: cpu-pd0 {
+        #power-domain-cells = <0>;
+        domain-idle-states = <&CPU_PWRDN>;
+        power-domains = <&CLUSTER_PD>;
+      };
+
+      CPU_PD1: cpu-pd1 {
+        #power-domain-cells = <0>;
+        domain-idle-states =  <&CPU_PWRDN>;
+        power-domains = <&CLUSTER_PD>;
+      };
+
+      CLUSTER_PD: cluster-pd {
+        #power-domain-cells = <0>;
+        domain-idle-states = <&CLUSTER_RET>, <&CLUSTER_PWRDN>;
+      };
+    };
 ...
diff --git a/Documentation/devicetree/bindings/power/qcom,rpmpd.txt b/Documentation/devicetree/bindings/power/qcom,rpmpd.txt
deleted file mode 100644 (file)
index bc75bf4..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-Qualcomm RPM/RPMh Power domains
-
-For RPM/RPMh Power domains, we communicate a performance state to RPM/RPMh
-which then translates it into a corresponding voltage on a rail
-
-Required Properties:
- - compatible: Should be one of the following
-       * qcom,msm8976-rpmpd: RPM Power domain for the msm8976 family of SoC
-       * qcom,msm8996-rpmpd: RPM Power domain for the msm8996 family of SoC
-       * qcom,msm8998-rpmpd: RPM Power domain for the msm8998 family of SoC
-       * qcom,qcs404-rpmpd: RPM Power domain for the qcs404 family of SoC
-       * qcom,sdm845-rpmhpd: RPMh Power domain for the sdm845 family of SoC
- - #power-domain-cells: number of cells in Power domain specifier
-       must be 1.
- - operating-points-v2: Phandle to the OPP table for the Power domain.
-       Refer to Documentation/devicetree/bindings/power/power_domain.txt
-       and Documentation/devicetree/bindings/opp/opp.txt for more details
-
-Refer to <dt-bindings/power/qcom-rpmpd.h> for the level values for
-various OPPs for different platforms as well as Power domain indexes
-
-Example: rpmh power domain controller and OPP table
-
-#include <dt-bindings/power/qcom-rpmhpd.h>
-
-opp-level values specified in the OPP tables for RPMh power domains
-should use the RPMH_REGULATOR_LEVEL_* constants from
-<dt-bindings/power/qcom-rpmhpd.h>
-
-       rpmhpd: power-controller {
-               compatible = "qcom,sdm845-rpmhpd";
-               #power-domain-cells = <1>;
-               operating-points-v2 = <&rpmhpd_opp_table>;
-
-               rpmhpd_opp_table: opp-table {
-                       compatible = "operating-points-v2";
-
-                       rpmhpd_opp_ret: opp1 {
-                               opp-level = <RPMH_REGULATOR_LEVEL_RETENTION>;
-                       };
-
-                       rpmhpd_opp_min_svs: opp2 {
-                               opp-level = <RPMH_REGULATOR_LEVEL_MIN_SVS>;
-                       };
-
-                       rpmhpd_opp_low_svs: opp3 {
-                               opp-level = <RPMH_REGULATOR_LEVEL_LOW_SVS>;
-                       };
-
-                       rpmhpd_opp_svs: opp4 {
-                               opp-level = <RPMH_REGULATOR_LEVEL_SVS>;
-                       };
-
-                       rpmhpd_opp_svs_l1: opp5 {
-                               opp-level = <RPMH_REGULATOR_LEVEL_SVS_L1>;
-                       };
-
-                       rpmhpd_opp_nom: opp6 {
-                               opp-level = <RPMH_REGULATOR_LEVEL_NOM>;
-                       };
-
-                       rpmhpd_opp_nom_l1: opp7 {
-                               opp-level = <RPMH_REGULATOR_LEVEL_NOM_L1>;
-                       };
-
-                       rpmhpd_opp_nom_l2: opp8 {
-                               opp-level = <RPMH_REGULATOR_LEVEL_NOM_L2>;
-                       };
-
-                       rpmhpd_opp_turbo: opp9 {
-                               opp-level = <RPMH_REGULATOR_LEVEL_TURBO>;
-                       };
-
-                       rpmhpd_opp_turbo_l1: opp10 {
-                               opp-level = <RPMH_REGULATOR_LEVEL_TURBO_L1>;
-                       };
-               };
-       };
-
-Example: rpm power domain controller and OPP table
-
-       rpmpd: power-controller {
-               compatible = "qcom,msm8996-rpmpd";
-               #power-domain-cells = <1>;
-               operating-points-v2 = <&rpmpd_opp_table>;
-
-               rpmpd_opp_table: opp-table {
-                       compatible = "operating-points-v2";
-
-                       rpmpd_opp_low: opp1 {
-                               opp-level = <1>;
-                       };
-
-                       rpmpd_opp_ret: opp2 {
-                               opp-level = <2>;
-                       };
-
-                       rpmpd_opp_svs: opp3 {
-                               opp-level = <3>;
-                       };
-
-                       rpmpd_opp_normal: opp4 {
-                               opp-level = <4>;
-                       };
-
-                       rpmpd_opp_high: opp5 {
-                               opp-level = <5>;
-                       };
-
-                       rpmpd_opp_turbo: opp6 {
-                               opp-level = <6>;
-                       };
-               };
-       };
-
-Example: Client/Consumer device using OPP table
-
-       leaky-device0@12350000 {
-               compatible = "foo,i-leak-current";
-               reg = <0x12350000 0x1000>;
-               power-domains = <&rpmhpd SDM845_MX>;
-               operating-points-v2 = <&leaky_opp_table>;
-       };
-
-
-       leaky_opp_table: opp-table {
-               compatible = "operating-points-v2";
-
-               opp1 {
-                       opp-hz = /bits/ 64 <144000>;
-                       required-opps = <&rpmhpd_opp_low>;
-               };
-
-               opp2 {
-                       opp-hz = /bits/ 64 <400000>;
-                       required-opps = <&rpmhpd_opp_ret>;
-               };
-
-               opp3 {
-                       opp-hz = /bits/ 64 <20000000>;
-                       required-opps = <&rpmpd_opp_svs>;
-               };
-
-               opp4 {
-                       opp-hz = /bits/ 64 <25000000>;
-                       required-opps = <&rpmpd_opp_normal>;
-               };
-       };
diff --git a/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml b/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml
new file mode 100644 (file)
index 0000000..ba60531
--- /dev/null
@@ -0,0 +1,170 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/power/qcom,rpmpd.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm RPM/RPMh Power domains
+
+maintainers:
+  - Rajendra Nayak <rnayak@codeaurora.org>
+
+description:
+  For RPM/RPMh Power domains, we communicate a performance state to RPM/RPMh
+  which then translates it into a corresponding voltage on a rail.
+
+properties:
+  compatible:
+    enum:
+      - qcom,msm8976-rpmpd
+      - qcom,msm8996-rpmpd
+      - qcom,msm8998-rpmpd
+      - qcom,qcs404-rpmpd
+      - qcom,sc7180-rpmhpd
+      - qcom,sdm845-rpmhpd
+      - qcom,sm8150-rpmhpd
+
+  '#power-domain-cells':
+    const: 1
+
+  operating-points-v2: true
+
+  opp-table:
+    type: object
+
+required:
+  - compatible
+  - '#power-domain-cells'
+  - operating-points-v2
+
+additionalProperties: false
+
+examples:
+  - |
+
+    // Example 1 (rpmh power domain controller and OPP table):
+
+    #include <dt-bindings/power/qcom-rpmpd.h>
+
+    rpmhpd: power-controller {
+      compatible = "qcom,sdm845-rpmhpd";
+      #power-domain-cells = <1>;
+      operating-points-v2 = <&rpmhpd_opp_table>;
+
+      rpmhpd_opp_table: opp-table {
+        compatible = "operating-points-v2";
+
+        rpmhpd_opp_ret: opp1 {
+          opp-level = <RPMH_REGULATOR_LEVEL_RETENTION>;
+        };
+
+        rpmhpd_opp_min_svs: opp2 {
+          opp-level = <RPMH_REGULATOR_LEVEL_MIN_SVS>;
+        };
+
+        rpmhpd_opp_low_svs: opp3 {
+          opp-level = <RPMH_REGULATOR_LEVEL_LOW_SVS>;
+        };
+
+        rpmhpd_opp_svs: opp4 {
+          opp-level = <RPMH_REGULATOR_LEVEL_SVS>;
+        };
+
+        rpmhpd_opp_svs_l1: opp5 {
+          opp-level = <RPMH_REGULATOR_LEVEL_SVS_L1>;
+        };
+
+        rpmhpd_opp_nom: opp6 {
+          opp-level = <RPMH_REGULATOR_LEVEL_NOM>;
+        };
+
+        rpmhpd_opp_nom_l1: opp7 {
+          opp-level = <RPMH_REGULATOR_LEVEL_NOM_L1>;
+        };
+
+        rpmhpd_opp_nom_l2: opp8 {
+          opp-level = <RPMH_REGULATOR_LEVEL_NOM_L2>;
+        };
+
+        rpmhpd_opp_turbo: opp9 {
+          opp-level = <RPMH_REGULATOR_LEVEL_TURBO>;
+        };
+
+        rpmhpd_opp_turbo_l1: opp10 {
+          opp-level = <RPMH_REGULATOR_LEVEL_TURBO_L1>;
+        };
+      };
+    };
+
+  - |
+
+    // Example 2 (rpm power domain controller and OPP table):
+
+    rpmpd: power-controller {
+      compatible = "qcom,msm8996-rpmpd";
+      #power-domain-cells = <1>;
+      operating-points-v2 = <&rpmpd_opp_table>;
+
+      rpmpd_opp_table: opp-table {
+        compatible = "operating-points-v2";
+
+        rpmpd_opp_low: opp1 {
+          opp-level = <1>;
+        };
+
+        rpmpd_opp_ret: opp2 {
+          opp-level = <2>;
+        };
+
+        rpmpd_opp_svs: opp3 {
+          opp-level = <3>;
+        };
+
+        rpmpd_opp_normal: opp4 {
+          opp-level = <4>;
+        };
+
+        rpmpd_opp_high: opp5 {
+          opp-level = <5>;
+        };
+
+        rpmpd_opp_turbo: opp6 {
+          opp-level = <6>;
+        };
+      };
+    };
+
+  - |
+
+    // Example 3 (Client/Consumer device using OPP table):
+
+    leaky-device0@12350000 {
+      compatible = "foo,i-leak-current";
+      reg = <0x12350000 0x1000>;
+      power-domains = <&rpmhpd 0>;
+      operating-points-v2 = <&leaky_opp_table>;
+    };
+
+    leaky_opp_table: opp-table {
+      compatible = "operating-points-v2";
+      opp1 {
+        opp-hz = /bits/ 64 <144000>;
+        required-opps = <&rpmhpd_opp_low>;
+      };
+
+      opp2 {
+        opp-hz = /bits/ 64 <400000>;
+        required-opps = <&rpmhpd_opp_ret>;
+      };
+
+      opp3 {
+        opp-hz = /bits/ 64 <20000000>;
+        required-opps = <&rpmpd_opp_svs>;
+      };
+
+      opp4 {
+        opp-hz = /bits/ 64 <25000000>;
+        required-opps = <&rpmpd_opp_normal>;
+      };
+    };
+...
index d366f1eb623ad23770e5fb7509df8272358310aa..bb529ecf8a5768659986f0e59185aeed349e9867 100644 (file)
@@ -8,9 +8,41 @@ Required properties:
  - compatible:         Must contain:   "xlnx,zynqmp-power"
  - interrupts:         Interrupt specifier
 
--------
-Example
--------
+Optional properties:
+ - mbox-names  : Name given to channels seen in the 'mboxes' property.
+                 "tx" - Mailbox corresponding to transmit path
+                 "rx" - Mailbox corresponding to receive path
+ - mboxes      : Standard property to specify a Mailbox. Each value of
+                 the mboxes property should contain a phandle to the
+                 mailbox controller device node and an args specifier
+                 that will be the phandle to the intended sub-mailbox
+                 child node to be used for communication. See
+                 Documentation/devicetree/bindings/mailbox/mailbox.txt
+                 for more details about the generic mailbox controller
+                 and client driver bindings. Also see
+                 Documentation/devicetree/bindings/mailbox/ \
+                 xlnx,zynqmp-ipi-mailbox.txt for typical controller that
+                 is used to communicate with this System controllers.
+
+--------
+Examples
+--------
+
+Example with interrupt method:
+
+firmware {
+       zynqmp_firmware: zynqmp-firmware {
+               compatible = "xlnx,zynqmp-firmware";
+               method = "smc";
+
+               zynqmp_power: zynqmp-power {
+                       compatible = "xlnx,zynqmp-power";
+                       interrupts = <0 35 4>;
+               };
+       };
+};
+
+Example with IPI mailbox method:
 
 firmware {
        zynqmp_firmware: zynqmp-firmware {
@@ -19,7 +51,11 @@ firmware {
 
                zynqmp_power: zynqmp-power {
                        compatible = "xlnx,zynqmp-power";
+                       interrupt-parent = <&gic>;
                        interrupts = <0 35 4>;
+                       mboxes = <&ipi_mailbox_pmu0 0>,
+                                <&ipi_mailbox_pmu0 1>;
+                       mbox-names = "tx", "rx";
                };
        };
 };
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 (file)
index 0000000..411bd76
--- /dev/null
@@ -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 (file)
index 0000000..246dea8
--- /dev/null
@@ -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 (file)
index 0000000..6e80270
--- /dev/null
@@ -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>.
index 8f469d85833b2e6ac0c9bd05f7ff70e0f97cde02..2bc367793aec187e9f863ce2b714de3ab70e8fac 100644 (file)
@@ -11,6 +11,7 @@ The driver implements the Generic PM domain bindings described in
 power/power-domain.yaml. It provides the power domains defined in
 - include/dt-bindings/power/mt8173-power.h
 - include/dt-bindings/power/mt6797-power.h
+- include/dt-bindings/power/mt6765-power.h
 - include/dt-bindings/power/mt2701-power.h
 - include/dt-bindings/power/mt2712-power.h
 - include/dt-bindings/power/mt7622-power.h
@@ -19,6 +20,7 @@ Required properties:
 - compatible: Should be one of:
        - "mediatek,mt2701-scpsys"
        - "mediatek,mt2712-scpsys"
+       - "mediatek,mt6765-scpsys"
        - "mediatek,mt6797-scpsys"
        - "mediatek,mt7622-scpsys"
        - "mediatek,mt7623-scpsys", "mediatek,mt2701-scpsys": For MT7623 SoC
@@ -33,6 +35,10 @@ Required properties:
                       enabled before enabling certain power domains.
        Required clocks for MT2701 or MT7623: "mm", "mfg", "ethif"
        Required clocks for MT2712: "mm", "mfg", "venc", "jpgdec", "audio", "vdec"
+       Required clocks for MT6765: MUX: "mm", "mfg"
+                                   CG: "mm-0", "mm-1", "mm-2", "mm-3", "isp-0",
+                                       "isp-1", "cam-0", "cam-1", "cam-2",
+                                       "cam-3","cam-4"
        Required clocks for MT6797: "mm", "mfg", "vdec"
        Required clocks for MT7622 or MT7629: "hif_sel"
        Required clocks for MT7623A: "ethif"
index 6d81608967688bb4f79fa4ce8db39129cfe76bb8..e7874c4d83f097852542bd1f9d5ee3bb2a13e60d 100644 (file)
@@ -3289,6 +3289,8 @@ S:        Maintained
 N:     bcm2711
 N:     bcm2835
 F:     drivers/staging/vc04_services
+F:     Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml
+F:     drivers/pci/controller/pcie-brcmstb.c
 
 BROADCOM BCM47XX MIPS ARCHITECTURE
 M:     Hauke Mehrtens <hauke@hauke-m.de>
@@ -3344,6 +3346,8 @@ F:        drivers/bus/brcmstb_gisb.c
 F:     arch/arm/mm/cache-b15-rac.c
 F:     arch/arm/include/asm/hardware/cache-b15-rac.h
 N:     brcmstb
+F:     Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml
+F:     drivers/pci/controller/pcie-brcmstb.c
 
 BROADCOM BMIPS CPUFREQ DRIVER
 M:     Markus Mayer <mmayer@broadcom.com>
@@ -16148,6 +16152,7 @@ F:      drivers/firmware/arm_scpi.c
 F:     drivers/firmware/arm_scmi/
 F:     drivers/reset/reset-scmi.c
 F:     include/linux/sc[mp]i_protocol.h
+F:     include/trace/events/scmi.h
 
 SYSTEM RESET/SHUTDOWN DRIVERS
 M:     Sebastian Reichel <sre@kernel.org>
index a6a2ac88f042b4f1232d137d6937ef3ae6c476fd..9f31064f2374e3110b2761ef58e49d8c414f81dd 100644 (file)
                        reg = <0x0>;
                        next-level-cache = <&L2_0>;
                        enable-method = "psci";
-                       cpu-idle-states = <&CPU_SLEEP_0>;
                        clocks = <&apcs>;
                        operating-points-v2 = <&cpu_opp_table>;
                        #cooling-cells = <2>;
+                       power-domains = <&CPU_PD0>;
+                       power-domain-names = "psci";
                };
 
                CPU1: cpu@1 {
                        reg = <0x1>;
                        next-level-cache = <&L2_0>;
                        enable-method = "psci";
-                       cpu-idle-states = <&CPU_SLEEP_0>;
                        clocks = <&apcs>;
                        operating-points-v2 = <&cpu_opp_table>;
                        #cooling-cells = <2>;
+                       power-domains = <&CPU_PD1>;
+                       power-domain-names = "psci";
                };
 
                CPU2: cpu@2 {
                        reg = <0x2>;
                        next-level-cache = <&L2_0>;
                        enable-method = "psci";
-                       cpu-idle-states = <&CPU_SLEEP_0>;
                        clocks = <&apcs>;
                        operating-points-v2 = <&cpu_opp_table>;
                        #cooling-cells = <2>;
+                       power-domains = <&CPU_PD2>;
+                       power-domain-names = "psci";
                };
 
                CPU3: cpu@3 {
                        reg = <0x3>;
                        next-level-cache = <&L2_0>;
                        enable-method = "psci";
-                       cpu-idle-states = <&CPU_SLEEP_0>;
                        clocks = <&apcs>;
                        operating-points-v2 = <&cpu_opp_table>;
                        #cooling-cells = <2>;
+                       power-domains = <&CPU_PD3>;
+                       power-domain-names = "psci";
                };
 
                L2_0: l2-cache {
                                min-residency-us = <2000>;
                                local-timer-stop;
                        };
+
+                       CLUSTER_RET: cluster-retention {
+                               compatible = "domain-idle-state";
+                               arm,psci-suspend-param = <0x41000012>;
+                               entry-latency-us = <500>;
+                               exit-latency-us = <500>;
+                               min-residency-us = <2000>;
+                       };
+
+                       CLUSTER_PWRDN: cluster-gdhs {
+                               compatible = "domain-idle-state";
+                               arm,psci-suspend-param = <0x41000032>;
+                               entry-latency-us = <2000>;
+                               exit-latency-us = <2000>;
+                               min-residency-us = <6000>;
+                       };
                };
        };
 
        psci {
                compatible = "arm,psci-1.0";
                method = "smc";
+
+               CPU_PD0: cpu-pd0 {
+                       #power-domain-cells = <0>;
+                       power-domains = <&CLUSTER_PD>;
+                       domain-idle-states = <&CPU_SLEEP_0>;
+               };
+
+               CPU_PD1: cpu-pd1 {
+                       #power-domain-cells = <0>;
+                       power-domains = <&CLUSTER_PD>;
+                       domain-idle-states = <&CPU_SLEEP_0>;
+               };
+
+               CPU_PD2: cpu-pd2 {
+                       #power-domain-cells = <0>;
+                       power-domains = <&CLUSTER_PD>;
+                       domain-idle-states = <&CPU_SLEEP_0>;
+               };
+
+               CPU_PD3: cpu-pd3 {
+                       #power-domain-cells = <0>;
+                       power-domains = <&CLUSTER_PD>;
+                       domain-idle-states = <&CPU_SLEEP_0>;
+               };
+
+               CLUSTER_PD: cluster-pd {
+                       #power-domain-cells = <0>;
+                       domain-idle-states = <&CLUSTER_RET>, <&CLUSTER_PWRDN>;
+               };
        };
 
        pmu {
index 4c24ea8209bbabe16dc68336f9ab206c7932e7a0..ce483b0f8a4d60b43cb2fe4819ef67a79dfc1e82 100644 (file)
@@ -1,171 +1 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __CPM_H
-#define __CPM_H
-
-#include <linux/compiler.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/of.h>
-#include <soc/fsl/qe/qe.h>
-
-/*
- * SPI Parameter RAM common to QE and CPM.
- */
-struct spi_pram {
-       __be16  rbase;  /* Rx Buffer descriptor base address */
-       __be16  tbase;  /* Tx Buffer descriptor base address */
-       u8      rfcr;   /* Rx function code */
-       u8      tfcr;   /* Tx function code */
-       __be16  mrblr;  /* Max receive buffer length */
-       __be32  rstate; /* Internal */
-       __be32  rdp;    /* Internal */
-       __be16  rbptr;  /* Internal */
-       __be16  rbc;    /* Internal */
-       __be32  rxtmp;  /* Internal */
-       __be32  tstate; /* Internal */
-       __be32  tdp;    /* Internal */
-       __be16  tbptr;  /* Internal */
-       __be16  tbc;    /* Internal */
-       __be32  txtmp;  /* Internal */
-       __be32  res;    /* Tx temp. */
-       __be16  rpbase; /* Relocation pointer (CPM1 only) */
-       __be16  res1;   /* Reserved */
-};
-
-/*
- * USB Controller pram common to QE and CPM.
- */
-struct usb_ctlr {
-       u8      usb_usmod;
-       u8      usb_usadr;
-       u8      usb_uscom;
-       u8      res1[1];
-       __be16  usb_usep[4];
-       u8      res2[4];
-       __be16  usb_usber;
-       u8      res3[2];
-       __be16  usb_usbmr;
-       u8      res4[1];
-       u8      usb_usbs;
-       /* Fields down below are QE-only */
-       __be16  usb_ussft;
-       u8      res5[2];
-       __be16  usb_usfrn;
-       u8      res6[0x22];
-} __attribute__ ((packed));
-
-/*
- * Function code bits, usually generic to devices.
- */
-#ifdef CONFIG_CPM1
-#define CPMFCR_GBL     ((u_char)0x00)  /* Flag doesn't exist in CPM1 */
-#define CPMFCR_TC2     ((u_char)0x00)  /* Flag doesn't exist in CPM1 */
-#define CPMFCR_DTB     ((u_char)0x00)  /* Flag doesn't exist in CPM1 */
-#define CPMFCR_BDB     ((u_char)0x00)  /* Flag doesn't exist in CPM1 */
-#else
-#define CPMFCR_GBL     ((u_char)0x20)  /* Set memory snooping */
-#define CPMFCR_TC2     ((u_char)0x04)  /* Transfer code 2 value */
-#define CPMFCR_DTB     ((u_char)0x02)  /* Use local bus for data when set */
-#define CPMFCR_BDB     ((u_char)0x01)  /* Use local bus for BD when set */
-#endif
-#define CPMFCR_EB      ((u_char)0x10)  /* Set big endian byte order */
-
-/* Opcodes common to CPM1 and CPM2
-*/
-#define CPM_CR_INIT_TRX                ((ushort)0x0000)
-#define CPM_CR_INIT_RX         ((ushort)0x0001)
-#define CPM_CR_INIT_TX         ((ushort)0x0002)
-#define CPM_CR_HUNT_MODE       ((ushort)0x0003)
-#define CPM_CR_STOP_TX         ((ushort)0x0004)
-#define CPM_CR_GRA_STOP_TX     ((ushort)0x0005)
-#define CPM_CR_RESTART_TX      ((ushort)0x0006)
-#define CPM_CR_CLOSE_RX_BD     ((ushort)0x0007)
-#define CPM_CR_SET_GADDR       ((ushort)0x0008)
-#define CPM_CR_SET_TIMER       ((ushort)0x0008)
-#define CPM_CR_STOP_IDMA       ((ushort)0x000b)
-
-/* Buffer descriptors used by many of the CPM protocols. */
-typedef struct cpm_buf_desc {
-       ushort  cbd_sc;         /* Status and Control */
-       ushort  cbd_datlen;     /* Data length in buffer */
-       uint    cbd_bufaddr;    /* Buffer address in host memory */
-} cbd_t;
-
-/* Buffer descriptor control/status used by serial
- */
-
-#define BD_SC_EMPTY    (0x8000)        /* Receive is empty */
-#define BD_SC_READY    (0x8000)        /* Transmit is ready */
-#define BD_SC_WRAP     (0x2000)        /* Last buffer descriptor */
-#define BD_SC_INTRPT   (0x1000)        /* Interrupt on change */
-#define BD_SC_LAST     (0x0800)        /* Last buffer in frame */
-#define BD_SC_TC       (0x0400)        /* Transmit CRC */
-#define BD_SC_CM       (0x0200)        /* Continuous mode */
-#define BD_SC_ID       (0x0100)        /* Rec'd too many idles */
-#define BD_SC_P                (0x0100)        /* xmt preamble */
-#define BD_SC_BR       (0x0020)        /* Break received */
-#define BD_SC_FR       (0x0010)        /* Framing error */
-#define BD_SC_PR       (0x0008)        /* Parity error */
-#define BD_SC_NAK      (0x0004)        /* NAK - did not respond */
-#define BD_SC_OV       (0x0002)        /* Overrun */
-#define BD_SC_UN       (0x0002)        /* Underrun */
-#define BD_SC_CD       (0x0001)        /* */
-#define BD_SC_CL       (0x0001)        /* Collision */
-
-/* Buffer descriptor control/status used by Ethernet receive.
- * Common to SCC and FCC.
- */
-#define BD_ENET_RX_EMPTY       (0x8000)
-#define BD_ENET_RX_WRAP                (0x2000)
-#define BD_ENET_RX_INTR                (0x1000)
-#define BD_ENET_RX_LAST                (0x0800)
-#define BD_ENET_RX_FIRST       (0x0400)
-#define BD_ENET_RX_MISS                (0x0100)
-#define BD_ENET_RX_BC          (0x0080)        /* FCC Only */
-#define BD_ENET_RX_MC          (0x0040)        /* FCC Only */
-#define BD_ENET_RX_LG          (0x0020)
-#define BD_ENET_RX_NO          (0x0010)
-#define BD_ENET_RX_SH          (0x0008)
-#define BD_ENET_RX_CR          (0x0004)
-#define BD_ENET_RX_OV          (0x0002)
-#define BD_ENET_RX_CL          (0x0001)
-#define BD_ENET_RX_STATS       (0x01ff)        /* All status bits */
-
-/* Buffer descriptor control/status used by Ethernet transmit.
- * Common to SCC and FCC.
- */
-#define BD_ENET_TX_READY       (0x8000)
-#define BD_ENET_TX_PAD         (0x4000)
-#define BD_ENET_TX_WRAP                (0x2000)
-#define BD_ENET_TX_INTR                (0x1000)
-#define BD_ENET_TX_LAST                (0x0800)
-#define BD_ENET_TX_TC          (0x0400)
-#define BD_ENET_TX_DEF         (0x0200)
-#define BD_ENET_TX_HB          (0x0100)
-#define BD_ENET_TX_LC          (0x0080)
-#define BD_ENET_TX_RL          (0x0040)
-#define BD_ENET_TX_RCMASK      (0x003c)
-#define BD_ENET_TX_UN          (0x0002)
-#define BD_ENET_TX_CSL         (0x0001)
-#define BD_ENET_TX_STATS       (0x03ff)        /* All status bits */
-
-/* Buffer descriptor control/status used by Transparent mode SCC.
- */
-#define BD_SCC_TX_LAST         (0x0800)
-
-/* Buffer descriptor control/status used by I2C.
- */
-#define BD_I2C_START           (0x0400)
-
-#ifdef CONFIG_CPM
-int cpm_command(u32 command, u8 opcode);
-#else
-static inline int cpm_command(u32 command, u8 opcode)
-{
-       return -ENOSYS;
-}
-#endif /* CONFIG_CPM */
-
-int cpm2_gpiochip_add32(struct device *dev);
-
-#endif
+#include <soc/fsl/cpm.h>
index b0d5471f620d395dbd899747ebb360811b0bd001..ada42f03915acca0dc55d5afcea0b901015c4552 100644 (file)
@@ -34,7 +34,6 @@
 #include <sysdev/fsl_soc.h>
 #include <sysdev/fsl_pci.h>
 #include <soc/fsl/qe/qe.h>
-#include <soc/fsl/qe/qe_ic.h>
 
 #include "mpc83xx.h"
 
@@ -178,7 +177,7 @@ define_machine(mpc83xx_km) {
        .name           = "mpc83xx-km-platform",
        .probe          = mpc83xx_km_probe,
        .setup_arch     = mpc83xx_km_setup_arch,
-       .init_IRQ       = mpc83xx_ipic_and_qe_init_IRQ,
+       .init_IRQ       = mpc83xx_ipic_init_IRQ,
        .get_irq        = ipic_get_irq,
        .restart        = mpc83xx_restart,
        .time_init      = mpc83xx_time_init,
index 6399865a625e52b74cba6dd00e0a324036e5d1c3..a952e91db3eeec2e1ab0040189c00cb32f8d6441 100644 (file)
@@ -14,7 +14,6 @@
 #include <asm/io.h>
 #include <asm/hw_irq.h>
 #include <asm/ipic.h>
-#include <soc/fsl/qe/qe_ic.h>
 #include <sysdev/fsl_soc.h>
 #include <sysdev/fsl_pci.h>
 
@@ -91,28 +90,6 @@ void __init mpc83xx_ipic_init_IRQ(void)
        ipic_set_default_priority();
 }
 
-#ifdef CONFIG_QUICC_ENGINE
-void __init mpc83xx_qe_init_IRQ(void)
-{
-       struct device_node *np;
-
-       np = of_find_compatible_node(NULL, NULL, "fsl,qe-ic");
-       if (!np) {
-               np = of_find_node_by_type(NULL, "qeic");
-               if (!np)
-                       return;
-       }
-       qe_ic_init(np, 0, qe_ic_cascade_low_ipic, qe_ic_cascade_high_ipic);
-       of_node_put(np);
-}
-
-void __init mpc83xx_ipic_and_qe_init_IRQ(void)
-{
-       mpc83xx_ipic_init_IRQ();
-       mpc83xx_qe_init_IRQ();
-}
-#endif /* CONFIG_QUICC_ENGINE */
-
 static const struct of_device_id of_bus_ids[] __initconst = {
        { .type = "soc", },
        { .compatible = "soc", },
index b428835e5919eb69801409b602ae8505e8aabfc0..6fa5402ebf2037b6a7d86fbfc4495b21c9f54ad6 100644 (file)
@@ -33,7 +33,6 @@
 #include <sysdev/fsl_soc.h>
 #include <sysdev/fsl_pci.h>
 #include <soc/fsl/qe/qe.h>
-#include <soc/fsl/qe/qe_ic.h>
 
 #include "mpc83xx.h"
 
@@ -102,7 +101,7 @@ define_machine(mpc832x_mds) {
        .name           = "MPC832x MDS",
        .probe          = mpc832x_sys_probe,
        .setup_arch     = mpc832x_sys_setup_arch,
-       .init_IRQ       = mpc83xx_ipic_and_qe_init_IRQ,
+       .init_IRQ       = mpc83xx_ipic_init_IRQ,
        .get_irq        = ipic_get_irq,
        .restart        = mpc83xx_restart,
        .time_init      = mpc83xx_time_init,
index 4588ce632484e1f81fabe04dfc9ac0d46e74bbe8..622c625d5ce4be17bd31b776b92af09079a3d244 100644 (file)
@@ -22,7 +22,6 @@
 #include <asm/ipic.h>
 #include <asm/udbg.h>
 #include <soc/fsl/qe/qe.h>
-#include <soc/fsl/qe/qe_ic.h>
 #include <sysdev/fsl_soc.h>
 #include <sysdev/fsl_pci.h>
 
@@ -220,7 +219,7 @@ define_machine(mpc832x_rdb) {
        .name           = "MPC832x RDB",
        .probe          = mpc832x_rdb_probe,
        .setup_arch     = mpc832x_rdb_setup_arch,
-       .init_IRQ       = mpc83xx_ipic_and_qe_init_IRQ,
+       .init_IRQ       = mpc83xx_ipic_init_IRQ,
        .get_irq        = ipic_get_irq,
        .restart        = mpc83xx_restart,
        .time_init      = mpc83xx_time_init,
index 240a26d88b07d1d1e65163c9b88d4077e2069f76..90d9cbfae6591f0eda1b3f38a5ac3e3eb7cb9781 100644 (file)
@@ -40,7 +40,6 @@
 #include <sysdev/fsl_soc.h>
 #include <sysdev/fsl_pci.h>
 #include <soc/fsl/qe/qe.h>
-#include <soc/fsl/qe/qe_ic.h>
 
 #include "mpc83xx.h"
 
@@ -202,7 +201,7 @@ define_machine(mpc836x_mds) {
        .name           = "MPC836x MDS",
        .probe          = mpc836x_mds_probe,
        .setup_arch     = mpc836x_mds_setup_arch,
-       .init_IRQ       = mpc83xx_ipic_and_qe_init_IRQ,
+       .init_IRQ       = mpc83xx_ipic_init_IRQ,
        .get_irq        = ipic_get_irq,
        .restart        = mpc83xx_restart,
        .time_init      = mpc83xx_time_init,
index 9923059cb111c2c59451d87164daa44504cb5977..b4aac2cde849ee2b801d7ac21cb67eb4ccc0d9ff 100644 (file)
@@ -17,7 +17,6 @@
 #include <asm/ipic.h>
 #include <asm/udbg.h>
 #include <soc/fsl/qe/qe.h>
-#include <soc/fsl/qe/qe_ic.h>
 #include <sysdev/fsl_soc.h>
 #include <sysdev/fsl_pci.h>
 
@@ -42,7 +41,7 @@ define_machine(mpc836x_rdk) {
        .name           = "MPC836x RDK",
        .probe          = mpc836x_rdk_probe,
        .setup_arch     = mpc836x_rdk_setup_arch,
-       .init_IRQ       = mpc83xx_ipic_and_qe_init_IRQ,
+       .init_IRQ       = mpc83xx_ipic_init_IRQ,
        .get_irq        = ipic_get_irq,
        .restart        = mpc83xx_restart,
        .time_init      = mpc83xx_time_init,
index 459145623334256946a244e38f2d2c9d89adaf8d..f37d04332fc7c200a6294ae65a018f981d40792c 100644 (file)
@@ -72,13 +72,6 @@ extern int mpc837x_usb_cfg(void);
 extern int mpc834x_usb_cfg(void);
 extern int mpc831x_usb_cfg(void);
 extern void mpc83xx_ipic_init_IRQ(void);
-#ifdef CONFIG_QUICC_ENGINE
-extern void mpc83xx_qe_init_IRQ(void);
-extern void mpc83xx_ipic_and_qe_init_IRQ(void);
-#else
-static inline void __init mpc83xx_qe_init_IRQ(void) {}
-#define mpc83xx_ipic_and_qe_init_IRQ mpc83xx_ipic_init_IRQ
-#endif /* CONFIG_QUICC_ENGINE */
 
 #ifdef CONFIG_PCI
 extern void mpc83xx_setup_pci(void);
index a328a741b45728c7561b564765796a8c9bf50fef..27ac38f7e1a9bc502db0382ab7f415fae87043f6 100644 (file)
@@ -24,7 +24,6 @@
 #include <asm/mpic.h>
 #include <asm/ehv_pic.h>
 #include <asm/swiotlb.h>
-#include <soc/fsl/qe/qe_ic.h>
 
 #include <linux/of_platform.h>
 #include <sysdev/fsl_soc.h>
@@ -38,8 +37,6 @@ void __init corenet_gen_pic_init(void)
        unsigned int flags = MPIC_BIG_ENDIAN | MPIC_SINGLE_DEST_CPU |
                MPIC_NO_RESET;
 
-       struct device_node *np;
-
        if (ppc_md.get_irq == mpic_get_coreint_irq)
                flags |= MPIC_ENABLE_COREINT;
 
@@ -47,13 +44,6 @@ void __init corenet_gen_pic_init(void)
        BUG_ON(mpic == NULL);
 
        mpic_init(mpic);
-
-       np = of_find_compatible_node(NULL, NULL, "fsl,qe-ic");
-       if (np) {
-               qe_ic_init(np, 0, qe_ic_cascade_low_mpic,
-                               qe_ic_cascade_high_mpic);
-               of_node_put(np);
-       }
 }
 
 /*
index 381a6ac8cb4bfba1eda2582cb98976e84f389371..7759eca7d535a635b09ec5476b0a6aa8dd8d0fa8 100644 (file)
@@ -44,7 +44,6 @@
 #include <sysdev/fsl_soc.h>
 #include <sysdev/fsl_pci.h>
 #include <soc/fsl/qe/qe.h>
-#include <soc/fsl/qe/qe_ic.h>
 #include <asm/mpic.h>
 #include <asm/swiotlb.h>
 #include "smp.h"
@@ -268,33 +267,8 @@ static void __init mpc85xx_mds_qe_init(void)
        }
 }
 
-static void __init mpc85xx_mds_qeic_init(void)
-{
-       struct device_node *np;
-
-       np = of_find_compatible_node(NULL, NULL, "fsl,qe");
-       if (!of_device_is_available(np)) {
-               of_node_put(np);
-               return;
-       }
-
-       np = of_find_compatible_node(NULL, NULL, "fsl,qe-ic");
-       if (!np) {
-               np = of_find_node_by_type(NULL, "qeic");
-               if (!np)
-                       return;
-       }
-
-       if (machine_is(p1021_mds))
-               qe_ic_init(np, 0, qe_ic_cascade_low_mpic,
-                               qe_ic_cascade_high_mpic);
-       else
-               qe_ic_init(np, 0, qe_ic_cascade_muxed_mpic, NULL);
-       of_node_put(np);
-}
 #else
 static void __init mpc85xx_mds_qe_init(void) { }
-static void __init mpc85xx_mds_qeic_init(void) { }
 #endif /* CONFIG_QUICC_ENGINE */
 
 static void __init mpc85xx_mds_setup_arch(void)
@@ -364,7 +338,6 @@ static void __init mpc85xx_mds_pic_init(void)
        BUG_ON(mpic == NULL);
 
        mpic_init(mpic);
-       mpc85xx_mds_qeic_init();
 }
 
 static int __init mpc85xx_mds_probe(void)
index 7f9a84f857664758c093a1adbc901522a31d7ebf..80a80174768c3ab144db3b1bd6010675465b8b25 100644 (file)
@@ -23,7 +23,6 @@
 #include <asm/udbg.h>
 #include <asm/mpic.h>
 #include <soc/fsl/qe/qe.h>
-#include <soc/fsl/qe/qe_ic.h>
 
 #include <sysdev/fsl_soc.h>
 #include <sysdev/fsl_pci.h>
@@ -44,10 +43,6 @@ void __init mpc85xx_rdb_pic_init(void)
 {
        struct mpic *mpic;
 
-#ifdef CONFIG_QUICC_ENGINE
-       struct device_node *np;
-#endif
-
        if (of_machine_is_compatible("fsl,MPC85XXRDB-CAMP")) {
                mpic = mpic_alloc(NULL, 0, MPIC_NO_RESET |
                        MPIC_BIG_ENDIAN |
@@ -62,18 +57,6 @@ void __init mpc85xx_rdb_pic_init(void)
 
        BUG_ON(mpic == NULL);
        mpic_init(mpic);
-
-#ifdef CONFIG_QUICC_ENGINE
-       np = of_find_compatible_node(NULL, NULL, "fsl,qe-ic");
-       if (np) {
-               qe_ic_init(np, 0, qe_ic_cascade_low_mpic,
-                               qe_ic_cascade_high_mpic);
-               of_node_put(np);
-
-       } else
-               pr_err("%s: Could not find qe-ic node\n", __func__);
-#endif
-
 }
 
 /*
index b301ef9d6ce756613a42c2518e3443231ce67a17..eaec099b4077172940233fa0d1de4ae75e689bba 100644 (file)
@@ -19,7 +19,6 @@
 #include <asm/udbg.h>
 #include <asm/mpic.h>
 #include <soc/fsl/qe/qe.h>
-#include <soc/fsl/qe/qe_ic.h>
 
 #include <sysdev/fsl_soc.h>
 #include <sysdev/fsl_pci.h>
@@ -31,26 +30,12 @@ static void __init twr_p1025_pic_init(void)
 {
        struct mpic *mpic;
 
-#ifdef CONFIG_QUICC_ENGINE
-       struct device_node *np;
-#endif
-
        mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN |
                        MPIC_SINGLE_DEST_CPU,
                        0, 256, " OpenPIC  ");
 
        BUG_ON(mpic == NULL);
        mpic_init(mpic);
-
-#ifdef CONFIG_QUICC_ENGINE
-       np = of_find_compatible_node(NULL, NULL, "fsl,qe-ic");
-       if (np) {
-               qe_ic_init(np, 0, qe_ic_cascade_low_mpic,
-                               qe_ic_cascade_high_mpic);
-               of_node_put(np);
-       } else
-               pr_err("Could not find qe-ic node\n");
-#endif
 }
 
 /* ************************************************************************
index 8e5725b11ee8c2dbaed6f9f0835fc369a3867199..959d6d5eb000dd0f56b275cd3950d5f5e94f2ab8 100644 (file)
@@ -2302,6 +2302,44 @@ out:
 }
 EXPORT_SYMBOL_GPL(of_genpd_add_subdomain);
 
+/**
+ * of_genpd_remove_subdomain - Remove a subdomain from an I/O PM domain.
+ * @parent_spec: OF phandle args to use for parent PM domain look-up
+ * @subdomain_spec: OF phandle args to use for subdomain look-up
+ *
+ * Looks-up a parent PM domain and subdomain based upon phandle args
+ * provided and removes the subdomain from the parent PM domain. Returns a
+ * negative error code on failure.
+ */
+int of_genpd_remove_subdomain(struct of_phandle_args *parent_spec,
+                             struct of_phandle_args *subdomain_spec)
+{
+       struct generic_pm_domain *parent, *subdomain;
+       int ret;
+
+       mutex_lock(&gpd_list_lock);
+
+       parent = genpd_get_from_provider(parent_spec);
+       if (IS_ERR(parent)) {
+               ret = PTR_ERR(parent);
+               goto out;
+       }
+
+       subdomain = genpd_get_from_provider(subdomain_spec);
+       if (IS_ERR(subdomain)) {
+               ret = PTR_ERR(subdomain);
+               goto out;
+       }
+
+       ret = pm_genpd_remove_subdomain(parent, subdomain);
+
+out:
+       mutex_unlock(&gpd_list_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(of_genpd_remove_subdomain);
+
 /**
  * of_genpd_remove_last - Remove the last PM domain registered for a provider
  * @provider: Pointer to device structure associated with provider
index 50200d1c06ea624d342341593144f89ad5d8a795..6095b6df8a81ffb910fa27c3d4cf9a7d8b48aeaa 100644 (file)
@@ -139,7 +139,6 @@ config TEGRA_ACONNECT
        tristate "Tegra ACONNECT Bus Driver"
        depends on ARCH_TEGRA_210_SOC
        depends on OF && PM
-       select PM_CLK
        help
          Driver for the Tegra ACONNECT bus which is used to interface with
          the devices inside the Audio Processing Engine (APE) for Tegra210.
index 36cf13eee6b8ba9af71747cc6bd2e0e7eab0a01b..15fa293819a03124355d6163b7b393de75f553f8 100644 (file)
@@ -102,12 +102,11 @@ static int moxtet_match(struct device *dev, struct device_driver *drv)
        return 0;
 }
 
-struct bus_type moxtet_bus_type = {
+static struct bus_type moxtet_bus_type = {
        .name           = "moxtet",
        .dev_groups     = moxtet_dev_groups,
        .match          = moxtet_match,
 };
-EXPORT_SYMBOL_GPL(moxtet_bus_type);
 
 int __moxtet_register_driver(struct module *owner,
                             struct moxtet_driver *mdrv)
index ccb44fe790a71ebbc5ccfa07216cbffaad29d6bd..f702c85c81b657ec5e0dfe0712ab32e309028fa0 100644 (file)
@@ -479,7 +479,7 @@ static void sysc_clkdm_deny_idle(struct sysc *ddata)
 {
        struct ti_sysc_platform_data *pdata;
 
-       if (ddata->legacy_mode)
+       if (ddata->legacy_mode || (ddata->cfg.quirks & SYSC_QUIRK_CLKDM_NOAUTO))
                return;
 
        pdata = dev_get_platdata(ddata->dev);
@@ -491,7 +491,7 @@ static void sysc_clkdm_allow_idle(struct sysc *ddata)
 {
        struct ti_sysc_platform_data *pdata;
 
-       if (ddata->legacy_mode)
+       if (ddata->legacy_mode || (ddata->cfg.quirks & SYSC_QUIRK_CLKDM_NOAUTO))
                return;
 
        pdata = dev_get_platdata(ddata->dev);
@@ -509,10 +509,8 @@ static int sysc_init_resets(struct sysc *ddata)
 {
        ddata->rsts =
                devm_reset_control_get_optional_shared(ddata->dev, "rstctrl");
-       if (IS_ERR(ddata->rsts))
-               return PTR_ERR(ddata->rsts);
 
-       return 0;
+       return PTR_ERR_OR_ZERO(ddata->rsts);
 }
 
 /**
@@ -1216,10 +1214,6 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
        /* These drivers need to be fixed to not use pm_runtime_irq_safe() */
        SYSC_QUIRK("gpio", 0, 0, 0x10, 0x114, 0x50600801, 0xffff00ff,
                   SYSC_QUIRK_LEGACY_IDLE | SYSC_QUIRK_OPT_CLKS_IN_RESET),
-       SYSC_QUIRK("mmu", 0, 0, 0x10, 0x14, 0x00000020, 0xffffffff,
-                  SYSC_QUIRK_LEGACY_IDLE),
-       SYSC_QUIRK("mmu", 0, 0, 0x10, 0x14, 0x00000030, 0xffffffff,
-                  SYSC_QUIRK_LEGACY_IDLE),
        SYSC_QUIRK("sham", 0, 0x100, 0x110, 0x114, 0x40000c03, 0xffffffff,
                   SYSC_QUIRK_LEGACY_IDLE),
        SYSC_QUIRK("smartreflex", 0, -1, 0x24, -1, 0x00000000, 0xffffffff,
@@ -1251,6 +1245,12 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
        /* Quirks that need to be set based on detected module */
        SYSC_QUIRK("aess", 0, 0, 0x10, -1, 0x40000000, 0xffffffff,
                   SYSC_MODULE_QUIRK_AESS),
+       SYSC_QUIRK("dcan", 0x48480000, 0x20, -1, -1, 0xa3170504, 0xffffffff,
+                  SYSC_QUIRK_CLKDM_NOAUTO),
+       SYSC_QUIRK("dwc3", 0x48880000, 0, 0x10, -1, 0x500a0200, 0xffffffff,
+                  SYSC_QUIRK_CLKDM_NOAUTO),
+       SYSC_QUIRK("dwc3", 0x488c0000, 0, 0x10, -1, 0x500a0200, 0xffffffff,
+                  SYSC_QUIRK_CLKDM_NOAUTO),
        SYSC_QUIRK("hdq1w", 0, 0, 0x14, 0x18, 0x00000006, 0xffffffff,
                   SYSC_MODULE_QUIRK_HDQ1W),
        SYSC_QUIRK("hdq1w", 0, 0, 0x14, 0x18, 0x0000000a, 0xffffffff,
index 886f7c5df51a919cadb74d1161438a7607554105..c491f5de0f3f45f7906cbcb99513d534e0082f0e 100644 (file)
@@ -176,7 +176,7 @@ static int scmi_clocks_probe(struct scmi_device *sdev)
 }
 
 static const struct scmi_device_id scmi_id_table[] = {
-       { SCMI_PROTOCOL_CLOCK },
+       { SCMI_PROTOCOL_CLOCK, "clocks" },
        { },
 };
 MODULE_DEVICE_TABLE(scmi, scmi_id_table);
index e6182c89df7973a781ac93c2a68dd61e9c1428b0..61623e2ff14955ea4e5d4f966066ebe5b61eeef6 100644 (file)
@@ -261,7 +261,7 @@ static void scmi_cpufreq_remove(struct scmi_device *sdev)
 }
 
 static const struct scmi_device_id scmi_id_table[] = {
-       { SCMI_PROTOCOL_PERF },
+       { SCMI_PROTOCOL_PERF, "cpufreq" },
        { },
 };
 MODULE_DEVICE_TABLE(scmi, scmi_id_table);
index ee70d5cc5b996b446bb130dd8ee47dae63c4c23d..cc8c769d7fa9a2a57e319beb3be45c631a275c73 100644 (file)
@@ -21,7 +21,9 @@ obj-$(CONFIG_ARM_U8500_CPUIDLE)         += cpuidle-ux500.o
 obj-$(CONFIG_ARM_AT91_CPUIDLE)          += cpuidle-at91.o
 obj-$(CONFIG_ARM_EXYNOS_CPUIDLE)        += cpuidle-exynos.o
 obj-$(CONFIG_ARM_CPUIDLE)              += cpuidle-arm.o
-obj-$(CONFIG_ARM_PSCI_CPUIDLE)         += cpuidle-psci.o
+obj-$(CONFIG_ARM_PSCI_CPUIDLE)         += cpuidle_psci.o
+cpuidle_psci-y                         := cpuidle-psci.o
+cpuidle_psci-$(CONFIG_PM_GENERIC_DOMAINS_OF) += cpuidle-psci-domain.o
 
 ###############################################################################
 # MIPS drivers
diff --git a/drivers/cpuidle/cpuidle-psci-domain.c b/drivers/cpuidle/cpuidle-psci-domain.c
new file mode 100644 (file)
index 0000000..423f03b
--- /dev/null
@@ -0,0 +1,308 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * PM domains for CPUs via genpd - managed by cpuidle-psci.
+ *
+ * Copyright (C) 2019 Linaro Ltd.
+ * Author: Ulf Hansson <ulf.hansson@linaro.org>
+ *
+ */
+
+#define pr_fmt(fmt) "CPUidle PSCI: " fmt
+
+#include <linux/cpu.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/pm_domain.h>
+#include <linux/pm_runtime.h>
+#include <linux/psci.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#include "cpuidle-psci.h"
+
+struct psci_pd_provider {
+       struct list_head link;
+       struct device_node *node;
+};
+
+static LIST_HEAD(psci_pd_providers);
+static bool osi_mode_enabled __initdata;
+
+static int psci_pd_power_off(struct generic_pm_domain *pd)
+{
+       struct genpd_power_state *state = &pd->states[pd->state_idx];
+       u32 *pd_state;
+
+       if (!state->data)
+               return 0;
+
+       /* OSI mode is enabled, set the corresponding domain state. */
+       pd_state = state->data;
+       psci_set_domain_state(*pd_state);
+
+       return 0;
+}
+
+static int __init psci_pd_parse_state_nodes(struct genpd_power_state *states,
+                                       int state_count)
+{
+       int i, ret;
+       u32 psci_state, *psci_state_buf;
+
+       for (i = 0; i < state_count; i++) {
+               ret = psci_dt_parse_state_node(to_of_node(states[i].fwnode),
+                                       &psci_state);
+               if (ret)
+                       goto free_state;
+
+               psci_state_buf = kmalloc(sizeof(u32), GFP_KERNEL);
+               if (!psci_state_buf) {
+                       ret = -ENOMEM;
+                       goto free_state;
+               }
+               *psci_state_buf = psci_state;
+               states[i].data = psci_state_buf;
+       }
+
+       return 0;
+
+free_state:
+       i--;
+       for (; i >= 0; i--)
+               kfree(states[i].data);
+       return ret;
+}
+
+static int __init psci_pd_parse_states(struct device_node *np,
+                       struct genpd_power_state **states, int *state_count)
+{
+       int ret;
+
+       /* Parse the domain idle states. */
+       ret = of_genpd_parse_idle_states(np, states, state_count);
+       if (ret)
+               return ret;
+
+       /* Fill out the PSCI specifics for each found state. */
+       ret = psci_pd_parse_state_nodes(*states, *state_count);
+       if (ret)
+               kfree(*states);
+
+       return ret;
+}
+
+static void psci_pd_free_states(struct genpd_power_state *states,
+                               unsigned int state_count)
+{
+       int i;
+
+       for (i = 0; i < state_count; i++)
+               kfree(states[i].data);
+       kfree(states);
+}
+
+static int __init psci_pd_init(struct device_node *np)
+{
+       struct generic_pm_domain *pd;
+       struct psci_pd_provider *pd_provider;
+       struct dev_power_governor *pd_gov;
+       struct genpd_power_state *states = NULL;
+       int ret = -ENOMEM, state_count = 0;
+
+       pd = kzalloc(sizeof(*pd), GFP_KERNEL);
+       if (!pd)
+               goto out;
+
+       pd_provider = kzalloc(sizeof(*pd_provider), GFP_KERNEL);
+       if (!pd_provider)
+               goto free_pd;
+
+       pd->name = kasprintf(GFP_KERNEL, "%pOF", np);
+       if (!pd->name)
+               goto free_pd_prov;
+
+       /*
+        * Parse the domain idle states and let genpd manage the state selection
+        * for those being compatible with "domain-idle-state".
+        */
+       ret = psci_pd_parse_states(np, &states, &state_count);
+       if (ret)
+               goto free_name;
+
+       pd->free_states = psci_pd_free_states;
+       pd->name = kbasename(pd->name);
+       pd->power_off = psci_pd_power_off;
+       pd->states = states;
+       pd->state_count = state_count;
+       pd->flags |= GENPD_FLAG_IRQ_SAFE | GENPD_FLAG_CPU_DOMAIN;
+
+       /* Use governor for CPU PM domains if it has some states to manage. */
+       pd_gov = state_count > 0 ? &pm_domain_cpu_gov : NULL;
+
+       ret = pm_genpd_init(pd, pd_gov, false);
+       if (ret) {
+               psci_pd_free_states(states, state_count);
+               goto free_name;
+       }
+
+       ret = of_genpd_add_provider_simple(np, pd);
+       if (ret)
+               goto remove_pd;
+
+       pd_provider->node = of_node_get(np);
+       list_add(&pd_provider->link, &psci_pd_providers);
+
+       pr_debug("init PM domain %s\n", pd->name);
+       return 0;
+
+remove_pd:
+       pm_genpd_remove(pd);
+free_name:
+       kfree(pd->name);
+free_pd_prov:
+       kfree(pd_provider);
+free_pd:
+       kfree(pd);
+out:
+       pr_err("failed to init PM domain ret=%d %pOF\n", ret, np);
+       return ret;
+}
+
+static void __init psci_pd_remove(void)
+{
+       struct psci_pd_provider *pd_provider, *it;
+       struct generic_pm_domain *genpd;
+
+       list_for_each_entry_safe(pd_provider, it, &psci_pd_providers, link) {
+               of_genpd_del_provider(pd_provider->node);
+
+               genpd = of_genpd_remove_last(pd_provider->node);
+               if (!IS_ERR(genpd))
+                       kfree(genpd);
+
+               of_node_put(pd_provider->node);
+               list_del(&pd_provider->link);
+               kfree(pd_provider);
+       }
+}
+
+static int __init psci_pd_init_topology(struct device_node *np, bool add)
+{
+       struct device_node *node;
+       struct of_phandle_args child, parent;
+       int ret;
+
+       for_each_child_of_node(np, node) {
+               if (of_parse_phandle_with_args(node, "power-domains",
+                                       "#power-domain-cells", 0, &parent))
+                       continue;
+
+               child.np = node;
+               child.args_count = 0;
+
+               ret = add ? of_genpd_add_subdomain(&parent, &child) :
+                       of_genpd_remove_subdomain(&parent, &child);
+               of_node_put(parent.np);
+               if (ret) {
+                       of_node_put(node);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static int __init psci_pd_add_topology(struct device_node *np)
+{
+       return psci_pd_init_topology(np, true);
+}
+
+static void __init psci_pd_remove_topology(struct device_node *np)
+{
+       psci_pd_init_topology(np, false);
+}
+
+static const struct of_device_id psci_of_match[] __initconst = {
+       { .compatible = "arm,psci-1.0" },
+       {}
+};
+
+static int __init psci_idle_init_domains(void)
+{
+       struct device_node *np = of_find_matching_node(NULL, psci_of_match);
+       struct device_node *node;
+       int ret = 0, pd_count = 0;
+
+       if (!np)
+               return -ENODEV;
+
+       /* Currently limit the hierarchical topology to be used in OSI mode. */
+       if (!psci_has_osi_support())
+               goto out;
+
+       /*
+        * Parse child nodes for the "#power-domain-cells" property and
+        * initialize a genpd/genpd-of-provider pair when it's found.
+        */
+       for_each_child_of_node(np, node) {
+               if (!of_find_property(node, "#power-domain-cells", NULL))
+                       continue;
+
+               ret = psci_pd_init(node);
+               if (ret)
+                       goto put_node;
+
+               pd_count++;
+       }
+
+       /* Bail out if not using the hierarchical CPU topology. */
+       if (!pd_count)
+               goto out;
+
+       /* Link genpd masters/subdomains to model the CPU topology. */
+       ret = psci_pd_add_topology(np);
+       if (ret)
+               goto remove_pd;
+
+       /* Try to enable OSI mode. */
+       ret = psci_set_osi_mode();
+       if (ret) {
+               pr_warn("failed to enable OSI mode: %d\n", ret);
+               psci_pd_remove_topology(np);
+               goto remove_pd;
+       }
+
+       osi_mode_enabled = true;
+       of_node_put(np);
+       pr_info("Initialized CPU PM domain topology\n");
+       return pd_count;
+
+put_node:
+       of_node_put(node);
+remove_pd:
+       if (pd_count)
+               psci_pd_remove();
+       pr_err("failed to create CPU PM domains ret=%d\n", ret);
+out:
+       of_node_put(np);
+       return ret;
+}
+subsys_initcall(psci_idle_init_domains);
+
+struct device __init *psci_dt_attach_cpu(int cpu)
+{
+       struct device *dev;
+
+       if (!osi_mode_enabled)
+               return NULL;
+
+       dev = dev_pm_domain_attach_by_name(get_cpu_device(cpu), "psci");
+       if (IS_ERR_OR_NULL(dev))
+               return dev;
+
+       pm_runtime_irq_safe(dev);
+       if (cpu_online(cpu))
+               pm_runtime_get_sync(dev);
+
+       return dev;
+}
index f3c1a2396f989e29a9251106484d762ccca97aec..edd7a54ef0d30d63439f64605b4d4027718f628b 100644 (file)
@@ -8,6 +8,7 @@
 
 #define pr_fmt(fmt) "CPUidle PSCI: " fmt
 
+#include <linux/cpuhotplug.h>
 #include <linux/cpuidle.h>
 #include <linux/cpumask.h>
 #include <linux/cpu_pm.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/psci.h>
+#include <linux/pm_runtime.h>
 #include <linux/slab.h>
 
 #include <asm/cpuidle.h>
 
+#include "cpuidle-psci.h"
 #include "dt_idle_states.h"
 
-static DEFINE_PER_CPU_READ_MOSTLY(u32 *, psci_power_state);
+struct psci_cpuidle_data {
+       u32 *psci_states;
+       struct device *dev;
+};
+
+static DEFINE_PER_CPU_READ_MOSTLY(struct psci_cpuidle_data, psci_cpuidle_data);
+static DEFINE_PER_CPU(u32, domain_state);
+static bool psci_cpuidle_use_cpuhp __initdata;
+
+void psci_set_domain_state(u32 state)
+{
+       __this_cpu_write(domain_state, state);
+}
+
+static inline u32 psci_get_domain_state(void)
+{
+       return __this_cpu_read(domain_state);
+}
+
+static inline int psci_enter_state(int idx, u32 state)
+{
+       return CPU_PM_CPU_IDLE_ENTER_PARAM(psci_cpu_suspend_enter, idx, state);
+}
+
+static int psci_enter_domain_idle_state(struct cpuidle_device *dev,
+                                       struct cpuidle_driver *drv, int idx)
+{
+       struct psci_cpuidle_data *data = this_cpu_ptr(&psci_cpuidle_data);
+       u32 *states = data->psci_states;
+       struct device *pd_dev = data->dev;
+       u32 state;
+       int ret;
+
+       /* Do runtime PM to manage a hierarchical CPU toplogy. */
+       pm_runtime_put_sync_suspend(pd_dev);
+
+       state = psci_get_domain_state();
+       if (!state)
+               state = states[idx];
+
+       ret = psci_enter_state(idx, state);
+
+       pm_runtime_get_sync(pd_dev);
+
+       /* Clear the domain state to start fresh when back from idle. */
+       psci_set_domain_state(0);
+       return ret;
+}
+
+static int psci_idle_cpuhp_up(unsigned int cpu)
+{
+       struct device *pd_dev = __this_cpu_read(psci_cpuidle_data.dev);
+
+       if (pd_dev)
+               pm_runtime_get_sync(pd_dev);
+
+       return 0;
+}
+
+static int psci_idle_cpuhp_down(unsigned int cpu)
+{
+       struct device *pd_dev = __this_cpu_read(psci_cpuidle_data.dev);
+
+       if (pd_dev) {
+               pm_runtime_put_sync(pd_dev);
+               /* Clear domain state to start fresh at next online. */
+               psci_set_domain_state(0);
+       }
+
+       return 0;
+}
+
+static void __init psci_idle_init_cpuhp(void)
+{
+       int err;
+
+       if (!psci_cpuidle_use_cpuhp)
+               return;
+
+       err = cpuhp_setup_state_nocalls(CPUHP_AP_CPU_PM_STARTING,
+                                       "cpuidle/psci:online",
+                                       psci_idle_cpuhp_up,
+                                       psci_idle_cpuhp_down);
+       if (err)
+               pr_warn("Failed %d while setup cpuhp state\n", err);
+}
 
 static int psci_enter_idle_state(struct cpuidle_device *dev,
                                struct cpuidle_driver *drv, int idx)
 {
-       u32 *state = __this_cpu_read(psci_power_state);
+       u32 *state = __this_cpu_read(psci_cpuidle_data.psci_states);
 
-       return CPU_PM_CPU_IDLE_ENTER_PARAM(psci_cpu_suspend_enter,
-                                          idx, state[idx - 1]);
+       return psci_enter_state(idx, state[idx]);
 }
 
 static struct cpuidle_driver psci_idle_driver __initdata = {
@@ -56,7 +143,7 @@ static const struct of_device_id psci_idle_state_match[] __initconst = {
        { },
 };
 
-static int __init psci_dt_parse_state_node(struct device_node *np, u32 *state)
+int __init psci_dt_parse_state_node(struct device_node *np, u32 *state)
 {
        int err = of_property_read_u32(np, "arm,psci-suspend-param", state);
 
@@ -73,28 +160,25 @@ static int __init psci_dt_parse_state_node(struct device_node *np, u32 *state)
        return 0;
 }
 
-static int __init psci_dt_cpu_init_idle(struct device_node *cpu_node, int cpu)
+static int __init psci_dt_cpu_init_idle(struct cpuidle_driver *drv,
+                                       struct device_node *cpu_node,
+                                       unsigned int state_count, int cpu)
 {
-       int i, ret = 0, count = 0;
+       int i, ret = 0;
        u32 *psci_states;
        struct device_node *state_node;
+       struct psci_cpuidle_data *data = per_cpu_ptr(&psci_cpuidle_data, cpu);
 
-       /* Count idle states */
-       while ((state_node = of_parse_phandle(cpu_node, "cpu-idle-states",
-                                             count))) {
-               count++;
-               of_node_put(state_node);
-       }
-
-       if (!count)
-               return -ENODEV;
-
-       psci_states = kcalloc(count, sizeof(*psci_states), GFP_KERNEL);
+       state_count++; /* Add WFI state too */
+       psci_states = kcalloc(state_count, sizeof(*psci_states), GFP_KERNEL);
        if (!psci_states)
                return -ENOMEM;
 
-       for (i = 0; i < count; i++) {
-               state_node = of_parse_phandle(cpu_node, "cpu-idle-states", i);
+       for (i = 1; i < state_count; i++) {
+               state_node = of_get_cpu_state_node(cpu_node, i - 1);
+               if (!state_node)
+                       break;
+
                ret = psci_dt_parse_state_node(state_node, &psci_states[i]);
                of_node_put(state_node);
 
@@ -104,8 +188,33 @@ static int __init psci_dt_cpu_init_idle(struct device_node *cpu_node, int cpu)
                pr_debug("psci-power-state %#x index %d\n", psci_states[i], i);
        }
 
-       /* Idle states parsed correctly, initialize per-cpu pointer */
-       per_cpu(psci_power_state, cpu) = psci_states;
+       if (i != state_count) {
+               ret = -ENODEV;
+               goto free_mem;
+       }
+
+       /* Currently limit the hierarchical topology to be used in OSI mode. */
+       if (psci_has_osi_support()) {
+               data->dev = psci_dt_attach_cpu(cpu);
+               if (IS_ERR(data->dev)) {
+                       ret = PTR_ERR(data->dev);
+                       goto free_mem;
+               }
+
+               /*
+                * Using the deepest state for the CPU to trigger a potential
+                * selection of a shared state for the domain, assumes the
+                * domain states are all deeper states.
+                */
+               if (data->dev) {
+                       drv->states[state_count - 1].enter =
+                               psci_enter_domain_idle_state;
+                       psci_cpuidle_use_cpuhp = true;
+               }
+       }
+
+       /* Idle states parsed correctly, store them in the per-cpu struct. */
+       data->psci_states = psci_states;
        return 0;
 
 free_mem:
@@ -113,7 +222,8 @@ free_mem:
        return ret;
 }
 
-static __init int psci_cpu_init_idle(unsigned int cpu)
+static __init int psci_cpu_init_idle(struct cpuidle_driver *drv,
+                                    unsigned int cpu, unsigned int state_count)
 {
        struct device_node *cpu_node;
        int ret;
@@ -129,7 +239,7 @@ static __init int psci_cpu_init_idle(unsigned int cpu)
        if (!cpu_node)
                return -ENODEV;
 
-       ret = psci_dt_cpu_init_idle(cpu_node, cpu);
+       ret = psci_dt_cpu_init_idle(drv, cpu_node, state_count, cpu);
 
        of_node_put(cpu_node);
 
@@ -185,7 +295,7 @@ static int __init psci_idle_init_cpu(int cpu)
        /*
         * Initialize PSCI idle states.
         */
-       ret = psci_cpu_init_idle(cpu);
+       ret = psci_cpu_init_idle(drv, cpu, ret);
        if (ret) {
                pr_err("CPU %d failed to PSCI idle\n", cpu);
                goto out_kfree_drv;
@@ -221,6 +331,7 @@ static int __init psci_idle_init(void)
                        goto out_fail;
        }
 
+       psci_idle_init_cpuhp();
        return 0;
 
 out_fail:
diff --git a/drivers/cpuidle/cpuidle-psci.h b/drivers/cpuidle/cpuidle-psci.h
new file mode 100644 (file)
index 0000000..7299a04
--- /dev/null
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __CPUIDLE_PSCI_H
+#define __CPUIDLE_PSCI_H
+
+struct device_node;
+
+void psci_set_domain_state(u32 state);
+int __init psci_dt_parse_state_node(struct device_node *np, u32 *state);
+
+#ifdef CONFIG_PM_GENERIC_DOMAINS_OF
+struct device __init *psci_dt_attach_cpu(int cpu);
+#else
+static inline struct device __init *psci_dt_attach_cpu(int cpu) { return NULL; }
+#endif
+
+#endif /* __CPUIDLE_PSCI_H */
index d06d21a9525dfa80cf5e8e936dad1f3befd57389..252f2a9686a6270f1c3a8f51c31d46bf8b7f0b27 100644 (file)
@@ -111,8 +111,7 @@ static bool idle_state_valid(struct device_node *state_node, unsigned int idx,
        for (cpu = cpumask_next(cpumask_first(cpumask), cpumask);
             cpu < nr_cpu_ids; cpu = cpumask_next(cpu, cpumask)) {
                cpu_node = of_cpu_device_node_get(cpu);
-               curr_state_node = of_parse_phandle(cpu_node, "cpu-idle-states",
-                                                  idx);
+               curr_state_node = of_get_cpu_state_node(cpu_node, idx);
                if (state_node != curr_state_node)
                        valid = false;
 
@@ -170,7 +169,7 @@ int dt_init_idle_driver(struct cpuidle_driver *drv,
        cpu_node = of_cpu_device_node_get(cpumask_first(cpumask));
 
        for (i = 0; ; i++) {
-               state_node = of_parse_phandle(cpu_node, "cpu-idle-states", i);
+               state_node = of_get_cpu_state_node(cpu_node, i);
                if (!state_node)
                        break;
 
index e40a77bfe8210fe4a81f87adfcfa2d4fc417aee7..ea869addc89bb046480bf0b3421ada0063313e7b 100644 (file)
@@ -239,14 +239,6 @@ config QCOM_SCM
        depends on ARM || ARM64
        select RESET_CONTROLLER
 
-config QCOM_SCM_32
-       def_bool y
-       depends on QCOM_SCM && ARM
-
-config QCOM_SCM_64
-       def_bool y
-       depends on QCOM_SCM && ARM64
-
 config QCOM_SCM_DOWNLOAD_MODE_DEFAULT
        bool "Qualcomm download mode enabled by default"
        depends on QCOM_SCM
index 3fcb91975bdc68612ccff283cdd7f07fd29b63a4..e9fb838af4dff087e11737af9c493022312d1943 100644 (file)
@@ -17,10 +17,7 @@ obj-$(CONFIG_ISCSI_IBFT)     += iscsi_ibft.o
 obj-$(CONFIG_FIRMWARE_MEMMAP)  += memmap.o
 obj-$(CONFIG_RASPBERRYPI_FIRMWARE) += raspberrypi.o
 obj-$(CONFIG_FW_CFG_SYSFS)     += qemu_fw_cfg.o
-obj-$(CONFIG_QCOM_SCM)         += qcom_scm.o
-obj-$(CONFIG_QCOM_SCM_64)      += qcom_scm-64.o
-obj-$(CONFIG_QCOM_SCM_32)      += qcom_scm-32.o
-CFLAGS_qcom_scm-32.o :=$(call as-instr,.arch armv7-a\n.arch_extension sec,-DREQUIRES_SEC=1) -march=armv7-a
+obj-$(CONFIG_QCOM_SCM)         += qcom_scm.o qcom_scm-smc.o qcom_scm-legacy.o
 obj-$(CONFIG_TI_SCI_PROTOCOL)  += ti_sci.o
 obj-$(CONFIG_TRUSTED_FOUNDATIONS) += trusted_foundations.o
 obj-$(CONFIG_TURRIS_MOX_RWTM)  += turris-mox-rwtm.o
index 7a30952b463d58329edd05980409b40b6b856c74..db55c43a2cbda6e3fc1f8d01e3a6ef4845490563 100644 (file)
@@ -28,8 +28,12 @@ scmi_dev_match_id(struct scmi_device *scmi_dev, struct scmi_driver *scmi_drv)
                return NULL;
 
        for (; id->protocol_id; id++)
-               if (id->protocol_id == scmi_dev->protocol_id)
-                       return id;
+               if (id->protocol_id == scmi_dev->protocol_id) {
+                       if (!id->name)
+                               return id;
+                       else if (!strcmp(id->name, scmi_dev->name))
+                               return id;
+               }
 
        return NULL;
 }
@@ -56,6 +60,11 @@ static int scmi_protocol_init(int protocol_id, struct scmi_handle *handle)
        return fn(handle);
 }
 
+static int scmi_protocol_dummy_init(struct scmi_handle *handle)
+{
+       return 0;
+}
+
 static int scmi_dev_probe(struct device *dev)
 {
        struct scmi_driver *scmi_drv = to_scmi_driver(dev->driver);
@@ -74,6 +83,10 @@ static int scmi_dev_probe(struct device *dev)
        if (ret)
                return ret;
 
+       /* Skip protocol initialisation for additional devices */
+       idr_replace(&scmi_protocols, &scmi_protocol_dummy_init,
+                   scmi_dev->protocol_id);
+
        return scmi_drv->probe(scmi_dev);
 }
 
@@ -125,7 +138,8 @@ static void scmi_device_release(struct device *dev)
 }
 
 struct scmi_device *
-scmi_device_create(struct device_node *np, struct device *parent, int protocol)
+scmi_device_create(struct device_node *np, struct device *parent, int protocol,
+                  const char *name)
 {
        int id, retval;
        struct scmi_device *scmi_dev;
@@ -134,8 +148,15 @@ scmi_device_create(struct device_node *np, struct device *parent, int protocol)
        if (!scmi_dev)
                return NULL;
 
+       scmi_dev->name = kstrdup_const(name ?: "unknown", GFP_KERNEL);
+       if (!scmi_dev->name) {
+               kfree(scmi_dev);
+               return NULL;
+       }
+
        id = ida_simple_get(&scmi_bus_id, 1, 0, GFP_KERNEL);
        if (id < 0) {
+               kfree_const(scmi_dev->name);
                kfree(scmi_dev);
                return NULL;
        }
@@ -154,6 +175,7 @@ scmi_device_create(struct device_node *np, struct device *parent, int protocol)
 
        return scmi_dev;
 put_dev:
+       kfree_const(scmi_dev->name);
        put_device(&scmi_dev->dev);
        ida_simple_remove(&scmi_bus_id, id);
        return NULL;
@@ -161,6 +183,7 @@ put_dev:
 
 void scmi_device_destroy(struct scmi_device *scmi_dev)
 {
+       kfree_const(scmi_dev->name);
        scmi_handle_put(scmi_dev->handle);
        ida_simple_remove(&scmi_bus_id, scmi_dev->id);
        device_unregister(&scmi_dev->dev);
index 32526a793f3ace11cb5835cf336aea22aae53325..4c2227662b261fb2415bf7419925fafcd63e468c 100644 (file)
@@ -65,6 +65,7 @@ struct scmi_clock_set_rate {
 };
 
 struct clock_info {
+       u32 version;
        int num_clocks;
        int max_async_req;
        atomic_t cur_async_req;
@@ -340,6 +341,7 @@ static int scmi_clock_protocol_init(struct scmi_handle *handle)
                        scmi_clock_describe_rates_get(handle, clkid, clk);
        }
 
+       cinfo->version = version;
        handle->clk_ops = &clk_ops;
        handle->clk_priv = cinfo;
 
index 5237c2ff79fea1dfce305a20542b3d3b9f17d5b6..df35358ff324c369e1bd36fac249da934c168b7b 100644 (file)
@@ -81,6 +81,7 @@ struct scmi_msg {
 /**
  * struct scmi_xfer - Structure representing a message flow
  *
+ * @transfer_id: Unique ID for debug & profiling purpose
  * @hdr: Transmit message header
  * @tx: Transmit message
  * @rx: Receive message, the buffer should be pre-allocated to store
@@ -90,6 +91,7 @@ struct scmi_msg {
  * @async: pointer to delayed response message received event completion
  */
 struct scmi_xfer {
+       int transfer_id;
        struct scmi_msg_hdr hdr;
        struct scmi_msg tx;
        struct scmi_msg rx;
index 3eb0382491cebbc973de870eda7fc43ec244eee2..2c96f6b5a7d811f71d76fbcc51d8095620160580 100644 (file)
@@ -29,6 +29,9 @@
 
 #include "common.h"
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/scmi.h>
+
 #define MSG_ID_MASK            GENMASK(7, 0)
 #define MSG_XTRACT_ID(hdr)     FIELD_GET(MSG_ID_MASK, (hdr))
 #define MSG_TYPE_MASK          GENMASK(9, 8)
@@ -61,6 +64,8 @@ enum scmi_error_codes {
 static LIST_HEAD(scmi_list);
 /* Protection for the entire list */
 static DEFINE_MUTEX(scmi_list_mutex);
+/* Track the unique id for the transfers for debug & profiling purpose */
+static atomic_t transfer_last_id;
 
 /**
  * struct scmi_xfers_info - Structure to manage transfer information
@@ -304,6 +309,7 @@ static struct scmi_xfer *scmi_xfer_get(const struct scmi_handle *handle,
        xfer = &minfo->xfer_block[xfer_id];
        xfer->hdr.seq = xfer_id;
        reinit_completion(&xfer->done);
+       xfer->transfer_id = atomic_inc_return(&transfer_last_id);
 
        return xfer;
 }
@@ -374,6 +380,10 @@ static void scmi_rx_callback(struct mbox_client *cl, void *m)
 
        scmi_fetch_response(xfer, mem);
 
+       trace_scmi_rx_done(xfer->transfer_id, xfer->hdr.id,
+                          xfer->hdr.protocol_id, xfer->hdr.seq,
+                          msg_type);
+
        if (msg_type == MSG_TYPE_DELAYED_RESP)
                complete(xfer->async_done);
        else
@@ -439,6 +449,10 @@ int scmi_do_xfer(const struct scmi_handle *handle, struct scmi_xfer *xfer)
        if (unlikely(!cinfo))
                return -EINVAL;
 
+       trace_scmi_xfer_begin(xfer->transfer_id, xfer->hdr.id,
+                             xfer->hdr.protocol_id, xfer->hdr.seq,
+                             xfer->hdr.poll_completion);
+
        ret = mbox_send_message(cinfo->chan, xfer);
        if (ret < 0) {
                dev_dbg(dev, "mbox send fail %d\n", ret);
@@ -478,6 +492,10 @@ int scmi_do_xfer(const struct scmi_handle *handle, struct scmi_xfer *xfer)
         */
        mbox_client_txdone(cinfo->chan, ret);
 
+       trace_scmi_xfer_end(xfer->transfer_id, xfer->hdr.id,
+                           xfer->hdr.protocol_id, xfer->hdr.seq,
+                           xfer->hdr.status);
+
        return ret;
 }
 
@@ -735,6 +753,11 @@ static int scmi_mbox_chan_setup(struct scmi_info *info, struct device *dev,
        idx = tx ? 0 : 1;
        idr = tx ? &info->tx_idr : &info->rx_idr;
 
+       /* check if already allocated, used for multiple device per protocol */
+       cinfo = idr_find(idr, prot_id);
+       if (cinfo)
+               return 0;
+
        if (scmi_mailbox_check(np, idx)) {
                cinfo = idr_find(idr, SCMI_PROTOCOL_BASE);
                if (unlikely(!cinfo)) /* Possible only if platform has no Rx */
@@ -803,11 +826,11 @@ scmi_mbox_txrx_setup(struct scmi_info *info, struct device *dev, int prot_id)
 
 static inline void
 scmi_create_protocol_device(struct device_node *np, struct scmi_info *info,
-                           int prot_id)
+                           int prot_id, const char *name)
 {
        struct scmi_device *sdev;
 
-       sdev = scmi_device_create(np, info->dev, prot_id);
+       sdev = scmi_device_create(np, info->dev, prot_id, name);
        if (!sdev) {
                dev_err(info->dev, "failed to create %d protocol device\n",
                        prot_id);
@@ -824,6 +847,40 @@ scmi_create_protocol_device(struct device_node *np, struct scmi_info *info,
        scmi_set_handle(sdev);
 }
 
+#define MAX_SCMI_DEV_PER_PROTOCOL      2
+struct scmi_prot_devnames {
+       int protocol_id;
+       char *names[MAX_SCMI_DEV_PER_PROTOCOL];
+};
+
+static struct scmi_prot_devnames devnames[] = {
+       { SCMI_PROTOCOL_POWER,  { "genpd" },},
+       { SCMI_PROTOCOL_PERF,   { "cpufreq" },},
+       { SCMI_PROTOCOL_CLOCK,  { "clocks" },},
+       { SCMI_PROTOCOL_SENSOR, { "hwmon" },},
+       { SCMI_PROTOCOL_RESET,  { "reset" },},
+};
+
+static inline void
+scmi_create_protocol_devices(struct device_node *np, struct scmi_info *info,
+                            int prot_id)
+{
+       int loop, cnt;
+
+       for (loop = 0; loop < ARRAY_SIZE(devnames); loop++) {
+               if (devnames[loop].protocol_id != prot_id)
+                       continue;
+
+               for (cnt = 0; cnt < ARRAY_SIZE(devnames[loop].names); cnt++) {
+                       const char *name = devnames[loop].names[cnt];
+
+                       if (name)
+                               scmi_create_protocol_device(np, info, prot_id,
+                                                           name);
+               }
+       }
+}
+
 static int scmi_probe(struct platform_device *pdev)
 {
        int ret;
@@ -892,7 +949,7 @@ static int scmi_probe(struct platform_device *pdev)
                        continue;
                }
 
-               scmi_create_protocol_device(child, info, prot_id);
+               scmi_create_protocol_devices(child, info, prot_id);
        }
 
        return 0;
@@ -940,6 +997,52 @@ static int scmi_remove(struct platform_device *pdev)
        return ret;
 }
 
+static ssize_t protocol_version_show(struct device *dev,
+                                    struct device_attribute *attr, char *buf)
+{
+       struct scmi_info *info = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%u.%u\n", info->version.major_ver,
+                      info->version.minor_ver);
+}
+static DEVICE_ATTR_RO(protocol_version);
+
+static ssize_t firmware_version_show(struct device *dev,
+                                    struct device_attribute *attr, char *buf)
+{
+       struct scmi_info *info = dev_get_drvdata(dev);
+
+       return sprintf(buf, "0x%x\n", info->version.impl_ver);
+}
+static DEVICE_ATTR_RO(firmware_version);
+
+static ssize_t vendor_id_show(struct device *dev,
+                             struct device_attribute *attr, char *buf)
+{
+       struct scmi_info *info = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%s\n", info->version.vendor_id);
+}
+static DEVICE_ATTR_RO(vendor_id);
+
+static ssize_t sub_vendor_id_show(struct device *dev,
+                                 struct device_attribute *attr, char *buf)
+{
+       struct scmi_info *info = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%s\n", info->version.sub_vendor_id);
+}
+static DEVICE_ATTR_RO(sub_vendor_id);
+
+static struct attribute *versions_attrs[] = {
+       &dev_attr_firmware_version.attr,
+       &dev_attr_protocol_version.attr,
+       &dev_attr_vendor_id.attr,
+       &dev_attr_sub_vendor_id.attr,
+       NULL,
+};
+ATTRIBUTE_GROUPS(versions);
+
 static const struct scmi_desc scmi_generic_desc = {
        .max_rx_timeout_ms = 30,        /* We may increase this if required */
        .max_msg = 20,          /* Limited by MBOX_TX_QUEUE_LEN */
@@ -958,6 +1061,7 @@ static struct platform_driver scmi_driver = {
        .driver = {
                   .name = "arm-scmi",
                   .of_match_table = scmi_of_match,
+                  .dev_groups = versions_groups,
                   },
        .probe = scmi_probe,
        .remove = scmi_remove,
index 601af4edad5e6de4597a1637d34d8f8f4fcafb4c..ec81e6f7e7a4142a0a62ddab5cad05c3911dd137 100644 (file)
@@ -145,6 +145,7 @@ struct perf_dom_info {
 };
 
 struct scmi_perf_info {
+       u32 version;
        int num_domains;
        bool power_scale_mw;
        u64 stats_addr;
@@ -736,6 +737,7 @@ static int scmi_perf_protocol_init(struct scmi_handle *handle)
                        scmi_perf_domain_init_fc(handle, domain, &dom->fc_info);
        }
 
+       pinfo->version = version;
        handle->perf_ops = &perf_ops;
        handle->perf_priv = pinfo;
 
index 5abef7079c0a31a84e7290209ff01f4bf0559e99..214886ce84f1ee1323ca7f9571ade7203e2a0a7e 100644 (file)
@@ -50,6 +50,7 @@ struct power_dom_info {
 };
 
 struct scmi_power_info {
+       u32 version;
        int num_domains;
        u64 stats_addr;
        u32 stats_size;
@@ -207,6 +208,7 @@ static int scmi_power_protocol_init(struct scmi_handle *handle)
                scmi_power_domain_attributes_get(handle, domain, dom);
        }
 
+       pinfo->version = version;
        handle->power_ops = &power_ops;
        handle->power_priv = pinfo;
 
index ab42c21c55175ddd81503a99af8a28fc06d3ca47..de73054554f32d3c595a79d6abe88ceb65a42e5a 100644 (file)
@@ -48,6 +48,7 @@ struct reset_dom_info {
 };
 
 struct scmi_reset_info {
+       u32 version;
        int num_domains;
        struct reset_dom_info *dom_info;
 };
@@ -217,6 +218,7 @@ static int scmi_reset_protocol_init(struct scmi_handle *handle)
                scmi_reset_domain_attributes_get(handle, domain, dom);
        }
 
+       pinfo->version = version;
        handle->reset_ops = &reset_ops;
        handle->reset_priv = pinfo;
 
index 87f737e01473c357212def7950a2868a7bbac299..bafbfe358f97d6aa8e1ebccfe54c019f29c8f004 100644 (file)
@@ -112,7 +112,7 @@ static int scmi_pm_domain_probe(struct scmi_device *sdev)
 }
 
 static const struct scmi_device_id scmi_id_table[] = {
-       { SCMI_PROTOCOL_POWER },
+       { SCMI_PROTOCOL_POWER, "genpd" },
        { },
 };
 MODULE_DEVICE_TABLE(scmi, scmi_id_table);
index a400ea805fc236738047efc3dc351cfa79aed895..eba61b9c1f53e4b4b142b233366161eca4de440e 100644 (file)
@@ -68,6 +68,7 @@ struct scmi_msg_sensor_reading_get {
 };
 
 struct sensors_info {
+       u32 version;
        int num_sensors;
        int max_requests;
        u64 reg_addr;
@@ -294,6 +295,7 @@ static int scmi_sensors_protocol_init(struct scmi_handle *handle)
 
        scmi_sensor_description_get(handle, sinfo);
 
+       sinfo->version = version;
        handle->sensor_ops = &sensor_ops;
        handle->sensor_priv = sinfo;
 
index 0dbee32da4c6d52ea3a84704245fee151ef37d65..1d2e5b85d7ca8458f3d67bac38b964f4f9100ef6 100644 (file)
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
 config IMX_DSP
-       bool "IMX DSP Protocol driver"
+       tristate "IMX DSP Protocol driver"
        depends on IMX_MBOX
        help
          This enables DSP IPC protocol between host AP (Linux)
index b3b6c15e7b36a2321340e4874cea651e43df4f72..2937d44b5df46ef1fc437b75b134a0f11905cff1 100644 (file)
@@ -97,7 +97,7 @@ static inline bool psci_has_ext_power_state(void)
                                PSCI_1_0_FEATURES_CPU_SUSPEND_PF_MASK;
 }
 
-static inline bool psci_has_osi_support(void)
+bool psci_has_osi_support(void)
 {
        return psci_cpu_suspend_feature & PSCI_1_0_OS_INITIATED;
 }
@@ -162,6 +162,15 @@ static u32 psci_get_version(void)
        return invoke_psci_fn(PSCI_0_2_FN_PSCI_VERSION, 0, 0, 0);
 }
 
+int psci_set_osi_mode(void)
+{
+       int err;
+
+       err = invoke_psci_fn(PSCI_1_0_FN_SET_SUSPEND_MODE,
+                            PSCI_1_0_SUSPEND_MODE_OSI, 0, 0);
+       return psci_to_linux_errno(err);
+}
+
 static int psci_cpu_suspend(u32 state, unsigned long entry_point)
 {
        int err;
@@ -544,9 +553,14 @@ static int __init psci_1_0_init(struct device_node *np)
        if (err)
                return err;
 
-       if (psci_has_osi_support())
+       if (psci_has_osi_support()) {
                pr_info("OSI mode supported.\n");
 
+               /* Default to PC mode. */
+               invoke_psci_fn(PSCI_1_0_FN_SET_SUSPEND_MODE,
+                              PSCI_1_0_SUSPEND_MODE_PC, 0, 0);
+       }
+
        return 0;
 }
 
diff --git a/drivers/firmware/qcom_scm-32.c b/drivers/firmware/qcom_scm-32.c
deleted file mode 100644 (file)
index 48e2ef7..0000000
+++ /dev/null
@@ -1,671 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2010,2015, The Linux Foundation. All rights reserved.
- * Copyright (C) 2015 Linaro Ltd.
- */
-
-#include <linux/slab.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/errno.h>
-#include <linux/err.h>
-#include <linux/qcom_scm.h>
-#include <linux/dma-mapping.h>
-
-#include "qcom_scm.h"
-
-#define QCOM_SCM_FLAG_COLDBOOT_CPU0    0x00
-#define QCOM_SCM_FLAG_COLDBOOT_CPU1    0x01
-#define QCOM_SCM_FLAG_COLDBOOT_CPU2    0x08
-#define QCOM_SCM_FLAG_COLDBOOT_CPU3    0x20
-
-#define QCOM_SCM_FLAG_WARMBOOT_CPU0    0x04
-#define QCOM_SCM_FLAG_WARMBOOT_CPU1    0x02
-#define QCOM_SCM_FLAG_WARMBOOT_CPU2    0x10
-#define QCOM_SCM_FLAG_WARMBOOT_CPU3    0x40
-
-struct qcom_scm_entry {
-       int flag;
-       void *entry;
-};
-
-static struct qcom_scm_entry qcom_scm_wb[] = {
-       { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU0 },
-       { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU1 },
-       { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU2 },
-       { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU3 },
-};
-
-static DEFINE_MUTEX(qcom_scm_lock);
-
-/**
- * struct qcom_scm_command - one SCM command buffer
- * @len: total available memory for command and response
- * @buf_offset: start of command buffer
- * @resp_hdr_offset: start of response buffer
- * @id: command to be executed
- * @buf: buffer returned from qcom_scm_get_command_buffer()
- *
- * An SCM command is laid out in memory as follows:
- *
- *     ------------------- <--- struct qcom_scm_command
- *     | command header  |
- *     ------------------- <--- qcom_scm_get_command_buffer()
- *     | command buffer  |
- *     ------------------- <--- struct qcom_scm_response and
- *     | response header |      qcom_scm_command_to_response()
- *     ------------------- <--- qcom_scm_get_response_buffer()
- *     | response buffer |
- *     -------------------
- *
- * There can be arbitrary padding between the headers and buffers so
- * you should always use the appropriate qcom_scm_get_*_buffer() routines
- * to access the buffers in a safe manner.
- */
-struct qcom_scm_command {
-       __le32 len;
-       __le32 buf_offset;
-       __le32 resp_hdr_offset;
-       __le32 id;
-       __le32 buf[0];
-};
-
-/**
- * struct qcom_scm_response - one SCM response buffer
- * @len: total available memory for response
- * @buf_offset: start of response data relative to start of qcom_scm_response
- * @is_complete: indicates if the command has finished processing
- */
-struct qcom_scm_response {
-       __le32 len;
-       __le32 buf_offset;
-       __le32 is_complete;
-};
-
-/**
- * qcom_scm_command_to_response() - Get a pointer to a qcom_scm_response
- * @cmd: command
- *
- * Returns a pointer to a response for a command.
- */
-static inline struct qcom_scm_response *qcom_scm_command_to_response(
-               const struct qcom_scm_command *cmd)
-{
-       return (void *)cmd + le32_to_cpu(cmd->resp_hdr_offset);
-}
-
-/**
- * qcom_scm_get_command_buffer() - Get a pointer to a command buffer
- * @cmd: command
- *
- * Returns a pointer to the command buffer of a command.
- */
-static inline void *qcom_scm_get_command_buffer(const struct qcom_scm_command *cmd)
-{
-       return (void *)cmd->buf;
-}
-
-/**
- * qcom_scm_get_response_buffer() - Get a pointer to a response buffer
- * @rsp: response
- *
- * Returns a pointer to a response buffer of a response.
- */
-static inline void *qcom_scm_get_response_buffer(const struct qcom_scm_response *rsp)
-{
-       return (void *)rsp + le32_to_cpu(rsp->buf_offset);
-}
-
-static u32 smc(u32 cmd_addr)
-{
-       int context_id;
-       register u32 r0 asm("r0") = 1;
-       register u32 r1 asm("r1") = (u32)&context_id;
-       register u32 r2 asm("r2") = cmd_addr;
-       do {
-               asm volatile(
-                       __asmeq("%0", "r0")
-                       __asmeq("%1", "r0")
-                       __asmeq("%2", "r1")
-                       __asmeq("%3", "r2")
-#ifdef REQUIRES_SEC
-                       ".arch_extension sec\n"
-#endif
-                       "smc    #0      @ switch to secure world\n"
-                       : "=r" (r0)
-                       : "r" (r0), "r" (r1), "r" (r2)
-                       : "r3", "r12");
-       } while (r0 == QCOM_SCM_INTERRUPTED);
-
-       return r0;
-}
-
-/**
- * qcom_scm_call() - Send an SCM command
- * @dev: struct device
- * @svc_id: service identifier
- * @cmd_id: command identifier
- * @cmd_buf: command buffer
- * @cmd_len: length of the command buffer
- * @resp_buf: response buffer
- * @resp_len: length of the response buffer
- *
- * Sends a command to the SCM and waits for the command to finish processing.
- *
- * A note on cache maintenance:
- * Note that any buffers that are expected to be accessed by the secure world
- * must be flushed before invoking qcom_scm_call and invalidated in the cache
- * immediately after qcom_scm_call returns. Cache maintenance on the command
- * and response buffers is taken care of by qcom_scm_call; however, callers are
- * responsible for any other cached buffers passed over to the secure world.
- */
-static int qcom_scm_call(struct device *dev, u32 svc_id, u32 cmd_id,
-                        const void *cmd_buf, size_t cmd_len, void *resp_buf,
-                        size_t resp_len)
-{
-       int ret;
-       struct qcom_scm_command *cmd;
-       struct qcom_scm_response *rsp;
-       size_t alloc_len = sizeof(*cmd) + cmd_len + sizeof(*rsp) + resp_len;
-       dma_addr_t cmd_phys;
-
-       cmd = kzalloc(PAGE_ALIGN(alloc_len), GFP_KERNEL);
-       if (!cmd)
-               return -ENOMEM;
-
-       cmd->len = cpu_to_le32(alloc_len);
-       cmd->buf_offset = cpu_to_le32(sizeof(*cmd));
-       cmd->resp_hdr_offset = cpu_to_le32(sizeof(*cmd) + cmd_len);
-
-       cmd->id = cpu_to_le32((svc_id << 10) | cmd_id);
-       if (cmd_buf)
-               memcpy(qcom_scm_get_command_buffer(cmd), cmd_buf, cmd_len);
-
-       rsp = qcom_scm_command_to_response(cmd);
-
-       cmd_phys = dma_map_single(dev, cmd, alloc_len, DMA_TO_DEVICE);
-       if (dma_mapping_error(dev, cmd_phys)) {
-               kfree(cmd);
-               return -ENOMEM;
-       }
-
-       mutex_lock(&qcom_scm_lock);
-       ret = smc(cmd_phys);
-       if (ret < 0)
-               ret = qcom_scm_remap_error(ret);
-       mutex_unlock(&qcom_scm_lock);
-       if (ret)
-               goto out;
-
-       do {
-               dma_sync_single_for_cpu(dev, cmd_phys + sizeof(*cmd) + cmd_len,
-                                       sizeof(*rsp), DMA_FROM_DEVICE);
-       } while (!rsp->is_complete);
-
-       if (resp_buf) {
-               dma_sync_single_for_cpu(dev, cmd_phys + sizeof(*cmd) + cmd_len +
-                                       le32_to_cpu(rsp->buf_offset),
-                                       resp_len, DMA_FROM_DEVICE);
-               memcpy(resp_buf, qcom_scm_get_response_buffer(rsp),
-                      resp_len);
-       }
-out:
-       dma_unmap_single(dev, cmd_phys, alloc_len, DMA_TO_DEVICE);
-       kfree(cmd);
-       return ret;
-}
-
-#define SCM_CLASS_REGISTER     (0x2 << 8)
-#define SCM_MASK_IRQS          BIT(5)
-#define SCM_ATOMIC(svc, cmd, n) (((((svc) << 10)|((cmd) & 0x3ff)) << 12) | \
-                               SCM_CLASS_REGISTER | \
-                               SCM_MASK_IRQS | \
-                               (n & 0xf))
-
-/**
- * qcom_scm_call_atomic1() - Send an atomic SCM command with one argument
- * @svc_id: service identifier
- * @cmd_id: command identifier
- * @arg1: first argument
- *
- * This shall only be used with commands that are guaranteed to be
- * uninterruptable, atomic and SMP safe.
- */
-static s32 qcom_scm_call_atomic1(u32 svc, u32 cmd, u32 arg1)
-{
-       int context_id;
-
-       register u32 r0 asm("r0") = SCM_ATOMIC(svc, cmd, 1);
-       register u32 r1 asm("r1") = (u32)&context_id;
-       register u32 r2 asm("r2") = arg1;
-
-       asm volatile(
-                       __asmeq("%0", "r0")
-                       __asmeq("%1", "r0")
-                       __asmeq("%2", "r1")
-                       __asmeq("%3", "r2")
-#ifdef REQUIRES_SEC
-                       ".arch_extension sec\n"
-#endif
-                       "smc    #0      @ switch to secure world\n"
-                       : "=r" (r0)
-                       : "r" (r0), "r" (r1), "r" (r2)
-                       : "r3", "r12");
-       return r0;
-}
-
-/**
- * qcom_scm_call_atomic2() - Send an atomic SCM command with two arguments
- * @svc_id:    service identifier
- * @cmd_id:    command identifier
- * @arg1:      first argument
- * @arg2:      second argument
- *
- * This shall only be used with commands that are guaranteed to be
- * uninterruptable, atomic and SMP safe.
- */
-static s32 qcom_scm_call_atomic2(u32 svc, u32 cmd, u32 arg1, u32 arg2)
-{
-       int context_id;
-
-       register u32 r0 asm("r0") = SCM_ATOMIC(svc, cmd, 2);
-       register u32 r1 asm("r1") = (u32)&context_id;
-       register u32 r2 asm("r2") = arg1;
-       register u32 r3 asm("r3") = arg2;
-
-       asm volatile(
-                       __asmeq("%0", "r0")
-                       __asmeq("%1", "r0")
-                       __asmeq("%2", "r1")
-                       __asmeq("%3", "r2")
-                       __asmeq("%4", "r3")
-#ifdef REQUIRES_SEC
-                       ".arch_extension sec\n"
-#endif
-                       "smc    #0      @ switch to secure world\n"
-                       : "=r" (r0)
-                       : "r" (r0), "r" (r1), "r" (r2), "r" (r3)
-                       : "r12");
-       return r0;
-}
-
-u32 qcom_scm_get_version(void)
-{
-       int context_id;
-       static u32 version = -1;
-       register u32 r0 asm("r0");
-       register u32 r1 asm("r1");
-
-       if (version != -1)
-               return version;
-
-       mutex_lock(&qcom_scm_lock);
-
-       r0 = 0x1 << 8;
-       r1 = (u32)&context_id;
-       do {
-               asm volatile(
-                       __asmeq("%0", "r0")
-                       __asmeq("%1", "r1")
-                       __asmeq("%2", "r0")
-                       __asmeq("%3", "r1")
-#ifdef REQUIRES_SEC
-                       ".arch_extension sec\n"
-#endif
-                       "smc    #0      @ switch to secure world\n"
-                       : "=r" (r0), "=r" (r1)
-                       : "r" (r0), "r" (r1)
-                       : "r2", "r3", "r12");
-       } while (r0 == QCOM_SCM_INTERRUPTED);
-
-       version = r1;
-       mutex_unlock(&qcom_scm_lock);
-
-       return version;
-}
-EXPORT_SYMBOL(qcom_scm_get_version);
-
-/**
- * qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus
- * @entry: Entry point function for the cpus
- * @cpus: The cpumask of cpus that will use the entry point
- *
- * Set the cold boot address of the cpus. Any cpu outside the supported
- * range would be removed from the cpu present mask.
- */
-int __qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus)
-{
-       int flags = 0;
-       int cpu;
-       int scm_cb_flags[] = {
-               QCOM_SCM_FLAG_COLDBOOT_CPU0,
-               QCOM_SCM_FLAG_COLDBOOT_CPU1,
-               QCOM_SCM_FLAG_COLDBOOT_CPU2,
-               QCOM_SCM_FLAG_COLDBOOT_CPU3,
-       };
-
-       if (!cpus || (cpus && cpumask_empty(cpus)))
-               return -EINVAL;
-
-       for_each_cpu(cpu, cpus) {
-               if (cpu < ARRAY_SIZE(scm_cb_flags))
-                       flags |= scm_cb_flags[cpu];
-               else
-                       set_cpu_present(cpu, false);
-       }
-
-       return qcom_scm_call_atomic2(QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_ADDR,
-                                   flags, virt_to_phys(entry));
-}
-
-/**
- * qcom_scm_set_warm_boot_addr() - Set the warm boot address for cpus
- * @entry: Entry point function for the cpus
- * @cpus: The cpumask of cpus that will use the entry point
- *
- * Set the Linux entry point for the SCM to transfer control to when coming
- * out of a power down. CPU power down may be executed on cpuidle or hotplug.
- */
-int __qcom_scm_set_warm_boot_addr(struct device *dev, void *entry,
-                                 const cpumask_t *cpus)
-{
-       int ret;
-       int flags = 0;
-       int cpu;
-       struct {
-               __le32 flags;
-               __le32 addr;
-       } cmd;
-
-       /*
-        * Reassign only if we are switching from hotplug entry point
-        * to cpuidle entry point or vice versa.
-        */
-       for_each_cpu(cpu, cpus) {
-               if (entry == qcom_scm_wb[cpu].entry)
-                       continue;
-               flags |= qcom_scm_wb[cpu].flag;
-       }
-
-       /* No change in entry function */
-       if (!flags)
-               return 0;
-
-       cmd.addr = cpu_to_le32(virt_to_phys(entry));
-       cmd.flags = cpu_to_le32(flags);
-       ret = qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_ADDR,
-                           &cmd, sizeof(cmd), NULL, 0);
-       if (!ret) {
-               for_each_cpu(cpu, cpus)
-                       qcom_scm_wb[cpu].entry = entry;
-       }
-
-       return ret;
-}
-
-/**
- * qcom_scm_cpu_power_down() - Power down the cpu
- * @flags - Flags to flush cache
- *
- * This is an end point to power down cpu. If there was a pending interrupt,
- * the control would return from this function, otherwise, the cpu jumps to the
- * warm boot entry point set for this cpu upon reset.
- */
-void __qcom_scm_cpu_power_down(u32 flags)
-{
-       qcom_scm_call_atomic1(QCOM_SCM_SVC_BOOT, QCOM_SCM_CMD_TERMINATE_PC,
-                       flags & QCOM_SCM_FLUSH_FLAG_MASK);
-}
-
-int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, u32 cmd_id)
-{
-       int ret;
-       __le32 svc_cmd = cpu_to_le32((svc_id << 10) | cmd_id);
-       __le32 ret_val = 0;
-
-       ret = qcom_scm_call(dev, QCOM_SCM_SVC_INFO, QCOM_IS_CALL_AVAIL_CMD,
-                           &svc_cmd, sizeof(svc_cmd), &ret_val,
-                           sizeof(ret_val));
-       if (ret)
-               return ret;
-
-       return le32_to_cpu(ret_val);
-}
-
-int __qcom_scm_hdcp_req(struct device *dev, struct qcom_scm_hdcp_req *req,
-                       u32 req_cnt, u32 *resp)
-{
-       if (req_cnt > QCOM_SCM_HDCP_MAX_REQ_CNT)
-               return -ERANGE;
-
-       return qcom_scm_call(dev, QCOM_SCM_SVC_HDCP, QCOM_SCM_CMD_HDCP,
-               req, req_cnt * sizeof(*req), resp, sizeof(*resp));
-}
-
-int __qcom_scm_ocmem_lock(struct device *dev, u32 id, u32 offset, u32 size,
-                         u32 mode)
-{
-       struct ocmem_tz_lock {
-               __le32 id;
-               __le32 offset;
-               __le32 size;
-               __le32 mode;
-       } request;
-
-       request.id = cpu_to_le32(id);
-       request.offset = cpu_to_le32(offset);
-       request.size = cpu_to_le32(size);
-       request.mode = cpu_to_le32(mode);
-
-       return qcom_scm_call(dev, QCOM_SCM_OCMEM_SVC, QCOM_SCM_OCMEM_LOCK_CMD,
-                            &request, sizeof(request), NULL, 0);
-}
-
-int __qcom_scm_ocmem_unlock(struct device *dev, u32 id, u32 offset, u32 size)
-{
-       struct ocmem_tz_unlock {
-               __le32 id;
-               __le32 offset;
-               __le32 size;
-       } request;
-
-       request.id = cpu_to_le32(id);
-       request.offset = cpu_to_le32(offset);
-       request.size = cpu_to_le32(size);
-
-       return qcom_scm_call(dev, QCOM_SCM_OCMEM_SVC, QCOM_SCM_OCMEM_UNLOCK_CMD,
-                            &request, sizeof(request), NULL, 0);
-}
-
-void __qcom_scm_init(void)
-{
-}
-
-bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral)
-{
-       __le32 out;
-       __le32 in;
-       int ret;
-
-       in = cpu_to_le32(peripheral);
-       ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL,
-                           QCOM_SCM_PAS_IS_SUPPORTED_CMD,
-                           &in, sizeof(in),
-                           &out, sizeof(out));
-
-       return ret ? false : !!out;
-}
-
-int __qcom_scm_pas_init_image(struct device *dev, u32 peripheral,
-                             dma_addr_t metadata_phys)
-{
-       __le32 scm_ret;
-       int ret;
-       struct {
-               __le32 proc;
-               __le32 image_addr;
-       } request;
-
-       request.proc = cpu_to_le32(peripheral);
-       request.image_addr = cpu_to_le32(metadata_phys);
-
-       ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL,
-                           QCOM_SCM_PAS_INIT_IMAGE_CMD,
-                           &request, sizeof(request),
-                           &scm_ret, sizeof(scm_ret));
-
-       return ret ? : le32_to_cpu(scm_ret);
-}
-
-int __qcom_scm_pas_mem_setup(struct device *dev, u32 peripheral,
-                            phys_addr_t addr, phys_addr_t size)
-{
-       __le32 scm_ret;
-       int ret;
-       struct {
-               __le32 proc;
-               __le32 addr;
-               __le32 len;
-       } request;
-
-       request.proc = cpu_to_le32(peripheral);
-       request.addr = cpu_to_le32(addr);
-       request.len = cpu_to_le32(size);
-
-       ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL,
-                           QCOM_SCM_PAS_MEM_SETUP_CMD,
-                           &request, sizeof(request),
-                           &scm_ret, sizeof(scm_ret));
-
-       return ret ? : le32_to_cpu(scm_ret);
-}
-
-int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 peripheral)
-{
-       __le32 out;
-       __le32 in;
-       int ret;
-
-       in = cpu_to_le32(peripheral);
-       ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL,
-                           QCOM_SCM_PAS_AUTH_AND_RESET_CMD,
-                           &in, sizeof(in),
-                           &out, sizeof(out));
-
-       return ret ? : le32_to_cpu(out);
-}
-
-int __qcom_scm_pas_shutdown(struct device *dev, u32 peripheral)
-{
-       __le32 out;
-       __le32 in;
-       int ret;
-
-       in = cpu_to_le32(peripheral);
-       ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL,
-                           QCOM_SCM_PAS_SHUTDOWN_CMD,
-                           &in, sizeof(in),
-                           &out, sizeof(out));
-
-       return ret ? : le32_to_cpu(out);
-}
-
-int __qcom_scm_pas_mss_reset(struct device *dev, bool reset)
-{
-       __le32 out;
-       __le32 in = cpu_to_le32(reset);
-       int ret;
-
-       ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_MSS_RESET,
-                       &in, sizeof(in),
-                       &out, sizeof(out));
-
-       return ret ? : le32_to_cpu(out);
-}
-
-int __qcom_scm_set_dload_mode(struct device *dev, bool enable)
-{
-       return qcom_scm_call_atomic2(QCOM_SCM_SVC_BOOT, QCOM_SCM_SET_DLOAD_MODE,
-                                    enable ? QCOM_SCM_SET_DLOAD_MODE : 0, 0);
-}
-
-int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id)
-{
-       struct {
-               __le32 state;
-               __le32 id;
-       } req;
-       __le32 scm_ret = 0;
-       int ret;
-
-       req.state = cpu_to_le32(state);
-       req.id = cpu_to_le32(id);
-
-       ret = qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_SET_REMOTE_STATE,
-                           &req, sizeof(req), &scm_ret, sizeof(scm_ret));
-
-       return ret ? : le32_to_cpu(scm_ret);
-}
-
-int __qcom_scm_assign_mem(struct device *dev, phys_addr_t mem_region,
-                         size_t mem_sz, phys_addr_t src, size_t src_sz,
-                         phys_addr_t dest, size_t dest_sz)
-{
-       return -ENODEV;
-}
-
-int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id,
-                              u32 spare)
-{
-       struct msm_scm_sec_cfg {
-               __le32 id;
-               __le32 ctx_bank_num;
-       } cfg;
-       int ret, scm_ret = 0;
-
-       cfg.id = cpu_to_le32(device_id);
-       cfg.ctx_bank_num = cpu_to_le32(spare);
-
-       ret = qcom_scm_call(dev, QCOM_SCM_SVC_MP, QCOM_SCM_RESTORE_SEC_CFG,
-                           &cfg, sizeof(cfg), &scm_ret, sizeof(scm_ret));
-
-       if (ret || scm_ret)
-               return ret ? ret : -EINVAL;
-
-       return 0;
-}
-
-int __qcom_scm_iommu_secure_ptbl_size(struct device *dev, u32 spare,
-                                     size_t *size)
-{
-       return -ENODEV;
-}
-
-int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr, u32 size,
-                                     u32 spare)
-{
-       return -ENODEV;
-}
-
-int __qcom_scm_io_readl(struct device *dev, phys_addr_t addr,
-                       unsigned int *val)
-{
-       int ret;
-
-       ret = qcom_scm_call_atomic1(QCOM_SCM_SVC_IO, QCOM_SCM_IO_READ, addr);
-       if (ret >= 0)
-               *val = ret;
-
-       return ret < 0 ? ret : 0;
-}
-
-int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val)
-{
-       return qcom_scm_call_atomic2(QCOM_SCM_SVC_IO, QCOM_SCM_IO_WRITE,
-                                    addr, val);
-}
-
-int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev, bool enable)
-{
-       return -ENODEV;
-}
diff --git a/drivers/firmware/qcom_scm-64.c b/drivers/firmware/qcom_scm-64.c
deleted file mode 100644 (file)
index 3c58503..0000000
+++ /dev/null
@@ -1,579 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
- */
-
-#include <linux/io.h>
-#include <linux/errno.h>
-#include <linux/delay.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-#include <linux/qcom_scm.h>
-#include <linux/arm-smccc.h>
-#include <linux/dma-mapping.h>
-
-#include "qcom_scm.h"
-
-#define QCOM_SCM_FNID(s, c) ((((s) & 0xFF) << 8) | ((c) & 0xFF))
-
-#define MAX_QCOM_SCM_ARGS 10
-#define MAX_QCOM_SCM_RETS 3
-
-enum qcom_scm_arg_types {
-       QCOM_SCM_VAL,
-       QCOM_SCM_RO,
-       QCOM_SCM_RW,
-       QCOM_SCM_BUFVAL,
-};
-
-#define QCOM_SCM_ARGS_IMPL(num, a, b, c, d, e, f, g, h, i, j, ...) (\
-                          (((a) & 0x3) << 4) | \
-                          (((b) & 0x3) << 6) | \
-                          (((c) & 0x3) << 8) | \
-                          (((d) & 0x3) << 10) | \
-                          (((e) & 0x3) << 12) | \
-                          (((f) & 0x3) << 14) | \
-                          (((g) & 0x3) << 16) | \
-                          (((h) & 0x3) << 18) | \
-                          (((i) & 0x3) << 20) | \
-                          (((j) & 0x3) << 22) | \
-                          ((num) & 0xf))
-
-#define QCOM_SCM_ARGS(...) QCOM_SCM_ARGS_IMPL(__VA_ARGS__, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
-
-/**
- * struct qcom_scm_desc
- * @arginfo:   Metadata describing the arguments in args[]
- * @args:      The array of arguments for the secure syscall
- * @res:       The values returned by the secure syscall
- */
-struct qcom_scm_desc {
-       u32 arginfo;
-       u64 args[MAX_QCOM_SCM_ARGS];
-};
-
-static u64 qcom_smccc_convention = -1;
-static DEFINE_MUTEX(qcom_scm_lock);
-
-#define QCOM_SCM_EBUSY_WAIT_MS 30
-#define QCOM_SCM_EBUSY_MAX_RETRY 20
-
-#define N_EXT_QCOM_SCM_ARGS 7
-#define FIRST_EXT_ARG_IDX 3
-#define N_REGISTER_ARGS (MAX_QCOM_SCM_ARGS - N_EXT_QCOM_SCM_ARGS + 1)
-
-static void __qcom_scm_call_do(const struct qcom_scm_desc *desc,
-                              struct arm_smccc_res *res, u32 fn_id,
-                              u64 x5, u32 type)
-{
-       u64 cmd;
-       struct arm_smccc_quirk quirk = { .id = ARM_SMCCC_QUIRK_QCOM_A6 };
-
-       cmd = ARM_SMCCC_CALL_VAL(type, qcom_smccc_convention,
-                                ARM_SMCCC_OWNER_SIP, fn_id);
-
-       quirk.state.a6 = 0;
-
-       do {
-               arm_smccc_smc_quirk(cmd, desc->arginfo, desc->args[0],
-                                   desc->args[1], desc->args[2], x5,
-                                   quirk.state.a6, 0, res, &quirk);
-
-               if (res->a0 == QCOM_SCM_INTERRUPTED)
-                       cmd = res->a0;
-
-       } while (res->a0 == QCOM_SCM_INTERRUPTED);
-}
-
-static void qcom_scm_call_do(const struct qcom_scm_desc *desc,
-                            struct arm_smccc_res *res, u32 fn_id,
-                            u64 x5, bool atomic)
-{
-       int retry_count = 0;
-
-       if (atomic) {
-               __qcom_scm_call_do(desc, res, fn_id, x5, ARM_SMCCC_FAST_CALL);
-               return;
-       }
-
-       do {
-               mutex_lock(&qcom_scm_lock);
-
-               __qcom_scm_call_do(desc, res, fn_id, x5,
-                                  ARM_SMCCC_STD_CALL);
-
-               mutex_unlock(&qcom_scm_lock);
-
-               if (res->a0 == QCOM_SCM_V2_EBUSY) {
-                       if (retry_count++ > QCOM_SCM_EBUSY_MAX_RETRY)
-                               break;
-                       msleep(QCOM_SCM_EBUSY_WAIT_MS);
-               }
-       }  while (res->a0 == QCOM_SCM_V2_EBUSY);
-}
-
-static int ___qcom_scm_call(struct device *dev, u32 svc_id, u32 cmd_id,
-                           const struct qcom_scm_desc *desc,
-                           struct arm_smccc_res *res, bool atomic)
-{
-       int arglen = desc->arginfo & 0xf;
-       int i;
-       u32 fn_id = QCOM_SCM_FNID(svc_id, cmd_id);
-       u64 x5 = desc->args[FIRST_EXT_ARG_IDX];
-       dma_addr_t args_phys = 0;
-       void *args_virt = NULL;
-       size_t alloc_len;
-       gfp_t flag = atomic ? GFP_ATOMIC : GFP_KERNEL;
-
-       if (unlikely(arglen > N_REGISTER_ARGS)) {
-               alloc_len = N_EXT_QCOM_SCM_ARGS * sizeof(u64);
-               args_virt = kzalloc(PAGE_ALIGN(alloc_len), flag);
-
-               if (!args_virt)
-                       return -ENOMEM;
-
-               if (qcom_smccc_convention == ARM_SMCCC_SMC_32) {
-                       __le32 *args = args_virt;
-
-                       for (i = 0; i < N_EXT_QCOM_SCM_ARGS; i++)
-                               args[i] = cpu_to_le32(desc->args[i +
-                                                     FIRST_EXT_ARG_IDX]);
-               } else {
-                       __le64 *args = args_virt;
-
-                       for (i = 0; i < N_EXT_QCOM_SCM_ARGS; i++)
-                               args[i] = cpu_to_le64(desc->args[i +
-                                                     FIRST_EXT_ARG_IDX]);
-               }
-
-               args_phys = dma_map_single(dev, args_virt, alloc_len,
-                                          DMA_TO_DEVICE);
-
-               if (dma_mapping_error(dev, args_phys)) {
-                       kfree(args_virt);
-                       return -ENOMEM;
-               }
-
-               x5 = args_phys;
-       }
-
-       qcom_scm_call_do(desc, res, fn_id, x5, atomic);
-
-       if (args_virt) {
-               dma_unmap_single(dev, args_phys, alloc_len, DMA_TO_DEVICE);
-               kfree(args_virt);
-       }
-
-       if ((long)res->a0 < 0)
-               return qcom_scm_remap_error(res->a0);
-
-       return 0;
-}
-
-/**
- * qcom_scm_call() - Invoke a syscall in the secure world
- * @dev:       device
- * @svc_id:    service identifier
- * @cmd_id:    command identifier
- * @desc:      Descriptor structure containing arguments and return values
- *
- * Sends a command to the SCM and waits for the command to finish processing.
- * This should *only* be called in pre-emptible context.
- */
-static int qcom_scm_call(struct device *dev, u32 svc_id, u32 cmd_id,
-                        const struct qcom_scm_desc *desc,
-                        struct arm_smccc_res *res)
-{
-       might_sleep();
-       return ___qcom_scm_call(dev, svc_id, cmd_id, desc, res, false);
-}
-
-/**
- * qcom_scm_call_atomic() - atomic variation of qcom_scm_call()
- * @dev:       device
- * @svc_id:    service identifier
- * @cmd_id:    command identifier
- * @desc:      Descriptor structure containing arguments and return values
- * @res:       Structure containing results from SMC/HVC call
- *
- * Sends a command to the SCM and waits for the command to finish processing.
- * This can be called in atomic context.
- */
-static int qcom_scm_call_atomic(struct device *dev, u32 svc_id, u32 cmd_id,
-                               const struct qcom_scm_desc *desc,
-                               struct arm_smccc_res *res)
-{
-       return ___qcom_scm_call(dev, svc_id, cmd_id, desc, res, true);
-}
-
-/**
- * qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus
- * @entry: Entry point function for the cpus
- * @cpus: The cpumask of cpus that will use the entry point
- *
- * Set the cold boot address of the cpus. Any cpu outside the supported
- * range would be removed from the cpu present mask.
- */
-int __qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus)
-{
-       return -ENOTSUPP;
-}
-
-/**
- * qcom_scm_set_warm_boot_addr() - Set the warm boot address for cpus
- * @dev: Device pointer
- * @entry: Entry point function for the cpus
- * @cpus: The cpumask of cpus that will use the entry point
- *
- * Set the Linux entry point for the SCM to transfer control to when coming
- * out of a power down. CPU power down may be executed on cpuidle or hotplug.
- */
-int __qcom_scm_set_warm_boot_addr(struct device *dev, void *entry,
-                                 const cpumask_t *cpus)
-{
-       return -ENOTSUPP;
-}
-
-/**
- * qcom_scm_cpu_power_down() - Power down the cpu
- * @flags - Flags to flush cache
- *
- * This is an end point to power down cpu. If there was a pending interrupt,
- * the control would return from this function, otherwise, the cpu jumps to the
- * warm boot entry point set for this cpu upon reset.
- */
-void __qcom_scm_cpu_power_down(u32 flags)
-{
-}
-
-int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, u32 cmd_id)
-{
-       int ret;
-       struct qcom_scm_desc desc = {0};
-       struct arm_smccc_res res;
-
-       desc.arginfo = QCOM_SCM_ARGS(1);
-       desc.args[0] = QCOM_SCM_FNID(svc_id, cmd_id) |
-                       (ARM_SMCCC_OWNER_SIP << ARM_SMCCC_OWNER_SHIFT);
-
-       ret = qcom_scm_call(dev, QCOM_SCM_SVC_INFO, QCOM_IS_CALL_AVAIL_CMD,
-                           &desc, &res);
-
-       return ret ? : res.a1;
-}
-
-int __qcom_scm_hdcp_req(struct device *dev, struct qcom_scm_hdcp_req *req,
-                       u32 req_cnt, u32 *resp)
-{
-       int ret;
-       struct qcom_scm_desc desc = {0};
-       struct arm_smccc_res res;
-
-       if (req_cnt > QCOM_SCM_HDCP_MAX_REQ_CNT)
-               return -ERANGE;
-
-       desc.args[0] = req[0].addr;
-       desc.args[1] = req[0].val;
-       desc.args[2] = req[1].addr;
-       desc.args[3] = req[1].val;
-       desc.args[4] = req[2].addr;
-       desc.args[5] = req[2].val;
-       desc.args[6] = req[3].addr;
-       desc.args[7] = req[3].val;
-       desc.args[8] = req[4].addr;
-       desc.args[9] = req[4].val;
-       desc.arginfo = QCOM_SCM_ARGS(10);
-
-       ret = qcom_scm_call(dev, QCOM_SCM_SVC_HDCP, QCOM_SCM_CMD_HDCP, &desc,
-                           &res);
-       *resp = res.a1;
-
-       return ret;
-}
-
-int __qcom_scm_ocmem_lock(struct device *dev, uint32_t id, uint32_t offset,
-                         uint32_t size, uint32_t mode)
-{
-       return -ENOTSUPP;
-}
-
-int __qcom_scm_ocmem_unlock(struct device *dev, uint32_t id, uint32_t offset,
-                           uint32_t size)
-{
-       return -ENOTSUPP;
-}
-
-void __qcom_scm_init(void)
-{
-       u64 cmd;
-       struct arm_smccc_res res;
-       u32 function = QCOM_SCM_FNID(QCOM_SCM_SVC_INFO, QCOM_IS_CALL_AVAIL_CMD);
-
-       /* First try a SMC64 call */
-       cmd = ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_64,
-                                ARM_SMCCC_OWNER_SIP, function);
-
-       arm_smccc_smc(cmd, QCOM_SCM_ARGS(1), cmd & (~BIT(ARM_SMCCC_TYPE_SHIFT)),
-                     0, 0, 0, 0, 0, &res);
-
-       if (!res.a0 && res.a1)
-               qcom_smccc_convention = ARM_SMCCC_SMC_64;
-       else
-               qcom_smccc_convention = ARM_SMCCC_SMC_32;
-}
-
-bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral)
-{
-       int ret;
-       struct qcom_scm_desc desc = {0};
-       struct arm_smccc_res res;
-
-       desc.args[0] = peripheral;
-       desc.arginfo = QCOM_SCM_ARGS(1);
-
-       ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL,
-                               QCOM_SCM_PAS_IS_SUPPORTED_CMD,
-                               &desc, &res);
-
-       return ret ? false : !!res.a1;
-}
-
-int __qcom_scm_pas_init_image(struct device *dev, u32 peripheral,
-                             dma_addr_t metadata_phys)
-{
-       int ret;
-       struct qcom_scm_desc desc = {0};
-       struct arm_smccc_res res;
-
-       desc.args[0] = peripheral;
-       desc.args[1] = metadata_phys;
-       desc.arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_VAL, QCOM_SCM_RW);
-
-       ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_INIT_IMAGE_CMD,
-                               &desc, &res);
-
-       return ret ? : res.a1;
-}
-
-int __qcom_scm_pas_mem_setup(struct device *dev, u32 peripheral,
-                             phys_addr_t addr, phys_addr_t size)
-{
-       int ret;
-       struct qcom_scm_desc desc = {0};
-       struct arm_smccc_res res;
-
-       desc.args[0] = peripheral;
-       desc.args[1] = addr;
-       desc.args[2] = size;
-       desc.arginfo = QCOM_SCM_ARGS(3);
-
-       ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_MEM_SETUP_CMD,
-                               &desc, &res);
-
-       return ret ? : res.a1;
-}
-
-int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 peripheral)
-{
-       int ret;
-       struct qcom_scm_desc desc = {0};
-       struct arm_smccc_res res;
-
-       desc.args[0] = peripheral;
-       desc.arginfo = QCOM_SCM_ARGS(1);
-
-       ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL,
-                               QCOM_SCM_PAS_AUTH_AND_RESET_CMD,
-                               &desc, &res);
-
-       return ret ? : res.a1;
-}
-
-int __qcom_scm_pas_shutdown(struct device *dev, u32 peripheral)
-{
-       int ret;
-       struct qcom_scm_desc desc = {0};
-       struct arm_smccc_res res;
-
-       desc.args[0] = peripheral;
-       desc.arginfo = QCOM_SCM_ARGS(1);
-
-       ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_SHUTDOWN_CMD,
-                       &desc, &res);
-
-       return ret ? : res.a1;
-}
-
-int __qcom_scm_pas_mss_reset(struct device *dev, bool reset)
-{
-       struct qcom_scm_desc desc = {0};
-       struct arm_smccc_res res;
-       int ret;
-
-       desc.args[0] = reset;
-       desc.args[1] = 0;
-       desc.arginfo = QCOM_SCM_ARGS(2);
-
-       ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_MSS_RESET, &desc,
-                           &res);
-
-       return ret ? : res.a1;
-}
-
-int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id)
-{
-       struct qcom_scm_desc desc = {0};
-       struct arm_smccc_res res;
-       int ret;
-
-       desc.args[0] = state;
-       desc.args[1] = id;
-       desc.arginfo = QCOM_SCM_ARGS(2);
-
-       ret = qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_SET_REMOTE_STATE,
-                           &desc, &res);
-
-       return ret ? : res.a1;
-}
-
-int __qcom_scm_assign_mem(struct device *dev, phys_addr_t mem_region,
-                         size_t mem_sz, phys_addr_t src, size_t src_sz,
-                         phys_addr_t dest, size_t dest_sz)
-{
-       int ret;
-       struct qcom_scm_desc desc = {0};
-       struct arm_smccc_res res;
-
-       desc.args[0] = mem_region;
-       desc.args[1] = mem_sz;
-       desc.args[2] = src;
-       desc.args[3] = src_sz;
-       desc.args[4] = dest;
-       desc.args[5] = dest_sz;
-       desc.args[6] = 0;
-
-       desc.arginfo = QCOM_SCM_ARGS(7, QCOM_SCM_RO, QCOM_SCM_VAL,
-                                    QCOM_SCM_RO, QCOM_SCM_VAL, QCOM_SCM_RO,
-                                    QCOM_SCM_VAL, QCOM_SCM_VAL);
-
-       ret = qcom_scm_call(dev, QCOM_SCM_SVC_MP,
-                           QCOM_MEM_PROT_ASSIGN_ID,
-                           &desc, &res);
-
-       return ret ? : res.a1;
-}
-
-int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id, u32 spare)
-{
-       struct qcom_scm_desc desc = {0};
-       struct arm_smccc_res res;
-       int ret;
-
-       desc.args[0] = device_id;
-       desc.args[1] = spare;
-       desc.arginfo = QCOM_SCM_ARGS(2);
-
-       ret = qcom_scm_call(dev, QCOM_SCM_SVC_MP, QCOM_SCM_RESTORE_SEC_CFG,
-                           &desc, &res);
-
-       return ret ? : res.a1;
-}
-
-int __qcom_scm_iommu_secure_ptbl_size(struct device *dev, u32 spare,
-                                     size_t *size)
-{
-       struct qcom_scm_desc desc = {0};
-       struct arm_smccc_res res;
-       int ret;
-
-       desc.args[0] = spare;
-       desc.arginfo = QCOM_SCM_ARGS(1);
-
-       ret = qcom_scm_call(dev, QCOM_SCM_SVC_MP,
-                           QCOM_SCM_IOMMU_SECURE_PTBL_SIZE, &desc, &res);
-
-       if (size)
-               *size = res.a1;
-
-       return ret ? : res.a2;
-}
-
-int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr, u32 size,
-                                     u32 spare)
-{
-       struct qcom_scm_desc desc = {0};
-       struct arm_smccc_res res;
-       int ret;
-
-       desc.args[0] = addr;
-       desc.args[1] = size;
-       desc.args[2] = spare;
-       desc.arginfo = QCOM_SCM_ARGS(3, QCOM_SCM_RW, QCOM_SCM_VAL,
-                                    QCOM_SCM_VAL);
-
-       ret = qcom_scm_call(dev, QCOM_SCM_SVC_MP,
-                           QCOM_SCM_IOMMU_SECURE_PTBL_INIT, &desc, &res);
-
-       /* the pg table has been initialized already, ignore the error */
-       if (ret == -EPERM)
-               ret = 0;
-
-       return ret;
-}
-
-int __qcom_scm_set_dload_mode(struct device *dev, bool enable)
-{
-       struct qcom_scm_desc desc = {0};
-       struct arm_smccc_res res;
-
-       desc.args[0] = QCOM_SCM_SET_DLOAD_MODE;
-       desc.args[1] = enable ? QCOM_SCM_SET_DLOAD_MODE : 0;
-       desc.arginfo = QCOM_SCM_ARGS(2);
-
-       return qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_SET_DLOAD_MODE,
-                            &desc, &res);
-}
-
-int __qcom_scm_io_readl(struct device *dev, phys_addr_t addr,
-                       unsigned int *val)
-{
-       struct qcom_scm_desc desc = {0};
-       struct arm_smccc_res res;
-       int ret;
-
-       desc.args[0] = addr;
-       desc.arginfo = QCOM_SCM_ARGS(1);
-
-       ret = qcom_scm_call(dev, QCOM_SCM_SVC_IO, QCOM_SCM_IO_READ,
-                           &desc, &res);
-       if (ret >= 0)
-               *val = res.a1;
-
-       return ret < 0 ? ret : 0;
-}
-
-int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val)
-{
-       struct qcom_scm_desc desc = {0};
-       struct arm_smccc_res res;
-
-       desc.args[0] = addr;
-       desc.args[1] = val;
-       desc.arginfo = QCOM_SCM_ARGS(2);
-
-       return qcom_scm_call(dev, QCOM_SCM_SVC_IO, QCOM_SCM_IO_WRITE,
-                            &desc, &res);
-}
-
-int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev, bool en)
-{
-       struct qcom_scm_desc desc = {0};
-       struct arm_smccc_res res;
-
-       desc.args[0] = QCOM_SCM_CONFIG_ERRATA1_CLIENT_ALL;
-       desc.args[1] = en;
-       desc.arginfo = QCOM_SCM_ARGS(2);
-
-       return qcom_scm_call_atomic(dev, QCOM_SCM_SVC_SMMU_PROGRAM,
-                                   QCOM_SCM_CONFIG_ERRATA1, &desc, &res);
-}
diff --git a/drivers/firmware/qcom_scm-legacy.c b/drivers/firmware/qcom_scm-legacy.c
new file mode 100644 (file)
index 0000000..8532e7c
--- /dev/null
@@ -0,0 +1,242 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2010,2015,2019 The Linux Foundation. All rights reserved.
+ * Copyright (C) 2015 Linaro Ltd.
+ */
+
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/qcom_scm.h>
+#include <linux/arm-smccc.h>
+#include <linux/dma-mapping.h>
+
+#include "qcom_scm.h"
+
+static DEFINE_MUTEX(qcom_scm_lock);
+
+
+/**
+ * struct arm_smccc_args
+ * @args:      The array of values used in registers in smc instruction
+ */
+struct arm_smccc_args {
+       unsigned long args[8];
+};
+
+
+/**
+ * struct scm_legacy_command - one SCM command buffer
+ * @len: total available memory for command and response
+ * @buf_offset: start of command buffer
+ * @resp_hdr_offset: start of response buffer
+ * @id: command to be executed
+ * @buf: buffer returned from scm_legacy_get_command_buffer()
+ *
+ * An SCM command is laid out in memory as follows:
+ *
+ *     ------------------- <--- struct scm_legacy_command
+ *     | command header  |
+ *     ------------------- <--- scm_legacy_get_command_buffer()
+ *     | command buffer  |
+ *     ------------------- <--- struct scm_legacy_response and
+ *     | response header |      scm_legacy_command_to_response()
+ *     ------------------- <--- scm_legacy_get_response_buffer()
+ *     | response buffer |
+ *     -------------------
+ *
+ * There can be arbitrary padding between the headers and buffers so
+ * you should always use the appropriate scm_legacy_get_*_buffer() routines
+ * to access the buffers in a safe manner.
+ */
+struct scm_legacy_command {
+       __le32 len;
+       __le32 buf_offset;
+       __le32 resp_hdr_offset;
+       __le32 id;
+       __le32 buf[0];
+};
+
+/**
+ * struct scm_legacy_response - one SCM response buffer
+ * @len: total available memory for response
+ * @buf_offset: start of response data relative to start of scm_legacy_response
+ * @is_complete: indicates if the command has finished processing
+ */
+struct scm_legacy_response {
+       __le32 len;
+       __le32 buf_offset;
+       __le32 is_complete;
+};
+
+/**
+ * scm_legacy_command_to_response() - Get a pointer to a scm_legacy_response
+ * @cmd: command
+ *
+ * Returns a pointer to a response for a command.
+ */
+static inline struct scm_legacy_response *scm_legacy_command_to_response(
+               const struct scm_legacy_command *cmd)
+{
+       return (void *)cmd + le32_to_cpu(cmd->resp_hdr_offset);
+}
+
+/**
+ * scm_legacy_get_command_buffer() - Get a pointer to a command buffer
+ * @cmd: command
+ *
+ * Returns a pointer to the command buffer of a command.
+ */
+static inline void *scm_legacy_get_command_buffer(
+               const struct scm_legacy_command *cmd)
+{
+       return (void *)cmd->buf;
+}
+
+/**
+ * scm_legacy_get_response_buffer() - Get a pointer to a response buffer
+ * @rsp: response
+ *
+ * Returns a pointer to a response buffer of a response.
+ */
+static inline void *scm_legacy_get_response_buffer(
+               const struct scm_legacy_response *rsp)
+{
+       return (void *)rsp + le32_to_cpu(rsp->buf_offset);
+}
+
+static void __scm_legacy_do(const struct arm_smccc_args *smc,
+                           struct arm_smccc_res *res)
+{
+       do {
+               arm_smccc_smc(smc->args[0], smc->args[1], smc->args[2],
+                             smc->args[3], smc->args[4], smc->args[5],
+                             smc->args[6], smc->args[7], res);
+       } while (res->a0 == QCOM_SCM_INTERRUPTED);
+}
+
+/**
+ * qcom_scm_call() - Sends a command to the SCM and waits for the command to
+ * finish processing.
+ *
+ * A note on cache maintenance:
+ * Note that any buffers that are expected to be accessed by the secure world
+ * must be flushed before invoking qcom_scm_call and invalidated in the cache
+ * immediately after qcom_scm_call returns. Cache maintenance on the command
+ * and response buffers is taken care of by qcom_scm_call; however, callers are
+ * responsible for any other cached buffers passed over to the secure world.
+ */
+int scm_legacy_call(struct device *dev, const struct qcom_scm_desc *desc,
+                   struct qcom_scm_res *res)
+{
+       u8 arglen = desc->arginfo & 0xf;
+       int ret = 0, context_id;
+       unsigned int i;
+       struct scm_legacy_command *cmd;
+       struct scm_legacy_response *rsp;
+       struct arm_smccc_args smc = {0};
+       struct arm_smccc_res smc_res;
+       const size_t cmd_len = arglen * sizeof(__le32);
+       const size_t resp_len = MAX_QCOM_SCM_RETS * sizeof(__le32);
+       size_t alloc_len = sizeof(*cmd) + cmd_len + sizeof(*rsp) + resp_len;
+       dma_addr_t cmd_phys;
+       __le32 *arg_buf;
+       const __le32 *res_buf;
+
+       cmd = kzalloc(PAGE_ALIGN(alloc_len), GFP_KERNEL);
+       if (!cmd)
+               return -ENOMEM;
+
+       cmd->len = cpu_to_le32(alloc_len);
+       cmd->buf_offset = cpu_to_le32(sizeof(*cmd));
+       cmd->resp_hdr_offset = cpu_to_le32(sizeof(*cmd) + cmd_len);
+       cmd->id = cpu_to_le32(SCM_LEGACY_FNID(desc->svc, desc->cmd));
+
+       arg_buf = scm_legacy_get_command_buffer(cmd);
+       for (i = 0; i < arglen; i++)
+               arg_buf[i] = cpu_to_le32(desc->args[i]);
+
+       rsp = scm_legacy_command_to_response(cmd);
+
+       cmd_phys = dma_map_single(dev, cmd, alloc_len, DMA_TO_DEVICE);
+       if (dma_mapping_error(dev, cmd_phys)) {
+               kfree(cmd);
+               return -ENOMEM;
+       }
+
+       smc.args[0] = 1;
+       smc.args[1] = (unsigned long)&context_id;
+       smc.args[2] = cmd_phys;
+
+       mutex_lock(&qcom_scm_lock);
+       __scm_legacy_do(&smc, &smc_res);
+       if (smc_res.a0)
+               ret = qcom_scm_remap_error(smc_res.a0);
+       mutex_unlock(&qcom_scm_lock);
+       if (ret)
+               goto out;
+
+       do {
+               dma_sync_single_for_cpu(dev, cmd_phys + sizeof(*cmd) + cmd_len,
+                                       sizeof(*rsp), DMA_FROM_DEVICE);
+       } while (!rsp->is_complete);
+
+       dma_sync_single_for_cpu(dev, cmd_phys + sizeof(*cmd) + cmd_len +
+                               le32_to_cpu(rsp->buf_offset),
+                               resp_len, DMA_FROM_DEVICE);
+
+       if (res) {
+               res_buf = scm_legacy_get_response_buffer(rsp);
+               for (i = 0; i < MAX_QCOM_SCM_RETS; i++)
+                       res->result[i] = le32_to_cpu(res_buf[i]);
+       }
+out:
+       dma_unmap_single(dev, cmd_phys, alloc_len, DMA_TO_DEVICE);
+       kfree(cmd);
+       return ret;
+}
+
+#define SCM_LEGACY_ATOMIC_N_REG_ARGS   5
+#define SCM_LEGACY_ATOMIC_FIRST_REG_IDX        2
+#define SCM_LEGACY_CLASS_REGISTER              (0x2 << 8)
+#define SCM_LEGACY_MASK_IRQS           BIT(5)
+#define SCM_LEGACY_ATOMIC_ID(svc, cmd, n) \
+                               ((SCM_LEGACY_FNID(svc, cmd) << 12) | \
+                               SCM_LEGACY_CLASS_REGISTER | \
+                               SCM_LEGACY_MASK_IRQS | \
+                               (n & 0xf))
+
+/**
+ * qcom_scm_call_atomic() - Send an atomic SCM command with up to 5 arguments
+ * and 3 return values
+ * @desc: SCM call descriptor containing arguments
+ * @res:  SCM call return values
+ *
+ * This shall only be used with commands that are guaranteed to be
+ * uninterruptable, atomic and SMP safe.
+ */
+int scm_legacy_call_atomic(struct device *unused,
+                          const struct qcom_scm_desc *desc,
+                          struct qcom_scm_res *res)
+{
+       int context_id;
+       struct arm_smccc_res smc_res;
+       size_t arglen = desc->arginfo & 0xf;
+
+       BUG_ON(arglen > SCM_LEGACY_ATOMIC_N_REG_ARGS);
+
+       arm_smccc_smc(SCM_LEGACY_ATOMIC_ID(desc->svc, desc->cmd, arglen),
+                     (unsigned long)&context_id,
+                     desc->args[0], desc->args[1], desc->args[2],
+                     desc->args[3], desc->args[4], 0, &smc_res);
+
+       if (res) {
+               res->result[0] = smc_res.a1;
+               res->result[1] = smc_res.a2;
+               res->result[2] = smc_res.a3;
+       }
+
+       return smc_res.a0;
+}
diff --git a/drivers/firmware/qcom_scm-smc.c b/drivers/firmware/qcom_scm-smc.c
new file mode 100644 (file)
index 0000000..497c13b
--- /dev/null
@@ -0,0 +1,151 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2015,2019 The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/io.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/qcom_scm.h>
+#include <linux/arm-smccc.h>
+#include <linux/dma-mapping.h>
+
+#include "qcom_scm.h"
+
+/**
+ * struct arm_smccc_args
+ * @args:      The array of values used in registers in smc instruction
+ */
+struct arm_smccc_args {
+       unsigned long args[8];
+};
+
+static DEFINE_MUTEX(qcom_scm_lock);
+
+#define QCOM_SCM_EBUSY_WAIT_MS 30
+#define QCOM_SCM_EBUSY_MAX_RETRY 20
+
+#define SCM_SMC_N_REG_ARGS     4
+#define SCM_SMC_FIRST_EXT_IDX  (SCM_SMC_N_REG_ARGS - 1)
+#define SCM_SMC_N_EXT_ARGS     (MAX_QCOM_SCM_ARGS - SCM_SMC_N_REG_ARGS + 1)
+#define SCM_SMC_FIRST_REG_IDX  2
+#define SCM_SMC_LAST_REG_IDX   (SCM_SMC_FIRST_REG_IDX + SCM_SMC_N_REG_ARGS - 1)
+
+static void __scm_smc_do_quirk(const struct arm_smccc_args *smc,
+                              struct arm_smccc_res *res)
+{
+       unsigned long a0 = smc->args[0];
+       struct arm_smccc_quirk quirk = { .id = ARM_SMCCC_QUIRK_QCOM_A6 };
+
+       quirk.state.a6 = 0;
+
+       do {
+               arm_smccc_smc_quirk(a0, smc->args[1], smc->args[2],
+                                   smc->args[3], smc->args[4], smc->args[5],
+                                   quirk.state.a6, smc->args[7], res, &quirk);
+
+               if (res->a0 == QCOM_SCM_INTERRUPTED)
+                       a0 = res->a0;
+
+       } while (res->a0 == QCOM_SCM_INTERRUPTED);
+}
+
+static void __scm_smc_do(const struct arm_smccc_args *smc,
+                        struct arm_smccc_res *res, bool atomic)
+{
+       int retry_count = 0;
+
+       if (atomic) {
+               __scm_smc_do_quirk(smc, res);
+               return;
+       }
+
+       do {
+               mutex_lock(&qcom_scm_lock);
+
+               __scm_smc_do_quirk(smc, res);
+
+               mutex_unlock(&qcom_scm_lock);
+
+               if (res->a0 == QCOM_SCM_V2_EBUSY) {
+                       if (retry_count++ > QCOM_SCM_EBUSY_MAX_RETRY)
+                               break;
+                       msleep(QCOM_SCM_EBUSY_WAIT_MS);
+               }
+       }  while (res->a0 == QCOM_SCM_V2_EBUSY);
+}
+
+int scm_smc_call(struct device *dev, const struct qcom_scm_desc *desc,
+                struct qcom_scm_res *res, bool atomic)
+{
+       int arglen = desc->arginfo & 0xf;
+       int i;
+       dma_addr_t args_phys = 0;
+       void *args_virt = NULL;
+       size_t alloc_len;
+       gfp_t flag = atomic ? GFP_ATOMIC : GFP_KERNEL;
+       u32 smccc_call_type = atomic ? ARM_SMCCC_FAST_CALL : ARM_SMCCC_STD_CALL;
+       u32 qcom_smccc_convention =
+                       (qcom_scm_convention == SMC_CONVENTION_ARM_32) ?
+                       ARM_SMCCC_SMC_32 : ARM_SMCCC_SMC_64;
+       struct arm_smccc_res smc_res;
+       struct arm_smccc_args smc = {0};
+
+       smc.args[0] = ARM_SMCCC_CALL_VAL(
+               smccc_call_type,
+               qcom_smccc_convention,
+               desc->owner,
+               SCM_SMC_FNID(desc->svc, desc->cmd));
+       smc.args[1] = desc->arginfo;
+       for (i = 0; i < SCM_SMC_N_REG_ARGS; i++)
+               smc.args[i + SCM_SMC_FIRST_REG_IDX] = desc->args[i];
+
+       if (unlikely(arglen > SCM_SMC_N_REG_ARGS)) {
+               alloc_len = SCM_SMC_N_EXT_ARGS * sizeof(u64);
+               args_virt = kzalloc(PAGE_ALIGN(alloc_len), flag);
+
+               if (!args_virt)
+                       return -ENOMEM;
+
+               if (qcom_smccc_convention == ARM_SMCCC_SMC_32) {
+                       __le32 *args = args_virt;
+
+                       for (i = 0; i < SCM_SMC_N_EXT_ARGS; i++)
+                               args[i] = cpu_to_le32(desc->args[i +
+                                                     SCM_SMC_FIRST_EXT_IDX]);
+               } else {
+                       __le64 *args = args_virt;
+
+                       for (i = 0; i < SCM_SMC_N_EXT_ARGS; i++)
+                               args[i] = cpu_to_le64(desc->args[i +
+                                                     SCM_SMC_FIRST_EXT_IDX]);
+               }
+
+               args_phys = dma_map_single(dev, args_virt, alloc_len,
+                                          DMA_TO_DEVICE);
+
+               if (dma_mapping_error(dev, args_phys)) {
+                       kfree(args_virt);
+                       return -ENOMEM;
+               }
+
+               smc.args[SCM_SMC_LAST_REG_IDX] = args_phys;
+       }
+
+       __scm_smc_do(&smc, &smc_res, atomic);
+
+       if (args_virt) {
+               dma_unmap_single(dev, args_phys, alloc_len, DMA_TO_DEVICE);
+               kfree(args_virt);
+       }
+
+       if (res) {
+               res->result[0] = smc_res.a1;
+               res->result[1] = smc_res.a2;
+               res->result[2] = smc_res.a3;
+       }
+
+       return (long)smc_res.a0 ? qcom_scm_remap_error(smc_res.a0) : 0;
+}
index 1ba0df4b97aba752624ec78fc3531cbd4ef5005f..059bb0fbae9e5bd810e5f71347b9175123ae9670 100644 (file)
@@ -1,8 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0-only
-/*
- * Qualcomm SCM driver
- *
- * Copyright (c) 2010,2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010,2015,2019 The Linux Foundation. All rights reserved.
  * Copyright (C) 2015 Linaro Ltd.
  */
 #include <linux/platform_device.h>
@@ -19,6 +16,7 @@
 #include <linux/of_platform.h>
 #include <linux/clk.h>
 #include <linux/reset-controller.h>
+#include <linux/arm-smccc.h>
 
 #include "qcom_scm.h"
 
@@ -52,6 +50,35 @@ struct qcom_scm_mem_map_info {
        __le64 mem_size;
 };
 
+#define QCOM_SCM_FLAG_COLDBOOT_CPU0    0x00
+#define QCOM_SCM_FLAG_COLDBOOT_CPU1    0x01
+#define QCOM_SCM_FLAG_COLDBOOT_CPU2    0x08
+#define QCOM_SCM_FLAG_COLDBOOT_CPU3    0x20
+
+#define QCOM_SCM_FLAG_WARMBOOT_CPU0    0x04
+#define QCOM_SCM_FLAG_WARMBOOT_CPU1    0x02
+#define QCOM_SCM_FLAG_WARMBOOT_CPU2    0x10
+#define QCOM_SCM_FLAG_WARMBOOT_CPU3    0x40
+
+struct qcom_scm_wb_entry {
+       int flag;
+       void *entry;
+};
+
+static struct qcom_scm_wb_entry qcom_scm_wb[] = {
+       { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU0 },
+       { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU1 },
+       { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU2 },
+       { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU3 },
+};
+
+static const char *qcom_scm_convention_names[] = {
+       [SMC_CONVENTION_UNKNOWN] = "unknown",
+       [SMC_CONVENTION_ARM_32] = "smc arm 32",
+       [SMC_CONVENTION_ARM_64] = "smc arm 64",
+       [SMC_CONVENTION_LEGACY] = "smc legacy",
+};
+
 static struct qcom_scm *__scm;
 
 static int qcom_scm_clk_enable(void)
@@ -87,149 +114,308 @@ static void qcom_scm_clk_disable(void)
        clk_disable_unprepare(__scm->bus_clk);
 }
 
-/**
- * qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus
- * @entry: Entry point function for the cpus
- * @cpus: The cpumask of cpus that will use the entry point
- *
- * Set the cold boot address of the cpus. Any cpu outside the supported
- * range would be removed from the cpu present mask.
- */
-int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus)
+static int __qcom_scm_is_call_available(struct device *dev, u32 svc_id,
+                                       u32 cmd_id);
+
+enum qcom_scm_convention qcom_scm_convention;
+static bool has_queried __read_mostly;
+static DEFINE_SPINLOCK(query_lock);
+
+static void __query_convention(void)
 {
-       return __qcom_scm_set_cold_boot_addr(entry, cpus);
+       unsigned long flags;
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_INFO,
+               .cmd = QCOM_SCM_INFO_IS_CALL_AVAIL,
+               .args[0] = SCM_SMC_FNID(QCOM_SCM_SVC_INFO,
+                                          QCOM_SCM_INFO_IS_CALL_AVAIL) |
+                          (ARM_SMCCC_OWNER_SIP << ARM_SMCCC_OWNER_SHIFT),
+               .arginfo = QCOM_SCM_ARGS(1),
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+       struct qcom_scm_res res;
+       int ret;
+
+       spin_lock_irqsave(&query_lock, flags);
+       if (has_queried)
+               goto out;
+
+       qcom_scm_convention = SMC_CONVENTION_ARM_64;
+       // Device isn't required as there is only one argument - no device
+       // needed to dma_map_single to secure world
+       ret = scm_smc_call(NULL, &desc, &res, true);
+       if (!ret && res.result[0] == 1)
+               goto out;
+
+       qcom_scm_convention = SMC_CONVENTION_ARM_32;
+       ret = scm_smc_call(NULL, &desc, &res, true);
+       if (!ret && res.result[0] == 1)
+               goto out;
+
+       qcom_scm_convention = SMC_CONVENTION_LEGACY;
+out:
+       has_queried = true;
+       spin_unlock_irqrestore(&query_lock, flags);
+       pr_info("qcom_scm: convention: %s\n",
+               qcom_scm_convention_names[qcom_scm_convention]);
 }
-EXPORT_SYMBOL(qcom_scm_set_cold_boot_addr);
 
-/**
- * qcom_scm_set_warm_boot_addr() - Set the warm boot address for cpus
- * @entry: Entry point function for the cpus
- * @cpus: The cpumask of cpus that will use the entry point
- *
- * Set the Linux entry point for the SCM to transfer control to when coming
- * out of a power down. CPU power down may be executed on cpuidle or hotplug.
- */
-int qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus)
+static inline enum qcom_scm_convention __get_convention(void)
 {
-       return __qcom_scm_set_warm_boot_addr(__scm->dev, entry, cpus);
+       if (unlikely(!has_queried))
+               __query_convention();
+       return qcom_scm_convention;
 }
-EXPORT_SYMBOL(qcom_scm_set_warm_boot_addr);
 
 /**
- * qcom_scm_cpu_power_down() - Power down the cpu
- * @flags - Flags to flush cache
+ * qcom_scm_call() - Invoke a syscall in the secure world
+ * @dev:       device
+ * @svc_id:    service identifier
+ * @cmd_id:    command identifier
+ * @desc:      Descriptor structure containing arguments and return values
  *
- * This is an end point to power down cpu. If there was a pending interrupt,
- * the control would return from this function, otherwise, the cpu jumps to the
- * warm boot entry point set for this cpu upon reset.
+ * Sends a command to the SCM and waits for the command to finish processing.
+ * This should *only* be called in pre-emptible context.
  */
-void qcom_scm_cpu_power_down(u32 flags)
+static int qcom_scm_call(struct device *dev, const struct qcom_scm_desc *desc,
+                        struct qcom_scm_res *res)
 {
-       __qcom_scm_cpu_power_down(flags);
+       might_sleep();
+       switch (__get_convention()) {
+       case SMC_CONVENTION_ARM_32:
+       case SMC_CONVENTION_ARM_64:
+               return scm_smc_call(dev, desc, res, false);
+       case SMC_CONVENTION_LEGACY:
+               return scm_legacy_call(dev, desc, res);
+       default:
+               pr_err("Unknown current SCM calling convention.\n");
+               return -EINVAL;
+       }
 }
-EXPORT_SYMBOL(qcom_scm_cpu_power_down);
 
 /**
- * qcom_scm_hdcp_available() - Check if secure environment supports HDCP.
+ * qcom_scm_call_atomic() - atomic variation of qcom_scm_call()
+ * @dev:       device
+ * @svc_id:    service identifier
+ * @cmd_id:    command identifier
+ * @desc:      Descriptor structure containing arguments and return values
+ * @res:       Structure containing results from SMC/HVC call
  *
- * Return true if HDCP is supported, false if not.
+ * Sends a command to the SCM and waits for the command to finish processing.
+ * This can be called in atomic context.
  */
-bool qcom_scm_hdcp_available(void)
+static int qcom_scm_call_atomic(struct device *dev,
+                               const struct qcom_scm_desc *desc,
+                               struct qcom_scm_res *res)
 {
-       int ret = qcom_scm_clk_enable();
-
-       if (ret)
-               return ret;
+       switch (__get_convention()) {
+       case SMC_CONVENTION_ARM_32:
+       case SMC_CONVENTION_ARM_64:
+               return scm_smc_call(dev, desc, res, true);
+       case SMC_CONVENTION_LEGACY:
+               return scm_legacy_call_atomic(dev, desc, res);
+       default:
+               pr_err("Unknown current SCM calling convention.\n");
+               return -EINVAL;
+       }
+}
 
-       ret = __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_HDCP,
-                                               QCOM_SCM_CMD_HDCP);
+static int __qcom_scm_is_call_available(struct device *dev, u32 svc_id,
+                                       u32 cmd_id)
+{
+       int ret;
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_INFO,
+               .cmd = QCOM_SCM_INFO_IS_CALL_AVAIL,
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+       struct qcom_scm_res res;
+
+       desc.arginfo = QCOM_SCM_ARGS(1);
+       switch (__get_convention()) {
+       case SMC_CONVENTION_ARM_32:
+       case SMC_CONVENTION_ARM_64:
+               desc.args[0] = SCM_SMC_FNID(svc_id, cmd_id) |
+                               (ARM_SMCCC_OWNER_SIP << ARM_SMCCC_OWNER_SHIFT);
+               break;
+       case SMC_CONVENTION_LEGACY:
+               desc.args[0] = SCM_LEGACY_FNID(svc_id, cmd_id);
+               break;
+       default:
+               pr_err("Unknown SMC convention being used\n");
+               return -EINVAL;
+       }
 
-       qcom_scm_clk_disable();
+       ret = qcom_scm_call(dev, &desc, &res);
 
-       return ret > 0 ? true : false;
+       return ret ? : res.result[0];
 }
-EXPORT_SYMBOL(qcom_scm_hdcp_available);
 
 /**
- * qcom_scm_hdcp_req() - Send HDCP request.
- * @req: HDCP request array
- * @req_cnt: HDCP request array count
- * @resp: response buffer passed to SCM
+ * qcom_scm_set_warm_boot_addr() - Set the warm boot address for cpus
+ * @entry: Entry point function for the cpus
+ * @cpus: The cpumask of cpus that will use the entry point
  *
- * Write HDCP register(s) through SCM.
+ * Set the Linux entry point for the SCM to transfer control to when coming
+ * out of a power down. CPU power down may be executed on cpuidle or hotplug.
  */
-int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp)
+int qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus)
 {
-       int ret = qcom_scm_clk_enable();
+       int ret;
+       int flags = 0;
+       int cpu;
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_BOOT,
+               .cmd = QCOM_SCM_BOOT_SET_ADDR,
+               .arginfo = QCOM_SCM_ARGS(2),
+       };
 
-       if (ret)
-               return ret;
+       /*
+        * Reassign only if we are switching from hotplug entry point
+        * to cpuidle entry point or vice versa.
+        */
+       for_each_cpu(cpu, cpus) {
+               if (entry == qcom_scm_wb[cpu].entry)
+                       continue;
+               flags |= qcom_scm_wb[cpu].flag;
+       }
+
+       /* No change in entry function */
+       if (!flags)
+               return 0;
+
+       desc.args[0] = flags;
+       desc.args[1] = virt_to_phys(entry);
+
+       ret = qcom_scm_call(__scm->dev, &desc, NULL);
+       if (!ret) {
+               for_each_cpu(cpu, cpus)
+                       qcom_scm_wb[cpu].entry = entry;
+       }
 
-       ret = __qcom_scm_hdcp_req(__scm->dev, req, req_cnt, resp);
-       qcom_scm_clk_disable();
        return ret;
 }
-EXPORT_SYMBOL(qcom_scm_hdcp_req);
+EXPORT_SYMBOL(qcom_scm_set_warm_boot_addr);
 
 /**
- * qcom_scm_pas_supported() - Check if the peripheral authentication service is
- *                           available for the given peripherial
- * @peripheral:        peripheral id
+ * qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus
+ * @entry: Entry point function for the cpus
+ * @cpus: The cpumask of cpus that will use the entry point
  *
- * Returns true if PAS is supported for this peripheral, otherwise false.
+ * Set the cold boot address of the cpus. Any cpu outside the supported
+ * range would be removed from the cpu present mask.
  */
-bool qcom_scm_pas_supported(u32 peripheral)
+int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus)
 {
-       int ret;
+       int flags = 0;
+       int cpu;
+       int scm_cb_flags[] = {
+               QCOM_SCM_FLAG_COLDBOOT_CPU0,
+               QCOM_SCM_FLAG_COLDBOOT_CPU1,
+               QCOM_SCM_FLAG_COLDBOOT_CPU2,
+               QCOM_SCM_FLAG_COLDBOOT_CPU3,
+       };
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_BOOT,
+               .cmd = QCOM_SCM_BOOT_SET_ADDR,
+               .arginfo = QCOM_SCM_ARGS(2),
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+
+       if (!cpus || (cpus && cpumask_empty(cpus)))
+               return -EINVAL;
 
-       ret = __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_PIL,
-                                          QCOM_SCM_PAS_IS_SUPPORTED_CMD);
-       if (ret <= 0)
-               return false;
+       for_each_cpu(cpu, cpus) {
+               if (cpu < ARRAY_SIZE(scm_cb_flags))
+                       flags |= scm_cb_flags[cpu];
+               else
+                       set_cpu_present(cpu, false);
+       }
+
+       desc.args[0] = flags;
+       desc.args[1] = virt_to_phys(entry);
 
-       return __qcom_scm_pas_supported(__scm->dev, peripheral);
+       return qcom_scm_call_atomic(__scm ? __scm->dev : NULL, &desc, NULL);
 }
-EXPORT_SYMBOL(qcom_scm_pas_supported);
+EXPORT_SYMBOL(qcom_scm_set_cold_boot_addr);
 
 /**
- * qcom_scm_ocmem_lock_available() - is OCMEM lock/unlock interface available
+ * qcom_scm_cpu_power_down() - Power down the cpu
+ * @flags - Flags to flush cache
+ *
+ * This is an end point to power down cpu. If there was a pending interrupt,
+ * the control would return from this function, otherwise, the cpu jumps to the
+ * warm boot entry point set for this cpu upon reset.
  */
-bool qcom_scm_ocmem_lock_available(void)
+void qcom_scm_cpu_power_down(u32 flags)
 {
-       return __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_OCMEM_SVC,
-                                           QCOM_SCM_OCMEM_LOCK_CMD);
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_BOOT,
+               .cmd = QCOM_SCM_BOOT_TERMINATE_PC,
+               .args[0] = flags & QCOM_SCM_FLUSH_FLAG_MASK,
+               .arginfo = QCOM_SCM_ARGS(1),
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+
+       qcom_scm_call_atomic(__scm ? __scm->dev : NULL, &desc, NULL);
 }
-EXPORT_SYMBOL(qcom_scm_ocmem_lock_available);
+EXPORT_SYMBOL(qcom_scm_cpu_power_down);
 
-/**
- * qcom_scm_ocmem_lock() - call OCMEM lock interface to assign an OCMEM
- * region to the specified initiator
- *
- * @id:     tz initiator id
- * @offset: OCMEM offset
- * @size:   OCMEM size
- * @mode:   access mode (WIDE/NARROW)
- */
-int qcom_scm_ocmem_lock(enum qcom_scm_ocmem_client id, u32 offset, u32 size,
-                       u32 mode)
+int qcom_scm_set_remote_state(u32 state, u32 id)
 {
-       return __qcom_scm_ocmem_lock(__scm->dev, id, offset, size, mode);
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_BOOT,
+               .cmd = QCOM_SCM_BOOT_SET_REMOTE_STATE,
+               .arginfo = QCOM_SCM_ARGS(2),
+               .args[0] = state,
+               .args[1] = id,
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+       struct qcom_scm_res res;
+       int ret;
+
+       ret = qcom_scm_call(__scm->dev, &desc, &res);
+
+       return ret ? : res.result[0];
 }
-EXPORT_SYMBOL(qcom_scm_ocmem_lock);
+EXPORT_SYMBOL(qcom_scm_set_remote_state);
 
-/**
- * qcom_scm_ocmem_unlock() - call OCMEM unlock interface to release an OCMEM
- * region from the specified initiator
- *
- * @id:     tz initiator id
- * @offset: OCMEM offset
- * @size:   OCMEM size
- */
-int qcom_scm_ocmem_unlock(enum qcom_scm_ocmem_client id, u32 offset, u32 size)
+static int __qcom_scm_set_dload_mode(struct device *dev, bool enable)
 {
-       return __qcom_scm_ocmem_unlock(__scm->dev, id, offset, size);
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_BOOT,
+               .cmd = QCOM_SCM_BOOT_SET_DLOAD_MODE,
+               .arginfo = QCOM_SCM_ARGS(2),
+               .args[0] = QCOM_SCM_BOOT_SET_DLOAD_MODE,
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+
+       desc.args[1] = enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0;
+
+       return qcom_scm_call(__scm->dev, &desc, NULL);
+}
+
+static void qcom_scm_set_download_mode(bool enable)
+{
+       bool avail;
+       int ret = 0;
+
+       avail = __qcom_scm_is_call_available(__scm->dev,
+                                            QCOM_SCM_SVC_BOOT,
+                                            QCOM_SCM_BOOT_SET_DLOAD_MODE);
+       if (avail) {
+               ret = __qcom_scm_set_dload_mode(__scm->dev, enable);
+       } else if (__scm->dload_mode_addr) {
+               ret = qcom_scm_io_writel(__scm->dload_mode_addr,
+                               enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0);
+       } else {
+               dev_err(__scm->dev,
+                       "No available mechanism for setting download mode\n");
+       }
+
+       if (ret)
+               dev_err(__scm->dev, "failed to set download mode: %d\n", ret);
 }
-EXPORT_SYMBOL(qcom_scm_ocmem_unlock);
 
 /**
  * qcom_scm_pas_init_image() - Initialize peripheral authentication service
@@ -248,6 +434,14 @@ int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size)
        dma_addr_t mdata_phys;
        void *mdata_buf;
        int ret;
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_PIL,
+               .cmd = QCOM_SCM_PIL_PAS_INIT_IMAGE,
+               .arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_VAL, QCOM_SCM_RW),
+               .args[0] = peripheral,
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+       struct qcom_scm_res res;
 
        /*
         * During the scm call memory protection will be enabled for the meta
@@ -266,14 +460,16 @@ int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size)
        if (ret)
                goto free_metadata;
 
-       ret = __qcom_scm_pas_init_image(__scm->dev, peripheral, mdata_phys);
+       desc.args[1] = mdata_phys;
+
+       ret = qcom_scm_call(__scm->dev, &desc, &res);
 
        qcom_scm_clk_disable();
 
 free_metadata:
        dma_free_coherent(__scm->dev, size, mdata_buf, mdata_phys);
 
-       return ret;
+       return ret ? : res.result[0];
 }
 EXPORT_SYMBOL(qcom_scm_pas_init_image);
 
@@ -289,15 +485,25 @@ EXPORT_SYMBOL(qcom_scm_pas_init_image);
 int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, phys_addr_t size)
 {
        int ret;
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_PIL,
+               .cmd = QCOM_SCM_PIL_PAS_MEM_SETUP,
+               .arginfo = QCOM_SCM_ARGS(3),
+               .args[0] = peripheral,
+               .args[1] = addr,
+               .args[2] = size,
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+       struct qcom_scm_res res;
 
        ret = qcom_scm_clk_enable();
        if (ret)
                return ret;
 
-       ret = __qcom_scm_pas_mem_setup(__scm->dev, peripheral, addr, size);
+       ret = qcom_scm_call(__scm->dev, &desc, &res);
        qcom_scm_clk_disable();
 
-       return ret;
+       return ret ? : res.result[0];
 }
 EXPORT_SYMBOL(qcom_scm_pas_mem_setup);
 
@@ -311,15 +517,23 @@ EXPORT_SYMBOL(qcom_scm_pas_mem_setup);
 int qcom_scm_pas_auth_and_reset(u32 peripheral)
 {
        int ret;
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_PIL,
+               .cmd = QCOM_SCM_PIL_PAS_AUTH_AND_RESET,
+               .arginfo = QCOM_SCM_ARGS(1),
+               .args[0] = peripheral,
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+       struct qcom_scm_res res;
 
        ret = qcom_scm_clk_enable();
        if (ret)
                return ret;
 
-       ret = __qcom_scm_pas_auth_and_reset(__scm->dev, peripheral);
+       ret = qcom_scm_call(__scm->dev, &desc, &res);
        qcom_scm_clk_disable();
 
-       return ret;
+       return ret ? : res.result[0];
 }
 EXPORT_SYMBOL(qcom_scm_pas_auth_and_reset);
 
@@ -332,18 +546,75 @@ EXPORT_SYMBOL(qcom_scm_pas_auth_and_reset);
 int qcom_scm_pas_shutdown(u32 peripheral)
 {
        int ret;
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_PIL,
+               .cmd = QCOM_SCM_PIL_PAS_SHUTDOWN,
+               .arginfo = QCOM_SCM_ARGS(1),
+               .args[0] = peripheral,
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+       struct qcom_scm_res res;
 
        ret = qcom_scm_clk_enable();
        if (ret)
                return ret;
 
-       ret = __qcom_scm_pas_shutdown(__scm->dev, peripheral);
+       ret = qcom_scm_call(__scm->dev, &desc, &res);
+
        qcom_scm_clk_disable();
 
-       return ret;
+       return ret ? : res.result[0];
 }
 EXPORT_SYMBOL(qcom_scm_pas_shutdown);
 
+/**
+ * qcom_scm_pas_supported() - Check if the peripheral authentication service is
+ *                           available for the given peripherial
+ * @peripheral:        peripheral id
+ *
+ * Returns true if PAS is supported for this peripheral, otherwise false.
+ */
+bool qcom_scm_pas_supported(u32 peripheral)
+{
+       int ret;
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_PIL,
+               .cmd = QCOM_SCM_PIL_PAS_IS_SUPPORTED,
+               .arginfo = QCOM_SCM_ARGS(1),
+               .args[0] = peripheral,
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+       struct qcom_scm_res res;
+
+       ret = __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_PIL,
+                                          QCOM_SCM_PIL_PAS_IS_SUPPORTED);
+       if (ret <= 0)
+               return false;
+
+       ret = qcom_scm_call(__scm->dev, &desc, &res);
+
+       return ret ? false : !!res.result[0];
+}
+EXPORT_SYMBOL(qcom_scm_pas_supported);
+
+static int __qcom_scm_pas_mss_reset(struct device *dev, bool reset)
+{
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_PIL,
+               .cmd = QCOM_SCM_PIL_PAS_MSS_RESET,
+               .arginfo = QCOM_SCM_ARGS(2),
+               .args[0] = reset,
+               .args[1] = 0,
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+       struct qcom_scm_res res;
+       int ret;
+
+       ret = qcom_scm_call(__scm->dev, &desc, &res);
+
+       return ret ? : res.result[0];
+}
+
 static int qcom_scm_pas_reset_assert(struct reset_controller_dev *rcdev,
                                     unsigned long idx)
 {
@@ -367,6 +638,43 @@ static const struct reset_control_ops qcom_scm_pas_reset_ops = {
        .deassert = qcom_scm_pas_reset_deassert,
 };
 
+int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val)
+{
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_IO,
+               .cmd = QCOM_SCM_IO_READ,
+               .arginfo = QCOM_SCM_ARGS(1),
+               .args[0] = addr,
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+       struct qcom_scm_res res;
+       int ret;
+
+
+       ret = qcom_scm_call(__scm->dev, &desc, &res);
+       if (ret >= 0)
+               *val = res.result[0];
+
+       return ret < 0 ? ret : 0;
+}
+EXPORT_SYMBOL(qcom_scm_io_readl);
+
+int qcom_scm_io_writel(phys_addr_t addr, unsigned int val)
+{
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_IO,
+               .cmd = QCOM_SCM_IO_WRITE,
+               .arginfo = QCOM_SCM_ARGS(2),
+               .args[0] = addr,
+               .args[1] = val,
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+
+
+       return qcom_scm_call(__scm->dev, &desc, NULL);
+}
+EXPORT_SYMBOL(qcom_scm_io_writel);
+
 /**
  * qcom_scm_restore_sec_cfg_available() - Check if secure environment
  * supports restore security config interface.
@@ -376,108 +684,106 @@ static const struct reset_control_ops qcom_scm_pas_reset_ops = {
 bool qcom_scm_restore_sec_cfg_available(void)
 {
        return __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_MP,
-                                           QCOM_SCM_RESTORE_SEC_CFG);
+                                           QCOM_SCM_MP_RESTORE_SEC_CFG);
 }
 EXPORT_SYMBOL(qcom_scm_restore_sec_cfg_available);
 
 int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare)
 {
-       return __qcom_scm_restore_sec_cfg(__scm->dev, device_id, spare);
-}
-EXPORT_SYMBOL(qcom_scm_restore_sec_cfg);
-
-int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size)
-{
-       return __qcom_scm_iommu_secure_ptbl_size(__scm->dev, spare, size);
-}
-EXPORT_SYMBOL(qcom_scm_iommu_secure_ptbl_size);
-
-int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare)
-{
-       return __qcom_scm_iommu_secure_ptbl_init(__scm->dev, addr, size, spare);
-}
-EXPORT_SYMBOL(qcom_scm_iommu_secure_ptbl_init);
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_MP,
+               .cmd = QCOM_SCM_MP_RESTORE_SEC_CFG,
+               .arginfo = QCOM_SCM_ARGS(2),
+               .args[0] = device_id,
+               .args[1] = spare,
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+       struct qcom_scm_res res;
+       int ret;
 
-int qcom_scm_qsmmu500_wait_safe_toggle(bool en)
-{
-       return __qcom_scm_qsmmu500_wait_safe_toggle(__scm->dev, en);
-}
-EXPORT_SYMBOL(qcom_scm_qsmmu500_wait_safe_toggle);
+       ret = qcom_scm_call(__scm->dev, &desc, &res);
 
-int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val)
-{
-       return __qcom_scm_io_readl(__scm->dev, addr, val);
+       return ret ? : res.result[0];
 }
-EXPORT_SYMBOL(qcom_scm_io_readl);
+EXPORT_SYMBOL(qcom_scm_restore_sec_cfg);
 
-int qcom_scm_io_writel(phys_addr_t addr, unsigned int val)
+int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size)
 {
-       return __qcom_scm_io_writel(__scm->dev, addr, val);
-}
-EXPORT_SYMBOL(qcom_scm_io_writel);
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_MP,
+               .cmd = QCOM_SCM_MP_IOMMU_SECURE_PTBL_SIZE,
+               .arginfo = QCOM_SCM_ARGS(1),
+               .args[0] = spare,
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+       struct qcom_scm_res res;
+       int ret;
 
-static void qcom_scm_set_download_mode(bool enable)
-{
-       bool avail;
-       int ret = 0;
+       ret = qcom_scm_call(__scm->dev, &desc, &res);
 
-       avail = __qcom_scm_is_call_available(__scm->dev,
-                                            QCOM_SCM_SVC_BOOT,
-                                            QCOM_SCM_SET_DLOAD_MODE);
-       if (avail) {
-               ret = __qcom_scm_set_dload_mode(__scm->dev, enable);
-       } else if (__scm->dload_mode_addr) {
-               ret = __qcom_scm_io_writel(__scm->dev, __scm->dload_mode_addr,
-                                          enable ? QCOM_SCM_SET_DLOAD_MODE : 0);
-       } else {
-               dev_err(__scm->dev,
-                       "No available mechanism for setting download mode\n");
-       }
+       if (size)
+               *size = res.result[0];
 
-       if (ret)
-               dev_err(__scm->dev, "failed to set download mode: %d\n", ret);
+       return ret ? : res.result[1];
 }
+EXPORT_SYMBOL(qcom_scm_iommu_secure_ptbl_size);
 
-static int qcom_scm_find_dload_address(struct device *dev, u64 *addr)
+int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare)
 {
-       struct device_node *tcsr;
-       struct device_node *np = dev->of_node;
-       struct resource res;
-       u32 offset;
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_MP,
+               .cmd = QCOM_SCM_MP_IOMMU_SECURE_PTBL_INIT,
+               .arginfo = QCOM_SCM_ARGS(3, QCOM_SCM_RW, QCOM_SCM_VAL,
+                                        QCOM_SCM_VAL),
+               .args[0] = addr,
+               .args[1] = size,
+               .args[2] = spare,
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
        int ret;
 
-       tcsr = of_parse_phandle(np, "qcom,dload-mode", 0);
-       if (!tcsr)
-               return 0;
-
-       ret = of_address_to_resource(tcsr, 0, &res);
-       of_node_put(tcsr);
-       if (ret)
-               return ret;
-
-       ret = of_property_read_u32_index(np, "qcom,dload-mode", 1, &offset);
-       if (ret < 0)
-               return ret;
+       desc.args[0] = addr;
+       desc.args[1] = size;
+       desc.args[2] = spare;
+       desc.arginfo = QCOM_SCM_ARGS(3, QCOM_SCM_RW, QCOM_SCM_VAL,
+                                    QCOM_SCM_VAL);
 
-       *addr = res.start + offset;
+       ret = qcom_scm_call(__scm->dev, &desc, NULL);
 
-       return 0;
-}
+       /* the pg table has been initialized already, ignore the error */
+       if (ret == -EPERM)
+               ret = 0;
 
-/**
- * qcom_scm_is_available() - Checks if SCM is available
- */
-bool qcom_scm_is_available(void)
-{
-       return !!__scm;
+       return ret;
 }
-EXPORT_SYMBOL(qcom_scm_is_available);
+EXPORT_SYMBOL(qcom_scm_iommu_secure_ptbl_init);
 
-int qcom_scm_set_remote_state(u32 state, u32 id)
+static int __qcom_scm_assign_mem(struct device *dev, phys_addr_t mem_region,
+                                size_t mem_sz, phys_addr_t src, size_t src_sz,
+                                phys_addr_t dest, size_t dest_sz)
 {
-       return __qcom_scm_set_remote_state(__scm->dev, state, id);
+       int ret;
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_MP,
+               .cmd = QCOM_SCM_MP_ASSIGN,
+               .arginfo = QCOM_SCM_ARGS(7, QCOM_SCM_RO, QCOM_SCM_VAL,
+                                        QCOM_SCM_RO, QCOM_SCM_VAL, QCOM_SCM_RO,
+                                        QCOM_SCM_VAL, QCOM_SCM_VAL),
+               .args[0] = mem_region,
+               .args[1] = mem_sz,
+               .args[2] = src,
+               .args[3] = src_sz,
+               .args[4] = dest,
+               .args[5] = dest_sz,
+               .args[6] = 0,
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+       struct qcom_scm_res res;
+
+       ret = qcom_scm_call(dev, &desc, &res);
+
+       return ret ? : res.result[0];
 }
-EXPORT_SYMBOL(qcom_scm_set_remote_state);
 
 /**
  * qcom_scm_assign_mem() - Make a secure call to reassign memory ownership
@@ -561,6 +867,184 @@ int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz,
 }
 EXPORT_SYMBOL(qcom_scm_assign_mem);
 
+/**
+ * qcom_scm_ocmem_lock_available() - is OCMEM lock/unlock interface available
+ */
+bool qcom_scm_ocmem_lock_available(void)
+{
+       return __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_OCMEM,
+                                           QCOM_SCM_OCMEM_LOCK_CMD);
+}
+EXPORT_SYMBOL(qcom_scm_ocmem_lock_available);
+
+/**
+ * qcom_scm_ocmem_lock() - call OCMEM lock interface to assign an OCMEM
+ * region to the specified initiator
+ *
+ * @id:     tz initiator id
+ * @offset: OCMEM offset
+ * @size:   OCMEM size
+ * @mode:   access mode (WIDE/NARROW)
+ */
+int qcom_scm_ocmem_lock(enum qcom_scm_ocmem_client id, u32 offset, u32 size,
+                       u32 mode)
+{
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_OCMEM,
+               .cmd = QCOM_SCM_OCMEM_LOCK_CMD,
+               .args[0] = id,
+               .args[1] = offset,
+               .args[2] = size,
+               .args[3] = mode,
+               .arginfo = QCOM_SCM_ARGS(4),
+       };
+
+       return qcom_scm_call(__scm->dev, &desc, NULL);
+}
+EXPORT_SYMBOL(qcom_scm_ocmem_lock);
+
+/**
+ * qcom_scm_ocmem_unlock() - call OCMEM unlock interface to release an OCMEM
+ * region from the specified initiator
+ *
+ * @id:     tz initiator id
+ * @offset: OCMEM offset
+ * @size:   OCMEM size
+ */
+int qcom_scm_ocmem_unlock(enum qcom_scm_ocmem_client id, u32 offset, u32 size)
+{
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_OCMEM,
+               .cmd = QCOM_SCM_OCMEM_UNLOCK_CMD,
+               .args[0] = id,
+               .args[1] = offset,
+               .args[2] = size,
+               .arginfo = QCOM_SCM_ARGS(3),
+       };
+
+       return qcom_scm_call(__scm->dev, &desc, NULL);
+}
+EXPORT_SYMBOL(qcom_scm_ocmem_unlock);
+
+/**
+ * qcom_scm_hdcp_available() - Check if secure environment supports HDCP.
+ *
+ * Return true if HDCP is supported, false if not.
+ */
+bool qcom_scm_hdcp_available(void)
+{
+       int ret = qcom_scm_clk_enable();
+
+       if (ret)
+               return ret;
+
+       ret = __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_HDCP,
+                                               QCOM_SCM_HDCP_INVOKE);
+
+       qcom_scm_clk_disable();
+
+       return ret > 0 ? true : false;
+}
+EXPORT_SYMBOL(qcom_scm_hdcp_available);
+
+/**
+ * qcom_scm_hdcp_req() - Send HDCP request.
+ * @req: HDCP request array
+ * @req_cnt: HDCP request array count
+ * @resp: response buffer passed to SCM
+ *
+ * Write HDCP register(s) through SCM.
+ */
+int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp)
+{
+       int ret;
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_HDCP,
+               .cmd = QCOM_SCM_HDCP_INVOKE,
+               .arginfo = QCOM_SCM_ARGS(10),
+               .args = {
+                       req[0].addr,
+                       req[0].val,
+                       req[1].addr,
+                       req[1].val,
+                       req[2].addr,
+                       req[2].val,
+                       req[3].addr,
+                       req[3].val,
+                       req[4].addr,
+                       req[4].val
+               },
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+       struct qcom_scm_res res;
+
+       if (req_cnt > QCOM_SCM_HDCP_MAX_REQ_CNT)
+               return -ERANGE;
+
+       ret = qcom_scm_clk_enable();
+       if (ret)
+               return ret;
+
+       ret = qcom_scm_call(__scm->dev, &desc, &res);
+       *resp = res.result[0];
+
+       qcom_scm_clk_disable();
+
+       return ret;
+}
+EXPORT_SYMBOL(qcom_scm_hdcp_req);
+
+int qcom_scm_qsmmu500_wait_safe_toggle(bool en)
+{
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_SMMU_PROGRAM,
+               .cmd = QCOM_SCM_SMMU_CONFIG_ERRATA1,
+               .arginfo = QCOM_SCM_ARGS(2),
+               .args[0] = QCOM_SCM_SMMU_CONFIG_ERRATA1_CLIENT_ALL,
+               .args[1] = en,
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+
+
+       return qcom_scm_call_atomic(__scm->dev, &desc, NULL);
+}
+EXPORT_SYMBOL(qcom_scm_qsmmu500_wait_safe_toggle);
+
+static int qcom_scm_find_dload_address(struct device *dev, u64 *addr)
+{
+       struct device_node *tcsr;
+       struct device_node *np = dev->of_node;
+       struct resource res;
+       u32 offset;
+       int ret;
+
+       tcsr = of_parse_phandle(np, "qcom,dload-mode", 0);
+       if (!tcsr)
+               return 0;
+
+       ret = of_address_to_resource(tcsr, 0, &res);
+       of_node_put(tcsr);
+       if (ret)
+               return ret;
+
+       ret = of_property_read_u32_index(np, "qcom,dload-mode", 1, &offset);
+       if (ret < 0)
+               return ret;
+
+       *addr = res.start + offset;
+
+       return 0;
+}
+
+/**
+ * qcom_scm_is_available() - Checks if SCM is available
+ */
+bool qcom_scm_is_available(void)
+{
+       return !!__scm;
+}
+EXPORT_SYMBOL(qcom_scm_is_available);
+
 static int qcom_scm_probe(struct platform_device *pdev)
 {
        struct qcom_scm *scm;
@@ -631,7 +1115,7 @@ static int qcom_scm_probe(struct platform_device *pdev)
        __scm = scm;
        __scm->dev = &pdev->dev;
 
-       __qcom_scm_init();
+       __query_convention();
 
        /*
         * If requested enable "download mode", from this point on warmboot
index 81dcf5f1138e781b80156d145bf4cd6e94fe0159..d9ed670da222c8f9b910bb8ed43e7d0cbfadeacf 100644 (file)
 /* SPDX-License-Identifier: GPL-2.0-only */
-/* Copyright (c) 2010-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2015,2019 The Linux Foundation. All rights reserved.
  */
 #ifndef __QCOM_SCM_INT_H
 #define __QCOM_SCM_INT_H
 
-#define QCOM_SCM_SVC_BOOT              0x1
-#define QCOM_SCM_BOOT_ADDR             0x1
-#define QCOM_SCM_SET_DLOAD_MODE                0x10
-#define QCOM_SCM_BOOT_ADDR_MC          0x11
-#define QCOM_SCM_SET_REMOTE_STATE      0xa
-extern int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id);
-extern int __qcom_scm_set_dload_mode(struct device *dev, bool enable);
-
-#define QCOM_SCM_FLAG_HLOS             0x01
-#define QCOM_SCM_FLAG_COLDBOOT_MC      0x02
-#define QCOM_SCM_FLAG_WARMBOOT_MC      0x04
-extern int __qcom_scm_set_warm_boot_addr(struct device *dev, void *entry,
-               const cpumask_t *cpus);
-extern int __qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus);
-
-#define QCOM_SCM_CMD_TERMINATE_PC      0x2
+enum qcom_scm_convention {
+       SMC_CONVENTION_UNKNOWN,
+       SMC_CONVENTION_LEGACY,
+       SMC_CONVENTION_ARM_32,
+       SMC_CONVENTION_ARM_64,
+};
+
+extern enum qcom_scm_convention qcom_scm_convention;
+
+#define MAX_QCOM_SCM_ARGS 10
+#define MAX_QCOM_SCM_RETS 3
+
+enum qcom_scm_arg_types {
+       QCOM_SCM_VAL,
+       QCOM_SCM_RO,
+       QCOM_SCM_RW,
+       QCOM_SCM_BUFVAL,
+};
+
+#define QCOM_SCM_ARGS_IMPL(num, a, b, c, d, e, f, g, h, i, j, ...) (\
+                          (((a) & 0x3) << 4) | \
+                          (((b) & 0x3) << 6) | \
+                          (((c) & 0x3) << 8) | \
+                          (((d) & 0x3) << 10) | \
+                          (((e) & 0x3) << 12) | \
+                          (((f) & 0x3) << 14) | \
+                          (((g) & 0x3) << 16) | \
+                          (((h) & 0x3) << 18) | \
+                          (((i) & 0x3) << 20) | \
+                          (((j) & 0x3) << 22) | \
+                          ((num) & 0xf))
+
+#define QCOM_SCM_ARGS(...) QCOM_SCM_ARGS_IMPL(__VA_ARGS__, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
+
+
+/**
+ * struct qcom_scm_desc
+ * @arginfo:   Metadata describing the arguments in args[]
+ * @args:      The array of arguments for the secure syscall
+ */
+struct qcom_scm_desc {
+       u32 svc;
+       u32 cmd;
+       u32 arginfo;
+       u64 args[MAX_QCOM_SCM_ARGS];
+       u32 owner;
+};
+
+/**
+ * struct qcom_scm_res
+ * @result:    The values returned by the secure syscall
+ */
+struct qcom_scm_res {
+       u64 result[MAX_QCOM_SCM_RETS];
+};
+
+#define SCM_SMC_FNID(s, c)     ((((s) & 0xFF) << 8) | ((c) & 0xFF))
+extern int scm_smc_call(struct device *dev, const struct qcom_scm_desc *desc,
+                       struct qcom_scm_res *res, bool atomic);
+
+#define SCM_LEGACY_FNID(s, c)  (((s) << 10) | ((c) & 0x3ff))
+extern int scm_legacy_call_atomic(struct device *dev,
+                                 const struct qcom_scm_desc *desc,
+                                 struct qcom_scm_res *res);
+extern int scm_legacy_call(struct device *dev, const struct qcom_scm_desc *desc,
+                          struct qcom_scm_res *res);
+
+#define QCOM_SCM_SVC_BOOT              0x01
+#define QCOM_SCM_BOOT_SET_ADDR         0x01
+#define QCOM_SCM_BOOT_TERMINATE_PC     0x02
+#define QCOM_SCM_BOOT_SET_DLOAD_MODE   0x10
+#define QCOM_SCM_BOOT_SET_REMOTE_STATE 0x0a
 #define QCOM_SCM_FLUSH_FLAG_MASK       0x3
-#define QCOM_SCM_CMD_CORE_HOTPLUGGED   0x10
-extern void __qcom_scm_cpu_power_down(u32 flags);
 
-#define QCOM_SCM_SVC_IO                        0x5
-#define QCOM_SCM_IO_READ               0x1
-#define QCOM_SCM_IO_WRITE              0x2
-extern int __qcom_scm_io_readl(struct device *dev, phys_addr_t addr, unsigned int *val);
-extern int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val);
+#define QCOM_SCM_SVC_PIL               0x02
+#define QCOM_SCM_PIL_PAS_INIT_IMAGE    0x01
+#define QCOM_SCM_PIL_PAS_MEM_SETUP     0x02
+#define QCOM_SCM_PIL_PAS_AUTH_AND_RESET        0x05
+#define QCOM_SCM_PIL_PAS_SHUTDOWN      0x06
+#define QCOM_SCM_PIL_PAS_IS_SUPPORTED  0x07
+#define QCOM_SCM_PIL_PAS_MSS_RESET     0x0a
+
+#define QCOM_SCM_SVC_IO                        0x05
+#define QCOM_SCM_IO_READ               0x01
+#define QCOM_SCM_IO_WRITE              0x02
+
+#define QCOM_SCM_SVC_INFO              0x06
+#define QCOM_SCM_INFO_IS_CALL_AVAIL    0x01
 
-#define QCOM_SCM_SVC_INFO              0x6
-#define QCOM_IS_CALL_AVAIL_CMD         0x1
-extern int __qcom_scm_is_call_available(struct device *dev, u32 svc_id,
-               u32 cmd_id);
+#define QCOM_SCM_SVC_MP                                0x0c
+#define QCOM_SCM_MP_RESTORE_SEC_CFG            0x02
+#define QCOM_SCM_MP_IOMMU_SECURE_PTBL_SIZE     0x03
+#define QCOM_SCM_MP_IOMMU_SECURE_PTBL_INIT     0x04
+#define QCOM_SCM_MP_ASSIGN                     0x16
+
+#define QCOM_SCM_SVC_OCMEM             0x0f
+#define QCOM_SCM_OCMEM_LOCK_CMD                0x01
+#define QCOM_SCM_OCMEM_UNLOCK_CMD      0x02
 
 #define QCOM_SCM_SVC_HDCP              0x11
-#define QCOM_SCM_CMD_HDCP              0x01
-extern int __qcom_scm_hdcp_req(struct device *dev,
-               struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp);
+#define QCOM_SCM_HDCP_INVOKE           0x01
 
-extern void __qcom_scm_init(void);
+#define QCOM_SCM_SVC_SMMU_PROGRAM              0x15
+#define QCOM_SCM_SMMU_CONFIG_ERRATA1           0x03
+#define QCOM_SCM_SMMU_CONFIG_ERRATA1_CLIENT_ALL        0x02
 
-#define QCOM_SCM_OCMEM_SVC                     0xf
-#define QCOM_SCM_OCMEM_LOCK_CMD                0x1
-#define QCOM_SCM_OCMEM_UNLOCK_CMD              0x2
-
-extern int __qcom_scm_ocmem_lock(struct device *dev, u32 id, u32 offset,
-                                u32 size, u32 mode);
-extern int __qcom_scm_ocmem_unlock(struct device *dev, u32 id, u32 offset,
-                                  u32 size);
-
-#define QCOM_SCM_SVC_PIL               0x2
-#define QCOM_SCM_PAS_INIT_IMAGE_CMD    0x1
-#define QCOM_SCM_PAS_MEM_SETUP_CMD     0x2
-#define QCOM_SCM_PAS_AUTH_AND_RESET_CMD        0x5
-#define QCOM_SCM_PAS_SHUTDOWN_CMD      0x6
-#define QCOM_SCM_PAS_IS_SUPPORTED_CMD  0x7
-#define QCOM_SCM_PAS_MSS_RESET         0xa
-extern bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral);
-extern int  __qcom_scm_pas_init_image(struct device *dev, u32 peripheral,
-               dma_addr_t metadata_phys);
-extern int  __qcom_scm_pas_mem_setup(struct device *dev, u32 peripheral,
-               phys_addr_t addr, phys_addr_t size);
-extern int  __qcom_scm_pas_auth_and_reset(struct device *dev, u32 peripheral);
-extern int  __qcom_scm_pas_shutdown(struct device *dev, u32 peripheral);
-extern int  __qcom_scm_pas_mss_reset(struct device *dev, bool reset);
+extern void __qcom_scm_init(void);
 
 /* common error codes */
 #define QCOM_SCM_V2_EBUSY      -12
@@ -94,25 +139,4 @@ static inline int qcom_scm_remap_error(int err)
        return -EINVAL;
 }
 
-#define QCOM_SCM_SVC_MP                        0xc
-#define QCOM_SCM_RESTORE_SEC_CFG       2
-extern int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id,
-                                     u32 spare);
-#define QCOM_SCM_IOMMU_SECURE_PTBL_SIZE        3
-#define QCOM_SCM_IOMMU_SECURE_PTBL_INIT        4
-#define QCOM_SCM_SVC_SMMU_PROGRAM      0x15
-#define QCOM_SCM_CONFIG_ERRATA1                0x3
-#define QCOM_SCM_CONFIG_ERRATA1_CLIENT_ALL     0x2
-extern int __qcom_scm_iommu_secure_ptbl_size(struct device *dev, u32 spare,
-                                            size_t *size);
-extern int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr,
-                                            u32 size, u32 spare);
-extern int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev,
-                                               bool enable);
-#define QCOM_MEM_PROT_ASSIGN_ID        0x16
-extern int  __qcom_scm_assign_mem(struct device *dev,
-                                 phys_addr_t mem_region, size_t mem_sz,
-                                 phys_addr_t src, size_t src_sz,
-                                 phys_addr_t dest, size_t dest_sz);
-
 #endif
index 72be58960e540f4b178ccddd826abda69e172249..e27f68437b5680f48f1beee1355443688d611256 100644 (file)
@@ -197,7 +197,7 @@ static int mox_get_board_info(struct mox_rwtm *rwtm)
                rwtm->serial_number = reply->status[1];
                rwtm->serial_number <<= 32;
                rwtm->serial_number |= reply->status[0];
-                       rwtm->board_version = reply->status[2];
+               rwtm->board_version = reply->status[2];
                rwtm->ram_size = reply->status[3];
                reply_to_mac_addr(rwtm->mac_address1, reply->status[4],
                                  reply->status[5]);
index 74d9f13d72c45f4c1c9052d044b70d0c341ba53a..ecc339d846deba4f802ee741ca7e729c4fb748f7 100644 (file)
@@ -26,6 +26,9 @@
 
 static const struct zynqmp_eemi_ops *eemi_ops_tbl;
 
+static bool feature_check_enabled;
+static u32 zynqmp_pm_features[PM_API_MAX];
+
 static const struct mfd_cell firmware_devs[] = {
        {
                .name = "zynqmp_power_controller",
@@ -44,6 +47,8 @@ static int zynqmp_pm_ret_code(u32 ret_status)
        case XST_PM_SUCCESS:
        case XST_PM_DOUBLE_REQ:
                return 0;
+       case XST_PM_NO_FEATURE:
+               return -ENOTSUPP;
        case XST_PM_NO_ACCESS:
                return -EACCES;
        case XST_PM_ABORT_SUSPEND:
@@ -128,6 +133,39 @@ static noinline int do_fw_call_hvc(u64 arg0, u64 arg1, u64 arg2,
        return zynqmp_pm_ret_code((enum pm_ret_status)res.a0);
 }
 
+/**
+ * zynqmp_pm_feature() - Check weather given feature is supported or not
+ * @api_id:            API ID to check
+ *
+ * Return: Returns status, either success or error+reason
+ */
+static int zynqmp_pm_feature(u32 api_id)
+{
+       int ret;
+       u32 ret_payload[PAYLOAD_ARG_CNT];
+       u64 smc_arg[2];
+
+       if (!feature_check_enabled)
+               return 0;
+
+       /* Return value if feature is already checked */
+       if (zynqmp_pm_features[api_id] != PM_FEATURE_UNCHECKED)
+               return zynqmp_pm_features[api_id];
+
+       smc_arg[0] = PM_SIP_SVC | PM_FEATURE_CHECK;
+       smc_arg[1] = api_id;
+
+       ret = do_fw_call(smc_arg[0], smc_arg[1], 0, ret_payload);
+       if (ret) {
+               zynqmp_pm_features[api_id] = PM_FEATURE_INVALID;
+               return PM_FEATURE_INVALID;
+       }
+
+       zynqmp_pm_features[api_id] = ret_payload[1];
+
+       return zynqmp_pm_features[api_id];
+}
+
 /**
  * zynqmp_pm_invoke_fn() - Invoke the system-level platform management layer
  *                        caller function depending on the configuration
@@ -162,6 +200,9 @@ int zynqmp_pm_invoke_fn(u32 pm_api_id, u32 arg0, u32 arg1,
         */
        u64 smc_arg[4];
 
+       if (zynqmp_pm_feature(pm_api_id) == PM_FEATURE_INVALID)
+               return -ENOTSUPP;
+
        smc_arg[0] = PM_SIP_SVC | pm_api_id;
        smc_arg[1] = ((u64)arg1 << 32) | arg0;
        smc_arg[2] = ((u64)arg3 << 32) | arg2;
@@ -717,6 +758,8 @@ static int zynqmp_firmware_probe(struct platform_device *pdev)
                np = of_find_compatible_node(NULL, NULL, "xlnx,versal");
                if (!np)
                        return 0;
+
+               feature_check_enabled = true;
        }
        of_node_put(np);
 
index 8a7732c0bef3e4fdbd1a2fa4b56d5998f38eae2b..286d3cfda7de868306099315ea91c975d885c718 100644 (file)
@@ -259,7 +259,7 @@ static int scmi_hwmon_probe(struct scmi_device *sdev)
 }
 
 static const struct scmi_device_id scmi_id_table[] = {
-       { SCMI_PROTOCOL_SENSOR },
+       { SCMI_PROTOCOL_SENSOR, "hwmon" },
        { },
 };
 MODULE_DEVICE_TABLE(scmi, scmi_id_table);
index 19f086716dc55426eceacda46031eaae1da4b376..02b7b28e696947a6cc3a03e60f0f840b6d865a0d 100644 (file)
@@ -143,7 +143,6 @@ static const struct mbox_chan_ops a37xx_mbox_ops = {
 static int armada_37xx_mbox_probe(struct platform_device *pdev)
 {
        struct a37xx_mbox *mbox;
-       struct resource *regs;
        struct mbox_chan *chans;
        int ret;
 
@@ -156,9 +155,7 @@ static int armada_37xx_mbox_probe(struct platform_device *pdev)
        if (!chans)
                return -ENOMEM;
 
-       regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
-       mbox->base = devm_ioremap_resource(&pdev->dev, regs);
+       mbox->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(mbox->base)) {
                dev_err(&pdev->dev, "ioremap failed\n");
                return PTR_ERR(mbox->base);
index 095f8a3b2cfcca0033ec4078f9b294e95daf3db4..886aea5872762e305f20ebd6fa12acf5f4755a10 100644 (file)
@@ -267,7 +267,6 @@ static int mvebu_devbus_probe(struct platform_device *pdev)
        struct devbus_read_params r;
        struct devbus_write_params w;
        struct devbus *devbus;
-       struct resource *res;
        struct clk *clk;
        unsigned long rate;
        int err;
@@ -277,8 +276,7 @@ static int mvebu_devbus_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        devbus->dev = dev;
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       devbus->base = devm_ioremap_resource(&pdev->dev, res);
+       devbus->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(devbus->base))
                return PTR_ERR(devbus->base);
 
index e9c3ce92350c07e6754c56420a34a0479aabec5b..20a8406ce78616dcc76aa7df2a7d475b232396e9 100644 (file)
@@ -8,7 +8,7 @@ config SAMSUNG_MC
 if SAMSUNG_MC
 
 config EXYNOS5422_DMC
-       tristate "EXYNOS5422 Dynamic Memory Controller driver"
+       tristate "Exynos5422 Dynamic Memory Controller driver"
        depends on ARCH_EXYNOS || (COMPILE_TEST && HAS_IOMEM)
        select DDR
        depends on DEVFREQ_GOV_SIMPLE_ONDEMAND
index c27c6105c66d8a44f6c1712ca176d985abc155fe..6510d7bab2178b8e97981cf99c1eb3752d9e08aa 100644 (file)
@@ -3,7 +3,7 @@
 // Copyright (c) 2015 Samsung Electronics Co., Ltd.
 //           http://www.samsung.com/
 //
-// EXYNOS - SROM Controller support
+// Exynos - SROM Controller support
 // Author: Pankaj Dubey <pankaj.dubey@samsung.com>
 
 #include <linux/io.h>
index 47dbf6d1789f069a4dc01a3bce1a53e67d1b1bb6..81a1b1d016836bf5b93bc3be3c4faf3810423565 100644 (file)
@@ -1374,7 +1374,6 @@ static int exynos5_dmc_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct device_node *np = dev->of_node;
        struct exynos5_dmc *dmc;
-       struct resource *res;
        int irq[2];
 
        dmc = devm_kzalloc(dev, sizeof(*dmc), GFP_KERNEL);
@@ -1386,13 +1385,11 @@ static int exynos5_dmc_probe(struct platform_device *pdev)
        dmc->dev = dev;
        platform_set_drvdata(pdev, dmc);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       dmc->base_drexi0 = devm_ioremap_resource(dev, res);
+       dmc->base_drexi0 = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(dmc->base_drexi0))
                return PTR_ERR(dmc->base_drexi0);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-       dmc->base_drexi1 = devm_ioremap_resource(dev, res);
+       dmc->base_drexi1 = devm_platform_ioremap_resource(pdev, 1);
        if (IS_ERR(dmc->base_drexi1))
                return PTR_ERR(dmc->base_drexi1);
 
index 3d23c426110425a05d10233c8e031caaf0e9079b..529d10bc5650657ab1c65e520ec38429a1820472 100644 (file)
@@ -13,4 +13,5 @@ obj-$(CONFIG_TEGRA_MC) += tegra-mc.o
 obj-$(CONFIG_TEGRA20_EMC)  += tegra20-emc.o
 obj-$(CONFIG_TEGRA30_EMC)  += tegra30-emc.o
 obj-$(CONFIG_TEGRA124_EMC) += tegra124-emc.o
-obj-$(CONFIG_ARCH_TEGRA_186_SOC) += tegra186.o
+obj-$(CONFIG_ARCH_TEGRA_186_SOC) += tegra186.o tegra186-emc.o
+obj-$(CONFIG_ARCH_TEGRA_194_SOC) += tegra186.o tegra186-emc.o
index 464f0ceaee6381922fd490426bf9e461541adaec..21f05240682b840ef6319b64f17e0c65e05e792d 100644 (file)
@@ -467,12 +467,20 @@ struct tegra_emc {
 
        void __iomem *regs;
 
+       struct clk *clk;
+
        enum emc_dram_type dram_type;
        unsigned int dram_num;
 
        struct emc_timing last_timing;
        struct emc_timing *timings;
        unsigned int num_timings;
+
+       struct {
+               struct dentry *root;
+               unsigned long min_rate;
+               unsigned long max_rate;
+       } debugfs;
 };
 
 /* Timing change sequence functions */
@@ -998,38 +1006,51 @@ tegra_emc_find_node_by_ram_code(struct device_node *node, u32 ram_code)
        return NULL;
 }
 
-/* Debugfs entry */
+/*
+ * debugfs interface
+ *
+ * The memory controller driver exposes some files in debugfs that can be used
+ * to control the EMC frequency. The top-level directory can be found here:
+ *
+ *   /sys/kernel/debug/emc
+ *
+ * It contains the following files:
+ *
+ *   - available_rates: This file contains a list of valid, space-separated
+ *     EMC frequencies.
+ *
+ *   - min_rate: Writing a value to this file sets the given frequency as the
+ *       floor of the permitted range. If this is higher than the currently
+ *       configured EMC frequency, this will cause the frequency to be
+ *       increased so that it stays within the valid range.
+ *
+ *   - max_rate: Similarily to the min_rate file, writing a value to this file
+ *       sets the given frequency as the ceiling of the permitted range. If
+ *       the value is lower than the currently configured EMC frequency, this
+ *       will cause the frequency to be decreased so that it stays within the
+ *       valid range.
+ */
 
-static int emc_debug_rate_get(void *data, u64 *rate)
+static bool tegra_emc_validate_rate(struct tegra_emc *emc, unsigned long rate)
 {
-       struct clk *c = data;
-
-       *rate = clk_get_rate(c);
-
-       return 0;
-}
+       unsigned int i;
 
-static int emc_debug_rate_set(void *data, u64 rate)
-{
-       struct clk *c = data;
+       for (i = 0; i < emc->num_timings; i++)
+               if (rate == emc->timings[i].rate)
+                       return true;
 
-       return clk_set_rate(c, rate);
+       return false;
 }
 
-DEFINE_SIMPLE_ATTRIBUTE(emc_debug_rate_fops, emc_debug_rate_get,
-                       emc_debug_rate_set, "%lld\n");
-
-static int emc_debug_supported_rates_show(struct seq_file *s, void *data)
+static int tegra_emc_debug_available_rates_show(struct seq_file *s,
+                                               void *data)
 {
        struct tegra_emc *emc = s->private;
        const char *prefix = "";
        unsigned int i;
 
        for (i = 0; i < emc->num_timings; i++) {
-               struct emc_timing *timing = &emc->timings[i];
-
-               seq_printf(s, "%s%lu", prefix, timing->rate);
-
+               seq_printf(s, "%s%lu", prefix, emc->timings[i].rate);
                prefix = " ";
        }
 
@@ -1038,46 +1059,126 @@ static int emc_debug_supported_rates_show(struct seq_file *s, void *data)
        return 0;
 }
 
-static int emc_debug_supported_rates_open(struct inode *inode,
-                                         struct file *file)
+static int tegra_emc_debug_available_rates_open(struct inode *inode,
+                                               struct file *file)
 {
-       return single_open(file, emc_debug_supported_rates_show,
+       return single_open(file, tegra_emc_debug_available_rates_show,
                           inode->i_private);
 }
 
-static const struct file_operations emc_debug_supported_rates_fops = {
-       .open = emc_debug_supported_rates_open,
+static const struct file_operations tegra_emc_debug_available_rates_fops = {
+       .open = tegra_emc_debug_available_rates_open,
        .read = seq_read,
        .llseek = seq_lseek,
        .release = single_release,
 };
 
+static int tegra_emc_debug_min_rate_get(void *data, u64 *rate)
+{
+       struct tegra_emc *emc = data;
+
+       *rate = emc->debugfs.min_rate;
+
+       return 0;
+}
+
+static int tegra_emc_debug_min_rate_set(void *data, u64 rate)
+{
+       struct tegra_emc *emc = data;
+       int err;
+
+       if (!tegra_emc_validate_rate(emc, rate))
+               return -EINVAL;
+
+       err = clk_set_min_rate(emc->clk, rate);
+       if (err < 0)
+               return err;
+
+       emc->debugfs.min_rate = rate;
+
+       return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(tegra_emc_debug_min_rate_fops,
+                       tegra_emc_debug_min_rate_get,
+                       tegra_emc_debug_min_rate_set, "%llu\n");
+
+static int tegra_emc_debug_max_rate_get(void *data, u64 *rate)
+{
+       struct tegra_emc *emc = data;
+
+       *rate = emc->debugfs.max_rate;
+
+       return 0;
+}
+
+static int tegra_emc_debug_max_rate_set(void *data, u64 rate)
+{
+       struct tegra_emc *emc = data;
+       int err;
+
+       if (!tegra_emc_validate_rate(emc, rate))
+               return -EINVAL;
+
+       err = clk_set_max_rate(emc->clk, rate);
+       if (err < 0)
+               return err;
+
+       emc->debugfs.max_rate = rate;
+
+       return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(tegra_emc_debug_max_rate_fops,
+                       tegra_emc_debug_max_rate_get,
+                       tegra_emc_debug_max_rate_set, "%llu\n");
+
 static void emc_debugfs_init(struct device *dev, struct tegra_emc *emc)
 {
-       struct dentry *root, *file;
-       struct clk *clk;
+       unsigned int i;
+       int err;
 
-       root = debugfs_create_dir("emc", NULL);
-       if (!root) {
-               dev_err(dev, "failed to create debugfs directory\n");
-               return;
+       emc->clk = devm_clk_get(dev, "emc");
+       if (IS_ERR(emc->clk)) {
+               if (PTR_ERR(emc->clk) != -ENODEV) {
+                       dev_err(dev, "failed to get EMC clock: %ld\n",
+                               PTR_ERR(emc->clk));
+                       return;
+               }
        }
 
-       clk = clk_get_sys("tegra-clk-debug", "emc");
-       if (IS_ERR(clk)) {
-               dev_err(dev, "failed to get debug clock: %ld\n", PTR_ERR(clk));
+       emc->debugfs.min_rate = ULONG_MAX;
+       emc->debugfs.max_rate = 0;
+
+       for (i = 0; i < emc->num_timings; i++) {
+               if (emc->timings[i].rate < emc->debugfs.min_rate)
+                       emc->debugfs.min_rate = emc->timings[i].rate;
+
+               if (emc->timings[i].rate > emc->debugfs.max_rate)
+                       emc->debugfs.max_rate = emc->timings[i].rate;
+       }
+
+       err = clk_set_rate_range(emc->clk, emc->debugfs.min_rate,
+                                emc->debugfs.max_rate);
+       if (err < 0) {
+               dev_err(dev, "failed to set rate range [%lu-%lu] for %pC\n",
+                       emc->debugfs.min_rate, emc->debugfs.max_rate,
+                       emc->clk);
                return;
        }
 
-       file = debugfs_create_file("rate", S_IRUGO | S_IWUSR, root, clk,
-                                  &emc_debug_rate_fops);
-       if (!file)
-               dev_err(dev, "failed to create debugfs entry\n");
+       emc->debugfs.root = debugfs_create_dir("emc", NULL);
+       if (!emc->debugfs.root) {
+               dev_err(dev, "failed to create debugfs directory\n");
+               return;
+       }
 
-       file = debugfs_create_file("supported_rates", S_IRUGO, root, emc,
-                                  &emc_debug_supported_rates_fops);
-       if (!file)
-               dev_err(dev, "failed to create debugfs entry\n");
+       debugfs_create_file("available_rates", S_IRUGO, emc->debugfs.root, emc,
+                           &tegra_emc_debug_available_rates_fops);
+       debugfs_create_file("min_rate", S_IRUGO | S_IWUSR, emc->debugfs.root,
+                           emc, &tegra_emc_debug_min_rate_fops);
+       debugfs_create_file("max_rate", S_IRUGO | S_IWUSR, emc->debugfs.root,
+                           emc, &tegra_emc_debug_max_rate_fops);
 }
 
 static int tegra_emc_probe(struct platform_device *pdev)
diff --git a/drivers/memory/tegra/tegra186-emc.c b/drivers/memory/tegra/tegra186-emc.c
new file mode 100644 (file)
index 0000000..97f26bc
--- /dev/null
@@ -0,0 +1,293 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2019 NVIDIA CORPORATION.  All rights reserved.
+ */
+
+#include <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+
+#include <soc/tegra/bpmp.h>
+
+struct tegra186_emc_dvfs {
+       unsigned long latency;
+       unsigned long rate;
+};
+
+struct tegra186_emc {
+       struct tegra_bpmp *bpmp;
+       struct device *dev;
+       struct clk *clk;
+
+       struct tegra186_emc_dvfs *dvfs;
+       unsigned int num_dvfs;
+
+       struct {
+               struct dentry *root;
+               unsigned long min_rate;
+               unsigned long max_rate;
+       } debugfs;
+};
+
+/*
+ * debugfs interface
+ *
+ * The memory controller driver exposes some files in debugfs that can be used
+ * to control the EMC frequency. The top-level directory can be found here:
+ *
+ *   /sys/kernel/debug/emc
+ *
+ * It contains the following files:
+ *
+ *   - available_rates: This file contains a list of valid, space-separated
+ *     EMC frequencies.
+ *
+ *   - min_rate: Writing a value to this file sets the given frequency as the
+ *       floor of the permitted range. If this is higher than the currently
+ *       configured EMC frequency, this will cause the frequency to be
+ *       increased so that it stays within the valid range.
+ *
+ *   - max_rate: Similarily to the min_rate file, writing a value to this file
+ *       sets the given frequency as the ceiling of the permitted range. If
+ *       the value is lower than the currently configured EMC frequency, this
+ *       will cause the frequency to be decreased so that it stays within the
+ *       valid range.
+ */
+
+static bool tegra186_emc_validate_rate(struct tegra186_emc *emc,
+                                      unsigned long rate)
+{
+       unsigned int i;
+
+       for (i = 0; i < emc->num_dvfs; i++)
+               if (rate == emc->dvfs[i].rate)
+                       return true;
+
+       return false;
+}
+
+static int tegra186_emc_debug_available_rates_show(struct seq_file *s,
+                                                  void *data)
+{
+       struct tegra186_emc *emc = s->private;
+       const char *prefix = "";
+       unsigned int i;
+
+       for (i = 0; i < emc->num_dvfs; i++) {
+               seq_printf(s, "%s%lu", prefix, emc->dvfs[i].rate);
+               prefix = " ";
+       }
+
+       seq_puts(s, "\n");
+
+       return 0;
+}
+
+static int tegra186_emc_debug_available_rates_open(struct inode *inode,
+                                                  struct file *file)
+{
+       return single_open(file, tegra186_emc_debug_available_rates_show,
+                          inode->i_private);
+}
+
+static const struct file_operations tegra186_emc_debug_available_rates_fops = {
+       .open = tegra186_emc_debug_available_rates_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+
+static int tegra186_emc_debug_min_rate_get(void *data, u64 *rate)
+{
+       struct tegra186_emc *emc = data;
+
+       *rate = emc->debugfs.min_rate;
+
+       return 0;
+}
+
+static int tegra186_emc_debug_min_rate_set(void *data, u64 rate)
+{
+       struct tegra186_emc *emc = data;
+       int err;
+
+       if (!tegra186_emc_validate_rate(emc, rate))
+               return -EINVAL;
+
+       err = clk_set_min_rate(emc->clk, rate);
+       if (err < 0)
+               return err;
+
+       emc->debugfs.min_rate = rate;
+
+       return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(tegra186_emc_debug_min_rate_fops,
+                       tegra186_emc_debug_min_rate_get,
+                       tegra186_emc_debug_min_rate_set, "%llu\n");
+
+static int tegra186_emc_debug_max_rate_get(void *data, u64 *rate)
+{
+       struct tegra186_emc *emc = data;
+
+       *rate = emc->debugfs.max_rate;
+
+       return 0;
+}
+
+static int tegra186_emc_debug_max_rate_set(void *data, u64 rate)
+{
+       struct tegra186_emc *emc = data;
+       int err;
+
+       if (!tegra186_emc_validate_rate(emc, rate))
+               return -EINVAL;
+
+       err = clk_set_max_rate(emc->clk, rate);
+       if (err < 0)
+               return err;
+
+       emc->debugfs.max_rate = rate;
+
+       return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(tegra186_emc_debug_max_rate_fops,
+                       tegra186_emc_debug_max_rate_get,
+                       tegra186_emc_debug_max_rate_set, "%llu\n");
+
+static int tegra186_emc_probe(struct platform_device *pdev)
+{
+       struct mrq_emc_dvfs_latency_response response;
+       struct tegra_bpmp_message msg;
+       struct tegra186_emc *emc;
+       unsigned int i;
+       int err;
+
+       emc = devm_kzalloc(&pdev->dev, sizeof(*emc), GFP_KERNEL);
+       if (!emc)
+               return -ENOMEM;
+
+       emc->bpmp = tegra_bpmp_get(&pdev->dev);
+       if (IS_ERR(emc->bpmp)) {
+               err = PTR_ERR(emc->bpmp);
+
+               if (err != -EPROBE_DEFER)
+                       dev_err(&pdev->dev, "failed to get BPMP: %d\n", err);
+
+               return err;
+       }
+
+       emc->clk = devm_clk_get(&pdev->dev, "emc");
+       if (IS_ERR(emc->clk)) {
+               err = PTR_ERR(emc->clk);
+               dev_err(&pdev->dev, "failed to get EMC clock: %d\n", err);
+               return err;
+       }
+
+       platform_set_drvdata(pdev, emc);
+       emc->dev = &pdev->dev;
+
+       memset(&msg, 0, sizeof(msg));
+       msg.mrq = MRQ_EMC_DVFS_LATENCY;
+       msg.tx.data = NULL;
+       msg.tx.size = 0;
+       msg.rx.data = &response;
+       msg.rx.size = sizeof(response);
+
+       err = tegra_bpmp_transfer(emc->bpmp, &msg);
+       if (err < 0) {
+               dev_err(&pdev->dev, "failed to EMC DVFS pairs: %d\n", err);
+               return err;
+       }
+
+       emc->debugfs.min_rate = ULONG_MAX;
+       emc->debugfs.max_rate = 0;
+
+       emc->num_dvfs = response.num_pairs;
+
+       emc->dvfs = devm_kmalloc_array(&pdev->dev, emc->num_dvfs,
+                                      sizeof(*emc->dvfs), GFP_KERNEL);
+       if (!emc->dvfs)
+               return -ENOMEM;
+
+       dev_dbg(&pdev->dev, "%u DVFS pairs:\n", emc->num_dvfs);
+
+       for (i = 0; i < emc->num_dvfs; i++) {
+               emc->dvfs[i].rate = response.pairs[i].freq * 1000;
+               emc->dvfs[i].latency = response.pairs[i].latency;
+
+               if (emc->dvfs[i].rate < emc->debugfs.min_rate)
+                       emc->debugfs.min_rate = emc->dvfs[i].rate;
+
+               if (emc->dvfs[i].rate > emc->debugfs.max_rate)
+                       emc->debugfs.max_rate = emc->dvfs[i].rate;
+
+               dev_dbg(&pdev->dev, "  %2u: %lu Hz -> %lu us\n", i,
+                       emc->dvfs[i].rate, emc->dvfs[i].latency);
+       }
+
+       err = clk_set_rate_range(emc->clk, emc->debugfs.min_rate,
+                                emc->debugfs.max_rate);
+       if (err < 0) {
+               dev_err(&pdev->dev,
+                       "failed to set rate range [%lu-%lu] for %pC\n",
+                       emc->debugfs.min_rate, emc->debugfs.max_rate,
+                       emc->clk);
+               return err;
+       }
+
+       emc->debugfs.root = debugfs_create_dir("emc", NULL);
+       if (!emc->debugfs.root) {
+               dev_err(&pdev->dev, "failed to create debugfs directory\n");
+               return 0;
+       }
+
+       debugfs_create_file("available_rates", S_IRUGO, emc->debugfs.root,
+                           emc, &tegra186_emc_debug_available_rates_fops);
+       debugfs_create_file("min_rate", S_IRUGO | S_IWUSR, emc->debugfs.root,
+                           emc, &tegra186_emc_debug_min_rate_fops);
+       debugfs_create_file("max_rate", S_IRUGO | S_IWUSR, emc->debugfs.root,
+                           emc, &tegra186_emc_debug_max_rate_fops);
+
+       return 0;
+}
+
+static int tegra186_emc_remove(struct platform_device *pdev)
+{
+       struct tegra186_emc *emc = platform_get_drvdata(pdev);
+
+       debugfs_remove_recursive(emc->debugfs.root);
+       tegra_bpmp_put(emc->bpmp);
+
+       return 0;
+}
+
+static const struct of_device_id tegra186_emc_of_match[] = {
+#if defined(CONFIG_ARCH_TEGRA186_SOC)
+       { .compatible = "nvidia,tegra186-emc" },
+#endif
+#if defined(CONFIG_ARCH_TEGRA194_SOC)
+       { .compatible = "nvidia,tegra194-emc" },
+#endif
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, tegra186_emc_of_match);
+
+static struct platform_driver tegra186_emc_driver = {
+       .driver = {
+               .name = "tegra186-emc",
+               .of_match_table = tegra186_emc_of_match,
+               .suppress_bind_attrs = true,
+       },
+       .probe = tegra186_emc_probe,
+       .remove = tegra186_emc_remove,
+};
+module_platform_driver(tegra186_emc_driver);
+
+MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>");
+MODULE_DESCRIPTION("NVIDIA Tegra186 External Memory Controller driver");
+MODULE_LICENSE("GPL v2");
index 441213a3593058c7f20573da686a803e3ced16e3..5d53f11ca7b6a8c935f63220806b0073f3e6073f 100644 (file)
@@ -6,16 +6,18 @@
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 
+#if defined(CONFIG_ARCH_TEGRA_186_SOC)
 #include <dt-bindings/memory/tegra186-mc.h>
+#endif
 
-struct tegra_mc {
-       struct device *dev;
-       void __iomem *regs;
-};
+#if defined(CONFIG_ARCH_TEGRA_194_SOC)
+#include <dt-bindings/memory/tegra194-mc.h>
+#endif
 
-struct tegra_mc_client {
+struct tegra186_mc_client {
        const char *name;
        unsigned int sid;
        struct {
@@ -24,7 +26,46 @@ struct tegra_mc_client {
        } regs;
 };
 
-static const struct tegra_mc_client tegra186_mc_clients[] = {
+struct tegra186_mc_soc {
+       const struct tegra186_mc_client *clients;
+       unsigned int num_clients;
+};
+
+struct tegra186_mc {
+       struct device *dev;
+       void __iomem *regs;
+
+       const struct tegra186_mc_soc *soc;
+};
+
+static void tegra186_mc_program_sid(struct tegra186_mc *mc)
+{
+       unsigned int i;
+
+       for (i = 0; i < mc->soc->num_clients; i++) {
+               const struct tegra186_mc_client *client = &mc->soc->clients[i];
+               u32 override, security;
+
+               override = readl(mc->regs + client->regs.override);
+               security = readl(mc->regs + client->regs.security);
+
+               dev_dbg(mc->dev, "client %s: override: %x security: %x\n",
+                       client->name, override, security);
+
+               dev_dbg(mc->dev, "setting SID %u for %s\n", client->sid,
+                       client->name);
+               writel(client->sid, mc->regs + client->regs.override);
+
+               override = readl(mc->regs + client->regs.override);
+               security = readl(mc->regs + client->regs.security);
+
+               dev_dbg(mc->dev, "client %s: override: %x security: %x\n",
+                       client->name, override, security);
+       }
+}
+
+#if defined(CONFIG_ARCH_TEGRA_186_SOC)
+static const struct tegra186_mc_client tegra186_mc_clients[] = {
        {
                .name = "ptcr",
                .sid = TEGRA186_SID_PASSTHROUGH,
@@ -532,64 +573,1030 @@ static const struct tegra_mc_client tegra186_mc_clients[] = {
        },
 };
 
-static int tegra186_mc_probe(struct platform_device *pdev)
-{
-       struct resource *res;
-       struct tegra_mc *mc;
-       unsigned int i;
-       int err = 0;
-
-       mc = devm_kzalloc(&pdev->dev, sizeof(*mc), GFP_KERNEL);
-       if (!mc)
-               return -ENOMEM;
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       mc->regs = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(mc->regs))
-               return PTR_ERR(mc->regs);
-
-       mc->dev = &pdev->dev;
-
-       for (i = 0; i < ARRAY_SIZE(tegra186_mc_clients); i++) {
-               const struct tegra_mc_client *client = &tegra186_mc_clients[i];
-               u32 override, security;
-
-               override = readl(mc->regs + client->regs.override);
-               security = readl(mc->regs + client->regs.security);
-
-               dev_dbg(&pdev->dev, "client %s: override: %x security: %x\n",
-                       client->name, override, security);
-
-               dev_dbg(&pdev->dev, "setting SID %u for %s\n", client->sid,
-                       client->name);
-               writel(client->sid, mc->regs + client->regs.override);
-
-               override = readl(mc->regs + client->regs.override);
-               security = readl(mc->regs + client->regs.security);
-
-               dev_dbg(&pdev->dev, "client %s: override: %x security: %x\n",
-                       client->name, override, security);
-       }
-
-       platform_set_drvdata(pdev, mc);
-
-       return err;
-}
-
-static const struct of_device_id tegra186_mc_of_match[] = {
-       { .compatible = "nvidia,tegra186-mc", },
-       { /* sentinel */ }
+static const struct tegra186_mc_soc tegra186_mc_soc = {
+       .num_clients = ARRAY_SIZE(tegra186_mc_clients),
+       .clients = tegra186_mc_clients,
+};
+#endif
+
+#if defined(CONFIG_ARCH_TEGRA_194_SOC)
+static const struct tegra186_mc_client tegra194_mc_clients[] = {
+       {
+               .name = "ptcr",
+               .sid = TEGRA194_SID_PASSTHROUGH,
+               .regs = {
+                       .override = 0x000,
+                       .security = 0x004,
+               },
+       }, {
+               .name = "miu7r",
+               .sid = TEGRA194_SID_MIU,
+               .regs = {
+                       .override = 0x008,
+                       .security = 0x00c,
+               },
+       }, {
+               .name = "miu7w",
+               .sid = TEGRA194_SID_MIU,
+               .regs = {
+                       .override = 0x010,
+                       .security = 0x014,
+               },
+       }, {
+               .name = "hdar",
+               .sid = TEGRA194_SID_HDA,
+               .regs = {
+                       .override = 0x0a8,
+                       .security = 0x0ac,
+               },
+       }, {
+               .name = "host1xdmar",
+               .sid = TEGRA194_SID_HOST1X,
+               .regs = {
+                       .override = 0x0b0,
+                       .security = 0x0b4,
+               },
+       }, {
+               .name = "nvencsrd",
+               .sid = TEGRA194_SID_NVENC,
+               .regs = {
+                       .override = 0x0e0,
+                       .security = 0x0e4,
+               },
+       }, {
+               .name = "satar",
+               .sid = TEGRA194_SID_SATA,
+               .regs = {
+                       .override = 0x0f8,
+                       .security = 0x0fc,
+               },
+       }, {
+               .name = "mpcorer",
+               .sid = TEGRA194_SID_PASSTHROUGH,
+               .regs = {
+                       .override = 0x138,
+                       .security = 0x13c,
+               },
+       }, {
+               .name = "nvencswr",
+               .sid = TEGRA194_SID_NVENC,
+               .regs = {
+                       .override = 0x158,
+                       .security = 0x15c,
+               },
+       }, {
+               .name = "hdaw",
+               .sid = TEGRA194_SID_HDA,
+               .regs = {
+                       .override = 0x1a8,
+                       .security = 0x1ac,
+               },
+       }, {
+               .name = "mpcorew",
+               .sid = TEGRA194_SID_PASSTHROUGH,
+               .regs = {
+                       .override = 0x1c8,
+                       .security = 0x1cc,
+               },
+       }, {
+               .name = "sataw",
+               .sid = TEGRA194_SID_SATA,
+               .regs = {
+                       .override = 0x1e8,
+                       .security = 0x1ec,
+               },
+       }, {
+               .name = "ispra",
+               .sid = TEGRA194_SID_ISP,
+               .regs = {
+                       .override = 0x220,
+                       .security = 0x224,
+               },
+       }, {
+               .name = "ispfalr",
+               .sid = TEGRA194_SID_ISP_FALCON,
+               .regs = {
+                       .override = 0x228,
+                       .security = 0x22c,
+               },
+       }, {
+               .name = "ispwa",
+               .sid = TEGRA194_SID_ISP,
+               .regs = {
+                       .override = 0x230,
+                       .security = 0x234,
+               },
+       }, {
+               .name = "ispwb",
+               .sid = TEGRA194_SID_ISP,
+               .regs = {
+                       .override = 0x238,
+                       .security = 0x23c,
+               },
+       }, {
+               .name = "xusb_hostr",
+               .sid = TEGRA194_SID_XUSB_HOST,
+               .regs = {
+                       .override = 0x250,
+                       .security = 0x254,
+               },
+       }, {
+               .name = "xusb_hostw",
+               .sid = TEGRA194_SID_XUSB_HOST,
+               .regs = {
+                       .override = 0x258,
+                       .security = 0x25c,
+               },
+       }, {
+               .name = "xusb_devr",
+               .sid = TEGRA194_SID_XUSB_DEV,
+               .regs = {
+                       .override = 0x260,
+                       .security = 0x264,
+               },
+       }, {
+               .name = "xusb_devw",
+               .sid = TEGRA194_SID_XUSB_DEV,
+               .regs = {
+                       .override = 0x268,
+                       .security = 0x26c,
+               },
+       }, {
+               .name = "sdmmcra",
+               .sid = TEGRA194_SID_SDMMC1,
+               .regs = {
+                       .override = 0x300,
+                       .security = 0x304,
+               },
+       }, {
+               .name = "sdmmcr",
+               .sid = TEGRA194_SID_SDMMC3,
+               .regs = {
+                       .override = 0x310,
+                       .security = 0x314,
+               },
+       }, {
+               .name = "sdmmcrab",
+               .sid = TEGRA194_SID_SDMMC4,
+               .regs = {
+                       .override = 0x318,
+                       .security = 0x31c,
+               },
+       }, {
+               .name = "sdmmcwa",
+               .sid = TEGRA194_SID_SDMMC1,
+               .regs = {
+                       .override = 0x320,
+                       .security = 0x324,
+               },
+       }, {
+               .name = "sdmmcw",
+               .sid = TEGRA194_SID_SDMMC3,
+               .regs = {
+                       .override = 0x330,
+                       .security = 0x334,
+               },
+       }, {
+               .name = "sdmmcwab",
+               .sid = TEGRA194_SID_SDMMC4,
+               .regs = {
+                       .override = 0x338,
+                       .security = 0x33c,
+               },
+       }, {
+               .name = "vicsrd",
+               .sid = TEGRA194_SID_VIC,
+               .regs = {
+                       .override = 0x360,
+                       .security = 0x364,
+               },
+       }, {
+               .name = "vicswr",
+               .sid = TEGRA194_SID_VIC,
+               .regs = {
+                       .override = 0x368,
+                       .security = 0x36c,
+               },
+       }, {
+               .name = "viw",
+               .sid = TEGRA194_SID_VI,
+               .regs = {
+                       .override = 0x390,
+                       .security = 0x394,
+               },
+       }, {
+               .name = "nvdecsrd",
+               .sid = TEGRA194_SID_NVDEC,
+               .regs = {
+                       .override = 0x3c0,
+                       .security = 0x3c4,
+               },
+       }, {
+               .name = "nvdecswr",
+               .sid = TEGRA194_SID_NVDEC,
+               .regs = {
+                       .override = 0x3c8,
+                       .security = 0x3cc,
+               },
+       }, {
+               .name = "aper",
+               .sid = TEGRA194_SID_APE,
+               .regs = {
+                       .override = 0x3c0,
+                       .security = 0x3c4,
+               },
+       }, {
+               .name = "apew",
+               .sid = TEGRA194_SID_APE,
+               .regs = {
+                       .override = 0x3d0,
+                       .security = 0x3d4,
+               },
+       }, {
+               .name = "nvjpgsrd",
+               .sid = TEGRA194_SID_NVJPG,
+               .regs = {
+                       .override = 0x3f0,
+                       .security = 0x3f4,
+               },
+       }, {
+               .name = "nvjpgswr",
+               .sid = TEGRA194_SID_NVJPG,
+               .regs = {
+                       .override = 0x3f0,
+                       .security = 0x3f4,
+               },
+       }, {
+               .name = "axiapr",
+               .sid = TEGRA194_SID_PASSTHROUGH,
+               .regs = {
+                       .override = 0x410,
+                       .security = 0x414,
+               },
+       }, {
+               .name = "axiapw",
+               .sid = TEGRA194_SID_PASSTHROUGH,
+               .regs = {
+                       .override = 0x418,
+                       .security = 0x41c,
+               },
+       }, {
+               .name = "etrr",
+               .sid = TEGRA194_SID_ETR,
+               .regs = {
+                       .override = 0x420,
+                       .security = 0x424,
+               },
+       }, {
+               .name = "etrw",
+               .sid = TEGRA194_SID_ETR,
+               .regs = {
+                       .override = 0x428,
+                       .security = 0x42c,
+               },
+       }, {
+               .name = "axisr",
+               .sid = TEGRA194_SID_PASSTHROUGH,
+               .regs = {
+                       .override = 0x460,
+                       .security = 0x464,
+               },
+       }, {
+               .name = "axisw",
+               .sid = TEGRA194_SID_PASSTHROUGH,
+               .regs = {
+                       .override = 0x468,
+                       .security = 0x46c,
+               },
+       }, {
+               .name = "eqosr",
+               .sid = TEGRA194_SID_EQOS,
+               .regs = {
+                       .override = 0x470,
+                       .security = 0x474,
+               },
+       }, {
+               .name = "eqosw",
+               .sid = TEGRA194_SID_EQOS,
+               .regs = {
+                       .override = 0x478,
+                       .security = 0x47c,
+               },
+       }, {
+               .name = "ufshcr",
+               .sid = TEGRA194_SID_UFSHC,
+               .regs = {
+                       .override = 0x480,
+                       .security = 0x484,
+               },
+       }, {
+               .name = "ufshcw",
+               .sid = TEGRA194_SID_UFSHC,
+               .regs = {
+                       .override = 0x488,
+                       .security = 0x48c,
+               },
+       }, {
+               .name = "nvdisplayr",
+               .sid = TEGRA194_SID_NVDISPLAY,
+               .regs = {
+                       .override = 0x490,
+                       .security = 0x494,
+               },
+       }, {
+               .name = "bpmpr",
+               .sid = TEGRA194_SID_BPMP,
+               .regs = {
+                       .override = 0x498,
+                       .security = 0x49c,
+               },
+       }, {
+               .name = "bpmpw",
+               .sid = TEGRA194_SID_BPMP,
+               .regs = {
+                       .override = 0x4a0,
+                       .security = 0x4a4,
+               },
+       }, {
+               .name = "bpmpdmar",
+               .sid = TEGRA194_SID_BPMP,
+               .regs = {
+                       .override = 0x4a8,
+                       .security = 0x4ac,
+               },
+       }, {
+               .name = "bpmpdmaw",
+               .sid = TEGRA194_SID_BPMP,
+               .regs = {
+                       .override = 0x4b0,
+                       .security = 0x4b4,
+               },
+       }, {
+               .name = "aonr",
+               .sid = TEGRA194_SID_AON,
+               .regs = {
+                       .override = 0x4b8,
+                       .security = 0x4bc,
+               },
+       }, {
+               .name = "aonw",
+               .sid = TEGRA194_SID_AON,
+               .regs = {
+                       .override = 0x4c0,
+                       .security = 0x4c4,
+               },
+       }, {
+               .name = "aondmar",
+               .sid = TEGRA194_SID_AON,
+               .regs = {
+                       .override = 0x4c8,
+                       .security = 0x4cc,
+               },
+       }, {
+               .name = "aondmaw",
+               .sid = TEGRA194_SID_AON,
+               .regs = {
+                       .override = 0x4d0,
+                       .security = 0x4d4,
+               },
+       }, {
+               .name = "scer",
+               .sid = TEGRA194_SID_SCE,
+               .regs = {
+                       .override = 0x4d8,
+                       .security = 0x4dc,
+               },
+       }, {
+               .name = "scew",
+               .sid = TEGRA194_SID_SCE,
+               .regs = {
+                       .override = 0x4e0,
+                       .security = 0x4e4,
+               },
+       }, {
+               .name = "scedmar",
+               .sid = TEGRA194_SID_SCE,
+               .regs = {
+                       .override = 0x4e8,
+                       .security = 0x4ec,
+               },
+       }, {
+               .name = "scedmaw",
+               .sid = TEGRA194_SID_SCE,
+               .regs = {
+                       .override = 0x4f0,
+                       .security = 0x4f4,
+               },
+       }, {
+               .name = "apedmar",
+               .sid = TEGRA194_SID_APE,
+               .regs = {
+                       .override = 0x4f8,
+                       .security = 0x4fc,
+               },
+       }, {
+               .name = "apedmaw",
+               .sid = TEGRA194_SID_APE,
+               .regs = {
+                       .override = 0x500,
+                       .security = 0x504,
+               },
+       }, {
+               .name = "nvdisplayr1",
+               .sid = TEGRA194_SID_NVDISPLAY,
+               .regs = {
+                       .override = 0x508,
+                       .security = 0x50c,
+               },
+       }, {
+               .name = "vicsrd1",
+               .sid = TEGRA194_SID_VIC,
+               .regs = {
+                       .override = 0x510,
+                       .security = 0x514,
+               },
+       }, {
+               .name = "nvdecsrd1",
+               .sid = TEGRA194_SID_NVDEC,
+               .regs = {
+                       .override = 0x518,
+                       .security = 0x51c,
+               },
+       }, {
+               .name = "miu0r",
+               .sid = TEGRA194_SID_MIU,
+               .regs = {
+                       .override = 0x530,
+                       .security = 0x534,
+               },
+       }, {
+               .name = "miu0w",
+               .sid = TEGRA194_SID_MIU,
+               .regs = {
+                       .override = 0x538,
+                       .security = 0x53c,
+               },
+       }, {
+               .name = "miu1r",
+               .sid = TEGRA194_SID_MIU,
+               .regs = {
+                       .override = 0x540,
+                       .security = 0x544,
+               },
+       }, {
+               .name = "miu1w",
+               .sid = TEGRA194_SID_MIU,
+               .regs = {
+                       .override = 0x548,
+                       .security = 0x54c,
+               },
+       }, {
+               .name = "miu2r",
+               .sid = TEGRA194_SID_MIU,
+               .regs = {
+                       .override = 0x570,
+                       .security = 0x574,
+               },
+       }, {
+               .name = "miu2w",
+               .sid = TEGRA194_SID_MIU,
+               .regs = {
+                       .override = 0x578,
+                       .security = 0x57c,
+               },
+       }, {
+               .name = "miu3r",
+               .sid = TEGRA194_SID_MIU,
+               .regs = {
+                       .override = 0x580,
+                       .security = 0x584,
+               },
+       }, {
+               .name = "miu3w",
+               .sid = TEGRA194_SID_MIU,
+               .regs = {
+                       .override = 0x588,
+                       .security = 0x58c,
+               },
+       }, {
+               .name = "miu4r",
+               .sid = TEGRA194_SID_MIU,
+               .regs = {
+                       .override = 0x590,
+                       .security = 0x594,
+               },
+       }, {
+               .name = "miu4w",
+               .sid = TEGRA194_SID_MIU,
+               .regs = {
+                       .override = 0x598,
+                       .security = 0x59c,
+               },
+       }, {
+               .name = "dpmur",
+               .sid = TEGRA194_SID_PASSTHROUGH,
+               .regs = {
+                       .override = 0x598,
+                       .security = 0x59c,
+               },
+       }, {
+               .name = "vifalr",
+               .sid = TEGRA194_SID_VI_FALCON,
+               .regs = {
+                       .override = 0x5e0,
+                       .security = 0x5e4,
+               },
+       }, {
+               .name = "vifalw",
+               .sid = TEGRA194_SID_VI_FALCON,
+               .regs = {
+                       .override = 0x5e8,
+                       .security = 0x5ec,
+               },
+       }, {
+               .name = "dla0rda",
+               .sid = TEGRA194_SID_NVDLA0,
+               .regs = {
+                       .override = 0x5f0,
+                       .security = 0x5f4,
+               },
+       }, {
+               .name = "dla0falrdb",
+               .sid = TEGRA194_SID_NVDLA0,
+               .regs = {
+                       .override = 0x5f8,
+                       .security = 0x5fc,
+               },
+       }, {
+               .name = "dla0wra",
+               .sid = TEGRA194_SID_NVDLA0,
+               .regs = {
+                       .override = 0x600,
+                       .security = 0x604,
+               },
+       }, {
+               .name = "dla0falwrb",
+               .sid = TEGRA194_SID_NVDLA0,
+               .regs = {
+                       .override = 0x608,
+                       .security = 0x60c,
+               },
+       }, {
+               .name = "dla1rda",
+               .sid = TEGRA194_SID_NVDLA1,
+               .regs = {
+                       .override = 0x610,
+                       .security = 0x614,
+               },
+       }, {
+               .name = "dla1falrdb",
+               .sid = TEGRA194_SID_NVDLA1,
+               .regs = {
+                       .override = 0x618,
+                       .security = 0x61c,
+               },
+       }, {
+               .name = "dla1wra",
+               .sid = TEGRA194_SID_NVDLA1,
+               .regs = {
+                       .override = 0x620,
+                       .security = 0x624,
+               },
+       }, {
+               .name = "dla1falwrb",
+               .sid = TEGRA194_SID_NVDLA1,
+               .regs = {
+                       .override = 0x628,
+                       .security = 0x62c,
+               },
+       }, {
+               .name = "pva0rda",
+               .sid = TEGRA194_SID_PVA0,
+               .regs = {
+                       .override = 0x630,
+                       .security = 0x634,
+               },
+       }, {
+               .name = "pva0rdb",
+               .sid = TEGRA194_SID_PVA0,
+               .regs = {
+                       .override = 0x638,
+                       .security = 0x63c,
+               },
+       }, {
+               .name = "pva0rdc",
+               .sid = TEGRA194_SID_PVA0,
+               .regs = {
+                       .override = 0x640,
+                       .security = 0x644,
+               },
+       }, {
+               .name = "pva0wra",
+               .sid = TEGRA194_SID_PVA0,
+               .regs = {
+                       .override = 0x648,
+                       .security = 0x64c,
+               },
+       }, {
+               .name = "pva0wrb",
+               .sid = TEGRA194_SID_PVA0,
+               .regs = {
+                       .override = 0x650,
+                       .security = 0x654,
+               },
+       }, {
+               .name = "pva0wrc",
+               .sid = TEGRA194_SID_PVA0,
+               .regs = {
+                       .override = 0x658,
+                       .security = 0x65c,
+               },
+       }, {
+               .name = "pva1rda",
+               .sid = TEGRA194_SID_PVA1,
+               .regs = {
+                       .override = 0x660,
+                       .security = 0x664,
+               },
+       }, {
+               .name = "pva1rdb",
+               .sid = TEGRA194_SID_PVA1,
+               .regs = {
+                       .override = 0x668,
+                       .security = 0x66c,
+               },
+       }, {
+               .name = "pva1rdc",
+               .sid = TEGRA194_SID_PVA1,
+               .regs = {
+                       .override = 0x670,
+                       .security = 0x674,
+               },
+       }, {
+               .name = "pva1wra",
+               .sid = TEGRA194_SID_PVA1,
+               .regs = {
+                       .override = 0x678,
+                       .security = 0x67c,
+               },
+       }, {
+               .name = "pva1wrb",
+               .sid = TEGRA194_SID_PVA1,
+               .regs = {
+                       .override = 0x680,
+                       .security = 0x684,
+               },
+       }, {
+               .name = "pva1wrc",
+               .sid = TEGRA194_SID_PVA1,
+               .regs = {
+                       .override = 0x688,
+                       .security = 0x68c,
+               },
+       }, {
+               .name = "rcer",
+               .sid = TEGRA194_SID_RCE,
+               .regs = {
+                       .override = 0x690,
+                       .security = 0x694,
+               },
+       }, {
+               .name = "rcew",
+               .sid = TEGRA194_SID_RCE,
+               .regs = {
+                       .override = 0x698,
+                       .security = 0x69c,
+               },
+       }, {
+               .name = "rcedmar",
+               .sid = TEGRA194_SID_RCE,
+               .regs = {
+                       .override = 0x6a0,
+                       .security = 0x6a4,
+               },
+       }, {
+               .name = "rcedmaw",
+               .sid = TEGRA194_SID_RCE,
+               .regs = {
+                       .override = 0x6a8,
+                       .security = 0x6ac,
+               },
+       }, {
+               .name = "nvenc1srd",
+               .sid = TEGRA194_SID_NVENC1,
+               .regs = {
+                       .override = 0x6b0,
+                       .security = 0x6b4,
+               },
+       }, {
+               .name = "nvenc1swr",
+               .sid = TEGRA194_SID_NVENC1,
+               .regs = {
+                       .override = 0x6b8,
+                       .security = 0x6bc,
+               },
+       }, {
+               .name = "pcie0r",
+               .sid = TEGRA194_SID_PCIE0,
+               .regs = {
+                       .override = 0x6c0,
+                       .security = 0x6c4,
+               },
+       }, {
+               .name = "pcie0w",
+               .sid = TEGRA194_SID_PCIE0,
+               .regs = {
+                       .override = 0x6c8,
+                       .security = 0x6cc,
+               },
+       }, {
+               .name = "pcie1r",
+               .sid = TEGRA194_SID_PCIE1,
+               .regs = {
+                       .override = 0x6d0,
+                       .security = 0x6d4,
+               },
+       }, {
+               .name = "pcie1w",
+               .sid = TEGRA194_SID_PCIE1,
+               .regs = {
+                       .override = 0x6d8,
+                       .security = 0x6dc,
+               },
+       }, {
+               .name = "pcie2ar",
+               .sid = TEGRA194_SID_PCIE2,
+               .regs = {
+                       .override = 0x6e0,
+                       .security = 0x6e4,
+               },
+       }, {
+               .name = "pcie2aw",
+               .sid = TEGRA194_SID_PCIE2,
+               .regs = {
+                       .override = 0x6e8,
+                       .security = 0x6ec,
+               },
+       }, {
+               .name = "pcie3r",
+               .sid = TEGRA194_SID_PCIE3,
+               .regs = {
+                       .override = 0x6f0,
+                       .security = 0x6f4,
+               },
+       }, {
+               .name = "pcie3w",
+               .sid = TEGRA194_SID_PCIE3,
+               .regs = {
+                       .override = 0x6f8,
+                       .security = 0x6fc,
+               },
+       }, {
+         &nb