Skip to contentSkip to conversation

iommu: add qcom_iommu for early "B" family devices (v2)

PATCH In review Rob Clark 6 participants 16 messages Mar 14, 2017 – Mar 31, 2017 3 messages not in the archive

Subsystems (4)
lore
Share & tools
lore

Rob Clark

author
#0 lore raw

cover iommu: add qcom_iommu for early "B" family devices (v2)

An iommu driver for Qualcomm "B" family devices which do not completely implement the ARM SMMU spec. These devices have context-bank register layout that is similar to ARM SMMU, but no global register space (or at least not one that is accessible).

There are a couple vaguely unrelated patches to add venus and gpu dt nodes, so that we have something to wire up the iommu to.

These patches apply on top of some in-flight patches to support IOMMU probe deferral. You can find full branch on top of linux-next here:

git://people.freedesktop.org/~robclark/linux next-20170307-db410c-qcom-smmu-3-venus

or github if you prefer:

https://github.com/freedreno/kernel-msm/commits/next-20170307-db410c-qcom-smmu-3-venus

Compared to previous patchset, there have been some (mostly binding related) cleanups. Also fixed some other-config related build issues that kbuild robot spotted.

Rob Clark (6):
firmware/qcom: add qcom_scm_restore_sec_cfg()
Docs: dt: document qcom iommu bindings
iommu: arm-smmu: split out register defines
iommu: add qcom_iommu
ARM64: DT: add gpu for msm8916
ARM64: DT: add iommu for msm8916

Stanimir Varbanov (3):
firmware: qcom_scm: add two scm calls for iommu secure page table
iommu: qcom: initialize secure page table
ARM64: DT: add video codec devicetree node

 .../devicetree/bindings/iommu/qcom,iommu.txt       | 113 +++
 arch/arm64/boot/dts/qcom/msm8916.dtsi              | 108 +++
 drivers/firmware/qcom_scm-32.c                     |  18 +
 drivers/firmware/qcom_scm-64.c                     |  58 ++
 drivers/firmware/qcom_scm.c                        |  18 +
 drivers/firmware/qcom_scm.h                        |  11 +
 drivers/iommu/Kconfig                              |  10 +
 drivers/iommu/Makefile                             |   1 +
 drivers/iommu/arm-smmu-regs.h                      | 227 ++++++
 drivers/iommu/arm-smmu.c                           | 200 +----
 drivers/iommu/qcom_iommu.c                         | 882 +++++++++++++++++++++
 include/linux/qcom_scm.h                           |   6 +
 12 files changed, 1453 insertions(+), 199 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/iommu/qcom,iommu.txt
 create mode 100644 drivers/iommu/arm-smmu-regs.h
 create mode 100644 drivers/iommu/qcom_iommu.c
Signature · 1 line
2.9.3

A message that is not in the archive (sent off-list or not yet received): 20170314151811.17234-1-robdclark-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org

author
#2 lore raw

PATCH 1/9 firmware/qcom: add qcom_scm_restore_sec_cfg()

---
 drivers/firmware/qcom_scm-32.c |  6 ++++++
 drivers/firmware/qcom_scm-64.c | 16 ++++++++++++++++
 drivers/firmware/qcom_scm.c    |  6 ++++++
 drivers/firmware/qcom_scm.h    |  5 +++++
 include/linux/qcom_scm.h       |  2 ++
 5 files changed, 35 insertions(+)
drivers/firmware/qcom_scm-32.c +6 -0
index 8ad226c..722e65a 100644
@@ -578,3 +578,9 @@ int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id)
 
 	return ret ? : le32_to_cpu(scm_ret);
 }
+
+int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id,
+			       u32 spare)
+{
+	return -ENODEV;
+}
drivers/firmware/qcom_scm-64.c +16 -0
index c933259..550e3a3 100644
@@ -381,3 +381,19 @@ int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id)
 
 	return ret ? : res.a1;
 }
+
+int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id, u32 spare)
+{
+	struct qcom_scm_desc desc = {0};
+	struct arm_smccc_res res;
+	int ret;
+
+	desc.args[0] = device_id;
+	desc.args[1] = spare;
+	desc.arginfo = QCOM_SCM_ARGS(2);
+
+	ret = qcom_scm_call(dev, QCOM_SCM_SVC_MP, QCOM_SCM_RESTORE_SEC_CFG,
+			    &desc, &res);
+
+	return ret ? : res.a1;
+}
drivers/firmware/qcom_scm.c +6 -0
index d987bcc..ae1f473 100644
@@ -315,6 +315,12 @@ static const struct reset_control_ops qcom_scm_pas_reset_ops = {
 	.deassert = qcom_scm_pas_reset_deassert,
 };
 
+int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare)
+{
+	return __qcom_scm_restore_sec_cfg(__scm->dev, device_id, spare);
+}
+EXPORT_SYMBOL(qcom_scm_restore_sec_cfg);
+
 /**
  * qcom_scm_is_available() - Checks if SCM is available
  */
drivers/firmware/qcom_scm.h +5 -0
index 6a0f154..31fc732 100644
@@ -85,4 +85,9 @@ static inline int qcom_scm_remap_error(int err)
 	return -EINVAL;
 }
 
+#define QCOM_SCM_SVC_MP			0xc
+#define QCOM_SCM_RESTORE_SEC_CFG	2
+extern int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id,
+				      u32 spare);
+
 #endif
include/linux/qcom_scm.h +2 -0
index d32f6f1..22017f5d 100644
@@ -40,6 +40,7 @@ extern int qcom_scm_pas_shutdown(u32 peripheral);
 extern void qcom_scm_cpu_power_down(u32 flags);
 extern u32 qcom_scm_get_version(void);
 extern int qcom_scm_set_remote_state(u32 state, u32 id);
+extern int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare);
 #else
 static inline
 int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus)
@@ -67,5 +68,6 @@ static inline void qcom_scm_cpu_power_down(u32 flags) {}
 static inline u32 qcom_scm_get_version(void) { return 0; }
 static inline u32
 qcom_scm_set_remote_state(u32 state,u32 id) { return -ENODEV; }
+static inline int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare) { return -ENODEV; }
 #endif
 #endif
Signature · 1 line
2.9.3
author
#3 lore raw

PATCH 2/9 firmware: qcom_scm: add two scm calls for iommu secure page table

In reply to a message not in the archive

From: Stanimir Varbanov <[email protected]>

Those two new SCM calls are needed from qcom-iommu driver in order to initialize secure iommu page table.

---
 drivers/firmware/qcom_scm-32.c | 12 ++++++++++++
 drivers/firmware/qcom_scm-64.c | 42 ++++++++++++++++++++++++++++++++++++++++++
 drivers/firmware/qcom_scm.c    | 12 ++++++++++++
 drivers/firmware/qcom_scm.h    |  6 ++++++
 include/linux/qcom_scm.h       |  4 ++++
 5 files changed, 76 insertions(+)
drivers/firmware/qcom_scm-32.c +12 -0
index 722e65a..93e3b96 100644
@@ -584,3 +584,15 @@ int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id,
 {
 	return -ENODEV;
 }
+
+int __qcom_scm_iommu_secure_ptbl_size(struct device *dev, u32 spare,
+				      size_t *size)
+{
+	return -ENODEV;
+}
+
+int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr, u32 size,
+				      u32 spare)
+{
+	return -ENODEV;
+}
drivers/firmware/qcom_scm-64.c +42 -0

45 lines not on this page · raw message

drivers/firmware/qcom_scm.c +12 -0
index ae1f473..bb16510 100644
@@ -321,6 +321,18 @@ int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare)
 }
 EXPORT_SYMBOL(qcom_scm_restore_sec_cfg);
 
+int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size)
+{
+	return __qcom_scm_iommu_secure_ptbl_size(__scm->dev, spare, size);
+}
+EXPORT_SYMBOL(qcom_scm_iommu_secure_ptbl_size);
+
+int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare)
+{
+	return __qcom_scm_iommu_secure_ptbl_init(__scm->dev, addr, size, spare);
+}
+EXPORT_SYMBOL(qcom_scm_iommu_secure_ptbl_init);
+
 /**
  * qcom_scm_is_available() - Checks if SCM is available
  */
drivers/firmware/qcom_scm.h +6 -0
index 31fc732..9bea691 100644
@@ -89,5 +89,11 @@ static inline int qcom_scm_remap_error(int err)
 #define QCOM_SCM_RESTORE_SEC_CFG	2
 extern int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id,
 				      u32 spare);
+#define QCOM_SCM_IOMMU_SECURE_PTBL_SIZE	3
+#define QCOM_SCM_IOMMU_SECURE_PTBL_INIT	4
+extern int __qcom_scm_iommu_secure_ptbl_size(struct device *dev, u32 spare,
+					     size_t *size);
+extern int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr,
+					     u32 size, u32 spare);
 
 #endif
include/linux/qcom_scm.h +4 -0
index 22017f5d..e538047 100644
@@ -41,6 +41,8 @@ extern void qcom_scm_cpu_power_down(u32 flags);
 extern u32 qcom_scm_get_version(void);
 extern int qcom_scm_set_remote_state(u32 state, u32 id);
 extern int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare);
+extern int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size);
+extern int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare);
 #else
 static inline
 int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus)
@@ -69,5 +71,7 @@ static inline u32 qcom_scm_get_version(void) { return 0; }
 static inline u32
 qcom_scm_set_remote_state(u32 state,u32 id) { return -ENODEV; }
 static inline int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare) { return -ENODEV; }
+static inline int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size) { return -ENODEV; }
+static inline int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare) { return -ENODEV; }
 #endif
 #endif
Signature · 1 line
2.9.3
author
#4 lore raw

PATCH 3/9 Docs: dt: document qcom iommu bindings

In reply to a message not in the archive
---
 .../devicetree/bindings/iommu/qcom,iommu.txt       | 113 +++++++++++++++++++++
 1 file changed, 113 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iommu/qcom,iommu.txt
Documentation/devicetree/bindings/iommu/qcom,iommu.txt new file +113 -0
new file mode 100644
index 0000000..fd5b7fa
@@ -0,0 +1,113 @@
+* QCOM IOMMU v1 Implementation
+
+Qualcomm "B" family devices which are not compatible with arm-smmu have
+a similar looking IOMMU but without access to the global register space,
+and optionally requiring additional configuration to route context irqs
+to non-secure vs secure interrupt line.
+
+** Required properties:
+
+- compatible       : Should be one of:
+
+                        "qcom,msm8916-iommu"
+
+- clock-names      : Should be a pair of "iface" (required for IOMMUs
+                     register group access) and "bus" (required for
+                     the IOMMUs underlying bus access).
+- clocks           : Phandles for respective clocks described by
+                     clock-names.
+- #address-cells   : must be 1.
+- #size-cells      : must be 1.
+- #iommu-cells     : Must be 1.
+- ranges           : Base address and size of the iommu context banks.
+- qcom,iommu-secure-id  : secure-id.
+
+- List of sub-nodes, one per translation context bank.  Each sub-node
+  has the following required properties:
+
+  - compatible     : Should be one of:
+        - "qcom,msm-iommu-v1-ns"  : non-secure context bank
+        - "qcom,msm-iommu-v1-sec" : secure context bank
+  - reg            : Base address and size of context bank within the iommu
+  - interrupts     : The context fault irq.
+
+** Optional properties:
+
+- reg              : Base address and size of the SMMU local base, should
+                     be only specified if the iommu requires configuration
+                     for routing of context bank irq's to secure vs non-
+                     secure lines.  (Ie. if the iommu contains secure
+                     context banks)
+
+
+** Examples:
+
+	apps_iommu: iommu@1e20000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		#iommu-cells = <1>;
+		compatible = "qcom,msm8916-iommu", "qcom,msm-iommu-v1";
+		ranges = <0 0x1e20000 0x40000>;
+		reg = <0x1ef0000 0x3000>;
+		clocks = <&gcc GCC_SMMU_CFG_CLK>,
+			 <&gcc GCC_APSS_TCU_CLK>;
+		clock-names = "iface", "bus";
+		qcom,iommu-secure-id = <17>;
+
+		// mdp_0:
+		iommu-ctx@4000 {
+			compatible = "qcom,msm-iommu-v1-ns";
+			reg = <0x4000 0x1000>;
+			interrupts = <GIC_SPI 70 0>;
+		};
+
+		// venus_ns:
+		iommu-ctx@5000 {
+			compatible = "qcom,msm-iommu-v1-sec";
+			reg = <0x5000 0x1000>;
+			interrupts = <GIC_SPI 70 0>;
+		};
+	};
+
+	gpu_iommu: iommu@1f08000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		#iommu-cells = <1>;
+		compatible = "qcom,msm8916-iommu", "qcom,msm-iommu-v1";
+		ranges = <0 0x1f08000 0x10000>;
+		clocks = <&gcc GCC_SMMU_CFG_CLK>,
+			 <&gcc GCC_GFX_TCU_CLK>;
+		clock-names = "iface", "bus";
+		qcom,iommu-secure-id = <18>;
+
+		// gfx3d_user:
+		iommu-ctx@1f09000 {
+			compatible = "qcom,msm-iommu-v1-ns";
+			reg = <0x1000 0x1000>;
+			interrupts = <GIC_SPI 241 0>;
+		};
+
+		// gfx3d_priv:
+		iommu-ctx@1f0a000 {
+			compatible = "qcom,msm-iommu-v1-ns";
+			reg = <0x2000 0x1000>;
+			interrupts = <GIC_SPI 242 0>;
+		};
+	};
+
+	...
+
+	venus: video-codec@1d00000 {
+		...
+		iommus = <&apps_iommu 5>;
+	};
+
+	mdp: mdp@1a01000 {
+		...
+		iommus = <&apps_iommu 4>;
+	};
+
+	gpu@01c00000 {
+		...
+		iommus = <&gpu_iommu 1>, <&gpu_iommu 2>;
+	};
Signature · 1 line
2.9.3

