1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
4 */
5
6 #include <linux/of_device.h>
7 #include <linux/qcom_scm.h>
8 #include <linux/ratelimit.h>
9
10 #include "arm-smmu.h"
11 #include "arm-smmu-qcom.h"
12
13 enum qcom_smmu_impl_reg_offset {
14 QCOM_SMMU_TBU_PWR_STATUS,
15 QCOM_SMMU_STATS_SYNC_INV_TBU_ACK,
16 QCOM_SMMU_MMU2QSS_AND_SAFE_WAIT_CNTR,
17 };
18
19 struct qcom_smmu_config {
20 const u32 *reg_offset;
21 };
22
qcom_smmu_tlb_sync_debug(struct arm_smmu_device * smmu)23 void qcom_smmu_tlb_sync_debug(struct arm_smmu_device *smmu)
24 {
25 int ret;
26 u32 tbu_pwr_status, sync_inv_ack, sync_inv_progress;
27 struct qcom_smmu *qsmmu = container_of(smmu, struct qcom_smmu, smmu);
28 const struct qcom_smmu_config *cfg;
29 static DEFINE_RATELIMIT_STATE(rs, DEFAULT_RATELIMIT_INTERVAL,
30 DEFAULT_RATELIMIT_BURST);
31
32 if (__ratelimit(&rs)) {
33 dev_err(smmu->dev, "TLB sync timed out -- SMMU may be deadlocked\n");
34
35 cfg = qsmmu->cfg;
36 if (!cfg)
37 return;
38
39 ret = qcom_scm_io_readl(smmu->ioaddr + cfg->reg_offset[QCOM_SMMU_TBU_PWR_STATUS],
40 &tbu_pwr_status);
41 if (ret)
42 dev_err(smmu->dev,
43 "Failed to read TBU power status: %d\n", ret);
44
45 ret = qcom_scm_io_readl(smmu->ioaddr + cfg->reg_offset[QCOM_SMMU_STATS_SYNC_INV_TBU_ACK],
46 &sync_inv_ack);
47 if (ret)
48 dev_err(smmu->dev,
49 "Failed to read TBU sync/inv ack status: %d\n", ret);
50
51 ret = qcom_scm_io_readl(smmu->ioaddr + cfg->reg_offset[QCOM_SMMU_MMU2QSS_AND_SAFE_WAIT_CNTR],
52 &sync_inv_progress);
53 if (ret)
54 dev_err(smmu->dev,
55 "Failed to read TCU syn/inv progress: %d\n", ret);
56
57 dev_err(smmu->dev,
58 "TBU: power_status %#x sync_inv_ack %#x sync_inv_progress %#x\n",
59 tbu_pwr_status, sync_inv_ack, sync_inv_progress);
60 }
61 }
62
63 /* Implementation Defined Register Space 0 register offsets */
64 static const u32 qcom_smmu_impl0_reg_offset[] = {
65 [QCOM_SMMU_TBU_PWR_STATUS] = 0x2204,
66 [QCOM_SMMU_STATS_SYNC_INV_TBU_ACK] = 0x25dc,
67 [QCOM_SMMU_MMU2QSS_AND_SAFE_WAIT_CNTR] = 0x2670,
68 };
69
70 static const struct qcom_smmu_config qcm2290_smmu_cfg = {
71 .reg_offset = qcom_smmu_impl0_reg_offset,
72 };
73
74 static const struct qcom_smmu_config sc7180_smmu_cfg = {
75 .reg_offset = qcom_smmu_impl0_reg_offset,
76 };
77
78 static const struct qcom_smmu_config sc7280_smmu_cfg = {
79 .reg_offset = qcom_smmu_impl0_reg_offset,
80 };
81
82 static const struct qcom_smmu_config sc8180x_smmu_cfg = {
83 .reg_offset = qcom_smmu_impl0_reg_offset,
84 };
85
86 static const struct qcom_smmu_config sc8280xp_smmu_cfg = {
87 .reg_offset = qcom_smmu_impl0_reg_offset,
88 };
89
90 static const struct qcom_smmu_config sm6125_smmu_cfg = {
91 .reg_offset = qcom_smmu_impl0_reg_offset,
92 };
93
94 static const struct qcom_smmu_config sm6350_smmu_cfg = {
95 .reg_offset = qcom_smmu_impl0_reg_offset,
96 };
97
98 static const struct qcom_smmu_config sm8150_smmu_cfg = {
99 .reg_offset = qcom_smmu_impl0_reg_offset,
100 };
101
102 static const struct qcom_smmu_config sm8250_smmu_cfg = {
103 .reg_offset = qcom_smmu_impl0_reg_offset,
104 };
105
106 static const struct qcom_smmu_config sm8350_smmu_cfg = {
107 .reg_offset = qcom_smmu_impl0_reg_offset,
108 };
109
110 static const struct qcom_smmu_config sm8450_smmu_cfg = {
111 .reg_offset = qcom_smmu_impl0_reg_offset,
112 };
113
114 static const struct of_device_id __maybe_unused qcom_smmu_impl_debug_match[] = {
115 { .compatible = "qcom,msm8998-smmu-v2" },
116 { .compatible = "qcom,qcm2290-smmu-500", .data = &qcm2290_smmu_cfg },
117 { .compatible = "qcom,sc7180-smmu-500", .data = &sc7180_smmu_cfg },
118 { .compatible = "qcom,sc7280-smmu-500", .data = &sc7280_smmu_cfg},
119 { .compatible = "qcom,sc8180x-smmu-500", .data = &sc8180x_smmu_cfg },
120 { .compatible = "qcom,sc8280xp-smmu-500", .data = &sc8280xp_smmu_cfg },
121 { .compatible = "qcom,sdm630-smmu-v2" },
122 { .compatible = "qcom,sdm845-smmu-500" },
123 { .compatible = "qcom,sm6125-smmu-500", .data = &sm6125_smmu_cfg},
124 { .compatible = "qcom,sm6350-smmu-500", .data = &sm6350_smmu_cfg},
125 { .compatible = "qcom,sm8150-smmu-500", .data = &sm8150_smmu_cfg },
126 { .compatible = "qcom,sm8250-smmu-500", .data = &sm8250_smmu_cfg },
127 { .compatible = "qcom,sm8350-smmu-500", .data = &sm8350_smmu_cfg },
128 { .compatible = "qcom,sm8450-smmu-500", .data = &sm8450_smmu_cfg },
129 { }
130 };
131
qcom_smmu_impl_data(struct arm_smmu_device * smmu)132 const void *qcom_smmu_impl_data(struct arm_smmu_device *smmu)
133 {
134 const struct of_device_id *match;
135 const struct device_node *np = smmu->dev->of_node;
136
137 match = of_match_node(qcom_smmu_impl_debug_match, np);
138 if (!match)
139 return NULL;
140
141 return match->data;
142 }
143