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