1e86d1aa8SWill Deacon // SPDX-License-Identifier: GPL-2.0-only 2e86d1aa8SWill Deacon /* 3e86d1aa8SWill Deacon * Copyright (c) 2019, The Linux Foundation. All rights reserved. 4e86d1aa8SWill Deacon */ 5e86d1aa8SWill Deacon 6e86d1aa8SWill Deacon #include <linux/of_device.h> 7e86d1aa8SWill Deacon #include <linux/qcom_scm.h> 8e86d1aa8SWill Deacon 9e86d1aa8SWill Deacon #include "arm-smmu.h" 10e86d1aa8SWill Deacon 11e86d1aa8SWill Deacon struct qcom_smmu { 12e86d1aa8SWill Deacon struct arm_smmu_device smmu; 13*f9081b8fSBjorn Andersson bool bypass_quirk; 14*f9081b8fSBjorn Andersson u8 bypass_cbndx; 15e86d1aa8SWill Deacon }; 16e86d1aa8SWill Deacon 17*f9081b8fSBjorn Andersson static struct qcom_smmu *to_qcom_smmu(struct arm_smmu_device *smmu) 18*f9081b8fSBjorn Andersson { 19*f9081b8fSBjorn Andersson return container_of(smmu, struct qcom_smmu, smmu); 20*f9081b8fSBjorn Andersson } 21*f9081b8fSBjorn Andersson 22e46b3c0dSJoerg Roedel static const struct of_device_id qcom_smmu_client_of_match[] __maybe_unused = { 23e86d1aa8SWill Deacon { .compatible = "qcom,adreno" }, 24e86d1aa8SWill Deacon { .compatible = "qcom,mdp4" }, 25e86d1aa8SWill Deacon { .compatible = "qcom,mdss" }, 26e86d1aa8SWill Deacon { .compatible = "qcom,sc7180-mdss" }, 27e86d1aa8SWill Deacon { .compatible = "qcom,sc7180-mss-pil" }, 28e86d1aa8SWill Deacon { .compatible = "qcom,sdm845-mdss" }, 29e86d1aa8SWill Deacon { .compatible = "qcom,sdm845-mss-pil" }, 30e86d1aa8SWill Deacon { } 31e86d1aa8SWill Deacon }; 32e86d1aa8SWill Deacon 3307a7f2caSBjorn Andersson static int qcom_smmu_cfg_probe(struct arm_smmu_device *smmu) 3407a7f2caSBjorn Andersson { 35*f9081b8fSBjorn Andersson unsigned int last_s2cr = ARM_SMMU_GR0_S2CR(smmu->num_mapping_groups - 1); 36*f9081b8fSBjorn Andersson struct qcom_smmu *qsmmu = to_qcom_smmu(smmu); 37*f9081b8fSBjorn Andersson u32 reg; 3807a7f2caSBjorn Andersson u32 smr; 3907a7f2caSBjorn Andersson int i; 4007a7f2caSBjorn Andersson 41*f9081b8fSBjorn Andersson /* 42*f9081b8fSBjorn Andersson * With some firmware versions writes to S2CR of type FAULT are 43*f9081b8fSBjorn Andersson * ignored, and writing BYPASS will end up written as FAULT in the 44*f9081b8fSBjorn Andersson * register. Perform a write to S2CR to detect if this is the case and 45*f9081b8fSBjorn Andersson * if so reserve a context bank to emulate bypass streams. 46*f9081b8fSBjorn Andersson */ 47*f9081b8fSBjorn Andersson reg = FIELD_PREP(ARM_SMMU_S2CR_TYPE, S2CR_TYPE_BYPASS) | 48*f9081b8fSBjorn Andersson FIELD_PREP(ARM_SMMU_S2CR_CBNDX, 0xff) | 49*f9081b8fSBjorn Andersson FIELD_PREP(ARM_SMMU_S2CR_PRIVCFG, S2CR_PRIVCFG_DEFAULT); 50*f9081b8fSBjorn Andersson arm_smmu_gr0_write(smmu, last_s2cr, reg); 51*f9081b8fSBjorn Andersson reg = arm_smmu_gr0_read(smmu, last_s2cr); 52*f9081b8fSBjorn Andersson if (FIELD_GET(ARM_SMMU_S2CR_TYPE, reg) != S2CR_TYPE_BYPASS) { 53*f9081b8fSBjorn Andersson qsmmu->bypass_quirk = true; 54*f9081b8fSBjorn Andersson qsmmu->bypass_cbndx = smmu->num_context_banks - 1; 55*f9081b8fSBjorn Andersson 56*f9081b8fSBjorn Andersson set_bit(qsmmu->bypass_cbndx, smmu->context_map); 57*f9081b8fSBjorn Andersson 58*f9081b8fSBjorn Andersson reg = FIELD_PREP(ARM_SMMU_CBAR_TYPE, CBAR_TYPE_S1_TRANS_S2_BYPASS); 59*f9081b8fSBjorn Andersson arm_smmu_gr1_write(smmu, ARM_SMMU_GR1_CBAR(qsmmu->bypass_cbndx), reg); 60*f9081b8fSBjorn Andersson } 61*f9081b8fSBjorn Andersson 6207a7f2caSBjorn Andersson for (i = 0; i < smmu->num_mapping_groups; i++) { 6307a7f2caSBjorn Andersson smr = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_SMR(i)); 6407a7f2caSBjorn Andersson 6507a7f2caSBjorn Andersson if (FIELD_GET(ARM_SMMU_SMR_VALID, smr)) { 6607a7f2caSBjorn Andersson smmu->smrs[i].id = FIELD_GET(ARM_SMMU_SMR_ID, smr); 6707a7f2caSBjorn Andersson smmu->smrs[i].mask = FIELD_GET(ARM_SMMU_SMR_MASK, smr); 6807a7f2caSBjorn Andersson smmu->smrs[i].valid = true; 6907a7f2caSBjorn Andersson 7007a7f2caSBjorn Andersson smmu->s2crs[i].type = S2CR_TYPE_BYPASS; 7107a7f2caSBjorn Andersson smmu->s2crs[i].privcfg = S2CR_PRIVCFG_DEFAULT; 7207a7f2caSBjorn Andersson smmu->s2crs[i].cbndx = 0xff; 7307a7f2caSBjorn Andersson } 7407a7f2caSBjorn Andersson } 7507a7f2caSBjorn Andersson 7607a7f2caSBjorn Andersson return 0; 7707a7f2caSBjorn Andersson } 7807a7f2caSBjorn Andersson 79*f9081b8fSBjorn Andersson static void qcom_smmu_write_s2cr(struct arm_smmu_device *smmu, int idx) 80*f9081b8fSBjorn Andersson { 81*f9081b8fSBjorn Andersson struct arm_smmu_s2cr *s2cr = smmu->s2crs + idx; 82*f9081b8fSBjorn Andersson struct qcom_smmu *qsmmu = to_qcom_smmu(smmu); 83*f9081b8fSBjorn Andersson u32 cbndx = s2cr->cbndx; 84*f9081b8fSBjorn Andersson u32 type = s2cr->type; 85*f9081b8fSBjorn Andersson u32 reg; 86*f9081b8fSBjorn Andersson 87*f9081b8fSBjorn Andersson if (qsmmu->bypass_quirk) { 88*f9081b8fSBjorn Andersson if (type == S2CR_TYPE_BYPASS) { 89*f9081b8fSBjorn Andersson /* 90*f9081b8fSBjorn Andersson * Firmware with quirky S2CR handling will substitute 91*f9081b8fSBjorn Andersson * BYPASS writes with FAULT, so point the stream to the 92*f9081b8fSBjorn Andersson * reserved context bank and ask for translation on the 93*f9081b8fSBjorn Andersson * stream 94*f9081b8fSBjorn Andersson */ 95*f9081b8fSBjorn Andersson type = S2CR_TYPE_TRANS; 96*f9081b8fSBjorn Andersson cbndx = qsmmu->bypass_cbndx; 97*f9081b8fSBjorn Andersson } else if (type == S2CR_TYPE_FAULT) { 98*f9081b8fSBjorn Andersson /* 99*f9081b8fSBjorn Andersson * Firmware with quirky S2CR handling will ignore FAULT 100*f9081b8fSBjorn Andersson * writes, so trick it to write FAULT by asking for a 101*f9081b8fSBjorn Andersson * BYPASS. 102*f9081b8fSBjorn Andersson */ 103*f9081b8fSBjorn Andersson type = S2CR_TYPE_BYPASS; 104*f9081b8fSBjorn Andersson cbndx = 0xff; 105*f9081b8fSBjorn Andersson } 106*f9081b8fSBjorn Andersson } 107*f9081b8fSBjorn Andersson 108*f9081b8fSBjorn Andersson reg = FIELD_PREP(ARM_SMMU_S2CR_TYPE, type) | 109*f9081b8fSBjorn Andersson FIELD_PREP(ARM_SMMU_S2CR_CBNDX, cbndx) | 110*f9081b8fSBjorn Andersson FIELD_PREP(ARM_SMMU_S2CR_PRIVCFG, s2cr->privcfg); 111*f9081b8fSBjorn Andersson arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_S2CR(idx), reg); 112*f9081b8fSBjorn Andersson } 113*f9081b8fSBjorn Andersson 114e86d1aa8SWill Deacon static int qcom_smmu_def_domain_type(struct device *dev) 115e86d1aa8SWill Deacon { 116e86d1aa8SWill Deacon const struct of_device_id *match = 117e86d1aa8SWill Deacon of_match_device(qcom_smmu_client_of_match, dev); 118e86d1aa8SWill Deacon 119e86d1aa8SWill Deacon return match ? IOMMU_DOMAIN_IDENTITY : 0; 120e86d1aa8SWill Deacon } 121e86d1aa8SWill Deacon 122e86d1aa8SWill Deacon static int qcom_sdm845_smmu500_reset(struct arm_smmu_device *smmu) 123e86d1aa8SWill Deacon { 124e86d1aa8SWill Deacon int ret; 125e86d1aa8SWill Deacon 126e86d1aa8SWill Deacon /* 127e86d1aa8SWill Deacon * To address performance degradation in non-real time clients, 128e86d1aa8SWill Deacon * such as USB and UFS, turn off wait-for-safe on sdm845 based boards, 129e86d1aa8SWill Deacon * such as MTP and db845, whose firmwares implement secure monitor 130e86d1aa8SWill Deacon * call handlers to turn on/off the wait-for-safe logic. 131e86d1aa8SWill Deacon */ 132e86d1aa8SWill Deacon ret = qcom_scm_qsmmu500_wait_safe_toggle(0); 133e86d1aa8SWill Deacon if (ret) 134e86d1aa8SWill Deacon dev_warn(smmu->dev, "Failed to turn off SAFE logic\n"); 135e86d1aa8SWill Deacon 136e86d1aa8SWill Deacon return ret; 137e86d1aa8SWill Deacon } 138e86d1aa8SWill Deacon 139e86d1aa8SWill Deacon static int qcom_smmu500_reset(struct arm_smmu_device *smmu) 140e86d1aa8SWill Deacon { 141e86d1aa8SWill Deacon const struct device_node *np = smmu->dev->of_node; 142e86d1aa8SWill Deacon 143e86d1aa8SWill Deacon arm_mmu500_reset(smmu); 144e86d1aa8SWill Deacon 145e86d1aa8SWill Deacon if (of_device_is_compatible(np, "qcom,sdm845-smmu-500")) 146e86d1aa8SWill Deacon return qcom_sdm845_smmu500_reset(smmu); 147e86d1aa8SWill Deacon 148e86d1aa8SWill Deacon return 0; 149e86d1aa8SWill Deacon } 150e86d1aa8SWill Deacon 151e86d1aa8SWill Deacon static const struct arm_smmu_impl qcom_smmu_impl = { 15207a7f2caSBjorn Andersson .cfg_probe = qcom_smmu_cfg_probe, 153e86d1aa8SWill Deacon .def_domain_type = qcom_smmu_def_domain_type, 154e86d1aa8SWill Deacon .reset = qcom_smmu500_reset, 155*f9081b8fSBjorn Andersson .write_s2cr = qcom_smmu_write_s2cr, 156e86d1aa8SWill Deacon }; 157e86d1aa8SWill Deacon 158e86d1aa8SWill Deacon struct arm_smmu_device *qcom_smmu_impl_init(struct arm_smmu_device *smmu) 159e86d1aa8SWill Deacon { 160e86d1aa8SWill Deacon struct qcom_smmu *qsmmu; 161e86d1aa8SWill Deacon 162e86d1aa8SWill Deacon qsmmu = devm_kzalloc(smmu->dev, sizeof(*qsmmu), GFP_KERNEL); 163e86d1aa8SWill Deacon if (!qsmmu) 164e86d1aa8SWill Deacon return ERR_PTR(-ENOMEM); 165e86d1aa8SWill Deacon 166e86d1aa8SWill Deacon qsmmu->smmu = *smmu; 167e86d1aa8SWill Deacon 168e86d1aa8SWill Deacon qsmmu->smmu.impl = &qcom_smmu_impl; 169e86d1aa8SWill Deacon devm_kfree(smmu->dev, smmu); 170e86d1aa8SWill Deacon 171e86d1aa8SWill Deacon return &qsmmu->smmu; 172e86d1aa8SWill Deacon } 173