1 /* 2 * Copyright (c) 2013-2014, 2016-2018 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 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 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 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 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 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 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_TRACE("%s: E", __func__); 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\n", (tmp >> 16) & 0x0000ffff); 226 qdf_debug("0x%x\n", 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_TRACE("%s: X", __func__); 250 } 251 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_TRACE("%s: AGC history buffer dump: E", __func__); 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_TRACE("%s: AGC history buffer dump X", __func__); 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 306 void priv_dump_bbwatchdog(struct hif_softc *scn) 307 { 308 uint32_t val; 309 310 HIF_TRACE("%s: BB watchdog dump E", __func__); 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_TRACE("%s: BB watchdog dump X", __func__); 320 } 321