A message that is not in the archive (sent off-list or not yet received): 20170314151811.17234-4-robdclark-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org

#6 lore raw

Re: [PATCH 3/9] Docs: dt: document qcom iommu bindings

Quoted 52 lines · Rob Clark
---
 .../devicetree/bindings/iommu/qcom,iommu.txt       | 113 +++++++++++++++++++++
 1 file changed, 113 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iommu/qcom,iommu.txt
Documentation/devicetree/bindings/iommu/qcom,iommu.txt new file +39 -0
new file mode 100644
index 0000000..fd5b7fa
@@ -0,0 +1,113 @@
+* QCOM IOMMU v1 Implementation
+
+Qualcomm "B" family devices which are not compatible with arm-smmu have
+a similar looking IOMMU but without access to the global register space,
+and optionally requiring additional configuration to route context irqs
+to non-secure vs secure interrupt line.
+
+** Required properties:
+
+- compatible       : Should be one of:
+
+                        "qcom,msm8916-iommu"
+
+- clock-names      : Should be a pair of "iface" (required for IOMMUs
+                     register group access) and "bus" (required for
+                     the IOMMUs underlying bus access).
+- clocks           : Phandles for respective clocks described by
+                     clock-names.
+- #address-cells   : must be 1.
+- #size-cells      : must be 1.
+- #iommu-cells     : Must be 1.
+- ranges           : Base address and size of the iommu context banks.
+- qcom,iommu-secure-id  : secure-id.
+
+- List of sub-nodes, one per translation context bank.  Each sub-node
+  has the following required properties:
+
+  - compatible     : Should be one of:
+        - "qcom,msm-iommu-v1-ns"  : non-secure context bank
+        - "qcom,msm-iommu-v1-sec" : secure context bank
+  - reg            : Base address and size of context bank within the iommu
+  - interrupts     : The context fault irq.
+
+** Optional properties:
+
+- reg              : Base address and size of the SMMU local base, should
+                     be only specified if the iommu requires configuration
+                     for routing of context bank irq's to secure vs non-
+                     secure lines.  (Ie. if the iommu contains secure

Documentation/devicetree/bindings/iommu/qcom,iommu.txt line 49

Quoted 10 lines
Documentation/devicetree/bindings/iommu/qcom,iommu.txt new file +10 -0
+                     context banks)
+
+
+** Examples:
+
+	apps_iommu: iommu@1e20000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		#iommu-cells = <1>;
+		compatible = "qcom,msm8916-iommu", "qcom,msm-iommu-v1";

You didn't document the fallback above. Maybe just drop it if only a few chips have this iommu.

Documentation/devicetree/bindings/iommu/qcom,iommu.txt line 51

Quoted 2 lines
Documentation/devicetree/bindings/iommu/qcom,iommu.txt new file +2 -0
+		ranges = <0 0x1e20000 0x40000>;
+		reg = <0x1ef0000 0x3000>;

When you have both reg and ranges, use reg value for the unit-address.

Quoted 23 lines
Documentation/devicetree/bindings/iommu/qcom,iommu.txt new file +23 -0
+		clocks = <&gcc GCC_SMMU_CFG_CLK>,
+			 <&gcc GCC_APSS_TCU_CLK>;
+		clock-names = "iface", "bus";
+		qcom,iommu-secure-id = <17>;
+
+		// mdp_0:
+		iommu-ctx@4000 {
+			compatible = "qcom,msm-iommu-v1-ns";
+			reg = <0x4000 0x1000>;
+			interrupts = <GIC_SPI 70 0>;
+		};
+
+		// venus_ns:
+		iommu-ctx@5000 {
+			compatible = "qcom,msm-iommu-v1-sec";
+			reg = <0x5000 0x1000>;
+			interrupts = <GIC_SPI 70 0>;
+		};
+	};
+
+	gpu_iommu: iommu@1f08000 {
+		#address-cells = <1>;
+		#size-cells = <1>;

Documentation/devicetree/bindings/iommu/qcom,iommu.txt line 84

Quoted 10 lines
Documentation/devicetree/bindings/iommu/qcom,iommu.txt new file +10 -0
+		#iommu-cells = <1>;
+		compatible = "qcom,msm8916-iommu", "qcom,msm-iommu-v1";
+		ranges = <0 0x1f08000 0x10000>;
+		clocks = <&gcc GCC_SMMU_CFG_CLK>,
+			 <&gcc GCC_GFX_TCU_CLK>;
+		clock-names = "iface", "bus";
+		qcom,iommu-secure-id = <18>;
+
+		// gfx3d_user:
+		iommu-ctx@1f09000 {

iommu-ctx@1000

Documentation/devicetree/bindings/iommu/qcom,iommu.txt line 91

Quoted 7 lines
Documentation/devicetree/bindings/iommu/qcom,iommu.txt new file +7 -0
+			compatible = "qcom,msm-iommu-v1-ns";
+			reg = <0x1000 0x1000>;
+			interrupts = <GIC_SPI 241 0>;
+		};
+
+		// gfx3d_priv:
+		iommu-ctx@1f0a000 {

iommu-ctx@2000

Quoted 29 lines
Documentation/devicetree/bindings/iommu/qcom,iommu.txt new file +22 -0
+			compatible = "qcom,msm-iommu-v1-ns";
+			reg = <0x2000 0x1000>;
+			interrupts = <GIC_SPI 242 0>;
+		};
+	};
+
+	...
+
+	venus: video-codec@1d00000 {
+		...
+		iommus = <&apps_iommu 5>;
+	};
+
+	mdp: mdp@1a01000 {
+		...
+		iommus = <&apps_iommu 4>;
+	};
+
+	gpu@01c00000 {
+		...
+		iommus = <&gpu_iommu 1>, <&gpu_iommu 2>;
+	};
Signature · 6 lines
2.9.3

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

author
#7 lore raw

Re: [PATCH 3/9] Docs: dt: document qcom iommu bindings

Quoted 58 lines · Rob Herring
Quoted 57 lines · Rob Clark
---
 .../devicetree/bindings/iommu/qcom,iommu.txt       | 113 +++++++++++++++++++++
 1 file changed, 113 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iommu/qcom,iommu.txt
Documentation/devicetree/bindings/iommu/qcom,iommu.txt new file +44 -0
new file mode 100644
index 0000000..fd5b7fa
@@ -0,0 +1,113 @@
+* QCOM IOMMU v1 Implementation
+
+Qualcomm "B" family devices which are not compatible with arm-smmu have
+a similar looking IOMMU but without access to the global register space,
+and optionally requiring additional configuration to route context irqs
+to non-secure vs secure interrupt line.
+
+** Required properties:
+
+- compatible       : Should be one of:
+
+                        "qcom,msm8916-iommu"
+
+- clock-names      : Should be a pair of "iface" (required for IOMMUs
+                     register group access) and "bus" (required for
+                     the IOMMUs underlying bus access).
+- clocks           : Phandles for respective clocks described by
+                     clock-names.
+- #address-cells   : must be 1.
+- #size-cells      : must be 1.
+- #iommu-cells     : Must be 1.
+- ranges           : Base address and size of the iommu context banks.
+- qcom,iommu-secure-id  : secure-id.
+
+- List of sub-nodes, one per translation context bank.  Each sub-node
+  has the following required properties:
+
+  - compatible     : Should be one of:
+        - "qcom,msm-iommu-v1-ns"  : non-secure context bank
+        - "qcom,msm-iommu-v1-sec" : secure context bank
+  - reg            : Base address and size of context bank within the iommu
+  - interrupts     : The context fault irq.
+
+** Optional properties:
+
+- reg              : Base address and size of the SMMU local base, should
+                     be only specified if the iommu requires configuration
+                     for routing of context bank irq's to secure vs non-
+                     secure lines.  (Ie. if the iommu contains secure
+                     context banks)
+
+
+** Examples:
+
Quoted 8 lines

Documentation/devicetree/bindings/iommu/qcom,iommu.txt line 49

Quoted 5 lines
Documentation/devicetree/bindings/iommu/qcom,iommu.txt new file +5 -0
+     apps_iommu: iommu@1e20000 {
+             #address-cells = <1>;
+             #size-cells = <1>;
+             #iommu-cells = <1>;
+             compatible = "qcom,msm8916-iommu", "qcom,msm-iommu-v1";

You didn't document the fallback above. Maybe just drop it if only a few chips have this iommu.

not completely sure I understand what you want..

I think more than a few chips.. I suspect it is more like everything after the last "a" family devices (snapdragon 600?) and before 820.. (well, more or less at least a few years worth of devices, stuff that seems likely to be able to run an upstream kernel would be 800, 805, 808, 810.. and I guess there are some cut down 6xx and 4xx variants of those)

I guess qcom_iommu wouldn't care about all the various 32b devices (since they aren't going to use 64b page tables).. 808/810, I'm not 100% sure about..

Quoted 4 lines

Documentation/devicetree/bindings/iommu/qcom,iommu.txt line 51

Quoted 2 lines
Documentation/devicetree/bindings/iommu/qcom,iommu.txt new file +2 -0
+             ranges = <0 0x1e20000 0x40000>;
+             reg = <0x1ef0000 0x3000>;

When you have both reg and ranges, use reg value for the unit-address.

whoops, I thought I fixed that

