xref: /OK3568_Linux_fs/external/rkwifibt/drivers/rtl8821cs/hal/rtl8821c/sdio/rtl8821cs_ops.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /******************************************************************************
2  *
3  * Copyright(c) 2016 - 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 _RTL8821CS_OPS_C_
16 
17 #include <drv_types.h>		/* PADAPTER, basic_types.h and etc. */
18 #include <hal_data.h>		/* HAL_DATA_TYPE, GET_HAL_DATA() and etc. */
19 #include <hal_intf.h>		/* struct hal_ops */
20 #include "../rtl8821c.h"
21 #include "rtl8821cs.h"		/* rtl8821cs_hal_init() */
22 #include "rtl8821cs_xmit.h"
23 #include "rtl8821cs_recv.h"
24 #include "rtl8821cs_io.h"
25 #include "rtl8821cs_led.h"
26 #include "rtl8821cs_halmac.h"
27 
28 
intf_chip_configure(PADAPTER adapter)29 static void intf_chip_configure(PADAPTER adapter)
30 {
31 #if 0
32 	u8 try_cnt = 0;
33 
34 	/*adjust SDIO output driving -output delay time about 8ns (SDIO SPEC must last than 7.5ns),offset 0x74[18]*/
35 	if (rtw_is_sdio30(adapter)) {
36 		rtw_write8(adapter, REG_SDIO_HSUS_CTRL, rtw_read8(adapter, REG_SDIO_HSUS_CTRL) & ~BIT(0));
37 
38 		do {
39 			rtw_mdelay_os(2);
40 			if ((rtw_read8(adapter, REG_SDIO_HSUS_CTRL) & BIT(1)))
41 				break;
42 			try_cnt++;
43 		} while (try_cnt <= 50);
44 
45 		if (try_cnt == 10)
46 			RTW_ERR("%s: SDIO active state change failed!!\n", __func__);
47 
48 		rtw_write32(adapter, REG_HCI_OPT_CTRL,
49 			rtw_read32(adapter, REG_HCI_OPT_CTRL) | BIT(18));
50 	}
51 #endif
52 }
53 
rtl8821cs_get_interrupt(PADAPTER adapter)54 u32 rtl8821cs_get_interrupt(PADAPTER adapter)
55 {
56 	return rtw_read32(adapter, REG_SDIO_HISR_8821C);
57 }
58 
rtl8821cs_clear_interrupt(PADAPTER adapter,u32 hisr)59 void rtl8821cs_clear_interrupt(PADAPTER adapter, u32 hisr)
60 {
61 	/* Perform write one clear operation */
62 	if (hisr)
63 		rtw_write32(adapter, REG_SDIO_HISR_8821C, hisr);
64 }
65 
rtl8821cs_get_himr(PADAPTER adapter)66 u32 rtl8821cs_get_himr(PADAPTER adapter)
67 {
68 	return rtw_read32(adapter, REG_SDIO_HIMR_8821C);
69 }
70 
rtl8821cs_update_himr(PADAPTER adapter,u32 himr)71 void rtl8821cs_update_himr(PADAPTER adapter, u32 himr)
72 {
73 	rtw_write32(adapter, REG_SDIO_HIMR_8821C, himr);
74 }
75 
rtl8821cs_update_interrupt_mask(PADAPTER padapter,u32 AddMSR,u32 RemoveMSR)76 void rtl8821cs_update_interrupt_mask(PADAPTER padapter,u32 AddMSR, u32 RemoveMSR)
77 {
78 	HAL_DATA_TYPE *pHalData;
79 	pHalData = GET_HAL_DATA(padapter);
80 
81 	if (AddMSR)
82 		pHalData->sdio_himr |= AddMSR;
83 
84 	if (RemoveMSR)
85 		pHalData->sdio_himr &= (~RemoveMSR);
86 
87 	rtl8821cs_update_himr(padapter,pHalData->sdio_himr);
88 }
89 
90 /*
91  * Description:
92  *	Initialize SDIO Host Interrupt Mask configuration variables for future use.
93  *
94  * Assumption:
95  *	Using SDIO Local register ONLY for configuration.
96  */
rtl8821cs_init_interrupt(PADAPTER adapter)97 void rtl8821cs_init_interrupt(PADAPTER adapter)
98 {
99 	PHAL_DATA_TYPE hal;
100 
101 
102 	hal = GET_HAL_DATA(adapter);
103 	hal->sdio_himr = (u32)(\
104 			       BIT_RX_REQUEST_MSK_8821C	|
105 #ifdef CONFIG_SDIO_TX_ENABLE_AVAL_INT
106 			       BIT_SDIO_AVAL_MSK_8821C		|
107 #endif /* CONFIG_SDIO_TX_ENABLE_AVAL_INT */
108 
109 #ifdef CONFIG_ERROR_STATE_MONITOR
110 			       BIT_SDIO_TXERR_MSK_8821C	|
111 			       BIT_SDIO_RXERR_MSK_8821C	|
112 #endif
113 #ifdef CONFIG_MONITOR_OVERFLOW
114 			       BIT_SDIO_TXFOVW_MSK_8821C	|
115 			       BIT_SDIO_RXFOVW_MSK_8821C	|
116 #endif
117 #ifdef CONFIG_INTERRUPT_BASED_TXBCN
118 
119 				#ifdef CONFIG_INTERRUPT_BASED_TXBCN_BCN_OK_ERR
120 				BIT_SDIO_TXBCNOK_MSK_8821C	|
121 				BIT_SDIO_TXBCNERR_MSK_8821C	|
122 				#endif
123 
124 				#ifdef CONFIG_INTERRUPT_BASED_TXBCN_EARLY_INT
125 				BIT_SDIO_BCNERLY_INT_MSK_8821C	|
126 				#endif
127 #endif
128 #if 0
129 			       BIT_SDIO_C2HCMD_INT_MSK_8821C	|
130 #endif
131 #if defined(CONFIG_LPS_LCLK) && !defined(CONFIG_DETECT_CPWM_BY_POLLING)
132 			       BIT_SDIO_CPWM1_MSK_8821C	|
133 #if 0
134 			       BIT_SDIO_CPWM2_MSK_8821C	|
135 #endif
136 #endif /* CONFIG_LPS_LCLK && !CONFIG_DETECT_CPWM_BY_POLLING */
137 #if 0
138 			       BIT_SDIO_HSISR_IND_MSK_8821C	|
139 			       BIT_SDIO_GTINT3_MSK_8821C	|
140 			       BIT_SDIO_GTINT4_MSK_8821C	|
141 			       BIT_SDIO_PSTIMEOUT_MSK_8821C	|
142 			       BIT_SDIO_OCPINT_MSK_8821C	|
143 			       BIT_SDIIO_ATIMend_MSK_8821C	|
144 			       BIT_SDIO_ATIMend_E_MSK_8821C	|
145 			       BIT_SDIO_CTWend_MSK_8821C	|
146 			       BIT_SDIO_CRCERR_MSK_8821C	|
147 #endif
148 			       0);
149 
150 }
151 
152 /*
153  * Description:
154  *	Clear corresponding SDIO Host ISR interrupt service.
155  *
156  * Assumption:
157  *	Using SDIO Local register ONLY for configuration.
158  */
159  #if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN)
clear_interrupt_all(PADAPTER adapter)160 static void clear_interrupt_all(PADAPTER adapter)
161 {
162 	PHAL_DATA_TYPE hal;
163 
164 
165 	if (rtw_is_surprise_removed(adapter))
166 		return;
167 
168 	hal = GET_HAL_DATA(adapter);
169 	rtl8821cs_clear_interrupt(adapter, 0xFFFFFFFF);
170 }
171 #endif /*#if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN)*/
172 /*
173  * Description:
174  *	Enalbe SDIO Host Interrupt Mask configuration on SDIO local domain.
175  *
176  * Assumption:
177  *	1. Using SDIO Local register ONLY for configuration.
178  *	2. PASSIVE LEVEL
179  */
enable_interrupt(PADAPTER adapter)180 static void enable_interrupt(PADAPTER adapter)
181 {
182 	PHAL_DATA_TYPE hal;
183 
184 
185 	hal = GET_HAL_DATA(adapter);
186 
187 	rtl8821cs_update_himr(adapter, hal->sdio_himr);
188 	RTW_INFO(FUNC_ADPT_FMT ": update SDIO HIMR=0x%08X\n",
189 		 FUNC_ADPT_ARG(adapter), hal->sdio_himr);
190 }
191 
192 /*
193  * Description:
194  *	Disable SDIO Host IMR configuration to mask unnecessary interrupt service.
195  *
196  * Assumption:
197  *	Using SDIO Local register ONLY for configuration.
198  */
disable_interrupt(PADAPTER adapter)199 static void disable_interrupt(PADAPTER adapter)
200 {
201 	PHAL_DATA_TYPE hal;
202 
203 
204 	hal = GET_HAL_DATA(adapter);
205 
206 	rtl8821cs_update_himr(adapter, 0);
207 	RTW_INFO("%s: update SDIO HIMR=0\n", __FUNCTION__);
208 }
209 
210 #ifdef CONFIG_WOWLAN
rtl8821cs_disable_interrupt_but_cpwm2(PADAPTER adapter)211 void rtl8821cs_disable_interrupt_but_cpwm2(PADAPTER adapter)
212 {
213 	u32 himr, tmp;
214 
215 	tmp = rtw_read32(adapter, REG_SDIO_HIMR);
216 	RTW_INFO("%s: Read SDIO_REG_HIMR: 0x%08x\n", __FUNCTION__, tmp);
217 
218 	himr = BIT_SDIO_CPWM2_MSK;
219 	rtl8821cs_update_himr(adapter, himr);
220 
221 	tmp = rtw_read32(adapter, REG_SDIO_HIMR);
222 	RTW_INFO("%s: Read again SDIO_REG_HIMR: 0x%08x\n", __FUNCTION__, tmp);
223 }
224 #endif /* CONFIG_WOWLAN */
225 
_run_thread(PADAPTER adapter)226 static void _run_thread(PADAPTER adapter)
227 {
228 #ifndef CONFIG_SDIO_TX_TASKLET
229 	struct xmit_priv *xmitpriv = &adapter->xmitpriv;
230 
231 	if (xmitpriv->SdioXmitThread == NULL) {
232 		RTW_INFO(FUNC_ADPT_FMT " start RTWHALXT\n", FUNC_ADPT_ARG(adapter));
233 		xmitpriv->SdioXmitThread = kthread_run(rtl8821cs_xmit_thread, adapter, "RTWHALXT");
234 		if (IS_ERR(xmitpriv->SdioXmitThread)) {
235 			RTW_ERR("%s: start rtl8821cs_xmit_thread FAIL!!\n", __FUNCTION__);
236 			xmitpriv->SdioXmitThread = NULL;
237 		}
238 	}
239 #endif /* !CONFIG_SDIO_TX_TASKLET */
240 }
241 
run_thread(PADAPTER adapter)242 static void run_thread(PADAPTER adapter)
243 {
244 	_run_thread(adapter);
245 	rtl8821c_run_thread(adapter);
246 }
247 
_cancel_thread(PADAPTER adapter)248 static void _cancel_thread(PADAPTER adapter)
249 {
250 #ifndef CONFIG_SDIO_TX_TASKLET
251 	struct xmit_priv *xmitpriv = &adapter->xmitpriv;
252 
253 	/* stop xmit_buf_thread */
254 	if (xmitpriv->SdioXmitThread) {
255 		_rtw_up_sema(&xmitpriv->SdioXmitSema);
256 		rtw_thread_stop(xmitpriv->SdioXmitThread);
257 		xmitpriv->SdioXmitThread = NULL;
258 	}
259 #endif /* !CONFIG_SDIO_TX_TASKLET */
260 }
261 
cancel_thread(PADAPTER adapter)262 static void cancel_thread(PADAPTER adapter)
263 {
264 	rtl8821c_cancel_thread(adapter);
265 	_cancel_thread(adapter);
266 }
267 
268 #ifdef CONFIG_SDIO_OOB
269 /*
270 REG_SYS_SDIO_CTRL_8821C
271 BIT_SDIO_INT - 1: Enabled (GPIO4:SDIO_INT); 0 : Disabled
272 BIT_SDIO_INT_POLARITY - 0: Low Active 1: High Active
273 */
274 
rtl8821cs_gpio4_sdio_int_enable(_adapter * adapter,u8 enable,u8 polarity_high)275 void rtl8821cs_gpio4_sdio_int_enable(_adapter *adapter, u8 enable, u8 polarity_high)
276 {
277 	u32 sdio_ctrl = 0;
278 
279 	sdio_ctrl = rtw_read32(adapter, REG_SYS_SDIO_CTRL_8821C);
280 	if (enable) {
281 		sdio_ctrl |= BIT_SDIO_INT;
282 		if (polarity_high == _TRUE)
283 			sdio_ctrl |= BIT_SDIO_INT_POLARITY;
284 		else
285 			sdio_ctrl &= (~BIT_SDIO_INT_POLARITY);
286 	} else
287 		sdio_ctrl &= (~BIT_SDIO_INT);
288 	rtw_write32(adapter, REG_SYS_SDIO_CTRL_8821C, sdio_ctrl);
289 }
290 #endif
291 
292 /*
293  * If variable not handled here,
294  * some variables will be processed in rtl8821c_sethwreg()
295  */
sethwreg(PADAPTER adapter,u8 variable,u8 * val)296 static u8 sethwreg(PADAPTER adapter, u8 variable, u8 *val)
297 {
298 	u8 ret = _SUCCESS;
299 
300 	switch (variable) {
301 	case HW_VAR_SET_RPWM:
302 		{
303 			/*
304 			 * rpwm value only use BIT0(clock bit), and BIT7(Toggle bit)
305 			 * BIT0 value - 1: 32k, 0:40MHz.
306 			 * BIT4 value - 1: enable power gated, 0: disable power gated
307 			 * BIT6 value - 1: report cpwm value after success set, 0:do not report.
308 			 * BIT7 value - Toggling Bit.
309 			 */
310 			u8 val8 = 0;
311 			struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(adapter);
312 
313 			val8 = (*val) & 0xC1;
314 
315 #ifdef CONFIG_LPS_PG
316 			if ((val8 & BIT(0)) && (LPS_PG == pwrpriv->lps_level))
317 				val8 |= BIT(4);
318 #endif
319 			rtw_write8(adapter, REG_SDIO_HRPWM1_8821C, val8);
320 		}
321 		break;
322 
323 #ifdef CONFIG_GPIO_WAKEUP
324 	case HW_SET_GPIO_WL_CTRL:
325 	{
326 	}
327 	break;
328 #endif
329 /*
330 #ifdef CONFIG_SDIO_OOB
331 	case HW_SET_SDIO_OOB:
332 	{
333 		u8 sdio_ctrl = *val;
334 		u8 enable, is_high_active;
335 
336 		enable = (sdio_ctrl & BIT(0)) ? _TRUE : _FALSE;
337 		is_high_active = (sdio_ctrl & BIT(4)) ? _TRUE : _FALSE;
338 		rtl8821cs_gpio4_sdio_int_enable(adapter, enable, is_high_active);
339 	}
340 	break;
341 #endif
342 */
343 	default:
344 		ret = rtl8821c_sethwreg(adapter, variable, val);
345 		break;
346 	}
347 
348 	return ret;
349 }
350 
351 /*
352  * If variable not handled here,
353  * some variables will be processed in GetHwReg8723B()
354  */
gethwreg(PADAPTER adapter,u8 variable,u8 * val)355 static void gethwreg(PADAPTER adapter, u8 variable, u8 *val)
356 {
357 	PHAL_DATA_TYPE hal;
358 
359 
360 	hal = GET_HAL_DATA(adapter);
361 
362 	switch (variable) {
363 	case HW_VAR_CPWM:
364 		*val = rtw_read8(adapter, REG_SDIO_HCPWM1_V2_8821C);
365 		break;
366 
367 	case HW_VAR_RPWM_TOG:
368 		*val = rtw_read8(adapter, REG_SDIO_HRPWM1_8821C);
369 		*val &= BIT_TOGGLE_8821C;
370 		break;
371 
372 #ifdef CONFIG_GPIO_WAKEUP
373 	case HW_SET_GPIO_WL_CTRL:
374 
375 		break;
376 #endif
377 
378 	default:
379 		rtl8821c_gethwreg(adapter, variable, val);
380 		break;
381 	}
382 }
383 
384 /*
385  * Description:
386  *	Query setting of specified variable.
387  */
gethaldefvar(PADAPTER adapter,HAL_DEF_VARIABLE eVariable,void * pval)388 static u8 gethaldefvar(PADAPTER adapter, HAL_DEF_VARIABLE eVariable, void *pval)
389 {
390 	u8 bResult = _SUCCESS;
391 	struct dvobj_priv *dvobj = adapter_to_dvobj(adapter);
392 	PSDIO_DATA psdio_data = &dvobj->intf_data;
393 	PHAL_DATA_TYPE hal = GET_HAL_DATA(adapter);
394 
395 	switch (eVariable) {
396 
397 	case HW_VAR_MAX_RX_AMPDU_FACTOR:
398 		{
399 			if (psdio_data->clock > RTW_SDIO_CLK_40M) {
400 				*(HT_CAP_AMPDU_FACTOR *)pval = MAX_AMPDU_FACTOR_32K;
401 				RTW_INFO("AMPDU FACTOR - 32K\n");
402 			} else if (psdio_data->clock > RTW_SDIO_CLK_33M) {
403 				*(HT_CAP_AMPDU_FACTOR *)pval = MAX_AMPDU_FACTOR_16K;
404 				RTW_INFO("AMPDU FACTOR - 16K\n");
405 			} else {
406 				*(HT_CAP_AMPDU_FACTOR *)pval = MAX_AMPDU_FACTOR_8K;
407 				RTW_INFO("AMPDU FACTOR - 8K\n");
408 			}
409 		}
410 		break;
411 
412 	default:
413 		bResult = rtl8821c_gethaldefvar(adapter, eVariable, pval);
414 		break;
415 	}
416 
417 	return bResult;
418 }
419 
420 /*
421  * Description:
422  *	Change default setting of specified variable.
423  */
sethaldefvar(PADAPTER adapter,HAL_DEF_VARIABLE eVariable,void * pval)424 static u8 sethaldefvar(PADAPTER adapter, HAL_DEF_VARIABLE eVariable, void *pval)
425 {
426 	PHAL_DATA_TYPE hal = GET_HAL_DATA(adapter);
427 	u8 bResult = _SUCCESS;
428 
429 	switch (eVariable) {
430 	default:
431 		bResult = rtl8821c_sethaldefvar(adapter, eVariable, pval);
432 		break;
433 	}
434 
435 	return bResult;
436 }
437 
rtl8821cs_set_hal_ops(PADAPTER adapter)438 u8 rtl8821cs_set_hal_ops(PADAPTER adapter)
439 {
440 	struct hal_ops *ops_func = &adapter->hal_func;
441 
442 	u8 err;
443 
444 	err = rtl8821cs_halmac_init_adapter(adapter);
445 	if (err) {
446 		RTW_INFO("%s: [ERROR]HALMAC initialize FAIL!\n", __FUNCTION__);
447 		return _FAIL;
448 	}
449 
450 	rtl8821c_set_hal_ops(adapter);
451 	rtl8821cs_init_interrupt(adapter);
452 
453 	ops_func->init_default_value = rtl8821cs_init_default_value;
454 	ops_func->intf_chip_configure = intf_chip_configure;
455 
456 	ops_func->hal_init = rtl8821cs_hal_init;
457 	ops_func->hal_deinit = rtl8821cs_hal_deinit;
458 
459 	ops_func->init_xmit_priv = rtl8821cs_init_xmit_priv;
460 	ops_func->free_xmit_priv = rtl8821cs_free_xmit_priv;
461 	ops_func->hal_xmit = rtl8821cs_hal_xmit;
462 	ops_func->mgnt_xmit = rtl8821cs_mgnt_xmit;
463 #ifdef CONFIG_RTW_MGMT_QUEUE
464 	ops_func->hal_mgmt_xmitframe_enqueue = rtl8821cs_hal_mgmt_xmit_enqueue;
465 #endif
466 	ops_func->hal_xmitframe_enqueue = rtl8821cs_hal_xmit_enqueue;
467 #ifdef CONFIG_XMIT_THREAD_MODE
468 	ops_func->xmit_thread_handler = rtl8821cs_xmit_buf_handler;
469 #endif
470 	ops_func->run_thread = run_thread;
471 	ops_func->cancel_thread = cancel_thread;
472 
473 	ops_func->init_recv_priv = rtl8821cs_init_recv_priv;
474 	ops_func->free_recv_priv = rtl8821cs_free_recv_priv;
475 #ifdef CONFIG_RECV_THREAD_MODE
476 	ops_func->recv_hdl = rtl8821cs_recv_hdl;
477 #endif
478 
479 	ops_func->enable_interrupt = enable_interrupt;
480 	ops_func->disable_interrupt = disable_interrupt;
481 #if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN)
482 	ops_func->clear_interrupt = clear_interrupt_all;
483 #endif
484 #ifdef CONFIG_RTW_SW_LED
485 	ops_func->InitSwLeds = rtl8821cs_initswleds;
486 	ops_func->DeInitSwLeds = rtl8821cs_deinitswleds;
487 #endif
488 	ops_func->set_hw_reg_handler = sethwreg;
489 	ops_func->GetHwRegHandler = gethwreg;
490 	ops_func->get_hal_def_var_handler = gethaldefvar;
491 	ops_func->SetHalDefVarHandler = sethaldefvar;
492 	return _TRUE;
493 }
494