1 /* 2 * Copyright (c) 2013-2019 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for 6 * any purpose with or without fee is hereby granted, provided that the 7 * above copyright notice and this permission notice appear in all 8 * copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include "athdefs.h" 21 #include "a_types.h" 22 #include "a_osapi.h" 23 #define ATH_MODULE_NAME hif 24 #include "a_debug.h" 25 26 #include "targaddrs.h" 27 #include "hif.h" 28 #include "if_sdio.h" 29 #include "regtable_sdio.h" 30 #include "hif_sdio_dev.h" 31 #include "qdf_module.h" 32 33 #define CPU_DBG_SEL_ADDRESS 0x00000483 34 #define CPU_DBG_ADDRESS 0x00000484 35 #define WORD_NON_ALIGNMENT_MASK 0x03 36 37 /** 38 * hif_ar6000_set_address_window_register() - set the window address register 39 * (using 4-byte register access). 40 * @hif_device: hif context 41 * @register_addr: register address 42 * @addr: addr 43 * 44 * This mitigates host interconnect issues with non-4byte aligned bus requests, 45 * some interconnects use bus adapters that impose strict limitations. 46 * Since diag window access is not intended for performance critical operations, 47 * the 4byte mode should be satisfactory as it generates 4X the bus activity. 48 * 49 * Return: QDF_STATUS_SUCCESS for success. 50 */ 51 static 52 QDF_STATUS hif_ar6000_set_address_window_register( 53 struct hif_sdio_dev *hif_device, 54 uint32_t register_addr, 55 uint32_t addr) 56 { 57 QDF_STATUS status; 58 static uint32_t address; 59 60 address = addr; 61 /*AR6320,just write the 4-byte address to window register*/ 62 status = hif_read_write(hif_device, 63 register_addr, 64 (char *) (&address), 65 4, HIF_WR_SYNC_BYTE_INC, NULL); 66 67 if (status != QDF_STATUS_SUCCESS) { 68 AR_DEBUG_PRINTF(ATH_LOG_ERR, 69 ("Cannot write 0x%x to window reg: 0x%X\n", 70 addr, register_addr)); 71 return status; 72 } 73 74 return QDF_STATUS_SUCCESS; 75 } 76 77 /** 78 * hif_diag_read_access() - Read from the AR6000 through its diagnostic window. 79 * @hif_ctx: hif context 80 * @address: address 81 * @data: data 82 * 83 * No cooperation from the Target is required for this. 84 * 85 * Return: QDF_STATUS_SUCCESS for success. 86 */ 87 QDF_STATUS hif_diag_read_access(struct hif_opaque_softc *hif_ctx, 88 uint32_t address, 89 uint32_t *data) 90 { 91 QDF_STATUS status; 92 static uint32_t readvalue; 93 struct hif_sdio_softc *scn = HIF_GET_SDIO_SOFTC(hif_ctx); 94 struct hif_sdio_dev *hif_device = scn->hif_handle; 95 96 if (address & WORD_NON_ALIGNMENT_MASK) { 97 AR_DEBUG_PRINTF(ATH_LOG_ERR, 98 ("[%s]addr is not 4 bytes align.addr[0x%08x]\n", 99 __func__, address)); 100 return QDF_STATUS_E_FAILURE; 101 } 102 103 /* set window register to start read cycle */ 104 status = hif_ar6000_set_address_window_register(hif_device, 105 WINDOW_READ_ADDR_ADDRESS, 106 address); 107 108 if (status != QDF_STATUS_SUCCESS) 109 return status; 110 111 /* read the data */ 112 status = hif_read_write(hif_device, 113 WINDOW_DATA_ADDRESS, 114 (char *) &readvalue, 115 sizeof(uint32_t), HIF_RD_SYNC_BYTE_INC, NULL); 116 if (status != QDF_STATUS_SUCCESS) { 117 AR_DEBUG_PRINTF(ATH_LOG_ERR, 118 ("Cannot read from WINDOW_DATA_ADDRESS\n")); 119 return status; 120 } 121 122 *data = readvalue; 123 return status; 124 } 125 126 /** 127 * hif_diag_write_access() - Write to the AR6000 through its diagnostic window. 128 * @hif_ctx: hif context 129 * @address: address 130 * @data: data 131 * 132 * No cooperation from the Target is required for this. 133 * 134 * Return: QDF_STATUS_SUCCESS for success. 135 */ 136 QDF_STATUS hif_diag_write_access(struct hif_opaque_softc *hif_ctx, 137 uint32_t address, uint32_t data) 138 { 139 QDF_STATUS status; 140 static uint32_t write_value; 141 struct hif_sdio_softc *scn = HIF_GET_SDIO_SOFTC(hif_ctx); 142 struct hif_sdio_dev *hif_device = scn->hif_handle; 143 144 if (address & WORD_NON_ALIGNMENT_MASK) { 145 AR_DEBUG_PRINTF(ATH_LOG_ERR, 146 ("[%s]addr is not 4 bytes align.addr[0x%08x]\n", 147 __func__, address)); 148 return QDF_STATUS_E_FAILURE; 149 } 150 151 write_value = data; 152 153 /* set write data */ 154 status = hif_read_write(hif_device, 155 WINDOW_DATA_ADDRESS, 156 (char *) &write_value, 157 sizeof(uint32_t), HIF_WR_SYNC_BYTE_INC, NULL); 158 if (status != QDF_STATUS_SUCCESS) { 159 AR_DEBUG_PRINTF(ATH_LOG_ERR, 160 ("Cannot write 0x%x to WINDOW_DATA_ADDRESS\n", 161 data)); 162 return status; 163 } 164 165 /* set window register, which starts the write cycle */ 166 return hif_ar6000_set_address_window_register(hif_device, 167 WINDOW_WRITE_ADDR_ADDRESS, 168 address); 169 } 170 171 /** 172 * hif_diag_write_mem() - Write a block data to the AR6000 through its 173 * diagnostic window. 174 * @scn: hif context 175 * @address: address 176 * @data: data 177 * @nbytes: nbytes 178 * 179 * This function may take some time. 180 * No cooperation from the Target is required for this. 181 * 182 * Return: QDF_STATUS_SUCCESS for success. 183 */ 184 QDF_STATUS hif_diag_write_mem(struct hif_opaque_softc *scn, uint32_t address, 185 uint8_t *data, int nbytes) 186 { 187 QDF_STATUS status; 188 int32_t i; 189 uint32_t tmp_data; 190 191 if ((address & WORD_NON_ALIGNMENT_MASK) || 192 (nbytes & WORD_NON_ALIGNMENT_MASK)) { 193 AR_DEBUG_PRINTF(ATH_LOG_ERR, 194 ("[%s]addr or length is not 4 bytes align.addr[0x%08x] len[0x%08x]\n", 195 __func__, address, nbytes)); 196 return QDF_STATUS_E_FAILURE; 197 } 198 199 for (i = 0; i < nbytes; i += 4) { 200 tmp_data = 201 data[i] | (data[i + 1] << 8) | (data[i + 2] << 16) | 202 (data[i + 3] << 24); 203 status = hif_diag_write_access(scn, address + i, tmp_data); 204 if (status != QDF_STATUS_SUCCESS) { 205 AR_DEBUG_PRINTF(ATH_LOG_ERR, 206 ("Diag Write mem failed.addr[0x%08x] value[0x%08x]\n", 207 address + i, tmp_data)); 208 return status; 209 } 210 } 211 212 return QDF_STATUS_SUCCESS; 213 } 214 215 /** 216 * hif_diag_read_mem() - Read a block data to the AR6000 through its diagnostic 217 * window. 218 * @scn: hif context 219 * @address: target address 220 * @data: data 221 * @nbytes: nbytes 222 * 223 * This function may take some time. 224 * No cooperation from the Target is required for this. 225 * 226 * Return: QDF_STATUS_SUCCESS for success. 227 */ 228 QDF_STATUS hif_diag_read_mem(struct hif_opaque_softc *scn, 229 uint32_t address, uint8_t *data, 230 int nbytes) 231 { 232 QDF_STATUS status; 233 int32_t i; 234 uint32_t tmp_data; 235 236 if ((address & WORD_NON_ALIGNMENT_MASK) || 237 (nbytes & WORD_NON_ALIGNMENT_MASK)) { 238 AR_DEBUG_PRINTF(ATH_LOG_ERR, 239 ("[%s]addr or length is not 4 bytes align.addr[0x%08x] len[0x%08x]\n", 240 __func__, address, nbytes)); 241 return QDF_STATUS_E_FAILURE; 242 } 243 244 for (i = 0; i < nbytes; i += 4) { 245 status = hif_diag_read_access(scn, address + i, &tmp_data); 246 if (status != QDF_STATUS_SUCCESS) { 247 AR_DEBUG_PRINTF(ATH_LOG_ERR, 248 ("Diag Write mem failed.addr[0x%08x] value[0x%08x]\n", 249 address + i, tmp_data)); 250 return status; 251 } 252 data[i] = tmp_data & 0xff; 253 data[i + 1] = tmp_data >> 8 & 0xff; 254 data[i + 2] = tmp_data >> 16 & 0xff; 255 data[i + 3] = tmp_data >> 24 & 0xff; 256 } 257 258 return QDF_STATUS_SUCCESS; 259 } 260 qdf_export_symbol(hif_diag_read_mem); 261 262 /** 263 * hif_ar6k_read_target_register() - call to read target register values 264 * @hif_device: hif context 265 * @regsel: register selection 266 * @regval: reg value 267 * 268 * Return: QDF_STATUS_SUCCESS for success. 269 */ 270 static QDF_STATUS hif_ar6k_read_target_register(struct hif_sdio_dev *hif_device, 271 int regsel, uint32_t *regval) 272 { 273 QDF_STATUS status; 274 char vals[4]; 275 char register_selection[4]; 276 277 register_selection[0] = regsel & 0xff; 278 register_selection[1] = regsel & 0xff; 279 register_selection[2] = regsel & 0xff; 280 register_selection[3] = regsel & 0xff; 281 status = hif_read_write(hif_device, CPU_DBG_SEL_ADDRESS, 282 register_selection, 4, 283 HIF_WR_SYNC_BYTE_FIX, NULL); 284 285 if (status != QDF_STATUS_SUCCESS) { 286 AR_DEBUG_PRINTF(ATH_LOG_ERR, 287 ("Cannot write CPU_DBG_SEL (%d)\n", regsel)); 288 return status; 289 } 290 291 status = hif_read_write(hif_device, 292 CPU_DBG_ADDRESS, 293 (char *) vals, 294 sizeof(vals), HIF_RD_SYNC_BYTE_INC, NULL); 295 if (status != QDF_STATUS_SUCCESS) { 296 AR_DEBUG_PRINTF(ATH_LOG_ERR, 297 ("Cannot read from CPU_DBG_ADDRESS\n")); 298 return status; 299 } 300 301 *regval = vals[0] << 0 | vals[1] << 8 | 302 vals[2] << 16 | vals[3] << 24; 303 304 return status; 305 } 306 307 /** 308 * hif_ar6k_fetch_target_regs() - call to fetch target reg values 309 * @hif_device: hif context 310 * @targregs: target regs 311 * 312 * Return: None 313 */ 314 void hif_ar6k_fetch_target_regs(struct hif_sdio_dev *hif_device, 315 uint32_t *targregs) 316 { 317 int i; 318 uint32_t val; 319 320 for (i = 0; i < AR6003_FETCH_TARG_REGS_COUNT; i++) { 321 val = 0xffffffff; 322 hif_ar6k_read_target_register(hif_device, i, &val); 323 targregs[i] = val; 324 } 325 } 326