Quoted 27 lines
Quoted 27 lines
Documentation/devicetree/bindings/iommu/qcom,iommu.txt new file +27 -0
+             clocks = <&gcc GCC_SMMU_CFG_CLK>,
+                      <&gcc GCC_APSS_TCU_CLK>;
+             clock-names = "iface", "bus";
+             qcom,iommu-secure-id = <17>;
+
+             // mdp_0:
+             iommu-ctx@4000 {
+                     compatible = "qcom,msm-iommu-v1-ns";
+                     reg = <0x4000 0x1000>;
+                     interrupts = <GIC_SPI 70 0>;
+             };
+
+             // venus_ns:
+             iommu-ctx@5000 {
+                     compatible = "qcom,msm-iommu-v1-sec";
+                     reg = <0x5000 0x1000>;
+                     interrupts = <GIC_SPI 70 0>;
+             };
+     };
+
+     gpu_iommu: iommu@1f08000 {
+             #address-cells = <1>;
+             #size-cells = <1>;
+             #iommu-cells = <1>;
+             compatible = "qcom,msm8916-iommu", "qcom,msm-iommu-v1";
+             ranges = <0 0x1f08000 0x10000>;
+             clocks = <&gcc GCC_SMMU_CFG_CLK>,
Quoted 8 lines

Documentation/devicetree/bindings/iommu/qcom,iommu.txt line 84

Quoted 6 lines
Documentation/devicetree/bindings/iommu/qcom,iommu.txt new file +6 -0
+                      <&gcc GCC_GFX_TCU_CLK>;
+             clock-names = "iface", "bus";
+             qcom,iommu-secure-id = <18>;
+
+             // gfx3d_user:
+             iommu-ctx@1f09000 {

iommu-ctx@1000

will fix, thx

BR,
-R

Quoted 39 lines

Documentation/devicetree/bindings/iommu/qcom,iommu.txt line 91

Quoted 7 lines
Documentation/devicetree/bindings/iommu/qcom,iommu.txt new file +7 -0
+                     compatible = "qcom,msm-iommu-v1-ns";
+                     reg = <0x1000 0x1000>;
+                     interrupts = <GIC_SPI 241 0>;
+             };
+
+             // gfx3d_priv:
+             iommu-ctx@1f0a000 {

iommu-ctx@2000

Quoted 29 lines
Documentation/devicetree/bindings/iommu/qcom,iommu.txt new file +22 -1
+                     compatible = "qcom,msm-iommu-v1-ns";
+                     reg = <0x2000 0x1000>;
+                     interrupts = <GIC_SPI 242 0>;
+             };
+     };
+
+     ...
+
+     venus: video-codec@1d00000 {
+             ...
+             iommus = <&apps_iommu 5>;
+     };
+
+     mdp: mdp@1a01000 {
+             ...
+             iommus = <&apps_iommu 4>;
+     };
+
+     gpu@01c00000 {
+             ...
+             iommus = <&gpu_iommu 1>, <&gpu_iommu 2>;
+     };
--

2.9.3

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

maintainer
#8 lore raw

Re: [PATCH 3/9] Docs: dt: document qcom iommu bindings

Quoted 68 lines · Rob Clark
Quoted 58 lines · Rob Herring
Quoted 57 lines · Rob Clark
---
 .../devicetree/bindings/iommu/qcom,iommu.txt       | 113 +++++++++++++++++++++
 1 file changed, 113 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iommu/qcom,iommu.txt
Documentation/devicetree/bindings/iommu/qcom,iommu.txt new file +44 -0
new file mode 100644
index 0000000..fd5b7fa
@@ -0,0 +1,113 @@
+* QCOM IOMMU v1 Implementation
+
+Qualcomm "B" family devices which are not compatible with arm-smmu have
+a similar looking IOMMU but without access to the global register space,
+and optionally requiring additional configuration to route context irqs
+to non-secure vs secure interrupt line.
+
+** Required properties:
+
+- compatible       : Should be one of:
+
+                        "qcom,msm8916-iommu"
+
+- clock-names      : Should be a pair of "iface" (required for IOMMUs
+                     register group access) and "bus" (required for
+                     the IOMMUs underlying bus access).
+- clocks           : Phandles for respective clocks described by
+                     clock-names.
+- #address-cells   : must be 1.
+- #size-cells      : must be 1.
+- #iommu-cells     : Must be 1.
+- ranges           : Base address and size of the iommu context banks.
+- qcom,iommu-secure-id  : secure-id.
+
+- List of sub-nodes, one per translation context bank.  Each sub-node
+  has the following required properties:
+
+  - compatible     : Should be one of:
+        - "qcom,msm-iommu-v1-ns"  : non-secure context bank
+        - "qcom,msm-iommu-v1-sec" : secure context bank
+  - reg            : Base address and size of context bank within the iommu
+  - interrupts     : The context fault irq.
+
+** Optional properties:
+
+- reg              : Base address and size of the SMMU local base, should
+                     be only specified if the iommu requires configuration
+                     for routing of context bank irq's to secure vs non-
+                     secure lines.  (Ie. if the iommu contains secure
+                     context banks)
+
+
+** Examples:
+
Quoted 8 lines

Documentation/devicetree/bindings/iommu/qcom,iommu.txt line 49

Quoted 5 lines
Documentation/devicetree/bindings/iommu/qcom,iommu.txt new file +5 -0
+     apps_iommu: iommu@1e20000 {
+             #address-cells = <1>;
+             #size-cells = <1>;
+             #iommu-cells = <1>;
+             compatible = "qcom,msm8916-iommu", "qcom,msm-iommu-v1";

You didn't document the fallback above. Maybe just drop it if only a few chips have this iommu.

Quoted 8 lines

not completely sure I understand what you want..

I think more than a few chips.. I suspect it is more like everything after the last "a" family devices (snapdragon 600?) and before 820.. (well, more or less at least a few years worth of devices, stuff that seems likely to be able to run an upstream kernel would be 800, 805, 808, 810.. and I guess there are some cut down 6xx and 4xx variants of those)

Okay, then you just need to list qcom,msm-iommu-v1 above. Something like 'followed by "qcom,msm-iommu-v1"' at the end of the list of compatibles.

Rob

author
#9 lore raw

PATCH 4/9 iommu: arm-smmu: split out register defines

In reply to a message not in the archive

I want to re-use some of these for qcom_iommu, which has (roughly) the same context-bank registers.

---
 drivers/iommu/arm-smmu-regs.h | 225 ++++++++++++++++++++++++++++++++++++++++++
 drivers/iommu/arm-smmu.c      | 200 +------------------------------------
 2 files changed, 226 insertions(+), 199 deletions(-)
 create mode 100644 drivers/iommu/arm-smmu-regs.h
drivers/iommu/arm-smmu-regs.h new file +225 -0
new file mode 100644
index 0000000..632240f
@@ -0,0 +1,225 @@
+/*
+ * IOMMU API for ARM architected SMMU implementations.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) 2013 ARM Limited
+ *
+ * Author: Will Deacon <[email protected]>
+ */
+
+#ifndef _ARM_SMMU_REGS_H
+#define _ARM_SMMU_REGS_H
+
+
+/* Configuration registers */
+#define ARM_SMMU_GR0_sCR0		0x0
+#define sCR0_CLIENTPD			(1 << 0)
+#define sCR0_GFRE			(1 << 1)
+#define sCR0_GFIE			(1 << 2)
+#define sCR0_EXIDENABLE			(1 << 3)
+#define sCR0_GCFGFRE			(1 << 4)
+#define sCR0_GCFGFIE			(1 << 5)
+#define sCR0_USFCFG			(1 << 10)
+#define sCR0_VMIDPNE			(1 << 11)
+#define sCR0_PTM			(1 << 12)
+#define sCR0_FB				(1 << 13)
+#define sCR0_VMID16EN			(1 << 31)
+#define sCR0_BSU_SHIFT			14
+#define sCR0_BSU_MASK			0x3
+
+/* Auxiliary Configuration register */
+#define ARM_SMMU_GR0_sACR		0x10
+
+/* Identification registers */
+#define ARM_SMMU_GR0_ID0		0x20
+#define ARM_SMMU_GR0_ID1		0x24
+#define ARM_SMMU_GR0_ID2		0x28
+#define ARM_SMMU_GR0_ID3		0x2c
+#define ARM_SMMU_GR0_ID4		0x30
+#define ARM_SMMU_GR0_ID5		0x34
+#define ARM_SMMU_GR0_ID6		0x38
+#define ARM_SMMU_GR0_ID7		0x3c
+#define ARM_SMMU_GR0_sGFSR		0x48
+#define ARM_SMMU_GR0_sGFSYNR0		0x50
+#define ARM_SMMU_GR0_sGFSYNR1		0x54
+#define ARM_SMMU_GR0_sGFSYNR2		0x58
+
+#define ID0_S1TS			(1 << 30)
+#define ID0_S2TS			(1 << 29)
+#define ID0_NTS				(1 << 28)
+#define ID0_SMS				(1 << 27)
+#define ID0_ATOSNS			(1 << 26)
+#define ID0_PTFS_NO_AARCH32		(1 << 25)
+#define ID0_PTFS_NO_AARCH32S		(1 << 24)
+#define ID0_CTTW			(1 << 14)
+#define ID0_NUMIRPT_SHIFT		16
+#define ID0_NUMIRPT_MASK		0xff
+#define ID0_NUMSIDB_SHIFT		9
+#define ID0_NUMSIDB_MASK		0xf
+#define ID0_EXIDS			(1 << 8)
+#define ID0_NUMSMRG_SHIFT		0
+#define ID0_NUMSMRG_MASK		0xff
+
+#define ID1_PAGESIZE			(1 << 31)
+#define ID1_NUMPAGENDXB_SHIFT		28
+#define ID1_NUMPAGENDXB_MASK		7
+#define ID1_NUMS2CB_SHIFT		16
+#define ID1_NUMS2CB_MASK		0xff
+#define ID1_NUMCB_SHIFT			0
+#define ID1_NUMCB_MASK			0xff
+
+#define ID2_OAS_SHIFT			4
+#define ID2_OAS_MASK			0xf
+#define ID2_IAS_SHIFT			0
+#define ID2_IAS_MASK			0xf
+#define ID2_UBS_SHIFT			8
+#define ID2_UBS_MASK			0xf
+#define ID2_PTFS_4K			(1 << 12)
+#define ID2_PTFS_16K			(1 << 13)
+#define ID2_PTFS_64K			(1 << 14)
+#define ID2_VMID16			(1 << 15)
+
+#define ID7_MAJOR_SHIFT			4
+#define ID7_MAJOR_MASK			0xf
+
+/* Global TLB invalidation */
+#define ARM_SMMU_GR0_TLBIVMID		0x64
+#define ARM_SMMU_GR0_TLBIALLNSNH	0x68
+#define ARM_SMMU_GR0_TLBIALLH		0x6c
+#define ARM_SMMU_GR0_sTLBGSYNC		0x70
+#define ARM_SMMU_GR0_sTLBGSTATUS	0x74
+#define sTLBGSTATUS_GSACTIVE		(1 << 0)
+#define TLB_LOOP_TIMEOUT		1000000	/* 1s! */
+
+/* Stream mapping registers */
+#define ARM_SMMU_GR0_SMR(n)		(0x800 + ((n) << 2))
+#define SMR_VALID			(1 << 31)
+#define SMR_MASK_SHIFT			16
+#define SMR_ID_SHIFT			0
+
+#define ARM_SMMU_GR0_S2CR(n)		(0xc00 + ((n) << 2))
+#define S2CR_CBNDX_SHIFT		0
+#define S2CR_CBNDX_MASK			0xff
+#define S2CR_EXIDVALID			(1 << 10)
+#define S2CR_TYPE_SHIFT			16
+#define S2CR_TYPE_MASK			0x3
+enum arm_smmu_s2cr_type {
+	S2CR_TYPE_TRANS,
+	S2CR_TYPE_BYPASS,
+	S2CR_TYPE_FAULT,
+};
+
+#define S2CR_PRIVCFG_SHIFT		24
+#define S2CR_PRIVCFG_MASK		0x3
+enum arm_smmu_s2cr_privcfg {
+	S2CR_PRIVCFG_DEFAULT,
+	S2CR_PRIVCFG_DIPAN,
+	S2CR_PRIVCFG_UNPRIV,
+	S2CR_PRIVCFG_PRIV,
+};
+
+/* Context bank attribute registers */
+#define ARM_SMMU_GR1_CBAR(n)		(0x0 + ((n) << 2))
+#define CBAR_VMID_SHIFT			0
+#define CBAR_VMID_MASK			0xff
+#define CBAR_S1_BPSHCFG_SHIFT		8
+#define CBAR_S1_BPSHCFG_MASK		3
+#define CBAR_S1_BPSHCFG_NSH		3
+#define CBAR_S1_MEMATTR_SHIFT		12
+#define CBAR_S1_MEMATTR_MASK		0xf
+#define CBAR_S1_MEMATTR_WB		0xf
+#define CBAR_TYPE_SHIFT			16
+#define CBAR_TYPE_MASK			0x3
+#define CBAR_TYPE_S2_TRANS		(0 << CBAR_TYPE_SHIFT)
+#define CBAR_TYPE_S1_TRANS_S2_BYPASS	(1 << CBAR_TYPE_SHIFT)
+#define CBAR_TYPE_S1_TRANS_S2_FAULT	(2 << CBAR_TYPE_SHIFT)
+#define CBAR_TYPE_S1_TRANS_S2_TRANS	(3 << CBAR_TYPE_SHIFT)
+#define CBAR_IRPTNDX_SHIFT		24
+#define CBAR_IRPTNDX_MASK		0xff
+
+#define ARM_SMMU_GR1_CBA2R(n)		(0x800 + ((n) << 2))
+#define CBA2R_RW64_32BIT		(0 << 0)
+#define CBA2R_RW64_64BIT		(1 << 0)
+#define CBA2R_VMID_SHIFT		16
+#define CBA2R_VMID_MASK			0xffff
+
+#define ARM_SMMU_CB_SCTLR		0x0
+#define ARM_SMMU_CB_ACTLR		0x4
+#define ARM_SMMU_CB_RESUME		0x8
+#define ARM_SMMU_CB_TTBCR2		0x10
+#define ARM_SMMU_CB_TTBR0		0x20
+#define ARM_SMMU_CB_TTBR1		0x28
+#define ARM_SMMU_CB_TTBCR		0x30
+#define ARM_SMMU_CB_CONTEXTIDR		0x34
+#define ARM_SMMU_CB_S1_MAIR0		0x38
+#define ARM_SMMU_CB_S1_MAIR1		0x3c
+#define ARM_SMMU_CB_PAR			0x50
+#define ARM_SMMU_CB_FSR			0x58
+#define ARM_SMMU_CB_FAR			0x60
+#define ARM_SMMU_CB_FSYNR0		0x68
+#define ARM_SMMU_CB_S1_TLBIVA		0x600
+#define ARM_SMMU_CB_S1_TLBIASID		0x610
+#define ARM_SMMU_CB_S1_TLBIVAL		0x620
+#define ARM_SMMU_CB_S2_TLBIIPAS2	0x630
+#define ARM_SMMU_CB_S2_TLBIIPAS2L	0x638
+#define ARM_SMMU_CB_ATS1PR		0x800
+#define ARM_SMMU_CB_ATSR		0x8f0
+
+#define SCTLR_S1_ASIDPNE		(1 << 12)
+#define SCTLR_CFCFG			(1 << 7)
+#define SCTLR_CFIE			(1 << 6)
+#define SCTLR_CFRE			(1 << 5)
+#define SCTLR_E				(1 << 4)
+#define SCTLR_AFE			(1 << 2)
+#define SCTLR_TRE			(1 << 1)
+#define SCTLR_M				(1 << 0)
+
+#define ARM_MMU500_ACTLR_CPRE		(1 << 1)
+
+#define ARM_MMU500_ACR_CACHE_LOCK	(1 << 26)
+#define ARM_MMU500_ACR_SMTNMB_TLBEN	(1 << 8)
+
+#define CB_PAR_F			(1 << 0)
+
+#define ATSR_ACTIVE			(1 << 0)
+
+#define RESUME_RETRY			(0 << 0)
+#define RESUME_TERMINATE		(1 << 0)
+
+#define TTBCR2_SEP_SHIFT		15
+#define TTBCR2_SEP_UPSTREAM		(0x7 << TTBCR2_SEP_SHIFT)
+#define TTBCR2_AS			(1 << 4)
+
+#define TTBRn_ASID_SHIFT		48
+
+#define FSR_MULTI			(1 << 31)
+#define FSR_SS				(1 << 30)
+#define FSR_UUT				(1 << 8)
+#define FSR_ASF				(1 << 7)
+#define FSR_TLBLKF			(1 << 6)
+#define FSR_TLBMCF			(1 << 5)
+#define FSR_EF				(1 << 4)
+#define FSR_PF				(1 << 3)
+#define FSR_AFF				(1 << 2)
+#define FSR_TF				(1 << 1)
+
+#define FSR_IGN				(FSR_AFF | FSR_ASF | \
+					 FSR_TLBMCF | FSR_TLBLKF)
+#define FSR_FAULT			(FSR_MULTI | FSR_SS | FSR_UUT | \
+					 FSR_EF | FSR_PF | FSR_TF | FSR_IGN)
+
+#define FSYNR0_WNR			(1 << 4)
+
+#endif /* _ARM_SMMU_REGS_H */
drivers/iommu/arm-smmu.c +1 -199

