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