xref: /wlan-dirver/qca-wifi-host-cmn/hif/src/sdio/hif_diag_reg_access.c (revision 11f5a63a6cbdda84849a730de22f0a71e635d58c)
1 /*
2  * Copyright (c) 2013-2019 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 #include "hif_sdio_dev.h"
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