216 lines not on this page · raw message

Signature · 1 line
2.9.3
author
#10 lore raw

PATCH 5/9 iommu: add qcom_iommu

In reply to a message not in the archive

An iommu driver for Qualcomm "B" family devices which do not completely implement the ARM SMMU spec. These devices have context-bank register layout that is similar to ARM SMMU, but no global register space (or at least not one that is accessible).

---
 drivers/iommu/Kconfig         |  10 +
 drivers/iommu/Makefile        |   1 +
 drivers/iommu/arm-smmu-regs.h |   2 +
 drivers/iommu/qcom_iommu.c    | 818 ++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 831 insertions(+)
 create mode 100644 drivers/iommu/qcom_iommu.c
drivers/iommu/Kconfig +10 -0
index 37e204f..400a404 100644
@@ -359,4 +359,14 @@ config MTK_IOMMU_V1
 
 	  if unsure, say N here.
 
+config QCOM_IOMMU
+	bool "Qualcomm IOMMU Support"
+	depends on ARM || ARM64
+	depends on ARCH_QCOM || COMPILE_TEST
+	select IOMMU_API
+	select IOMMU_IO_PGTABLE_LPAE
+	select ARM_DMA_USE_IOMMU
+	help
+	  Support for IOMMU on certain Qualcomm SoCs.
+
 endif # IOMMU_SUPPORT
drivers/iommu/Makefile +1 -0
index 195f7b9..b910aea 100644
@@ -27,3 +27,4 @@ obj-$(CONFIG_TEGRA_IOMMU_SMMU) += tegra-smmu.o
 obj-$(CONFIG_EXYNOS_IOMMU) += exynos-iommu.o
 obj-$(CONFIG_FSL_PAMU) += fsl_pamu.o fsl_pamu_domain.o
 obj-$(CONFIG_S390_IOMMU) += s390-iommu.o
