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 
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 
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