* [PATCH 0/9] iommu: add qcom_iommu for early "B" family devices (v2) @ 2017-03-14 15:18 Rob Clark [not found] ` <20170314151811.17234-1-robdclark-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> ` (4 more replies) 0 siblings, 5 replies; 16+ messages in thread From: Rob Clark @ 2017-03-14 15:18 UTC (permalink / raw) To: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA Cc: Mark Rutland, linux-arm-msm-u79uwXL29TY76Z2rM5mHXA, Will Deacon, Stanimir Varbanov 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 -- 2.9.3 ^ permalink raw reply [flat|nested] 16+ messages in thread
[parent not found: <20170314151811.17234-1-robdclark-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>]
* [PATCH 1/9] firmware/qcom: add qcom_scm_restore_sec_cfg() [not found] ` <20170314151811.17234-1-robdclark-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> @ 2017-03-14 15:18 ` Rob Clark 2017-03-14 15:18 ` [PATCH 2/9] firmware: qcom_scm: add two scm calls for iommu secure page table Rob Clark ` (3 subsequent siblings) 4 siblings, 0 replies; 16+ messages in thread From: Rob Clark @ 2017-03-14 15:18 UTC (permalink / raw) To: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA Cc: Mark Rutland, linux-arm-msm-u79uwXL29TY76Z2rM5mHXA, Will Deacon, Stanimir Varbanov Signed-off-by: Rob Clark <robdclark-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> --- 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(+) diff --git a/drivers/firmware/qcom_scm-32.c b/drivers/firmware/qcom_scm-32.c index 8ad226c..722e65a 100644 --- a/drivers/firmware/qcom_scm-32.c +++ b/drivers/firmware/qcom_scm-32.c @@ -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; +} diff --git a/drivers/firmware/qcom_scm-64.c b/drivers/firmware/qcom_scm-64.c index c933259..550e3a3 100644 --- a/drivers/firmware/qcom_scm-64.c +++ b/drivers/firmware/qcom_scm-64.c @@ -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; +} diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index d987bcc..ae1f473 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -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 */ diff --git a/drivers/firmware/qcom_scm.h b/drivers/firmware/qcom_scm.h index 6a0f154..31fc732 100644 --- a/drivers/firmware/qcom_scm.h +++ b/drivers/firmware/qcom_scm.h @@ -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 diff --git a/include/linux/qcom_scm.h b/include/linux/qcom_scm.h index d32f6f1..22017f5d 100644 --- a/include/linux/qcom_scm.h +++ b/include/linux/qcom_scm.h @@ -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 -- 2.9.3 ^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 2/9] firmware: qcom_scm: add two scm calls for iommu secure page table [not found] ` <20170314151811.17234-1-robdclark-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 2017-03-14 15:18 ` [PATCH 1/9] firmware/qcom: add qcom_scm_restore_sec_cfg() Rob Clark @ 2017-03-14 15:18 ` Rob Clark 2017-03-14 15:18 ` [PATCH 3/9] Docs: dt: document qcom iommu bindings Rob Clark ` (2 subsequent siblings) 4 siblings, 0 replies; 16+ messages in thread From: Rob Clark @ 2017-03-14 15:18 UTC (permalink / raw) To: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA Cc: Mark Rutland, linux-arm-msm-u79uwXL29TY76Z2rM5mHXA, Will Deacon, Stanimir Varbanov From: Stanimir Varbanov <stanimir.varbanov-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> Those two new SCM calls are needed from qcom-iommu driver in order to initialize secure iommu page table. Signed-off-by: Stanimir Varbanov <stanimir.varbanov-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> Signed-off-by: Rob Clark <robdclark-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> --- 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(+) diff --git a/drivers/firmware/qcom_scm-32.c b/drivers/firmware/qcom_scm-32.c index 722e65a..93e3b96 100644 --- a/drivers/firmware/qcom_scm-32.c +++ b/drivers/firmware/qcom_scm-32.c @@ -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; +} diff --git a/drivers/firmware/qcom_scm-64.c b/drivers/firmware/qcom_scm-64.c index 550e3a3..6e6d561 100644 --- a/drivers/firmware/qcom_scm-64.c +++ b/drivers/firmware/qcom_scm-64.c @@ -397,3 +397,45 @@ int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id, u32 spare) return ret ? : res.a1; } + +int __qcom_scm_iommu_secure_ptbl_size(struct device *dev, u32 spare, + size_t *size) +{ + struct qcom_scm_desc desc = {0}; + struct arm_smccc_res res; + int ret; + + desc.args[0] = spare; + desc.arginfo = QCOM_SCM_ARGS(1); + + ret = qcom_scm_call(dev, QCOM_SCM_SVC_MP, + QCOM_SCM_IOMMU_SECURE_PTBL_SIZE, &desc, &res); + + if (size) + *size = res.a1; + + return ret ? : res.a2; +} + +int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr, u32 size, + u32 spare) +{ + struct qcom_scm_desc desc = {0}; + struct arm_smccc_res res; + int ret; + + desc.args[0] = addr; + desc.args[1] = size; + desc.args[2] = spare; + desc.arginfo = QCOM_SCM_ARGS(3, QCOM_SCM_RW, QCOM_SCM_VAL, + QCOM_SCM_VAL); + + ret = qcom_scm_call(dev, QCOM_SCM_SVC_MP, + QCOM_SCM_IOMMU_SECURE_PTBL_INIT, &desc, &res); + + /* the pg table has been initialized already, ignore the error */ + if (ret == -EPERM) + ret = 0; + + return ret; +} diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index ae1f473..bb16510 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -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 */ diff --git a/drivers/firmware/qcom_scm.h b/drivers/firmware/qcom_scm.h index 31fc732..9bea691 100644 --- a/drivers/firmware/qcom_scm.h +++ b/drivers/firmware/qcom_scm.h @@ -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 diff --git a/include/linux/qcom_scm.h b/include/linux/qcom_scm.h index 22017f5d..e538047 100644 --- a/include/linux/qcom_scm.h +++ b/include/linux/qcom_scm.h @@ -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 -- 2.9.3 ^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 3/9] Docs: dt: document qcom iommu bindings [not found] ` <20170314151811.17234-1-robdclark-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 2017-03-14 15:18 ` [PATCH 1/9] firmware/qcom: add qcom_scm_restore_sec_cfg() Rob Clark 2017-03-14 15:18 ` [PATCH 2/9] firmware: qcom_scm: add two scm calls for iommu secure page table Rob Clark @ 2017-03-14 15:18 ` Rob Clark [not found] ` <20170314151811.17234-4-robdclark-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 2017-03-14 15:18 ` [PATCH 4/9] iommu: arm-smmu: split out register defines Rob Clark 2017-03-14 15:18 ` [PATCH 5/9] iommu: add qcom_iommu Rob Clark 4 siblings, 1 reply; 16+ messages in thread From: Rob Clark @ 2017-03-14 15:18 UTC (permalink / raw) To: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA Cc: Mark Rutland, devicetree-u79uwXL29TY76Z2rM5mHXA, linux-arm-msm-u79uwXL29TY76Z2rM5mHXA, Will Deacon, Stanimir Varbanov Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org Signed-off-by: Rob Clark <robdclark-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> --- .../devicetree/bindings/iommu/qcom,iommu.txt | 113 +++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 Documentation/devicetree/bindings/iommu/qcom,iommu.txt diff --git a/Documentation/devicetree/bindings/iommu/qcom,iommu.txt b/Documentation/devicetree/bindings/iommu/qcom,iommu.txt new file mode 100644 index 0000000..fd5b7fa --- /dev/null +++ b/Documentation/devicetree/bindings/iommu/qcom,iommu.txt @@ -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>; + }; -- 2.9.3 ^ permalink raw reply related [flat|nested] 16+ messages in thread
[parent not found: <20170314151811.17234-4-robdclark-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>]
* Re: [PATCH 3/9] Docs: dt: document qcom iommu bindings [not found] ` <20170314151811.17234-4-robdclark-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> @ 2017-03-23 22:21 ` Rob Herring 2017-03-24 2:45 ` Rob Clark 0 siblings, 1 reply; 16+ messages in thread From: Rob Herring @ 2017-03-23 22:21 UTC (permalink / raw) To: Rob Clark Cc: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA, linux-arm-msm-u79uwXL29TY76Z2rM5mHXA, Robin Murphy, Will Deacon, Sricharan, Mark Rutland, Stanimir Varbanov, devicetree-u79uwXL29TY76Z2rM5mHXA On Tue, Mar 14, 2017 at 11:18:05AM -0400, Rob Clark wrote: > Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org > Signed-off-by: Rob Clark <robdclark-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> > --- > .../devicetree/bindings/iommu/qcom,iommu.txt | 113 +++++++++++++++++++++ > 1 file changed, 113 insertions(+) > create mode 100644 Documentation/devicetree/bindings/iommu/qcom,iommu.txt > > diff --git a/Documentation/devicetree/bindings/iommu/qcom,iommu.txt b/Documentation/devicetree/bindings/iommu/qcom,iommu.txt > new file mode 100644 > index 0000000..fd5b7fa > --- /dev/null > +++ b/Documentation/devicetree/bindings/iommu/qcom,iommu.txt > @@ -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"; You didn't document the fallback above. Maybe just drop it if only a few chips have this iommu. > + ranges = <0 0x1e20000 0x40000>; > + reg = <0x1ef0000 0x3000>; When you have both reg and ranges, use reg value for the unit-address. > + 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 { iommu-ctx@1000 > + compatible = "qcom,msm-iommu-v1-ns"; > + reg = <0x1000 0x1000>; > + interrupts = <GIC_SPI 241 0>; > + }; > + > + // gfx3d_priv: > + iommu-ctx@1f0a000 { iommu-ctx@2000 > + 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 majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org > 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 majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 3/9] Docs: dt: document qcom iommu bindings 2017-03-23 22:21 ` Rob Herring @ 2017-03-24 2:45 ` Rob Clark 2017-03-27 19:10 ` Rob Herring 0 siblings, 1 reply; 16+ messages in thread From: Rob Clark @ 2017-03-24 2:45 UTC (permalink / raw) To: Rob Herring Cc: Mark Rutland, devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, linux-arm-msm, Will Deacon, Stanimir Varbanov, iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org On Thu, Mar 23, 2017 at 6:21 PM, Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> wrote: > On Tue, Mar 14, 2017 at 11:18:05AM -0400, Rob Clark wrote: >> Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org >> Signed-off-by: Rob Clark <robdclark-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> >> --- >> .../devicetree/bindings/iommu/qcom,iommu.txt | 113 +++++++++++++++++++++ >> 1 file changed, 113 insertions(+) >> create mode 100644 Documentation/devicetree/bindings/iommu/qcom,iommu.txt >> >> diff --git a/Documentation/devicetree/bindings/iommu/qcom,iommu.txt b/Documentation/devicetree/bindings/iommu/qcom,iommu.txt >> new file mode 100644 >> index 0000000..fd5b7fa >> --- /dev/null >> +++ b/Documentation/devicetree/bindings/iommu/qcom,iommu.txt >> @@ -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"; > > 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.. >> + 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 >> + 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 { > > iommu-ctx@1000 will fix, thx BR, -R >> + compatible = "qcom,msm-iommu-v1-ns"; >> + reg = <0x1000 0x1000>; >> + interrupts = <GIC_SPI 241 0>; >> + }; >> + >> + // gfx3d_priv: >> + iommu-ctx@1f0a000 { > > iommu-ctx@2000 > >> + 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 majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org >> More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 3/9] Docs: dt: document qcom iommu bindings 2017-03-24 2:45 ` Rob Clark @ 2017-03-27 19:10 ` Rob Herring 0 siblings, 0 replies; 16+ messages in thread From: Rob Herring @ 2017-03-27 19:10 UTC (permalink / raw) To: Rob Clark Cc: iommu@lists.linux-foundation.org, linux-arm-msm, Robin Murphy, Will Deacon, Sricharan, Mark Rutland, Stanimir Varbanov, devicetree@vger.kernel.org On Thu, Mar 23, 2017 at 9:45 PM, Rob Clark <robdclark@gmail.com> wrote: > On Thu, Mar 23, 2017 at 6:21 PM, Rob Herring <robh@kernel.org> wrote: >> On Tue, Mar 14, 2017 at 11:18:05AM -0400, Rob Clark wrote: >>> Cc: devicetree@vger.kernel.org >>> Signed-off-by: Rob Clark <robdclark@gmail.com> >>> --- >>> .../devicetree/bindings/iommu/qcom,iommu.txt | 113 +++++++++++++++++++++ >>> 1 file changed, 113 insertions(+) >>> create mode 100644 Documentation/devicetree/bindings/iommu/qcom,iommu.txt >>> >>> diff --git a/Documentation/devicetree/bindings/iommu/qcom,iommu.txt b/Documentation/devicetree/bindings/iommu/qcom,iommu.txt >>> new file mode 100644 >>> index 0000000..fd5b7fa >>> --- /dev/null >>> +++ b/Documentation/devicetree/bindings/iommu/qcom,iommu.txt >>> @@ -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"; >> >> 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) 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 ^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 4/9] iommu: arm-smmu: split out register defines [not found] ` <20170314151811.17234-1-robdclark-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> ` (2 preceding siblings ...) 2017-03-14 15:18 ` [PATCH 3/9] Docs: dt: document qcom iommu bindings Rob Clark @ 2017-03-14 15:18 ` Rob Clark 2017-03-14 15:18 ` [PATCH 5/9] iommu: add qcom_iommu Rob Clark 4 siblings, 0 replies; 16+ messages in thread From: Rob Clark @ 2017-03-14 15:18 UTC (permalink / raw) To: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA Cc: Mark Rutland, linux-arm-msm-u79uwXL29TY76Z2rM5mHXA, Will Deacon, Stanimir Varbanov I want to re-use some of these for qcom_iommu, which has (roughly) the same context-bank registers. Signed-off-by: Rob Clark <robdclark-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> --- 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 diff --git a/drivers/iommu/arm-smmu-regs.h b/drivers/iommu/arm-smmu-regs.h new file mode 100644 index 0000000..632240f --- /dev/null +++ b/drivers/iommu/arm-smmu-regs.h @@ -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 <will.deacon-5wv7dgnIgG8@public.gmane.org> + */ + +#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 */ diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index e19b1cc..0700a62 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -54,6 +54,7 @@ #include <linux/amba/bus.h> #include "io-pgtable.h" +#include "arm-smmu-regs.h" /* Maximum number of context banks per SMMU */ #define ARM_SMMU_MAX_CBS 128 @@ -83,209 +84,10 @@ #define smmu_write_atomic_lq writel_relaxed #endif -/* 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 - /* Translation context bank */ #define ARM_SMMU_CB_BASE(smmu) ((smmu)->base + ((smmu)->size >> 1)) #define ARM_SMMU_CB(smmu, n) ((n) * (1 << (smmu)->pgshift)) -#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) - #define MSI_IOVA_BASE 0x8000000 #define MSI_IOVA_LENGTH 0x100000 -- 2.9.3 ^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 5/9] iommu: add qcom_iommu [not found] ` <20170314151811.17234-1-robdclark-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> ` (3 preceding siblings ...) 2017-03-14 15:18 ` [PATCH 4/9] iommu: arm-smmu: split out register defines Rob Clark @ 2017-03-14 15:18 ` Rob Clark [not found] ` <20170314151811.17234-6-robdclark-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 4 siblings, 1 reply; 16+ messages in thread From: Rob Clark @ 2017-03-14 15:18 UTC (permalink / raw) To: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA Cc: Mark Rutland, linux-arm-msm-u79uwXL29TY76Z2rM5mHXA, Will Deacon, Stanimir Varbanov 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 <robdclark-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> Signed-off-by: Stanimir Varbanov <stanimir.varbanov-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> --- 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 diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index 37e204f..400a404 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig @@ -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 diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile index 195f7b9..b910aea 100644 --- a/drivers/iommu/Makefile +++ b/drivers/iommu/Makefile @@ -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 diff --git a/drivers/iommu/arm-smmu-regs.h b/drivers/iommu/arm-smmu-regs.h index 632240f..e643164 100644 --- a/drivers/iommu/arm-smmu-regs.h +++ b/drivers/iommu/arm-smmu-regs.h @@ -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 diff --git a/drivers/iommu/qcom_iommu.c b/drivers/iommu/qcom_iommu.c new file mode 100644 index 0000000..6b7adbf --- /dev/null +++ b/drivers/iommu/qcom_iommu.c @@ -0,0 +1,818 @@ +/* + * IOMMU API for QCOM secure IOMMUs. Somewhat based on arm-smmu.c + * + * 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 + * Copyright (C) 2017 Red Hat + */ + +#define pr_fmt(fmt) "qcom-iommu: " fmt + +#include <linux/atomic.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/dma-iommu.h> +#include <linux/dma-mapping.h> +#include <linux/err.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/io-64-nonatomic-hi-lo.h> +#include <linux/iommu.h> +#include <linux/iopoll.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/of_iommu.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/qcom_scm.h> +#include <linux/slab.h> +#include <linux/spinlock.h> + +#include "io-pgtable.h" +#include "arm-smmu-regs.h" + +#define SMMU_INTR_SEL_NS 0x2000 + +struct qcom_iommu_dev { + /* IOMMU core code handle */ + struct iommu_device iommu; + struct device *dev; + struct clk *iface_clk; + struct clk *bus_clk; + void __iomem *local_base; + u32 sec_id; + struct list_head context_list; /* list of qcom_iommu_context */ +}; + +struct qcom_iommu_ctx { + struct device *dev; + void __iomem *base; + unsigned int irq; + bool secure_init; + u32 asid; /* asid and ctx bank # are 1:1 */ + struct iommu_group *group; + struct list_head node; /* head in qcom_iommu_device::context_list */ +}; + +struct qcom_iommu_domain { + struct io_pgtable_ops *pgtbl_ops; + spinlock_t pgtbl_lock; + struct mutex init_mutex; /* Protects iommu pointer */ + struct iommu_domain domain; + struct qcom_iommu_dev *iommu; +}; + +static struct qcom_iommu_domain *to_qcom_iommu_domain(struct iommu_domain *dom) +{ + return container_of(dom, struct qcom_iommu_domain, domain); +} + +static const struct iommu_ops qcom_iommu_ops; + +static struct qcom_iommu_dev * __to_iommu(struct iommu_fwspec *fwspec) +{ + if (WARN_ON(!fwspec || fwspec->ops != &qcom_iommu_ops)) + return NULL; + return fwspec->iommu_priv; +} + +static struct qcom_iommu_ctx * __to_ctx(struct iommu_fwspec *fwspec, unsigned asid) +{ + struct qcom_iommu_dev *qcom_iommu = __to_iommu(fwspec); + struct qcom_iommu_ctx *ctx; + + if (!qcom_iommu) + return NULL; + + list_for_each_entry(ctx, &qcom_iommu->context_list, node) + if (ctx->asid == asid) + return ctx; + + WARN(1, "no ctx for asid %u\n", asid); + return NULL; +} + +static inline void +iommu_writel(struct qcom_iommu_ctx *ctx, unsigned reg, u32 val) +{ + writel_relaxed(val, ctx->base + reg); +} + +static inline void +iommu_writeq(struct qcom_iommu_ctx *ctx, unsigned reg, u64 val) +{ + writeq_relaxed(val, ctx->base + reg); +} + +static inline u32 +iommu_readl(struct qcom_iommu_ctx *ctx, unsigned reg) +{ + return readl_relaxed(ctx->base + reg); +} + +static inline u32 +iommu_readq(struct qcom_iommu_ctx *ctx, unsigned reg) +{ + return readq_relaxed(ctx->base + reg); +} + +static void __sync_tlb(struct qcom_iommu_ctx *ctx) +{ + unsigned int val; + unsigned int ret; + + iommu_writel(ctx, ARM_SMMU_CB_TLBSYNC, 0); + + ret = readl_poll_timeout(ctx->base + ARM_SMMU_CB_TLBSTATUS, val, + (val & 0x1) == 0, 0, 5000000); + if (ret) + dev_err(ctx->dev, "timeout waiting for TLB SYNC\n"); +} + +static void qcom_iommu_tlb_sync(void *cookie) +{ + struct iommu_fwspec *fwspec = cookie; + unsigned i; + + for (i = 0; i < fwspec->num_ids; i++) + __sync_tlb(__to_ctx(fwspec, fwspec->ids[i])); +} + +static void qcom_iommu_tlb_inv_context(void *cookie) +{ + struct iommu_fwspec *fwspec = cookie; + unsigned i; + + for (i = 0; i < fwspec->num_ids; i++) { + struct qcom_iommu_ctx *ctx = __to_ctx(fwspec, fwspec->ids[i]); + + iommu_writel(ctx, ARM_SMMU_CB_S1_TLBIASID, ctx->asid); + __sync_tlb(ctx); + } +} + +static void qcom_iommu_tlb_inv_range_nosync(unsigned long iova, size_t size, + size_t granule, bool leaf, void *cookie) +{ + struct iommu_fwspec *fwspec = cookie; + unsigned i, reg; + + reg = leaf ? ARM_SMMU_CB_S1_TLBIVAL : ARM_SMMU_CB_S1_TLBIVA; + + for (i = 0; i < fwspec->num_ids; i++) { + struct qcom_iommu_ctx *ctx = __to_ctx(fwspec, fwspec->ids[i]); + size_t s = size; + + iova &= ~12UL; + iova |= ctx->asid; + do { + iommu_writel(ctx, reg, iova); + iova += granule; + } while (s -= granule); + } +} + +static const struct iommu_gather_ops qcom_gather_ops = { + .tlb_flush_all = qcom_iommu_tlb_inv_context, + .tlb_add_flush = qcom_iommu_tlb_inv_range_nosync, + .tlb_sync = qcom_iommu_tlb_sync, +}; + +static irqreturn_t qcom_iommu_fault(int irq, void *dev) +{ + struct qcom_iommu_ctx *ctx = dev; + u32 fsr, fsynr; + unsigned long iova; + + fsr = iommu_readl(ctx, ARM_SMMU_CB_FSR); + + if (!(fsr & FSR_FAULT)) + return IRQ_NONE; + + fsynr = iommu_readl(ctx, ARM_SMMU_CB_FSYNR0); + iova = iommu_readq(ctx, ARM_SMMU_CB_FAR); + + dev_err_ratelimited(ctx->dev, + "Unhandled context fault: fsr=0x%x, " + "iova=0x%08lx, fsynr=0x%x, cb=%d\n", + fsr, iova, fsynr, ctx->asid); + + iommu_writel(ctx, ARM_SMMU_CB_FSR, fsr); + + return IRQ_HANDLED; +} + +static int qcom_iommu_init_domain(struct iommu_domain *domain, + struct qcom_iommu_dev *qcom_iommu, + struct iommu_fwspec *fwspec) +{ + struct qcom_iommu_domain *qcom_domain = to_qcom_iommu_domain(domain); + struct io_pgtable_ops *pgtbl_ops; + struct io_pgtable_cfg pgtbl_cfg; + int i, ret = 0; + u32 reg; + + mutex_lock(&qcom_domain->init_mutex); + if (qcom_domain->iommu) + goto out_unlock; + + pgtbl_cfg = (struct io_pgtable_cfg) { + .pgsize_bitmap = qcom_iommu_ops.pgsize_bitmap, + .ias = 32, + .oas = 40, + .tlb = &qcom_gather_ops, + .iommu_dev = qcom_iommu->dev, + }; + + qcom_domain->iommu = qcom_iommu; + pgtbl_ops = alloc_io_pgtable_ops(ARM_32_LPAE_S1, &pgtbl_cfg, fwspec); + if (!pgtbl_ops) { + dev_err(qcom_iommu->dev, "failed to allocate pagetable ops\n"); + ret = -ENOMEM; + goto out_clear_iommu; + } + + /* Update the domain's page sizes to reflect the page table format */ + domain->pgsize_bitmap = pgtbl_cfg.pgsize_bitmap; + domain->geometry.aperture_end = (1ULL << pgtbl_cfg.ias) - 1; + domain->geometry.force_aperture = true; + + for (i = 0; i < fwspec->num_ids; i++) { + struct qcom_iommu_ctx *ctx = __to_ctx(fwspec, fwspec->ids[i]); + + if (!ctx->secure_init) { + ret = qcom_scm_restore_sec_cfg(qcom_iommu->sec_id, ctx->asid); + if (ret) { + dev_err(qcom_iommu->dev, "secure init failed: %d\n", ret); + goto out_clear_iommu; + } + ctx->secure_init = true; + } + + /* TTBRs */ + iommu_writeq(ctx, ARM_SMMU_CB_TTBR0, + pgtbl_cfg.arm_lpae_s1_cfg.ttbr[0] | + ((u64)ctx->asid << TTBRn_ASID_SHIFT)); + iommu_writeq(ctx, ARM_SMMU_CB_TTBR1, + pgtbl_cfg.arm_lpae_s1_cfg.ttbr[1] | + ((u64)ctx->asid << TTBRn_ASID_SHIFT)); + + /* TTBCR */ + iommu_writel(ctx, ARM_SMMU_CB_TTBCR2, + (pgtbl_cfg.arm_lpae_s1_cfg.tcr >> 32) | + TTBCR2_SEP_UPSTREAM); + iommu_writel(ctx, ARM_SMMU_CB_TTBCR, + pgtbl_cfg.arm_lpae_s1_cfg.tcr); + + /* MAIRs (stage-1 only) */ + iommu_writel(ctx, ARM_SMMU_CB_S1_MAIR0, + pgtbl_cfg.arm_lpae_s1_cfg.mair[0]); + iommu_writel(ctx, ARM_SMMU_CB_S1_MAIR1, + pgtbl_cfg.arm_lpae_s1_cfg.mair[1]); + + /* SCTLR */ + reg = SCTLR_CFIE | SCTLR_CFRE | SCTLR_AFE | SCTLR_TRE | + SCTLR_M | SCTLR_S1_ASIDPNE; +#ifdef __BIG_ENDIAN + reg |= SCTLR_E; +#endif + iommu_writel(ctx, ARM_SMMU_CB_SCTLR, reg); + } + + mutex_unlock(&qcom_domain->init_mutex); + + /* Publish page table ops for map/unmap */ + qcom_domain->pgtbl_ops = pgtbl_ops; + + return 0; + +out_clear_iommu: + qcom_domain->iommu = NULL; +out_unlock: + mutex_unlock(&qcom_domain->init_mutex); + return ret; +} + +static struct iommu_domain *qcom_iommu_domain_alloc(unsigned type) +{ + struct qcom_iommu_domain *qcom_domain; + + if (type != IOMMU_DOMAIN_UNMANAGED && type != IOMMU_DOMAIN_DMA) + return NULL; + /* + * Allocate the domain and initialise some of its data structures. + * We can't really do anything meaningful until we've added a + * master. + */ + qcom_domain = kzalloc(sizeof(*qcom_domain), GFP_KERNEL); + if (!qcom_domain) + return NULL; + + if (type == IOMMU_DOMAIN_DMA && + iommu_get_dma_cookie(&qcom_domain->domain)) { + kfree(qcom_domain); + return NULL; + } + + mutex_init(&qcom_domain->init_mutex); + spin_lock_init(&qcom_domain->pgtbl_lock); + + return &qcom_domain->domain; +} + +static void qcom_iommu_domain_free(struct iommu_domain *domain) +{ + struct qcom_iommu_domain *qcom_domain = to_qcom_iommu_domain(domain); + + if (WARN_ON(qcom_domain->iommu)) /* forgot to detach? */ + return; + + iommu_put_dma_cookie(domain); + + free_io_pgtable_ops(qcom_domain->pgtbl_ops); + + kfree(qcom_domain); +} + +static int qcom_iommu_attach_dev(struct iommu_domain *domain, struct device *dev) +{ + struct qcom_iommu_dev *qcom_iommu = __to_iommu(dev->iommu_fwspec); + struct qcom_iommu_domain *qcom_domain = to_qcom_iommu_domain(domain); + int ret; + + if (!qcom_iommu) { + dev_err(dev, "cannot attach to IOMMU, is it on the same bus?\n"); + return -ENXIO; + } + + /* Ensure that the domain is finalized */ + pm_runtime_get_sync(qcom_iommu->dev); + ret = qcom_iommu_init_domain(domain, qcom_iommu, dev->iommu_fwspec); + pm_runtime_put_sync(qcom_iommu->dev); + if (ret < 0) + return ret; + + /* + * Sanity check the domain. We don't support domains across + * different IOMMUs. + */ + if (qcom_domain->iommu != qcom_iommu) { + dev_err(dev, "cannot attach to IOMMU %s while already " + "attached to domain on IOMMU %s\n", + dev_name(qcom_domain->iommu->dev), + dev_name(qcom_iommu->dev)); + return -EINVAL; + } + + return 0; +} + +static void qcom_iommu_detach_dev(struct iommu_domain *domain, struct device *dev) +{ + struct iommu_fwspec *fwspec = dev->iommu_fwspec; + struct qcom_iommu_dev *qcom_iommu = __to_iommu(fwspec); + struct qcom_iommu_domain *qcom_domain = to_qcom_iommu_domain(domain); + unsigned i; + + if (!qcom_domain->iommu) + return; + + pm_runtime_get_sync(qcom_iommu->dev); + for (i = 0; i < fwspec->num_ids; i++) { + struct qcom_iommu_ctx *ctx = __to_ctx(fwspec, fwspec->ids[i]); + + /* Disable the context bank: */ + iommu_writel(ctx, ARM_SMMU_CB_SCTLR, 0); + } + pm_runtime_put_sync(qcom_iommu->dev); + + qcom_domain->iommu = NULL; +} + +static int qcom_iommu_map(struct iommu_domain *domain, unsigned long iova, + phys_addr_t paddr, size_t size, int prot) +{ + int ret; + unsigned long flags; + struct qcom_iommu_domain *qcom_domain = to_qcom_iommu_domain(domain); + struct io_pgtable_ops *ops = qcom_domain->pgtbl_ops; + + if (!ops) + return -ENODEV; + + spin_lock_irqsave(&qcom_domain->pgtbl_lock, flags); + ret = ops->map(ops, iova, paddr, size, prot); + spin_unlock_irqrestore(&qcom_domain->pgtbl_lock, flags); + return ret; +} + +static size_t qcom_iommu_unmap(struct iommu_domain *domain, unsigned long iova, + size_t size) +{ + size_t ret; + unsigned long flags; + struct qcom_iommu_domain *qcom_domain = to_qcom_iommu_domain(domain); + struct io_pgtable_ops *ops = qcom_domain->pgtbl_ops; + + if (!ops) + return 0; + + spin_lock_irqsave(&qcom_domain->pgtbl_lock, flags); + ret = ops->unmap(ops, iova, size); + spin_unlock_irqrestore(&qcom_domain->pgtbl_lock, flags); + return ret; +} + +static phys_addr_t qcom_iommu_iova_to_phys(struct iommu_domain *domain, + dma_addr_t iova) +{ + phys_addr_t ret; + unsigned long flags; + struct qcom_iommu_domain *qcom_domain = to_qcom_iommu_domain(domain); + struct io_pgtable_ops *ops = qcom_domain->pgtbl_ops; + + if (!ops) + return 0; + + spin_lock_irqsave(&qcom_domain->pgtbl_lock, flags); + ret = ops->iova_to_phys(ops, iova); + spin_unlock_irqrestore(&qcom_domain->pgtbl_lock, flags); + + return ret; +} + +static bool qcom_iommu_capable(enum iommu_cap cap) +{ + switch (cap) { + case IOMMU_CAP_CACHE_COHERENCY: + /* + * Return true here as the SMMU can always send out coherent + * requests. + */ + return true; + case IOMMU_CAP_NOEXEC: + return true; + default: + return false; + } +} + +static int qcom_iommu_add_device(struct device *dev) +{ + struct qcom_iommu_dev *qcom_iommu = __to_iommu(dev->iommu_fwspec); + struct iommu_group *group; + struct device_link *link; + + 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"); -- 2.9.3 ^ permalink raw reply related [flat|nested] 16+ messages in thread
[parent not found: <20170314151811.17234-6-robdclark-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>]
* Re: [PATCH 5/9] iommu: add qcom_iommu [not found] ` <20170314151811.17234-6-robdclark-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> @ 2017-03-30 6:19 ` Archit Taneja 2017-03-30 13:46 ` Rob Clark 0 siblings, 1 reply; 16+ messages in thread From: Archit Taneja @ 2017-03-30 6:19 UTC (permalink / raw) To: Rob Clark Cc: Mark Rutland, linux-arm-msm-u79uwXL29TY76Z2rM5mHXA, iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA, Will Deacon, Stanimir Varbanov Hi, On 03/14/2017 08:48 PM, Rob Clark wrote: > 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 <robdclark-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> > Signed-off-by: Stanimir Varbanov <stanimir.varbanov-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> > --- > 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> > + > +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. > + 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 > + 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"); > -- Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 5/9] iommu: add qcom_iommu 2017-03-30 6:19 ` Archit Taneja @ 2017-03-30 13:46 ` Rob Clark 2017-03-31 4:19 ` Archit Taneja 0 siblings, 1 reply; 16+ messages in thread From: Rob Clark @ 2017-03-30 13:46 UTC (permalink / raw) To: Archit Taneja Cc: iommu@lists.linux-foundation.org, Mark Rutland, linux-arm-msm, Will Deacon, Stanimir Varbanov On Thu, Mar 30, 2017 at 2:19 AM, Archit Taneja <architt@codeaurora.org> wrote: > Hi, > > On 03/14/2017 08:48 PM, Rob Clark wrote: >> >> 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 <robdclark@gmail.com> >> Signed-off-by: Stanimir Varbanov <stanimir.varbanov@linaro.org> >> --- >> 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> > >> + >> +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. > >> + 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.. 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 > Thanks, > Archit > > >> + 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"); >> > > -- > Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, > a Linux Foundation Collaborative Project ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 5/9] iommu: add qcom_iommu 2017-03-30 13:46 ` Rob Clark @ 2017-03-31 4:19 ` Archit Taneja 0 siblings, 0 replies; 16+ messages in thread From: Archit Taneja @ 2017-03-31 4:19 UTC (permalink / raw) To: Rob Clark Cc: iommu@lists.linux-foundation.org, Mark Rutland, linux-arm-msm, Will Deacon, Stanimir Varbanov On 3/30/2017 7:16 PM, Rob Clark wrote: > On Thu, Mar 30, 2017 at 2:19 AM, Archit Taneja <architt@codeaurora.org> wrote: >> Hi, >> >> On 03/14/2017 08:48 PM, Rob Clark wrote: >>> >>> 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 <robdclark@gmail.com> >>> Signed-off-by: Stanimir Varbanov <stanimir.varbanov@linaro.org> >>> --- >>> 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> >> >>> + >>> +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. >> >>> + 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.. 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 >> 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 > > >> Thanks, >> Archit >> >> >>> + 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"); >>> >> >> -- >> 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 majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html > -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, hosted by The Linux Foundation ^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 6/9] iommu: qcom: initialize secure page table 2017-03-14 15:18 [PATCH 0/9] iommu: add qcom_iommu for early "B" family devices (v2) Rob Clark [not found] ` <20170314151811.17234-1-robdclark-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> @ 2017-03-14 15:18 ` Rob Clark 2017-03-14 15:18 ` [PATCH 7/9] ARM64: DT: add gpu for msm8916 Rob Clark ` (2 subsequent siblings) 4 siblings, 0 replies; 16+ messages in thread From: Rob Clark @ 2017-03-14 15:18 UTC (permalink / raw) To: iommu Cc: linux-arm-msm, Robin Murphy, Will Deacon, Sricharan, Mark Rutland, Stanimir Varbanov, Rob Clark From: Stanimir Varbanov <stanimir.varbanov@linaro.org> This basically gets the secure page table size, allocates memory for secure pagetables and passes the physical address to the trusted zone. Signed-off-by: Stanimir Varbanov <stanimir.varbanov@linaro.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- drivers/iommu/qcom_iommu.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/drivers/iommu/qcom_iommu.c b/drivers/iommu/qcom_iommu.c index 6b7adbf..743a628 100644 --- a/drivers/iommu/qcom_iommu.c +++ b/drivers/iommu/qcom_iommu.c @@ -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: */ -- 2.9.3 ^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 7/9] ARM64: DT: add gpu for msm8916 2017-03-14 15:18 [PATCH 0/9] iommu: add qcom_iommu for early "B" family devices (v2) Rob Clark [not found] ` <20170314151811.17234-1-robdclark-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 2017-03-14 15:18 ` [PATCH 6/9] iommu: qcom: initialize secure page table Rob Clark @ 2017-03-14 15:18 ` Rob Clark 2017-03-14 15:18 ` [PATCH 8/9] ARM64: DT: add video codec devicetree node Rob Clark 2017-03-14 15:18 ` [PATCH 9/9] ARM64: DT: add iommu for msm8916 Rob Clark 4 siblings, 0 replies; 16+ messages in thread From: Rob Clark @ 2017-03-14 15:18 UTC (permalink / raw) To: iommu Cc: linux-arm-msm, Robin Murphy, Will Deacon, Sricharan, Mark Rutland, Stanimir Varbanov, Rob Clark Signed-off-by: Rob Clark <robdclark@gmail.com> --- arch/arm64/boot/dts/qcom/msm8916.dtsi | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi index 68a8e67..b0daf39 100644 --- a/arch/arm64/boot/dts/qcom/msm8916.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi @@ -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>, -- 2.9.3 ^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 8/9] ARM64: DT: add video codec devicetree node 2017-03-14 15:18 [PATCH 0/9] iommu: add qcom_iommu for early "B" family devices (v2) Rob Clark ` (2 preceding siblings ...) 2017-03-14 15:18 ` [PATCH 7/9] ARM64: DT: add gpu for msm8916 Rob Clark @ 2017-03-14 15:18 ` Rob Clark 2017-03-14 15:18 ` [PATCH 9/9] ARM64: DT: add iommu for msm8916 Rob Clark 4 siblings, 0 replies; 16+ messages in thread From: Rob Clark @ 2017-03-14 15:18 UTC (permalink / raw) To: iommu Cc: linux-arm-msm, Robin Murphy, Will Deacon, Sricharan, Mark Rutland, Stanimir Varbanov, Rob Clark From: Stanimir Varbanov <stanimir.varbanov@linaro.org> Signed-off-by: Stanimir Varbanov <stanimir.varbanov@linaro.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- arch/arm64/boot/dts/qcom/msm8916.dtsi | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi index b0daf39..7bcf4cd 100644 --- a/arch/arm64/boot/dts/qcom/msm8916.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi @@ -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 { -- 2.9.3 ^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 9/9] ARM64: DT: add iommu for msm8916 2017-03-14 15:18 [PATCH 0/9] iommu: add qcom_iommu for early "B" family devices (v2) Rob Clark ` (3 preceding siblings ...) 2017-03-14 15:18 ` [PATCH 8/9] ARM64: DT: add video codec devicetree node Rob Clark @ 2017-03-14 15:18 ` Rob Clark 4 siblings, 0 replies; 16+ messages in thread From: Rob Clark @ 2017-03-14 15:18 UTC (permalink / raw) To: iommu Cc: linux-arm-msm, Robin Murphy, Will Deacon, Sricharan, Mark Rutland, Stanimir Varbanov, Rob Clark Signed-off-by: Rob Clark <robdclark@gmail.com> --- arch/arm64/boot/dts/qcom/msm8916.dtsi | 57 +++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi index 7bcf4cd..8aeec6f 100644 --- a/arch/arm64/boot/dts/qcom/msm8916.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi @@ -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"; -- 2.9.3 ^ permalink raw reply related [flat|nested] 16+ messages in thread
end of thread, other threads:[~2017-03-31 4:19 UTC | newest] Thread overview: 16+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2017-03-14 15:18 [PATCH 0/9] iommu: add qcom_iommu for early "B" family devices (v2) Rob Clark [not found] ` <20170314151811.17234-1-robdclark-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 2017-03-14 15:18 ` [PATCH 1/9] firmware/qcom: add qcom_scm_restore_sec_cfg() Rob Clark 2017-03-14 15:18 ` [PATCH 2/9] firmware: qcom_scm: add two scm calls for iommu secure page table Rob Clark 2017-03-14 15:18 ` [PATCH 3/9] Docs: dt: document qcom iommu bindings Rob Clark [not found] ` <20170314151811.17234-4-robdclark-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 2017-03-23 22:21 ` Rob Herring 2017-03-24 2:45 ` Rob Clark 2017-03-27 19:10 ` Rob Herring 2017-03-14 15:18 ` [PATCH 4/9] iommu: arm-smmu: split out register defines Rob Clark 2017-03-14 15:18 ` [PATCH 5/9] iommu: add qcom_iommu Rob Clark [not found] ` <20170314151811.17234-6-robdclark-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 2017-03-30 6:19 ` Archit Taneja 2017-03-30 13:46 ` Rob Clark 2017-03-31 4:19 ` Archit Taneja 2017-03-14 15:18 ` [PATCH 6/9] iommu: qcom: initialize secure page table Rob Clark 2017-03-14 15:18 ` [PATCH 7/9] ARM64: DT: add gpu for msm8916 Rob Clark 2017-03-14 15:18 ` [PATCH 8/9] ARM64: DT: add video codec devicetree node Rob Clark 2017-03-14 15:18 ` [PATCH 9/9] ARM64: DT: add iommu for msm8916 Rob Clark
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).