+obj-$(CONFIG_QCOM_IOMMU) += qcom_iommu.o
drivers/iommu/arm-smmu-regs.h +2 -0
index 632240f..e643164 100644
@@ -174,6 +174,8 @@ enum arm_smmu_s2cr_privcfg {
 #define ARM_SMMU_CB_S1_TLBIVAL		0x620
 #define ARM_SMMU_CB_S2_TLBIIPAS2	0x630
 #define ARM_SMMU_CB_S2_TLBIIPAS2L	0x638
+#define ARM_SMMU_CB_TLBSYNC		0x7f0
+#define ARM_SMMU_CB_TLBSTATUS		0x7f4
 #define ARM_SMMU_CB_ATS1PR		0x800
 #define ARM_SMMU_CB_ATSR		0x8f0
 
drivers/iommu/qcom_iommu.c new file +818 -0

818 lines not on this page · raw message

Signature · 1 line
2.9.3

A message that is not in the archive (sent off-list or not yet received): 20170314151811.17234-6-robdclark-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org

#12 lore raw

Re: [PATCH 5/9] iommu: add qcom_iommu

Hi,

Quoted 14 lines · Rob Clark

An iommu driver for Qualcomm "B" family devices which do not completely implement the ARM SMMU spec. These devices have context-bank register layout that is similar to ARM SMMU, but no global register space (or at least not one that is accessible).

---
 drivers/iommu/Kconfig         |  10 +
 drivers/iommu/Makefile        |   1 +
 drivers/iommu/arm-smmu-regs.h |   2 +
 drivers/iommu/qcom_iommu.c    | 818 ++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 831 insertions(+)
 create mode 100644 drivers/iommu/qcom_iommu.c

<snip>

drivers/iommu/qcom_iommu.c line 477

Quoted 4 lines
drivers/iommu/qcom_iommu.c new file +4 -0
+
+static int qcom_iommu_add_device(struct device *dev)
+{
+	struct qcom_iommu_dev *qcom_iommu = __to_iommu(dev->iommu_fwspec);

__to_iommu() has a WARN_ON() that gets triggered here for all devices on the platform bus that aren't backed by our iommu. We should return -ENODEV for all of them without throwing a warning.

drivers/iommu/qcom_iommu.c line 480

Quoted 3 lines
drivers/iommu/qcom_iommu.c new file +3 -0
+	struct iommu_group *group;
+	struct device_link *link;
+

We could do something like:

if (fwspec && fwspec->ops == &qcom_iommu_ops)

	qcom_iommu = __to_iommu(fwspec);
else
	qcom_iommu = NULL;

Thanks,
Archit

Quoted 339 lines
drivers/iommu/qcom_iommu.c new file +338 -0
+	if (!qcom_iommu)
+		return -ENODEV;
+
+	/*
+	 * Establish the link between iommu and master, so that the
+	 * iommu gets runtime enabled/disabled as per the master's
+	 * needs.
+	 */
+	link = device_link_add(dev, qcom_iommu->dev, DL_FLAG_PM_RUNTIME);
+	if (!link) {
+		dev_err(qcom_iommu->dev, "Unable to create device link between %s and %s\n",
+			dev_name(qcom_iommu->dev), dev_name(dev));
+		return -ENODEV;
+	}
+
+	group = iommu_group_get_for_dev(dev);
+	if (IS_ERR_OR_NULL(group))
+		return PTR_ERR_OR_ZERO(group);
+
+	iommu_group_put(group);
+	iommu_device_link(&qcom_iommu->iommu, dev);
+
+	return 0;
+}
+
+static void qcom_iommu_remove_device(struct device *dev)
+{
+	struct qcom_iommu_dev *qcom_iommu = __to_iommu(dev->iommu_fwspec);
+
+	if (!qcom_iommu)
+		return;
+
+	iommu_group_remove_device(dev);
+	iommu_device_unlink(&qcom_iommu->iommu, dev);
+	iommu_fwspec_free(dev);
+}
+
+static struct iommu_group *qcom_iommu_device_group(struct device *dev)
+{
+	struct iommu_fwspec *fwspec = dev->iommu_fwspec;
+	struct iommu_group *group = NULL;
+	unsigned i;
+
+	for (i = 0; i < fwspec->num_ids; i++) {
+		struct qcom_iommu_ctx *ctx = __to_ctx(fwspec, fwspec->ids[i]);
+
+		if (group && ctx->group && group != ctx->group)
+			return ERR_PTR(-EINVAL);
+
+		group = ctx->group;
+	}
+
+	if (group)
+		return iommu_group_ref_get(group);
+
+	group = generic_device_group(dev);
+
+	for (i = 0; i < fwspec->num_ids; i++) {
+		struct qcom_iommu_ctx *ctx = __to_ctx(fwspec, fwspec->ids[i]);
+		ctx->group = iommu_group_ref_get(group);
+	}
+
+	return group;
+}
+
+static int qcom_iommu_of_xlate(struct device *dev, struct of_phandle_args *args)
+{
+	struct platform_device *iommu_pdev;
+
+	if (args->args_count != 1) {
+		dev_err(dev, "incorrect number of iommu params found for %s "
+			"(found %d, expected 1)\n",
+			args->np->full_name, args->args_count);
+		return -EINVAL;
+	}
+
+	if (!dev->iommu_fwspec->iommu_priv) {
+		iommu_pdev = of_find_device_by_node(args->np);
+		if (WARN_ON(!iommu_pdev))
+			return -EINVAL;
+
+		dev->iommu_fwspec->iommu_priv = platform_get_drvdata(iommu_pdev);
+	}
+
+	return iommu_fwspec_add_ids(dev, &args->args[0], 1);
+}
+
+static const struct iommu_ops qcom_iommu_ops = {
+	.capable	= qcom_iommu_capable,
+	.domain_alloc	= qcom_iommu_domain_alloc,
+	.domain_free	= qcom_iommu_domain_free,
+	.attach_dev	= qcom_iommu_attach_dev,
+	.detach_dev	= qcom_iommu_detach_dev,
+	.map		= qcom_iommu_map,
+	.unmap		= qcom_iommu_unmap,
+	.map_sg		= default_iommu_map_sg,
+	.iova_to_phys	= qcom_iommu_iova_to_phys,
+	.add_device	= qcom_iommu_add_device,
+	.remove_device	= qcom_iommu_remove_device,
+	.device_group	= qcom_iommu_device_group,
+	.of_xlate	= qcom_iommu_of_xlate,
+	.pgsize_bitmap	= SZ_4K | SZ_64K | SZ_1M | SZ_16M,
+};
+
+static int qcom_iommu_enable_clocks(struct qcom_iommu_dev *qcom_iommu)
+{
+	int ret;
+
+	ret = clk_prepare_enable(qcom_iommu->iface_clk);
+	if (ret) {
+		dev_err(qcom_iommu->dev, "Couldn't enable iface_clk\n");
+		return ret;
+	}
+
+	ret = clk_prepare_enable(qcom_iommu->bus_clk);
+	if (ret) {
+		dev_err(qcom_iommu->dev, "Couldn't enable bus_clk\n");
+		clk_disable_unprepare(qcom_iommu->iface_clk);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void qcom_iommu_disable_clocks(struct qcom_iommu_dev *qcom_iommu)
+{
+	clk_disable_unprepare(qcom_iommu->bus_clk);
+	clk_disable_unprepare(qcom_iommu->iface_clk);
+}
+
+static int qcom_iommu_ctx_probe(struct platform_device *pdev)
+{
+	struct qcom_iommu_ctx *ctx;
+	struct device *dev = &pdev->dev;
+	struct qcom_iommu_dev *qcom_iommu = dev_get_drvdata(dev->parent);
+	struct resource *res;
+	int ret;
+	u32 reg;
+
+	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	ctx->dev = dev;
+	platform_set_drvdata(pdev, ctx);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	ctx->base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(ctx->base))
+		return PTR_ERR(ctx->base);
+
+	ctx->irq = platform_get_irq(pdev, 0);
+	if (ctx->irq < 0) {
+		dev_err(dev, "failed to get irq\n");
+		return -ENODEV;
+	}
+
+	ret = devm_request_irq(dev, ctx->irq,
+			       qcom_iommu_fault,
+			       IRQF_SHARED,
+			       "qcom-iommu-fault",
+			       ctx);
+	if (ret) {
+		dev_err(dev, "failed to request IRQ %u\n", ctx->irq);
+		return ret;
+	}
+
+	/* read the "reg" property directly to get the relative address
+	 * of the context bank, and calculate the asid from that:
+	 */
+	if (of_property_read_u32_index(dev->of_node, "reg", 0, &reg)) {
+		dev_err(dev, "missing reg property\n");
+		return -ENODEV;
+	}
+
+	ctx->asid = reg / 0x1000;      /* context banks are 0x1000 apart */
+
+	dev_dbg(dev, "found asid %u\n", ctx->asid);
+
+	list_add_tail(&ctx->node, &qcom_iommu->context_list);
+
+	return 0;
+}
+
+static int qcom_iommu_ctx_remove(struct platform_device *pdev)
+{
+	struct qcom_iommu_ctx *ctx = platform_get_drvdata(pdev);
+
+	iommu_group_put(ctx->group);
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static const struct of_device_id ctx_of_match[] = {
+	{ .compatible = "qcom,msm-iommu-v1-ns" },
+	{ .compatible = "qcom,msm-iommu-v1-sec" },
+	{ /* sentinel */ }
+};
+
+static struct platform_driver qcom_iommu_ctx_driver = {
+	.driver	= {
+		.name		= "qcom-iommu-ctx",
+		.of_match_table	= of_match_ptr(ctx_of_match),
+	},
+	.probe	= qcom_iommu_ctx_probe,
+	.remove = qcom_iommu_ctx_remove,
+};
+module_platform_driver(qcom_iommu_ctx_driver);
+
+static int qcom_iommu_device_probe(struct platform_device *pdev)
+{
+	struct qcom_iommu_dev *qcom_iommu;
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	int ret;
+
+	qcom_iommu = devm_kzalloc(dev, sizeof(*qcom_iommu), GFP_KERNEL);
+	if (!qcom_iommu)
+		return -ENOMEM;
+	qcom_iommu->dev = dev;
+
+	INIT_LIST_HEAD(&qcom_iommu->context_list);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res)
+		qcom_iommu->local_base = devm_ioremap_resource(dev, res);
+
+	qcom_iommu->iface_clk = devm_clk_get(dev, "iface");
+	if (IS_ERR(qcom_iommu->iface_clk)) {
+		dev_err(dev, "failed to get iface clock\n");
+		return PTR_ERR(qcom_iommu->iface_clk);
+	}
+
+	qcom_iommu->bus_clk = devm_clk_get(dev, "bus");
+	if (IS_ERR(qcom_iommu->bus_clk)) {
+		dev_err(dev, "failed to get bus clock\n");
+		return PTR_ERR(qcom_iommu->bus_clk);
+	}
+
+	if (of_property_read_u32(dev->of_node, "qcom,iommu-secure-id",
+				 &qcom_iommu->sec_id)) {
+		dev_err(dev, "missing qcom,iommu-secure-id property\n");
+		return -ENODEV;
+	}
+
+	platform_set_drvdata(pdev, qcom_iommu);
+
+	/* register context bank devices, which are child nodes: */
+	ret = of_platform_populate(dev->of_node, ctx_of_match, NULL, dev);
+	if (ret) {
+		dev_err(dev, "Failed to populate iommu contexts\n");
+		return ret;
+	}
+
+	ret = iommu_device_sysfs_add(&qcom_iommu->iommu, dev, NULL,
+				     "smmu.%pa", &res->start);
+	if (ret) {
+		dev_err(dev, "Failed to register iommu in sysfs\n");
+		return ret;
+	}
+
+	iommu_device_set_ops(&qcom_iommu->iommu, &qcom_iommu_ops);
+	iommu_device_set_fwnode(&qcom_iommu->iommu, dev->fwnode);
+
+	ret = iommu_device_register(&qcom_iommu->iommu);
+	if (ret) {
+		dev_err(dev, "Failed to register iommu\n");
+		return ret;
+	}
+
+	pm_runtime_enable(dev);
+	bus_set_iommu(&platform_bus_type, &qcom_iommu_ops);
+
+	if (qcom_iommu->local_base) {
+		pm_runtime_get_sync(dev);
+		writel_relaxed(0xffffffff, qcom_iommu->local_base + SMMU_INTR_SEL_NS);
+		pm_runtime_put_sync(dev);
+	}
+
+	return 0;
+}
+
+static int qcom_iommu_device_remove(struct platform_device *pdev)
+{
+	pm_runtime_force_suspend(&pdev->dev);
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int qcom_iommu_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct qcom_iommu_dev *qcom_iommu = platform_get_drvdata(pdev);
+
+	return qcom_iommu_enable_clocks(qcom_iommu);
+}
+
+static int qcom_iommu_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct qcom_iommu_dev *qcom_iommu = platform_get_drvdata(pdev);
+
+	qcom_iommu_disable_clocks(qcom_iommu);
+
+	return 0;
+}
+#endif
+
+static const struct dev_pm_ops qcom_iommu_pm_ops = {
+	SET_RUNTIME_PM_OPS(qcom_iommu_suspend, qcom_iommu_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				pm_runtime_force_resume)
+};
+
+static const struct of_device_id qcom_iommu_of_match[] = {
+	{ .compatible = "qcom,msm-iommu-v1" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, qcom_iommu_of_match);
+
+static struct platform_driver qcom_iommu_driver = {
+	.driver	= {
+		.name		= "qcom-iommu",
+		.of_match_table	= of_match_ptr(qcom_iommu_of_match),
+		.pm		= &qcom_iommu_pm_ops,
+	},
+	.probe	= qcom_iommu_device_probe,
+	.remove	= qcom_iommu_device_remove,
+};
+module_platform_driver(qcom_iommu_driver);
+
+IOMMU_OF_DECLARE(qcom_iommu_dev, "qcom,msm-iommu-v1", NULL);
+
+MODULE_DESCRIPTION("IOMMU API for QCOM IOMMU v1 implementations");
+MODULE_LICENSE("GPL v2");
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
#13 lore raw

Re: [PATCH 5/9] iommu: add qcom_iommu

Quoted 38 lines · Archit Taneja

Hi,

Quoted 16 lines · Rob Clark

An iommu driver for Qualcomm "B" family devices which do not completely implement the ARM SMMU spec. These devices have context-bank register layout that is similar to ARM SMMU, but no global register space (or at least not one that is accessible).

---
 drivers/iommu/Kconfig         |  10 +
 drivers/iommu/Makefile        |   1 +
 drivers/iommu/arm-smmu-regs.h |   2 +
 drivers/iommu/qcom_iommu.c    | 818
++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 831 insertions(+)
 create mode 100644 drivers/iommu/qcom_iommu.c

<snip>

drivers/iommu/qcom_iommu.c line 477

Quoted 4 lines
drivers/iommu/qcom_iommu.c new file +4 -0
+
+static int qcom_iommu_add_device(struct device *dev)
+{
+       struct qcom_iommu_dev *qcom_iommu = __to_iommu(dev->iommu_fwspec);

__to_iommu() has a WARN_ON() that gets triggered here for all devices on the platform bus that aren't backed by our iommu. We should return -ENODEV for all of them without throwing a warning.

drivers/iommu/qcom_iommu.c line 480

Quoted 3 lines
drivers/iommu/qcom_iommu.c new file +3 -0
+       struct iommu_group *group;
+       struct device_link *link;
+
Quoted 6 lines

We could do something like:

if (fwspec && fwspec->ops == &qcom_iommu_ops)

        qcom_iommu = __to_iommu(fwspec);
else
        qcom_iommu = NULL;

thanks.. I wonder how I wasn't hitting that?

I'll incorporate this (plus small dt bindings doc update) into next version.. probably won't have time to send until the weekend or next week

BR,
-R

Quoted 355 lines

Thanks,
Archit

Quoted 337 lines
drivers/iommu/qcom_iommu.c new file +11 -0
+       if (!qcom_iommu)
+               return -ENODEV;
+
+       /*
+        * Establish the link between iommu and master, so that the
+        * iommu gets runtime enabled/disabled as per the master's
+        * needs.
+        */
+       link = device_link_add(dev, qcom_iommu->dev, DL_FLAG_PM_RUNTIME);
+       if (!link) {
+               dev_err(qcom_iommu->dev, "Unable to create device link

between %s and %s\n",

drivers/iommu/qcom_iommu.c new file +34 -0
+                       dev_name(qcom_iommu->dev), dev_name(dev));
+               return -ENODEV;
+       }
+
+       group = iommu_group_get_for_dev(dev);
+       if (IS_ERR_OR_NULL(group))
+               return PTR_ERR_OR_ZERO(group);
+
+       iommu_group_put(group);
+       iommu_device_link(&qcom_iommu->iommu, dev);
+
+       return 0;
+}
+
+static void qcom_iommu_remove_device(struct device *dev)
+{
+       struct qcom_iommu_dev *qcom_iommu = __to_iommu(dev->iommu_fwspec);
+
+       if (!qcom_iommu)
+               return;
+
+       iommu_group_remove_device(dev);
+       iommu_device_unlink(&qcom_iommu->iommu, dev);
+       iommu_fwspec_free(dev);
+}
+
+static struct iommu_group *qcom_iommu_device_group(struct device *dev)
+{
+       struct iommu_fwspec *fwspec = dev->iommu_fwspec;
+       struct iommu_group *group = NULL;
+       unsigned i;
+
+       for (i = 0; i < fwspec->num_ids; i++) {
+               struct qcom_iommu_ctx *ctx = __to_ctx(fwspec,

fwspec->ids[i]);

drivers/iommu/qcom_iommu.c new file +14 -0
+
+               if (group && ctx->group && group != ctx->group)
+                       return ERR_PTR(-EINVAL);
+
+               group = ctx->group;
+       }
+
+       if (group)
+               return iommu_group_ref_get(group);
+
+       group = generic_device_group(dev);
+
+       for (i = 0; i < fwspec->num_ids; i++) {
+               struct qcom_iommu_ctx *ctx = __to_ctx(fwspec,

fwspec->ids[i]);

drivers/iommu/qcom_iommu.c new file +7 -0
+               ctx->group = iommu_group_ref_get(group);
+       }
+
+       return group;
+}
+
+static int qcom_iommu_of_xlate(struct device *dev, struct of_phandle_args

*args)

drivers/iommu/qcom_iommu.c new file +5 -0
+{
+       struct platform_device *iommu_pdev;
+
+       if (args->args_count != 1) {
+               dev_err(dev, "incorrect number of iommu params found for

%s "

drivers/iommu/qcom_iommu.c new file +11 -0
+                       "(found %d, expected 1)\n",
+                       args->np->full_name, args->args_count);
+               return -EINVAL;
+       }
+
+       if (!dev->iommu_fwspec->iommu_priv) {
+               iommu_pdev = of_find_device_by_node(args->np);
+               if (WARN_ON(!iommu_pdev))
+                       return -EINVAL;
+
+               dev->iommu_fwspec->iommu_priv =

platform_get_drvdata(iommu_pdev);

drivers/iommu/qcom_iommu.c new file +94 -0
+       }
+
+       return iommu_fwspec_add_ids(dev, &args->args[0], 1);
+}
+
+static const struct iommu_ops qcom_iommu_ops = {
+       .capable        = qcom_iommu_capable,
+       .domain_alloc   = qcom_iommu_domain_alloc,
+       .domain_free    = qcom_iommu_domain_free,
+       .attach_dev     = qcom_iommu_attach_dev,
+       .detach_dev     = qcom_iommu_detach_dev,
+       .map            = qcom_iommu_map,
+       .unmap          = qcom_iommu_unmap,
+       .map_sg         = default_iommu_map_sg,
+       .iova_to_phys   = qcom_iommu_iova_to_phys,
+       .add_device     = qcom_iommu_add_device,
+       .remove_device  = qcom_iommu_remove_device,
+       .device_group   = qcom_iommu_device_group,
+       .of_xlate       = qcom_iommu_of_xlate,
+       .pgsize_bitmap  = SZ_4K | SZ_64K | SZ_1M | SZ_16M,
+};
+
+static int qcom_iommu_enable_clocks(struct qcom_iommu_dev *qcom_iommu)
+{
+       int ret;
+
+       ret = clk_prepare_enable(qcom_iommu->iface_clk);
+       if (ret) {
+               dev_err(qcom_iommu->dev, "Couldn't enable iface_clk\n");
+               return ret;
+       }
+
+       ret = clk_prepare_enable(qcom_iommu->bus_clk);
+       if (ret) {
+               dev_err(qcom_iommu->dev, "Couldn't enable bus_clk\n");
+               clk_disable_unprepare(qcom_iommu->iface_clk);
+               return ret;
+       }
+
+       return 0;
+}
+
+static void qcom_iommu_disable_clocks(struct qcom_iommu_dev *qcom_iommu)
+{
+       clk_disable_unprepare(qcom_iommu->bus_clk);
+       clk_disable_unprepare(qcom_iommu->iface_clk);
+}
+
+static int qcom_iommu_ctx_probe(struct platform_device *pdev)
+{
+       struct qcom_iommu_ctx *ctx;
+       struct device *dev = &pdev->dev;
+       struct qcom_iommu_dev *qcom_iommu = dev_get_drvdata(dev->parent);
+       struct resource *res;
+       int ret;
+       u32 reg;
+
+       ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+       if (!ctx)
+               return -ENOMEM;
+
+       ctx->dev = dev;
+       platform_set_drvdata(pdev, ctx);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       ctx->base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(ctx->base))
+               return PTR_ERR(ctx->base);
+
+       ctx->irq = platform_get_irq(pdev, 0);
+       if (ctx->irq < 0) {
+               dev_err(dev, "failed to get irq\n");
+               return -ENODEV;
+       }
+
+       ret = devm_request_irq(dev, ctx->irq,
+                              qcom_iommu_fault,
+                              IRQF_SHARED,
+                              "qcom-iommu-fault",
+                              ctx);
+       if (ret) {
+               dev_err(dev, "failed to request IRQ %u\n", ctx->irq);
+               return ret;
+       }
+
+       /* read the "reg" property directly to get the relative address
+        * of the context bank, and calculate the asid from that:
+        */
+       if (of_property_read_u32_index(dev->of_node, "reg", 0, &reg)) {
+               dev_err(dev, "missing reg property\n");
+               return -ENODEV;
+       }
+
+       ctx->asid = reg / 0x1000;      /* context banks are 0x1000 apart

*/

drivers/iommu/qcom_iommu.c new file +101 -0
+
+       dev_dbg(dev, "found asid %u\n", ctx->asid);
+
+       list_add_tail(&ctx->node, &qcom_iommu->context_list);
+
+       return 0;
+}
+
+static int qcom_iommu_ctx_remove(struct platform_device *pdev)
+{
+       struct qcom_iommu_ctx *ctx = platform_get_drvdata(pdev);
+
+       iommu_group_put(ctx->group);
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+static const struct of_device_id ctx_of_match[] = {
+       { .compatible = "qcom,msm-iommu-v1-ns" },
+       { .compatible = "qcom,msm-iommu-v1-sec" },
+       { /* sentinel */ }
+};
+
+static struct platform_driver qcom_iommu_ctx_driver = {
+       .driver = {
+               .name           = "qcom-iommu-ctx",
+               .of_match_table = of_match_ptr(ctx_of_match),
+       },
+       .probe  = qcom_iommu_ctx_probe,
+       .remove = qcom_iommu_ctx_remove,
+};
+module_platform_driver(qcom_iommu_ctx_driver);
+
+static int qcom_iommu_device_probe(struct platform_device *pdev)
+{
+       struct qcom_iommu_dev *qcom_iommu;
+       struct device *dev = &pdev->dev;
+       struct resource *res;
+       int ret;
+
+       qcom_iommu = devm_kzalloc(dev, sizeof(*qcom_iommu), GFP_KERNEL);
+       if (!qcom_iommu)
+               return -ENOMEM;
+       qcom_iommu->dev = dev;
+
+       INIT_LIST_HEAD(&qcom_iommu->context_list);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res)
+               qcom_iommu->local_base = devm_ioremap_resource(dev, res);
+
+       qcom_iommu->iface_clk = devm_clk_get(dev, "iface");
+       if (IS_ERR(qcom_iommu->iface_clk)) {
+               dev_err(dev, "failed to get iface clock\n");
+               return PTR_ERR(qcom_iommu->iface_clk);
+       }
+
+       qcom_iommu->bus_clk = devm_clk_get(dev, "bus");
+       if (IS_ERR(qcom_iommu->bus_clk)) {
+               dev_err(dev, "failed to get bus clock\n");
+               return PTR_ERR(qcom_iommu->bus_clk);
+       }
+
+       if (of_property_read_u32(dev->of_node, "qcom,iommu-secure-id",
+                                &qcom_iommu->sec_id)) {
+               dev_err(dev, "missing qcom,iommu-secure-id property\n");
+               return -ENODEV;
+       }
+
+       platform_set_drvdata(pdev, qcom_iommu);
+
+       /* register context bank devices, which are child nodes: */
+       ret = of_platform_populate(dev->of_node, ctx_of_match, NULL, dev);
+       if (ret) {
+               dev_err(dev, "Failed to populate iommu contexts\n");
+               return ret;
+       }
+
+       ret = iommu_device_sysfs_add(&qcom_iommu->iommu, dev, NULL,
+                                    "smmu.%pa", &res->start);
+       if (ret) {
+               dev_err(dev, "Failed to register iommu in sysfs\n");
+               return ret;
+       }
+
+       iommu_device_set_ops(&qcom_iommu->iommu, &qcom_iommu_ops);
+       iommu_device_set_fwnode(&qcom_iommu->iommu, dev->fwnode);
+
+       ret = iommu_device_register(&qcom_iommu->iommu);
+       if (ret) {
+               dev_err(dev, "Failed to register iommu\n");
+               return ret;
+       }
+
+       pm_runtime_enable(dev);
+       bus_set_iommu(&platform_bus_type, &qcom_iommu_ops);
+
+       if (qcom_iommu->local_base) {
+               pm_runtime_get_sync(dev);
+               writel_relaxed(0xffffffff, qcom_iommu->local_base +

SMMU_INTR_SEL_NS);

drivers/iommu/qcom_iommu.c new file +51 -0
+               pm_runtime_put_sync(dev);
+       }
+
+       return 0;
+}
+
+static int qcom_iommu_device_remove(struct platform_device *pdev)
+{
+       pm_runtime_force_suspend(&pdev->dev);
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int qcom_iommu_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct qcom_iommu_dev *qcom_iommu = platform_get_drvdata(pdev);
+
+       return qcom_iommu_enable_clocks(qcom_iommu);
+}
+
+static int qcom_iommu_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct qcom_iommu_dev *qcom_iommu = platform_get_drvdata(pdev);
+
+       qcom_iommu_disable_clocks(qcom_iommu);
+
+       return 0;
+}
+#endif
+
+static const struct dev_pm_ops qcom_iommu_pm_ops = {
+       SET_RUNTIME_PM_OPS(qcom_iommu_suspend, qcom_iommu_resume, NULL)
+       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+                               pm_runtime_force_resume)
+};
+
+static const struct of_device_id qcom_iommu_of_match[] = {
+       { .compatible = "qcom,msm-iommu-v1" },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, qcom_iommu_of_match);
+
+static struct platform_driver qcom_iommu_driver = {
+       .driver = {
+               .name           = "qcom-iommu",
+               .of_match_table = of_match_ptr(qcom_iommu_of_match),
+               .pm             = &qcom_iommu_pm_ops,

drivers/iommu/qcom_iommu.c line 818

Quoted 10 lines
drivers/iommu/qcom_iommu.c new file +10 -0
+       },
+       .probe  = qcom_iommu_device_probe,
+       .remove = qcom_iommu_device_remove,
+};
+module_platform_driver(qcom_iommu_driver);
+
+IOMMU_OF_DECLARE(qcom_iommu_dev, "qcom,msm-iommu-v1", NULL);
+
+MODULE_DESCRIPTION("IOMMU API for QCOM IOMMU v1 implementations");
+MODULE_LICENSE("GPL v2");

