Merge tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 24 Oct 2020 17:39:22 +0000 (10:39 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 24 Oct 2020 17:39:22 +0000 (10:39 -0700)
Pull ARM SoC-related driver updates from Olof Johansson:
 "Various driver updates for platforms. A bulk of this is smaller fixes
  or cleanups, but some of the new material this time around is:

   - Support for Nvidia Tegra234 SoC

   - Ring accelerator support for TI AM65x

   - PRUSS driver for TI platforms

   - Renesas support for R-Car V3U SoC

   - Reset support for Cortex-M4 processor on i.MX8MQ

  There are also new socinfo entries for a handful of different SoCs and
  platforms"

* tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc: (131 commits)
  drm/mediatek: reduce clear event
  soc: mediatek: cmdq: add clear option in cmdq_pkt_wfe api
  soc: mediatek: cmdq: add jump function
  soc: mediatek: cmdq: add write_s_mask value function
  soc: mediatek: cmdq: add write_s value function
  soc: mediatek: cmdq: add read_s function
  soc: mediatek: cmdq: add write_s_mask function
  soc: mediatek: cmdq: add write_s function
  soc: mediatek: cmdq: add address shift in jump
  soc: mediatek: mtk-infracfg: Fix kerneldoc
  soc: amlogic: pm-domains: use always-on flag
  reset: sti: reset-syscfg: fix struct description warnings
  reset: imx7: add the cm4 reset for i.MX8MQ
  dt-bindings: reset: imx8mq: add m4 reset
  reset: Fix and extend kerneldoc
  reset: reset-zynqmp: Added support for Versal platform
  dt-bindings: reset: Updated binding for Versal reset driver
  reset: imx7: Support module build
  soc: fsl: qe: Remove unnessesary check in ucc_set_tdm_rxtx_clk
  soc: fsl: qman: convert to use be32_add_cpu()
  ...

117 files changed:
Documentation/devicetree/bindings/bus/brcm,gisb-arb.txt
Documentation/devicetree/bindings/memory-controllers/mediatek,smi-common.txt
Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.txt
Documentation/devicetree/bindings/power/amlogic,meson-ee-pwrc.yaml
Documentation/devicetree/bindings/power/brcm,bcm63xx-power.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/reset/xlnx,zynqmp-reset.txt
Documentation/devicetree/bindings/soc/ti/k3-ringacc.yaml
Documentation/devicetree/bindings/soc/ti/ti,pruss.yaml [new file with mode: 0644]
MAINTAINERS
arch/mips/boot/dts/brcm/bcm63268.dtsi
arch/mips/boot/dts/brcm/bcm6328.dtsi
arch/mips/boot/dts/brcm/bcm6362.dtsi
drivers/bus/brcmstb_gisb.c
drivers/cpufreq/scmi-cpufreq.c
drivers/dma/ti/k3-udma-glue.c
drivers/firmware/Kconfig
drivers/firmware/Makefile
drivers/firmware/arm_scmi/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/mailbox.c
drivers/firmware/arm_scmi/notify.c
drivers/firmware/arm_scmi/perf.c
drivers/firmware/arm_scmi/power.c
drivers/firmware/arm_scmi/reset.c
drivers/firmware/arm_scmi/sensors.c
drivers/firmware/arm_scmi/smc.c
drivers/firmware/arm_scmi/system.c [new file with mode: 0644]
drivers/firmware/imx/scu-pd.c
drivers/firmware/smccc/smccc.c
drivers/firmware/tegra/bpmp.c
drivers/firmware/ti_sci.c
drivers/gpu/drm/mediatek/mtk_drm_crtc.c
drivers/mailbox/tegra-hsp.c
drivers/memory/Kconfig
drivers/memory/Makefile
drivers/memory/brcmstb_dpfe.c
drivers/memory/emif.c
drivers/memory/fsl-corenet-cf.c
drivers/memory/mtk-smi.c
drivers/memory/omap-gpmc.c
drivers/memory/renesas-rpc-if.c
drivers/memory/samsung/exynos5422-dmc.c
drivers/memory/tegra/tegra124-emc.c
drivers/memory/tegra/tegra124.c
drivers/memory/tegra/tegra186-emc.c
drivers/memory/tegra/tegra210-emc-cc-r21021.c
drivers/memory/tegra/tegra210.c
drivers/reset/Kconfig
drivers/reset/core.c
drivers/reset/reset-imx7.c
drivers/reset/reset-zynqmp.c
drivers/reset/sti/reset-syscfg.c
drivers/soc/amlogic/meson-ee-pwrc.c
drivers/soc/amlogic/meson-gx-pwrc-vpu.c
drivers/soc/bcm/Kconfig
drivers/soc/bcm/Makefile
drivers/soc/bcm/bcm63xx/Kconfig [new file with mode: 0644]
drivers/soc/bcm/bcm63xx/Makefile [new file with mode: 0644]
drivers/soc/bcm/bcm63xx/bcm63xx-power.c [new file with mode: 0644]
drivers/soc/bcm/brcmstb/biuctrl.c
drivers/soc/fsl/dpio/qbman-portal.c
drivers/soc/fsl/qbman/bman.c
drivers/soc/fsl/qbman/qman_test_api.c
drivers/soc/fsl/qe/ucc.c
drivers/soc/imx/gpcv2.c
drivers/soc/mediatek/mtk-cmdq-helper.c
drivers/soc/mediatek/mtk-infracfg.c
drivers/soc/qcom/apr.c
drivers/soc/qcom/llcc-qcom.c
drivers/soc/qcom/rpmh-internal.h
drivers/soc/qcom/rpmh-rsc.c
drivers/soc/qcom/socinfo.c
drivers/soc/renesas/Kconfig
drivers/soc/renesas/Makefile
drivers/soc/renesas/r8a779a0-sysc.c [new file with mode: 0644]
drivers/soc/renesas/rcar-rst.c
drivers/soc/renesas/renesas-soc.c
drivers/soc/sunxi/sunxi_sram.c
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/pmc.c
drivers/soc/ti/Kconfig
drivers/soc/ti/Makefile
drivers/soc/ti/k3-ringacc.c
drivers/soc/ti/k3-socinfo.c
drivers/soc/ti/knav_dma.c
drivers/soc/ti/knav_qmss_queue.c
drivers/soc/ti/pruss.c [new file with mode: 0644]
drivers/soc/ti/ti_sci_pm_domains.c
drivers/tee/optee/core.c
drivers/tee/optee/optee_msg.h
drivers/tee/optee/optee_private.h
drivers/tee/optee/optee_smc.h
drivers/tee/optee/rpc.c
drivers/tee/tee_core.c
drivers/tee/tee_shm.c
include/dt-bindings/power/meson-axg-power.h [new file with mode: 0644]
include/dt-bindings/reset/imx8mq-reset.h
include/dt-bindings/reset/xlnx-versal-resets.h [new file with mode: 0644]
include/dt-bindings/soc/bcm6318-pm.h [new file with mode: 0644]
include/dt-bindings/soc/bcm63268-pm.h [new file with mode: 0644]
include/dt-bindings/soc/bcm6328-pm.h [new file with mode: 0644]
include/dt-bindings/soc/bcm6362-pm.h [new file with mode: 0644]
include/linux/mailbox/mtk-cmdq-mailbox.h
include/linux/pruss_driver.h [new file with mode: 0644]
include/linux/qcom-geni-se.h
include/linux/scmi_protocol.h
include/linux/soc/mediatek/mtk-cmdq.h
include/linux/tee_drv.h
include/soc/fsl/qman.h
include/soc/tegra/fuse.h
include/uapi/linux/tee.h

index 729def6..10f6d0a 100644 (file)
@@ -10,7 +10,8 @@ Required properties:
     "brcm,bcm7038-gisb-arb" for 130nm chips
 - reg: specifies the base physical address and size of the registers
 - interrupts: specifies the two interrupts (timeout and TEA) to be used from
-  the parent interrupt controller
+  the parent interrupt controller. A third optional interrupt may be specified
+  for breakpoints.
 
 Optional properties:
 
index b645736..dbafffe 100644 (file)
@@ -5,7 +5,7 @@ The hardware block diagram please check bindings/iommu/mediatek,iommu.txt
 Mediatek SMI have two generations of HW architecture, here is the list
 which generation the SoCs use:
 generation 1: mt2701 and mt7623.
-generation 2: mt2712, mt6779, mt8173 and mt8183.
+generation 2: mt2712, mt6779, mt8167, mt8173 and mt8183.
 
 There's slight differences between the two SMI, for generation 2, the
 register which control the iommu port is at each larb's register base. But
@@ -20,6 +20,7 @@ Required properties:
        "mediatek,mt2712-smi-common"
        "mediatek,mt6779-smi-common"
        "mediatek,mt7623-smi-common", "mediatek,mt2701-smi-common"
+       "mediatek,mt8167-smi-common"
        "mediatek,mt8173-smi-common"
        "mediatek,mt8183-smi-common"
 - reg : the register and size of the SMI block.
index 8f19dfe..0c5de12 100644 (file)
@@ -8,6 +8,7 @@ Required properties:
                "mediatek,mt2712-smi-larb"
                "mediatek,mt6779-smi-larb"
                "mediatek,mt7623-smi-larb", "mediatek,mt2701-smi-larb"
+               "mediatek,mt8167-smi-larb"
                "mediatek,mt8173-smi-larb"
                "mediatek,mt8183-smi-larb"
 - reg : the register and size of this local arbiter.
@@ -22,7 +23,7 @@ Required properties:
   - "gals": the clock for GALS(Global Async Local Sync).
   Here is the list which has this GALS: mt8183.
 
-Required property for mt2701, mt2712, mt6779 and mt7623:
+Required property for mt2701, mt2712, mt6779, mt7623 and mt8167:
 - mediatek,larb-id :the hardware id of this larb.
 
 Example:
index 4f524f8..d30f85c 100644 (file)
@@ -27,6 +27,7 @@ properties:
       - amlogic,meson8b-pwrc
       - amlogic,meson8m2-pwrc
       - amlogic,meson-gxbb-pwrc
+      - amlogic,meson-axg-pwrc
       - amlogic,meson-g12a-pwrc
       - amlogic,meson-sm1-pwrc
 
@@ -42,11 +43,11 @@ properties:
       - const: vapb
 
   resets:
-    minItems: 11
+    minItems: 5
     maxItems: 12
 
   reset-names:
-    minItems: 11
+    minItems: 5
     maxItems: 12
 
   "#power-domain-cells":
@@ -111,6 +112,24 @@ allOf:
       properties:
         compatible:
           enum:
+            - amlogic,meson-axg-pwrc
+    then:
+      properties:
+        reset-names:
+          items:
+            - const: viu
+            - const: venc
+            - const: vcbus
+            - const: vencl
+            - const: vid_lock
+      required:
+        - resets
+        - reset-names
+
+  - if:
+      properties:
+        compatible:
+          enum:
             - amlogic,meson-g12a-pwrc
             - amlogic,meson-sm1-pwrc
     then:
diff --git a/Documentation/devicetree/bindings/power/brcm,bcm63xx-power.yaml b/Documentation/devicetree/bindings/power/brcm,bcm63xx-power.yaml
new file mode 100644 (file)
index 0000000..63b15ac
--- /dev/null
@@ -0,0 +1,44 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/power/brcm,bcm63xx-power.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: BCM63xx power domain driver
+
+maintainers:
+  - Álvaro Fernández Rojas <noltari@gmail.com>
+
+description: |
+  BCM6318, BCM6328, BCM6362 and BCM63268 SoCs have a power domain controller
+  to enable/disable certain components in order to save power.
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - brcm,bcm6318-power-controller
+          - brcm,bcm6328-power-controller
+          - brcm,bcm6362-power-controller
+          - brcm,bcm63268-power-controller
+
+  reg:
+    maxItems: 1
+
+  "#power-domain-cells":
+    const: 1
+
+required:
+  - compatible
+  - reg
+  - "#power-domain-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+    periph_pwr: power-controller@10001848 {
+        compatible = "brcm,bcm6328-power-controller";
+        reg = <0x10001848 0x4>;
+        #power-domain-cells = <1>;
+    };
index 27a45fe..ed83686 100644 (file)
@@ -1,7 +1,7 @@
 --------------------------------------------------------------------------
- =  Zynq UltraScale+ MPSoC reset driver binding =
+ =  Zynq UltraScale+ MPSoC and Versal reset driver binding =
 --------------------------------------------------------------------------
-The Zynq UltraScale+ MPSoC has several different resets.
+The Zynq UltraScale+ MPSoC and Versal has several different resets.
 
 See Chapter 36 of the Zynq UltraScale+ MPSoC TRM (UG) for more information
 about zynqmp resets.
@@ -10,7 +10,8 @@ Please also refer to reset.txt in this directory for common reset
 controller binding usage.
 
 Required Properties:
-- compatible:  "xlnx,zynqmp-reset"
+- compatible:  "xlnx,zynqmp-reset" for Zynq UltraScale+ MPSoC platform
+               "xlnx,versal-reset" for Versal platform
 - #reset-cells:        Specifies the number of cells needed to encode reset
                line, should be 1
 
@@ -37,8 +38,10 @@ Device nodes that need access to reset lines should
 specify them as a reset phandle in their corresponding node as
 specified in reset.txt.
 
-For list of all valid reset indicies see
+For list of all valid reset indices for Zynq UltraScale+ MPSoC see
 <dt-bindings/reset/xlnx-zynqmp-resets.h>
+For list of all valid reset indices for Versal see
+<dt-bindings/reset/xlnx-versal-resets.h>
 
 Example:
 
index ae33fc9..c3c595e 100644 (file)
@@ -62,11 +62,6 @@ properties:
     $ref: /schemas/types.yaml#/definitions/uint32
     description: TI-SCI device id of the ring accelerator
 
-  ti,dma-ring-reset-quirk:
-    $ref: /schemas/types.yaml#definitions/flag
-    description: |
-      enable ringacc/udma ring state interoperability issue software w/a
-
 required:
   - compatible
   - reg
@@ -94,7 +89,6 @@ examples:
             reg-names = "rt", "fifos", "proxy_gcfg", "proxy_target";
             ti,num-rings = <818>;
             ti,sci-rm-range-gp-rings = <0x2>; /* GP ring range */
-            ti,dma-ring-reset-quirk;
             ti,sci = <&dmsc>;
             ti,sci-dev-id = <187>;
             msi-parent = <&inta_main_udmass>;
diff --git a/Documentation/devicetree/bindings/soc/ti/ti,pruss.yaml b/Documentation/devicetree/bindings/soc/ti/ti,pruss.yaml
new file mode 100644 (file)
index 0000000..037c51b
--- /dev/null
@@ -0,0 +1,439 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/soc/ti/ti,pruss.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: |+
+  TI Programmable Real-Time Unit and Industrial Communication Subsystem
+
+maintainers:
+  - Suman Anna <s-anna@ti.com>
+
+description: |+
+
+  The Programmable Real-Time Unit and Industrial Communication Subsystem
+  (PRU-ICSS a.k.a. PRUSS) is present on various TI SoCs such as AM335x, AM437x,
+  Keystone 66AK2G, OMAP-L138/DA850 etc. A PRUSS consists of dual 32-bit RISC
+  cores (Programmable Real-Time Units, or PRUs), shared RAM, data and
+  instruction RAMs, some internal peripheral modules to facilitate industrial
+  communication, and an interrupt controller.
+
+  The programmable nature of the PRUs provide flexibility to implement custom
+  peripheral interfaces, fast real-time responses, or specialized data handling.
+  The common peripheral modules include the following,
+    - an Ethernet MII_RT module with two MII ports
+    - an MDIO port to control external Ethernet PHYs
+    - an Industrial Ethernet Peripheral (IEP) to manage/generate Industrial
+      Ethernet functions
+    - an Enhanced Capture Module (eCAP)
+    - an Industrial Ethernet Timer with 7/9 capture and 16 compare events
+    - a 16550-compatible UART to support PROFIBUS
+    - Enhanced GPIO with async capture and serial support
+
+  A PRU-ICSS subsystem can have up to three shared data memories. A PRU core
+  acts on a primary Data RAM (there are usually 2 Data RAMs) at its address
+  0x0, but also has access to a secondary Data RAM (primary to the other PRU
+  core) at its address 0x2000. A shared Data RAM, if present, can be accessed
+  by both the PRU cores. The Interrupt Controller (INTC) and a CFG module are
+  common to both the PRU cores. Each PRU core also has a private instruction
+  RAM, and specific register spaces for Control and Debug functionalities.
+
+  Various sub-modules within a PRU-ICSS subsystem are represented as individual
+  nodes and are defined using a parent-child hierarchy depending on their
+  integration within the IP and the SoC. These nodes are described in the
+  following sections.
+
+
+  PRU-ICSS Node
+  ==============
+  Each PRU-ICSS instance is represented as its own node with the individual PRU
+  processor cores, the memories node, an INTC node and an MDIO node represented
+  as child nodes within this PRUSS node. This node shall be a child of the
+  corresponding interconnect bus nodes or target-module nodes.
+
+  See ../../mfd/syscon.yaml for generic SysCon binding details.
+
+
+properties:
+  $nodename:
+    pattern: "^(pruss|icssg)@[0-9a-f]+$"
+
+  compatible:
+    enum:
+      - ti,am3356-pruss  # for AM335x SoC family
+      - ti,am4376-pruss0 # for AM437x SoC family and PRUSS unit 0
+      - ti,am4376-pruss1 # for AM437x SoC family and PRUSS unit 1
+      - ti,am5728-pruss  # for AM57xx SoC family
+      - ti,k2g-pruss     # for 66AK2G SoC family
+      - ti,am654-icssg   # for K3 AM65x SoC family
+      - ti,j721e-icssg   # for K3 J721E SoC family
+
+  reg:
+    maxItems: 1
+
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 1
+
+  ranges:
+    maxItems: 1
+
+  power-domains:
+    description: |
+      This property is as per sci-pm-domain.txt.
+
+patternProperties:
+
+  memories@[a-f0-9]+$:
+    description: |
+      The various Data RAMs within a single PRU-ICSS unit are represented as a
+      single node with the name 'memories'.
+
+    type: object
+
+    properties:
+      reg:
+        minItems: 2 # On AM437x one of two PRUSS units don't contain Shared RAM.
+        maxItems: 3
+        items:
+          - description: Address and size of the Data RAM0.
+          - description: Address and size of the Data RAM1.
+          - description: |
+              Address and size of the Shared Data RAM. Note that on AM437x one
+              of two PRUSS units don't contain Shared RAM, while the second one
+              has it.
+
+      reg-names:
+        minItems: 2
+        maxItems: 3
+        items:
+          - const: dram0
+          - const: dram1
+          - const: shrdram2
+
+    required:
+      - reg
+      - reg-names
+
+    additionalProperties: false
+
+  cfg@[a-f0-9]+$:
+    description: |
+      PRU-ICSS configuration space. CFG sub-module represented as a SysCon.
+
+    type: object
+
+    properties:
+      compatible:
+        items:
+          - const: ti,pruss-cfg
+          - const: syscon
+
+      "#address-cells":
+        const: 1
+
+      "#size-cells":
+        const: 1
+
+      reg:
+        maxItems: 1
+
+      ranges:
+        maxItems: 1
+
+      clocks:
+        type: object
+
+        properties:
+          "#address-cells":
+            const: 1
+
+          "#size-cells":
+            const: 0
+
+        patternProperties:
+          coreclk-mux@[a-f0-9]+$:
+            description: |
+              This is applicable only for ICSSG (K3 SoCs). The ICSSG modules
+              core clock can be set to one of the 2 sources: ICSSG_CORE_CLK or
+              ICSSG_ICLK.  This node models this clock mux and should have the
+              name "coreclk-mux".
+
+            type: object
+
+            properties:
+              '#clock-cells':
+                const: 0
+
+              clocks:
+                items:
+                  - description: ICSSG_CORE Clock
+                  - description: ICSSG_ICLK Clock
+
+              assigned-clocks:
+                maxItems: 1
+
+              assigned-clock-parents:
+                maxItems: 1
+                description: |
+                  Standard assigned-clocks-parents definition used for selecting
+                  mux parent (one of the mux input).
+
+              reg:
+                maxItems: 1
+
+            required:
+              - clocks
+
+            additionalProperties: false
+
+          iepclk-mux@[a-f0-9]+$:
+            description: |
+              The IEP module can get its clock from 2 sources: ICSSG_IEP_CLK or
+              CORE_CLK (OCP_CLK in older SoCs). This node models this clock
+              mux and should have the name "iepclk-mux".
+
+            type: object
+
+            properties:
+              '#clock-cells':
+                const: 0
+
+              clocks:
+                items:
+                  - description: ICSSG_IEP Clock
+                  - description: Core Clock (OCP Clock in older SoCs)
+
+              assigned-clocks:
+                maxItems: 1
+
+              assigned-clock-parents:
+                maxItems: 1
+                description: |
+                  Standard assigned-clocks-parents definition used for selecting
+                  mux parent (one of the mux input).
+
+              reg:
+                maxItems: 1
+
+            required:
+              - clocks
+
+            additionalProperties: false
+
+        additionalProperties: false
+
+  iep@[a-f0-9]+$:
+    description: |
+      Industrial Ethernet Peripheral to manage/generate Industrial Ethernet
+      functions such as time stamping. Each PRUSS has either 1 IEP (on AM335x,
+      AM437x, AM57xx & 66AK2G SoCs) or 2 IEPs (on K3 AM65x & J721E SoCs ). IEP
+      is used for creating PTP clocks and generating PPS signals.
+
+    type: object
+
+  mii-rt@[a-f0-9]+$:
+    description: |
+      Real-Time Ethernet to support multiple industrial communication protocols.
+      MII-RT sub-module represented as a SysCon.
+
+    type: object
+
+    properties:
+      compatible:
+        items:
+          - const: ti,pruss-mii
+          - const: syscon
+
+      reg:
+        maxItems: 1
+
+    additionalProperties: false
+
+  mii-g-rt@[a-f0-9]+$:
+    description: |
+      The Real-time Media Independent Interface to support multiple industrial
+      communication protocols (G stands for Gigabit). MII-G-RT sub-module
+      represented as a SysCon.
+
+    type: object
+
+    properties:
+      compatible:
+        items:
+          - const: ti,pruss-mii-g
+          - const: syscon
+
+      reg:
+        maxItems: 1
+
+    additionalProperties: false
+
+  interrupt-controller@[a-f0-9]+$:
+    description: |
+      PRUSS INTC Node. Each PRUSS has a single interrupt controller instance
+      that is common to all the PRU cores. This should be represented as an
+      interrupt-controller node.
+
+    type: object
+
+  mdio@[a-f0-9]+$:
+    description: |
+      MDIO Node. Each PRUSS has an MDIO module that can be used to control
+      external PHYs. The MDIO module used within the PRU-ICSS is an instance of
+      the MDIO Controller used in TI Davinci SoCs.
+
+    allOf:
+      - $ref: /schemas/net/ti,davinci-mdio.yaml#
+
+    type: object
+
+  "^(pru|rtu|txpru)@[0-9a-f]+$":
+    description: |
+      PRU Node. Each PRUSS has dual PRU cores, each represented as a RemoteProc
+      device through a PRU child node each. Each node can optionally be rendered
+      inactive by using the standard DT string property, "status". The ICSSG IP
+      present on K3 SoCs have additional auxiliary PRU cores with slightly
+      different IP integration.
+
+    type: object
+
+required:
+  - compatible
+  - reg
+  - ranges
+
+additionalProperties: false
+
+# Due to inability of correctly verifying sub-nodes with an @address through
+# the "required" list, the required sub-nodes below are commented out for now.
+
+#required:
+# - memories
+# - interrupt-controller
+# - pru
+
+if:
+  properties:
+    compatible:
+      contains:
+        enum:
+          - ti,k2g-pruss
+          - ti,am654-icssg
+          - ti,j721e-icssg
+then:
+  required:
+    - power-domains
+
+examples:
+  - |
+
+    /* Example 1 AM33xx PRU-ICSS */
+    pruss: pruss@0 {
+        compatible = "ti,am3356-pruss";
+        reg = <0x0 0x80000>;
+        #address-cells = <1>;
+        #size-cells = <1>;
+        ranges;
+
+        pruss_mem: memories@0 {
+            reg = <0x0 0x2000>,
+                  <0x2000 0x2000>,
+                  <0x10000 0x3000>;
+            reg-names = "dram0", "dram1", "shrdram2";
+        };
+
+        pruss_cfg: cfg@26000 {
+            compatible = "ti,pruss-cfg", "syscon";
+            #address-cells = <1>;
+            #size-cells = <1>;
+            reg = <0x26000 0x2000>;
+            ranges = <0x00 0x26000 0x2000>;
+
+            clocks {
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                pruss_iepclk_mux: iepclk-mux@30 {
+                    reg = <0x30>;
+                    #clock-cells = <0>;
+                    clocks = <&l3_gclk>,        /* icss_iep */
+                             <&pruss_ocp_gclk>; /* icss_ocp */
+                };
+            };
+        };
+
+        pruss_mii_rt: mii-rt@32000 {
+            compatible = "ti,pruss-mii", "syscon";
+            reg = <0x32000 0x58>;
+        };
+
+        pruss_mdio: mdio@32400 {
+            compatible = "ti,davinci_mdio";
+            reg = <0x32400 0x90>;
+            clocks = <&dpll_core_m4_ck>;
+            clock-names = "fck";
+            bus_freq = <1000000>;
+            #address-cells = <1>;
+            #size-cells = <0>;
+        };
+    };
+
+  - |
+
+    /* Example 2 AM43xx PRU-ICSS with PRUSS1 node */
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    pruss1: pruss@0 {
+        compatible = "ti,am4376-pruss1";
+        reg = <0x0 0x40000>;
+        #address-cells = <1>;
+        #size-cells = <1>;
+        ranges;
+
+        pruss1_mem: memories@0 {
+            reg = <0x0 0x2000>,
+                  <0x2000 0x2000>,
+                  <0x10000 0x8000>;
+            reg-names = "dram0", "dram1", "shrdram2";
+        };
+
+        pruss1_cfg: cfg@26000 {
+            compatible = "ti,pruss-cfg", "syscon";
+            #address-cells = <1>;
+            #size-cells = <1>;
+            reg = <0x26000 0x2000>;
+            ranges = <0x00 0x26000 0x2000>;
+
+            clocks {
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                pruss1_iepclk_mux: iepclk-mux@30 {
+                    reg = <0x30>;
+                    #clock-cells = <0>;
+                    clocks = <&sysclk_div>,     /* icss_iep */
+                             <&pruss_ocp_gclk>; /* icss_ocp */
+                };
+            };
+        };
+
+        pruss1_mii_rt: mii-rt@32000 {
+            compatible = "ti,pruss-mii", "syscon";
+            reg = <0x32000 0x58>;
+        };
+
+        pruss1_mdio: mdio@32400 {
+            compatible = "ti,davinci_mdio";
+            reg = <0x32400 0x90>;
+            clocks = <&dpll_core_m4_ck>;
+            clock-names = "fck";
+            bus_freq = <1000000>;
+            #address-cells = <1>;
+            #size-cells = <0>;
+        };
+    };
+
+...
index 0b2423a..bfa9054 100644 (file)
@@ -3482,6 +3482,7 @@ F:        arch/mips/bmips/*
 F:     arch/mips/boot/dts/brcm/bcm*.dts*
 F:     arch/mips/include/asm/mach-bmips/*
 F:     arch/mips/kernel/*bmips*
+F:     drivers/soc/bcm/bcm63xx
 F:     drivers/irqchip/irq-bcm63*
 F:     drivers/irqchip/irq-bcm7*
 F:     drivers/irqchip/irq-brcmstb*
index beec241..5acb49b 100644 (file)
                        status = "disabled";
                };
 
+               periph_pwr: power-controller@1000184c {
+                       compatible = "brcm,bcm6328-power-controller";
+                       reg = <0x1000184c 0x4>;
+                       #power-domain-cells = <1>;
+               };
+
                ehci: usb@10002500 {
                        compatible = "brcm,bcm63268-ehci", "generic-ehci";
                        reg = <0x10002500 0x100>;
index af860d0..1f9edd7 100644 (file)
                        status = "disabled";
                };
 
+               periph_pwr: power-controller@10001848 {
+                       compatible = "brcm,bcm6328-power-controller";
+                       reg = <0x10001848 0x4>;
+                       #power-domain-cells = <1>;
+               };
+
                ehci: usb@10002500 {
                        compatible = "brcm,bcm6328-ehci", "generic-ehci";
                        reg = <0x10002500 0x100>;
index 8ae6981..c98f911 100644 (file)
                        status = "disabled";
                };
 
+               periph_pwr: power-controller@10001848 {
+                       compatible = "brcm,bcm6362-power-controller";
+                       reg = <0x10001848 0x4>;
+                       #power-domain-cells = <1>;
+               };
+
                leds0: led-controller@10001900 {
                        #address-cells = <1>;
                        #size-cells = <0>;
index ec1004c..7355fa2 100644 (file)
 #define  ARB_ERR_CAP_STATUS_WRITE      (1 << 1)
 #define  ARB_ERR_CAP_STATUS_VALID      (1 << 0)
 
+#define  ARB_BP_CAP_CLEAR              (1 << 0)
+#define  ARB_BP_CAP_STATUS_PROT_SHIFT  14
+#define  ARB_BP_CAP_STATUS_TYPE                (1 << 13)
+#define  ARB_BP_CAP_STATUS_RSP_SHIFT   10
+#define  ARB_BP_CAP_STATUS_MASK                GENMASK(1, 0)
+#define  ARB_BP_CAP_STATUS_BS_SHIFT    2
+#define  ARB_BP_CAP_STATUS_WRITE       (1 << 1)
+#define  ARB_BP_CAP_STATUS_VALID       (1 << 0)
+
 enum {
        ARB_TIMER,
+       ARB_BP_CAP_CLR,
+       ARB_BP_CAP_HI_ADDR,
+       ARB_BP_CAP_ADDR,
+       ARB_BP_CAP_STATUS,
+       ARB_BP_CAP_MASTER,
        ARB_ERR_CAP_CLR,
        ARB_ERR_CAP_HI_ADDR,
        ARB_ERR_CAP_ADDR,
@@ -41,6 +55,11 @@ enum {
 
 static const int gisb_offsets_bcm7038[] = {
        [ARB_TIMER]             = 0x00c,
+       [ARB_BP_CAP_CLR]        = 0x014,
+       [ARB_BP_CAP_HI_ADDR]    = -1,
+       [ARB_BP_CAP_ADDR]       = 0x0b8,
+       [ARB_BP_CAP_STATUS]     = 0x0c0,
+       [ARB_BP_CAP_MASTER]     = -1,
        [ARB_ERR_CAP_CLR]       = 0x0c4,
        [ARB_ERR_CAP_HI_ADDR]   = -1,
        [ARB_ERR_CAP_ADDR]      = 0x0c8,
@@ -50,6 +69,11 @@ static const int gisb_offsets_bcm7038[] = {
 
 static const int gisb_offsets_bcm7278[] = {
        [ARB_TIMER]             = 0x008,
+       [ARB_BP_CAP_CLR]        = 0x01c,
+       [ARB_BP_CAP_HI_ADDR]    = -1,
+       [ARB_BP_CAP_ADDR]       = 0x220,
+       [ARB_BP_CAP_STATUS]     = 0x230,
+       [ARB_BP_CAP_MASTER]     = 0x234,
        [ARB_ERR_CAP_CLR]       = 0x7f8,
        [ARB_ERR_CAP_HI_ADDR]   = -1,
        [ARB_ERR_CAP_ADDR]      = 0x7e0,
@@ -59,6 +83,11 @@ static const int gisb_offsets_bcm7278[] = {
 
 static const int gisb_offsets_bcm7400[] = {
        [ARB_TIMER]             = 0x00c,
+       [ARB_BP_CAP_CLR]        = 0x014,
+       [ARB_BP_CAP_HI_ADDR]    = -1,
+       [ARB_BP_CAP_ADDR]       = 0x0b8,
+       [ARB_BP_CAP_STATUS]     = 0x0c0,
+       [ARB_BP_CAP_MASTER]     = 0x0c4,
        [ARB_ERR_CAP_CLR]       = 0x0c8,
        [ARB_ERR_CAP_HI_ADDR]   = -1,
        [ARB_ERR_CAP_ADDR]      = 0x0cc,
@@ -68,6 +97,11 @@ static const int gisb_offsets_bcm7400[] = {
 
 static const int gisb_offsets_bcm7435[] = {
        [ARB_TIMER]             = 0x00c,
+       [ARB_BP_CAP_CLR]        = 0x014,
+       [ARB_BP_CAP_HI_ADDR]    = -1,
+       [ARB_BP_CAP_ADDR]       = 0x158,
+       [ARB_BP_CAP_STATUS]     = 0x160,
+       [ARB_BP_CAP_MASTER]     = 0x164,
        [ARB_ERR_CAP_CLR]       = 0x168,
        [ARB_ERR_CAP_HI_ADDR]   = -1,
        [ARB_ERR_CAP_ADDR]      = 0x16c,
@@ -77,6 +111,11 @@ static const int gisb_offsets_bcm7435[] = {
 
 static const int gisb_offsets_bcm7445[] = {
        [ARB_TIMER]             = 0x008,
+       [ARB_BP_CAP_CLR]        = 0x010,
+       [ARB_BP_CAP_HI_ADDR]    = -1,
+       [ARB_BP_CAP_ADDR]       = 0x1d8,
+       [ARB_BP_CAP_STATUS]     = 0x1e0,
+       [ARB_BP_CAP_MASTER]     = 0x1e4,
        [ARB_ERR_CAP_CLR]       = 0x7e4,
        [ARB_ERR_CAP_HI_ADDR]   = 0x7e8,
        [ARB_ERR_CAP_ADDR]      = 0x7ec,
@@ -125,6 +164,16 @@ static u64 gisb_read_address(struct brcmstb_gisb_arb_device *gdev)
        return value;
 }
 
+static u64 gisb_read_bp_address(struct brcmstb_gisb_arb_device *gdev)
+{
+       u64 value;
+
+       value = gisb_read(gdev, ARB_BP_CAP_ADDR);
+       value |= (u64)gisb_read(gdev, ARB_BP_CAP_HI_ADDR) << 32;
+
+       return value;
+}
+
 static void gisb_write(struct brcmstb_gisb_arb_device *gdev, u32 val, int reg)
 {
        int offset = gdev->gisb_offsets[reg];
@@ -210,8 +259,8 @@ static int brcmstb_gisb_arb_decode_addr(struct brcmstb_gisb_arb_device *gdev,
                m_name = m_fmt;
        }
 
-       pr_crit("%s: %s at 0x%llx [%c %s], core: %s\n",
-               __func__, reason, arb_addr,
+       pr_crit("GISB: %s at 0x%llx [%c %s], core: %s\n",
+               reason, arb_addr,
                cap_status & ARB_ERR_CAP_STATUS_WRITE ? 'W' : 'R',
                cap_status & ARB_ERR_CAP_STATUS_TIMEOUT ? "timeout" : "",
                m_name);
@@ -259,6 +308,41 @@ static irqreturn_t brcmstb_gisb_tea_handler(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
+static irqreturn_t brcmstb_gisb_bp_handler(int irq, void *dev_id)
+{
+       struct brcmstb_gisb_arb_device *gdev = dev_id;
+       const char *m_name;
+       u32 bp_status;
+       u64 arb_addr;
+       u32 master;
+       char m_fmt[11];
+
+       bp_status = gisb_read(gdev, ARB_BP_CAP_STATUS);
+
+       /* Invalid captured address, bail out */
+       if (!(bp_status & ARB_BP_CAP_STATUS_VALID))
+               return IRQ_HANDLED;
+
+       /* Read the address and master */
+       arb_addr = gisb_read_bp_address(gdev);
+       master = gisb_read(gdev, ARB_BP_CAP_MASTER);
+
+       m_name = brcmstb_gisb_master_to_str(gdev, master);
+       if (!m_name) {
+               snprintf(m_fmt, sizeof(m_fmt), "0x%08x", master);
+               m_name = m_fmt;
+       }
+
+       pr_crit("GISB: breakpoint at 0x%llx [%c], core: %s\n",
+               arb_addr, bp_status & ARB_BP_CAP_STATUS_WRITE ? 'W' : 'R',
+               m_name);
+
+       /* clear the GISB error */
+       gisb_write(gdev, ARB_ERR_CAP_CLEAR, ARB_ERR_CAP_CLR);
+
+       return IRQ_HANDLED;
+}
+
 /*
  * Dump out gisb errors on die or panic.
  */
@@ -317,13 +401,14 @@ static int __init brcmstb_gisb_arb_probe(struct platform_device *pdev)
        struct brcmstb_gisb_arb_device *gdev;
        const struct of_device_id *of_id;
        struct resource *r;
-       int err, timeout_irq, tea_irq;
+       int err, timeout_irq, tea_irq, bp_irq;
        unsigned int num_masters, j = 0;
        int i, first, last;
 
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        timeout_irq = platform_get_irq(pdev, 0);
        tea_irq = platform_get_irq(pdev, 1);
+       bp_irq = platform_get_irq(pdev, 2);
 
        gdev = devm_kzalloc(&pdev->dev, sizeof(*gdev), GFP_KERNEL);
        if (!gdev)
