iommu: add qcom_iommu for early "B" family devices (v2)
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
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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
PATCH 2/9 firmware: qcom_scm: add two scm calls for iommu secure page table
In reply to a message not in the archiveFrom: 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
@@ -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
@@ -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
@@ -89,5 +89,11 @@ static inline int qcom_scm_remap_error(int err)#define QCOM_SCM_RESTORE_SEC_CFG 2extern 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
@@ -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
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
@@ -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
Re: [PATCH 3/9] Docs: dt: document qcom iommu bindings
Quoted 52 lines · Rob Clark
Signed-off-by Rob Clark <[email protected]>--- .../devicetree/bindings/iommu/qcom,iommu.txt | 113 +++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 Documentation/devicetree/bindings/iommu/qcom,iommu.txtDocumentation/devicetree/bindings/iommu/qcom,iommu.txt new file +39
-0@@ -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
Re: [PATCH 3/9] Docs: dt: document qcom iommu bindings
Quoted 58 lines · Rob Herring
Quoted 57 lines · Rob Clark
Signed-off-by Rob Clark <[email protected]>--- .../devicetree/bindings/iommu/qcom,iommu.txt | 113 +++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 Documentation/devicetree/bindings/iommu/qcom,iommu.txtDocumentation/devicetree/bindings/iommu/qcom,iommu.txt new file +44
-0@@ -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
Rob Herring
maintainerRe: [PATCH 3/9] Docs: dt: document qcom iommu bindings
Quoted 68 lines · Rob Clark
Quoted 58 lines · Rob Herring
Quoted 57 lines · Rob Clark
Signed-off-by Rob Clark <[email protected]>--- .../devicetree/bindings/iommu/qcom,iommu.txt | 113 +++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 Documentation/devicetree/bindings/iommu/qcom,iommu.txtDocumentation/devicetree/bindings/iommu/qcom,iommu.txt new file +44
-0@@ -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
PATCH 4/9 iommu: arm-smmu: split out register defines
In reply to a message not in the archiveI 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
@@ -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
PATCH 5/9 iommu: add qcom_iommu
In reply to a message not in the archiveAn 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
@@ -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
@@ -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
@@ -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
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).
Signed-off-by Rob Clark <[email protected]>Signed-off-by Stanimir Varbanov <[email protected]>--- 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 , ®)) { +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
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).
Signed-off-by Rob Clark <[email protected]>Signed-off-by Stanimir Varbanov <[email protected]>--- 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 aWARN_ON()that gets triggered here for all devices on the platform bus that aren't backed by our iommu. We should return-ENODEVfor 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,
ArchitQuoted 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 linkbetween %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 , ®)) { +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
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).
Signed-off-by Rob Clark <[email protected]>Signed-off-by Stanimir Varbanov <[email protected]>--- 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 aWARN_ON()that gets triggered here for all devices on the platform bus that aren't backed by our iommu. We should return-ENODEVfor 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,
-RQuoted 347 lines
Thanks,
ArchitQuoted 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 linkbetween %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 , ®)) { +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
PATCH 6/9 iommu: qcom: initialize secure page table
In reply to Rob ClarkFrom: 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
@@ -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
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
@@ -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
PATCH 8/9 ARM64: DT: add video codec devicetree node
In reply to Rob ClarkFrom: 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
@@ -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
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
@@ -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