--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project

#14 lore raw

Re: [PATCH 5/9] iommu: add qcom_iommu

Quoted 39 lines · Rob Clark
Quoted 38 lines · Archit Taneja

Hi,

Quoted 16 lines · Rob Clark

An iommu driver for Qualcomm "B" family devices which do not completely implement the ARM SMMU spec. These devices have context-bank register layout that is similar to ARM SMMU, but no global register space (or at least not one that is accessible).

---
 drivers/iommu/Kconfig         |  10 +
 drivers/iommu/Makefile        |   1 +
 drivers/iommu/arm-smmu-regs.h |   2 +
 drivers/iommu/qcom_iommu.c    | 818
++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 831 insertions(+)
 create mode 100644 drivers/iommu/qcom_iommu.c

<snip>

drivers/iommu/qcom_iommu.c line 477

Quoted 4 lines
drivers/iommu/qcom_iommu.c new file +4 -0
+
+static int qcom_iommu_add_device(struct device *dev)
+{
+       struct qcom_iommu_dev *qcom_iommu = __to_iommu(dev->iommu_fwspec);

__to_iommu() has a WARN_ON() that gets triggered here for all devices on the platform bus that aren't backed by our iommu. We should return -ENODEV for all of them without throwing a warning.

Quoted 3 lines
drivers/iommu/qcom_iommu.c new file +3 -0
+       struct iommu_group *group;
+       struct device_link *link;
+
Quoted 8 lines
Quoted 6 lines

We could do something like:

if (fwspec && fwspec->ops == &qcom_iommu_ops)

        qcom_iommu = __to_iommu(fwspec);
else
        qcom_iommu = NULL;

thanks.. I wonder how I wasn't hitting that?

There's an additional commit in your branch which unintentionally avoids calling add_device() being called for all devs.

https://github.com/freedreno/kernel-msm/commit/e2444266e37a85ad5188a4511ab26cc4b0f85641

Thanks,
Archit

Quoted 368 lines
Quoted 1 line

I'll incorporate this (plus small dt bindings doc update) into next

version.. probably won't have time to send until the weekend or next week

BR,
-R

Quoted 347 lines

Thanks,
Archit

Quoted 343 lines
drivers/iommu/qcom_iommu.c new file +11 -0
+       if (!qcom_iommu)
+               return -ENODEV;
+
+       /*
+        * Establish the link between iommu and master, so that the
+        * iommu gets runtime enabled/disabled as per the master's
+        * needs.
+        */
+       link = device_link_add(dev, qcom_iommu->dev, DL_FLAG_PM_RUNTIME);
+       if (!link) {
+               dev_err(qcom_iommu->dev, "Unable to create device link

between %s and %s\n",

drivers/iommu/qcom_iommu.c new file +34 -0
+                       dev_name(qcom_iommu->dev), dev_name(dev));
+               return -ENODEV;
+       }
+
+       group = iommu_group_get_for_dev(dev);
+       if (IS_ERR_OR_NULL(group))
+               return PTR_ERR_OR_ZERO(group);
+
+       iommu_group_put(group);
+       iommu_device_link(&qcom_iommu->iommu, dev);
+
+       return 0;
+}
+
+static void qcom_iommu_remove_device(struct device *dev)
+{
+       struct qcom_iommu_dev *qcom_iommu = __to_iommu(dev->iommu_fwspec);
+
+       if (!qcom_iommu)
+               return;
+
+       iommu_group_remove_device(dev);
+       iommu_device_unlink(&qcom_iommu->iommu, dev);
+       iommu_fwspec_free(dev);
+}
+
+static struct iommu_group *qcom_iommu_device_group(struct device *dev)
+{
+       struct iommu_fwspec *fwspec = dev->iommu_fwspec;
+       struct iommu_group *group = NULL;
+       unsigned i;
+
+       for (i = 0; i < fwspec->num_ids; i++) {
+               struct qcom_iommu_ctx *ctx = __to_ctx(fwspec,

fwspec->ids[i]);

drivers/iommu/qcom_iommu.c new file +14 -0
+
+               if (group && ctx->group && group != ctx->group)
+                       return ERR_PTR(-EINVAL);
+
+               group = ctx->group;
+       }
+
+       if (group)
+               return iommu_group_ref_get(group);
+
+       group = generic_device_group(dev);
+
+       for (i = 0; i < fwspec->num_ids; i++) {
+               struct qcom_iommu_ctx *ctx = __to_ctx(fwspec,

fwspec->ids[i]);

drivers/iommu/qcom_iommu.c new file +7 -0
+               ctx->group = iommu_group_ref_get(group);
+       }
+
+       return group;
+}
+
+static int qcom_iommu_of_xlate(struct device *dev, struct of_phandle_args

*args)

