• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /******************************************************************************
2  *
3  * Copyright(c) 2015 - 2017 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 _RTL8822CS_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 "rtl8822cs.h"		/* rtl8822cs_get_interrupt(), rtl8822cs_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  */
rtl8822cs_read_port(struct dvobj_priv * d,u32 cnt,u8 * mem)61 u32 rtl8822cs_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 rtl8822cs_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  */
rtl8822cs_write_port(struct dvobj_priv * d,u32 cnt,u8 * mem)136 u32 rtl8822cs_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 = rtl8822cs_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 = rtl8822cs_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 = rtl8822cs_read_port(d, bufsz, rbuf);
276 	if (_FAIL == ret) {
277 		RTW_ERR("%s: read port FAIL!\n", __FUNCTION__);
278 		rtl8822cs_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 = rtl8822cs_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
329 
sd_int_dpc(PADAPTER adapter)330 void sd_int_dpc(PADAPTER adapter)
331 {
332 	PHAL_DATA_TYPE phal;
333 	struct dvobj_priv *dvobj;
334 	struct pwrctrl_priv *pwrctl;
335 
336 
337 	phal = GET_HAL_DATA(adapter);
338 	dvobj = adapter_to_dvobj(adapter);
339 	pwrctl = dvobj_to_pwrctl(dvobj);
340 
341 #ifdef CONFIG_SDIO_TX_ENABLE_AVAL_INT
342 	if (phal->sdio_hisr & BIT_SDIO_AVAL_8822C)
343 		_rtw_up_sema(&adapter->xmitpriv.xmit_sema);
344 
345 #endif /* CONFIG_SDIO_TX_ENABLE_AVAL_INT */
346 
347 	if (phal->sdio_hisr & BIT_SDIO_CPWM1_8822C) {
348 		struct reportpwrstate_parm report;
349 
350 #ifdef CONFIG_LPS_RPWM_TIMER
351 		_cancel_timer_ex(&pwrctl->pwr_rpwm_timer);
352 #endif /* CONFIG_LPS_RPWM_TIMER */
353 
354 		report.state = rtw_read8(adapter, REG_SDIO_HCPWM1_V2_8822C);
355 
356 #ifdef CONFIG_LPS_LCLK
357 		_set_workitem(&(pwrctl->cpwm_event));
358 #endif /* CONFIG_LPS_LCLK */
359 	}
360 
361 	if (phal->sdio_hisr & BIT_SDIO_TXERR_8822C) {
362 		u32 status;
363 		u32 addr;
364 
365 		addr = REG_TXDMA_STATUS_8822C;
366 		status = rtw_read32(adapter, addr);
367 		rtw_write32(adapter, addr, status);
368 
369 		RTW_INFO("%s: SDIO_HISR_TXERR (0x%08x)\n", __FUNCTION__, status);
370 	}
371 
372 	if (phal->sdio_hisr & BIT_SDIO_TXBCNOK_8822C)
373 		RTW_INFO("%s: SDIO_HISR_TXBCNOK\n", __FUNCTION__);
374 
375 	if (phal->sdio_hisr & BIT_SDIO_TXBCNERR_8822C)
376 		RTW_INFO("%s: SDIO_HISR_TXBCNERR\n", __FUNCTION__);
377 
378 	if (phal->sdio_hisr & BIT_SDIO_RXFOVW_8822C)
379 		RTW_INFO("%s: Rx Overflow\n", __FUNCTION__);
380 
381 	if (phal->sdio_hisr & BIT_SDIO_RXERR_8822C)
382 		RTW_INFO("%s: Rx Error\n", __FUNCTION__);
383 #ifdef CONFIG_SDIO_MULTI_FUNCTION_COEX
384 #if DBG_SDIO_MULTI_FUNCTION_COEX
385 	if (phal->sdio_hisr & BIT_BT_INT_8822C)
386 		RTW_INFO("%s: SDIO bus resume to available\n", __FUNCTION__);
387 #endif
388 #endif
389 
390 	if (phal->sdio_hisr & BIT_RX_REQUEST_8822C) {
391 		struct recv_buf *precvbuf;
392 		int rx_fail_time = 0;
393 		u32 rx_len;
394 
395 		#ifdef CONFIG_SDIO_MULTI_FUNCTION_COEX
396 		if (!ex_hal_sdio_multi_if_bus_available(adapter)
397 			&& !(phal->sdio_hisr & BIT_BT_INT_8822C)
398 		) {
399 			#if DBG_SDIO_MULTI_FUNCTION_COEX
400 			RTW_INFO("%s: RX entry, SDIO_MULTI_BT && not resume\n", __FUNCTION__);
401 			#endif
402 			goto rx_end;
403 		}
404 		#endif
405 
406 		/* No need to write 1 clear for RX_REQUEST */
407 		phal->sdio_hisr ^= BIT_RX_REQUEST_8822C;
408 
409 		rx_len = phal->SdioRxFIFOSize;
410 		do {
411 			if (!rx_len)
412 				break;
413 
414 			if (rx_len > MAX_RECVBUF_SZ) {
415 				RTW_ERR("%s : rx drop for invalid len %d\n", __func__, rx_len);
416 				break;
417 			}
418 
419 			precvbuf = sd_recv_rxfifo(adapter, rx_len);
420 			if (precvbuf) {
421 				rtl8822cs_rxhandler(adapter, precvbuf);
422 
423 			} else {
424 				rx_fail_time++;
425 				#ifdef CONFIG_RECV_THREAD_MODE
426 				if (rx_fail_time >= 10) {
427 					if (_FAIL == sdio_recv_and_drop(adapter, rx_len))
428 						break;
429 
430 					rx_fail_time = 0;
431 				} else if (1
432 					#ifdef CONFIG_SDIO_MULTI_FUNCTION_COEX
433 					&& ex_hal_sdio_multi_if_bus_available(adapter)
434 					#endif
435 				) {
436 					rtw_msleep_os(1);
437 					continue;
438 				}
439 				#else /* !CONFIG_RECV_THREAD_MODE */
440 				RTW_WARN("%s: recv fail!(time=%d)\n", __FUNCTION__, rx_fail_time);
441 				if (rx_fail_time >= 10)
442 					break;
443 				#endif /* !CONFIG_RECV_THREAD_MODE */
444 			}
445 
446 			#ifdef CONFIG_SDIO_MULTI_FUNCTION_COEX
447 			if (!ex_hal_sdio_multi_if_bus_available(adapter)) {
448 				#if DBG_SDIO_MULTI_FUNCTION_COEX
449 				RTW_INFO("%s: RX, SDIO_MULTI_BT\n", __FUNCTION__);
450 				#endif
451 				break;
452 			}
453 			#endif
454 
455 			rx_len = 0;
456 			rtl8822cs_get_interrupt(adapter, NULL, &rx_len);
457 		} while (1);
458 
459 		if (rx_fail_time == 10)
460 			RTW_ERR("%s: exit because recv failed more than 10 times!\n", __FUNCTION__);
461 
462 #ifdef CONFIG_SDIO_MULTI_FUNCTION_COEX
463 rx_end:
464 		;
465 #endif
466 	}
467 }
468 
sd_int_hdl(PADAPTER adapter)469 void sd_int_hdl(PADAPTER adapter)
470 {
471 	PHAL_DATA_TYPE phal;
472 	u8 pwr;
473 
474 
475 	if (RTW_CANNOT_RUN(adapter))
476 		return;
477 
478 	phal = GET_HAL_DATA(adapter);
479 
480 	rtw_hal_get_hwreg(adapter, HW_VAR_APFM_ON_MAC, &pwr);
481 	if (pwr != _TRUE) {
482 		RTW_WARN("%s: unexpected interrupt!\n", __FUNCTION__);
483 		return;
484 	}
485 
486 	rtl8822cs_get_interrupt(adapter, &phal->sdio_hisr, &phal->SdioRxFIFOSize);
487 	if (phal->sdio_hisr & phal->sdio_himr) {
488 		phal->sdio_hisr &= phal->sdio_himr;
489 		sd_int_dpc(adapter);
490 		rtl8822cs_clear_interrupt(adapter, phal->sdio_hisr);
491 	} else {
492 		RTW_DBG("%s: HISR(0x%08x) and HIMR(0x%08x) no match!\n",
493 			 __FUNCTION__, phal->sdio_hisr, phal->sdio_himr);
494 	}
495 }
496 
497 #if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN)
rtw_hal_enable_cpwm2(_adapter * adapter)498 u8 rtw_hal_enable_cpwm2(_adapter *adapter)
499 {
500 	rtl8822cs_disable_interrupt_but_cpwm2(adapter);
501 	return _SUCCESS;
502 }
503 
RecvOnePkt(PADAPTER adapter)504 u8 RecvOnePkt(PADAPTER adapter)
505 {
506 	struct recv_buf *precvbuf;
507 	struct dvobj_priv *psddev;
508 	PSDIO_DATA psdio_data;
509 	PHAL_DATA_TYPE phal;
510 	struct sdio_func *func;
511 	u8 res = _TRUE;
512 	u32 len = 0;
513 
514 	if (adapter == NULL) {
515 		RTW_ERR("%s: adapter is NULL!\n", __func__);
516 		return _FALSE;
517 	}
518 
519 	psddev = adapter->dvobj;
520 	psdio_data = &psddev->intf_data;
521 	func = psdio_data->func;
522 	phal = GET_HAL_DATA(adapter);
523 
524 	rtl8822cs_get_interrupt(adapter, &phal->sdio_hisr,
525 				&phal->SdioRxFIFOSize);
526 
527 	len = phal->SdioRxFIFOSize;
528 
529 	RTW_DBG("+%s: hisr: %08x size=%d+\n",
530 		 __func__, phal->sdio_hisr, phal->SdioRxFIFOSize);
531 
532 	if (len) {
533 		sdio_claim_host(func);
534 		precvbuf = sd_recv_rxfifo(adapter, len);
535 		if (precvbuf)
536 			rtl8822cs_rxhandler(adapter, precvbuf);
537 		else
538 			res = _FALSE;
539 		sdio_release_host(func);
540 	}
541 	return res;
542 }
543 #endif /* CONFIG_WOWLAN */
544 
545