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