drivers/iommu/qcom_iommu.c new file +5 -0
+{
+       struct platform_device *iommu_pdev;
+
+       if (args->args_count != 1) {
+               dev_err(dev, "incorrect number of iommu params found for

%s "

drivers/iommu/qcom_iommu.c new file +11 -0
+                       "(found %d, expected 1)\n",
+                       args->np->full_name, args->args_count);
+               return -EINVAL;
+       }
+
+       if (!dev->iommu_fwspec->iommu_priv) {
+               iommu_pdev = of_find_device_by_node(args->np);
+               if (WARN_ON(!iommu_pdev))
+                       return -EINVAL;
+
+               dev->iommu_fwspec->iommu_priv =

platform_get_drvdata(iommu_pdev);

drivers/iommu/qcom_iommu.c new file +94 -0
+       }
+
+       return iommu_fwspec_add_ids(dev, &args->args[0], 1);
+}
+
+static const struct iommu_ops qcom_iommu_ops = {
+       .capable        = qcom_iommu_capable,
+       .domain_alloc   = qcom_iommu_domain_alloc,
+       .domain_free    = qcom_iommu_domain_free,
+       .attach_dev     = qcom_iommu_attach_dev,
+       .detach_dev     = qcom_iommu_detach_dev,
+       .map            = qcom_iommu_map,
+       .unmap          = qcom_iommu_unmap,
+       .map_sg         = default_iommu_map_sg,
+       .iova_to_phys   = qcom_iommu_iova_to_phys,
+       .add_device     = qcom_iommu_add_device,
+       .remove_device  = qcom_iommu_remove_device,
+       .device_group   = qcom_iommu_device_group,
+       .of_xlate       = qcom_iommu_of_xlate,
+       .pgsize_bitmap  = SZ_4K | SZ_64K | SZ_1M | SZ_16M,
+};
+
+static int qcom_iommu_enable_clocks(struct qcom_iommu_dev *qcom_iommu)
+{
+       int ret;
+
+       ret = clk_prepare_enable(qcom_iommu->iface_clk);
+       if (ret) {
+               dev_err(qcom_iommu->dev, "Couldn't enable iface_clk\n");
+               return ret;
+       }
+
+       ret = clk_prepare_enable(qcom_iommu->bus_clk);
+       if (ret) {
+               dev_err(qcom_iommu->dev, "Couldn't enable bus_clk\n");
+               clk_disable_unprepare(qcom_iommu->iface_clk);
+               return ret;
+       }
+
+       return 0;
+}
+
+static void qcom_iommu_disable_clocks(struct qcom_iommu_dev *qcom_iommu)
+{
+       clk_disable_unprepare(qcom_iommu->bus_clk);
+       clk_disable_unprepare(qcom_iommu->iface_clk);
+}
+
+static int qcom_iommu_ctx_probe(struct platform_device *pdev)
+{
+       struct qcom_iommu_ctx *ctx;
+       struct device *dev = &pdev->dev;
+       struct qcom_iommu_dev *qcom_iommu = dev_get_drvdata(dev->parent);
+       struct resource *res;
+       int ret;
+       u32 reg;
+
+       ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+       if (!ctx)
+               return -ENOMEM;
+
+       ctx->dev = dev;
+       platform_set_drvdata(pdev, ctx);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       ctx->base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(ctx->base))
+               return PTR_ERR(ctx->base);
+
+       ctx->irq = platform_get_irq(pdev, 0);
+       if (ctx->irq < 0) {
+               dev_err(dev, "failed to get irq\n");
+               return -ENODEV;
+       }
+
+       ret = devm_request_irq(dev, ctx->irq,
+                              qcom_iommu_fault,
+                              IRQF_SHARED,
+                              "qcom-iommu-fault",
+                              ctx);
+       if (ret) {
+               dev_err(dev, "failed to request IRQ %u\n", ctx->irq);
+               return ret;
+       }
+
+       /* read the "reg" property directly to get the relative address
+        * of the context bank, and calculate the asid from that:
+        */
+       if (of_property_read_u32_index(dev->of_node, "reg", 0, &reg)) {
+               dev_err(dev, "missing reg property\n");
+               return -ENODEV;
+       }
+
+       ctx->asid = reg / 0x1000;      /* context banks are 0x1000 apart

*/

drivers/iommu/qcom_iommu.c new file +101 -0
+
+       dev_dbg(dev, "found asid %u\n", ctx->asid);
+
+       list_add_tail(&ctx->node, &qcom_iommu->context_list);
+
+       return 0;
+}
+
+static int qcom_iommu_ctx_remove(struct platform_device *pdev)
+{
+       struct qcom_iommu_ctx *ctx = platform_get_drvdata(pdev);
+
+       iommu_group_put(ctx->group);
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+static const struct of_device_id ctx_of_match[] = {
+       { .compatible = "qcom,msm-iommu-v1-ns" },
+       { .compatible = "qcom,msm-iommu-v1-sec" },
+       { /* sentinel */ }
+};
+
+static struct platform_driver qcom_iommu_ctx_driver = {
+       .driver = {
+               .name           = "qcom-iommu-ctx",
+               .of_match_table = of_match_ptr(ctx_of_match),
+       },
+       .probe  = qcom_iommu_ctx_probe,
+       .remove = qcom_iommu_ctx_remove,
+};
+module_platform_driver(qcom_iommu_ctx_driver);
+
+static int qcom_iommu_device_probe(struct platform_device *pdev)
+{
+       struct qcom_iommu_dev *qcom_iommu;
+       struct device *dev = &pdev->dev;
+       struct resource *res;
+       int ret;
+
+       qcom_iommu = devm_kzalloc(dev, sizeof(*qcom_iommu), GFP_KERNEL);
+       if (!qcom_iommu)
+               return -ENOMEM;
+       qcom_iommu->dev = dev;
+
+       INIT_LIST_HEAD(&qcom_iommu->context_list);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res)
+               qcom_iommu->local_base = devm_ioremap_resource(dev, res);
+
+       qcom_iommu->iface_clk = devm_clk_get(dev, "iface");
+       if (IS_ERR(qcom_iommu->iface_clk)) {
+               dev_err(dev, "failed to get iface clock\n");
+               return PTR_ERR(qcom_iommu->iface_clk);
+       }
+
+       qcom_iommu->bus_clk = devm_clk_get(dev, "bus");
+       if (IS_ERR(qcom_iommu->bus_clk)) {
+               dev_err(dev, "failed to get bus clock\n");
+               return PTR_ERR(qcom_iommu->bus_clk);
+       }
+
+       if (of_property_read_u32(dev->of_node, "qcom,iommu-secure-id",
+                                &qcom_iommu->sec_id)) {
+               dev_err(dev, "missing qcom,iommu-secure-id property\n");
+               return -ENODEV;
+       }
+
+       platform_set_drvdata(pdev, qcom_iommu);
+
+       /* register context bank devices, which are child nodes: */
+       ret = of_platform_populate(dev->of_node, ctx_of_match, NULL, dev);
+       if (ret) {
+               dev_err(dev, "Failed to populate iommu contexts\n");
+               return ret;
+       }
+
+       ret = iommu_device_sysfs_add(&qcom_iommu->iommu, dev, NULL,
+                                    "smmu.%pa", &res->start);
+       if (ret) {
+               dev_err(dev, "Failed to register iommu in sysfs\n");
+               return ret;
+       }
+
+       iommu_device_set_ops(&qcom_iommu->iommu, &qcom_iommu_ops);
+       iommu_device_set_fwnode(&qcom_iommu->iommu, dev->fwnode);
+
+       ret = iommu_device_register(&qcom_iommu->iommu);
+       if (ret) {
+               dev_err(dev, "Failed to register iommu\n");
+               return ret;
+       }
+
+       pm_runtime_enable(dev);
+       bus_set_iommu(&platform_bus_type, &qcom_iommu_ops);
+
+       if (qcom_iommu->local_base) {
+               pm_runtime_get_sync(dev);
+               writel_relaxed(0xffffffff, qcom_iommu->local_base +

SMMU_INTR_SEL_NS);

drivers/iommu/qcom_iommu.c new file +58 -0
+               pm_runtime_put_sync(dev);
+       }
+
+       return 0;
+}
+
+static int qcom_iommu_device_remove(struct platform_device *pdev)
+{
+       pm_runtime_force_suspend(&pdev->dev);
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int qcom_iommu_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct qcom_iommu_dev *qcom_iommu = platform_get_drvdata(pdev);
+
+       return qcom_iommu_enable_clocks(qcom_iommu);
+}
+
+static int qcom_iommu_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct qcom_iommu_dev *qcom_iommu = platform_get_drvdata(pdev);
+
+       qcom_iommu_disable_clocks(qcom_iommu);
+
+       return 0;
+}
+#endif
+
+static const struct dev_pm_ops qcom_iommu_pm_ops = {
+       SET_RUNTIME_PM_OPS(qcom_iommu_suspend, qcom_iommu_resume, NULL)
+       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+                               pm_runtime_force_resume)
+};
+
+static const struct of_device_id qcom_iommu_of_match[] = {
+       { .compatible = "qcom,msm-iommu-v1" },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, qcom_iommu_of_match);
+
+static struct platform_driver qcom_iommu_driver = {
+       .driver = {
+               .name           = "qcom-iommu",
+               .of_match_table = of_match_ptr(qcom_iommu_of_match),
+               .pm             = &qcom_iommu_pm_ops,
+       },
+       .probe  = qcom_iommu_device_probe,
+       .remove = qcom_iommu_device_remove,
+};
+module_platform_driver(qcom_iommu_driver);
+
+IOMMU_OF_DECLARE(qcom_iommu_dev, "qcom,msm-iommu-v1", NULL);
Quoted 8 lines

