xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/rockchip_wlan/rtl8822bs/hal/rtl8822b/sdio/rtl8822bs_io.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /******************************************************************************
2  *
3  * Copyright(c) 2015 - 2018 Realtek Corporation.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of version 2 of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12  * more details.
13  *
14  *****************************************************************************/
15 #define _RTL8822BS_IO_C_
16 
17 #include <drv_types.h>		/* PADAPTER and etc. */
18 #include <hal_data.h>		/* HAL_DATA_TYPE */
19 #include <rtw_sdio.h>		/* rtw_sdio_write_cmd53() */
20 #include <sdio_ops_linux.h>	/* SDIO_ERR_VAL8 and etc. */
21 #include "rtl8822bs.h"		/* rtl8822bs_get_interrupt(), rtl8822bs_clear_interrupt() and etc. */
22 #include "../../hal_halmac.h"	/* rtw_halmac_sdio_get_rx_addr() */
23 
24 
25 /*
26  * For Core I/O API
27  */
28 
sdio_f0_read8(struct intf_hdl * pintfhdl,u32 addr)29 static u8 sdio_f0_read8(struct intf_hdl *pintfhdl, u32 addr)
30 {
31 	struct dvobj_priv *d;
32 	u8 val = 0;
33 	u8 ret;
34 
35 
36 	d = pintfhdl->pintf_dev;
37 	ret = rtw_sdio_f0_read(d, addr, &val, 1);
38 	if (_FAIL == ret)
39 		RTW_ERR("%s: Read f0 register(0x%x) FAIL!\n",
40 			__FUNCTION__, addr);
41 
42 	return val;
43 }
44 
45 /*
46  * Description:
47  *	Read from RX FIFO
48  *	Round read size to block size,
49  *	and make sure data transfer will be done in one command.
50  *
51  * Parameters:
52  *	d		a pointer of dvobj_priv
53  *	addr		not use
54  *	cnt		size to write
55  *	mem		buffer to write
56  *
57  * Return:
58  *	_SUCCESS(1)	Success
59  *	_FAIL(0)	Fail
60  */
rtl8822bs_read_port(struct dvobj_priv * d,u32 cnt,u8 * mem)61 u32 rtl8822bs_read_port(struct dvobj_priv *d, u32 cnt, u8 *mem)
62 {
63 	struct _ADAPTER *adapter;
64 	struct hal_com_data *hal;
65 	u32 rxaddr;
66 	void *buf;
67 	size_t buflen;
68 	u32 ret;
69 
70 
71 	adapter = dvobj_get_primary_adapter(d);
72 	hal = GET_HAL_DATA(adapter);
73 
74 	rxaddr = rtw_halmac_sdio_get_rx_addr(d, &hal->SdioRxFIFOCnt);
75 	buf = mem;
76 
77 	/* align size to guarantee I/O would be done in one command */
78 	buflen = rtw_sdio_cmd53_align_size(d, cnt);
79 	if (buflen != cnt) {
80 		buf = rtw_zmalloc(buflen);
81 		if (!buf)
82 			return _FAIL;
83 	}
84 
85 	ret = rtw_sdio_read_cmd53(d, rxaddr, buf, buflen);
86 
87 	if (buflen != cnt) {
88 		_rtw_memcpy(mem, buf, cnt);
89 		rtw_mfree(buf, buflen);
90 	}
91 
92 	return ret;
93 }
94 
95 /*
96  * Description:
97  *	Read from RX FIFO
98  *	Round read size to block size,
99  *	and make sure data transfer will be done in one command.
100  *
101  * Parameters:
102  *	pintfhdl	a pointer of intf_hdl
103  *	addr		port ID
104  *	cnt		size to read
105  *	mem		struct recv_buf*
106  *
107  * Return:
108  *	_SUCCESS(1)	Success
109  *	_FAIL(0)	Fail
110  */
sdio_read_port(struct intf_hdl * pintfhdl,u32 addr,u32 cnt,u8 * mem)111 static u32 sdio_read_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *mem)
112 {
113 	struct recv_buf *recvbuf;
114 
115 
116 	recvbuf = (struct recv_buf *)mem;
117 	return rtl8822bs_read_port(pintfhdl->pintf_dev, cnt, recvbuf->pbuf);
118 }
119 
120 /*
121  * Description:
122  *	Write to TX FIFO
123  *	Align write size to block size,
124  *	and check enough FIFO size to write.
125  *
126  * Parameters:
127  *	d		a pointer of dvobj_priv
128  *	addr		not use
129  *	cnt		size to write
130  *	mem		buffer to write
131  *
132  * Return:
133  *	_SUCCESS(1)	Success
134  *	_FAIL(0)	Fail
135  */
rtl8822bs_write_port(struct dvobj_priv * d,u32 cnt,u8 * mem)136 u32 rtl8822bs_write_port(struct dvobj_priv *d, u32 cnt, u8 *mem)
137 {
138 	u32 txaddr, txsize;
139 	u32 ret = _FAIL;
140 
141 
142 	txaddr = rtw_halmac_sdio_get_tx_addr(d, mem, cnt);
143 	if (!txaddr)
144 		goto exit;
145 	/*
146 	 * Align size to SDIO IC excpeted,
147 	 * and this would be done by calling halmac function later.
148 	 */
149 	cnt = _RND4(cnt);
150 
151 	/* align size to guarantee I/O would be done in one command */
152 	txsize = rtw_sdio_cmd53_align_size(d, cnt);
153 
154 	ret = rtw_sdio_write_cmd53(d, txaddr, mem, txsize);
155 
156 exit:
157 
158 	return ret;
159 }
160 
161 /*
162  * Description:
163  *	Write to TX FIFO
164  *	Align write size to block size,
165  *	and check enough FIFO size to write.
166  *
167  * Parameters:
168  *	pintfhdl	a pointer of intf_hdl
169  *	addr		not use
170  *	cnt		size to write
171  *	mem		struct xmit_buf*
172  *
173  * Return:
174  *	_SUCCESS(1)	Success
175  *	_FAIL(0)	Fail
176  */
sdio_write_port(struct intf_hdl * pintfhdl,u32 addr,u32 cnt,u8 * mem)177 static u32 sdio_write_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *mem)
178 {
179 	struct dvobj_priv *d;
180 	PADAPTER adapter;
181 	struct xmit_buf *xmitbuf;
182 	u32 txaddr, txsize;
183 	u32 ret = _FAIL;
184 
185 
186 	d = pintfhdl->pintf_dev;
187 	adapter = pintfhdl->padapter;
188 	xmitbuf = (struct xmit_buf *)mem;
189 
190 #if 0 /* who will call this when hardware not be initialized? */
191 	if (!rtw_is_hw_init_completed(adapter)) {
192 		RTW_INFO("%s [addr=0x%x cnt=%d] adapter->hw_init_completed == _FALSE\n",
193 			 __FUNCTION__, addr, cnt);
194 		goto exit;
195 	}
196 #endif
197 
198 	ret = rtl8822bs_write_port(d, cnt, xmitbuf->pdata);
199 
200 	rtw_sctx_done_err(&xmitbuf->sctx,
201 		(_FAIL == ret) ? RTW_SCTX_DONE_WRITE_PORT_ERR : RTW_SCTX_DONE_SUCCESS);
202 
203 	return ret;
204 }
205 
sdio_set_intf_ops(PADAPTER adapter,struct _io_ops * pops)206 void sdio_set_intf_ops(PADAPTER adapter, struct _io_ops *pops)
207 {
208 	pops->_read8 = rtw_halmac_read8;
209 	pops->_read16 = rtw_halmac_read16;
210 	pops->_read32 = rtw_halmac_read32;
211 	pops->_read_mem = rtw_halmac_read_mem;
212 	pops->_read_port = sdio_read_port;
213 
214 	pops->_write8 = rtw_halmac_write8;
215 	pops->_write16 = rtw_halmac_write16;
216 	pops->_write32 = rtw_halmac_write32;
217 	pops->_writeN = NULL;
218 	pops->_write_mem = NULL;
219 	pops->_write_port = sdio_write_port;
220 
221 	pops->_sd_f0_read8 = sdio_f0_read8;
222 
223 #ifdef CONFIG_SDIO_INDIRECT_ACCESS
224 	pops->_sd_iread8 = rtw_halmac_iread8;
225 	pops->_sd_iread16 = rtw_halmac_iread16;
226 	pops->_sd_iread32 = rtw_halmac_iread32;
227 	pops->_sd_iwrite8 = rtw_halmac_write8;
228 	pops->_sd_iwrite16 = rtw_halmac_write16;
229 	pops->_sd_iwrite32 = rtw_halmac_write32;
230 #endif /* CONFIG_SDIO_INDIRECT_ACCESS */
231 }
232 
sd_recv_rxfifo(PADAPTER adapter,u32 size)233 static struct recv_buf *sd_recv_rxfifo(PADAPTER adapter, u32 size)
234 {
235 	struct dvobj_priv *d;
236 	struct recv_priv *recvpriv;
237 	struct recv_buf	*recvbuf;
238 	u32 readsz, bufsz;
239 	u8 *rbuf;
240 	_pkt *pkt;
241 	s32 ret;
242 
243 
244 	d = adapter_to_dvobj(adapter);
245 
246 	/*
247 	 * Patch for some SDIO Host 4 bytes issue
248 	 * ex. RK3188
249 	 */
250 	readsz = RND4(size);
251 
252 	/* round to block size */
253 	bufsz = rtw_sdio_cmd53_align_size(d, readsz);
254 
255 	/* 1. alloc recvbuf */
256 	recvpriv = &adapter->recvpriv;
257 	recvbuf = rtw_dequeue_recvbuf(&recvpriv->free_recv_buf_queue);
258 	if (recvbuf == NULL) {
259 #ifndef CONFIG_RECV_THREAD_MODE
260 		RTW_WARN("%s:alloc recvbuf FAIL!\n", __FUNCTION__);
261 #endif /* !CONFIG_RECV_THREAD_MODE */
262 		return NULL;
263 	}
264 
265 	/* 2. alloc skb */
266 	pkt = rtl8822bs_alloc_recvbuf_skb(recvbuf, bufsz);
267 	if (!pkt) {
268 		RTW_ERR("%s: alloc_skb fail! alloc=%d read=%d\n", __FUNCTION__, bufsz, size);
269 		rtw_enqueue_recvbuf(recvbuf, &recvpriv->free_recv_buf_queue);
270 		return NULL;
271 	}
272 
273 	/* 3. read data from rxfifo */
274 	rbuf = skb_put(pkt, size);
275 	ret = rtl8822bs_read_port(d, bufsz, rbuf);
276 	if (_FAIL == ret) {
277 		RTW_ERR("%s: read port FAIL!\n", __FUNCTION__);
278 		rtl8822bs_free_recvbuf_skb(recvbuf);
279 		rtw_enqueue_recvbuf(recvbuf, &recvpriv->free_recv_buf_queue);
280 		return NULL;
281 	}
282 
283 	/* 4. init recvbuf */
284 	recvbuf->len = pkt->len;
285 	recvbuf->phead = pkt->head;
286 	recvbuf->pdata = pkt->data;
287 	recvbuf->ptail = skb_tail_pointer(pkt);
288 	recvbuf->pend = skb_end_pointer(pkt);
289 
290 	return recvbuf;
291 }
292 #ifdef CONFIG_RECV_THREAD_MODE
sdio_recv_and_drop(PADAPTER adapter,u32 size)293 static u32 sdio_recv_and_drop(PADAPTER adapter, u32 size)
294 {
295 	struct dvobj_priv *d;
296 	u32 readsz, bufsz;
297 	u8 *rbuf;
298 	s32 ret = _SUCCESS;
299 
300 
301 	d = adapter_to_dvobj(adapter);
302 
303 	/*
304 	 * Patch for some SDIO Host 4 bytes issue
305 	 * ex. RK3188
306 	 */
307 	readsz = RND4(size);
308 
309 	/* round to block size */
310 	bufsz = rtw_sdio_cmd53_align_size(d, readsz);
311 
312 	rbuf = rtw_zmalloc(bufsz);
313 	if (NULL == rbuf) {
314 		ret = _FAIL;
315 		goto _exit;
316 	}
317 
318 	ret = rtl8822bs_read_port(d, bufsz, rbuf);
319 	if (_FAIL == ret)
320 		RTW_ERR("%s: read port FAIL!\n", __FUNCTION__);
321 
322 	if (NULL != rbuf)
323 		rtw_mfree(rbuf, bufsz);
324 
325 _exit:
326 	return ret;
327 }
328 #endif
sd_int_dpc(PADAPTER adapter)329 void sd_int_dpc(PADAPTER adapter)
330 {
331 	PHAL_DATA_TYPE phal;
332 	struct dvobj_priv *dvobj;
333 	struct pwrctrl_priv *pwrctl;
334 
335 
336 	phal = GET_HAL_DATA(adapter);
337 	dvobj = adapter_to_dvobj(adapter);
338 	pwrctl = dvobj_to_pwrctl(dvobj);
339 
340 #ifdef CONFIG_SDIO_TX_ENABLE_AVAL_INT
341 	if (phal->sdio_hisr & BIT_SDIO_AVAL_8822B)
342 		_rtw_up_sema(&adapter->xmitpriv.xmit_sema);
343 
344 #endif /* CONFIG_SDIO_TX_ENABLE_AVAL_INT */
345 
346 	if (phal->sdio_hisr & BIT_SDIO_CPWM1_8822B) {
347 		struct reportpwrstate_parm report;
348 
349 #ifdef CONFIG_LPS_RPWM_TIMER
350 		_cancel_timer_ex(&pwrctl->pwr_rpwm_timer);
351 #endif /* CONFIG_LPS_RPWM_TIMER */
352 
353 		report.state = rtw_read8(adapter, REG_SDIO_HCPWM1_V2_8822B);
354 
355 #ifdef CONFIG_LPS_LCLK
356 		_set_workitem(&(pwrctl->cpwm_event));
357 #endif /* CONFIG_LPS_LCLK */
358 	}
359 
360 	if (phal->sdio_hisr & BIT_SDIO_TXERR_8822B) {
361 		u32 status;
362 		u32 addr;
363 
364 		addr = REG_TXDMA_STATUS_8822B;
365 		status = rtw_read32(adapter, addr);
366 		rtw_write32(adapter, addr, status);
367 
368 		RTW_INFO("%s: SDIO_HISR_TXERR (0x%08x)\n", __FUNCTION__, status);
369 	}
370 
371 	if (phal->sdio_hisr & BIT_SDIO_TXBCNOK_8822B)
372 		RTW_INFO("%s: SDIO_HISR_TXBCNOK\n", __FUNCTION__);
373 
374 	if (phal->sdio_hisr & BIT_SDIO_TXBCNERR_8822B)
375 		RTW_INFO("%s: SDIO_HISR_TXBCNERR\n", __FUNCTION__);
376 
377 	if (phal->sdio_hisr & BIT_SDIO_RXFOVW_8822B)
378 		RTW_INFO("%s: Rx Overflow\n", __FUNCTION__);
379 
380 	if (phal->sdio_hisr & BIT_SDIO_RXERR_8822B)
381 		RTW_INFO("%s: Rx Error\n", __FUNCTION__);
382 
383 	if (phal->sdio_hisr & BIT_RX_REQUEST_8822B) {
384 		struct recv_buf *precvbuf;
385 		int rx_fail_time = 0;
386 		u16 rx_len;
387 
388 
389 		/* No need to write 1 clear for RX_REQUEST */
390 		phal->sdio_hisr ^= BIT_RX_REQUEST_8822B;
391 
392 		rx_len = phal->SdioRxFIFOSize;
393 		do {
394 			if (!rx_len)
395 				break;
396 
397 			precvbuf = sd_recv_rxfifo(adapter, rx_len);
398 			if (precvbuf) {
399 				rtl8822bs_rxhandler(adapter, precvbuf);
400 			} else {
401 				rx_fail_time++;
402 #ifdef CONFIG_RECV_THREAD_MODE
403 				if (rx_fail_time >= 10) {
404 					if (_FAIL == sdio_recv_and_drop(adapter, rx_len))
405 						break;
406 
407 					rx_fail_time = 0;
408 				} else {
409 					rtw_msleep_os(1);
410 					continue;
411 				}
412 #else /* !CONFIG_RECV_THREAD_MODE */
413 				RTW_WARN("%s: recv fail!(time=%d)\n", __FUNCTION__, rx_fail_time);
414 				if (rx_fail_time >= 10)
415 					break;
416 #endif /* !CONFIG_RECV_THREAD_MODE */
417 			}
418 
419 			rx_len = 0;
420 			rtl8822bs_get_interrupt(adapter, NULL, &rx_len);
421 		} while (1);
422 
423 		if (rx_fail_time == 10)
424 			RTW_ERR("%s: exit because recv failed more than 10 times!\n", __FUNCTION__);
425 	}
426 }
427 
sd_int_hdl(PADAPTER adapter)428 void sd_int_hdl(PADAPTER adapter)
429 {
430 	PHAL_DATA_TYPE phal;
431 	u8 pwr;
432 
433 
434 	if (RTW_CANNOT_RUN(adapter))
435 		return;
436 
437 	phal = GET_HAL_DATA(adapter);
438 
439 	rtw_hal_get_hwreg(adapter, HW_VAR_APFM_ON_MAC, &pwr);
440 	if (pwr != _TRUE) {
441 		RTW_WARN("%s: unexpected interrupt!\n", __FUNCTION__);
442 		return;
443 	}
444 
445 	rtl8822bs_get_interrupt(adapter, &phal->sdio_hisr, &phal->SdioRxFIFOSize);
446 	if (phal->sdio_hisr & phal->sdio_himr) {
447 		phal->sdio_hisr &= phal->sdio_himr;
448 		sd_int_dpc(adapter);
449 		rtl8822bs_clear_interrupt(adapter, phal->sdio_hisr);
450 	} else {
451 		RTW_INFO("%s: HISR(0x%08x) and HIMR(0x%08x) no match!\n",
452 			 __FUNCTION__, phal->sdio_hisr, phal->sdio_himr);
453 	}
454 }
455 
456 #if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN)
rtw_hal_enable_cpwm2(_adapter * adapter)457 u8 rtw_hal_enable_cpwm2(_adapter *adapter)
458 {
459 	rtl8822bs_disable_interrupt_but_cpwm2(adapter);
460 	return _SUCCESS;
461 }
462 
RecvOnePkt(PADAPTER adapter)463 u8 RecvOnePkt(PADAPTER adapter)
464 {
465 	struct recv_buf *precvbuf;
466 	struct dvobj_priv *psddev;
467 	PSDIO_DATA psdio_data;
468 	PHAL_DATA_TYPE phal;
469 	struct sdio_func *func;
470 	u8 res = _TRUE;
471 	u32 len = 0;
472 
473 	if (adapter == NULL) {
474 		RTW_ERR("%s: adapter is NULL!\n", __func__);
475 		return _FALSE;
476 	}
477 
478 	psddev = adapter->dvobj;
479 	psdio_data = &psddev->intf_data;
480 	func = psdio_data->func;
481 	phal = GET_HAL_DATA(adapter);
482 
483 	rtl8822bs_get_interrupt(adapter, &phal->sdio_hisr,
484 				&phal->SdioRxFIFOSize);
485 
486 	len = phal->SdioRxFIFOSize;
487 
488 	RTW_DBG("+%s: hisr: %08x size=%d+\n",
489 		 __func__, phal->sdio_hisr, phal->SdioRxFIFOSize);
490 
491 	if (len) {
492 		sdio_claim_host(func);
493 		precvbuf = sd_recv_rxfifo(adapter, len);
494 		if (precvbuf)
495 			rtl8822bs_rxhandler(adapter, precvbuf);
496 		else
497 			res = _FALSE;
498 		sdio_release_host(func);
499 	}
500 	return res;
501 }
502 #endif /* CONFIG_WOWLAN */
503 
504