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