1 /*
2 * Copyright (c) 2013-2014, 2016-2018, 2020 The Linux Foundation. All rights reserved.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for
5 * any purpose with or without fee is hereby granted, provided that the
6 * above copyright notice and this permission notice appear in all
7 * copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 * PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include "hif_io32.h"
20 #include "hif_debug.h"
21 #include "mp_dev.h"
22
23 /*chaninfo*/
24 #define CHANINFOMEM_S2_READ_MASK 0x00000008
25 #define CHANINFO_CTRL_CAPTURE_CHAN_INFO_MASK 0x00000001
26 #define CHANINFO_CTRL_CHANINFOMEM_BW_MASK 0x00000030
27 #define MULTICHAIN_ENABLE_RX_CHAIN_MASK_MASK 0x00000007
28
29 /*agc*/
30 #define GAINS_MIN_OFFSETS_CF_AGC_HIST_ENABLE_MASK 0x00040000
31 #define GAINS_MIN_OFFSETS_CF_AGC_HIST_GC_MASK 0x00080000
32 #define GAINS_MIN_OFFSETS_CF_AGC_HIST_VOTING_MASK 0x00100000
33 #define GAINS_MIN_OFFSETS_CF_AGC_HIST_PHY_ERR_MASK 0x00200000
34 #define AGC_HISTORY_DUMP_MASK (\
35 GAINS_MIN_OFFSETS_CF_AGC_HIST_ENABLE_MASK| \
36 GAINS_MIN_OFFSETS_CF_AGC_HIST_GC_MASK| \
37 GAINS_MIN_OFFSETS_CF_AGC_HIST_VOTING_MASK| \
38 GAINS_MIN_OFFSETS_CF_AGC_HIST_PHY_ERR_MASK \
39 )
40
41 #define BB_chaninfo_ctrl 0x1a370
42 #define BB_multichain_enable 0x1a2a0
43 #define BB_chn_tables_intf_addr 0x19894
44 #define BB_chn1_tables_intf_addr 0x1a894
45 #define BB_chn_tables_intf_data 0x19898
46 #define BB_chn1_tables_intf_data 0x1a898
47 #define BB_gains_min_offsets 0x19e08
48 #define BB_chaninfo_tab_b0 0x03200
49 #define BB_chaninfo_tab_b1 0x03300
50 #define BB_watchdog_status 0x1a7c0
51 #define BB_watchdog_ctrl_1 0x1a7c4
52 #define BB_watchdog_ctrl_2 0x1a7c8
53 #define BB_watchdog_status_B 0x1a7e0
54
55
56 #define PHY_BB_CHN_TABLES_INTF_ADDR 0x19894
57 #define PHY_BB_CHN_TABLES_INTF_DATA 0x19898
58
59 #define PHY_BB_CHN1_TABLES_INTF_ADDR 0x1a894
60 #define PHY_BB_CHN1_TABLES_INTF_DATA 0x1a898
61
62
63 struct priv_ctrl_ctx {
64 uint32_t chaninfo_ctrl_orig;
65 uint32_t gain_min_offsets_orig;
66 uint32_t anyreg_start;
67 uint32_t anyreg_len;
68 };
69
70 static struct priv_ctrl_ctx g_priv_dump_ctx;
71
set_target_reg_bits(struct hif_softc * scn,void __iomem * mem,uint32_t reg,uint32_t bitmask,uint32_t val)72 static inline void set_target_reg_bits(struct hif_softc *scn,
73 void __iomem *mem, uint32_t reg,
74 uint32_t bitmask, uint32_t val)
75 {
76 uint32_t value = hif_read32_mb(scn, mem + (reg));
77 uint32_t shift = 0;
78
79 value &= ~(bitmask);
80 while (!((bitmask >> shift) & 0x01))
81 shift++;
82
83 value |= (((val) << shift) & (bitmask));
84 hif_write32_mb(scn, mem + (reg), value);
85 }
86
get_target_reg_bits(struct hif_softc * scn,void __iomem * mem,uint32_t reg,uint32_t bitmask)87 static inline uint32_t get_target_reg_bits(struct hif_softc *scn,
88 void __iomem *mem,
89 uint32_t reg, uint32_t bitmask)
90 {
91 uint32_t value = hif_read32_mb(scn, mem + (reg));
92 uint32_t shift = 0;
93
94 while (!((bitmask >> shift) & 0x01))
95 shift++;
96
97 return (value >> shift) & bitmask;
98 }
99
priv_start_cap_chaninfo(struct hif_softc * scn)100 void priv_start_cap_chaninfo(struct hif_softc *scn)
101 {
102 set_target_reg_bits(scn, scn->mem, BB_chaninfo_ctrl,
103 CHANINFO_CTRL_CAPTURE_CHAN_INFO_MASK, 1);
104 }
105
priv_start_agc(struct hif_softc * scn)106 void priv_start_agc(struct hif_softc *scn)
107 {
108 g_priv_dump_ctx.gain_min_offsets_orig =
109 hif_read32_mb(scn, scn->mem + BB_gains_min_offsets);
110 set_target_reg_bits(scn, scn->mem, BB_gains_min_offsets,
111 AGC_HISTORY_DUMP_MASK,
112 0x0f);
113 }
114
priv_stop_agc(struct hif_softc * scn)115 static void priv_stop_agc(struct hif_softc *scn)
116 {
117 set_target_reg_bits(scn, scn->mem, BB_gains_min_offsets,
118 AGC_HISTORY_DUMP_MASK,
119 0);
120 }
121
priv_dump_chaninfo(struct hif_softc * scn)122 void priv_dump_chaninfo(struct hif_softc *scn)
123 {
124 uint32_t bw, val;
125 uint32_t len, i, tmp;
126 uint32_t chain_mask;
127 uint32_t chain0, chain1;
128
129 chain_mask =
130 get_target_reg_bits(scn, scn->mem, BB_multichain_enable,
131 MULTICHAIN_ENABLE_RX_CHAIN_MASK_MASK);
132 chain0 = chain_mask & 1;
133 chain1 = chain_mask & 2;
134
135 hif_info("E");
136 bw = get_target_reg_bits(scn, scn->mem, BB_chaninfo_ctrl,
137 CHANINFO_CTRL_CHANINFOMEM_BW_MASK);
138
139 if (bw == 0)
140 len = 53;
141 else if (bw == 1)
142 len = 57;
143 else if (bw == 2)
144 len = 59 * 2 - 1;
145 else
146 len = 60 * 2 + 61 * 2;
147
148 /*
149 * each tone is 16 bit valid, write to 32bit buffer each.
150 * bw==0(legacy20): 53 tones.
151 * bw==1(ht/vht20): 57 tones.
152 * bw==2(ht/vht40): 59+58 tones.
153 * bw==3(vht80): 60*2+61*2 tones.
154 */
155
156 if (chain0) {
157 hif_write32_mb(scn, scn->mem + BB_chn_tables_intf_addr,
158 0x80003200);
159 }
160 if (chain1) {
161 hif_write32_mb(scn, scn->mem + BB_chn1_tables_intf_addr,
162 0x80003200);
163 }
164
165 set_target_reg_bits(scn, scn->mem, BB_chaninfo_ctrl,
166 CHANINFOMEM_S2_READ_MASK, 0);
167
168 if (chain0) {
169 if (bw < 2) {
170 len = (bw == 0) ? 53 : 57;
171 for (i = 0; i < len; i++) {
172 val = hif_read32_mb(scn, scn->mem +
173 BB_chn_tables_intf_data) &
174 0x0000ffff;
175 qdf_debug("0x%x\t", val);
176 if (i % 4 == 0)
177 qdf_debug("\n");
178 }
179 } else {
180 len = (bw == 2) ? 59 : 60;
181 for (i = 0; i < len; i++) {
182 tmp = hif_read32_mb(scn, scn->mem +
183 BB_chn_tables_intf_data);
184 qdf_debug("0x%x\t", ((tmp >> 16) & 0x0000ffff));
185 qdf_debug("0x%x\t", (tmp & 0x0000ffff));
186 if (i % 2 == 0)
187 qdf_debug("\n");
188 }
189 if (bw > 2) {
190 /* bw == 3 for vht80 */
191 hif_write32_mb(scn, scn->mem +
192 BB_chn_tables_intf_addr,
193 0x80003300);
194 len = 61;
195 for (i = 0; i < len; i++) {
196 tmp = hif_read32_mb(scn, scn->mem +
197 BB_chn_tables_intf_data);
198 qdf_debug("0x%x\t",
199 ((tmp >> 16) & 0x0000ffff));
200 qdf_debug("0x%x\t", (tmp & 0x0000ffff));
201 if (i % 2 == 0)
202 qdf_debug("\n");
203 }
204 }
205 }
206 }
207 if (chain1) {
208 if (bw < 2) {
209 len = (bw == 0) ? 53 : 57;
210 for (i = 0; i < len; i++) {
211 val =
212 hif_read32_mb(scn, scn->mem +
213 BB_chn1_tables_intf_data) &
214 0x0000ffff;
215 qdf_debug("0x%x\t", val);
216 if (i % 4 == 0)
217 qdf_debug("\n");
218 }
219 } else {
220 len = (bw == 2) ? 59 : 60;
221 for (i = 0; i < len; i++) {
222 tmp =
223 hif_read32_mb(scn, scn->mem +
224 BB_chn1_tables_intf_data);
225 qdf_debug("0x%x", (tmp >> 16) & 0x0000ffff);
226 qdf_debug("0x%x", tmp & 0x0000ffff);
227 if (i % 2 == 0)
228 qdf_debug("\n");
229 }
230 if (bw > 2) {
231 /* bw == 3 for vht80 */
232 hif_write32_mb(scn, scn->mem +
233 BB_chn1_tables_intf_addr,
234 0x80003300);
235 len = 61;
236 for (i = 0; i < len; i++) {
237 tmp =
238 hif_read32_mb(scn, scn->mem +
239 BB_chn1_tables_intf_data);
240 qdf_debug("0x%x\t",
241 ((tmp >> 16) & 0x0000ffff));
242 qdf_debug("0x%x\t", (tmp & 0x0000ffff));
243 if (i % 2 == 0)
244 qdf_debug("\n");
245 }
246 }
247 }
248 }
249 hif_info("X");
250 }
251
priv_dump_agc(struct hif_softc * scn)252 void priv_dump_agc(struct hif_softc *scn)
253 {
254 int i, len = 30; /* check this value for Rome and Peregrine */
255 uint32_t chain0, chain1, chain_mask, val;
256
257 if (Q_TARGET_ACCESS_BEGIN(scn) < 0)
258 return;
259
260 chain_mask =
261 get_target_reg_bits(scn, scn->mem, BB_multichain_enable,
262 MULTICHAIN_ENABLE_RX_CHAIN_MASK_MASK);
263 chain0 = chain_mask & 1;
264 chain1 = chain_mask & 2;
265
266 len = len << 1; /* each agc item is 64bit, total*2 */
267 priv_stop_agc(scn);
268
269 set_target_reg_bits(scn, scn->mem, BB_chaninfo_ctrl,
270 CHANINFOMEM_S2_READ_MASK, 0);
271
272 hif_info("AGC history buffer dump: E");
273 if (chain0) {
274 for (i = 0; i < len; i++) {
275 hif_write32_mb(scn, scn->mem +
276 PHY_BB_CHN_TABLES_INTF_ADDR,
277 BB_chaninfo_tab_b0 + i * 4);
278 val = hif_read32_mb(scn, scn->mem +
279 PHY_BB_CHN_TABLES_INTF_DATA);
280 qdf_debug("0x%x\t", val);
281 if (i % 4 == 0)
282 qdf_debug("\n");
283 }
284 }
285 if (chain1) {
286 for (i = 0; i < len; i++) {
287 hif_write32_mb(scn, scn->mem +
288 PHY_BB_CHN1_TABLES_INTF_ADDR,
289 BB_chaninfo_tab_b0 + i * 4);
290 val = hif_read32_mb(scn, scn->mem +
291 PHY_BB_CHN1_TABLES_INTF_DATA);
292 qdf_debug("0x%x\t", val);
293 if (i % 4 == 0)
294 qdf_debug("\n");
295 }
296 }
297 hif_info("AGC history buffer dump X");
298 /* restore original value */
299 hif_write32_mb(scn, scn->mem + BB_gains_min_offsets,
300 g_priv_dump_ctx.gain_min_offsets_orig);
301
302 Q_TARGET_ACCESS_END(scn);
303
304 }
305
priv_dump_bbwatchdog(struct hif_softc * scn)306 void priv_dump_bbwatchdog(struct hif_softc *scn)
307 {
308 uint32_t val;
309
310 hif_info("BB watchdog dump E");
311 val = hif_read32_mb(scn, scn->mem + BB_watchdog_status);
312 qdf_debug("0x%x\t", val);
313 val = hif_read32_mb(scn, scn->mem + BB_watchdog_ctrl_1);
314 qdf_debug("0x%x\t", val);
315 val = hif_read32_mb(scn, scn->mem + BB_watchdog_ctrl_2);
316 qdf_debug("0x%x\t", val);
317 val = hif_read32_mb(scn, scn->mem + BB_watchdog_status_B);
318 qdf_debug("0x%x", val);
319 hif_info("BB watchdog dump X");
320 }
321