drivers/iommu/qcom_iommu.c line 818

Quoted 4 lines
drivers/iommu/qcom_iommu.c new file +3 -0
+
+MODULE_DESCRIPTION("IOMMU API for QCOM IOMMU v1 implementations");
+MODULE_LICENSE("GPL v2");

--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project

--
To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#15 lore raw

PATCH 6/9 iommu: qcom: initialize secure page table

In reply to Rob Clark

From: Stanimir Varbanov <[email protected]>

This basically gets the secure page table size, allocates memory for secure pagetables and passes the physical address to the trusted zone.

---
 drivers/iommu/qcom_iommu.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 64 insertions(+)
drivers/iommu/qcom_iommu.c +64 -0
index 6b7adbf..743a628 100644
@@ -608,6 +608,51 @@ static void qcom_iommu_disable_clocks(struct qcom_iommu_dev *qcom_iommu)
 	clk_disable_unprepare(qcom_iommu->iface_clk);
 }
 
+static int qcom_iommu_sec_ptbl_init(struct device *dev)
+{
+	size_t psize = 0;
+	unsigned int spare = 0;
+	void *cpu_addr;
+	dma_addr_t paddr;
+	unsigned long attrs;
+	static bool allocated = false;
+	int ret;
+
+	if (allocated)
+		return 0;
+
+	ret = qcom_scm_iommu_secure_ptbl_size(spare, &psize);
+	if (ret) {
+		dev_err(dev, "failed to get iommu secure pgtable size (%d)\n",
+			ret);
+		return ret;
+	}
+
+	dev_info(dev, "iommu sec: pgtable size: %zu\n", psize);
+
+	attrs = DMA_ATTR_NO_KERNEL_MAPPING;
+
+	cpu_addr = dma_alloc_attrs(dev, psize, &paddr, GFP_KERNEL, attrs);
+	if (!cpu_addr) {
+		dev_err(dev, "failed to allocate %zu bytes for pgtable\n",
+			psize);
+		return -ENOMEM;
+	}
+
+	ret = qcom_scm_iommu_secure_ptbl_init(paddr, psize, spare);
+	if (ret) {
+		dev_err(dev, "failed to init iommu pgtable (%d)\n", ret);
+		goto free_mem;
+	}
+
+	allocated = true;
+	return 0;
+
+free_mem:
+	dma_free_attrs(dev, psize, cpu_addr, paddr, attrs);
+	return ret;
+}
+
 static int qcom_iommu_ctx_probe(struct platform_device *pdev)
 {
 	struct qcom_iommu_ctx *ctx;
@@ -688,6 +733,17 @@ static struct platform_driver qcom_iommu_ctx_driver = {
 };
 module_platform_driver(qcom_iommu_ctx_driver);
 
+static bool qcom_iommu_has_secure_context(struct qcom_iommu_dev *qcom_iommu)
+{
+	struct device_node *child;
+
+	for_each_child_of_node(qcom_iommu->dev->of_node, child)
+		if (of_device_is_compatible(child, "qcom,msm-iommu-v1-sec"))
+			return true;
+
+	return false;
+}
+
 static int qcom_iommu_device_probe(struct platform_device *pdev)
 {
 	struct qcom_iommu_dev *qcom_iommu;
@@ -724,6 +780,14 @@ static int qcom_iommu_device_probe(struct platform_device *pdev)
 		return -ENODEV;
 	}
 
+	if (qcom_iommu_has_secure_context(qcom_iommu)) {
+		ret = qcom_iommu_sec_ptbl_init(dev);
+		if (ret) {
+			dev_err(dev, "cannot init secure pg table(%d)\n", ret);
+			return ret;
+		}
+	}
+
 	platform_set_drvdata(pdev, qcom_iommu);
 
 	/* register context bank devices, which are child nodes: */
Signature · 1 line
2.9.3
#16 lore raw

PATCH 7/9 ARM64: DT: add gpu for msm8916

In reply to Rob Clark
---
 arch/arm64/boot/dts/qcom/msm8916.dtsi | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)
arch/arm64/boot/dts/qcom/msm8916.dtsi +23 -0
index 68a8e67..b0daf39 100644
@@ -698,6 +698,29 @@
 			#thermal-sensor-cells = <1>;
 		};
 
+		gpu@01c00000 {
+			compatible = "qcom,adreno-306.0", "qcom,adreno";
+			reg = <0x01c00000 0x20000>;
+			reg-names = "kgsl_3d0_reg_memory";
+			interrupts = <0 33 0>;
+			interrupt-names = "kgsl_3d0_irq";
+			clock-names =
+			    "core",
+			    "iface",
+			    "mem",
+			    "mem_iface",
+			    "alt_mem_iface",
+			    "gfx3d_clk";
+			clocks =
+			    <&gcc GCC_OXILI_GFX3D_CLK>,
+			    <&gcc GCC_OXILI_AHB_CLK>,
+			    <&gcc GCC_OXILI_GMEM_CLK>,
+			    <&gcc GCC_BIMC_GFX_CLK>,
+			    <&gcc GCC_BIMC_GPU_CLK>,
+			    <&gcc GFX3D_CLK_SRC>;
+			power-domains = <&gcc OXILI_GDSC>;
+		};
+
 		mdss: mdss@1a00000 {
 			compatible = "qcom,mdss";
 			reg = <0x1a00000 0x1000>,
Signature · 1 line
2.9.3
#17 lore raw

PATCH 8/9 ARM64: DT: add video codec devicetree node

In reply to Rob Clark

From: Stanimir Varbanov <[email protected]>

---
 arch/arm64/boot/dts/qcom/msm8916.dtsi | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)
arch/arm64/boot/dts/qcom/msm8916.dtsi +28 -0
index b0daf39..7bcf4cd 100644
@@ -88,6 +88,13 @@
 			no-map;
 		};
 
+		venus_mem: venus@89900000 {
+			compatible = "shared-dma-pool";
+			reg = <0x0 0x89900000 0x0 0x800000>;
+			alignment = <0x1000>;
+			no-map;
+		};
+
 		mba_mem: mba@8ea00000 {
 			no-map;
 			reg = <0 0x8ea00000 0 0x100000>;
@@ -1190,6 +1197,27 @@
 				};
 			};
 		};
+
+		venus: video-codec@1d00000 {
+			compatible = "qcom,msm8916-venus";
+			reg = <0x01d00000 0xff000>;
+			interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
+			power-domains = <&gcc VENUS_GDSC>;
+			clocks = <&gcc GCC_VENUS0_VCODEC0_CLK>,
+				 <&gcc GCC_VENUS0_AHB_CLK>,
+				 <&gcc GCC_VENUS0_AXI_CLK>;
+			clock-names = "core", "iface", "bus";
+			memory-region = <&venus_mem>;
+			status = "okay";
+
+			video-decoder {
+				compatible = "venus-decoder";
+			};
+
+			video-encoder {
+				compatible = "venus-encoder";
+			};
+		};
 	};
 
 	smd {
Signature · 1 line
2.9.3
#18 lore raw

PATCH 9/9 ARM64: DT: add iommu for msm8916

In reply to Rob Clark
---
 arch/arm64/boot/dts/qcom/msm8916.dtsi | 57 +++++++++++++++++++++++++++++++++++
 1 file changed, 57 insertions(+)
arch/arm64/boot/dts/qcom/msm8916.dtsi +57 -0
index 7bcf4cd..8aeec6f 100644
@@ -705,6 +705,59 @@
 			#thermal-sensor-cells = <1>;
 		};
 
+		apps_iommu: iommu@1ef0000 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			#iommu-cells = <1>;
+			compatible = "qcom,msm8916-iommu", "qcom,msm-iommu-v1";
+			ranges = <0 0x1e20000 0x40000>;
+			reg = <0x1ef0000 0x3000>;
+			clocks = <&gcc GCC_SMMU_CFG_CLK>,
+				 <&gcc GCC_APSS_TCU_CLK>;
+			clock-names = "iface", "bus";
+			qcom,iommu-secure-id = <17>;
+
+			// mdp_0:
+			iommu-ctx@4000 {
+				compatible = "qcom,msm-iommu-v1-ns";
+				reg = <0x4000 0x1000>;
+				interrupts = <GIC_SPI 70 0>;
+			};
+
+			// venus_ns:
+			iommu-ctx@5000 {
+				compatible = "qcom,msm-iommu-v1-sec";
+				reg = <0x5000 0x1000>;
+				interrupts = <GIC_SPI 70 0>;
+			};
+		};
+
+		gpu_iommu: iommu@1f08000 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			#iommu-cells = <1>;
+			compatible = "qcom,msm8916-iommu", "qcom,msm-iommu-v1";
+			ranges = <0 0x1f08000 0x10000>;
+			clocks = <&gcc GCC_SMMU_CFG_CLK>,
+				 <&gcc GCC_GFX_TCU_CLK>;
+			clock-names = "iface", "bus";
+			qcom,iommu-secure-id = <18>;
+
+			// gfx3d_user:
+			iommu-ctx@1000 {
+				compatible = "qcom,msm-iommu-v1-ns";
+				reg = <0x1000 0x1000>;
+				interrupts = <GIC_SPI 241 0>;
+			};
+
+			// gfx3d_priv:
+			iommu-ctx@2000 {
+				compatible = "qcom,msm-iommu-v1-ns";
+				reg = <0x2000 0x1000>;
+				interrupts = <GIC_SPI 242 0>;
+			};
+		};
+
 		gpu@01c00000 {
 			compatible = "qcom,adreno-306.0", "qcom,adreno";
 			reg = <0x01c00000 0x20000>;
@@ -726,6 +779,7 @@
 			    <&gcc GCC_BIMC_GPU_CLK>,
 			    <&gcc GFX3D_CLK_SRC>;
 			power-domains = <&gcc OXILI_GDSC>;
+			iommus = <&gpu_iommu 1>, <&gpu_iommu 2>;
 		};
 
 		mdss: mdss@1a00000 {
@@ -769,6 +823,8 @@
 					      "core_clk",
 					      "vsync_clk";
 
+				iommus = <&apps_iommu 4>;
+
 				ports {
 					#address-cells = <1>;
 					#size-cells = <0>;
@@ -1207,6 +1263,7 @@
 				 <&gcc GCC_VENUS0_AHB_CLK>,
 				 <&gcc GCC_VENUS0_AXI_CLK>;
 			clock-names = "core", "iface", "bus";
+			iommus = <&apps_iommu 5>;
 			memory-region = <&venus_mem>;
 			status = "okay";
 
Signature · 1 line
2.9.3