@@ -356,6 +441,15 @@ static int __init brcmstb_gisb_arb_probe(struct platform_device *pdev)
        if (err < 0)
                return err;
 
+       /* Interrupt is optional */
+       if (bp_irq > 0) {
+               err = devm_request_irq(&pdev->dev, bp_irq,
+                                      brcmstb_gisb_bp_handler, 0, pdev->name,
+                                      gdev);
+               if (err < 0)
+                       return err;
+       }
+
        /* If we do not have a valid mask, assume all masters are enabled */
        if (of_property_read_u32(dn, "brcm,gisb-arb-master-mask",
                                &gdev->valid_mask))
index 6dd1311..e855e86 100644 (file)
@@ -29,7 +29,7 @@ static const struct scmi_handle *handle;
 static unsigned int scmi_cpufreq_get_rate(unsigned int cpu)
 {
        struct cpufreq_policy *policy = cpufreq_cpu_get_raw(cpu);
-       struct scmi_perf_ops *perf_ops = handle->perf_ops;
+       const struct scmi_perf_ops *perf_ops = handle->perf_ops;
        struct scmi_data *priv = policy->driver_data;
        unsigned long rate;
        int ret;
@@ -49,7 +49,7 @@ static int
 scmi_cpufreq_set_target(struct cpufreq_policy *policy, unsigned int index)
 {
        struct scmi_data *priv = policy->driver_data;
-       struct scmi_perf_ops *perf_ops = handle->perf_ops;
+       const struct scmi_perf_ops *perf_ops = handle->perf_ops;
        u64 freq = policy->freq_table[index].frequency;
 
        return perf_ops->freq_set(handle, priv->domain_id, freq * 1000, false);
@@ -59,7 +59,7 @@ static unsigned int scmi_cpufreq_fast_switch(struct cpufreq_policy *policy,
                                             unsigned int target_freq)
 {
        struct scmi_data *priv = policy->driver_data;
-       struct scmi_perf_ops *perf_ops = handle->perf_ops;
+       const struct scmi_perf_ops *perf_ops = handle->perf_ops;
 
        if (!perf_ops->freq_set(handle, priv->domain_id,
                                target_freq * 1000, true))
index 42c8ad1..a367584 100644 (file)
@@ -573,8 +573,8 @@ static int k3_udma_glue_cfg_rx_flow(struct k3_udma_glue_rx_channel *rx_chn,
 
        /* request and cfg rings */
        ret =  k3_ringacc_request_rings_pair(rx_chn->common.ringacc,
-                                            flow_cfg->ring_rxq_id,
                                             flow_cfg->ring_rxfdq0_id,
+                                            flow_cfg->ring_rxq_id,
                                             &flow->ringrxfdq,
                                             &flow->ringrx);
        if (ret) {
index d78dd3c..3315e3c 100644 (file)
@@ -7,7 +7,7 @@
 menu "Firmware Drivers"
 
 config ARM_SCMI_PROTOCOL
-       bool "ARM System Control and Management Interface (SCMI) Message Protocol"
+       tristate "ARM System Control and Management Interface (SCMI) Message Protocol"
        depends on ARM || ARM64 || COMPILE_TEST
        depends on MAILBOX
        help
index 99510be..5e013b6 100644 (file)
@@ -22,7 +22,7 @@ obj-$(CONFIG_TI_SCI_PROTOCOL) += ti_sci.o
 obj-$(CONFIG_TRUSTED_FOUNDATIONS) += trusted_foundations.o
 obj-$(CONFIG_TURRIS_MOX_RWTM)  += turris-mox-rwtm.o
 
-obj-$(CONFIG_ARM_SCMI_PROTOCOL)        += arm_scmi/
+obj-y                          += arm_scmi/
 obj-y                          += broadcom/
 obj-y                          += meson/
 obj-$(CONFIG_GOOGLE_FIRMWARE)  += google/
index 6f9cbc4..bc0d54f 100644 (file)
@@ -1,9 +1,11 @@
 # SPDX-License-Identifier: GPL-2.0-only
-obj-y  = scmi-bus.o scmi-driver.o scmi-protocols.o scmi-transport.o
 scmi-bus-y = bus.o
 scmi-driver-y = driver.o notify.o
 scmi-transport-y = shmem.o
 scmi-transport-$(CONFIG_MAILBOX) += mailbox.o
 scmi-transport-$(CONFIG_HAVE_ARM_SMCCC_DISCOVERY) += smc.o
-scmi-protocols-y = base.o clock.o perf.o power.o reset.o sensors.o
+scmi-protocols-y = base.o clock.o perf.o power.o reset.o sensors.o system.o
+scmi-module-objs := $(scmi-bus-y) $(scmi-driver-y) $(scmi-protocols-y) \
+                   $(scmi-transport-y)
+obj-$(CONFIG_ARM_SCMI_PROTOCOL) += scmi-module.o
 obj-$(CONFIG_ARM_SCMI_POWER_DOMAIN) += scmi_pm_domain.o
index db55c43..1377ec7 100644 (file)
@@ -230,7 +230,7 @@ static void scmi_devices_unregister(void)
        bus_for_each_dev(&scmi_bus_type, NULL, NULL, __scmi_devices_unregister);
 }
 
-static int __init scmi_bus_init(void)
+int __init scmi_bus_init(void)
 {
        int retval;
 
@@ -240,12 +240,10 @@ static int __init scmi_bus_init(void)
 
        return retval;
 }
-subsys_initcall(scmi_bus_init);
 
-static void __exit scmi_bus_exit(void)
+void __exit scmi_bus_exit(void)
 {
        scmi_devices_unregister();
        bus_unregister(&scmi_bus_type);
        ida_destroy(&scmi_bus_id);
 }
-module_exit(scmi_bus_exit);
index 75e3988..c1cfe3e 100644 (file)
@@ -318,7 +318,7 @@ scmi_clock_info_get(const struct scmi_handle *handle, u32 clk_id)
        return clk;
 }
 
-static struct scmi_clk_ops clk_ops = {
+static const struct scmi_clk_ops clk_ops = {
        .count_get = scmi_clock_count_get,
        .info_get = scmi_clock_info_get,
        .rate_get = scmi_clock_rate_get,
@@ -364,9 +364,4 @@ static int scmi_clock_protocol_init(struct scmi_handle *handle)
        return 0;
 }
 
-static int __init scmi_clock_init(void)
-{
-       return scmi_protocol_register(SCMI_PROTOCOL_CLOCK,
-                                     &scmi_clock_protocol_init);
-}
-subsys_initcall(scmi_clock_init);
+DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(SCMI_PROTOCOL_CLOCK, clock)
index c113e57..37fb583 100644 (file)
@@ -156,6 +156,30 @@ void scmi_setup_protocol_implemented(const struct scmi_handle *handle,
 
 int scmi_base_protocol_init(struct scmi_handle *h);
 
+int __init scmi_bus_init(void);
+void __exit scmi_bus_exit(void);
+
+#define DECLARE_SCMI_REGISTER_UNREGISTER(func)         \
+       int __init scmi_##func##_register(void);        \
+       void __exit scmi_##func##_unregister(void)
+DECLARE_SCMI_REGISTER_UNREGISTER(clock);
+DECLARE_SCMI_REGISTER_UNREGISTER(perf);
+DECLARE_SCMI_REGISTER_UNREGISTER(power);
+DECLARE_SCMI_REGISTER_UNREGISTER(reset);
+DECLARE_SCMI_REGISTER_UNREGISTER(sensors);
+DECLARE_SCMI_REGISTER_UNREGISTER(system);
+
+#define DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(id, name) \
+int __init scmi_##name##_register(void) \
+{ \
+       return scmi_protocol_register((id), &scmi_##name##_protocol_init); \
+} \
+\
+void __exit scmi_##name##_unregister(void) \
+{ \
+       scmi_protocol_unregister((id)); \
+}
+
 /* SCMI Transport */
 /**
  * struct scmi_chan_info - Structure representing a SCMI channel information
@@ -210,7 +234,7 @@ struct scmi_transport_ops {
  * @max_msg_size: Maximum size of data per message that can be handled.
  */
 struct scmi_desc {
-       struct scmi_transport_ops *ops;
+       const struct scmi_transport_ops *ops;
        int max_rx_timeout_ms;
        int max_msg;
        int max_msg_size;
index 03ec742..c5dea87 100644 (file)
@@ -730,6 +730,7 @@ struct scmi_prot_devnames {
 
 static struct scmi_prot_devnames devnames[] = {
        { SCMI_PROTOCOL_POWER,  { "genpd" },},
+       { SCMI_PROTOCOL_SYSTEM, { "syspower" },},
        { SCMI_PROTOCOL_PERF,   { "cpufreq" },},
        { SCMI_PROTOCOL_CLOCK,  { "clocks" },},
        { SCMI_PROTOCOL_SENSOR, { "hwmon" },},
@@ -928,7 +929,35 @@ static struct platform_driver scmi_driver = {
        .remove = scmi_remove,
 };
 
-module_platform_driver(scmi_driver);
+static int __init scmi_driver_init(void)
+{
+       scmi_bus_init();
+
+       scmi_clock_register();
+       scmi_perf_register();
+       scmi_power_register();
+       scmi_reset_register();
+       scmi_sensors_register();
+       scmi_system_register();
+
+       return platform_driver_register(&scmi_driver);
+}
+subsys_initcall(scmi_driver_init);
+
+static void __exit scmi_driver_exit(void)
+{
+       scmi_bus_exit();
+
+       scmi_clock_unregister();
+       scmi_perf_unregister();
+       scmi_power_unregister();
+       scmi_reset_unregister();
+       scmi_sensors_unregister();
+       scmi_system_unregister();
+
+       platform_driver_unregister(&scmi_driver);
+}
+module_exit(scmi_driver_exit);
 
 MODULE_ALIAS("platform: arm-scmi");
 MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");
index 6998dc8..4626404 100644 (file)
@@ -110,7 +110,7 @@ static int mailbox_chan_free(int id, void *p, void *data)
        struct scmi_chan_info *cinfo = p;
        struct scmi_mailbox *smbox = cinfo->transport_info;
 
-       if (!IS_ERR(smbox->chan)) {
+       if (smbox && !IS_ERR(smbox->chan)) {
                mbox_free_channel(smbox->chan);
                cinfo->transport_info = NULL;
                smbox->chan = NULL;
@@ -181,7 +181,7 @@ mailbox_poll_done(struct scmi_chan_info *cinfo, struct scmi_xfer *xfer)
        return shmem_poll_done(smbox->shmem, xfer);
 }
 
-static struct scmi_transport_ops scmi_mailbox_ops = {
+static const struct scmi_transport_ops scmi_mailbox_ops = {
        .chan_available = mailbox_chan_available,
        .chan_setup = mailbox_chan_setup,
        .chan_free = mailbox_chan_free,
index 4731daa..2754f9d 100644 (file)
@@ -1421,7 +1421,7 @@ static void scmi_protocols_late_init(struct work_struct *work)
  * notify_ops are attached to the handle so that can be accessed
  * directly from an scmi_driver to register its own notifiers.
  */
-static struct scmi_notify_ops notify_ops = {
+static const struct scmi_notify_ops notify_ops = {
        .register_event_notifier = scmi_register_notifier,
        .unregister_event_notifier = scmi_unregister_notifier,
 };
index 3e1e870..ed475b4 100644 (file)
@@ -748,7 +748,7 @@ static bool scmi_fast_switch_possible(const struct scmi_handle *handle,
        return dom->fc_info && dom->fc_info->level_set_addr;
 }
 
-static struct scmi_perf_ops perf_ops = {
+static const struct scmi_perf_ops perf_ops = {
        .limits_set = scmi_perf_limits_set,
        .limits_get = scmi_perf_limits_get,
        .level_set = scmi_perf_level_set,
@@ -890,9 +890,4 @@ static int scmi_perf_protocol_init(struct scmi_handle *handle)
        return 0;
 }
 
-static int __init scmi_perf_init(void)
-{
-       return scmi_protocol_register(SCMI_PROTOCOL_PERF,
-                                     &scmi_perf_protocol_init);
-}
-subsys_initcall(scmi_perf_init);
+DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(SCMI_PROTOCOL_PERF, perf)
index 46f2136..1f37258 100644 (file)
@@ -184,7 +184,7 @@ static char *scmi_power_name_get(const struct scmi_handle *handle, u32 domain)
        return dom->name;
 }
 
-static struct scmi_power_ops power_ops = {
+static const struct scmi_power_ops power_ops = {
        .num_domains_get = scmi_power_num_domains_get,
        .name_get = scmi_power_name_get,
        .state_set = scmi_power_state_set,
@@ -301,9 +301,4 @@ static int scmi_power_protocol_init(struct scmi_handle *handle)
        return 0;
 }
 
-static int __init scmi_power_init(void)
-{
-       return scmi_protocol_register(SCMI_PROTOCOL_POWER,
-                                     &scmi_power_protocol_init);
-}
-subsys_initcall(scmi_power_init);
+DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(SCMI_PROTOCOL_POWER, power)
index 3691baf..f063cfe 100644 (file)
@@ -194,7 +194,7 @@ scmi_reset_domain_deassert(const struct scmi_handle *handle, u32 domain)
        return scmi_domain_reset(handle, domain, 0, ARCH_COLD_RESET);
 }
 
-static struct scmi_reset_ops reset_ops = {
+static const struct scmi_reset_ops reset_ops = {
        .num_domains_get = scmi_reset_num_domains_get,
        .name_get = scmi_reset_name_get,
        .latency_get = scmi_reset_latency_get,
@@ -313,9 +313,4 @@ static int scmi_reset_protocol_init(struct scmi_handle *handle)
        return 0;
 }
 
-static int __init scmi_reset_init(void)
-{
-       return scmi_protocol_register(SCMI_PROTOCOL_RESET,
-                                     &scmi_reset_protocol_init);
-}
-subsys_initcall(scmi_reset_init);
+DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(SCMI_PROTOCOL_RESET, reset)
index 1af0ad3..9703cf6 100644 (file)
@@ -275,7 +275,7 @@ static int scmi_sensor_count_get(const struct scmi_handle *handle)
        return si->num_sensors;
 }
 
-static struct scmi_sensor_ops sensor_ops = {
+static const struct scmi_sensor_ops sensor_ops = {
        .count_get = scmi_sensor_count_get,
        .info_get = scmi_sensor_info_get,
        .trip_point_config = scmi_sensor_trip_point_config,
@@ -365,9 +365,4 @@ static int scmi_sensors_protocol_init(struct scmi_handle *handle)
        return 0;
 }
 
-static int __init scmi_sensors_init(void)
-{
-       return scmi_protocol_register(SCMI_PROTOCOL_SENSOR,
-                                     &scmi_sensors_protocol_init);
-}
-subsys_initcall(scmi_sensors_init);
+DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(SCMI_PROTOCOL_SENSOR, sensors)
index a1537d1..1a03c3e 100644 (file)
@@ -137,7 +137,7 @@ smc_poll_done(struct scmi_chan_info *cinfo, struct scmi_xfer *xfer)
        return shmem_poll_done(scmi_info->shmem, xfer);
 }
 
-static struct scmi_transport_ops scmi_smc_ops = {
+static const struct scmi_transport_ops scmi_smc_ops = {
        .chan_available = smc_chan_available,
        .chan_setup = smc_chan_setup,
        .chan_free = smc_chan_free,
diff --git a/drivers/firmware/arm_scmi/system.c b/drivers/firmware/arm_scmi/system.c
new file mode 100644 (file)
index 0000000..283e12d
--- /dev/null
@@ -0,0 +1,131 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * System Control and Management Interface (SCMI) System Power Protocol
+ *
+ * Copyright (C) 2020 ARM Ltd.
+ */
+
+#define pr_fmt(fmt) "SCMI Notifications SYSTEM - " fmt
+
+#include <linux/scmi_protocol.h>
+
+#include "common.h"
+#include "notify.h"
+
+#define SCMI_SYSTEM_NUM_SOURCES                1
+
+enum scmi_system_protocol_cmd {
+       SYSTEM_POWER_STATE_NOTIFY = 0x5,
+};
+
+struct scmi_system_power_state_notify {
+       __le32 notify_enable;
+};
+
+struct scmi_system_power_state_notifier_payld {
+       __le32 agent_id;
+       __le32 flags;
+       __le32 system_state;
+};
+
+struct scmi_system_info {
+       u32 version;
+};
+
+static int scmi_system_request_notify(const struct scmi_handle *handle,
+                                     bool enable)
+{
+       int ret;
+       struct scmi_xfer *t;
+       struct scmi_system_power_state_notify *notify;
+
+       ret = scmi_xfer_get_init(handle, SYSTEM_POWER_STATE_NOTIFY,
+                                SCMI_PROTOCOL_SYSTEM, sizeof(*notify), 0, &t);
+       if (ret)
+               return ret;
+
+       notify = t->tx.buf;
+       notify->notify_enable = enable ? cpu_to_le32(BIT(0)) : 0;
+
+       ret = scmi_do_xfer(handle, t);
+
+       scmi_xfer_put(handle, t);
+       return ret;
+}
+
+static int scmi_system_set_notify_enabled(const struct scmi_handle *handle,
+                                         u8 evt_id, u32 src_id, bool enable)
+{
+       int ret;
+
+       ret = scmi_system_request_notify(handle, enable);
+       if (ret)
+               pr_debug("FAIL_ENABLE - evt[%X] - ret:%d\n", evt_id, ret);
+
+       return ret;
+}
+
+static void *scmi_system_fill_custom_report(const struct scmi_handle *handle,
+                                           u8 evt_id, ktime_t timestamp,
+                                           const void *payld, size_t payld_sz,
+                                           void *report, u32 *src_id)
+{
+       const struct scmi_system_power_state_notifier_payld *p = payld;
+       struct scmi_system_power_state_notifier_report *r = report;
+
+       if (evt_id != SCMI_EVENT_SYSTEM_POWER_STATE_NOTIFIER ||
+           sizeof(*p) != payld_sz)
+               return NULL;
+
+       r->timestamp = timestamp;
+       r->agent_id = le32_to_cpu(p->agent_id);
+       r->flags = le32_to_cpu(p->flags);
+       r->system_state = le32_to_cpu(p->system_state);
+       *src_id = 0;
+
+       return r;
+}
+
+static const struct scmi_event system_events[] = {
+       {
+               .id = SCMI_EVENT_SYSTEM_POWER_STATE_NOTIFIER,
+               .max_payld_sz =
+                       sizeof(struct scmi_system_power_state_notifier_payld),
+               .max_report_sz =
+                       sizeof(struct scmi_system_power_state_notifier_report),
+       },
+};
+
+static const struct scmi_event_ops system_event_ops = {
+       .set_notify_enabled = scmi_system_set_notify_enabled,
+       .fill_custom_report = scmi_system_fill_custom_report,
+};
+
+static int scmi_system_protocol_init(struct scmi_handle *handle)
+{
+       u32 version;
+       struct scmi_system_info *pinfo;
+
+       scmi_version_get(handle, SCMI_PROTOCOL_SYSTEM, &version);
+
+       dev_dbg(handle->dev, "System Power Version %d.%d\n",
+               PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
+
+       pinfo = devm_kzalloc(handle->dev, sizeof(*pinfo), GFP_KERNEL);
+       if (!pinfo)
+               return -ENOMEM;
+
+       scmi_register_protocol_events(handle,
+                                     SCMI_PROTOCOL_SYSTEM, SCMI_PROTO_QUEUE_SZ,
+                                     &system_event_ops,
+                                     system_events,
+                                     ARRAY_SIZE(system_events),
+                                     SCMI_SYSTEM_NUM_SOURCES);
+
+       pinfo->version = version;
+       handle->system_priv = pinfo;
+
+       return 0;
+}
+
+DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(SCMI_PROTOCOL_SYSTEM, system)
index af3d6d9..946eea2 100644 (file)
@@ -46,6 +46,7 @@
 
 #include <dt-bindings/firmware/imx/rsrc.h>
 #include <linux/firmware/imx/sci.h>
+#include <linux/firmware/imx/svc/rm.h>
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/of.h>
@@ -256,6 +257,9 @@ imx_scu_add_pm_domain(struct device *dev, int idx,
        struct imx_sc_pm_domain *sc_pd;
        int ret;
 
+       if (!imx_sc_rm_is_resource_owned(pm_ipc_handle, pd_ranges->rsrc + idx))
+               return NULL;
+
        sc_pd = devm_kzalloc(dev, sizeof(*sc_pd), GFP_KERNEL);
        if (!sc_pd)
                return ERR_PTR(-ENOMEM);
index 4e80921..00c88b8 100644 (file)
@@ -24,8 +24,10 @@ enum arm_smccc_conduit arm_smccc_1_1_get_conduit(void)
 
        return smccc_conduit;
 }
+EXPORT_SYMBOL_GPL(arm_smccc_1_1_get_conduit);
 
 u32 arm_smccc_get_version(void)
 {
        return smccc_version;
 }
+EXPORT_SYMBOL_GPL(arm_smccc_get_version);
index 4d93d89..0742a90 100644 (file)
@@ -856,7 +856,8 @@ static const struct tegra_bpmp_soc tegra210_soc = {
 
 static const struct of_device_id tegra_bpmp_match[] = {
 #if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC) || \
-    IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC)
+    IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) || \
+    IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC)
        { .compatible = "nvidia,tegra186-bpmp", .data = &tegra186_soc },
 #endif
 #if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC)
index 722af9e..896f53e 100644 (file)
@@ -1106,7 +1106,8 @@ static int ti_sci_cmd_get_clock(const struct ti_sci_handle *handle, u32 dev_id,
 static int ti_sci_cmd_idle_clock(const struct ti_sci_handle *handle,
                                 u32 dev_id, u32 clk_id)
 {
-       return ti_sci_set_clock_state(handle, dev_id, clk_id, 0,
+       return ti_sci_set_clock_state(handle, dev_id, clk_id,
+                                     MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE,
                                      MSG_CLOCK_SW_STATE_UNREQ);
 }
 
@@ -1125,7 +1126,8 @@ static int ti_sci_cmd_idle_clock(const struct ti_sci_handle *handle,
 static int ti_sci_cmd_put_clock(const struct ti_sci_handle *handle,
                                u32 dev_id, u32 clk_id)
 {
-       return ti_sci_set_clock_state(handle, dev_id, clk_id, 0,
+       return ti_sci_set_clock_state(handle, dev_id, clk_id,
+                                     MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE,
                                      MSG_CLOCK_SW_STATE_AUTO);
 }
 
index 4d29568..ac03857 100644 (file)
@@ -481,7 +481,7 @@ static void mtk_drm_crtc_hw_config(struct mtk_drm_crtc *mtk_crtc)
                mbox_flush(mtk_crtc->cmdq_client->chan, 2000);
                cmdq_handle = cmdq_pkt_create(mtk_crtc->cmdq_client, PAGE_SIZE);
                cmdq_pkt_clear_event(cmdq_handle, mtk_crtc->cmdq_event);
-               cmdq_pkt_wfe(cmdq_handle, mtk_crtc->cmdq_event);
+               cmdq_pkt_wfe(cmdq_handle, mtk_crtc->cmdq_event, false);
                mtk_crtc_ddp_config(crtc, cmdq_handle);
                cmdq_pkt_finalize(cmdq_handle);
                cmdq_pkt_flush_async(cmdq_handle, ddp_cmdq_cb, cmdq_handle);
index 834b35d..e07091d 100644 (file)
@@ -13,6 +13,8 @@
 #include <linux/pm.h>
 #include <linux/slab.h>
 
+#include <soc/tegra/fuse.h>
+
 #include <dt-bindings/mailbox/tegra186-hsp.h>
 
 #include "mailbox.h"
@@ -322,7 +324,12 @@ static int tegra_hsp_doorbell_startup(struct mbox_chan *chan)
        if (!ccplex)
                return -ENODEV;
 
-       if (!tegra_hsp_doorbell_can_ring(db))
+       /*
+        * On simulation platforms the BPMP hasn't had a chance yet to mark
+        * the doorbell as ringable by the CCPLEX, so we want to skip extra
+        * checks here.
+        */
+       if (tegra_is_silicon() && !tegra_hsp_doorbell_can_ring(db))
                return -ENODEV;
 
        spin_lock_irqsave(&hsp->lock, flags);
index 2c79e95..00e013b 100644 (file)
@@ -32,8 +32,9 @@ config ARM_PL172_MPMC
 
 config ATMEL_SDRAMC
        bool "Atmel (Multi-port DDR-)SDRAM Controller"
-       default y
-       depends on ARCH_AT91 && OF
+       default y if ARCH_AT91
+       depends on ARCH_AT91 || COMPILE_TEST
+       depends on OF
        help
          This driver is for Atmel SDRAM Controller or Atmel Multi-port
          DDR-SDRAM Controller available on Atmel AT91SAM9 and SAMA5 SoCs.
@@ -42,8 +43,9 @@ config ATMEL_SDRAMC
 
 config ATMEL_EBI
        bool "Atmel EBI driver"
-       default y
-       depends on ARCH_AT91 && OF
+       default y if ARCH_AT91
+       depends on ARCH_AT91 || COMPILE_TEST
+       depends on OF
        select MFD_SYSCON
        select MFD_ATMEL_SMC
        help
@@ -52,6 +54,18 @@ config ATMEL_EBI
          tree is used. This bus supports NANDs, external ethernet controller,
          SRAMs, ATA devices, etc.
 
+config BRCMSTB_DPFE
+       bool "Broadcom STB DPFE driver" if COMPILE_TEST
+       default y if ARCH_BRCMSTB
+       depends on ARCH_BRCMSTB || COMPILE_TEST
+       help
+         This driver provides access to the DPFE interface of Broadcom
+         STB SoCs. The firmware running on the DCPU inside the DDR PHY can
+         provide current information about the system's RAM, for instance
+         the DRAM refresh rate. This can be used as an indirect indicator
+         for the DRAM's temperature. Slower refresh rate means cooler RAM,
+         higher refresh rate means hotter RAM.
+
 config BT1_L2_CTL
        bool "Baikal-T1 CM2 L2-RAM Cache Control Block"
        depends on MIPS_BAIKAL_T1 || COMPILE_TEST
@@ -65,7 +79,8 @@ config BT1_L2_CTL
 
 config TI_AEMIF
        tristate "Texas Instruments AEMIF driver"
-       depends on (ARCH_DAVINCI || ARCH_KEYSTONE) && OF
+       depends on ARCH_DAVINCI || ARCH_KEYSTONE || COMPILE_TEST
+       depends on OF
        help
          This driver is for the AEMIF module available in Texas Instruments
          SoCs. AEMIF stands for Asynchronous External Memory Interface and
@@ -76,7 +91,7 @@ config TI_AEMIF
 
 config TI_EMIF
        tristate "Texas Instruments EMIF driver"
-       depends on ARCH_OMAP2PLUS
+       depends on ARCH_OMAP2PLUS || COMPILE_TEST
        select DDR
        help
          This driver is for the EMIF module available in Texas Instruments
@@ -88,7 +103,8 @@ config TI_EMIF
          temperature changes
 
 config OMAP_GPMC
-       bool
+       bool "Texas Instruments OMAP SoC GPMC driver" if COMPILE_TEST
+       depends on OF_ADDRESS
        select GPIOLIB
        help
          This driver is for the General Purpose Memory Controller (GPMC)
@@ -112,7 +128,8 @@ config OMAP_GPMC_DEBUG
 
 config TI_EMIF_SRAM
        tristate "Texas Instruments EMIF SRAM driver"
-       depends on (SOC_AM33XX || SOC_AM43XX) && SRAM
+       depends on SOC_AM33XX || SOC_AM43XX || (ARM && COMPILE_TEST)
+       depends on SRAM
        help
          This driver is for the EMIF module available on Texas Instruments
          AM33XX and AM43XX SoCs and is required for PM. Certain parts of
@@ -122,8 +139,9 @@ config TI_EMIF_SRAM
 
 config MVEBU_DEVBUS
        bool "Marvell EBU Device Bus Controller"
-       default y
-       depends on PLAT_ORION && OF
+       default y if PLAT_ORION
+       depends on PLAT_ORION || COMPILE_TEST
+       depends on OF
        help
          This driver is for the Device Bus controller available in some
          Marvell EBU SoCs such as Discovery (mv78xx0), Orion (88f5xxx) and
@@ -132,7 +150,7 @@ config MVEBU_DEVBUS
 
 config FSL_CORENET_CF
        tristate "Freescale CoreNet Error Reporting"
-       depends on FSL_SOC_BOOKE
+       depends on FSL_SOC_BOOKE || COMPILE_TEST
        help
          Say Y for reporting of errors from the Freescale CoreNet
          Coherency Fabric.  Errors reported include accesses to
@@ -141,7 +159,7 @@ config FSL_CORENET_CF
          represents a coherency violation.
 
 config FSL_IFC
-       bool
+       bool "Freescale IFC driver" if COMPILE_TEST
        depends on FSL_SOC || ARCH_LAYERSCAPE || SOC_LS1021A || COMPILE_TEST
        depends on HAS_IOMEM
 
@@ -155,7 +173,7 @@ config JZ4780_NEMC
          memory devices such as NAND and SRAM.
 
 config MTK_SMI
-       bool
+       bool "Mediatek SoC Memory Controller driver" if COMPILE_TEST
        depends on ARCH_MEDIATEK || COMPILE_TEST
        help
          This driver is for the Memory Controller module in MediaTek SoCs,
@@ -164,7 +182,7 @@ config MTK_SMI
 
 config DA8XX_DDRCTL
        bool "Texas Instruments da8xx DDR2/mDDR driver"
-       depends on ARCH_DAVINCI_DA8XX
+       depends on ARCH_DAVINCI_DA8XX || COMPILE_TEST
        help
          This driver is for the DDR2/mDDR Memory Controller present on
          Texas Instruments da8xx SoCs. It's used to tweak various memory
@@ -172,16 +190,16 @@ config DA8XX_DDRCTL
 
 config PL353_SMC
        tristate "ARM PL35X Static Memory Controller(SMC) driver"
-       default y
+       default y if ARM
        depends on ARM
-       depends on ARM_AMBA
+       depends on ARM_AMBA || COMPILE_TEST
        help
          This driver is for the ARM PL351/PL353 Static Memory
          Controller(SMC) module.
 
 config RENESAS_RPCIF
        tristate "Renesas RPC-IF driver"
-       depends on ARCH_RENESAS
+       depends on ARCH_RENESAS || COMPILE_TEST
        select REGMAP_MMIO
        help
          This supports Renesas R-Car Gen3 RPC-IF which provides either SPI
index b4533ff..e71cf7b 100644 (file)
@@ -10,7 +10,7 @@ endif
 obj-$(CONFIG_ARM_PL172_MPMC)   += pl172.o
 obj-$(CONFIG_ATMEL_SDRAMC)     += atmel-sdramc.o
 obj-$(CONFIG_ATMEL_EBI)                += atmel-ebi.o
-obj-$(CONFIG_ARCH_BRCMSTB)     += brcmstb_dpfe.o
+obj-$(CONFIG_BRCMSTB_DPFE)     += brcmstb_dpfe.o
 obj-$(CONFIG_BT1_L2_CTL)       += bt1-l2-ctl.o
 obj-$(CONFIG_TI_AEMIF)         += ti-aemif.o
 obj-$(CONFIG_TI_EMIF)          += emif.o
index 60e8633..f43ba69 100644 (file)
@@ -188,11 +188,6 @@ struct brcmstb_dpfe_priv {
        struct mutex lock;
 };
 
-static const char * const error_text[] = {
-       "Success", "Header code incorrect", "Unknown command or argument",
-       "Incorrect checksum", "Malformed command", "Timed out",
-};
-
 /*
  * Forward declaration of our sysfs attribute functions, so we can declare the
  * attribute data structures early.
@@ -307,6 +302,20 @@ static const struct dpfe_api dpfe_api_v3 = {
        },
 };
 
+static const char *get_error_text(unsigned int i)
+{
+       static const char * const error_text[] = {
+               "Success", "Header code incorrect",
+               "Unknown command or argument", "Incorrect checksum",
+               "Malformed command", "Timed out", "Unknown error",
+       };
+
+       if (unlikely(i >= ARRAY_SIZE(error_text)))
+               i = ARRAY_SIZE(error_text) - 1;
+
+       return error_text[i];
+}
+
 static bool is_dcpu_enabled(struct brcmstb_dpfe_priv *priv)
 {
        u32 val;
@@ -445,7 +454,7 @@ static int __send_command(struct brcmstb_dpfe_priv *priv, unsigned int cmd,
        }
        if (resp != 0) {
                mutex_unlock(&priv->lock);
-               return -ETIMEDOUT;
+               return -ffs(DCPU_RET_ERR_TIMEDOUT);
        }
 
        /* Compute checksum over the message */
@@ -647,8 +656,10 @@ static int brcmstb_dpfe_download_firmware(struct brcmstb_dpfe_priv *priv)
                return (ret == -ENOENT) ? -EPROBE_DEFER : ret;
 
        ret = __verify_firmware(&init, fw);
-       if (ret)
-               return -EFAULT;
+       if (ret) {
+               ret = -EFAULT;
+               goto release_fw;
+       }
 
        __disable_dcpu(priv);
 
@@ -667,18 +678,20 @@ static int brcmstb_dpfe_download_firmware(struct brcmstb_dpfe_priv *priv)
 
        ret = __write_firmware(priv->dmem, dmem, dmem_size, is_big_endian);
        if (ret)
-               return ret;
+               goto release_fw;
        ret = __write_firmware(priv->imem, imem, imem_size, is_big_endian);
        if (ret)
-               return ret;
+               goto release_fw;
 
        ret = __verify_fw_checksum(&init, priv, header, init.chksum);
        if (ret)
-               return ret;
+               goto release_fw;
 
        __enable_dcpu(priv);
 
-       return 0;
+release_fw:
+       release_firmware(fw);
+       return ret;
 }
 
 static ssize_t generic_show(unsigned int command, u32 response[],
@@ -691,7 +704,7 @@ static ssize_t generic_show(unsigned int command, u32 response[],
 
        ret = __send_command(priv, command, response);
        if (ret < 0)
-               return sprintf(buf, "ERROR: %s\n", error_text[-ret]);
+               return sprintf(buf, "ERROR: %s\n", get_error_text(-ret));
 
        return 0;
 }
@@ -888,11 +901,8 @@ static int brcmstb_dpfe_probe(struct platform_device *pdev)
        }
 
        ret = brcmstb_dpfe_download_firmware(priv);
-       if (ret) {
-               if (ret != -EPROBE_DEFER)
-                       dev_err(dev, "Couldn't download firmware -- %d\n", ret);
-               return ret;
-       }
+       if (ret)
+               return dev_err_probe(dev, ret, "Couldn't download firmware\n");
 
        ret = sysfs_create_groups(&pdev->dev.kobj, priv->dpfe_api->sysfs_attrs);
        if (!ret)
index bb6a71d..ddb1879 100644 (file)
@@ -131,16 +131,7 @@ static int emif_regdump_show(struct seq_file *s, void *unused)
        return 0;
 }
 
-static int emif_regdump_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, emif_regdump_show, inode->i_private);
-}
-
-static const struct file_operations emif_regdump_fops = {
-       .open                   = emif_regdump_open,
-       .read                   = seq_read,
-       .release                = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(emif_regdump);
 
 static int emif_mr4_show(struct seq_file *s, void *unused)
 {
@@ -150,48 +141,16 @@ static int emif_mr4_show(struct seq_file *s, void *unused)
        return 0;
 }
 
-static int emif_mr4_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, emif_mr4_show, inode->i_private);
-}
-
-static const struct file_operations emif_mr4_fops = {
-       .open                   = emif_mr4_open,
-       .read                   = seq_read,
-       .release                = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(emif_mr4);
 
 static int __init_or_module emif_debugfs_init(struct emif_data *emif)
 {
-       struct dentry   *dentry;
-       int             ret;
-
-       dentry = debugfs_create_dir(dev_name(emif->dev), NULL);
-       if (!dentry) {
-               ret = -ENOMEM;
-               goto err0;
-       }
-       emif->debugfs_root = dentry;
-
-       dentry = debugfs_create_file("regcache_dump", S_IRUGO,
-                       emif->debugfs_root, emif, &emif_regdump_fops);
-       if (!dentry) {
-               ret = -ENOMEM;
-               goto err1;
-       }
-
-       dentry = debugfs_create_file("mr4", S_IRUGO,
-                       emif->debugfs_root, emif, &emif_mr4_fops);
-       if (!dentry) {
-               ret = -ENOMEM;
-               goto err1;
-       }
-
+       emif->debugfs_root = debugfs_create_dir(dev_name(emif->dev), NULL);
+       debugfs_create_file("regcache_dump", S_IRUGO, emif->debugfs_root, emif,
+                           &emif_regdump_fops);
+       debugfs_create_file("mr4", S_IRUGO, emif->debugfs_root, emif,
+                           &emif_mr4_fops);
        return 0;
-err1:
-       debugfs_remove_recursive(emif->debugfs_root);
-err0:
-       return ret;
 }
 
 static void __exit emif_debugfs_exit(struct emif_data *emif)
index 0b0ed72..0309bd5 100644 (file)
@@ -211,10 +211,8 @@ static int ccf_probe(struct platform_device *pdev)
        dev_set_drvdata(&pdev->dev, ccf);
 
        irq = platform_get_irq(pdev, 0);
-       if (!irq) {
-               dev_err(&pdev->dev, "%s: no irq\n", __func__);
-               return -ENXIO;
-       }
+       if (irq < 0)
+               return irq;
 
        ret = devm_request_irq(&pdev->dev, irq, ccf_irq, 0, pdev->name, ccf);
        if (ret) {
index c212625..691e4c3 100644 (file)
@@ -19,6 +19,9 @@
 /* mt8173 */
 #define SMI_LARB_MMU_EN                0xf00
 
+/* mt8167 */
+#define MT8167_SMI_LARB_MMU_EN 0xfc0
+
 /* mt2701 */
 #define REG_SMI_SECUR_CON_BASE         0x5c0
 
@@ -179,6 +182,13 @@ static void mtk_smi_larb_config_port_mt8173(struct device *dev)
        writel(*larb->mmu, larb->base + SMI_LARB_MMU_EN);
 }
 
+static void mtk_smi_larb_config_port_mt8167(struct device *dev)
+{
+       struct mtk_smi_larb *larb = dev_get_drvdata(dev);
+
+       writel(*larb->mmu, larb->base + MT8167_SMI_LARB_MMU_EN);
+}
+
 static void mtk_smi_larb_config_port_gen1(struct device *dev)
 {
        struct mtk_smi_larb *larb = dev_get_drvdata(dev);
@@ -226,6 +236,11 @@ static const struct mtk_smi_larb_gen mtk_smi_larb_mt8173 = {
        .config_port = mtk_smi_larb_config_port_mt8173,
 };
 
+static const struct mtk_smi_larb_gen mtk_smi_larb_mt8167 = {
+       /* mt8167 do not need the port in larb */
+       .config_port = mtk_smi_larb_config_port_mt8167,
+};
+
 static const struct mtk_smi_larb_gen mtk_smi_larb_mt2701 = {
        .port_in_larb = {
                LARB0_PORT_OFFSET, LARB1_PORT_OFFSET,
@@ -255,6 +270,10 @@ static const struct mtk_smi_larb_gen mtk_smi_larb_mt8183 = {
 
 static const struct of_device_id mtk_smi_larb_of_ids[] = {
        {
+               .compatible = "mediatek,mt8167-smi-larb",
+               .data = &mtk_smi_larb_mt8167
+       },
+       {
                .compatible = "mediatek,mt8173-smi-larb",
                .data = &mtk_smi_larb_mt8173
        },
@@ -419,6 +438,10 @@ static const struct of_device_id mtk_smi_common_of_ids[] = {
                .data = &mtk_smi_common_gen2,
        },
        {
+               .compatible = "mediatek,mt8167-smi-common",
+               .data = &mtk_smi_common_gen2,
+       },
+       {
                .compatible = "mediatek,mt2701-smi-common",
                .data = &mtk_smi_common_gen1,
        },
index ca00976..cfa730c 100644 (file)
@@ -33,8 +33,6 @@
 
 #include <linux/platform_data/mtd-nand-omap2.h>
 
-#include <asm/mach-types.h>
-
 #define        DEVICE_NAME             "omap-gpmc"
 
 /* GPMC register offsets */
@@ -245,7 +243,6 @@ static DEFINE_SPINLOCK(gpmc_mem_lock);
 /* Define chip-selects as reserved by default until probe completes */
 static unsigned int gpmc_cs_num = GPMC_CS_NUM;
 static unsigned int gpmc_nr_waitpins;
-static resource_size_t phys_base, mem_size;
 static unsigned int gpmc_capability;
 static void __iomem *gpmc_base;
 
@@ -634,14 +631,6 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit, int max
        return 0;
 }
 
-#define GPMC_SET_ONE_CD_MAX(reg, st, end, max, field, cd)  \
-       if (set_gpmc_timing_reg(cs, (reg), (st), (end), (max), \
-           t->field, (cd), #field) < 0)                       \
-               return -1
-
-#define GPMC_SET_ONE(reg, st, end, field) \
-       GPMC_SET_ONE_CD_MAX(reg, st, end, 0, field, GPMC_CD_FCLK)
-
 /**
  * gpmc_calc_waitmonitoring_divider - calculate proper GPMCFCLKDIVIDER based on WAITMONITORINGTIME
  * WAITMONITORINGTIME will be _at least_ as long as desired, i.e.
@@ -700,12 +689,12 @@ int gpmc_calc_divider(unsigned int sync_clk)
 int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t,
                        const struct gpmc_settings *s)
 {
-       int div;
+       int div, ret;
        u32 l;
 
        div = gpmc_calc_divider(t->sync_clk);
        if (div < 0)
-               return div;
+               return -EINVAL;
 
        /*
         * See if we need to change the divider for waitmonitoringtime.
@@ -729,57 +718,114 @@ int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t,
                               __func__,
                               t->wait_monitoring
                               );
-                       return -1;
+                       return -ENXIO;
                }
        }
 
-       GPMC_SET_ONE(GPMC_CS_CONFIG2,  0,  3, cs_on);
-       GPMC_SET_ONE(GPMC_CS_CONFIG2,  8, 12, cs_rd_off);
-       GPMC_SET_ONE(GPMC_CS_CONFIG2, 16, 20, cs_wr_off);
+       ret = 0;
+       ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG2, 0, 3, 0, t->cs_on,
+                                  GPMC_CD_FCLK, "cs_on");
+       ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG2, 8, 12, 0, t->cs_rd_off,
+                                  GPMC_CD_FCLK, "cs_rd_off");
+       ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG2, 16, 20, 0, t->cs_wr_off,
+                                  GPMC_CD_FCLK, "cs_wr_off");
+       if (ret)
+               return -ENXIO;
+
+       ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG3, 0, 3, 0, t->adv_on,
+                                  GPMC_CD_FCLK, "adv_on");
+       ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG3, 8, 12, 0, t->adv_rd_off,
+                                  GPMC_CD_FCLK, "adv_rd_off");
+       ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG3, 16, 20, 0, t->adv_wr_off,
+                                  GPMC_CD_FCLK, "adv_wr_off");
+       if (ret)
+               return -ENXIO;
 
-       GPMC_SET_ONE(GPMC_CS_CONFIG3,  0,  3, adv_on);
-       GPMC_SET_ONE(GPMC_CS_CONFIG3,  8, 12, adv_rd_off);
-       GPMC_SET_ONE(GPMC_CS_CONFIG3, 16, 20, adv_wr_off);
        if (gpmc_capability & GPMC_HAS_MUX_AAD) {
-               GPMC_SET_ONE(GPMC_CS_CONFIG3,  4,  6, adv_aad_mux_on);
-               GPMC_SET_ONE(GPMC_CS_CONFIG3, 24, 26, adv_aad_mux_rd_off);
-               GPMC_SET_ONE(GPMC_CS_CONFIG3, 28, 30, adv_aad_mux_wr_off);
+               ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG3, 4, 6, 0,
+                                          t->adv_aad_mux_on, GPMC_CD_FCLK,
+                                          "adv_aad_mux_on");
+               ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG3, 24, 26, 0,
+                                          t->adv_aad_mux_rd_off, GPMC_CD_FCLK,
+                                          "adv_aad_mux_rd_off");
+               ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG3, 28, 30, 0,
+                                          t->adv_aad_mux_wr_off, GPMC_CD_FCLK,
+                                          "adv_aad_mux_wr_off");
+               if (ret)
+                       return -ENXIO;
        }
 
-       GPMC_SET_ONE(GPMC_CS_CONFIG4,  0,  3, oe_on);
-       GPMC_SET_ONE(GPMC_CS_CONFIG4,  8, 12, oe_off);
+       ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG4, 0, 3, 0, t->oe_on,
+                                  GPMC_CD_FCLK, "oe_on");
+       ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG4, 8, 12, 0, t->oe_off,
+                                  GPMC_CD_FCLK, "oe_off");
        if (gpmc_capability & GPMC_HAS_MUX_AAD) {
-               GPMC_SET_ONE(GPMC_CS_CONFIG4,  4,  6, oe_aad_mux_on);
-               GPMC_SET_ONE(GPMC_CS_CONFIG4, 13, 15, oe_aad_mux_off);
+               ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG4, 4, 6, 0,
+                                          t->oe_aad_mux_on, GPMC_CD_FCLK,
+                                          "oe_aad_mux_on");
+               ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG4, 13, 15, 0,
+                                          t->oe_aad_mux_off, GPMC_CD_FCLK,
+                                          "oe_aad_mux_off");
+       }
+       ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG4, 16, 19, 0, t->we_on,
+                                  GPMC_CD_FCLK, "we_on");
+       ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG4, 24, 28, 0, t->we_off,
+                                  GPMC_CD_FCLK, "we_off");
+       if (ret)
+               return -ENXIO;
+
+       ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG5, 0, 4, 0, t->rd_cycle,
+                                  GPMC_CD_FCLK, "rd_cycle");
+       ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG5, 8, 12, 0, t->wr_cycle,
+                                  GPMC_CD_FCLK, "wr_cycle");
+       ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG5, 16, 20, 0, t->access,
+                                  GPMC_CD_FCLK, "access");
+       ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG5, 24, 27, 0,
+                                  t->page_burst_access, GPMC_CD_FCLK,
+                                  "page_burst_access");
+       if (ret)
+               return -ENXIO;
+
+       ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG6, 0, 3, 0,
+                                  t->bus_turnaround, GPMC_CD_FCLK,
+                                  "bus_turnaround");
+       ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG6, 8, 11, 0,
+                                  t->cycle2cycle_delay, GPMC_CD_FCLK,
+                                  "cycle2cycle_delay");
+       if (ret)
+               return -ENXIO;
+
+       if (gpmc_capability & GPMC_HAS_WR_DATA_MUX_BUS) {
+               ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG6, 16, 19, 0,
+                                          t->wr_data_mux_bus, GPMC_CD_FCLK,
+                                          "wr_data_mux_bus");
+               if (ret)
+                       return -ENXIO;
+       }
+       if (gpmc_capability & GPMC_HAS_WR_ACCESS) {
+               ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG6, 24, 28, 0,
+                                          t->wr_access, GPMC_CD_FCLK,
+                                          "wr_access");
+               if (ret)
+                       return -ENXIO;
        }
-       GPMC_SET_ONE(GPMC_CS_CONFIG4, 16, 19, we_on);
-       GPMC_SET_ONE(GPMC_CS_CONFIG4, 24, 28, we_off);
-
-       GPMC_SET_ONE(GPMC_CS_CONFIG5,  0,  4, rd_cycle);
-       GPMC_SET_ONE(GPMC_CS_CONFIG5,  8, 12, wr_cycle);
-       GPMC_SET_ONE(GPMC_CS_CONFIG5, 16, 20, access);
-
-       GPMC_SET_ONE(GPMC_CS_CONFIG5, 24, 27, page_burst_access);
-
-       GPMC_SET_ONE(GPMC_CS_CONFIG6, 0, 3, bus_turnaround);
-       GPMC_SET_ONE(GPMC_CS_CONFIG6, 8, 11, cycle2cycle_delay);
-
-       if (gpmc_capability & GPMC_HAS_WR_DATA_MUX_BUS)
-               GPMC_SET_ONE(GPMC_CS_CONFIG6, 16, 19, wr_data_mux_bus);
-       if (gpmc_capability & GPMC_HAS_WR_ACCESS)
-               GPMC_SET_ONE(GPMC_CS_CONFIG6, 24, 28, wr_access);
 
        l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
        l &= ~0x03;
        l |= (div - 1);
        gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, l);
 
-       GPMC_SET_ONE_CD_MAX(GPMC_CS_CONFIG1, 18, 19,
-                           GPMC_CONFIG1_WAITMONITORINGTIME_MAX,
-                           wait_monitoring, GPMC_CD_CLK);
-       GPMC_SET_ONE_CD_MAX(GPMC_CS_CONFIG1, 25, 26,
-                           GPMC_CONFIG1_CLKACTIVATIONTIME_MAX,
-                           clk_activation, GPMC_CD_FCLK);
+       ret = 0;
+       ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG1, 18, 19,
+                                  GPMC_CONFIG1_WAITMONITORINGTIME_MAX,
+                                  t->wait_monitoring, GPMC_CD_CLK,
+                                  "wait_monitoring");
+       ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG1, 25, 26,
+                                  GPMC_CONFIG1_CLKACTIVATIONTIME_MAX,
+                                  t->clk_activation, GPMC_CD_FCLK,
+                                  "clk_activation");
+       if (ret)
+               return -ENXIO;
 
 #ifdef CONFIG_OMAP_GPMC_DEBUG
        pr_info("GPMC CS%d CLK period is %lu ns (div %d)\n",
@@ -870,20 +916,6 @@ static bool gpmc_cs_reserved(int cs)
        return gpmc->flags & GPMC_CS_RESERVED;
 }
 
-static void gpmc_cs_set_name(int cs, const char *name)
-{
-       struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
-
-       gpmc->name = name;
-}
-
-static const char *gpmc_cs_get_name(int cs)
-{
-       struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
-
-       return gpmc->name;
-}
-
 static unsigned long gpmc_mem_align(unsigned long size)
 {
        int order;
@@ -929,56 +961,13 @@ static int gpmc_cs_delete_mem(int cs)
        return r;
 }
 
-/**
- * gpmc_cs_remap - remaps a chip-select physical base address
- * @cs:                chip-select to remap
- * @base:      physical base address to re-map chip-select to
- *
- * Re-maps a chip-select to a new physical base address specified by
- * "base". Returns 0 on success and appropriate negative error code
- * on failure.
- */
-static int gpmc_cs_remap(int cs, u32 base)
-{
-       int ret;
-       u32 old_base, size;
-
-       if (cs > gpmc_cs_num) {
-               pr_err("%s: requested chip-select is disabled\n", __func__);
-               return -ENODEV;
-       }
-
-       /*
-        * Make sure we ignore any device offsets from the GPMC partition
-        * allocated for the chip select and that the new base confirms
-        * to the GPMC 16MB minimum granularity.
-        */
-       base &= ~(SZ_16M - 1);
-
-       gpmc_cs_get_memconf(cs, &old_base, &size);
-       if (base == old_base)
-               return 0;
-
-       ret = gpmc_cs_delete_mem(cs);
-       if (ret < 0)
-               return ret;
-
-       ret = gpmc_cs_insert_mem(cs, base, size);
-       if (ret < 0)
-               return ret;
-
-       ret = gpmc_cs_set_memconf(cs, base, size);
-
-       return ret;
-}
-
 int gpmc_cs_request(int cs, unsigned long size, unsigned long *base)
 {
        struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
        struct resource *res = &gpmc->mem;
        int r = -1;
 
-       if (cs > gpmc_cs_num) {
+       if (cs >= gpmc_cs_num) {
                pr_err("%s: requested chip-select is disabled\n", __func__);
                return -ENODEV;
        }
@@ -1025,8 +1014,7 @@ void gpmc_cs_free(int cs)
 
        spin_lock(&gpmc_mem_lock);
        if (cs >= gpmc_cs_num || cs < 0 || !gpmc_cs_reserved(cs)) {
-               printk(KERN_ERR "Trying to free non-reserved GPMC CS%d\n", cs);
-               BUG();
+               WARN(1, "Trying to free non-reserved GPMC CS%d\n", cs);
                spin_unlock(&gpmc_mem_lock);
                return;
        }
@@ -1896,6 +1884,63 @@ static const struct of_device_id gpmc_dt_ids[] = {
        { }
 };
 
+static void gpmc_cs_set_name(int cs, const char *name)
+{
+       struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
+
+       gpmc->name = name;
+}
+
+static const char *gpmc_cs_get_name(int cs)
+{
+       struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
+
+       return gpmc->name;
+}
+
+/**
+ * gpmc_cs_remap - remaps a chip-select physical base address
+ * @cs:                chip-select to remap
+ * @base:      physical base address to re-map chip-select to
+ *
+ * Re-maps a chip-select to a new physical base address specified by
+ * "base". Returns 0 on success and appropriate negative error code
+ * on failure.
+ */
+static int gpmc_cs_remap(int cs, u32 base)
+{
+       int ret;
+       u32 old_base, size;
+
+       if (cs >= gpmc_cs_num) {
+               pr_err("%s: requested chip-select is disabled\n", __func__);
+               return -ENODEV;
+       }
+
+       /*
+        * Make sure we ignore any device offsets from the GPMC partition
+        * allocated for the chip select and that the new base confirms
+        * to the GPMC 16MB minimum granularity.
+        */
+       base &= ~(SZ_16M - 1);
+
+       gpmc_cs_get_memconf(cs, &old_base, &size);
+       if (base == old_base)
+               return 0;
+
+       ret = gpmc_cs_delete_mem(cs);
+       if (ret < 0)
+               return ret;
+
+       ret = gpmc_cs_insert_mem(cs, base, size);
+       if (ret < 0)
+               return ret;
+
+       ret = gpmc_cs_set_memconf(cs, base, size);
+
+       return ret;
+}
+
 /**
  * gpmc_read_settings_dt - read gpmc settings from device-tree
  * @np:                pointer to device-tree node for a gpmc child device
@@ -2265,6 +2310,10 @@ static void gpmc_probe_dt_children(struct platform_device *pdev)
        }
 }
 #else
+void gpmc_read_settings_dt(struct device_node *np, struct gpmc_settings *p)
+{
+       memset(p, 0, sizeof(*p));
+}
 static int gpmc_probe_dt(struct platform_device *pdev)
 {
        return 0;
@@ -2347,12 +2396,9 @@ static int gpmc_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, gpmc);
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (res == NULL)
+       if (!res)
                return -ENOENT;
 
-       phys_base = res->start;
-       mem_size = resource_size(res);
-
        gpmc_base = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(gpmc_base))
                return PTR_ERR(gpmc_base);
index 88f51ec..f2a33a1 100644 (file)
@@ -199,10 +199,8 @@ int rpcif_sw_init(struct rpcif *rpc, struct device *dev)
                rpc->dirmap = NULL;
 
        rpc->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
-       if (IS_ERR(rpc->rstc))
-               return PTR_ERR(rpc->rstc);
 
-       return 0;
+       return PTR_ERR_OR_ZERO(rpc->rstc);
 }
 EXPORT_SYMBOL(rpcif_sw_init);
 
index 714d1f6..c5ee412 100644 (file)
@@ -98,6 +98,8 @@ MODULE_PARM_DESC(irqmode, "Enable IRQ mode (0=off [default], 1=on)");
 
 /**
  * struct dmc_opp_table - Operating level desciption
+ * @freq_hz:           target frequency in Hz
+ * @volt_uv:           target voltage in uV
  *
  * Covers frequency and voltage settings of the DMC operating mode.
  */
@@ -108,6 +110,41 @@ struct dmc_opp_table {
 
 /**
  * struct exynos5_dmc - main structure describing DMC device
+ * @dev:               DMC device
+ * @df:                        devfreq device structure returned by devfreq framework
+ * @gov_data:          configuration of devfreq governor
+ * @base_drexi0:       DREX0 registers mapping
+ * @base_drexi1:       DREX1 registers mapping
+ * @clk_regmap:                regmap for clock controller registers
+ * @lock:              protects curr_rate and frequency/voltage setting section
+ * @curr_rate:         current frequency
+ * @curr_volt:         current voltage
+ * @opp:               OPP table
+ * @opp_count:         number of 'opp' elements
+ * @timings_arr_size:  number of 'timings' elements
+ * @timing_row:                values for timing row register, for each OPP
+ * @timing_data:       values for timing data register, for each OPP
+ * @timing_power:      balues for timing power register, for each OPP
+ * @timings:           DDR memory timings, from device tree
+ * @min_tck:           DDR memory minimum timing values, from device tree
+ * @bypass_timing_row: value for timing row register for bypass timings
+ * @bypass_timing_data:        value for timing data register for bypass timings
+ * @bypass_timing_power:       value for timing power register for bypass
+ *                             timings
+ * @vdd_mif:           Memory interface regulator
+ * @fout_spll:         clock: SPLL
+ * @fout_bpll:         clock: BPLL
+ * @mout_spll:         clock: mux SPLL
+ * @mout_bpll:         clock: mux BPLL
+ * @mout_mclk_cdrex:   clock: mux mclk_cdrex
+ * @mout_mx_mspll_ccore:       clock: mux mx_mspll_ccore
+ * @counter:           devfreq events
+ * @num_counters:      number of 'counter' elements
+ * @last_overflow_ts:  time (in ns) of last overflow of each DREX
+ * @load:              utilization in percents
+ * @total:             total time between devfreq events
+ * @in_irq_mode:       whether running in interrupt mode (true)
+ *                     or polling (false)
  *
  * The main structure for the Dynamic Memory Controller which covers clocks,
  * memory regions, HW information, parameters and current operating mode.
@@ -119,12 +156,11 @@ struct exynos5_dmc {
        void __iomem *base_drexi0;
        void __iomem *base_drexi1;
        struct regmap *clk_regmap;
+       /* Protects curr_rate and frequency/voltage setting section */
        struct mutex lock;
        unsigned long curr_rate;
        unsigned long curr_volt;
-       unsigned long bypass_rate;
        struct dmc_opp_table *opp;
-       struct dmc_opp_table opp_bypass;
        int opp_count;
        u32 timings_arr_size;
        u32 *timing_row;
@@ -142,8 +178,6 @@ struct exynos5_dmc {
        struct clk *mout_bpll;
        struct clk *mout_mclk_cdrex;
        struct clk *mout_mx_mspll_ccore;
-       struct clk *mx_mspll_ccore_phy;
-       struct clk *mout_mx_mspll_ccore_phy;
        struct devfreq_event_dev **counter;
        int num_counters;
        u64 last_overflow_ts[2];
@@ -169,7 +203,7 @@ struct timing_reg {
        unsigned int val;
 };
 
-static const struct timing_reg timing_row[] = {
+static const struct timing_reg timing_row_reg_fields[] = {
        TIMING_FIELD("tRFC", 24, 31),
        TIMING_FIELD("tRRD", 20, 23),
        TIMING_FIELD("tRP", 16, 19),
@@ -178,7 +212,7 @@ static const struct timing_reg timing_row[] = {
        TIMING_FIELD("tRAS", 0, 5),
 };
 
-static const struct timing_reg timing_data[] = {
+static const struct timing_reg timing_data_reg_fields[] = {
        TIMING_FIELD("tWTR", 28, 31),
        TIMING_FIELD("tWR", 24, 27),
        TIMING_FIELD("tRTP", 20, 23),
@@ -189,7 +223,7 @@ static const struct timing_reg timing_data[] = {
        TIMING_FIELD("RL", 0, 3),
 };
 
-static const struct timing_reg timing_power[] = {
+static const struct timing_reg timing_power_reg_fields[] = {
        TIMING_FIELD("tFAW", 26, 31),
        TIMING_FIELD("tXSR", 16, 25),
        TIMING_FIELD("tXP", 8, 15),
@@ -197,8 +231,9 @@ static const struct timing_reg timing_power[] = {
        TIMING_FIELD("tMRD", 0, 3),
 };
 
-#define TIMING_COUNT (ARRAY_SIZE(timing_row) + ARRAY_SIZE(timing_data) + \
-                     ARRAY_SIZE(timing_power))
+#define TIMING_COUNT (ARRAY_SIZE(timing_row_reg_fields) + \
+                     ARRAY_SIZE(timing_data_reg_fields) + \
+                     ARRAY_SIZE(timing_power_reg_fields))
 
 static int exynos5_counters_set_event(struct exynos5_dmc *dmc)
 {
@@ -346,7 +381,6 @@ err_opp:
 /**
  * exynos5_set_bypass_dram_timings() - Low-level changes of the DRAM timings
  * @dmc:       device for which the new settings is going to be applied
- * @param:     DRAM parameters which passes timing data
  *
  * Low-level function for changing timings for DRAM memory clocking from
  * 'bypass' clock source (fixed frequency @400MHz).
@@ -453,9 +487,6 @@ static int exynos5_dmc_align_bypass_voltage(struct exynos5_dmc *dmc,
                                            unsigned long target_volt)
 {
        int ret = 0;
-       unsigned long bypass_volt = dmc->opp_bypass.volt_uv;
-
-       target_volt = max(bypass_volt, target_volt);
 
        if (dmc->curr_volt >= target_volt)
                return 0;
@@ -617,6 +648,7 @@ disable_clocks:
  *                     requested
  * @target_volt:       returned voltage which corresponds to the returned
  *                     frequency
+ * @flags:     devfreq flags provided for this frequency change request
  *
  * Function gets requested frequency and checks OPP framework for needed
  * frequency and voltage. It populates the values 'target_rate' and
@@ -908,7 +940,10 @@ static int exynos5_dmc_get_status(struct device *dev,
        int ret;
 
        if (dmc->in_irq_mode) {
+               mutex_lock(&dmc->lock);
                stat->current_frequency = dmc->curr_rate;
+               mutex_unlock(&dmc->lock);
+
                stat->busy_time = dmc->load;
                stat->total_time = dmc->total;
        } else {
@@ -950,7 +985,7 @@ static int exynos5_dmc_get_cur_freq(struct device *dev, unsigned long *freq)
        return 0;
 }
 
-/**
+/*
  * exynos5_dmc_df_profile - Devfreq governor's profile structure
  *
  * It provides to the devfreq framework needed functions and polling period.
@@ -993,7 +1028,9 @@ exynos5_dmc_align_init_freq(struct exynos5_dmc *dmc,
 /**
  * create_timings_aligned() - Create register values and align with standard
  * @dmc:       device for which the frequency is going to be set
- * @idx:       speed bin in the OPP table
+ * @reg_timing_row:    array to fill with values for timing row register
+ * @reg_timing_data:   array to fill with values for timing data register
+ * @reg_timing_power:  array to fill with values for timing power register
  * @clk_period_ps:     the period of the clock, known as tCK
  *
  * The function calculates timings and creates a register value ready for
@@ -1018,117 +1055,117 @@ static int create_timings_aligned(struct exynos5_dmc *dmc, u32 *reg_timing_row,
        val = dmc->timings->tRFC / clk_period_ps;
        val += dmc->timings->tRFC % clk_period_ps ? 1 : 0;
        val = max(val, dmc->min_tck->tRFC);
-       reg = &timing_row[0];
+       reg = &timing_row_reg_fields[0];
        *reg_timing_row |= TIMING_VAL2REG(reg, val);
 
        val = dmc->timings->tRRD / clk_period_ps;
        val += dmc->timings->tRRD % clk_period_ps ? 1 : 0;
        val = max(val, dmc->min_tck->tRRD);
-       reg = &timing_row[1];
+       reg = &timing_row_reg_fields[1];
        *reg_timing_row |= TIMING_VAL2REG(reg, val);
 
        val = dmc->timings->tRPab / clk_period_ps;
        val += dmc->timings->tRPab % clk_period_ps ? 1 : 0;
        val = max(val, dmc->min_tck->tRPab);
-       reg = &timing_row[2];
+       reg = &timing_row_reg_fields[2];
        *reg_timing_row |= TIMING_VAL2REG(reg, val);
 
        val = dmc->timings->tRCD / clk_period_ps;
        val += dmc->timings->tRCD % clk_period_ps ? 1 : 0;
        val = max(val, dmc->min_tck->tRCD);
-       reg = &timing_row[3];
+       reg = &timing_row_reg_fields[3];
        *reg_timing_row |= TIMING_VAL2REG(reg, val);
 
        val = dmc->timings->tRC / clk_period_ps;
        val += dmc->timings->tRC % clk_period_ps ? 1 : 0;
        val = max(val, dmc->min_tck->tRC);
-       reg = &timing_row[4];
+       reg = &timing_row_reg_fields[4];
        *reg_timing_row |= TIMING_VAL2REG(reg, val);
 
        val = dmc->timings->tRAS / clk_period_ps;
        val += dmc->timings->tRAS % clk_period_ps ? 1 : 0;
        val = max(val, dmc->min_tck->tRAS);
-       reg = &timing_row[5];
+       reg = &timing_row_reg_fields[5];
        *reg_timing_row |= TIMING_VAL2REG(reg, val);
 
        /* data related timings */
        val = dmc->timings->tWTR / clk_period_ps;
        val += dmc->timings->tWTR % clk_period_ps ? 1 : 0;
        val = max(val, dmc->min_tck->tWTR);
-       reg = &timing_data[0];
+       reg = &timing_data_reg_fields[0];
        *reg_timing_data |= TIMING_VAL2REG(reg, val);
 
        val = dmc->timings->tWR / clk_period_ps;
        val += dmc->timings->tWR % clk_period_ps ? 1 : 0;
        val = max(val, dmc->min_tck->tWR);
-       reg = &timing_data[1];
+       reg = &timing_data_reg_fields[1];
        *reg_timing_data |= TIMING_VAL2REG(reg, val);
 
        val = dmc->timings->tRTP / clk_period_ps;
        val += dmc->timings->tRTP % clk_period_ps ? 1 : 0;
        val = max(val, dmc->min_tck->tRTP);
-       reg = &timing_data[2];
+       reg = &timing_data_reg_fields[2];
        *reg_timing_data |= TIMING_VAL2REG(reg, val);
 
        val = dmc->timings->tW2W_C2C / clk_period_ps;
        val += dmc->timings->tW2W_C2C % clk_period_ps ? 1 : 0;
        val = max(val, dmc->min_tck->tW2W_C2C);
-       reg = &timing_data[3];
+       reg = &timing_data_reg_fields[3];
        *reg_timing_data |= TIMING_VAL2REG(reg, val);
 
        val = dmc->timings->tR2R_C2C / clk_period_ps;
        val += dmc->timings->tR2R_C2C % clk_period_ps ? 1 : 0;
        val = max(val, dmc->min_tck->tR2R_C2C);
-       reg = &timing_data[4];
+       reg = &timing_data_reg_fields[4];
        *reg_timing_data |= TIMING_VAL2REG(reg, val);
 
        val = dmc->timings->tWL / clk_period_ps;
        val += dmc->timings->tWL % clk_period_ps ? 1 : 0;
        val = max(val, dmc->min_tck->tWL);
-       reg = &timing_data[5];
+       reg = &timing_data_reg_fields[5];
        *reg_timing_data |= TIMING_VAL2REG(reg, val);
 
        val = dmc->timings->tDQSCK / clk_period_ps;
        val += dmc->timings->tDQSCK % clk_period_ps ? 1 : 0;
        val = max(val, dmc->min_tck->tDQSCK);
-       reg = &timing_data[6];
+       reg = &timing_data_reg_fields[6];
        *reg_timing_data |= TIMING_VAL2REG(reg, val);
 
        val = dmc->timings->tRL / clk_period_ps;
        val += dmc->timings->tRL % clk_period_ps ? 1 : 0;
        val = max(val, dmc->min_tck->tRL);
-       reg = &timing_data[7];
+       reg = &timing_data_reg_fields[7];
        *reg_timing_data |= TIMING_VAL2REG(reg, val);
 
        /* power related timings */
        val = dmc->timings->tFAW / clk_period_ps;
        val += dmc->timings->tFAW % clk_period_ps ? 1 : 0;
        val = max(val, dmc->min_tck->tFAW);
-       reg = &timing_power[0];
+       reg = &timing_power_reg_fields[0];
        *reg_timing_power |= TIMING_VAL2REG(reg, val);
 
        val = dmc->timings->tXSR / clk_period_ps;
        val += dmc->timings->tXSR % clk_period_ps ? 1 : 0;
        val = max(val, dmc->min_tck->tXSR);
-       reg = &timing_power[1];
+       reg = &timing_power_reg_fields[1];
        *reg_timing_power |= TIMING_VAL2REG(reg, val);
 
        val = dmc->timings->tXP / clk_period_ps;
        val += dmc->timings->tXP % clk_period_ps ? 1 : 0;
        val = max(val, dmc->min_tck->tXP);
-       reg = &timing_power[2];
+       reg = &timing_power_reg_fields[2];
        *reg_timing_power |= TIMING_VAL2REG(reg, val);
 
        val = dmc->timings->tCKE / clk_period_ps;
        val += dmc->timings->tCKE % clk_period_ps ? 1 : 0;
        val = max(val, dmc->min_tck->tCKE);
-       reg = &timing_power[3];
+       reg = &timing_power_reg_fields[3];
        *reg_timing_power |= TIMING_VAL2REG(reg, val);
 
        val = dmc->timings->tMRD / clk_period_ps;
        val += dmc->timings->tMRD % clk_period_ps ? 1 : 0;
        val = max(val, dmc->min_tck->tMRD);
-       reg = &timing_power[4];
+       reg = &timing_power_reg_fields[4];
        *reg_timing_power |= TIMING_VAL2REG(reg, val);
 
        return 0;
@@ -1263,8 +1300,6 @@ static int exynos5_dmc_init_clks(struct exynos5_dmc *dmc)
 
        clk_set_parent(dmc->mout_mx_mspll_ccore, dmc->mout_spll);
 
-       dmc->bypass_rate = clk_get_rate(dmc->mout_mx_mspll_ccore);
-
        clk_prepare_enable(dmc->fout_bpll);
        clk_prepare_enable(dmc->mout_bpll);
 
@@ -1332,7 +1367,6 @@ static int exynos5_performance_counters_init(struct exynos5_dmc *dmc)
 /**
  * exynos5_dmc_set_pause_on_switching() - Controls a pause feature in DMC
  * @dmc:       device which is used for changing this feature
- * @set:       a boolean state passing enable/disable request
  *
  * There is a need of pausing DREX DMC when divider or MUX in clock tree
  * changes its configuration. In such situation access to the memory is blocked
index ba5cb1f..76ace42 100644 (file)
@@ -1060,19 +1060,7 @@ static int tegra_emc_debug_available_rates_show(struct seq_file *s,
        return 0;
 }
 
-static int tegra_emc_debug_available_rates_open(struct inode *inode,
-                                               struct file *file)
-{
-       return single_open(file, tegra_emc_debug_available_rates_show,
-                          inode->i_private);
-}
-
-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,
-};
+DEFINE_SHOW_ATTRIBUTE(tegra_emc_debug_available_rates);
 
 static int tegra_emc_debug_min_rate_get(void *data, u64 *rate)
 {
index 493b5dc..0cede24 100644 (file)
@@ -957,7 +957,6 @@ static const struct tegra_smmu_swgroup tegra124_swgroups[] = {
 static const unsigned int tegra124_group_drm[] = {
        TEGRA_SWGROUP_DC,
        TEGRA_SWGROUP_DCB,
-       TEGRA_SWGROUP_GPU,
        TEGRA_SWGROUP_VIC,
 };
 
index 8478f59..fa8af17 100644 (file)
@@ -172,14 +172,8 @@ static int tegra186_emc_probe(struct platform_device *pdev)
                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;
-       }
+       if (IS_ERR(emc->bpmp))
+               return dev_err_probe(&pdev->dev, PTR_ERR(emc->bpmp), "failed to get BPMP\n");
 
        emc->clk = devm_clk_get(&pdev->dev, "emc");
        if (IS_ERR(emc->clk)) {
index ff55a17..0ebfa8e 100644 (file)
@@ -501,7 +501,6 @@ static u32 tegra210_emc_r21021_periodic_compensation(struct tegra210_emc *emc)
                emc_cfg_o = emc_readl(emc, EMC_CFG);
                emc_cfg = emc_cfg_o & ~(EMC_CFG_DYN_SELF_REF |
                                        EMC_CFG_DRAM_ACPD |
-                                       EMC_CFG_DRAM_CLKSTOP_PD |
                                        EMC_CFG_DRAM_CLKSTOP_PD);
 
 
@@ -1044,7 +1043,7 @@ static void tegra210_emc_r21021_set_clock(struct tegra210_emc *emc, u32 clksrc)
                           !opt_cc_short_zcal && opt_short_zcal) {
                        value = (value & ~(EMC_ZCAL_WAIT_CNT_ZCAL_WAIT_CNT_MASK <<
                                           EMC_ZCAL_WAIT_CNT_ZCAL_WAIT_CNT_SHIFT)) |
-                               ((zq_wait_long & EMC_ZCAL_WAIT_CNT_ZCAL_WAIT_CNT_MASK) <<
+                               ((zq_wait_long & EMC_ZCAL_WAIT_CNT_ZCAL_WAIT_CNT_MASK) <<
                                                 EMC_MRS_WAIT_CNT_SHORT_WAIT_SHIFT);
                } else if (offset == EMC_ZCAL_INTERVAL && opt_zcal_en_cc) {
                        value = 0; /* EMC_ZCAL_INTERVAL reset value. */
index 7212d1d..7fb8b54 100644 (file)
@@ -842,7 +842,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = {
                },
                .la = {
                        .reg = 0x3dc,
-                       .shift = 0,
+                       .shift = 16,
                        .mask = 0xff,
                        .def = 0x80,
                },
index 97e8487..07d162b 100644 (file)
@@ -65,9 +65,10 @@ config RESET_HSDK
          This enables the reset controller driver for HSDK board.
 
 config RESET_IMX7
-       bool "i.MX7/8 Reset Driver" if COMPILE_TEST
+       tristate "i.MX7/8 Reset Driver"
        depends on HAS_IOMEM
-       default SOC_IMX7D || (ARM64 && ARCH_MXC)
+       depends on SOC_IMX7D || (ARM64 && ARCH_MXC) || COMPILE_TEST
+       default y if SOC_IMX7D
        select MFD_SYSCON
        help
          This enables the reset controller driver for i.MX7 SoCs.
index 01c0c7a..a2df88e 100644 (file)
@@ -32,7 +32,8 @@ static LIST_HEAD(reset_lookup_list);
  * @refcnt: Number of gets of this reset_control
  * @acquired: Only one reset_control may be acquired for a given rcdev and id.
  * @shared: Is this a shared (1), or an exclusive (0) reset_control?
- * @deassert_cnt: Number of times this reset line has been deasserted
+ * @array: Is this an array of reset controls (1)?
+ * @deassert_count: Number of times this reset line has been deasserted
  * @triggered_count: Number of times this reset line has been reset. Currently
  *                   only used for shared resets, which means that the value
  *                   will be either 0 or 1.
index e8aa869..185a333 100644 (file)
@@ -8,7 +8,7 @@
  */
 
 #include <linux/mfd/syscon.h>
-#include <linux/mod_devicetable.h>
+#include <linux/module.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/reset-controller.h>
@@ -178,6 +178,9 @@ static const struct imx7_src_signal imx8mq_src_signals[IMX8MQ_RESET_NUM] = {
        [IMX8MQ_RESET_A53_SOC_DBG_RESET]        = { SRC_A53RCR0, BIT(20) },
        [IMX8MQ_RESET_A53_L2RESET]              = { SRC_A53RCR0, BIT(21) },
        [IMX8MQ_RESET_SW_NON_SCLR_M4C_RST]      = { SRC_M4RCR, BIT(0) },
+       [IMX8MQ_RESET_SW_M4C_RST]               = { SRC_M4RCR, BIT(1) },
+       [IMX8MQ_RESET_SW_M4P_RST]               = { SRC_M4RCR, BIT(2) },
+       [IMX8MQ_RESET_M4_ENABLE]                = { SRC_M4RCR, BIT(3) },
        [IMX8MQ_RESET_OTG1_PHY_RESET]           = { SRC_USBOPHY1_RCR, BIT(0) },
        [IMX8MQ_RESET_OTG2_PHY_RESET]           = { SRC_USBOPHY2_RCR, BIT(0) },
        [IMX8MQ_RESET_MIPI_DSI_RESET_BYTE_N]    = { SRC_MIPIPHY_RCR, BIT(1) },
@@ -238,6 +241,7 @@ static int imx8mq_reset_set(struct reset_controller_dev *rcdev,
        case IMX8MQ_RESET_MIPI_DSI_DPI_RESET_N:
        case IMX8MQ_RESET_MIPI_DSI_RESET_N:
        case IMX8MQ_RESET_MIPI_DSI_RESET_BYTE_N:
+       case IMX8MQ_RESET_M4_ENABLE:
                value = assert ? 0 : bit;
                break;
        }
@@ -386,6 +390,7 @@ static const struct of_device_id imx7_reset_dt_ids[] = {
        { .compatible = "fsl,imx8mp-src", .data = &variant_imx8mp },
        { /* sentinel */ },
 };
+MODULE_DEVICE_TABLE(of, imx7_reset_dt_ids);
 
 static struct platform_driver imx7_reset_driver = {
        .probe  = imx7_reset_probe,
@@ -394,4 +399,8 @@ static struct platform_driver imx7_reset_driver = {
                .of_match_table = imx7_reset_dt_ids,
        },
 };
-builtin_platform_driver(imx7_reset_driver);
+module_platform_driver(imx7_reset_driver);
+
+MODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>");
+MODULE_DESCRIPTION("NXP i.MX7 reset driver");
+MODULE_LICENSE("GPL v2");
index 373ea8d..ebd433f 100644 (file)
@@ -9,12 +9,20 @@
 #include <linux/platform_device.h>
 #include <linux/reset-controller.h>
 #include <linux/firmware/xlnx-zynqmp.h>
+#include <linux/of_device.h>
 
 #define ZYNQMP_NR_RESETS (ZYNQMP_PM_RESET_END - ZYNQMP_PM_RESET_START)
 #define ZYNQMP_RESET_ID ZYNQMP_PM_RESET_START
+#define VERSAL_NR_RESETS       95
+
+struct zynqmp_reset_soc_data {
+       u32 reset_id;
+       u32 num_resets;
+};
 
 struct zynqmp_reset_data {
        struct reset_controller_dev rcdev;
+       const struct zynqmp_reset_soc_data *data;
 };
 
 static inline struct zynqmp_reset_data *
@@ -26,23 +34,28 @@ to_zynqmp_reset_data(struct reset_controller_dev *rcdev)
 static int zynqmp_reset_assert(struct reset_controller_dev *rcdev,
                               unsigned long id)
 {
-       return zynqmp_pm_reset_assert(ZYNQMP_RESET_ID + id,
+       struct zynqmp_reset_data *priv = to_zynqmp_reset_data(rcdev);
+
+       return zynqmp_pm_reset_assert(priv->data->reset_id + id,
                                      PM_RESET_ACTION_ASSERT);
 }
 
 static int zynqmp_reset_deassert(struct reset_controller_dev *rcdev,
                                 unsigned long id)
 {
-       return zynqmp_pm_reset_assert(ZYNQMP_RESET_ID + id,
+       struct zynqmp_reset_data *priv = to_zynqmp_reset_data(rcdev);
+
+       return zynqmp_pm_reset_assert(priv->data->reset_id + id,
                                      PM_RESET_ACTION_RELEASE);
 }
 
 static int zynqmp_reset_status(struct reset_controller_dev *rcdev,
                               unsigned long id)
 {
+       struct zynqmp_reset_data *priv = to_zynqmp_reset_data(rcdev);
        int val, err;
 
-       err = zynqmp_pm_reset_get_status(ZYNQMP_RESET_ID + id, &val);
+       err = zynqmp_pm_reset_get_status(priv->data->reset_id + id, &val);
        if (err)
                return err;
 
@@ -52,10 +65,28 @@ static int zynqmp_reset_status(struct reset_controller_dev *rcdev,
 static int zynqmp_reset_reset(struct reset_controller_dev *rcdev,
                              unsigned long id)
 {
-       return zynqmp_pm_reset_assert(ZYNQMP_RESET_ID + id,
+       struct zynqmp_reset_data *priv = to_zynqmp_reset_data(rcdev);
+
+       return zynqmp_pm_reset_assert(priv->data->reset_id + id,
                                      PM_RESET_ACTION_PULSE);
 }
 
+static int zynqmp_reset_of_xlate(struct reset_controller_dev *rcdev,
+                                const struct of_phandle_args *reset_spec)
+{
+       return reset_spec->args[0];
+}
+
+static const struct zynqmp_reset_soc_data zynqmp_reset_data = {
+       .reset_id = ZYNQMP_RESET_ID,
+       .num_resets = ZYNQMP_NR_RESETS,
+};
+
+static const struct zynqmp_reset_soc_data versal_reset_data = {
+        .reset_id = 0,
+        .num_resets = VERSAL_NR_RESETS,
+};
+
 static const struct reset_control_ops zynqmp_reset_ops = {
        .reset = zynqmp_reset_reset,
        .assert = zynqmp_reset_assert,
@@ -71,18 +102,25 @@ static int zynqmp_reset_probe(struct platform_device *pdev)
        if (!priv)
                return -ENOMEM;
 
+       priv->data = of_device_get_match_data(&pdev->dev);
+       if (!priv->data)
+               return -EINVAL;
+
        platform_set_drvdata(pdev, priv);
 
        priv->rcdev.ops = &zynqmp_reset_ops;
        priv->rcdev.owner = THIS_MODULE;
        priv->rcdev.of_node = pdev->dev.of_node;
-       priv->rcdev.nr_resets = ZYNQMP_NR_RESETS;
+       priv->rcdev.nr_resets = priv->data->num_resets;
+       priv->rcdev.of_reset_n_cells = 1;
+       priv->rcdev.of_xlate = zynqmp_reset_of_xlate;
 
        return devm_reset_controller_register(&pdev->dev, &priv->rcdev);
 }
 
 static const struct of_device_id zynqmp_reset_dt_ids[] = {
-       { .compatible = "xlnx,zynqmp-reset", },
+       { .compatible = "xlnx,zynqmp-reset", .data = &zynqmp_reset_data, },
+       { .compatible = "xlnx,versal-reset", .data = &versal_reset_data, },
        { /* sentinel */ },
 };
 
index 91215bb..99b6303 100644 (file)
@@ -17,7 +17,7 @@
 #include "reset-syscfg.h"
 
 /**
- * Reset channel regmap configuration
+ * struct syscfg_reset_channel - Reset channel regmap configuration
  *
  * @reset: regmap field for the channel's reset bit.
  * @ack: regmap field for the channel's ack bit (optional).
@@ -28,8 +28,9 @@ struct syscfg_reset_channel {
 };
 
 /**
- * A reset controller which groups together a set of related reset bits, which
- * may be located in different system configuration registers.
+ * struct syscfg_reset_controller - A reset controller which groups together
+ * a set of related reset bits, which may be located in different system
+ * configuration registers.
  *
  * @rst: base reset controller structure.
  * @active_low: are the resets in this controller active low, i.e. clearing
index 43665b7..5164a4d 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/reset.h>
 #include <linux/clk.h>
 #include <dt-bindings/power/meson8-power.h>
+#include <dt-bindings/power/meson-axg-power.h>
 #include <dt-bindings/power/meson-g12a-power.h>
 #include <dt-bindings/power/meson-gxbb-power.h>
 #include <dt-bindings/power/meson-sm1-power.h>
@@ -134,6 +135,11 @@ static struct meson_ee_pwrc_top_domain sm1_pwrc_ge2d = SM1_EE_PD(19);
        { __reg, BIT(14) },                                     \
        { __reg, BIT(15) }
 
+static struct meson_ee_pwrc_mem_domain axg_pwrc_mem_vpu[] = {
+       VPU_MEMPD(HHI_VPU_MEM_PD_REG0),
+       VPU_HHI_MEMPD(HHI_MEM_PD_REG0),
+};
+
 static struct meson_ee_pwrc_mem_domain g12a_pwrc_mem_vpu[] = {
        VPU_MEMPD(HHI_VPU_MEM_PD_REG0),
        VPU_MEMPD(HHI_VPU_MEM_PD_REG1),
@@ -190,6 +196,10 @@ static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_ge2d[] = {
        { HHI_MEM_PD_REG0, GENMASK(25, 18) },
 };
 
+static struct meson_ee_pwrc_mem_domain axg_pwrc_mem_audio[] = {
+       { HHI_MEM_PD_REG0, GENMASK(5, 4) },
+};
+
 static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_audio[] = {
        { HHI_MEM_PD_REG0, GENMASK(5, 4) },
        { HHI_AUDIO_MEM_PD_REG0, GENMASK(1, 0) },
@@ -231,6 +241,13 @@ static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_audio[] = {
 
 static bool pwrc_ee_get_power(struct meson_ee_pwrc_domain *pwrc_domain);
 
+static struct meson_ee_pwrc_domain_desc axg_pwrc_domains[] = {
+       [PWRC_AXG_VPU_ID]  = VPU_PD("VPU", &gx_pwrc_vpu, axg_pwrc_mem_vpu,
+                                    pwrc_ee_get_power, 5, 2),
+       [PWRC_AXG_ETHERNET_MEM_ID] = MEM_PD("ETH", meson_pwrc_mem_eth),
+       [PWRC_AXG_AUDIO_ID] = MEM_PD("AUDIO", axg_pwrc_mem_audio),
+};
+
 static struct meson_ee_pwrc_domain_desc g12a_pwrc_domains[] = {
        [PWRC_G12A_VPU_ID]  = VPU_PD("VPU", &gx_pwrc_vpu, g12a_pwrc_mem_vpu,
                                     pwrc_ee_get_power, 11, 2),
@@ -433,8 +450,8 @@ static int meson_ee_pwrc_init_domain(struct platform_device *pdev,
                if (ret)
                        return ret;
 
-               ret = pm_genpd_init(&dom->base, &pm_domain_always_on_gov,
-                                   false);
+               dom->base.flags = GENPD_FLAG_ALWAYS_ON;
+               ret = pm_genpd_init(&dom->base, NULL, false);
                if (ret)
                        return ret;
        } else {
@@ -529,6 +546,11 @@ static struct meson_ee_pwrc_domain_data meson_ee_g12a_pwrc_data = {
        .domains = g12a_pwrc_domains,
 };
 
+static struct meson_ee_pwrc_domain_data meson_ee_axg_pwrc_data = {
+       .count = ARRAY_SIZE(axg_pwrc_domains),
+       .domains = axg_pwrc_domains,
+};
+
 static struct meson_ee_pwrc_domain_data meson_ee_gxbb_pwrc_data = {
        .count = ARRAY_SIZE(gxbb_pwrc_domains),
        .domains = gxbb_pwrc_domains,
@@ -563,6 +585,10 @@ static const struct of_device_id meson_ee_pwrc_match_table[] = {
                .data = &meson_ee_m8b_pwrc_data,
        },
        {
+               .compatible = "amlogic,meson-axg-pwrc",
+               .data = &meson_ee_axg_pwrc_data,
+       },
+       {
                .compatible = "amlogic,meson-gxbb-pwrc",
                .data = &meson_ee_gxbb_pwrc_data,
        },
index 511b685..21b4bc8 100644 (file)
@@ -339,8 +339,8 @@ static int meson_gx_pwrc_vpu_probe(struct platform_device *pdev)
                        return ret;
        }
 
-       pm_genpd_init(&vpu_pd->genpd, &pm_domain_always_on_gov,
-                     powered_off);
+       vpu_pd->genpd.flags = GENPD_FLAG_ALWAYS_ON;
+       pm_genpd_init(&vpu_pd->genpd, NULL, powered_off);
 
        return of_genpd_add_provider_simple(pdev->dev.of_node,
                                            &vpu_pd->genpd);
index 648e326..24f92a6 100644 (file)
@@ -22,6 +22,15 @@ config RASPBERRYPI_POWER
          This enables support for the RPi power domains which can be enabled
          or disabled via the RPi firmware.
 
+config SOC_BCM63XX
+       bool "Broadcom 63xx SoC drivers"
+       depends on BMIPS_GENERIC || COMPILE_TEST
+       help
+         Enables drivers for the Broadcom 63xx series of chips.
+         Drivers can be enabled individually within this menu.
+
+         If unsure, say N.
+
 config SOC_BRCMSTB
        bool "Broadcom STB SoC drivers"
        depends on ARM || ARM64 || BMIPS_GENERIC || COMPILE_TEST
@@ -33,6 +42,7 @@ config SOC_BRCMSTB
 
          If unsure, say N.
 
+source "drivers/soc/bcm/bcm63xx/Kconfig"
 source "drivers/soc/bcm/brcmstb/Kconfig"
 
 endmenu
index d92268a..7bc90e0 100644 (file)
@@ -1,4 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0-only
 obj-$(CONFIG_BCM2835_POWER)    += bcm2835-power.o
 obj-$(CONFIG_RASPBERRYPI_POWER)        += raspberrypi-power.o
+obj-$(CONFIG_SOC_BCM63XX)      += bcm63xx/
 obj-$(CONFIG_SOC_BRCMSTB)      += brcmstb/
diff --git a/drivers/soc/bcm/bcm63xx/Kconfig b/drivers/soc/bcm/bcm63xx/Kconfig
new file mode 100644 (file)
index 0000000..16f648a
--- /dev/null
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0-only
+if SOC_BCM63XX
+
+config BCM63XX_POWER
+       bool "BCM63xx power domain driver"
+       depends on BMIPS_GENERIC || (COMPILE_TEST && OF)
+       select PM_GENERIC_DOMAINS if PM
+       help
+         This enables support for the BCM63xx power domains controller on
+         BCM6318, BCM6328, BCM6362 and BCM63268 SoCs.
+
+endif # SOC_BCM63XX
diff --git a/drivers/soc/bcm/bcm63xx/Makefile b/drivers/soc/bcm/bcm63xx/Makefile
new file mode 100644 (file)
index 0000000..0710d5e
--- /dev/null
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_BCM63XX_POWER) += bcm63xx-power.o
diff --git a/drivers/soc/bcm/bcm63xx/bcm63xx-power.c b/drivers/soc/bcm/bcm63xx/bcm63xx-power.c
new file mode 100644 (file)
index 0000000..515fe18
--- /dev/null
@@ -0,0 +1,378 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * BCM63xx Power Domain Controller Driver
+ *
+ * Copyright (C) 2020 Álvaro Fernández Rojas <noltari@gmail.com>
+ */
+
+#include <dt-bindings/soc/bcm6318-pm.h>
+#include <dt-bindings/soc/bcm6328-pm.h>
+#include <dt-bindings/soc/bcm6362-pm.h>
+#include <dt-bindings/soc/bcm63268-pm.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+struct bcm63xx_power_dev {
+       struct generic_pm_domain genpd;
+       struct bcm63xx_power *power;
+       uint32_t mask;
+};
+
+struct bcm63xx_power {
+       void __iomem *base;
+       spinlock_t lock;
+       struct bcm63xx_power_dev *dev;
+       struct genpd_onecell_data genpd_data;
+       struct generic_pm_domain **genpd;
+};
+
+struct bcm63xx_power_data {
+       const char * const name;
+       uint8_t bit;
+       unsigned int flags;
+};
+
+static int bcm63xx_power_get_state(struct bcm63xx_power_dev *pmd, bool *is_on)
+{
+       struct bcm63xx_power *power = pmd->power;
+
+       if (!pmd->mask) {
+               *is_on = false;
+               return -EINVAL;
+       }
+
+       *is_on = !(__raw_readl(power->base) & pmd->mask);
+
+       return 0;
+}
+
+static int bcm63xx_power_set_state(struct bcm63xx_power_dev *pmd, bool on)
+{
+       struct bcm63xx_power *power = pmd->power;
+       unsigned long flags;
+       uint32_t val;
+
+       if (!pmd->mask)
+               return -EINVAL;
+
+       spin_lock_irqsave(&power->lock, flags);
+       val = __raw_readl(power->base);
+       if (on)
+               val &= ~pmd->mask;
+       else
+               val |= pmd->mask;
+       __raw_writel(val, power->base);
+       spin_unlock_irqrestore(&power->lock, flags);
+
+       return 0;
+}
+
+static int bcm63xx_power_on(struct generic_pm_domain *genpd)
+{
+       struct bcm63xx_power_dev *pmd = container_of(genpd,
+               struct bcm63xx_power_dev, genpd);
+
+       return bcm63xx_power_set_state(pmd, true);
+}
+
+static int bcm63xx_power_off(struct generic_pm_domain *genpd)
+{
+       struct bcm63xx_power_dev *pmd = container_of(genpd,
+               struct bcm63xx_power_dev, genpd);
+
+       return bcm63xx_power_set_state(pmd, false);
+}
+
+static int bcm63xx_power_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct device_node *np = dev->of_node;
+       struct resource *res;
+       const struct bcm63xx_power_data *entry, *table;
+       struct bcm63xx_power *power;
+       unsigned int ndom;
+       uint8_t max_bit = 0;
+       int ret;
+
+       power = devm_kzalloc(dev, sizeof(*power), GFP_KERNEL);
+       if (!power)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       power->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(power->base))
+               return PTR_ERR(power->base);
+
+       table = of_device_get_match_data(dev);
+       if (!table)
+               return -EINVAL;
+
+       power->genpd_data.num_domains = 0;
+       ndom = 0;
+       for (entry = table; entry->name; entry++) {
+               max_bit = max(max_bit, entry->bit);
+               ndom++;
+       }
+
+       if (!ndom)
+               return -ENODEV;
+
+       power->genpd_data.num_domains = max_bit + 1;
+
+       power->dev = devm_kcalloc(dev, power->genpd_data.num_domains,
+                                 sizeof(struct bcm63xx_power_dev),
+                                 GFP_KERNEL);
+       if (!power->dev)
+               return -ENOMEM;
+
+       power->genpd = devm_kcalloc(dev, power->genpd_data.num_domains,
+                                   sizeof(struct generic_pm_domain *),
+                                   GFP_KERNEL);
+       if (!power->genpd)
+               return -ENOMEM;
+
+       power->genpd_data.domains = power->genpd;
+
+       ndom = 0;
+       for (entry = table; entry->name; entry++) {
+               struct bcm63xx_power_dev *pmd = &power->dev[ndom];
+               bool is_on;
+
+               pmd->power = power;
+               pmd->mask = BIT(entry->bit);
+               pmd->genpd.name = entry->name;
+               pmd->genpd.flags = entry->flags;
+
+               ret = bcm63xx_power_get_state(pmd, &is_on);
+               if (ret)
+                       dev_warn(dev, "unable to get current state for %s\n",
+                                pmd->genpd.name);
+
+               pmd->genpd.power_on = bcm63xx_power_on;
+               pmd->genpd.power_off = bcm63xx_power_off;
+
+               pm_genpd_init(&pmd->genpd, NULL, !is_on);
+               power->genpd[entry->bit] = &pmd->genpd;
+
+               ndom++;
+       }
+
+       spin_lock_init(&power->lock);
+
+       ret = of_genpd_add_provider_onecell(np, &power->genpd_data);
+       if (ret) {
+               dev_err(dev, "failed to register genpd driver: %d\n", ret);
+               return ret;
+       }
+
+       dev_info(dev, "registered %u power domains\n", ndom);
+
+       return 0;
+}
+
+static const struct bcm63xx_power_data bcm6318_power_domains[] = {
+       {
+               .name = "pcie",
+               .bit = BCM6318_POWER_DOMAIN_PCIE,
+       }, {
+               .name = "usb",
+               .bit = BCM6318_POWER_DOMAIN_USB,
+       }, {
+               .name = "ephy0",
+               .bit = BCM6318_POWER_DOMAIN_EPHY0,
+       }, {
+               .name = "ephy1",
+               .bit = BCM6318_POWER_DOMAIN_EPHY1,
+       }, {
+               .name = "ephy2",
+               .bit = BCM6318_POWER_DOMAIN_EPHY2,
+       }, {
+               .name = "ephy3",
+               .bit = BCM6318_POWER_DOMAIN_EPHY3,
+       }, {
+               .name = "ldo2p5",
+               .bit = BCM6318_POWER_DOMAIN_LDO2P5,
+               .flags = GENPD_FLAG_ALWAYS_ON,
+       }, {
+               .name = "ldo2p9",
+               .bit = BCM6318_POWER_DOMAIN_LDO2P9,
+               .flags = GENPD_FLAG_ALWAYS_ON,
+       }, {
+               .name = "sw1p0",
+               .bit = BCM6318_POWER_DOMAIN_SW1P0,
+               .flags = GENPD_FLAG_ALWAYS_ON,
+       }, {
+               .name = "pad",
+               .bit = BCM6318_POWER_DOMAIN_PAD,
+               .flags = GENPD_FLAG_ALWAYS_ON,
+       }, {
+               /* sentinel */
+       },
+};
+
+static const struct bcm63xx_power_data bcm6328_power_domains[] = {
+       {
+               .name = "adsl2-mips",
+               .bit = BCM6328_POWER_DOMAIN_ADSL2_MIPS,
+       }, {
+               .name = "adsl2-phy",
+               .bit = BCM6328_POWER_DOMAIN_ADSL2_PHY,
+       }, {
+               .name = "adsl2-afe",
+               .bit = BCM6328_POWER_DOMAIN_ADSL2_AFE,
+       }, {
+               .name = "sar",
+               .bit = BCM6328_POWER_DOMAIN_SAR,
+       }, {
+               .name = "pcm",
+               .bit = BCM6328_POWER_DOMAIN_PCM,
+       }, {
+               .name = "usbd",
+               .bit = BCM6328_POWER_DOMAIN_USBD,
+       }, {
+               .name = "usbh",
+               .bit = BCM6328_POWER_DOMAIN_USBH,
+       }, {
+               .name = "pcie",
+               .bit = BCM6328_POWER_DOMAIN_PCIE,
+       }, {
+               .name = "robosw",
+               .bit = BCM6328_POWER_DOMAIN_ROBOSW,
+       }, {
+               .name = "ephy",
+               .bit = BCM6328_POWER_DOMAIN_EPHY,
+       }, {
+               /* sentinel */
+       },
+};
+
+static const struct bcm63xx_power_data bcm6362_power_domains[] = {
+       {
+               .name = "sar",
+               .bit = BCM6362_POWER_DOMAIN_SAR,
+       }, {
+               .name = "ipsec",
+               .bit = BCM6362_POWER_DOMAIN_IPSEC,
+       }, {
+               .name = "mips",
+               .bit = BCM6362_POWER_DOMAIN_MIPS,
+               .flags = GENPD_FLAG_ALWAYS_ON,
+       }, {
+               .name = "dect",
+               .bit = BCM6362_POWER_DOMAIN_DECT,
+       }, {
+               .name = "usbh",
+               .bit = BCM6362_POWER_DOMAIN_USBH,
+       }, {
+               .name = "usbd",
+               .bit = BCM6362_POWER_DOMAIN_USBD,
+       }, {
+               .name = "robosw",
+               .bit = BCM6362_POWER_DOMAIN_ROBOSW,
+       }, {
+               .name = "pcm",
+               .bit = BCM6362_POWER_DOMAIN_PCM,
+       }, {
+               .name = "periph",
+               .bit = BCM6362_POWER_DOMAIN_PERIPH,
+               .flags = GENPD_FLAG_ALWAYS_ON,
+       }, {
+               .name = "adsl-phy",
+               .bit = BCM6362_POWER_DOMAIN_ADSL_PHY,
+       }, {
+               .name = "gmii-pads",
+               .bit = BCM6362_POWER_DOMAIN_GMII_PADS,
+       }, {
+               .name = "fap",
+               .bit = BCM6362_POWER_DOMAIN_FAP,
+       }, {
+               .name = "pcie",
+               .bit = BCM6362_POWER_DOMAIN_PCIE,
+       }, {
+               .name = "wlan-pads",
+               .bit = BCM6362_POWER_DOMAIN_WLAN_PADS,
+       }, {
+               /* sentinel */
+       },
+};
+
+static const struct bcm63xx_power_data bcm63268_power_domains[] = {
+       {
+               .name = "sar",
+               .bit = BCM63268_POWER_DOMAIN_SAR,
+       }, {
+               .name = "ipsec",
+               .bit = BCM63268_POWER_DOMAIN_IPSEC,
+       }, {
+               .name = "mips",
+               .bit = BCM63268_POWER_DOMAIN_MIPS,
+               .flags = GENPD_FLAG_ALWAYS_ON,
+       }, {
+               .name = "dect",
+               .bit = BCM63268_POWER_DOMAIN_DECT,
+       }, {
+               .name = "usbh",
+               .bit = BCM63268_POWER_DOMAIN_USBH,
+       }, {
+               .name = "usbd",
+               .bit = BCM63268_POWER_DOMAIN_USBD,
+       }, {
+               .name = "robosw",
+               .bit = BCM63268_POWER_DOMAIN_ROBOSW,
+       }, {
+               .name = "pcm",
+               .bit = BCM63268_POWER_DOMAIN_PCM,
+       }, {
+               .name = "periph",
+               .bit = BCM63268_POWER_DOMAIN_PERIPH,
+               .flags = GENPD_FLAG_ALWAYS_ON,
+       }, {
+               .name = "vdsl-phy",
+               .bit = BCM63268_POWER_DOMAIN_VDSL_PHY,
+       }, {
+               .name = "vdsl-mips",
+               .bit = BCM63268_POWER_DOMAIN_VDSL_MIPS,
+       }, {
+               .name = "fap",
+               .bit = BCM63268_POWER_DOMAIN_FAP,
+       }, {
+               .name = "pcie",
+               .bit = BCM63268_POWER_DOMAIN_PCIE,
+       }, {
+               .name = "wlan-pads",
+               .bit = BCM63268_POWER_DOMAIN_WLAN_PADS,
+       }, {
+               /* sentinel */
+       },
+};
+
+static const struct of_device_id bcm63xx_power_of_match[] = {
+       {
+               .compatible = "brcm,bcm6318-power-controller",
+               .data = &bcm6318_power_domains,
+       }, {
+               .compatible = "brcm,bcm6328-power-controller",
+               .data = &bcm6328_power_domains,
+       }, {
+               .compatible = "brcm,bcm6362-power-controller",
+               .data = &bcm6362_power_domains,
+       }, {
+               .compatible = "brcm,bcm63268-power-controller",
+               .data = &bcm63268_power_domains,
+       }, {
+               /* sentinel */
+       }
+};
+
+static struct platform_driver bcm63xx_power_driver = {
+       .driver = {
+               .name = "bcm63xx-power-controller",
+               .of_match_table = bcm63xx_power_of_match,
+       },
+       .probe  = bcm63xx_power_probe,
+};
+builtin_platform_driver(bcm63xx_power_driver);
index 61731e0..7f8dc30 100644 (file)
 #include <linux/syscore_ops.h>
 #include <linux/soc/brcmstb/brcmstb.h>
 
+#define RACENPREF_MASK                 0x3
+#define RACPREFINST_SHIFT              0
+#define RACENINST_SHIFT                        2
+#define RACPREFDATA_SHIFT              4
+#define RACENDATA_SHIFT                        6
+#define RAC_CPU_SHIFT                  8
+#define RACCFG_MASK                    0xff
+#define DPREF_LINE_2_SHIFT             24
+#define DPREF_LINE_2_MASK              0xff
+
+/* Bitmask to enable instruction and data prefetching with a 256-bytes stride */
+#define RAC_DATA_INST_EN_MASK          (1 << RACPREFINST_SHIFT | \
+                                        RACENPREF_MASK << RACENINST_SHIFT | \
+                                        1 << RACPREFDATA_SHIFT | \
+                                        RACENPREF_MASK << RACENDATA_SHIFT)
+
 #define  CPU_CREDIT_REG_MCPx_WR_PAIRING_EN_MASK        0x70000000
 #define CPU_CREDIT_REG_MCPx_READ_CRED_MASK     0xf
 #define CPU_CREDIT_REG_MCPx_WRITE_CRED_MASK    0xf
@@ -31,11 +47,21 @@ static void __iomem *cpubiuctrl_base;
 static bool mcp_wr_pairing_en;
 static const int *cpubiuctrl_regs;
 
+enum cpubiuctrl_regs {
+       CPU_CREDIT_REG = 0,
+       CPU_MCP_FLOW_REG,
+       CPU_WRITEBACK_CTRL_REG,
+       RAC_CONFIG0_REG,
+       RAC_CONFIG1_REG,
+       NUM_CPU_BIUCTRL_REGS,
+};
+
 static inline u32 cbc_readl(int reg)
 {
        int offset = cpubiuctrl_regs[reg];
 
-       if (offset == -1)
+       if (offset == -1 ||
+           (IS_ENABLED(CONFIG_CACHE_B15_RAC) && reg >= RAC_CONFIG0_REG))
                return (u32)-1;
 
        return readl_relaxed(cpubiuctrl_base + offset);
@@ -45,22 +71,19 @@ static inline void cbc_writel(u32 val, int reg)
 {
        int offset = cpubiuctrl_regs[reg];
 
-       if (offset == -1)
+       if (offset == -1 ||
+           (IS_ENABLED(CONFIG_CACHE_B15_RAC) && reg >= RAC_CONFIG0_REG))
                return;
 
        writel(val, cpubiuctrl_base + offset);
 }
 
-enum cpubiuctrl_regs {
-       CPU_CREDIT_REG = 0,
-       CPU_MCP_FLOW_REG,
-       CPU_WRITEBACK_CTRL_REG
-};
-
 static const int b15_cpubiuctrl_regs[] = {
        [CPU_CREDIT_REG] = 0x184,
        [CPU_MCP_FLOW_REG] = -1,
        [CPU_WRITEBACK_CTRL_REG] = -1,
+       [RAC_CONFIG0_REG] = -1,
+       [RAC_CONFIG1_REG] = -1,
 };
 
 /* Odd cases, e.g: 7260A0 */
@@ -68,22 +91,26 @@ static const int b53_cpubiuctrl_no_wb_regs[] = {
        [CPU_CREDIT_REG] = 0x0b0,
        [CPU_MCP_FLOW_REG] = 0x0b4,
        [CPU_WRITEBACK_CTRL_REG] = -1,
+       [RAC_CONFIG0_REG] = 0x78,
+       [RAC_CONFIG1_REG] = 0x7c,
 };
 
 static const int b53_cpubiuctrl_regs[] = {
        [CPU_CREDIT_REG] = 0x0b0,
        [CPU_MCP_FLOW_REG] = 0x0b4,
        [CPU_WRITEBACK_CTRL_REG] = 0x22c,
+       [RAC_CONFIG0_REG] = 0x78,
+       [RAC_CONFIG1_REG] = 0x7c,
 };
 
 static const int a72_cpubiuctrl_regs[] = {
        [CPU_CREDIT_REG] = 0x18,
        [CPU_MCP_FLOW_REG] = 0x1c,
        [CPU_WRITEBACK_CTRL_REG] = 0x20,
+       [RAC_CONFIG0_REG] = 0x08,
+       [RAC_CONFIG1_REG] = 0x0c,
 };
 
-#define NUM_CPU_BIUCTRL_REGS   3
-
 static int __init mcp_write_pairing_set(void)
 {
        u32 creds = 0;
@@ -110,6 +137,8 @@ static int __init mcp_write_pairing_set(void)
 static const u32 a72_b53_mach_compat[] = {
        0x7211,
        0x7216,
+       0x72164,
+       0x72165,
        0x7255,
        0x7260,
        0x7268,
@@ -117,6 +146,61 @@ static const u32 a72_b53_mach_compat[] = {
        0x7278,
 };
 
+/* The read-ahead cache present in the Brahma-B53 CPU is a special piece of
+ * hardware after the integrated L2 cache of the B53 CPU complex whose purpose
+ * is to prefetch instruction and/or data with a line size of either 64 bytes
+ * or 256 bytes. The rationale is that the data-bus of the CPU interface is
+ * optimized for 256-byte transactions, and enabling the read-ahead cache
+ * provides a significant performance boost (typically twice the performance
+ * for a memcpy benchmark application).
+ *
+ * The read-ahead cache is transparent for Virtual Address cache maintenance
+ * operations: IC IVAU, DC IVAC, DC CVAC, DC CVAU and DC CIVAC.  So no special
+ * handling is needed for the DMA API above and beyond what is included in the
+ * arm64 implementation.
+ *
+ * In addition, since the Point of Unification is typically between L1 and L2
+ * for the Brahma-B53 processor no special read-ahead cache handling is needed
+ * for the IC IALLU and IC IALLUIS cache maintenance operations.
+ *
+ * However, it is not possible to specify the cache level (L3) for the cache
+ * maintenance instructions operating by set/way to operate on the read-ahead
+ * cache.  The read-ahead cache will maintain coherency when inner cache lines
+ * are cleaned by set/way, but if it is necessary to invalidate inner cache
+ * lines by set/way to maintain coherency with system masters operating on
+ * shared memory that does not have hardware support for coherency, then it
+ * will also be necessary to explicitly invalidate the read-ahead cache.
+ */
+static void __init a72_b53_rac_enable_all(struct device_node *np)
+{
+       unsigned int cpu;
+       u32 enable = 0, pref_dist, shift;
+
+       if (IS_ENABLED(CONFIG_CACHE_B15_RAC))
+               return;
+
+       if (WARN(num_possible_cpus() > 4, "RAC only supports 4 CPUs\n"))
+               return;
+
+       pref_dist = cbc_readl(RAC_CONFIG1_REG);
+       for_each_possible_cpu(cpu) {
+               shift = cpu * RAC_CPU_SHIFT + RACPREFDATA_SHIFT;
+               enable |= RAC_DATA_INST_EN_MASK << (cpu * RAC_CPU_SHIFT);
+               if (cpubiuctrl_regs == a72_cpubiuctrl_regs) {
+                       enable &= ~(RACENPREF_MASK << shift);
+                       enable |= 3 << shift;
+                       pref_dist |= 1 << (cpu + DPREF_LINE_2_SHIFT);
+               }
+       }
+
+       cbc_writel(enable, RAC_CONFIG0_REG);
+       cbc_writel(pref_dist, RAC_CONFIG1_REG);
+
+       pr_info("%pOF: Broadcom %s read-ahead cache\n",
+               np, cpubiuctrl_regs == a72_cpubiuctrl_regs ?
+               "Cortex-A72" : "Brahma-B53");
+}
+
 static void __init mcp_a72_b53_set(void)
 {
        unsigned int i;
@@ -262,6 +346,7 @@ static int __init brcmstb_biuctrl_init(void)
                return ret;
        }
 
+       a72_b53_rac_enable_all(np);
        mcp_a72_b53_set();
 #ifdef CONFIG_PM_SLEEP
        register_syscore_ops(&brcmstb_cpu_credit_syscore_ops);
index 0ab85bf..659b4a5 100644 (file)
@@ -647,7 +647,6 @@ int qbman_swp_enqueue_multiple_direct(struct qbman_swp *s,
        const uint32_t *cl = (uint32_t *)d;
        uint32_t eqcr_ci, eqcr_pi, half_mask, full_mask;
        int i, num_enqueued = 0;
-       uint64_t addr_cena;
 
        spin_lock(&s->access_spinlock);
        half_mask = (s->eqcr.pi_ci_mask>>1);
@@ -701,7 +700,6 @@ int qbman_swp_enqueue_multiple_direct(struct qbman_swp *s,
 
        /* Flush all the cacheline without load/store in between */
        eqcr_pi = s->eqcr.pi;
-       addr_cena = (size_t)s->addr_cena;
        for (i = 0; i < num_enqueued; i++)
                eqcr_pi++;
        s->eqcr.pi = eqcr_pi & full_mask;
index f4fb527..c5dd026 100644 (file)
@@ -660,7 +660,7 @@ int bm_shutdown_pool(u32 bpid)
        }
 done:
        put_affine_portal();
-       return 0;
+       return err;
 }
 
 struct gen_pool *bm_bpalloc;
index 2895d06..7066b2f 100644 (file)
@@ -86,7 +86,7 @@ static void fd_inc(struct qm_fd *fd)
        len--;
        qm_fd_set_param(fd, fmt, off, len);
 
-       fd->cmd = cpu_to_be32(be32_to_cpu(fd->cmd) + 1);
+       be32_add_cpu(&fd->cmd, 1);
 }
 
 /* The only part of the 'fd' we can't memcmp() is the ppid */
index cac0fb7..21dbcd7 100644 (file)
@@ -523,7 +523,7 @@ int ucc_set_tdm_rxtx_clk(u32 tdm_num, enum qe_clock clock,
 
        qe_mux_reg = &qe_immr->qmx;
 
-       if (tdm_num > 7 || tdm_num < 0)
+       if (tdm_num > 7)
                return -EINVAL;
 
        /* The communications direction must be RX or TX */
index 6cf8a7a..db7e7fc 100644 (file)
@@ -487,22 +487,17 @@ static int imx_pgc_domain_probe(struct platform_device *pdev)
 
        domain->regulator = devm_regulator_get_optional(domain->dev, "power");
        if (IS_ERR(domain->regulator)) {
-               if (PTR_ERR(domain->regulator) != -ENODEV) {
-                       if (PTR_ERR(domain->regulator) != -EPROBE_DEFER)
-                               dev_err(domain->dev, "Failed to get domain's regulator\n");
-                       return PTR_ERR(domain->regulator);
-               }
+               if (PTR_ERR(domain->regulator) != -ENODEV)
+                       return dev_err_probe(domain->dev, PTR_ERR(domain->regulator),
+                                            "Failed to get domain's regulator\n");
        } else if (domain->voltage) {
                regulator_set_voltage(domain->regulator,
                                      domain->voltage, domain->voltage);
        }
 
        ret = imx_pgc_get_clocks(domain);
-       if (ret) {
-               if (ret != -EPROBE_DEFER)
-                       dev_err(domain->dev, "Failed to get domain's clocks\n");
-               return ret;
-       }
+       if (ret)
+               return dev_err_probe(domain->dev, ret, "Failed to get domain's clocks\n");
 
        ret = pm_genpd_init(&domain->genpd, NULL, true);
        if (ret) {
index dc644cf..505651b 100644 (file)
 #define CMDQ_POLL_ENABLE_MASK  BIT(0)
 #define CMDQ_EOC_IRQ_EN                BIT(0)
 #define CMDQ_REG_TYPE          1
+#define CMDQ_JUMP_RELATIVE     1
 
 struct cmdq_instruction {
        union {
                u32 value;
                u32 mask;
+               struct {
+                       u16 arg_c;
+                       u16 src_reg;
+               };
        };
        union {
                u16 offset;
@@ -223,15 +228,104 @@ int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u8 subsys,
 }
 EXPORT_SYMBOL(cmdq_pkt_write_mask);
 
-int cmdq_pkt_wfe(struct cmdq_pkt *pkt, u16 event)
+int cmdq_pkt_read_s(struct cmdq_pkt *pkt, u16 high_addr_reg_idx, u16 addr_low,
+                   u16 reg_idx)
+{
+       struct cmdq_instruction inst = {};
+
+       inst.op = CMDQ_CODE_READ_S;
+       inst.dst_t = CMDQ_REG_TYPE;
+       inst.sop = high_addr_reg_idx;
+       inst.reg_dst = reg_idx;
+       inst.src_reg = addr_low;
+
+       return cmdq_pkt_append_command(pkt, inst);
+}
+EXPORT_SYMBOL(cmdq_pkt_read_s);
+
+int cmdq_pkt_write_s(struct cmdq_pkt *pkt, u16 high_addr_reg_idx,
+                    u16 addr_low, u16 src_reg_idx)
+{
+       struct cmdq_instruction inst = {};
+
+       inst.op = CMDQ_CODE_WRITE_S;
+       inst.src_t = CMDQ_REG_TYPE;
+       inst.sop = high_addr_reg_idx;
+       inst.offset = addr_low;
+       inst.src_reg = src_reg_idx;
+
+       return cmdq_pkt_append_command(pkt, inst);
+}
+EXPORT_SYMBOL(cmdq_pkt_write_s);
+
+int cmdq_pkt_write_s_mask(struct cmdq_pkt *pkt, u16 high_addr_reg_idx,
+                         u16 addr_low, u16 src_reg_idx, u32 mask)
+{
+       struct cmdq_instruction inst = {};
+       int err;
+
+       inst.op = CMDQ_CODE_MASK;
+       inst.mask = ~mask;
+       err = cmdq_pkt_append_command(pkt, inst);
+       if (err < 0)
+               return err;
+
+       inst.mask = 0;
+       inst.op = CMDQ_CODE_WRITE_S_MASK;
+       inst.src_t = CMDQ_REG_TYPE;
+       inst.sop = high_addr_reg_idx;
+       inst.offset = addr_low;
+       inst.src_reg = src_reg_idx;
+
+       return cmdq_pkt_append_command(pkt, inst);
+}
+EXPORT_SYMBOL(cmdq_pkt_write_s_mask);
+
+int cmdq_pkt_write_s_value(struct cmdq_pkt *pkt, u8 high_addr_reg_idx,
+                          u16 addr_low, u32 value)
+{
+       struct cmdq_instruction inst = {};
+
+       inst.op = CMDQ_CODE_WRITE_S;
+       inst.sop = high_addr_reg_idx;
+       inst.offset = addr_low;
+       inst.value = value;
+
+       return cmdq_pkt_append_command(pkt, inst);
+}
+EXPORT_SYMBOL(cmdq_pkt_write_s_value);
+
+int cmdq_pkt_write_s_mask_value(struct cmdq_pkt *pkt, u8 high_addr_reg_idx,
+                               u16 addr_low, u32 value, u32 mask)
+{
+       struct cmdq_instruction inst = {};
+       int err;
+
+       inst.op = CMDQ_CODE_MASK;
+       inst.mask = ~mask;
+       err = cmdq_pkt_append_command(pkt, inst);
+       if (err < 0)
+               return err;
+
+       inst.op = CMDQ_CODE_WRITE_S_MASK;
+       inst.sop = high_addr_reg_idx;
+       inst.offset = addr_low;
+       inst.value = value;
+
+       return cmdq_pkt_append_command(pkt, inst);
+}
+EXPORT_SYMBOL(cmdq_pkt_write_s_mask_value);
+
+int cmdq_pkt_wfe(struct cmdq_pkt *pkt, u16 event, bool clear)
 {
        struct cmdq_instruction inst = { {0} };
+       u32 clear_option = clear ? CMDQ_WFE_UPDATE : 0;
 
        if (event >= CMDQ_MAX_EVENT)
                return -EINVAL;
 
        inst.op = CMDQ_CODE_WFE;
-       inst.value = CMDQ_WFE_OPTION;
+       inst.value = CMDQ_WFE_OPTION | clear_option;
        inst.event = event;
 
        return cmdq_pkt_append_command(pkt, inst);
@@ -315,6 +409,18 @@ int cmdq_pkt_assign(struct cmdq_pkt *pkt, u16 reg_idx, u32 value)
 }
 EXPORT_SYMBOL(cmdq_pkt_assign);
 
+int cmdq_pkt_jump(struct cmdq_pkt *pkt, dma_addr_t addr)
+{
+       struct cmdq_instruction inst = {};
+
+       inst.op = CMDQ_CODE_JUMP;
+       inst.offset = CMDQ_JUMP_RELATIVE;
+       inst.value = addr >>
+               cmdq_get_shift_pa(((struct cmdq_client *)pkt->cl)->chan);
+       return cmdq_pkt_append_command(pkt, inst);
+}
+EXPORT_SYMBOL(cmdq_pkt_jump);
+
 int cmdq_pkt_finalize(struct cmdq_pkt *pkt)
 {
        struct cmdq_instruction inst = { {0} };
@@ -329,7 +435,8 @@ int cmdq_pkt_finalize(struct cmdq_pkt *pkt)
 
        /* JUMP to end */
        inst.op = CMDQ_CODE_JUMP;
-       inst.value = CMDQ_JUMP_PASS;
+       inst.value = CMDQ_JUMP_PASS >>
+               cmdq_get_shift_pa(((struct cmdq_client *)pkt->cl)->chan);
        err = cmdq_pkt_append_command(pkt, inst);
 
        return err;
index 341c7ac..4a12379 100644 (file)
@@ -19,7 +19,7 @@
 
 /**
  * mtk_infracfg_set_bus_protection - enable bus protection
- * @regmap: The infracfg regmap
+ * @infracfg: The infracfg regmap
  * @mask: The mask containing the protection bits to be enabled.
  * @reg_update: The boolean flag determines to set the protection bits
  *              by regmap_update_bits with enable register(PROTECTEN) or
@@ -50,7 +50,7 @@ int mtk_infracfg_set_bus_protection(struct regmap *infracfg, u32 mask,
 
 /**
  * mtk_infracfg_clear_bus_protection - disable bus protection
- * @regmap: The infracfg regmap
+ * @infracfg: The infracfg regmap
  * @mask: The mask containing the protection bits to be disabled.
  * @reg_update: The boolean flag determines to clear the protection bits
  *              by regmap_update_bits with enable register(PROTECTEN) or
index 1f35b09..7abfc8c 100644 (file)
@@ -328,7 +328,7 @@ static int of_apr_add_pd_lookups(struct device *dev)
 
                pds = pdr_add_lookup(apr->pdr, service_name, service_path);
                if (IS_ERR(pds) && PTR_ERR(pds) != -EALREADY) {
-                       dev_err(dev, "pdr add lookup failed: %d\n", ret);
+                       dev_err(dev, "pdr add lookup failed: %ld\n", PTR_ERR(pds));
                        return PTR_ERR(pds);
                }
        }
index 429b5a6..70fbe70 100644 (file)
@@ -387,7 +387,6 @@ static int qcom_llcc_remove(struct platform_device *pdev)
 static struct regmap *qcom_llcc_init_mmio(struct platform_device *pdev,
                const char *name)
 {
-       struct resource *res;
        void __iomem *base;
        struct regmap_config llcc_regmap_config = {
                .reg_bits = 32,
@@ -396,11 +395,7 @@ static struct regmap *qcom_llcc_init_mmio(struct platform_device *pdev,
                .fast_io = true,
        };
 
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
-       if (!res)
-               return ERR_PTR(-ENODEV);
-
-       base = devm_ioremap_resource(&pdev->dev, res);
+       base = devm_platform_ioremap_resource_byname(pdev, name);
        if (IS_ERR(base))
                return ERR_CAST(base);
 
index ef60e79..344ba68 100644 (file)
@@ -8,6 +8,7 @@
 #define __RPM_INTERNAL_H__
 
 #include <linux/bitmap.h>
+#include <linux/wait.h>
 #include <soc/qcom/tcs.h>
 
 #define TCS_TYPE_NR                    4
@@ -106,6 +107,8 @@ struct rpmh_ctrlr {
  * @lock:               Synchronize state of the controller.  If RPMH's cache
  *                      lock will also be held, the order is: drv->lock then
  *                      cache_lock.
+ * @tcs_wait:           Wait queue used to wait for @tcs_in_use to free up a
+ *                      slot
  * @client:             Handle to the DRV's client.
  */
 struct rsc_drv {
@@ -118,6 +121,7 @@ struct rsc_drv {
        struct tcs_group tcs[TCS_TYPE_NR];
        DECLARE_BITMAP(tcs_in_use, MAX_TCS_NR);
        spinlock_t lock;
+       wait_queue_head_t tcs_wait;
        struct rpmh_ctrlr client;
 };
 
index ae66757..a297911 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
+#include <linux/wait.h>
 
 #include <soc/qcom/cmd-db.h>
 #include <soc/qcom/tcs.h>
@@ -453,6 +454,7 @@ skip:
                if (!drv->tcs[ACTIVE_TCS].num_tcs)
                        enable_tcs_irq(drv, i, false);
                spin_unlock(&drv->lock);
+               wake_up(&drv->tcs_wait);
                if (req)
                        rpmh_tx_done(req, err);
        }
@@ -571,73 +573,34 @@ static int find_free_tcs(struct tcs_group *tcs)
 }
 
 /**
- * tcs_write() - Store messages into a TCS right now, or return -EBUSY.
+ * claim_tcs_for_req() - Claim a tcs in the given tcs_group; only for active.
  * @drv: The controller.
+ * @tcs: The tcs_group used for ACTIVE_ONLY transfers.
  * @msg: The data to be sent.
  *
- * Grabs a TCS for ACTIVE_ONLY transfers and writes the messages to it.
+ * Claims a tcs in the given tcs_group while making sure that no existing cmd
+ * is in flight that would conflict with the one in @msg.
  *
- * If there are no free TCSes for ACTIVE_ONLY transfers or if a command for
- * the same address is already transferring returns -EBUSY which means the
- * client should retry shortly.
+ * Context: Must be called with the drv->lock held since that protects
+ * tcs_in_use.
  *
- * Return: 0 on success, -EBUSY if client should retry, or an error.
- *         Client should have interrupts enabled for a bit before retrying.
+ * Return: The id of the claimed tcs or -EBUSY if a matching msg is in flight
+ * or the tcs_group is full.
  */
-static int tcs_write(struct rsc_drv *drv, const struct tcs_request *msg)
+static int claim_tcs_for_req(struct rsc_drv *drv, struct tcs_group *tcs,
+                            const struct tcs_request *msg)
 {
-       struct tcs_group *tcs;
-       int tcs_id;
-       unsigned long flags;
        int ret;
 
-       tcs = get_tcs_for_msg(drv, msg);
-       if (IS_ERR(tcs))
-               return PTR_ERR(tcs);
-
-       spin_lock_irqsave(&drv->lock, flags);
        /*
         * The h/w does not like if we send a request to the same address,
         * when one is already in-flight or being processed.
         */
        ret = check_for_req_inflight(drv, tcs, msg);
        if (ret)
-               goto unlock;
-
-       ret = find_free_tcs(tcs);
-       if (ret < 0)
-               goto unlock;
-       tcs_id = ret;
-
-       tcs->req[tcs_id - tcs->offset] = msg;
-       set_bit(tcs_id, drv->tcs_in_use);
-       if (msg->state == RPMH_ACTIVE_ONLY_STATE && tcs->type != ACTIVE_TCS) {
-               /*
-                * Clear previously programmed WAKE commands in selected
-                * repurposed TCS to avoid triggering them. tcs->slots will be
-                * cleaned from rpmh_flush() by invoking rpmh_rsc_invalidate()
-                */
-               write_tcs_reg_sync(drv, RSC_DRV_CMD_ENABLE, tcs_id, 0);
-               write_tcs_reg_sync(drv, RSC_DRV_CMD_WAIT_FOR_CMPL, tcs_id, 0);
-               enable_tcs_irq(drv, tcs_id, true);
-       }
-       spin_unlock_irqrestore(&drv->lock, flags);
-
-       /*
-        * These two can be done after the lock is released because:
-        * - We marked "tcs_in_use" under lock.
-        * - Once "tcs_in_use" has been marked nobody else could be writing
-        *   to these registers until the interrupt goes off.
-        * - The interrupt can't go off until we trigger w/ the last line
-        *   of __tcs_set_trigger() below.
-        */
-       __tcs_buffer_write(drv, tcs_id, 0, msg);
-       __tcs_set_trigger(drv, tcs_id, true);
+               return ret;
 
-       return 0;
-unlock:
-       spin_unlock_irqrestore(&drv->lock, flags);
-       return ret;
+       return find_free_tcs(tcs);
 }
 
 /**
@@ -664,18 +627,47 @@ unlock:
  */
 int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg)
 {
-       int ret;
+       struct tcs_group *tcs;
+       int tcs_id;
+       unsigned long flags;
 
-       do {
-               ret = tcs_write(drv, msg);
-               if (ret == -EBUSY) {
-                       pr_info_ratelimited("TCS Busy, retrying RPMH message send: addr=%#x\n",
-                                           msg->cmds[0].addr);
-                       udelay(10);
-               }
-       } while (ret == -EBUSY);
+       tcs = get_tcs_for_msg(drv, msg);
+       if (IS_ERR(tcs))
+               return PTR_ERR(tcs);
 
-       return ret;
+       spin_lock_irqsave(&drv->lock, flags);
+
+       /* Wait forever for a free tcs. It better be there eventually! */
+       wait_event_lock_irq(drv->tcs_wait,
+                           (tcs_id = claim_tcs_for_req(drv, tcs, msg)) >= 0,
+                           drv->lock);
+
+       tcs->req[tcs_id - tcs->offset] = msg;
+       set_bit(tcs_id, drv->tcs_in_use);
+       if (msg->state == RPMH_ACTIVE_ONLY_STATE && tcs->type != ACTIVE_TCS) {
+               /*
+                * Clear previously programmed WAKE commands in selected
+                * repurposed TCS to avoid triggering them. tcs->slots will be
+                * cleaned from rpmh_flush() by invoking rpmh_rsc_invalidate()
+                */
+               write_tcs_reg_sync(drv, RSC_DRV_CMD_ENABLE, tcs_id, 0);
+               write_tcs_reg_sync(drv, RSC_DRV_CMD_WAIT_FOR_CMPL, tcs_id, 0);
+               enable_tcs_irq(drv, tcs_id, true);
+       }
+       spin_unlock_irqrestore(&drv->lock, flags);
+
+       /*
+        * These two can be done after the lock is released because:
+        * - We marked "tcs_in_use" under lock.
+        * - Once "tcs_in_use" has been marked nobody else could be writing
+        *   to these registers until the interrupt goes off.
+        * - The interrupt can't go off until we trigger w/ the last line
+        *   of __tcs_set_trigger() below.
+        */
+       __tcs_buffer_write(drv, tcs_id, 0, msg);
+       __tcs_set_trigger(drv, tcs_id, true);
+
+       return 0;
 }
 
 /**
@@ -983,6 +975,7 @@ static int rpmh_rsc_probe(struct platform_device *pdev)
                return ret;
 
        spin_lock_init(&drv->lock);
+       init_waitqueue_head(&drv->tcs_wait);
        bitmap_zero(drv->tcs_in_use, MAX_TCS_NR);
 
        irq = platform_get_irq(pdev, drv->id);
index b25d0f7..b44ede4 100644 (file)
@@ -194,6 +194,7 @@ static const struct soc_id soc_id[] = {
        { 186, "MSM8674" },
        { 194, "MSM8974PRO" },
        { 206, "MSM8916" },
+       { 207, "MSM8994" },
        { 208, "APQ8074-AA" },
        { 209, "APQ8074-AB" },
        { 210, "APQ8074PRO" },
@@ -214,6 +215,8 @@ static const struct soc_id soc_id[] = {
        { 248, "MSM8216" },
        { 249, "MSM8116" },
        { 250, "MSM8616" },
+       { 251, "MSM8992" },
+       { 253, "APQ8094" },
        { 291, "APQ8096" },
        { 305, "MSM8996SG" },
        { 310, "MSM8996AU" },
@@ -223,6 +226,8 @@ static const struct soc_id soc_id[] = {
        { 321, "SDM845" },
        { 341, "SDA845" },
        { 356, "SM8250" },
+       { 402, "IPQ6018" },
+       { 425, "SC7180" },
 };
 
 static const char *socinfo_machine(struct device *dev, unsigned int id)
index 3098465..b70bbc3 100644 (file)
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
-config SOC_RENESAS
+menuconfig SOC_RENESAS
        bool "Renesas SoC driver support" if COMPILE_TEST && !ARCH_RENESAS
        default y if ARCH_RENESAS
        select SOC_BUS
@@ -49,126 +49,126 @@ if ARM && ARCH_RENESAS
 #comment "Renesas ARM SoCs System Type"
 
 config ARCH_EMEV2
-       bool "Emma Mobile EV2"
+       bool "ARM32 Platform support for Emma Mobile EV2"
        select HAVE_ARM_SCU if SMP
        select SYS_SUPPORTS_EM_STI
 
-config ARCH_R7S72100
-       bool "RZ/A1H (R7S72100)"
-       select ARM_ERRATA_754322
-       select PM
-       select PM_GENERIC_DOMAINS
-       select RENESAS_OSTM
-       select RENESAS_RZA1_IRQC
-       select SYS_SUPPORTS_SH_MTU2
+config ARCH_R8A7794
+       bool "ARM32 Platform support for R-Car E2"
+       select ARCH_RCAR_GEN2
+       select ARM_ERRATA_814220
+       select SYSC_R8A7794
 
-config ARCH_R7S9210
-       bool "RZ/A2 (R7S9210)"
-       select PM
-       select PM_GENERIC_DOMAINS
-       select RENESAS_OSTM
-       select RENESAS_RZA1_IRQC
+config ARCH_R8A7779
+       bool "ARM32 Platform support for R-Car H1"
+       select ARCH_RCAR_GEN1
+       select ARM_ERRATA_754322
+       select ARM_GLOBAL_TIMER
+       select HAVE_ARM_SCU if SMP
+       select HAVE_ARM_TWD if SMP
+       select SYSC_R8A7779
 
-config ARCH_R8A73A4
-       bool "R-Mobile APE6 (R8A73A40)"
-       select ARCH_RMOBILE
+config ARCH_R8A7790
+       bool "ARM32 Platform support for R-Car H2"
+       select ARCH_RCAR_GEN2
        select ARM_ERRATA_798181 if SMP
        select ARM_ERRATA_814220
-       select HAVE_ARM_ARCH_TIMER
-       select RENESAS_IRQC
+       select I2C
+       select SYSC_R8A7790
 
-config ARCH_R8A7740
-       bool "R-Mobile A1 (R8A77400)"
-       select ARCH_RMOBILE
+config ARCH_R8A7778
+       bool "ARM32 Platform support for R-Car M1A"
+       select ARCH_RCAR_GEN1
        select ARM_ERRATA_754322
-       select RENESAS_INTC_IRQPIN
 
-config ARCH_R8A7742
-       bool "RZ/G1H (R8A77420)"
+config ARCH_R8A7793
+       bool "ARM32 Platform support for R-Car M2-N"
        select ARCH_RCAR_GEN2
        select ARM_ERRATA_798181 if SMP
-       select ARM_ERRATA_814220
-       select SYSC_R8A7742
+       select I2C
+       select SYSC_R8A7791
 
-config ARCH_R8A7743
-       bool "RZ/G1M (R8A77430)"
+config ARCH_R8A7791
+       bool "ARM32 Platform support for R-Car M2-W"
        select ARCH_RCAR_GEN2
        select ARM_ERRATA_798181 if SMP
-       select SYSC_R8A7743
+       select I2C
+       select SYSC_R8A7791
 
-config ARCH_R8A7744
-       bool "RZ/G1N (R8A77440)"
+config ARCH_R8A7792
+       bool "ARM32 Platform support for R-Car V2H"
        select ARCH_RCAR_GEN2
        select ARM_ERRATA_798181 if SMP
-       select SYSC_R8A7743
+       select SYSC_R8A7792
 
-config ARCH_R8A7745
-       bool "RZ/G1E (R8A77450)"
-       select ARCH_RCAR_GEN2
-       select ARM_ERRATA_814220
-       select SYSC_R8A7745
+config ARCH_R8A7740
+       bool "ARM32 Platform support for R-Mobile A1"
+       select ARCH_RMOBILE
+       select ARM_ERRATA_754322
+       select RENESAS_INTC_IRQPIN
 
-config ARCH_R8A77470
-       bool "RZ/G1C (R8A77470)"
-       select ARCH_RCAR_GEN2
+config ARCH_R8A73A4
+       bool "ARM32 Platform support for R-Mobile APE6"
+       select ARCH_RMOBILE
+       select ARM_ERRATA_798181 if SMP
        select ARM_ERRATA_814220
-       select SYSC_R8A77470
+       select HAVE_ARM_ARCH_TIMER
+       select RENESAS_IRQC
 
-config ARCH_R8A7778
-       bool "R-Car M1A (R8A77781)"
-       select ARCH_RCAR_GEN1
+config ARCH_R7S72100
+       bool "ARM32 Platform support for RZ/A1H"
        select ARM_ERRATA_754322
+       select PM
+       select PM_GENERIC_DOMAINS
+       select RENESAS_OSTM
+       select RENESAS_RZA1_IRQC
+       select SYS_SUPPORTS_SH_MTU2
 
-config ARCH_R8A7779
-       bool "R-Car H1 (R8A77790)"
-       select ARCH_RCAR_GEN1
-       select ARM_ERRATA_754322
-       select ARM_GLOBAL_TIMER
-       select HAVE_ARM_SCU if SMP
-       select HAVE_ARM_TWD if SMP
-       select SYSC_R8A7779
+config ARCH_R7S9210
+       bool "ARM32 Platform support for RZ/A2"
+       select PM
+       select PM_GENERIC_DOMAINS
+       select RENESAS_OSTM
+       select RENESAS_RZA1_IRQC
 
-config ARCH_R8A7790
-       bool "R-Car H2 (R8A77900)"
+config ARCH_R8A77470
+       bool "ARM32 Platform support for RZ/G1C"
        select ARCH_RCAR_GEN2
-       select ARM_ERRATA_798181 if SMP
        select ARM_ERRATA_814220
-       select I2C
-       select SYSC_R8A7790
+       select SYSC_R8A77470
 
-config ARCH_R8A7791
-       bool "R-Car M2-W (R8A77910)"
+config ARCH_R8A7745
+       bool "ARM32 Platform support for RZ/G1E"
        select ARCH_RCAR_GEN2
-       select ARM_ERRATA_798181 if SMP
-       select I2C
-       select SYSC_R8A7791
+       select ARM_ERRATA_814220
+       select SYSC_R8A7745
 
-config ARCH_R8A7792
-       bool "R-Car V2H (R8A77920)"
+config ARCH_R8A7742
+       bool "ARM32 Platform support for RZ/G1H"
        select ARCH_RCAR_GEN2
        select ARM_ERRATA_798181 if SMP
-       select SYSC_R8A7792
+       select ARM_ERRATA_814220
+       select SYSC_R8A7742
 
-config ARCH_R8A7793
-       bool "R-Car M2-N (R8A7793)"
+config ARCH_R8A7743
+       bool "ARM32 Platform support for RZ/G1M"
        select ARCH_RCAR_GEN2
        select ARM_ERRATA_798181 if SMP
-       select I2C
-       select SYSC_R8A7791
+       select SYSC_R8A7743
 
-config ARCH_R8A7794
-       bool "R-Car E2 (R8A77940)"
+config ARCH_R8A7744
+       bool "ARM32 Platform support for RZ/G1N"
        select ARCH_RCAR_GEN2
-       select ARM_ERRATA_814220
-       select SYSC_R8A7794
+       select ARM_ERRATA_798181 if SMP
+       select SYSC_R8A7743
 
 config ARCH_R9A06G032
-       bool "RZ/N1D (R9A06G032)"
+       bool "ARM32 Platform support for RZ/N1D"
        select ARCH_RZN1
        select ARM_ERRATA_814220
 
 config ARCH_SH73A0
-       bool "SH-Mobile AG5 (R8A73A00)"
+       bool "ARM32 Platform support for SH-Mobile AG5"
        select ARCH_RMOBILE
        select ARM_ERRATA_754322
        select ARM_GLOBAL_TIMER
@@ -180,193 +180,201 @@ endif # ARM
 
 if ARM64
 
-config ARCH_R8A774A1
-       bool "Renesas RZ/G2M SoC Platform"
-       select ARCH_RCAR_GEN3
-       select SYSC_R8A774A1
-       help
-         This enables support for the Renesas RZ/G2M SoC.
-
-config ARCH_R8A774B1
-       bool "Renesas RZ/G2N SoC Platform"
-       select ARCH_RCAR_GEN3
-       select SYSC_R8A774B1
-       help
-         This enables support for the Renesas RZ/G2N SoC.
-
-config ARCH_R8A774C0
-       bool "Renesas RZ/G2E SoC Platform"
+config ARCH_R8A77995
+       bool "ARM64 Platform support for R-Car D3"
        select ARCH_RCAR_GEN3
-       select SYSC_R8A774C0
+       select SYSC_R8A77995
        help
-         This enables support for the Renesas RZ/G2E SoC.
+         This enables support for the Renesas R-Car D3 SoC.
 
-config ARCH_R8A774E1
-       bool "Renesas RZ/G2H SoC Platform"
+config ARCH_R8A77990
+       bool "ARM64 Platform support for R-Car E3"
        select ARCH_RCAR_GEN3
-       select SYSC_R8A774E1
+       select SYSC_R8A77990
        help
-         This enables support for the Renesas RZ/G2H SoC.
+         This enables support for the Renesas R-Car E3 SoC.
 
 config ARCH_R8A77950
-       bool "Renesas R-Car H3 ES1.x SoC Platform"
+       bool "ARM64 Platform support for R-Car H3 ES1.x"
        select ARCH_RCAR_GEN3
        select SYSC_R8A7795
        help
          This enables support for the Renesas R-Car H3 SoC (revision 1.x).
 
 config ARCH_R8A77951
-       bool "Renesas R-Car H3 ES2.0+ SoC Platform"
+       bool "ARM64 Platform support for R-Car H3 ES2.0+"
        select ARCH_RCAR_GEN3
        select SYSC_R8A7795
        help
          This enables support for the Renesas R-Car H3 SoC (revisions 2.0 and
          later).
 
+config ARCH_R8A77965
+       bool "ARM64 Platform support for R-Car M3-N"
+       select ARCH_RCAR_GEN3
+       select SYSC_R8A77965
+       help
+         This enables support for the Renesas R-Car M3-N SoC.
+
 config ARCH_R8A77960
-       bool "Renesas R-Car M3-W SoC Platform"
+       bool "ARM64 Platform support for R-Car M3-W"
        select ARCH_RCAR_GEN3
        select SYSC_R8A77960
        help
          This enables support for the Renesas R-Car M3-W SoC.
 
 config ARCH_R8A77961
-       bool "Renesas R-Car M3-W+ SoC Platform"
+       bool "ARM64 Platform support for R-Car M3-W+"
        select ARCH_RCAR_GEN3
        select SYSC_R8A77961
        help
          This enables support for the Renesas R-Car M3-W+ SoC.
 
-config ARCH_R8A77965
-       bool "Renesas R-Car M3-N SoC Platform"
+config ARCH_R8A77980
+       bool "ARM64 Platform support for R-Car V3H"
        select ARCH_RCAR_GEN3
-       select SYSC_R8A77965
+       select SYSC_R8A77980
        help
-         This enables support for the Renesas R-Car M3-N SoC.
+         This enables support for the Renesas R-Car V3H SoC.
 
 config ARCH_R8A77970
-       bool "Renesas R-Car V3M SoC Platform"
+       bool "ARM64 Platform support for R-Car V3M"
        select ARCH_RCAR_GEN3
        select SYSC_R8A77970
        help
          This enables support for the Renesas R-Car V3M SoC.
 
-config ARCH_R8A77980
-       bool "Renesas R-Car V3H SoC Platform"
+config ARCH_R8A779A0
+       bool "ARM64 Platform support for R-Car V3U"
        select ARCH_RCAR_GEN3
-       select SYSC_R8A77980
+       select SYSC_R8A779A0
        help
-         This enables support for the Renesas R-Car V3H SoC.
+         This enables support for the Renesas R-Car V3U SoC.
 
-config ARCH_R8A77990
-       bool "Renesas R-Car E3 SoC Platform"
+config ARCH_R8A774C0
+       bool "ARM64 Platform support for RZ/G2E"
        select ARCH_RCAR_GEN3
-       select SYSC_R8A77990
+       select SYSC_R8A774C0
        help
-         This enables support for the Renesas R-Car E3 SoC.
+         This enables support for the Renesas RZ/G2E SoC.
 
-config ARCH_R8A77995
-       bool "Renesas R-Car D3 SoC Platform"
+config ARCH_R8A774E1
+       bool "ARM64 Platform support for RZ/G2H"
        select ARCH_RCAR_GEN3
-       select SYSC_R8A77995
+       select SYSC_R8A774E1
        help
-         This enables support for the Renesas R-Car D3 SoC.
+         This enables support for the Renesas RZ/G2H SoC.
+
+config ARCH_R8A774A1
+       bool "ARM64 Platform support for RZ/G2M"
+       select ARCH_RCAR_GEN3
+       select SYSC_R8A774A1
+       help
+         This enables support for the Renesas RZ/G2M SoC.
+
+config ARCH_R8A774B1
+       bool "ARM64 Platform support for RZ/G2N"
+       select ARCH_RCAR_GEN3
+       select SYSC_R8A774B1
+       help
+         This enables support for the Renesas RZ/G2N SoC.
 
 endif # ARM64
 
-# SoC
-config SYSC_R8A7742
-       bool "RZ/G1H System Controller support" if COMPILE_TEST
-       select SYSC_RCAR
+config RST_RCAR
+       bool "Reset Controller support for R-Car" if COMPILE_TEST
 
-config SYSC_R8A7743
-       bool "RZ/G1M System Controller support" if COMPILE_TEST
+config SYSC_RCAR
+       bool "System Controller support for R-Car" if COMPILE_TEST
+
+config SYSC_R8A77995
+       bool "System Controller support for R-Car D3" if COMPILE_TEST
        select SYSC_RCAR
 
-config SYSC_R8A7745
-       bool "RZ/G1E System Controller support" if COMPILE_TEST
+config SYSC_R8A7794
+       bool "System Controller support for R-Car E2" if COMPILE_TEST
        select SYSC_RCAR
 
-config SYSC_R8A77470
-       bool "RZ/G1C System Controller support" if COMPILE_TEST
+config SYSC_R8A77990
+       bool "System Controller support for R-Car E3" if COMPILE_TEST
        select SYSC_RCAR
 
-config SYSC_R8A774A1
-       bool "RZ/G2M System Controller support" if COMPILE_TEST
+config SYSC_R8A7779
+       bool "System Controller support for R-Car H1" if COMPILE_TEST
        select SYSC_RCAR
 
-config SYSC_R8A774B1
-       bool "RZ/G2N System Controller support" if COMPILE_TEST
+config SYSC_R8A7790
+       bool "System Controller support for R-Car H2" if COMPILE_TEST
        select SYSC_RCAR
 
-config SYSC_R8A774C0
-       bool "RZ/G2E System Controller support" if COMPILE_TEST
+config SYSC_R8A7795
+       bool "System Controller support for R-Car H3" if COMPILE_TEST
        select SYSC_RCAR
 
-config SYSC_R8A774E1
-       bool "RZ/G2H System Controller support" if COMPILE_TEST
+config SYSC_R8A7791
+       bool "System Controller support for R-Car M2-W/N" if COMPILE_TEST
        select SYSC_RCAR
 
-config SYSC_R8A7779
-       bool "R-Car H1 System Controller support" if COMPILE_TEST
+config SYSC_R8A77965
+       bool "System Controller support for R-Car M3-N" if COMPILE_TEST
        select SYSC_RCAR
 
-config SYSC_R8A7790
-       bool "R-Car H2 System Controller support" if COMPILE_TEST
+config SYSC_R8A77960
+       bool "System Controller support for R-Car M3-W" if COMPILE_TEST
        select SYSC_RCAR
 
-config SYSC_R8A7791
-       bool "R-Car M2-W/N System Controller support" if COMPILE_TEST
+config SYSC_R8A77961
+       bool "System Controller support for R-Car M3-W+" if COMPILE_TEST
        select SYSC_RCAR
 
 config SYSC_R8A7792
-       bool "R-Car V2H System Controller support" if COMPILE_TEST
+       bool "System Controller support for R-Car V2H" if COMPILE_TEST
        select SYSC_RCAR
 
-config SYSC_R8A7794
-       bool "R-Car E2 System Controller support" if COMPILE_TEST
+config SYSC_R8A77980
+       bool "System Controller support for R-Car V3H" if COMPILE_TEST
        select SYSC_RCAR
 
-config SYSC_R8A7795
-       bool "R-Car H3 System Controller support" if COMPILE_TEST
+config SYSC_R8A77970
+       bool "System Controller support for R-Car V3M" if COMPILE_TEST
        select SYSC_RCAR
 
-config SYSC_R8A77960
-       bool "R-Car M3-W System Controller support" if COMPILE_TEST
-       select SYSC_RCAR
+config SYSC_R8A779A0
+       bool "System Controller support for R-Car V3U" if COMPILE_TEST
 
-config SYSC_R8A77961
-       bool "R-Car M3-W+ System Controller support" if COMPILE_TEST
-       select SYSC_RCAR
+config SYSC_RMOBILE
+       bool "System Controller support for R-Mobile" if COMPILE_TEST
 
-config SYSC_R8A77965
-       bool "R-Car M3-N System Controller support" if COMPILE_TEST
+config SYSC_R8A77470
+       bool "System Controller support for RZ/G1C" if COMPILE_TEST
        select SYSC_RCAR
 
-config SYSC_R8A77970
-       bool "R-Car V3M System Controller support" if COMPILE_TEST
+config SYSC_R8A7745
+       bool "System Controller support for RZ/G1E" if COMPILE_TEST
        select SYSC_RCAR
 
-config SYSC_R8A77980
-       bool "R-Car V3H System Controller support" if COMPILE_TEST
+config SYSC_R8A7742
+       bool "System Controller support for RZ/G1H" if COMPILE_TEST
        select SYSC_RCAR
 
-config SYSC_R8A77990
-       bool "R-Car E3 System Controller support" if COMPILE_TEST
+config SYSC_R8A7743
+       bool "System Controller support for RZ/G1M" if COMPILE_TEST
        select SYSC_RCAR
 
-config SYSC_R8A77995
-       bool "R-Car D3 System Controller support" if COMPILE_TEST
+config SYSC_R8A774C0
+       bool "System Controller support for RZ/G2E" if COMPILE_TEST
        select SYSC_RCAR
 
-# Family
-config RST_RCAR
-       bool "R-Car Reset Controller support" if COMPILE_TEST
+config SYSC_R8A774E1
+       bool "System Controller support for RZ/G2H" if COMPILE_TEST
+       select SYSC_RCAR
 
-config SYSC_RCAR
-       bool "R-Car System Controller support" if COMPILE_TEST
+config SYSC_R8A774A1
+       bool "System Controller support for RZ/G2M" if COMPILE_TEST
+       select SYSC_RCAR
 
-config SYSC_RMOBILE
-       bool "R-Mobile System Controller support" if COMPILE_TEST
+config SYSC_R8A774B1
+       bool "System Controller support for RZ/G2N" if COMPILE_TEST
+       select SYSC_RCAR
 
 endif # SOC_RENESAS
index 10a399f..9b29bed 100644 (file)
@@ -24,6 +24,7 @@ obj-$(CONFIG_SYSC_R8A77970)   += r8a77970-sysc.o
 obj-$(CONFIG_SYSC_R8A77980)    += r8a77980-sysc.o
 obj-$(CONFIG_SYSC_R8A77990)    += r8a77990-sysc.o
 obj-$(CONFIG_SYSC_R8A77995)    += r8a77995-sysc.o
+obj-$(CONFIG_SYSC_R8A779A0)    += r8a779a0-sysc.o
 ifdef CONFIG_SMP
 obj-$(CONFIG_ARCH_R9A06G032)   += r9a06g032-smp.o
 endif
diff --git a/drivers/soc/renesas/r8a779a0-sysc.c b/drivers/soc/renesas/r8a779a0-sysc.c
new file mode 100644 (file)
index 0000000..d464ffa
--- /dev/null
@@ -0,0 +1,448 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Renesas R-Car V3U System Controller
+ *
+ * Copyright (C) 2020 Renesas Electronics Corp.
+ */
+
+#include <linux/bits.h>
+#include <linux/clk/renesas.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/of_address.h>
+#include <linux/pm_domain.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#include <dt-bindings/power/r8a779a0-sysc.h>
+
+/*
+ * Power Domain flags
+ */
+#define PD_CPU         BIT(0)  /* Area contains main CPU core */
+#define PD_SCU         BIT(1)  /* Area contains SCU and L2 cache */
+#define PD_NO_CR       BIT(2)  /* Area lacks PWR{ON,OFF}CR registers */
+
+#define PD_CPU_NOCR    PD_CPU | PD_NO_CR /* CPU area lacks CR */
+#define PD_ALWAYS_ON   PD_NO_CR          /* Always-on area */
+
+/*
+ * Description of a Power Area
+ */
+struct r8a779a0_sysc_area {
+       const char *name;
+       u8 pdr;                 /* PDRn */
+       int parent;             /* -1 if none */
+       unsigned int flags;     /* See PD_* */
+};
+
+/*
+ * SoC-specific Power Area Description
+ */
+struct r8a779a0_sysc_info {
+       const struct r8a779a0_sysc_area *areas;
+       unsigned int num_areas;
+};
+
+static struct r8a779a0_sysc_area r8a779a0_areas[] __initdata = {
+       { "always-on",  R8A779A0_PD_ALWAYS_ON, -1, PD_ALWAYS_ON },
+       { "a3e0",       R8A779A0_PD_A3E0, R8A779A0_PD_ALWAYS_ON, PD_SCU },
+       { "a3e1",       R8A779A0_PD_A3E1, R8A779A0_PD_ALWAYS_ON, PD_SCU },
+       { "a2e0d0",     R8A779A0_PD_A2E0D0, R8A779A0_PD_A3E0, PD_SCU },
+       { "a2e0d1",     R8A779A0_PD_A2E0D1, R8A779A0_PD_A3E0, PD_SCU },
+       { "a2e1d0",     R8A779A0_PD_A2E1D0, R8A779A0_PD_A3E1, PD_SCU },
+       { "a2e1d1",     R8A779A0_PD_A2E1D1, R8A779A0_PD_A3E1, PD_SCU },
+       { "a1e0d0c0",   R8A779A0_PD_A1E0D0C0, R8A779A0_PD_A2E0D0, PD_CPU_NOCR },
+       { "a1e0d0c1",   R8A779A0_PD_A1E0D0C1, R8A779A0_PD_A2E0D0, PD_CPU_NOCR },
+       { "a1e0d1c0",   R8A779A0_PD_A1E0D1C0, R8A779A0_PD_A2E0D1, PD_CPU_NOCR },
+       { "a1e0d1c1",   R8A779A0_PD_A1E0D1C1, R8A779A0_PD_A2E0D1, PD_CPU_NOCR },
+       { "a1e1d0c0",   R8A779A0_PD_A1E1D0C0, R8A779A0_PD_A2E1D0, PD_CPU_NOCR },
+       { "a1e1d0c1",   R8A779A0_PD_A1E1D0C1, R8A779A0_PD_A2E1D0, PD_CPU_NOCR },
+       { "a1e1d1c0",   R8A779A0_PD_A1E1D1C0, R8A779A0_PD_A2E1D1, PD_CPU_NOCR },
+       { "a1e1d1c1",   R8A779A0_PD_A1E1D1C1, R8A779A0_PD_A2E1D1, PD_CPU_NOCR },
+       { "3dg-a",      R8A779A0_PD_3DG_A, R8A779A0_PD_ALWAYS_ON },
+       { "3dg-b",      R8A779A0_PD_3DG_B, R8A779A0_PD_3DG_A },
+       { "a3vip0",     R8A779A0_PD_A3VIP0, R8A779A0_PD_ALWAYS_ON },
+       { "a3vip1",     R8A779A0_PD_A3VIP1, R8A779A0_PD_ALWAYS_ON },
+       { "a3vip3",     R8A779A0_PD_A3VIP3, R8A779A0_PD_ALWAYS_ON },
+       { "a3vip2",     R8A779A0_PD_A3VIP2, R8A779A0_PD_ALWAYS_ON },
+       { "a3isp01",    R8A779A0_PD_A3ISP01, R8A779A0_PD_ALWAYS_ON },
+       { "a3isp23",    R8A779A0_PD_A3ISP23, R8A779A0_PD_ALWAYS_ON },
+       { "a3ir",       R8A779A0_PD_A3IR, R8A779A0_PD_ALWAYS_ON },
+       { "a2cn0",      R8A779A0_PD_A2CN0, R8A779A0_PD_A3IR },
+       { "a2imp01",    R8A779A0_PD_A2IMP01, R8A779A0_PD_A3IR },
+       { "a2dp0",      R8A779A0_PD_A2DP0, R8A779A0_PD_A3IR },
+       { "a2cv0",      R8A779A0_PD_A2CV0, R8A779A0_PD_A3IR },
+       { "a2cv1",      R8A779A0_PD_A2CV1, R8A779A0_PD_A3IR },
+       { "a2cv4",      R8A779A0_PD_A2CV4, R8A779A0_PD_A3IR },
+       { "a2cv6",      R8A779A0_PD_A2CV6, R8A779A0_PD_A3IR },
+       { "a2cn2",      R8A779A0_PD_A2CN2, R8A779A0_PD_A3IR },
+       { "a2imp23",    R8A779A0_PD_A2IMP23, R8A779A0_PD_A3IR },
+       { "a2dp1",      R8A779A0_PD_A2DP0, R8A779A0_PD_A3IR },
+       { "a2cv2",      R8A779A0_PD_A2CV0, R8A779A0_PD_A3IR },
+       { "a2cv3",      R8A779A0_PD_A2CV1, R8A779A0_PD_A3IR },
+       { "a2cv5",      R8A779A0_PD_A2CV4, R8A779A0_PD_A3IR },
+       { "a2cv7",      R8A779A0_PD_A2CV6, R8A779A0_PD_A3IR },
+       { "a2cn1",      R8A779A0_PD_A2CN1, R8A779A0_PD_A3IR },
+       { "a1cnn0",     R8A779A0_PD_A1CNN0, R8A779A0_PD_A2CN0 },
+       { "a1cnn2",     R8A779A0_PD_A1CNN2, R8A779A0_PD_A2CN2 },
+       { "a1dsp0",     R8A779A0_PD_A1DSP0, R8A779A0_PD_A2CN2 },
+       { "a1cnn1",     R8A779A0_PD_A1CNN1, R8A779A0_PD_A2CN1 },
+       { "a1dsp1",     R8A779A0_PD_A1DSP1, R8A779A0_PD_A2CN1 },
+};
+
+static const struct r8a779a0_sysc_info r8a779a0_sysc_info __initconst = {
+       .areas = r8a779a0_areas,
+       .num_areas = ARRAY_SIZE(r8a779a0_areas),
+};
+
+/* SYSC Common */
+#define SYSCSR         0x000   /* SYSC Status Register */
+#define SYSCPONSR(x)   (0x800 + ((x) * 0x4)) /* Power-ON Status Register 0 */
+#define SYSCPOFFSR(x)  (0x808 + ((x) * 0x4)) /* Power-OFF Status Register */
+#define SYSCISCR(x)    (0x810 + ((x) * 0x4)) /* Interrupt Status/Clear Register */
+#define SYSCIER(x)     (0x820 + ((x) * 0x4)) /* Interrupt Enable Register */
+#define SYSCIMR(x)     (0x830 + ((x) * 0x4)) /* Interrupt Mask Register */
+
+/* Power Domain Registers */
+#define PDRSR(n)       (0x1000 + ((n) * 0x40))
+#define PDRONCR(n)     (0x1004 + ((n) * 0x40))
+#define PDROFFCR(n)    (0x1008 + ((n) * 0x40))
+#define PDRESR(n)      (0x100C + ((n) * 0x40))
+
+/* PWRON/PWROFF */
+#define PWRON_PWROFF           BIT(0)  /* Power-ON/OFF request */
+
+/* PDRESR */
+#define PDRESR_ERR             BIT(0)
+
+/* PDRSR */
+#define PDRSR_OFF              BIT(0)  /* Power-OFF state */
+#define PDRSR_ON               BIT(4)  /* Power-ON state */
+#define PDRSR_OFF_STATE                BIT(8)  /* Processing Power-OFF sequence */
+#define PDRSR_ON_STATE         BIT(12) /* Processing Power-ON sequence */
+
+#define SYSCSR_BUSY            GENMASK(1, 0)   /* All bit sets is not busy */
+
+#define SYSCSR_TIMEOUT         10000
+#define SYSCSR_DELAY_US                10
+
+#define PDRESR_RETRIES         1000
+#define PDRESR_DELAY_US                10
+
+#define SYSCISR_TIMEOUT                10000
+#define SYSCISR_DELAY_US       10
+
+#define NUM_DOMAINS_EACH_REG   BITS_PER_TYPE(u32)
+
+static void __iomem *r8a779a0_sysc_base;
+static DEFINE_SPINLOCK(r8a779a0_sysc_lock); /* SMP CPUs + I/O devices */
+
+static int r8a779a0_sysc_pwr_on_off(u8 pdr, bool on)
+{
+       unsigned int reg_offs;
+       u32 val;
+       int ret;
+
+       if (on)
+               reg_offs = PDRONCR(pdr);
+       else
+               reg_offs = PDROFFCR(pdr);
+
+       /* Wait until SYSC is ready to accept a power request */
+       ret = readl_poll_timeout_atomic(r8a779a0_sysc_base + SYSCSR, val,
+                                       (val & SYSCSR_BUSY) == SYSCSR_BUSY,
+                                       SYSCSR_DELAY_US, SYSCSR_TIMEOUT);
+       if (ret < 0)
+               return -EAGAIN;
+
+       /* Submit power shutoff or power resume request */
+       iowrite32(PWRON_PWROFF, r8a779a0_sysc_base + reg_offs);
+
+       return 0;
+}
+
+static int clear_irq_flags(unsigned int reg_idx, unsigned int isr_mask)
+{
+       u32 val;
+       int ret;
+
+       iowrite32(isr_mask, r8a779a0_sysc_base + SYSCISCR(reg_idx));
+
+       ret = readl_poll_timeout_atomic(r8a779a0_sysc_base + SYSCISCR(reg_idx),
+                                       val, !(val & isr_mask),
+                                       SYSCISR_DELAY_US, SYSCISR_TIMEOUT);
+       if (ret < 0) {
+               pr_err("\n %s : Can not clear IRQ flags in SYSCISCR", __func__);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int r8a779a0_sysc_power(u8 pdr, bool on)
+{
+       unsigned int isr_mask;
+       unsigned int reg_idx, bit_idx;
+       unsigned int status;
+       unsigned long flags;
+       int ret = 0;
+       u32 val;
+       int k;
+
+       spin_lock_irqsave(&r8a779a0_sysc_lock, flags);
+
+       reg_idx = pdr / NUM_DOMAINS_EACH_REG;
+       bit_idx = pdr % NUM_DOMAINS_EACH_REG;
+
+       isr_mask = BIT(bit_idx);
+
+       /*
+        * The interrupt source needs to be enabled, but masked, to prevent the
+        * CPU from receiving it.
+        */
+       iowrite32(ioread32(r8a779a0_sysc_base + SYSCIER(reg_idx)) | isr_mask,
+                 r8a779a0_sysc_base + SYSCIER(reg_idx));
+       iowrite32(ioread32(r8a779a0_sysc_base + SYSCIMR(reg_idx)) | isr_mask,
+                 r8a779a0_sysc_base + SYSCIMR(reg_idx));
+
+       ret = clear_irq_flags(reg_idx, isr_mask);
+       if (ret)
+               goto out;
+
+       /* Submit power shutoff or resume request until it was accepted */
+       for (k = 0; k < PDRESR_RETRIES; k++) {
+               ret = r8a779a0_sysc_pwr_on_off(pdr, on);
+               if (ret)
+                       goto out;
+
+               status = ioread32(r8a779a0_sysc_base + PDRESR(pdr));
+               if (!(status & PDRESR_ERR))
+                       break;
+
+               udelay(PDRESR_DELAY_US);
+       }
+
+       if (k == PDRESR_RETRIES) {
+               ret = -EIO;
+               goto out;
+       }
+
+       /* Wait until the power shutoff or resume request has completed * */
+       ret = readl_poll_timeout_atomic(r8a779a0_sysc_base + SYSCISCR(reg_idx),
+                                       val, (val & isr_mask),
+                                       SYSCISR_DELAY_US, SYSCISR_TIMEOUT);
+       if (ret < 0) {
+               ret = -EIO;
+               goto out;
+       }
+
+       /* Clear interrupt flags */
+       ret = clear_irq_flags(reg_idx, isr_mask);
+       if (ret)
+               goto out;
+
+ out:
+       spin_unlock_irqrestore(&r8a779a0_sysc_lock, flags);
+
+       pr_debug("sysc power %s domain %d: %08x -> %d\n", on ? "on" : "off",
+                pdr, ioread32(r8a779a0_sysc_base + SYSCISCR(reg_idx)), ret);
+       return ret;
+}
+
+static bool r8a779a0_sysc_power_is_off(u8 pdr)
+{
+       unsigned int st;
+
+       st = ioread32(r8a779a0_sysc_base + PDRSR(pdr));
+
+       if (st & PDRSR_OFF)
+               return true;
+
+       return false;
+}
+
+struct r8a779a0_sysc_pd {
+       struct generic_pm_domain genpd;
+       u8 pdr;
+       unsigned int flags;
+       char name[];
+};
+
+static inline struct r8a779a0_sysc_pd *to_r8a779a0_pd(struct generic_pm_domain *d)
+{
+       return container_of(d, struct r8a779a0_sysc_pd, genpd);
+}
+
+static int r8a779a0_sysc_pd_power_off(struct generic_pm_domain *genpd)
+{
+       struct r8a779a0_sysc_pd *pd = to_r8a779a0_pd(genpd);
+
+       pr_debug("%s: %s\n", __func__, genpd->name);
+       return r8a779a0_sysc_power(pd->pdr, false);
+}
+
+static int r8a779a0_sysc_pd_power_on(struct generic_pm_domain *genpd)
+{
+       struct r8a779a0_sysc_pd *pd = to_r8a779a0_pd(genpd);
+
+       pr_debug("%s: %s\n", __func__, genpd->name);
+       return r8a779a0_sysc_power(pd->pdr, true);
+}
+
+static int __init r8a779a0_sysc_pd_setup(struct r8a779a0_sysc_pd *pd)
+{
+       struct generic_pm_domain *genpd = &pd->genpd;
+       const char *name = pd->genpd.name;
+       int error;
+
+       if (pd->flags & PD_CPU) {
+               /*
+                * This domain contains a CPU core and therefore it should
+                * only be turned off if the CPU is not in use.
+                */
+               pr_debug("PM domain %s contains %s\n", name, "CPU");
+               genpd->flags |= GENPD_FLAG_ALWAYS_ON;
+       } else if (pd->flags & PD_SCU) {
+               /*
+                * This domain contains an SCU and cache-controller, and
+                * therefore it should only be turned off if the CPU cores are
+                * not in use.
+                */
+               pr_debug("PM domain %s contains %s\n", name, "SCU");
+               genpd->flags |= GENPD_FLAG_ALWAYS_ON;
+       } else if (pd->flags & PD_NO_CR) {
+               /*
+                * This domain cannot be turned off.
+                */
+               genpd->flags |= GENPD_FLAG_ALWAYS_ON;
+       }
+
+       if (!(pd->flags & (PD_CPU | PD_SCU))) {
+               /* Enable Clock Domain for I/O devices */
+               genpd->flags |= GENPD_FLAG_PM_CLK | GENPD_FLAG_ACTIVE_WAKEUP;
+               genpd->attach_dev = cpg_mssr_attach_dev;
+               genpd->detach_dev = cpg_mssr_detach_dev;
+       }
+
+       genpd->power_off = r8a779a0_sysc_pd_power_off;
+       genpd->power_on = r8a779a0_sysc_pd_power_on;
+
+       if (pd->flags & (PD_CPU | PD_NO_CR)) {
+               /* Skip CPUs (handled by SMP code) and areas without control */
+               pr_debug("%s: Not touching %s\n", __func__, genpd->name);
+               goto finalize;
+       }
+
+       if (!r8a779a0_sysc_power_is_off(pd->pdr)) {
+               pr_debug("%s: %s is already powered\n", __func__, genpd->name);
+               goto finalize;
+       }
+
+       r8a779a0_sysc_power(pd->pdr, true);
+
+finalize:
+       error = pm_genpd_init(genpd, &simple_qos_governor, false);
+       if (error)
+               pr_err("Failed to init PM domain %s: %d\n", name, error);
+
+       return error;
+}
+
+static const struct of_device_id r8a779a0_sysc_matches[] __initconst = {
+       { .compatible = "renesas,r8a779a0-sysc", .data = &r8a779a0_sysc_info },
+       { /* sentinel */ }
+};
+
+struct r8a779a0_pm_domains {
+       struct genpd_onecell_data onecell_data;
+       struct generic_pm_domain *domains[R8A779A0_PD_ALWAYS_ON + 1];
+};
+
+static struct genpd_onecell_data *r8a779a0_sysc_onecell_data;
+
+static int __init r8a779a0_sysc_pd_init(void)
+{
+       const struct r8a779a0_sysc_info *info;
+       const struct of_device_id *match;
+       struct r8a779a0_pm_domains *domains;
+       struct device_node *np;
+       void __iomem *base;
+       unsigned int i;
+       int error;
+
+       np = of_find_matching_node_and_match(NULL, r8a779a0_sysc_matches, &match);
+       if (!np)
+               return -ENODEV;
+
+       info = match->data;
+
+       base = of_iomap(np, 0);
+       if (!base) {
+               pr_warn("%pOF: Cannot map regs\n", np);
+               error = -ENOMEM;
+               goto out_put;
+       }
+
+       r8a779a0_sysc_base = base;
+
+       domains = kzalloc(sizeof(*domains), GFP_KERNEL);
+       if (!domains) {
+               error = -ENOMEM;
+               goto out_put;
+       }
+
+       domains->onecell_data.domains = domains->domains;
+       domains->onecell_data.num_domains = ARRAY_SIZE(domains->domains);
+       r8a779a0_sysc_onecell_data = &domains->onecell_data;
+
+       for (i = 0; i < info->num_areas; i++) {
+               const struct r8a779a0_sysc_area *area = &info->areas[i];
+               struct r8a779a0_sysc_pd *pd;
+
+               if (!area->name) {
+                       /* Skip NULLified area */
+                       continue;
+               }
+
+               pd = kzalloc(sizeof(*pd) + strlen(area->name) + 1, GFP_KERNEL);
+               if (!pd) {
+                       error = -ENOMEM;
+                       goto out_put;
+               }
+
+               strcpy(pd->name, area->name);
+               pd->genpd.name = pd->name;
+               pd->pdr = area->pdr;
+               pd->flags = area->flags;
+
+               error = r8a779a0_sysc_pd_setup(pd);
+               if (error)
+                       goto out_put;
+
+               domains->domains[area->pdr] = &pd->genpd;
+
+               if (area->parent < 0)
+                       continue;
+
+               error = pm_genpd_add_subdomain(domains->domains[area->parent],
+                                              &pd->genpd);
+               if (error) {
+                       pr_warn("Failed to add PM subdomain %s to parent %u\n",
+                               area->name, area->parent);
+                       goto out_put;
+               }
+       }
+
+       error = of_genpd_add_provider_onecell(np, &domains->onecell_data);
+
+out_put:
+       of_node_put(np);
+       return error;
+}
+early_initcall(r8a779a0_sysc_pd_init);
index a932015..8a1e402 100644 (file)
@@ -37,6 +37,10 @@ static const struct rst_config rcar_rst_gen3 __initconst = {
        .modemr = 0x60,
 };
 
+static const struct rst_config rcar_rst_r8a779a0 __initconst = {
+       .modemr = 0x00,         /* MODEMR0 and it has CPG related bits */
+};
+
 static const struct of_device_id rcar_rst_matches[] __initconst = {
        /* RZ/G1 is handled like R-Car Gen2 */
        { .compatible = "renesas,r8a7742-rst", .data = &rcar_rst_gen2 },
@@ -67,6 +71,8 @@ static const struct of_device_id rcar_rst_matches[] __initconst = {
        { .compatible = "renesas,r8a77980-rst", .data = &rcar_rst_gen3 },
        { .compatible = "renesas,r8a77990-rst", .data = &rcar_rst_gen3 },
        { .compatible = "renesas,r8a77995-rst", .data = &rcar_rst_gen3 },
+       /* R-Car V3U */
+       { .compatible = "renesas,r8a779a0-rst", .data = &rcar_rst_r8a779a0 },
        { /* sentinel */ }
 };
 
index f815a6a..0f8eff4 100644 (file)
@@ -200,6 +200,11 @@ static const struct renesas_soc soc_rcar_d3 __initconst __maybe_unused = {
        .id     = 0x58,
 };
 
+static const struct renesas_soc soc_rcar_v3u __initconst __maybe_unused = {
+       .family = &fam_rcar_gen3,
+       .id     = 0x59,
+};
+
 static const struct renesas_soc soc_shmobile_ag5 __initconst __maybe_unused = {
        .family = &fam_shmobile,
        .id     = 0x37,
@@ -291,6 +296,9 @@ static const struct of_device_id renesas_socs[] __initconst = {
 #ifdef CONFIG_ARCH_R8A77995
        { .compatible = "renesas,r8a77995",     .data = &soc_rcar_d3 },
 #endif
+#ifdef CONFIG_ARCH_R8A779A0
+       { .compatible = "renesas,r8a779a0",     .data = &soc_rcar_v3u },
+#endif
 #ifdef CONFIG_ARCH_SH73A0
        { .compatible = "renesas,sh73a0",       .data = &soc_shmobile_ag5 },
 #endif
index 1b0d50f..d4c7bd5 100644 (file)
@@ -194,7 +194,7 @@ static const struct sunxi_sram_data *sunxi_sram_of_parse(struct device_node *nod
        if (!data) {
                ret = -EINVAL;
                goto err;
-       };
+       }
 
        for (func = data->func; func->func; func++) {
                if (val == func->val) {
index d1f8dd0..94b60a6 100644 (file)
@@ -49,6 +49,9 @@ static struct tegra_fuse *fuse = &(struct tegra_fuse) {
 };
 
 static const struct of_device_id tegra_fuse_match[] = {
+#ifdef CONFIG_ARCH_TEGRA_234_SOC
+       { .compatible = "nvidia,tegra234-efuse", .data = &tegra234_fuse_soc },
+#endif
 #ifdef CONFIG_ARCH_TEGRA_194_SOC
        { .compatible = "nvidia,tegra194-efuse", .data = &tegra194_fuse_soc },
 #endif
@@ -326,7 +329,8 @@ const struct attribute_group tegra_soc_attr_group = {
        .attrs = tegra_soc_attr,
 };
 
-#ifdef CONFIG_ARCH_TEGRA_194_SOC
+#if IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) || \
+    IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC)
 static ssize_t platform_show(struct device *dev, struct device_attribute *attr,
                             char *buf)
 {
@@ -336,7 +340,7 @@ static ssize_t platform_show(struct device *dev, struct device_attribute *attr,
         * platform type is silicon and all other non-zero values indicate
         * the type of simulation platform is being used.
         */
-       return sprintf(buf, "%d\n", (tegra_read_chipid() >> 20) & 0xf);
+       return sprintf(buf, "%d\n", tegra_get_platform());
 }
 
 static DEVICE_ATTR_RO(platform);
index 85accef..9ea7f01 100644 (file)
@@ -356,3 +356,33 @@ const struct tegra_fuse_soc tegra194_fuse_soc = {
        .soc_attr_group = &tegra194_soc_attr_group,
 };
 #endif
+
+#if defined(CONFIG_ARCH_TEGRA_234_SOC)
+static const struct nvmem_cell_lookup tegra234_fuse_lookups[] = {
+       {
+               .nvmem_name = "fuse",
+               .cell_name = "xusb-pad-calibration",
+               .dev_id = "3520000.padctl",
+               .con_id = "calibration",
+       }, {
+               .nvmem_name = "fuse",
+               .cell_name = "xusb-pad-calibration-ext",
+               .dev_id = "3520000.padctl",
+               .con_id = "calibration-ext",
+       },
+};
+
+static const struct tegra_fuse_info tegra234_fuse_info = {
+       .read = tegra30_fuse_read,
+       .size = 0x300,
+       .spare = 0x280,
+};
+
+const struct tegra_fuse_soc tegra234_fuse_soc = {
+       .init = tegra30_fuse_init,
+       .info = &tegra234_fuse_info,
+       .lookups = tegra234_fuse_lookups,
+       .num_lookups = ARRAY_SIZE(tegra234_fuse_lookups),
+       .soc_attr_group = &tegra194_soc_attr_group,
+};
+#endif
index 9d4fc31..e057a58 100644 (file)
@@ -115,9 +115,17 @@ extern const struct tegra_fuse_soc tegra210_fuse_soc;
 extern const struct tegra_fuse_soc tegra186_fuse_soc;
 #endif
 
+#if IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) || \
+    IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC)
+extern const struct attribute_group tegra194_soc_attr_group;
+#endif
+
 #ifdef CONFIG_ARCH_TEGRA_194_SOC
 extern const struct tegra_fuse_soc tegra194_fuse_soc;
-extern const struct attribute_group tegra194_soc_attr_group;
+#endif
+
+#ifdef CONFIG_ARCH_TEGRA_234_SOC
+extern const struct tegra_fuse_soc tegra234_fuse_soc;
 #endif
 
 #endif
index 8e416ad..cee207d 100644 (file)
@@ -47,6 +47,31 @@ u8 tegra_get_minor_rev(void)
        return (tegra_read_chipid() >> 16) & 0xf;
 }
 
+u8 tegra_get_platform(void)
+{
+       return (tegra_read_chipid() >> 20) & 0xf;
+}
+
+bool tegra_is_silicon(void)
+{
+       switch (tegra_get_chip_id()) {
+       case TEGRA194:
+       case TEGRA234:
+               if (tegra_get_platform() == 0)
+                       return true;
+
+               return false;
+       }
+
+       /*
+        * Chips prior to Tegra194 have a different way of determining whether
+        * they are silicon or not. Since we never supported simulation on the
+        * older Tegra chips, don't bother extracting the information and just
+        * report that we're running on silicon.
+        */
+       return true;
+}
+
 u32 tegra_read_straps(void)
 {
        WARN(!chipid, "Tegra ABP MISC not yet available\n");
@@ -70,6 +95,7 @@ static const struct of_device_id apbmisc_match[] __initconst = {
        { .compatible = "nvidia,tegra20-apbmisc", },
        { .compatible = "nvidia,tegra186-misc", },
        { .compatible = "nvidia,tegra194-misc", },
+       { .compatible = "nvidia,tegra234-misc", },
        {},
 };
 
index b0bba8a..df9a5ca 100644 (file)
@@ -336,45 +336,6 @@ struct tegra_pmc_soc {
        bool has_blink_output;
 };
 
-static const char * const tegra186_reset_sources[] = {
-       "SYS_RESET",
-       "AOWDT",
-       "MCCPLEXWDT",
-       "BPMPWDT",
-       "SCEWDT",
-       "SPEWDT",
-       "APEWDT",
-       "BCCPLEXWDT",
-       "SENSOR",
-       "AOTAG",
-       "VFSENSOR",
-       "SWREST",
-       "SC7",
-       "HSM",
-       "CORESIGHT"
-};
-
-static const char * const tegra186_reset_levels[] = {
-       "L0", "L1", "L2", "WARM"
-};
-
-static const char * const tegra30_reset_sources[] = {
-       "POWER_ON_RESET",
-       "WATCHDOG",
-       "SENSOR",
-       "SW_MAIN",
-       "LP0"
-};
-
-static const char * const tegra210_reset_sources[] = {
-       "POWER_ON_RESET",
-       "WATCHDOG",
-       "SENSOR",
-       "SW_MAIN",
-       "LP0",
-       "AOTAG"
-};
-
 /**
  * struct tegra_pmc - NVIDIA Tegra PMC
  * @dev: pointer to PMC device structure
@@ -2771,6 +2732,14 @@ static const u8 tegra30_cpu_powergates[] = {
        TEGRA_POWERGATE_CPU3,
 };
 
+static const char * const tegra30_reset_sources[] = {
+       "POWER_ON_RESET",
+       "WATCHDOG",
+       "SENSOR",
+       "SW_MAIN",
+       "LP0"
+};
+
 static const struct tegra_pmc_soc tegra30_pmc_soc = {
        .num_powergates = ARRAY_SIZE(tegra30_powergates),
        .powergates = tegra30_powergates,
@@ -3048,6 +3017,15 @@ static const struct pinctrl_pin_desc tegra210_pin_descs[] = {
        TEGRA210_IO_PAD_TABLE(TEGRA_IO_PIN_DESC)
 };
 
+static const char * const tegra210_reset_sources[] = {
+       "POWER_ON_RESET",
+       "WATCHDOG",
+       "SENSOR",
+       "SW_MAIN",
+       "LP0",
+       "AOTAG"
+};
+
 static const struct tegra_wake_event tegra210_wake_events[] = {
        TEGRA_WAKE_IRQ("rtc", 16, 2),
        TEGRA_WAKE_IRQ("pmu", 51, 86),
@@ -3180,6 +3158,28 @@ static void tegra186_pmc_setup_irq_polarity(struct tegra_pmc *pmc,
        iounmap(wake);
 }
 
+static const char * const tegra186_reset_sources[] = {
+       "SYS_RESET",
+       "AOWDT",
+       "MCCPLEXWDT",
+       "BPMPWDT",
+       "SCEWDT",
+       "SPEWDT",
+       "APEWDT",
+       "BCCPLEXWDT",
+       "SENSOR",
+       "AOTAG",
+       "VFSENSOR",
+       "SWREST",
+       "SC7",
+       "HSM",
+       "CORESIGHT"
+};
+
+static const char * const tegra186_reset_levels[] = {
+       "L0", "L1", "L2", "WARM"
+};
+
 static const struct tegra_wake_event tegra186_wake_events[] = {
        TEGRA_WAKE_IRQ("pmu", 24, 209),
        TEGRA_WAKE_GPIO("power", 29, 1, TEGRA186_AON_GPIO(FF, 0)),
@@ -3349,7 +3349,75 @@ static const struct tegra_pmc_soc tegra194_pmc_soc = {
        .has_blink_output = false,
 };
 
+static const struct tegra_pmc_regs tegra234_pmc_regs = {
+       .scratch0 = 0x2000,
+       .dpd_req = 0,
+       .dpd_status = 0,
+       .dpd2_req = 0,
+       .dpd2_status = 0,
+       .rst_status = 0x70,
+       .rst_source_shift = 0x2,
+       .rst_source_mask = 0xfc,
+       .rst_level_shift = 0x0,
+       .rst_level_mask = 0x3,
+};
+
+static const char * const tegra234_reset_sources[] = {
+       "SYS_RESET_N",
+       "AOWDT",
+       "BCCPLEXWDT",
+       "BPMPWDT",
+       "SCEWDT",
+       "SPEWDT",
+       "APEWDT",
+       "LCCPLEXWDT",
+       "SENSOR",
+       "AOTAG",
+       "VFSENSOR",
+       "MAINSWRST",
+       "SC7",
+       "HSM",
+       "CSITE",
+       "RCEWDT",
+       "PVA0WDT",
+       "PVA1WDT",
+       "L1A_ASYNC",
+       "BPMPBOOT",
+       "FUSECRC",
+};
+
+static const struct tegra_pmc_soc tegra234_pmc_soc = {
+       .num_powergates = 0,
+       .powergates = NULL,
+       .num_cpu_powergates = 0,
+       .cpu_powergates = NULL,
+       .has_tsense_reset = false,
+       .has_gpu_clamps = false,
+       .needs_mbist_war = false,
+       .has_impl_33v_pwr = true,
+       .maybe_tz_only = false,
+       .num_io_pads = 0,
+       .io_pads = NULL,
+       .num_pin_descs = 0,
+       .pin_descs = NULL,
+       .regs = &tegra234_pmc_regs,
+       .init = NULL,
+       .setup_irq_polarity = tegra186_pmc_setup_irq_polarity,
+       .irq_set_wake = tegra186_pmc_irq_set_wake,
+       .irq_set_type = tegra186_pmc_irq_set_type,
+       .reset_sources = tegra234_reset_sources,
+       .num_reset_sources = ARRAY_SIZE(tegra234_reset_sources),
+       .reset_levels = tegra186_reset_levels,
+       .num_reset_levels = ARRAY_SIZE(tegra186_reset_levels),
+       .num_wake_events = 0,
+       .wake_events = NULL,
+       .pmc_clks_data = NULL,
+       .num_pmc_clks = 0,
+       .has_blink_output = false,
+};
+
 static const struct of_device_id tegra_pmc_match[] = {
+       { .compatible = "nvidia,tegra234-pmc", .data = &tegra234_pmc_soc },
        { .compatible = "nvidia,tegra194-pmc", .data = &tegra194_pmc_soc },
        { .compatible = "nvidia,tegra186-pmc", .data = &tegra186_pmc_soc },
        { .compatible = "nvidia,tegra210-pmc", .data = &tegra210_pmc_soc },
index e192fb7..f5b82ff 100644 (file)
@@ -101,6 +101,17 @@ config TI_K3_SOCINFO
          platforms to provide information about the SoC family and
          variant to user space.
 
+config TI_PRUSS
+       tristate "TI PRU-ICSS Subsystem Platform drivers"
+       depends on SOC_AM33XX || SOC_AM43XX || SOC_DRA7XX || ARCH_KEYSTONE || ARCH_K3
+       select MFD_SYSCON
+       help
+         TI PRU-ICSS Subsystem platform specific support.
+
+         Say Y or M here to support the Programmable Realtime Unit (PRU)
+         processors on various TI SoCs. It's safe to say N here if you're
+         not interested in the PRU or if you are unsure.
+
 endif # SOC_TI
 
 config TI_SCI_INTA_MSI_DOMAIN
index 5463431..cc3c972 100644 (file)
@@ -12,4 +12,5 @@ obj-$(CONFIG_TI_SCI_PM_DOMAINS)               += ti_sci_pm_domains.o
 obj-$(CONFIG_TI_SCI_INTA_MSI_DOMAIN)   += ti_sci_inta_msi.o
 obj-$(CONFIG_TI_K3_RINGACC)            += k3-ringacc.o
 obj-$(CONFIG_TI_K3_SOCINFO)            += k3-socinfo.o
+obj-$(CONFIG_TI_PRUSS)                 += pruss.o
 obj-$(CONFIG_POWER_AVS_OMAP)           += smartreflex.o
index 6dcc21d..1147dc4 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/init.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
+#include <linux/sys_soc.h>
 #include <linux/soc/ti/k3-ringacc.h>
 #include <linux/soc/ti/ti_sci_protocol.h>
 #include <linux/soc/ti/ti_sci_inta_msi.h>
@@ -208,6 +209,15 @@ struct k3_ringacc {
        const struct k3_ringacc_ops *ops;
 };
 
+/**
+ * struct k3_ringacc - Rings accelerator SoC data
+ *
+ * @dma_ring_reset_quirk:  DMA reset w/a enable
+ */
+struct k3_ringacc_soc_data {
+       unsigned dma_ring_reset_quirk:1;
+};
+
 static long k3_ringacc_ring_get_fifo_pos(struct k3_ring *ring)
 {
        return K3_RINGACC_FIFO_WINDOW_SIZE_BYTES -
@@ -1051,9 +1061,6 @@ static int k3_ringacc_probe_dt(struct k3_ringacc *ringacc)
                return ret;
        }
 
-       ringacc->dma_ring_reset_quirk =
-                       of_property_read_bool(node, "ti,dma-ring-reset-quirk");
-
        ringacc->tisci = ti_sci_get_by_phandle(node, "ti,sci");
        if (IS_ERR(ringacc->tisci)) {
                ret = PTR_ERR(ringacc->tisci);
@@ -1084,9 +1091,22 @@ static int k3_ringacc_probe_dt(struct k3_ringacc *ringacc)
                                                 ringacc->rm_gp_range);
 }
 
+static const struct k3_ringacc_soc_data k3_ringacc_soc_data_sr1 = {
+       .dma_ring_reset_quirk = 1,
+};
+
+static const struct soc_device_attribute k3_ringacc_socinfo[] = {
+       { .family = "AM65X",
+         .revision = "SR1.0",
+         .data = &k3_ringacc_soc_data_sr1
+       },
+       {/* sentinel */}
+};
+
 static int k3_ringacc_init(struct platform_device *pdev,
                           struct k3_ringacc *ringacc)
 {
+       const struct soc_device_attribute *soc;
        void __iomem *base_fifo, *base_rt;
        struct device *dev = &pdev->dev;
        struct resource *res;
@@ -1103,6 +1123,13 @@ static int k3_ringacc_init(struct platform_device *pdev,
        if (ret)
                return ret;
 
+       soc = soc_device_match(k3_ringacc_socinfo);
+       if (soc && soc->data) {
+               const struct k3_ringacc_soc_data *soc_data = soc->data;
+
+               ringacc->dma_ring_reset_quirk = soc_data->dma_ring_reset_quirk;
+       }
+
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rt");
        base_rt = devm_ioremap_resource(dev, res);
        if (IS_ERR(base_rt))
index af0ba52..bbbc2d2 100644 (file)
@@ -39,6 +39,7 @@ static const struct k3_soc_id {
 } k3_soc_ids[] = {
        { 0xBB5A, "AM65X" },
        { 0xBB64, "J721E" },
+       { 0xBB6D, "J7200" },
 };
 
 static int
index 6285cd8..8c863ec 100644 (file)
@@ -355,7 +355,7 @@ static void dma_debug_show_devices(struct seq_file *s,
        }
 }
 
-static int dma_debug_show(struct seq_file *s, void *v)
+static int knav_dma_debug_show(struct seq_file *s, void *v)
 {
        struct knav_dma_device *dma;
 
@@ -370,17 +370,7 @@ static int dma_debug_show(struct seq_file *s, void *v)
        return 0;
 }
 
-static int knav_dma_debug_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, dma_debug_show, NULL);
-}
-
-static const struct file_operations knav_dma_debug_ops = {
-       .open           = knav_dma_debug_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(knav_dma_debug);
 
 static int of_channel_match_helper(struct device_node *np, const char *name,
                                        const char **dma_instance)
@@ -778,7 +768,7 @@ static int knav_dma_probe(struct platform_device *pdev)
        }
 
        debugfs_create_file("knav_dma", S_IFREG | S_IRUGO, NULL, NULL,
-                           &knav_dma_debug_ops);
+                           &knav_dma_debug_fops);
 
        device_ready = true;
        return ret;
index aa071d9..a460f20 100644 (file)
@@ -478,17 +478,7 @@ static int knav_queue_debug_show(struct seq_file *s, void *v)
        return 0;
 }
 
-static int knav_queue_debug_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, knav_queue_debug_show, NULL);
-}
-
-static const struct file_operations knav_queue_debug_ops = {
-       .open           = knav_queue_debug_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(knav_queue_debug);
 
 static inline int knav_queue_pdsp_wait(u32 * __iomem addr, unsigned timeout,
                                        u32 flags)
@@ -1878,7 +1868,7 @@ static int knav_queue_probe(struct platform_device *pdev)
        }
 
        debugfs_create_file("qmss", S_IFREG | S_IRUGO, NULL, NULL,
-                           &knav_queue_debug_ops);
+                           &knav_queue_debug_fops);
        device_ready = true;
        return 0;
 
diff --git a/drivers/soc/ti/pruss.c b/drivers/soc/ti/pruss.c
new file mode 100644 (file)
index 0000000..cc0b4ad
--- /dev/null
@@ -0,0 +1,354 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * PRU-ICSS platform driver for various TI SoCs
+ *
+ * Copyright (C) 2014-2020 Texas Instruments Incorporated - http://www.ti.com/
+ * Author(s):
+ *     Suman Anna <s-anna@ti.com>
+ *     Andrew F. Davis <afd@ti.com>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/pruss_driver.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+/**
+ * struct pruss_private_data - PRUSS driver private data
+ * @has_no_sharedram: flag to indicate the absence of PRUSS Shared Data RAM
+ * @has_core_mux_clock: flag to indicate the presence of PRUSS core clock
+ */
+struct pruss_private_data {
+       bool has_no_sharedram;
+       bool has_core_mux_clock;
+};
+
+static void pruss_of_free_clk_provider(void *data)
+{
+       struct device_node *clk_mux_np = data;
+
+       of_clk_del_provider(clk_mux_np);
+       of_node_put(clk_mux_np);
+}
+
+static int pruss_clk_mux_setup(struct pruss *pruss, struct clk *clk_mux,
+                              char *mux_name, struct device_node *clks_np)
+{
+       struct device_node *clk_mux_np;
+       struct device *dev = pruss->dev;
+       char *clk_mux_name;
+       unsigned int num_parents;
+       const char **parent_names;
+       void __iomem *reg;
+       u32 reg_offset;
+       int ret;
+
+       clk_mux_np = of_get_child_by_name(clks_np, mux_name);
+       if (!clk_mux_np) {
+               dev_err(dev, "%pOF is missing its '%s' node\n", clks_np,
+                       mux_name);
+               return -ENODEV;
+       }
+
+       num_parents = of_clk_get_parent_count(clk_mux_np);
+       if (num_parents < 1) {
+               dev_err(dev, "mux-clock %pOF must have parents\n", clk_mux_np);
+               ret = -EINVAL;
+               goto put_clk_mux_np;
+       }
+
+       parent_names = devm_kcalloc(dev, sizeof(*parent_names), num_parents,
+                                   GFP_KERNEL);
+       if (!parent_names) {
+               ret = -ENOMEM;
+               goto put_clk_mux_np;
+       }
+
+       of_clk_parent_fill(clk_mux_np, parent_names, num_parents);
+
+       clk_mux_name = devm_kasprintf(dev, GFP_KERNEL, "%s.%pOFn",
+                                     dev_name(dev), clk_mux_np);
+       if (!clk_mux_name) {
+               ret = -ENOMEM;
+               goto put_clk_mux_np;
+       }
+
+       ret = of_property_read_u32(clk_mux_np, "reg", &reg_offset);
+       if (ret)
+               goto put_clk_mux_np;
+
+       reg = pruss->cfg_base + reg_offset;
+
+       clk_mux = clk_register_mux(NULL, clk_mux_name, parent_names,
+                                  num_parents, 0, reg, 0, 1, 0, NULL);
+       if (IS_ERR(clk_mux)) {
+               ret = PTR_ERR(clk_mux);
+               goto put_clk_mux_np;
+       }
+
+       ret = devm_add_action_or_reset(dev, (void(*)(void *))clk_unregister_mux,
+                                      clk_mux);
+       if (ret) {
+               dev_err(dev, "failed to add clkmux unregister action %d", ret);
+               goto put_clk_mux_np;
+       }
+
+       ret = of_clk_add_provider(clk_mux_np, of_clk_src_simple_get, clk_mux);
+       if (ret)
+               goto put_clk_mux_np;
+
+       ret = devm_add_action_or_reset(dev, pruss_of_free_clk_provider,
+                                      clk_mux_np);
+       if (ret) {
+               dev_err(dev, "failed to add clkmux free action %d", ret);
+               goto put_clk_mux_np;
+       }
+
+       return 0;
+
+put_clk_mux_np:
+       of_node_put(clk_mux_np);
+       return ret;
+}
+
+static int pruss_clk_init(struct pruss *pruss, struct device_node *cfg_node)
+{
+       const struct pruss_private_data *data;
+       struct device_node *clks_np;
+       struct device *dev = pruss->dev;
+       int ret = 0;
+
+       data = of_device_get_match_data(dev);
+       if (IS_ERR(data))
+               return -ENODEV;
+
+       clks_np = of_get_child_by_name(cfg_node, "clocks");
+       if (!clks_np) {
+               dev_err(dev, "%pOF is missing its 'clocks' node\n", clks_np);
+               return -ENODEV;
+       }
+
+       if (data && data->has_core_mux_clock) {
+               ret = pruss_clk_mux_setup(pruss, pruss->core_clk_mux,
+                                         "coreclk-mux", clks_np);
+               if (ret) {
+                       dev_err(dev, "failed to setup coreclk-mux\n");
+                       goto put_clks_node;
+               }
+       }
+
+       ret = pruss_clk_mux_setup(pruss, pruss->iep_clk_mux, "iepclk-mux",
+                                 clks_np);
+       if (ret) {
+               dev_err(dev, "failed to setup iepclk-mux\n");
+               goto put_clks_node;
+       }
+
+put_clks_node:
+       of_node_put(clks_np);
+
+       return ret;
+}
+
+static struct regmap_config regmap_conf = {
+       .reg_bits = 32,
+       .val_bits = 32,
+       .reg_stride = 4,
+};
+
+static int pruss_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct device_node *np = dev_of_node(dev);
+       struct device_node *child;
+       struct pruss *pruss;
+       struct resource res;
+       int ret, i, index;
+       const struct pruss_private_data *data;
+       const char *mem_names[PRUSS_MEM_MAX] = { "dram0", "dram1", "shrdram2" };
+
+       data = of_device_get_match_data(&pdev->dev);
+       if (IS_ERR(data)) {
+               dev_err(dev, "missing private data\n");
+               return -ENODEV;
+       }
+
+       ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
+       if (ret) {
+               dev_err(dev, "failed to set the DMA coherent mask");
+               return ret;
+       }
+
+       pruss = devm_kzalloc(dev, sizeof(*pruss), GFP_KERNEL);
+       if (!pruss)
+               return -ENOMEM;
+
+       pruss->dev = dev;
+
+       child = of_get_child_by_name(np, "memories");
+       if (!child) {
+               dev_err(dev, "%pOF is missing its 'memories' node\n", child);
+               return -ENODEV;
+       }
+
+       for (i = 0; i < PRUSS_MEM_MAX; i++) {
+               /*
+                * On AM437x one of two PRUSS units don't contain Shared RAM,
+                * skip it
+                */
+               if (data && data->has_no_sharedram && i == PRUSS_MEM_SHRD_RAM2)
+                       continue;
+
+               index = of_property_match_string(child, "reg-names",
+                                                mem_names[i]);
+               if (index < 0) {
+                       of_node_put(child);
+                       return index;
+               }
+
+               if (of_address_to_resource(child, index, &res)) {
+                       of_node_put(child);
+                       return -EINVAL;
+               }
+
+               pruss->mem_regions[i].va = devm_ioremap(dev, res.start,
+                                                       resource_size(&res));
+               if (!pruss->mem_regions[i].va) {
+                       dev_err(dev, "failed to parse and map memory resource %d %s\n",
+                               i, mem_names[i]);
+                       of_node_put(child);
+                       return -ENOMEM;
+               }
+               pruss->mem_regions[i].pa = res.start;
+               pruss->mem_regions[i].size = resource_size(&res);
+
+               dev_dbg(dev, "memory %8s: pa %pa size 0x%zx va %pK\n",
+                       mem_names[i], &pruss->mem_regions[i].pa,
+                       pruss->mem_regions[i].size, pruss->mem_regions[i].va);
+       }
+       of_node_put(child);
+
+       platform_set_drvdata(pdev, pruss);
+
+       pm_runtime_enable(dev);
+       ret = pm_runtime_get_sync(dev);
+       if (ret < 0) {
+               dev_err(dev, "couldn't enable module\n");
+               pm_runtime_put_noidle(dev);
+               goto rpm_disable;
+       }
+
+       child = of_get_child_by_name(np, "cfg");
+       if (!child) {
+               dev_err(dev, "%pOF is missing its 'cfg' node\n", child);
+               ret = -ENODEV;
+               goto rpm_put;
+       }
+
+       if (of_address_to_resource(child, 0, &res)) {
+               ret = -ENOMEM;
+               goto node_put;
+       }
+
+       pruss->cfg_base = devm_ioremap(dev, res.start, resource_size(&res));
+       if (!pruss->cfg_base) {
+               ret = -ENOMEM;
+               goto node_put;
+       }
+
+       regmap_conf.name = kasprintf(GFP_KERNEL, "%pOFn@%llx", child,
+                                    (u64)res.start);
+       regmap_conf.max_register = resource_size(&res) - 4;
+
+       pruss->cfg_regmap = devm_regmap_init_mmio(dev, pruss->cfg_base,
+                                                 &regmap_conf);
+       kfree(regmap_conf.name);
+       if (IS_ERR(pruss->cfg_regmap)) {
+               dev_err(dev, "regmap_init_mmio failed for cfg, ret = %ld\n",
+                       PTR_ERR(pruss->cfg_regmap));
+               ret = PTR_ERR(pruss->cfg_regmap);
+               goto node_put;
+       }
+
+       ret = pruss_clk_init(pruss, child);
+       if (ret) {
+               dev_err(dev, "failed to setup coreclk-mux\n");
+               goto node_put;
+       }
+
+       ret = devm_of_platform_populate(dev);
+       if (ret) {
+               dev_err(dev, "failed to register child devices\n");
+               goto node_put;
+       }
+
+       of_node_put(child);
+
+       return 0;
+
+node_put:
+       of_node_put(child);
+rpm_put:
+       pm_runtime_put_sync(dev);
+rpm_disable:
+       pm_runtime_disable(dev);
+       return ret;
+}
+
+static int pruss_remove(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+
+       devm_of_platform_depopulate(dev);
+
+       pm_runtime_put_sync(dev);
+       pm_runtime_disable(dev);
+
+       return 0;
+}
+
+/* instance-specific driver private data */
+static const struct pruss_private_data am437x_pruss1_data = {
+       .has_no_sharedram = false,
+};
+
+static const struct pruss_private_data am437x_pruss0_data = {
+       .has_no_sharedram = true,
+};
+
+static const struct pruss_private_data am65x_j721e_pruss_data = {
+       .has_core_mux_clock = true,
+};
+
+static const struct of_device_id pruss_of_match[] = {
+       { .compatible = "ti,am3356-pruss" },
+       { .compatible = "ti,am4376-pruss0", .data = &am437x_pruss0_data, },
+       { .compatible = "ti,am4376-pruss1", .data = &am437x_pruss1_data, },
+       { .compatible = "ti,am5728-pruss" },
+       { .compatible = "ti,k2g-pruss" },
+       { .compatible = "ti,am654-icssg", .data = &am65x_j721e_pruss_data, },
+       { .compatible = "ti,j721e-icssg", .data = &am65x_j721e_pruss_data, },
+       {},
+};
+MODULE_DEVICE_TABLE(of, pruss_of_match);
+
+static struct platform_driver pruss_driver = {
+       .driver = {
+               .name = "pruss",
+               .of_match_table = pruss_of_match,
+       },
+       .probe  = pruss_probe,
+       .remove = pruss_remove,
+};
+module_platform_driver(pruss_driver);
+
+MODULE_AUTHOR("Suman Anna <s-anna@ti.com>");
+MODULE_DESCRIPTION("PRU-ICSS Subsystem Driver");
+MODULE_LICENSE("GPL v2");
index 8c2a2f2..af2126d 100644 (file)
@@ -9,7 +9,6 @@
 
 #include <linux/err.h>
 #include <linux/module.h>
-#include <linux/mutex.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/pm_domain.h>
 #include <dt-bindings/soc/ti,sci_pm_domain.h>
 
 /**
- * struct ti_sci_genpd_dev_data: holds data needed for every device attached
- *                              to this genpd
- * @idx: index of the device that identifies it with the system
- *      control processor.
- * @exclusive: Permissions for exclusive request or shared request of the
- *            device.
+ * struct ti_sci_genpd_provider: holds common TI SCI genpd provider data
+ * @ti_sci: handle to TI SCI protocol driver that provides ops to
+ *         communicate with system control processor.
+ * @dev: pointer to dev for the driver for devm allocs
+ * @pd_list: list of all the power domains on the device
+ * @data: onecell data for genpd core
  */
-struct ti_sci_genpd_dev_data {
-       int idx;
-       u8 exclusive;
+struct ti_sci_genpd_provider {
+       const struct ti_sci_handle *ti_sci;
+       struct device *dev;
+       struct list_head pd_list;
+       struct genpd_onecell_data data;
 };
 
 /**
  * struct ti_sci_pm_domain: TI specific data needed for power domain
- * @ti_sci: handle to TI SCI protocol driver that provides ops to
- *         communicate with system control processor.
- * @dev: pointer to dev for the driver for devm allocs
+ * @idx: index of the device that identifies it with the system
+ *      control processor.
+ * @exclusive: Permissions for exclusive request or shared request of the
+ *            device.
  * @pd: generic_pm_domain for use with the genpd framework
+ * @node: link for the genpd list
+ * @parent: link to the parent TI SCI genpd provider
  */
 struct ti_sci_pm_domain {
-       const struct ti_sci_handle *ti_sci;
-       struct device *dev;
+       int idx;
+       u8 exclusive;
        struct generic_pm_domain pd;
+       struct list_head node;
+       struct ti_sci_genpd_provider *parent;
 };
 
 #define genpd_to_ti_sci_pd(gpd) container_of(gpd, struct ti_sci_pm_domain, pd)
 
-/**
- * ti_sci_dev_id(): get prepopulated ti_sci id from struct dev
- * @dev: pointer to device associated with this genpd
- *
- * Returns device_id stored from ti,sci_id property
- */
-static int ti_sci_dev_id(struct device *dev)
-{
-       struct generic_pm_domain_data *genpd_data = dev_gpd_data(dev);
-       struct ti_sci_genpd_dev_data *sci_dev_data = genpd_data->data;
-
-       return sci_dev_data->idx;
-}
-
-static u8 is_ti_sci_dev_exclusive(struct device *dev)
-{
-       struct generic_pm_domain_data *genpd_data = dev_gpd_data(dev);
-       struct ti_sci_genpd_dev_data *sci_dev_data = genpd_data->data;
-
-       return sci_dev_data->exclusive;
-}
-
-/**
- * ti_sci_dev_to_sci_handle(): get pointer to ti_sci_handle
- * @dev: pointer to device associated with this genpd
- *
- * Returns ti_sci_handle to be used to communicate with system
- *        control processor.
+/*
+ * ti_sci_pd_power_off(): genpd power down hook
+ * @domain: pointer to the powerdomain to power off
  */
-static const struct ti_sci_handle *ti_sci_dev_to_sci_handle(struct device *dev)
+static int ti_sci_pd_power_off(struct generic_pm_domain *domain)
 {
-       struct generic_pm_domain *pd = pd_to_genpd(dev->pm_domain);
-       struct ti_sci_pm_domain *ti_sci_genpd = genpd_to_ti_sci_pd(pd);
+       struct ti_sci_pm_domain *pd = genpd_to_ti_sci_pd(domain);
+       const struct ti_sci_handle *ti_sci = pd->parent->ti_sci;
 
-       return ti_sci_genpd->ti_sci;
+       return ti_sci->ops.dev_ops.put_device(ti_sci, pd->idx);
 }
 
-/**
- * ti_sci_dev_start(): genpd device start hook called to turn device on
- * @dev: pointer to device associated with this genpd to be powered on
+/*
+ * ti_sci_pd_power_on(): genpd power up hook
+ * @domain: pointer to the powerdomain to power on
  */
-static int ti_sci_dev_start(struct device *dev)
+static int ti_sci_pd_power_on(struct generic_pm_domain *domain)
 {
-       const struct ti_sci_handle *ti_sci = ti_sci_dev_to_sci_handle(dev);
-       int idx = ti_sci_dev_id(dev);
+       struct ti_sci_pm_domain *pd = genpd_to_ti_sci_pd(domain);
+       const struct ti_sci_handle *ti_sci = pd->parent->ti_sci;
 
-       if (is_ti_sci_dev_exclusive(dev))
-               return ti_sci->ops.dev_ops.get_device_exclusive(ti_sci, idx);
+       if (pd->exclusive)
+               return ti_sci->ops.dev_ops.get_device_exclusive(ti_sci,
+                                                               pd->idx);
        else
-               return ti_sci->ops.dev_ops.get_device(ti_sci, idx);
+               return ti_sci->ops.dev_ops.get_device(ti_sci, pd->idx);
 }
 
-/**
- * ti_sci_dev_stop(): genpd device stop hook called to turn device off
- * @dev: pointer to device associated with this genpd to be powered off
+/*
+ * ti_sci_pd_xlate(): translation service for TI SCI genpds
+ * @genpdspec: DT identification data for the genpd
+ * @data: genpd core data for all the powerdomains on the device
  */
-static int ti_sci_dev_stop(struct device *dev)
+static struct generic_pm_domain *ti_sci_pd_xlate(
+                                       struct of_phandle_args *genpdspec,
+                                       void *data)
 {
-       const struct ti_sci_handle *ti_sci = ti_sci_dev_to_sci_handle(dev);
-       int idx = ti_sci_dev_id(dev);
+       struct genpd_onecell_data *genpd_data = data;
+       unsigned int idx = genpdspec->args[0];
 
-       return ti_sci->ops.dev_ops.put_device(ti_sci, idx);
-}
+       if (genpdspec->args_count < 2)
+               return ERR_PTR(-EINVAL);
 
-static int ti_sci_pd_attach_dev(struct generic_pm_domain *domain,
-                               struct device *dev)
-{
-       struct device_node *np = dev->of_node;
-       struct of_phandle_args pd_args;
-       struct ti_sci_pm_domain *ti_sci_genpd = genpd_to_ti_sci_pd(domain);
-       const struct ti_sci_handle *ti_sci = ti_sci_genpd->ti_sci;
-       struct ti_sci_genpd_dev_data *sci_dev_data;
-       struct generic_pm_domain_data *genpd_data;
-       int idx, ret = 0;
-
-       ret = of_parse_phandle_with_args(np, "power-domains",
-                                        "#power-domain-cells", 0, &pd_args);
-       if (ret < 0)
-               return ret;
-
-       if (pd_args.args_count != 1 && pd_args.args_count != 2)
-               return -EINVAL;
-
-       idx = pd_args.args[0];
-
-       /*
-        * Check the validity of the requested idx, if the index is not valid
-        * the PMMC will return a NAK here and we will not allocate it.
-        */
-       ret = ti_sci->ops.dev_ops.is_valid(ti_sci, idx);
-       if (ret)
-               return -EINVAL;
-
-       sci_dev_data = kzalloc(sizeof(*sci_dev_data), GFP_KERNEL);
-       if (!sci_dev_data)
-               return -ENOMEM;
+       if (idx >= genpd_data->num_domains) {
+               pr_err("%s: invalid domain index %u\n", __func__, idx);
+               return ERR_PTR(-EINVAL);
+       }
 
-       sci_dev_data->idx = idx;
-       /* Enable the exclusive permissions by default */
-       sci_dev_data->exclusive = TI_SCI_PD_EXCLUSIVE;
-       if (pd_args.args_count == 2)
-               sci_dev_data->exclusive = pd_args.args[1] & 0x1;
+       if (!genpd_data->domains[idx])
+               return ERR_PTR(-ENOENT);
 
-       genpd_data = dev_gpd_data(dev);
-       genpd_data->data = sci_dev_data;
+       genpd_to_ti_sci_pd(genpd_data->domains[idx])->exclusive =
+               genpdspec->args[1];
 
-       return 0;
-}
-
-static void ti_sci_pd_detach_dev(struct generic_pm_domain *domain,
-                                struct device *dev)
-{
-       struct generic_pm_domain_data *genpd_data = dev_gpd_data(dev);
-       struct ti_sci_genpd_dev_data *sci_dev_data = genpd_data->data;
-
-       kfree(sci_dev_data);
-       genpd_data->data = NULL;
+       return genpd_data->domains[idx];
 }
 
 static const struct of_device_id ti_sci_pm_domain_matches[] = {
@@ -173,33 +117,80 @@ MODULE_DEVICE_TABLE(of, ti_sci_pm_domain_matches);
 static int ti_sci_pm_domain_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       struct device_node *np = dev->of_node;
-       struct ti_sci_pm_domain *ti_sci_pd;
+       struct ti_sci_genpd_provider *pd_provider;
+       struct ti_sci_pm_domain *pd;
+       struct device_node *np = NULL;
+       struct of_phandle_args args;
        int ret;
+       u32 max_id = 0;
+       int index;
 
-       ti_sci_pd = devm_kzalloc(dev, sizeof(*ti_sci_pd), GFP_KERNEL);
-       if (!ti_sci_pd)
+       pd_provider = devm_kzalloc(dev, sizeof(*pd_provider), GFP_KERNEL);
+       if (!pd_provider)
                return -ENOMEM;
 
-       ti_sci_pd->ti_sci = devm_ti_sci_get_handle(dev);
-       if (IS_ERR(ti_sci_pd->ti_sci))
-               return PTR_ERR(ti_sci_pd->ti_sci);
+       pd_provider->ti_sci = devm_ti_sci_get_handle(dev);
+       if (IS_ERR(pd_provider->ti_sci))
+               return PTR_ERR(pd_provider->ti_sci);
+
+       pd_provider->dev = dev;
+
+       INIT_LIST_HEAD(&pd_provider->pd_list);
+
+       /* Find highest device ID used for power domains */
+       while (1) {
+               np = of_find_node_with_property(np, "power-domains");
+               if (!np)
+                       break;
+
+               index = 0;
+
+               while (1) {
+                       ret = of_parse_phandle_with_args(np, "power-domains",
+                                                        "#power-domain-cells",
+                                                        index, &args);
+                       if (ret)
+                               break;
+
+                       if (args.args_count >= 1 && args.np == dev->of_node) {
+                               if (args.args[0] > max_id)
+                                       max_id = args.args[0];
+
+                               pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
+                               if (!pd)
+                                       return -ENOMEM;
+
+                               pd->pd.name = devm_kasprintf(dev, GFP_KERNEL,
+                                                            "pd:%d",
+                                                            args.args[0]);
+                               if (!pd->pd.name)
+                                       return -ENOMEM;
 
-       ti_sci_pd->dev = dev;
+                               pd->pd.power_off = ti_sci_pd_power_off;
+                               pd->pd.power_on = ti_sci_pd_power_on;
+                               pd->idx = args.args[0];
+                               pd->parent = pd_provider;
 
-       ti_sci_pd->pd.name = "ti_sci_pd";
+                               pm_genpd_init(&pd->pd, NULL, true);
 
-       ti_sci_pd->pd.attach_dev = ti_sci_pd_attach_dev;
-       ti_sci_pd->pd.detach_dev = ti_sci_pd_detach_dev;
+                               list_add(&pd->node, &pd_provider->pd_list);
+                       }
+                       index++;
+               }
+       }
 
-       ti_sci_pd->pd.dev_ops.start = ti_sci_dev_start;
-       ti_sci_pd->pd.dev_ops.stop = ti_sci_dev_stop;
+       pd_provider->data.domains =
+               devm_kcalloc(dev, max_id + 1,
+                            sizeof(*pd_provider->data.domains),
+                            GFP_KERNEL);
 
-       pm_genpd_init(&ti_sci_pd->pd, NULL, true);
+       pd_provider->data.num_domains = max_id + 1;
+       pd_provider->data.xlate = ti_sci_pd_xlate;
 
-       ret = of_genpd_add_provider_simple(np, &ti_sci_pd->pd);
+       list_for_each_entry(pd, &pd_provider->pd_list, node)
+               pd_provider->data.domains[pd->idx] = &pd->pd;
 
-       return ret;
+       return of_genpd_add_provider_onecell(dev->of_node, &pd_provider->data);
 }
 
 static struct platform_driver ti_sci_pm_domains_driver = {
index b373b1b..cf4718c 100644 (file)
@@ -216,6 +216,8 @@ static void optee_get_version(struct tee_device *teedev,
 
        if (optee->sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM)
                v.gen_caps |= TEE_GEN_CAP_REG_MEM;
+       if (optee->sec_caps & OPTEE_SMC_SEC_CAP_MEMREF_NULL)
+               v.gen_caps |= TEE_GEN_CAP_MEMREF_NULL;
        *vers = v;
 }
 
@@ -262,6 +264,11 @@ static int optee_open(struct tee_context *ctx)
        mutex_init(&ctxdata->mutex);
        INIT_LIST_HEAD(&ctxdata->sess_list);
 
+       if (optee->sec_caps & OPTEE_SMC_SEC_CAP_MEMREF_NULL)
+               ctx->cap_memref_null  = true;
+       else
+               ctx->cap_memref_null = false;
+
        ctx->data = ctxdata;
        return 0;
 }
index 795bc19..7b2d919 100644 (file)
@@ -419,4 +419,25 @@ struct optee_msg_arg {
  */
 #define OPTEE_MSG_RPC_CMD_SHM_FREE     7
 
+/*
+ * Access a device on an i2c bus
+ *
+ * [in]  param[0].u.value.a            mode: RD(0), WR(1)
+ * [in]  param[0].u.value.b            i2c adapter
+ * [in]  param[0].u.value.c            i2c chip
+ *
+ * [in]  param[1].u.value.a            i2c control flags
+ *
+ * [in/out] memref[2]                  buffer to exchange the transfer data
+ *                                     with the secure world
+ *
+ * [out]  param[3].u.value.a           bytes transferred by the driver
+ */
+#define OPTEE_MSG_RPC_CMD_I2C_TRANSFER 21
+/* I2C master transfer modes */
+#define OPTEE_MSG_RPC_CMD_I2C_TRANSFER_RD 0
+#define OPTEE_MSG_RPC_CMD_I2C_TRANSFER_WR 1
+/* I2C master control flags */
+#define OPTEE_MSG_RPC_CMD_I2C_FLAGS_TEN_BIT  BIT(0)
+
 #endif /* _OPTEE_MSG_H */
index 8b71839..e25b216 100644 (file)
@@ -17,6 +17,7 @@
 /* Some Global Platform error codes used in this driver */
 #define TEEC_SUCCESS                   0x00000000
 #define TEEC_ERROR_BAD_PARAMETERS      0xFFFF0006
+#define TEEC_ERROR_NOT_SUPPORTED       0xFFFF000A
 #define TEEC_ERROR_COMMUNICATION       0xFFFF000E
 #define TEEC_ERROR_OUT_OF_MEMORY       0xFFFF000C
 #define TEEC_ERROR_SHORT_BUFFER                0xFFFF0010
index c72122d..777ad54 100644 (file)
@@ -215,6 +215,9 @@ struct optee_smc_get_shm_config_result {
  */
 #define OPTEE_SMC_SEC_CAP_DYNAMIC_SHM          BIT(2)
 
+/* Secure world supports Shared Memory with a NULL buffer reference */
+#define OPTEE_SMC_SEC_CAP_MEMREF_NULL          BIT(4)
+
 #define OPTEE_SMC_FUNCID_EXCHANGE_CAPABILITIES 9
 #define OPTEE_SMC_EXCHANGE_CAPABILITIES \
        OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_EXCHANGE_CAPABILITIES)
index b4ade54..1e3614e 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <linux/delay.h>
 #include <linux/device.h>
+#include <linux/i2c.h>
 #include <linux/slab.h>
 #include <linux/tee_drv.h>
 #include "optee_private.h"
@@ -49,6 +50,97 @@ bad:
        arg->ret = TEEC_ERROR_BAD_PARAMETERS;
 }
 
+#if IS_REACHABLE(CONFIG_I2C)
+static void handle_rpc_func_cmd_i2c_transfer(struct tee_context *ctx,
+                                            struct optee_msg_arg *arg)
+{
+       struct i2c_client client = { 0 };
+       struct tee_param *params;
+       size_t i;
+       int ret = -EOPNOTSUPP;
+       u8 attr[] = {
+               TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
+               TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
+               TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT,
+               TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT,
+       };
+
+       if (arg->num_params != ARRAY_SIZE(attr)) {
+               arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+               return;
+       }
+
+       params = kmalloc_array(arg->num_params, sizeof(struct tee_param),
+                              GFP_KERNEL);
+       if (!params) {
+               arg->ret = TEEC_ERROR_OUT_OF_MEMORY;
+               return;
+       }
+
+       if (optee_from_msg_param(params, arg->num_params, arg->params))
+               goto bad;
+
+       for (i = 0; i < arg->num_params; i++) {
+               if (params[i].attr != attr[i])
+                       goto bad;
+       }
+
+       client.adapter = i2c_get_adapter(params[0].u.value.b);
+       if (!client.adapter)
+               goto bad;
+
+       if (params[1].u.value.a & OPTEE_MSG_RPC_CMD_I2C_FLAGS_TEN_BIT) {
+               if (!i2c_check_functionality(client.adapter,
+                                            I2C_FUNC_10BIT_ADDR)) {
+                       i2c_put_adapter(client.adapter);
+                       goto bad;
+               }
+
+               client.flags = I2C_CLIENT_TEN;
+       }
+
+       client.addr = params[0].u.value.c;
+       snprintf(client.name, I2C_NAME_SIZE, "i2c%d", client.adapter->nr);
+
+       switch (params[0].u.value.a) {
+       case OPTEE_MSG_RPC_CMD_I2C_TRANSFER_RD:
+               ret = i2c_master_recv(&client, params[2].u.memref.shm->kaddr,
+                                     params[2].u.memref.size);
+               break;
+       case OPTEE_MSG_RPC_CMD_I2C_TRANSFER_WR:
+               ret = i2c_master_send(&client, params[2].u.memref.shm->kaddr,
+                                     params[2].u.memref.size);
+               break;
+       default:
+               i2c_put_adapter(client.adapter);
+               goto bad;
+       }
+
+       if (ret < 0) {
+               arg->ret = TEEC_ERROR_COMMUNICATION;
+       } else {
+               params[3].u.value.a = ret;
+               if (optee_to_msg_param(arg->params, arg->num_params, params))
+                       arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+               else
+                       arg->ret = TEEC_SUCCESS;
+       }
+
+       i2c_put_adapter(client.adapter);
+       kfree(params);
+       return;
+bad:
+       kfree(params);
+       arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+}
+#else
+static void handle_rpc_func_cmd_i2c_transfer(struct tee_context *ctx,
+                                            struct optee_msg_arg *arg)
+{
+       arg->ret = TEEC_ERROR_NOT_SUPPORTED;
+}
+#endif
+
 static struct wq_entry *wq_entry_get(struct optee_wait_queue *wq, u32 key)
 {
        struct wq_entry *w;
@@ -382,6 +474,9 @@ static void handle_rpc_func_cmd(struct tee_context *ctx, struct optee *optee,
        case OPTEE_MSG_RPC_CMD_SHM_FREE:
                handle_rpc_func_cmd_shm_free(ctx, arg);
                break;
+       case OPTEE_MSG_RPC_CMD_I2C_TRANSFER:
+               handle_rpc_func_cmd_i2c_transfer(ctx, arg);
+               break;
        default:
                handle_rpc_supp_cmd(ctx, arg);
        }
index 64637e0..f53bf33 100644 (file)
@@ -383,25 +383,38 @@ static int params_from_user(struct tee_context *ctx, struct tee_param *params,
                case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
                case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
                        /*
-                        * If we fail to get a pointer to a shared memory
-                        * object (and increase the ref count) from an
-                        * identifier we return an error. All pointers that
-                        * has been added in params have an increased ref
-                        * count. It's the callers responibility to do
-                        * tee_shm_put() on all resolved pointers.
+                        * If a NULL pointer is passed to a TA in the TEE,
+                        * the ip.c IOCTL parameters is set to TEE_MEMREF_NULL
+                        * indicating a NULL memory reference.
                         */
-                       shm = tee_shm_get_from_id(ctx, ip.c);
-                       if (IS_ERR(shm))
-                               return PTR_ERR(shm);
-
-                       /*
-                        * Ensure offset + size does not overflow offset
-                        * and does not overflow the size of the referred
-                        * shared memory object.
-                        */
-                       if ((ip.a + ip.b) < ip.a ||
-                           (ip.a + ip.b) > shm->size) {
-                               tee_shm_put(shm);
+                       if (ip.c != TEE_MEMREF_NULL) {
+                               /*
+                                * If we fail to get a pointer to a shared
+                                * memory object (and increase the ref count)
+                                * from an identifier we return an error. All
+                                * pointers that has been added in params have
+                                * an increased ref count. It's the callers
+                                * responibility to do tee_shm_put() on all
+                                * resolved pointers.
+                                */
+                               shm = tee_shm_get_from_id(ctx, ip.c);
+                               if (IS_ERR(shm))
+                                       return PTR_ERR(shm);
+
+                               /*
+                                * Ensure offset + size does not overflow
+                                * offset and does not overflow the size of
+                                * the referred shared memory object.
+                                */
+                               if ((ip.a + ip.b) < ip.a ||
+                                   (ip.a + ip.b) > shm->size) {
+                                       tee_shm_put(shm);
+                                       return -EINVAL;
+                               }
+                       } else if (ctx->cap_memref_null) {
+                               /* Pass NULL pointer to OP-TEE */
+                               shm = NULL;
+                       } else {
                                return -EINVAL;
                        }
 
@@ -917,7 +930,6 @@ struct tee_device *tee_device_alloc(const struct tee_desc *teedesc,
 
        cdev_init(&teedev->cdev, &tee_fops);
        teedev->cdev.owner = teedesc->owner;
-       teedev->cdev.kobj.parent = &teedev->dev.kobj;
 
        dev_set_drvdata(&teedev->dev, driver_data);
        device_initialize(&teedev->dev);
@@ -963,9 +975,7 @@ static struct attribute *tee_dev_attrs[] = {
        NULL
 };
 
-static const struct attribute_group tee_dev_group = {
-       .attrs = tee_dev_attrs,
-};
+ATTRIBUTE_GROUPS(tee_dev);
 
 /**
  * tee_device_register() - Registers a TEE device
@@ -985,39 +995,19 @@ int tee_device_register(struct tee_device *teedev)
                return -EINVAL;
        }
 
-       rc = cdev_add(&teedev->cdev, teedev->dev.devt, 1);
-       if (rc) {
-               dev_err(&teedev->dev,
-                       "unable to cdev_add() %s, major %d, minor %d, err=%d\n",
-                       teedev->name, MAJOR(teedev->dev.devt),
-                       MINOR(teedev->dev.devt), rc);
-               return rc;
-       }
+       teedev->dev.groups = tee_dev_groups;
 
-       rc = device_add(&teedev->dev);
+       rc = cdev_device_add(&teedev->cdev, &teedev->dev);
        if (rc) {
                dev_err(&teedev->dev,
-                       "unable to device_add() %s, major %d, minor %d, err=%d\n",
+                       "unable to cdev_device_add() %s, major %d, minor %d, err=%d\n",
                        teedev->name, MAJOR(teedev->dev.devt),
                        MINOR(teedev->dev.devt), rc);
-               goto err_device_add;
-       }
-
-       rc = sysfs_create_group(&teedev->dev.kobj, &tee_dev_group);
-       if (rc) {
-               dev_err(&teedev->dev,
-                       "failed to create sysfs attributes, err=%d\n", rc);
-               goto err_sysfs_create_group;
+               return rc;
        }
 
        teedev->flags |= TEE_DEVICE_FLAG_REGISTERED;
        return 0;
-
-err_sysfs_create_group:
-       device_del(&teedev->dev);
-err_device_add:
-       cdev_del(&teedev->cdev);
-       return rc;
 }
 EXPORT_SYMBOL_GPL(tee_device_register);
 
@@ -1060,11 +1050,8 @@ void tee_device_unregister(struct tee_device *teedev)
        if (!teedev)
                return;
 
-       if (teedev->flags & TEE_DEVICE_FLAG_REGISTERED) {
-               sysfs_remove_group(&teedev->dev.kobj, &tee_dev_group);
-               cdev_del(&teedev->cdev);
-               device_del(&teedev->dev);
-       }
+       if (teedev->flags & TEE_DEVICE_FLAG_REGISTERED)
+               cdev_device_del(&teedev->cdev, &teedev->dev);
 
        tee_device_put(teedev);
        wait_for_completion(&teedev->c_no_users);
index 827ac3d..00472f5 100644 (file)
 #include <linux/uio.h>
 #include "tee_private.h"
 
+static void release_registered_pages(struct tee_shm *shm)
+{
+       if (shm->pages) {
+               if (shm->flags & TEE_SHM_USER_MAPPED) {
+                       unpin_user_pages(shm->pages, shm->num_pages);
+               } else {
+                       size_t n;
+
+                       for (n = 0; n < shm->num_pages; n++)
+                               put_page(shm->pages[n]);
+               }
+
+               kfree(shm->pages);
+       }
+}
+
 static void tee_shm_release(struct tee_shm *shm)
 {
        struct tee_device *teedev = shm->ctx->teedev;
@@ -32,17 +48,13 @@ static void tee_shm_release(struct tee_shm *shm)
 
                poolm->ops->free(poolm, shm);
        } else if (shm->flags & TEE_SHM_REGISTER) {
-               size_t n;
                int rc = teedev->desc->ops->shm_unregister(shm->ctx, shm);
 
                if (rc)
                        dev_err(teedev->dev.parent,
                                "unregister shm %p failed: %d", shm, rc);
 
-               for (n = 0; n < shm->num_pages; n++)
-                       put_page(shm->pages[n]);
-
-               kfree(shm->pages);
+               release_registered_pages(shm);
        }
 
        teedev_ctx_put(shm->ctx);
@@ -228,7 +240,7 @@ struct tee_shm *tee_shm_register(struct tee_context *ctx, unsigned long addr,
        }
 
        if (flags & TEE_SHM_USER_MAPPED) {
-               rc = get_user_pages_fast(start, num_pages, FOLL_WRITE,
+               rc = pin_user_pages_fast(start, num_pages, FOLL_WRITE,
                                         shm->pages);
        } else {
                struct kvec *kiov;
@@ -292,18 +304,12 @@ struct tee_shm *tee_shm_register(struct tee_context *ctx, unsigned long addr,
        return shm;
 err:
        if (shm) {
-               size_t n;
-
                if (shm->id >= 0) {
                        mutex_lock(&teedev->mutex);
                        idr_remove(&teedev->idr, shm->id);
                        mutex_unlock(&teedev->mutex);
                }
-               if (shm->pages) {
-                       for (n = 0; n < shm->num_pages; n++)
-                               put_page(shm->pages[n]);
-                       kfree(shm->pages);
-               }
+               release_registered_pages(shm);
        }
        kfree(shm);
        teedev_ctx_put(ctx);
diff --git a/include/dt-bindings/power/meson-axg-power.h b/include/dt-bindings/power/meson-axg-power.h
new file mode 100644 (file)
index 0000000..e524388
--- /dev/null
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: (GPL-2.0+ or MIT) */
+/*
+ * Copyright (c) 2020 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ */
+
+#ifndef _DT_BINDINGS_MESON_AXG_POWER_H
+#define _DT_BINDINGS_MESON_AXG_POWER_H
+
+#define PWRC_AXG_VPU_ID                        0
+#define PWRC_AXG_ETHERNET_MEM_ID       1
+#define PWRC_AXG_AUDIO_ID              2
+
+#endif
index a5b5707..7058706 100644 (file)
 #define IMX8MQ_RESET_DDRC2_PRST                        47      /* i.MX8MM/i.MX8MN does NOT support */
 #define IMX8MQ_RESET_DDRC2_CORE_RESET          48      /* i.MX8MM/i.MX8MN does NOT support */
 #define IMX8MQ_RESET_DDRC2_PHY_RESET           49      /* i.MX8MM/i.MX8MN does NOT support */
+#define IMX8MQ_RESET_SW_M4C_RST                        50
+#define IMX8MQ_RESET_SW_M4P_RST                        51
+#define IMX8MQ_RESET_M4_ENABLE                 52
 
-#define IMX8MQ_RESET_NUM                       50
+#define IMX8MQ_RESET_NUM                       53
 
 #endif
diff --git a/include/dt-bindings/reset/xlnx-versal-resets.h b/include/dt-bindings/reset/xlnx-versal-resets.h
new file mode 100644 (file)
index 0000000..895424e
--- /dev/null
@@ -0,0 +1,105 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ *  Copyright (C) 2020 Xilinx, Inc.
+ */
+
+#ifndef _DT_BINDINGS_VERSAL_RESETS_H
+#define _DT_BINDINGS_VERSAL_RESETS_H
+
+#define VERSAL_RST_PMC_POR                     (0xc30c001U)
+#define VERSAL_RST_PMC                         (0xc410002U)
+#define VERSAL_RST_PS_POR                      (0xc30c003U)
+#define VERSAL_RST_PL_POR                      (0xc30c004U)
+#define VERSAL_RST_NOC_POR                     (0xc30c005U)
+#define VERSAL_RST_FPD_POR                     (0xc30c006U)
+#define VERSAL_RST_ACPU_0_POR                  (0xc30c007U)
+#define VERSAL_RST_ACPU_1_POR                  (0xc30c008U)
+#define VERSAL_RST_OCM2_POR                    (0xc30c009U)
+#define VERSAL_RST_PS_SRST                     (0xc41000aU)
+#define VERSAL_RST_PL_SRST                     (0xc41000bU)
+#define VERSAL_RST_NOC                         (0xc41000cU)
+#define VERSAL_RST_NPI                         (0xc41000dU)
+#define VERSAL_RST_SYS_RST_1                   (0xc41000eU)
+#define VERSAL_RST_SYS_RST_2                   (0xc41000fU)
+#define VERSAL_RST_SYS_RST_3                   (0xc410010U)
+#define VERSAL_RST_FPD                         (0xc410011U)
+#define VERSAL_RST_PL0                         (0xc410012U)
+#define VERSAL_RST_PL1                         (0xc410013U)
+#define VERSAL_RST_PL2                         (0xc410014U)
+#define VERSAL_RST_PL3                         (0xc410015U)
+#define VERSAL_RST_APU                         (0xc410016U)
+#define VERSAL_RST_ACPU_0                      (0xc410017U)
+#define VERSAL_RST_ACPU_1                      (0xc410018U)
+#define VERSAL_RST_ACPU_L2                     (0xc410019U)
+#define VERSAL_RST_ACPU_GIC                    (0xc41001aU)
+#define VERSAL_RST_RPU_ISLAND                  (0xc41001bU)
+#define VERSAL_RST_RPU_AMBA                    (0xc41001cU)
+#define VERSAL_RST_R5_0                                (0xc41001dU)
+#define VERSAL_RST_R5_1                                (0xc41001eU)
+#define VERSAL_RST_SYSMON_PMC_SEQ_RST          (0xc41001fU)
+#define VERSAL_RST_SYSMON_PMC_CFG_RST          (0xc410020U)
+#define VERSAL_RST_SYSMON_FPD_CFG_RST          (0xc410021U)
+#define VERSAL_RST_SYSMON_FPD_SEQ_RST          (0xc410022U)
+#define VERSAL_RST_SYSMON_LPD                  (0xc410023U)
+#define VERSAL_RST_PDMA_RST1                   (0xc410024U)
+#define VERSAL_RST_PDMA_RST0                   (0xc410025U)
+#define VERSAL_RST_ADMA                                (0xc410026U)
+#define VERSAL_RST_TIMESTAMP                   (0xc410027U)
+#define VERSAL_RST_OCM                         (0xc410028U)
+#define VERSAL_RST_OCM2_RST                    (0xc410029U)
+#define VERSAL_RST_IPI                         (0xc41002aU)
+#define VERSAL_RST_SBI                         (0xc41002bU)
+#define VERSAL_RST_LPD                         (0xc41002cU)
+#define VERSAL_RST_QSPI                                (0xc10402dU)
+#define VERSAL_RST_OSPI                                (0xc10402eU)
+#define VERSAL_RST_SDIO_0                      (0xc10402fU)
+#define VERSAL_RST_SDIO_1                      (0xc104030U)
+#define VERSAL_RST_I2C_PMC                     (0xc104031U)
+#define VERSAL_RST_GPIO_PMC                    (0xc104032U)
+#define VERSAL_RST_GEM_0                       (0xc104033U)
+#define VERSAL_RST_GEM_1                       (0xc104034U)
+#define VERSAL_RST_SPARE                       (0xc104035U)
+#define VERSAL_RST_USB_0                       (0xc104036U)
+#define VERSAL_RST_UART_0                      (0xc104037U)
+#define VERSAL_RST_UART_1                      (0xc104038U)
+#define VERSAL_RST_SPI_0                       (0xc104039U)
+#define VERSAL_RST_SPI_1                       (0xc10403aU)
+#define VERSAL_RST_CAN_FD_0                    (0xc10403bU)
+#define VERSAL_RST_CAN_FD_1                    (0xc10403cU)
+#define VERSAL_RST_I2C_0                       (0xc10403dU)
+#define VERSAL_RST_I2C_1                       (0xc10403eU)
+#define VERSAL_RST_GPIO_LPD                    (0xc10403fU)
+#define VERSAL_RST_TTC_0                       (0xc104040U)
+#define VERSAL_RST_TTC_1                       (0xc104041U)
+#define VERSAL_RST_TTC_2                       (0xc104042U)
+#define VERSAL_RST_TTC_3                       (0xc104043U)
+#define VERSAL_RST_SWDT_FPD                    (0xc104044U)
+#define VERSAL_RST_SWDT_LPD                    (0xc104045U)
+#define VERSAL_RST_USB                         (0xc104046U)
+#define VERSAL_RST_DPC                         (0xc208047U)
+#define VERSAL_RST_PMCDBG                      (0xc208048U)
+#define VERSAL_RST_DBG_TRACE                   (0xc208049U)
+#define VERSAL_RST_DBG_FPD                     (0xc20804aU)
+#define VERSAL_RST_DBG_TSTMP                   (0xc20804bU)
+#define VERSAL_RST_RPU0_DBG                    (0xc20804cU)
+#define VERSAL_RST_RPU1_DBG                    (0xc20804dU)
+#define VERSAL_RST_HSDP                                (0xc20804eU)
+#define VERSAL_RST_DBG_LPD                     (0xc20804fU)
+#define VERSAL_RST_CPM_POR                     (0xc30c050U)
+#define VERSAL_RST_CPM                         (0xc410051U)
+#define VERSAL_RST_CPMDBG                      (0xc208052U)
+#define VERSAL_RST_PCIE_CFG                    (0xc410053U)
+#define VERSAL_RST_PCIE_CORE0                  (0xc410054U)
+#define VERSAL_RST_PCIE_CORE1                  (0xc410055U)
+#define VERSAL_RST_PCIE_DMA                    (0xc410056U)
+#define VERSAL_RST_CMN                         (0xc410057U)
+#define VERSAL_RST_L2_0                                (0xc410058U)
+#define VERSAL_RST_L2_1                                (0xc410059U)
+#define VERSAL_RST_ADDR_REMAP                  (0xc41005aU)
+#define VERSAL_RST_CPI0                                (0xc41005bU)
+#define VERSAL_RST_CPI1                                (0xc41005cU)
+#define VERSAL_RST_XRAM                                (0xc30c05dU)
+#define VERSAL_RST_AIE_ARRAY                   (0xc10405eU)
+#define VERSAL_RST_AIE_SHIM                    (0xc10405fU)
+
+#endif
diff --git a/include/dt-bindings/soc/bcm6318-pm.h b/include/dt-bindings/soc/bcm6318-pm.h
new file mode 100644 (file)
index 0000000..05931dc
--- /dev/null
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+#ifndef __DT_BINDINGS_BMIPS_BCM6318_PM_H
+#define __DT_BINDINGS_BMIPS_BCM6318_PM_H
+
+#define BCM6318_POWER_DOMAIN_PCIE      0
+#define BCM6318_POWER_DOMAIN_USB       1
+#define BCM6318_POWER_DOMAIN_EPHY0     2
+#define BCM6318_POWER_DOMAIN_EPHY1     3
+#define BCM6318_POWER_DOMAIN_EPHY2     4
+#define BCM6318_POWER_DOMAIN_EPHY3     5
+#define BCM6318_POWER_DOMAIN_LDO2P5    6
+#define BCM6318_POWER_DOMAIN_LDO2P9    7
+#define BCM6318_POWER_DOMAIN_SW1P0     8
+#define BCM6318_POWER_DOMAIN_PAD       9
+
+#endif /* __DT_BINDINGS_BMIPS_BCM6318_PM_H */
diff --git a/include/dt-bindings/soc/bcm63268-pm.h b/include/dt-bindings/soc/bcm63268-pm.h
new file mode 100644 (file)
index 0000000..84ded53
--- /dev/null
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+#ifndef __DT_BINDINGS_BMIPS_BCM63268_PM_H
+#define __DT_BINDINGS_BMIPS_BCM63268_PM_H
+
+#define BCM63268_POWER_DOMAIN_SAR      0
+#define BCM63268_POWER_DOMAIN_IPSEC    1
+#define BCM63268_POWER_DOMAIN_MIPS     2
+#define BCM63268_POWER_DOMAIN_DECT     3
+#define BCM63268_POWER_DOMAIN_USBH     4
+#define BCM63268_POWER_DOMAIN_USBD     5
+#define BCM63268_POWER_DOMAIN_ROBOSW   6
+#define BCM63268_POWER_DOMAIN_PCM      7
+#define BCM63268_POWER_DOMAIN_PERIPH   8
+#define BCM63268_POWER_DOMAIN_VDSL_PHY 9
+#define BCM63268_POWER_DOMAIN_VDSL_MIPS        10
+#define BCM63268_POWER_DOMAIN_FAP      11
+#define BCM63268_POWER_DOMAIN_PCIE     12
+#define BCM63268_POWER_DOMAIN_WLAN_PADS        13
+
+#endif /* __DT_BINDINGS_BMIPS_BCM63268_PM_H */
diff --git a/include/dt-bindings/soc/bcm6328-pm.h b/include/dt-bindings/soc/bcm6328-pm.h
new file mode 100644 (file)
index 0000000..557e1a6
--- /dev/null
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+#ifndef __DT_BINDINGS_BMIPS_BCM6328_PM_H
+#define __DT_BINDINGS_BMIPS_BCM6328_PM_H
+
+#define BCM6328_POWER_DOMAIN_ADSL2_MIPS        0
+#define BCM6328_POWER_DOMAIN_ADSL2_PHY 1
+#define BCM6328_POWER_DOMAIN_ADSL2_AFE 2
+#define BCM6328_POWER_DOMAIN_SAR       3
+#define BCM6328_POWER_DOMAIN_PCM       4
+#define BCM6328_POWER_DOMAIN_USBD      5
+#define BCM6328_POWER_DOMAIN_USBH      6
+#define BCM6328_POWER_DOMAIN_PCIE      7
+#define BCM6328_POWER_DOMAIN_ROBOSW    8
+#define BCM6328_POWER_DOMAIN_EPHY      9
+
+#endif /* __DT_BINDINGS_BMIPS_BCM6328_PM_H */
diff --git a/include/dt-bindings/soc/bcm6362-pm.h b/include/dt-bindings/soc/bcm6362-pm.h
new file mode 100644 (file)
index 0000000..d087ba6
--- /dev/null
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+#ifndef __DT_BINDINGS_BMIPS_BCM6362_PM_H
+#define __DT_BINDINGS_BMIPS_BCM6362_PM_H
+
+#define BCM6362_POWER_DOMAIN_SAR       0
+#define BCM6362_POWER_DOMAIN_IPSEC     1
+#define BCM6362_POWER_DOMAIN_MIPS      2
+#define BCM6362_POWER_DOMAIN_DECT      3
+#define BCM6362_POWER_DOMAIN_USBH      4
+#define BCM6362_POWER_DOMAIN_USBD      5
+#define BCM6362_POWER_DOMAIN_ROBOSW    6
+#define BCM6362_POWER_DOMAIN_PCM       7
+#define BCM6362_POWER_DOMAIN_PERIPH    8
+#define BCM6362_POWER_DOMAIN_ADSL_PHY  9
+#define BCM6362_POWER_DOMAIN_GMII_PADS 10
+#define BCM6362_POWER_DOMAIN_FAP       11
+#define BCM6362_POWER_DOMAIN_PCIE      12
+#define BCM6362_POWER_DOMAIN_WLAN_PADS 13
+
+#endif /* __DT_BINDINGS_BMIPS_BCM6362_PM_H */
index 05eea1a..d5a983d 100644 (file)
@@ -28,8 +28,7 @@
  * bit 16-27: update value
  * bit 31: 1 - update, 0 - no update
  */
-#define CMDQ_WFE_OPTION                        (CMDQ_WFE_UPDATE | CMDQ_WFE_WAIT | \
-                                       CMDQ_WFE_WAIT_VALUE)
+#define CMDQ_WFE_OPTION                        (CMDQ_WFE_WAIT | CMDQ_WFE_WAIT_VALUE)
 
 /** cmdq event maximum */
 #define CMDQ_MAX_EVENT                 0x3ff
@@ -60,6 +59,9 @@ enum cmdq_code {
        CMDQ_CODE_JUMP = 0x10,
        CMDQ_CODE_WFE = 0x20,
        CMDQ_CODE_EOC = 0x40,
+       CMDQ_CODE_READ_S = 0x80,
+       CMDQ_CODE_WRITE_S = 0x90,
+       CMDQ_CODE_WRITE_S_MASK = 0x91,
        CMDQ_CODE_LOGIC = 0xa0,
 };
 
diff --git a/include/linux/pruss_driver.h b/include/linux/pruss_driver.h
new file mode 100644 (file)
index 0000000..ecfded3
--- /dev/null
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * PRU-ICSS sub-system specific definitions
+ *
+ * Copyright (C) 2014-2020 Texas Instruments Incorporated - http://www.ti.com/
+ *     Suman Anna <s-anna@ti.com>
+ */
+
+#ifndef _PRUSS_DRIVER_H_
+#define _PRUSS_DRIVER_H_
+
+#include <linux/types.h>
+
+/*
+ * enum pruss_mem - PRUSS memory range identifiers
+ */
+enum pruss_mem {
+       PRUSS_MEM_DRAM0 = 0,
+       PRUSS_MEM_DRAM1,
+       PRUSS_MEM_SHRD_RAM2,
+       PRUSS_MEM_MAX,
+};
+
+/**
+ * struct pruss_mem_region - PRUSS memory region structure
+ * @va: kernel virtual address of the PRUSS memory region
+ * @pa: physical (bus) address of the PRUSS memory region
+ * @size: size of the PRUSS memory region
+ */
+struct pruss_mem_region {
+       void __iomem *va;
+       phys_addr_t pa;
+       size_t size;
+};
+
+/**
+ * struct pruss - PRUSS parent structure
+ * @dev: pruss device pointer
+ * @cfg_base: base iomap for CFG region
+ * @cfg_regmap: regmap for config region
+ * @mem_regions: data for each of the PRUSS memory regions
+ * @core_clk_mux: clk handle for PRUSS CORE_CLK_MUX
+ * @iep_clk_mux: clk handle for PRUSS IEP_CLK_MUX
+ */
+struct pruss {
+       struct device *dev;
+       void __iomem *cfg_base;
+       struct regmap *cfg_regmap;
+       struct pruss_mem_region mem_regions[PRUSS_MEM_MAX];
+       struct clk *core_clk_mux;
+       struct clk *iep_clk_mux;
+};
+
+#endif /* _PRUSS_DRIVER_H_ */
index 1c31f26..f7bbea3 100644 (file)
@@ -299,7 +299,7 @@ static inline void geni_se_setup_m_cmd(struct geni_se *se, u32 cmd, u32 params)
        u32 m_cmd;
 
        m_cmd = (cmd << M_OPCODE_SHFT) | (params & M_PARAMS_MSK);
-       writel_relaxed(m_cmd, se->base + SE_GENI_M_CMD0);
+       writel(m_cmd, se->base + SE_GENI_M_CMD0);
 }
 
 /**
@@ -319,7 +319,7 @@ static inline void geni_se_setup_s_cmd(struct geni_se *se, u32 cmd, u32 params)
        s_cmd &= ~(S_OPCODE_MSK | S_PARAMS_MSK);
        s_cmd |= (cmd << S_OPCODE_SHFT);
        s_cmd |= (params & S_PARAMS_MSK);
-       writel_relaxed(s_cmd, se->base + SE_GENI_S_CMD0);
+       writel(s_cmd, se->base + SE_GENI_S_CMD0);
 }
 
 /**
index 7e5dd7d..9cd312a 100644 (file)
@@ -279,12 +279,12 @@ struct scmi_notify_ops {
 struct scmi_handle {
        struct device *dev;
        struct scmi_revision_info *version;
-       struct scmi_perf_ops *perf_ops;
-       struct scmi_clk_ops *clk_ops;
-       struct scmi_power_ops *power_ops;
-       struct scmi_sensor_ops *sensor_ops;
-       struct scmi_reset_ops *reset_ops;
-       struct scmi_notify_ops *notify_ops;
+       const struct scmi_perf_ops *perf_ops;
+       const struct scmi_clk_ops *clk_ops;
+       const struct scmi_power_ops *power_ops;
+       const struct scmi_sensor_ops *sensor_ops;
+       const struct scmi_reset_ops *reset_ops;
+       const struct scmi_notify_ops *notify_ops;
        /* for protocol internal use */
        void *perf_priv;
        void *clk_priv;
@@ -292,6 +292,7 @@ struct scmi_handle {
        void *sensor_priv;
        void *reset_priv;
        void *notify_priv;
+       void *system_priv;
 };
 
 enum scmi_std_protocol {
@@ -304,6 +305,15 @@ enum scmi_std_protocol {
        SCMI_PROTOCOL_RESET = 0x16,
 };
 
+enum scmi_system_events {
+       SCMI_SYSTEM_SHUTDOWN,
+       SCMI_SYSTEM_COLDRESET,
+       SCMI_SYSTEM_WARMRESET,
+       SCMI_SYSTEM_POWERUP,
+       SCMI_SYSTEM_SUSPEND,
+       SCMI_SYSTEM_MAX
+};
+
 struct scmi_device {
        u32 id;
        u8 protocol_id;
@@ -335,7 +345,7 @@ struct scmi_driver {
 
 #define to_scmi_driver(d) container_of(d, struct scmi_driver, driver)
 
-#ifdef CONFIG_ARM_SCMI_PROTOCOL
+#if IS_REACHABLE(CONFIG_ARM_SCMI_PROTOCOL)
 int scmi_driver_register(struct scmi_driver *driver,
                         struct module *owner, const char *mod_name);
 void scmi_driver_unregister(struct scmi_driver *driver);
@@ -378,6 +388,7 @@ enum scmi_notification_events {
        SCMI_EVENT_SENSOR_TRIP_POINT_EVENT = 0x0,
        SCMI_EVENT_RESET_ISSUED = 0x0,
        SCMI_EVENT_BASE_ERROR_EVENT = 0x0,
+       SCMI_EVENT_SYSTEM_POWER_STATE_NOTIFIER = 0x0,
 };
 
 struct scmi_power_state_changed_report {
@@ -387,6 +398,13 @@ struct scmi_power_state_changed_report {
        unsigned int    power_state;
 };
 
+struct scmi_system_power_state_notifier_report {
+       ktime_t         timestamp;
+       unsigned int    agent_id;
+       unsigned int    flags;
+       unsigned int    system_state;
+};
+
 struct scmi_perf_limits_report {
        ktime_t         timestamp;
        unsigned int    agent_id;
index 2249eca..960704d 100644 (file)
@@ -12,6 +12,8 @@
 #include <linux/timer.h>
 
 #define CMDQ_NO_TIMEOUT                0xffffffffu
+#define CMDQ_ADDR_HIGH(addr)   ((u32)(((addr) >> 16) & GENMASK(31, 0)))
+#define CMDQ_ADDR_LOW(addr)    ((u16)(addr) | BIT(1))
 
 struct cmdq_pkt;
 
@@ -102,14 +104,90 @@ int cmdq_pkt_write(struct cmdq_pkt *pkt, u8 subsys, u16 offset, u32 value);
 int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u8 subsys,
                        u16 offset, u32 value, u32 mask);
 
+/*
+ * cmdq_pkt_read_s() - append read_s command to the CMDQ packet
+ * @pkt:       the CMDQ packet
+ * @high_addr_reg_idx: internal register ID which contains high address of pa
+ * @addr_low:  low address of pa
+ * @reg_idx:   the CMDQ internal register ID to cache read data
+ *
+ * Return: 0 for success; else the error code is returned
+ */
+int cmdq_pkt_read_s(struct cmdq_pkt *pkt, u16 high_addr_reg_idx, u16 addr_low,
+                   u16 reg_idx);
+
+/**
+ * cmdq_pkt_write_s() - append write_s command to the CMDQ packet
+ * @pkt:       the CMDQ packet
+ * @high_addr_reg_idx: internal register ID which contains high address of pa
+ * @addr_low:  low address of pa
+ * @src_reg_idx:       the CMDQ internal register ID which cache source value
+ *
+ * Return: 0 for success; else the error code is returned
+ *
+ * Support write value to physical address without subsys. Use CMDQ_ADDR_HIGH()
+ * to get high address and call cmdq_pkt_assign() to assign value into internal
+ * reg. Also use CMDQ_ADDR_LOW() to get low address for addr_low parameter when
+ * call to this function.
+ */
+int cmdq_pkt_write_s(struct cmdq_pkt *pkt, u16 high_addr_reg_idx,
+                    u16 addr_low, u16 src_reg_idx);
+
+/**
+ * cmdq_pkt_write_s_mask() - append write_s with mask command to the CMDQ packet
+ * @pkt:       the CMDQ packet
+ * @high_addr_reg_idx: internal register ID which contains high address of pa
+ * @addr_low:  low address of pa
+ * @src_reg_idx:       the CMDQ internal register ID which cache source value
+ * @mask:      the specified target address mask, use U32_MAX if no need
+ *
+ * Return: 0 for success; else the error code is returned
+ *
+ * Support write value to physical address without subsys. Use CMDQ_ADDR_HIGH()
+ * to get high address and call cmdq_pkt_assign() to assign value into internal
+ * reg. Also use CMDQ_ADDR_LOW() to get low address for addr_low parameter when
+ * call to this function.
+ */
+int cmdq_pkt_write_s_mask(struct cmdq_pkt *pkt, u16 high_addr_reg_idx,
+                         u16 addr_low, u16 src_reg_idx, u32 mask);
+
+/**
+ * cmdq_pkt_write_s_value() - append write_s command to the CMDQ packet which
+ *                           write value to a physical address
+ * @pkt:       the CMDQ packet
+ * @high_addr_reg_idx: internal register ID which contains high address of pa
+ * @addr_low:  low address of pa
+ * @value:     the specified target value
+ *
+ * Return: 0 for success; else the error code is returned
+ */
+int cmdq_pkt_write_s_value(struct cmdq_pkt *pkt, u8 high_addr_reg_idx,
+                          u16 addr_low, u32 value);
+
+/**
+ * cmdq_pkt_write_s_mask_value() - append write_s command with mask to the CMDQ
+ *                                packet which write value to a physical
+ *                                address
+ * @pkt:       the CMDQ packet
+ * @high_addr_reg_idx: internal register ID which contains high address of pa
+ * @addr_low:  low address of pa
+ * @value:     the specified target value
+ * @mask:      the specified target mask
+ *
+ * Return: 0 for success; else the error code is returned
+ */
+int cmdq_pkt_write_s_mask_value(struct cmdq_pkt *pkt, u8 high_addr_reg_idx,
+                               u16 addr_low, u32 value, u32 mask);
+
 /**
  * cmdq_pkt_wfe() - append wait for event command to the CMDQ packet
  * @pkt:       the CMDQ packet
- * @event:     the desired event type to "wait and CLEAR"
+ * @event:     the desired event type to wait
+ * @clear:     clear event or not after event arrive
  *
  * Return: 0 for success; else the error code is returned
  */
-int cmdq_pkt_wfe(struct cmdq_pkt *pkt, u16 event);
+int cmdq_pkt_wfe(struct cmdq_pkt *pkt, u16 event, bool clear);
 
 /**
  * cmdq_pkt_clear_event() - append clear event command to the CMDQ packet
@@ -176,6 +254,17 @@ int cmdq_pkt_poll_mask(struct cmdq_pkt *pkt, u8 subsys,
 int cmdq_pkt_assign(struct cmdq_pkt *pkt, u16 reg_idx, u32 value);
 
 /**
+ * cmdq_pkt_jump() - Append jump command to the CMDQ packet, ask GCE
+ *                  to execute an instruction that change current thread PC to
+ *                  a physical address which should contains more instruction.
+ * @pkt:        the CMDQ packet
+ * @addr:       physical address of target instruction buffer
+ *
+ * Return: 0 for success; else the error code is returned
+ */
+int cmdq_pkt_jump(struct cmdq_pkt *pkt, dma_addr_t addr);
+
+/**
  * cmdq_pkt_finalize() - Append EOC and jump command to pkt.
  * @pkt:       the CMDQ packet
  *
index d074302..cdd049a 100644 (file)
@@ -47,6 +47,8 @@ struct tee_shm_pool;
  *              and just return with an error code. It is needed for requests
  *              that arises from TEE based kernel drivers that should be
  *              non-blocking in nature.
+ * @cap_memref_null: flag indicating if the TEE Client support shared
+ *                   memory buffer with a NULL pointer.
  */
 struct tee_context {
        struct tee_device *teedev;
@@ -54,6 +56,7 @@ struct tee_context {
        struct kref refcount;
        bool releasing;
        bool supp_nowait;
+       bool cap_memref_null;
 };
 
 struct tee_param_memref {
index cfe00e0..9f48411 100644 (file)
@@ -256,7 +256,7 @@ struct qm_dqrr_entry {
        __be32 context_b;
        struct qm_fd fd;
        u8 __reserved4[32];
-} __packed;
+} __packed __aligned(64);
 #define QM_DQRR_VERB_VBIT              0x80
 #define QM_DQRR_VERB_MASK              0x7f    /* where the verb contains; */
 #define QM_DQRR_VERB_FRAME_DEQUEUE     0x60    /* "this format" */
@@ -289,7 +289,7 @@ union qm_mr_entry {
                __be32 tag;
                struct qm_fd fd;
                u8 __reserved1[32];
-       } __packed ern;
+       } __packed __aligned(64) ern;
        struct {
                u8 verb;
                u8 fqs;         /* Frame Queue Status */
index 1097fec..c702bd2 100644 (file)
@@ -14,6 +14,7 @@
 #define TEGRA210       0x21
 #define TEGRA186       0x18
 #define TEGRA194       0x19
+#define TEGRA234       0x23
 
 #define TEGRA_FUSE_SKU_CALIB_0 0xf0
 #define TEGRA30_FUSE_SATA_CALIB        0x124
@@ -23,6 +24,8 @@
 
 u32 tegra_read_chipid(void);
 u8 tegra_get_chip_id(void);
+u8 tegra_get_platform(void);
+bool tegra_is_silicon(void);
 
 enum tegra_revision {
        TEGRA_REVISION_UNKNOWN = 0,
index b619f37..d67cadf 100644 (file)
@@ -51,6 +51,9 @@
 #define TEE_GEN_CAP_GP         (1 << 0)/* GlobalPlatform compliant TEE */
 #define TEE_GEN_CAP_PRIVILEGED (1 << 1)/* Privileged device (for supplicant) */
 #define TEE_GEN_CAP_REG_MEM    (1 << 2)/* Supports registering shared memory */
+#define TEE_GEN_CAP_MEMREF_NULL        (1 << 3)/* NULL MemRef support */
+
+#define TEE_MEMREF_NULL                (__u64)(-1) /* NULL MemRef Buffer */
 
 /*
  * TEE Implementation ID
@@ -200,6 +203,16 @@ struct tee_ioctl_buf_data {
  * a part of a shared memory by specifying an offset (@a) and size (@b) of
  * the object. To supply the entire shared memory object set the offset
  * (@a) to 0 and size (@b) to the previously returned size of the object.
+ *
+ * A client may need to present a NULL pointer in the argument
+ * passed to a trusted application in the TEE.
+ * This is also a requirement in GlobalPlatform Client API v1.0c
+ * (section 3.2.5 memory references), which can be found at
+ * http://www.globalplatform.org/specificationsdevice.asp
+ *
+ * If a NULL pointer is passed to a TA in the TEE, the (@c)
+ * IOCTL parameters value must be set to TEE_MEMREF_NULL indicating a NULL
+ * memory reference.
  */
 struct tee_ioctl_param {
        __u64 attr;