forked from Minki/linux
d100ff3843
The modem remote processor has two access paths to DDR. One path is directly connected to DDR and another path goes through an SMMU. The SMMU path is configured to be a direct mapping because it's used by various peripherals in the modem subsystem. Typically this direct mapping is configured statically at EL2 by QHEE (Qualcomm's Hypervisor Execution Environment) before the kernel is entered. In certain firmware configuration, especially when the kernel is already in full control of the SMMU, defer programming the modem SIDs to the kernel. Let's add compatibles here so that we can have the kernel program the SIDs for the modem in these cases. Signed-off-by: Sibi Sankar <sibis@codeaurora.org> Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org> Reviewed-by: Stephen Boyd <swboyd@chromium.org> Link: https://lore.kernel.org/r/20200511175532.25874-1-sibis@codeaurora.org Signed-off-by: Will Deacon <will@kernel.org>
83 lines
1.9 KiB
C
83 lines
1.9 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
|
|
*/
|
|
|
|
#include <linux/of_device.h>
|
|
#include <linux/qcom_scm.h>
|
|
|
|
#include "arm-smmu.h"
|
|
|
|
struct qcom_smmu {
|
|
struct arm_smmu_device smmu;
|
|
};
|
|
|
|
static const struct of_device_id qcom_smmu_client_of_match[] = {
|
|
{ .compatible = "qcom,adreno" },
|
|
{ .compatible = "qcom,mdp4" },
|
|
{ .compatible = "qcom,mdss" },
|
|
{ .compatible = "qcom,sc7180-mdss" },
|
|
{ .compatible = "qcom,sc7180-mss-pil" },
|
|
{ .compatible = "qcom,sdm845-mdss" },
|
|
{ .compatible = "qcom,sdm845-mss-pil" },
|
|
{ }
|
|
};
|
|
|
|
static int qcom_smmu_def_domain_type(struct device *dev)
|
|
{
|
|
const struct of_device_id *match =
|
|
of_match_device(qcom_smmu_client_of_match, dev);
|
|
|
|
return match ? IOMMU_DOMAIN_IDENTITY : 0;
|
|
}
|
|
|
|
static int qcom_sdm845_smmu500_reset(struct arm_smmu_device *smmu)
|
|
{
|
|
int ret;
|
|
|
|
/*
|
|
* To address performance degradation in non-real time clients,
|
|
* such as USB and UFS, turn off wait-for-safe on sdm845 based boards,
|
|
* such as MTP and db845, whose firmwares implement secure monitor
|
|
* call handlers to turn on/off the wait-for-safe logic.
|
|
*/
|
|
ret = qcom_scm_qsmmu500_wait_safe_toggle(0);
|
|
if (ret)
|
|
dev_warn(smmu->dev, "Failed to turn off SAFE logic\n");
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int qcom_smmu500_reset(struct arm_smmu_device *smmu)
|
|
{
|
|
const struct device_node *np = smmu->dev->of_node;
|
|
|
|
arm_mmu500_reset(smmu);
|
|
|
|
if (of_device_is_compatible(np, "qcom,sdm845-smmu-500"))
|
|
return qcom_sdm845_smmu500_reset(smmu);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct arm_smmu_impl qcom_smmu_impl = {
|
|
.def_domain_type = qcom_smmu_def_domain_type,
|
|
.reset = qcom_smmu500_reset,
|
|
};
|
|
|
|
struct arm_smmu_device *qcom_smmu_impl_init(struct arm_smmu_device *smmu)
|
|
{
|
|
struct qcom_smmu *qsmmu;
|
|
|
|
qsmmu = devm_kzalloc(smmu->dev, sizeof(*qsmmu), GFP_KERNEL);
|
|
if (!qsmmu)
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
qsmmu->smmu = *smmu;
|
|
|
|
qsmmu->smmu.impl = &qcom_smmu_impl;
|
|
devm_kfree(smmu->dev, smmu);
|
|
|
|
return &qsmmu->smmu;
|
|
}
|