OSDN Git Service

Add rtl8821ce driver version 5.5.2
[android-x86/external-kernel-drivers.git] / rtl8821ce / hal / rtl8821c / pci / rtl8821ce_ops.c
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
16 #define _HCI_OPS_OS_C_
17
18 #include <drv_types.h>          /* PADAPTER, basic_types.h and etc. */
19 #include <hal_data.h>           /* HAL_DATA_TYPE, GET_HAL_DATA() and etc. */
20 #include <hal_intf.h>           /* struct hal_ops */
21 #include "../rtl8821c.h"
22 #include "rtl8821ce.h"
23
24 static void init_bd_ring_var(_adapter *padapter)
25 {
26         struct recv_priv *r_priv = &padapter->recvpriv;
27         struct xmit_priv *t_priv = &padapter->xmitpriv;
28         u8 i = 0;
29
30         for (i = 0; i < HW_QUEUE_ENTRY; i++)
31                 t_priv->txringcount[i] = TX_BD_NUM_8821CE;
32
33         /*
34          * we just alloc 2 desc for beacon queue,
35          * because we just need first desc in hw beacon.
36          */
37         t_priv->txringcount[BCN_QUEUE_INX] = TX_BD_NUM_8821CE_BCN;
38         t_priv->txringcount[TXCMD_QUEUE_INX] = TX_BD_NUM_8821CE_CMD;
39
40         /*
41          * BE queue need more descriptor for performance consideration
42          * or, No more tx desc will happen, and may cause mac80211 mem leakage.
43          */
44         r_priv->rxbuffersize = MAX_RECVBUF_SZ;
45         r_priv->rxringcount = PCI_MAX_RX_COUNT;
46 }
47
48 static void rtl8821ce_reset_bd(_adapter *padapter)
49 {
50         _irqL   irqL;
51         struct xmit_priv *t_priv = &padapter->xmitpriv;
52         struct recv_priv *r_priv = &padapter->recvpriv;
53         struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
54         struct xmit_buf *pxmitbuf = NULL;
55         u8 *tx_bd, *rx_bd;
56         int i, rx_queue_idx;
57         dma_addr_t mapping;
58
59         for (rx_queue_idx = 0; rx_queue_idx < 1; rx_queue_idx++) {
60                 if (r_priv->rx_ring[rx_queue_idx].buf_desc) {
61                         rx_bd = NULL;
62                         for (i = 0; i < r_priv->rxringcount; i++) {
63                                 rx_bd = (u8 *)
64                                         &r_priv->rx_ring[rx_queue_idx].buf_desc[i];
65                         }
66                         r_priv->rx_ring[rx_queue_idx].idx = 0;
67                 }
68         }
69
70         _enter_critical(&pdvobjpriv->irq_th_lock, &irqL);
71         for (i = 0; i < PCI_MAX_TX_QUEUE_COUNT; i++) {
72                 if (t_priv->tx_ring[i].buf_desc) {
73                         struct rtw_tx_ring *ring = &t_priv->tx_ring[i];
74
75                         while (ring->qlen) {
76                                 tx_bd = (u8 *)(&ring->buf_desc[ring->idx]);
77                                 SET_TX_BD_OWN(tx_bd, 0);
78
79                                 if (i != BCN_QUEUE_INX)
80                                         ring->idx =
81                                                 (ring->idx + 1) % ring->entries;
82
83                                 pxmitbuf = rtl8821ce_dequeue_xmitbuf(ring);
84                                 if (pxmitbuf) {
85                                         mapping = GET_TX_BD_PHYSICAL_ADDR0_LOW(tx_bd);
86                                 #ifdef CONFIG_64BIT_DMA
87                                         mapping |= (dma_addr_t)GET_TX_BD_PHYSICAL_ADDR0_HIGH(tx_bd) << 32;
88                                 #endif
89                                         pci_unmap_single(pdvobjpriv->ppcidev,
90                                                 mapping,
91                                                 pxmitbuf->len, PCI_DMA_TODEVICE);
92                                         rtw_free_xmitbuf(t_priv, pxmitbuf);
93                                 } else {
94                                         RTW_INFO("%s(): qlen(%d) is not zero, but have xmitbuf in pending queue\n",
95                                                  __func__, ring->qlen);
96                                         break;
97                                 }
98                         }
99                         ring->idx = 0;
100                 }
101         }
102         _exit_critical(&pdvobjpriv->irq_th_lock, &irqL);
103 }
104
105 static void intf_chip_configure(PADAPTER padapter)
106 {
107         HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
108         struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
109         struct pwrctrl_priv *pwrpriv = dvobj_to_pwrctl(pdvobjpriv);
110
111         /* close ASPM for AMD defaultly */
112         pdvobjpriv->const_amdpci_aspm = 0;
113
114         /* ASPM PS mode. */
115         /* 0 - Disable ASPM, 1 - Enable ASPM without Clock Req, */
116         /* 2 - Enable ASPM with Clock Req, 3- Alwyas Enable ASPM with Clock Req, */
117         /* 4-  Always Enable ASPM without Clock Req. */
118         /* set default to rtl8188ee:3 RTL8192E:2 */
119         pdvobjpriv->const_pci_aspm = 0;
120
121         /* Setting for PCI-E device */
122         pdvobjpriv->const_devicepci_aspm_setting = 0x03;
123
124         /* Setting for PCI-E bridge */
125         pdvobjpriv->const_hostpci_aspm_setting = 0x03;
126
127         /* In Hw/Sw Radio Off situation. */
128         /* 0 - Default, 1 - From ASPM setting without low Mac Pwr, */
129         /* 2 - From ASPM setting with low Mac Pwr, 3 - Bus D3 */
130         /* set default to RTL8192CE:0 RTL8192SE:2 */
131         pdvobjpriv->const_hwsw_rfoff_d3 = 0;
132
133         /* This setting works for those device with backdoor ASPM setting such as EPHY setting. */
134         /* 0: Not support ASPM, 1: Support ASPM, 2: According to chipset. */
135         pdvobjpriv->const_support_pciaspm = 1;
136
137         pwrpriv->reg_rfoff = 0;
138         pwrpriv->rfoff_reason = 0;
139
140         pHalData->bL1OffSupport = _FALSE;
141 }
142
143 /*
144  * Description:
145  *      Collect all hardware information, fill "HAL_DATA_TYPE".
146  *      Sometimes this would be used to read MAC address.
147  *      This function will do
148  *      1. Read Efuse/EEPROM to initialize
149  *      2. Read registers to initialize
150  *      3. Other vaiables initialization
151  */
152 static u8 read_adapter_info(PADAPTER padapter)
153 {
154         u8 ret = _FAIL;
155
156         /*
157          * 1. Read Efuse/EEPROM to initialize
158          */
159         if (rtl8821c_read_efuse(padapter) != _SUCCESS)
160                 goto exit;
161
162         /*
163          * 2. Read registers to initialize
164          */
165
166         /*
167          * 3. Other Initialization
168          */
169
170         ret = _SUCCESS;
171
172 exit:
173         return ret;
174 }
175
176 static BOOLEAN rtl8821ce_InterruptRecognized(PADAPTER Adapter)
177 {
178         HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter);
179         BOOLEAN bRecognized = _FALSE;
180
181         /* 2013.11.18 Glayrainx suggests that turn off IMR and
182          * restore after cleaning ISR.
183          */
184         rtw_write32(Adapter, REG_HIMR0, 0);
185         rtw_write32(Adapter, REG_HIMR1, 0);
186         rtw_write32(Adapter, REG_HIMR3, 0);
187
188         pHalData->IntArray[0] = rtw_read32(Adapter, REG_HISR0);
189         pHalData->IntArray[0] &= pHalData->IntrMask[0];
190         rtw_write32(Adapter, REG_HISR0, pHalData->IntArray[0]);
191
192         /* For HISR extension. Added by tynli. 2009.10.07. */
193         pHalData->IntArray[1] = rtw_read32(Adapter, REG_HISR1);
194         pHalData->IntArray[1] &= pHalData->IntrMask[1];
195         rtw_write32(Adapter, REG_HISR1, pHalData->IntArray[1]);
196
197         /* for H2C cmd queue */
198         pHalData->IntArray[3] = rtw_read32(Adapter, REG_HISR3);
199         pHalData->IntArray[3] &= pHalData->IntrMask[3];
200         rtw_write32(Adapter, REG_HISR3, pHalData->IntArray[3]);
201
202         if (((pHalData->IntArray[0]) & pHalData->IntrMask[0]) != 0 ||
203             ((pHalData->IntArray[1]) & pHalData->IntrMask[1]) != 0)
204                 bRecognized = _TRUE;
205
206         /* restore IMR */
207         rtw_write32(Adapter, REG_HIMR0, pHalData->IntrMask[0] & 0xFFFFFFFF);
208         rtw_write32(Adapter, REG_HIMR1, pHalData->IntrMask[1] & 0xFFFFFFFF);
209         rtw_write32(Adapter, REG_HIMR3, pHalData->IntrMask[3] & 0xFFFFFFFF);
210
211         return bRecognized;
212 }
213
214 static VOID DisableInterrupt8821ce(PADAPTER Adapter)
215 {
216         struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(Adapter);
217
218         rtw_write32(Adapter, REG_HIMR0, 0x0);
219         rtw_write32(Adapter, REG_HIMR1, 0x0);
220         rtw_write32(Adapter, REG_HIMR3, 0x0);
221         pdvobjpriv->irq_enabled = 0;
222 }
223
224 static VOID rtl8821ce_enable_interrupt(PADAPTER Adapter)
225 {
226         HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter);
227         struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(Adapter);
228
229         pdvobjpriv->irq_enabled = 1;
230
231         rtw_write32(Adapter, REG_HIMR0, pHalData->IntrMask[0] & 0xFFFFFFFF);
232         rtw_write32(Adapter, REG_HIMR1, pHalData->IntrMask[1] & 0xFFFFFFFF);
233         rtw_write32(Adapter, REG_HIMR3, pHalData->IntrMask[3] & 0xFFFFFFFF);
234
235 }
236
237 static VOID rtl8821ce_clear_interrupt(PADAPTER Adapter)
238 {
239         u32 u32b;
240         HAL_DATA_TYPE   *pHalData = GET_HAL_DATA(Adapter);
241
242         u32b = rtw_read32(Adapter, REG_HISR0_8821C);
243         rtw_write32(Adapter, REG_HISR0_8821C, u32b);
244         pHalData->IntArray[0] = 0;
245
246         u32b = rtw_read32(Adapter, REG_HISR1_8821C);
247         rtw_write32(Adapter, REG_HISR1_8821C, u32b);
248         pHalData->IntArray[1] = 0;
249 }
250
251 static VOID rtl8821ce_disable_interrupt(PADAPTER Adapter)
252 {
253         struct dvobj_priv       *pdvobjpriv = adapter_to_dvobj(Adapter);
254
255         rtw_write32(Adapter, REG_HIMR0, 0x0);
256         rtw_write32(Adapter, REG_HIMR1, 0x0);   /* by tynli */
257         pdvobjpriv->irq_enabled = 0;
258 }
259
260 VOID UpdateInterruptMask8821CE(PADAPTER Adapter, u32 AddMSR, u32 AddMSR1,
261                                u32 RemoveMSR, u32 RemoveMSR1)
262 {
263         PHAL_DATA_TYPE pHalData = GET_HAL_DATA(Adapter);
264
265         DisableInterrupt8821ce(Adapter);
266
267         if (AddMSR)
268                 pHalData->IntrMask[0] |= AddMSR;
269
270         if (AddMSR1)
271                 pHalData->IntrMask[1] |= AddMSR1;
272
273         if (RemoveMSR)
274                 pHalData->IntrMask[0] &= (~RemoveMSR);
275
276         if (RemoveMSR1)
277                 pHalData->IntrMask[1] &= (~RemoveMSR1);
278
279 #if 0 /* TODO */
280         if (RemoveMSR3)
281                 pHalData->IntrMask[3] &= (~RemoveMSR3);
282 #endif
283
284         rtl8821ce_enable_interrupt(Adapter);
285 }
286
287 static void rtl8821ce_bcn_handler(PADAPTER Adapter, u32 handled[])
288 {
289         PHAL_DATA_TYPE pHalData = GET_HAL_DATA(Adapter);
290
291         if (pHalData->IntArray[0] & BIT_TXBCN0OK_MSK) {
292 #ifdef CONFIG_BCN_ICF
293                 /* do nothing */
294 #else
295                 /* Modify for MI temporary,
296                  * this processor cannot apply to multi-ap
297                  */
298                 PADAPTER bcn_adapter = rtw_mi_get_ap_adapter(Adapter);
299
300                 if (bcn_adapter->xmitpriv.beaconDMAing) {
301                         bcn_adapter->xmitpriv.beaconDMAing = _FAIL;
302                         rtl8821ce_tx_isr(Adapter, BCN_QUEUE_INX);
303                 }
304 #endif /* CONFIG_BCN_ICF */
305                 handled[0] |= BIT_TXBCN0OK_MSK;
306         }
307
308         if (pHalData->IntArray[0] & BIT_TXBCN0ERR_MSK) {
309 #ifdef CONFIG_BCN_ICF
310                 RTW_INFO("IMR_TXBCN0ERR isr!\n");
311 #else /* !CONFIG_BCN_ICF */
312                 /* Modify for MI temporary,
313                  * this processor cannot apply to multi-ap
314                  */
315                 PADAPTER bcn_adapter = rtw_mi_get_ap_adapter(Adapter);
316
317                 if (bcn_adapter->xmitpriv.beaconDMAing) {
318                         bcn_adapter->xmitpriv.beaconDMAing = _FAIL;
319                         rtl8821ce_tx_isr(Adapter, BCN_QUEUE_INX);
320                 }
321 #endif /* CONFIG_BCN_ICF */
322                 handled[0] |= BIT_TXBCN0ERR_MSK;
323         }
324
325         if (pHalData->IntArray[0] & BIT_BCNDERR0_MSK) {
326 #ifdef CONFIG_BCN_ICF
327                 RTW_INFO("BIT_BCNDERR0_MSK isr!\n");
328 #else /* !CONFIG_BCN_ICF */
329                 /* Release resource and re-transmit beacon to HW */
330                 struct tasklet_struct  *bcn_tasklet;
331                 /* Modify for MI temporary,
332                  * this processor cannot apply to multi-ap
333                  */
334                 PADAPTER bcn_adapter = rtw_mi_get_ap_adapter(Adapter);
335
336                 rtl8821ce_tx_isr(Adapter, BCN_QUEUE_INX);
337                 bcn_adapter->mlmepriv.update_bcn = _TRUE;
338                 bcn_tasklet = &bcn_adapter->recvpriv.irq_prepare_beacon_tasklet;
339                 tasklet_hi_schedule(bcn_tasklet);
340 #endif /* CONFIG_BCN_ICF */
341                 handled[0] |= BIT_BCNDERR0_MSK;
342         }
343
344         if (pHalData->IntArray[0] & BIT_BCNDMAINT0_MSK) {
345                 struct tasklet_struct  *bcn_tasklet;
346                 /* Modify for MI temporary,
347                 *   this processor cannot apply to multi-ap
348                 */
349                 PADAPTER bcn_adapter = rtw_mi_get_ap_adapter(Adapter);
350
351                 bcn_tasklet = &bcn_adapter->recvpriv.irq_prepare_beacon_tasklet;
352                 tasklet_hi_schedule(bcn_tasklet);
353                 handled[0] |= BIT_BCNDMAINT0_MSK;
354         }
355 }
356
357 static void rtl8821ce_rx_handler(PADAPTER Adapter, u32 handled[])
358 {
359         PHAL_DATA_TYPE pHalData = GET_HAL_DATA(Adapter);
360
361         if ((pHalData->IntArray[0] & (BIT_RXOK | BIT_RDU)) ||
362             (pHalData->IntArray[1] & (BIT_FOVW | BIT_RXERR_INT))) {
363                 pHalData->IntrMask[0] &= (~(BIT_RXOK_MSK | BIT_RDU_MSK));
364                 pHalData->IntrMask[1] &= (~(BIT_FOVW_MSK | BIT_RXERR_MSK));
365                 rtw_write32(Adapter, REG_HIMR0, pHalData->IntrMask[0]);
366                 rtw_write32(Adapter, REG_HIMR1, pHalData->IntrMask[1]);
367                 tasklet_hi_schedule(&Adapter->recvpriv.recv_tasklet);
368                 handled[0] |= pHalData->IntArray[0] & (BIT_RXOK | BIT_RDU);
369                 handled[1] |= pHalData->IntArray[1] & (BIT_FOVW | BIT_RXERR_INT);
370         }
371 }
372
373 static void rtl8821ce_tx_handler(PADAPTER Adapter, u32 events[], u32 handled[])
374 {
375         PHAL_DATA_TYPE pHalData = GET_HAL_DATA(Adapter);
376
377         if (events[0] & BIT_MGTDOK_MSK) {
378                 rtl8821ce_tx_isr(Adapter, MGT_QUEUE_INX);
379                 handled[0] |= BIT_MGTDOK_MSK;
380         }
381
382         if (events[0] & BIT_HIGHDOK_MSK) {
383                 rtl8821ce_tx_isr(Adapter, HIGH_QUEUE_INX);
384                 handled[0] |= BIT_HIGHDOK_MSK;
385         }
386
387         if (events[0] & BIT_BKDOK_MSK) {
388                 rtl8821ce_tx_isr(Adapter, BK_QUEUE_INX);
389                 handled[0] |= BIT_BKDOK_MSK;
390         }
391
392         if (events[0] & BIT_BEDOK_MSK) {
393                 rtl8821ce_tx_isr(Adapter, BE_QUEUE_INX);
394                 handled[0] |= BIT_BEDOK_MSK;
395         }
396
397         if (events[0] & BIT_VIDOK_MSK) {
398                 rtl8821ce_tx_isr(Adapter, VI_QUEUE_INX);
399                 handled[0] |= BIT_VIDOK_MSK;
400         }
401
402         if (events[0] & BIT_VODOK_MSK) {
403                 rtl8821ce_tx_isr(Adapter, VO_QUEUE_INX);
404                 handled[0] |= BIT_VODOK_MSK;
405         }
406 }
407
408 static void rtl8821ce_cmd_handler(PADAPTER Adapter, u32 handled[])
409 {
410         PHAL_DATA_TYPE pHalData = GET_HAL_DATA(Adapter);
411
412         if (pHalData->IntArray[3] & BIT_SETH2CDOK_MASK) {
413                 rtl8821ce_tx_isr(Adapter, TXCMD_QUEUE_INX);
414                 handled[3] |= BIT_SETH2CDOK_MASK;
415         }
416 }
417
418 static s32 rtl8821ce_interrupt(PADAPTER Adapter)
419 {
420         _irqL irqL;
421         HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter);
422         struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(Adapter);
423         struct xmit_priv *t_priv = &Adapter->xmitpriv;
424         int ret = _SUCCESS;
425         u32 handled[4] = {0};
426
427         _enter_critical(&pdvobjpriv->irq_th_lock, &irqL);
428
429         /* read ISR: 4/8bytes */
430         if (rtl8821ce_InterruptRecognized(Adapter) == _FALSE) {
431                 ret = _FAIL;
432                 goto done;
433         }
434
435         /* <1> beacon related */
436         rtl8821ce_bcn_handler(Adapter, handled);
437
438         /* <2> Rx related */
439         rtl8821ce_rx_handler(Adapter, handled);
440
441         /* <3> Tx related */
442         rtl8821ce_tx_handler(Adapter, pHalData->IntArray, handled);
443
444         if (pHalData->IntArray[1] & BIT_TXFOVW) {
445                 /*if (printk_ratelimit())*/
446                 RTW_WARN("[TXFOVW]\n");
447                 handled[1] |= BIT_TXFOVW;
448         }
449
450         if (pHalData->IntArray[1] & BIT_PRETXERR_HANDLE_ISR) {
451                 RTW_ERR("[PRE-TX HANG]\n");
452                 handled[1] |= BIT_PRETXERR_HANDLE_ISR;
453         }
454
455         /* <4> Cmd related */
456         rtl8821ce_cmd_handler(Adapter, handled);
457
458 #ifdef CONFIG_LPS_LCLK
459         if (pHalData->IntArray[0] & BIT_CPWM) {
460                 struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(Adapter);
461
462                 _set_workitem(&(pwrpriv->cpwm_event));
463                 handled[0] |= BIT_CPWM;
464         }
465 #endif
466
467         if ((pHalData->IntArray[0] & (~handled[0])) || (pHalData->IntArray[1] & (~handled[1])) || (pHalData->IntArray[3] & (~handled[3]))) {
468                 /*if (printk_ratelimit()) */
469                 {
470                         RTW_WARN("Unhandled ISR = %x, %x, %x\n",
471                                 (pHalData->IntArray[0] & (~handled[0])),
472                                 (pHalData->IntArray[1] & (~handled[1])),
473                                 (pHalData->IntArray[3] & (~handled[3]))
474                         );
475                 }
476         }
477 done:
478         _exit_critical(&pdvobjpriv->irq_th_lock, &irqL);
479         return ret;
480 }
481
482 u32 rtl8821ce_init_bd(_adapter *padapter)
483 {
484         struct xmit_priv *t_priv = &padapter->xmitpriv;
485         int     i, ret = _SUCCESS;
486
487         init_bd_ring_var(padapter);
488         ret = rtl8821ce_init_rxbd_ring(padapter);
489
490         if (ret == _FAIL)
491                 return ret;
492
493         /* general process for other queue */
494         for (i = 0; i < PCI_MAX_TX_QUEUE_COUNT; i++) {
495                 ret = rtl8821ce_init_txbd_ring(padapter, i,
496                                                t_priv->txringcount[i]);
497                 if (ret == _FAIL)
498                         goto err_free_rings;
499         }
500
501         return ret;
502
503 err_free_rings:
504
505         rtl8821ce_free_rxbd_ring(padapter);
506
507         for (i = 0; i < PCI_MAX_TX_QUEUE_COUNT; i++)
508                 if (t_priv->tx_ring[i].buf_desc)
509                         rtl8821ce_free_txbd_ring(padapter, i);
510
511
512         return ret;
513 }
514
515 u32 rtl8821ce_free_bd(_adapter *padapter)
516 {
517         struct xmit_priv        *t_priv = &padapter->xmitpriv;
518         u32 i;
519
520
521         /* free rxbd rings */
522         rtl8821ce_free_rxbd_ring(padapter);
523
524         /* free txbd rings */
525         for (i = 0; i < HW_QUEUE_ENTRY; i++)
526                 rtl8821ce_free_txbd_ring(padapter, i);
527
528
529         return _SUCCESS;
530 }
531
532
533 static u16
534 hal_mdio_read_8821ce(PADAPTER Adapter, u8 Addr)
535 {
536         u2Byte ret = 0;
537         u1Byte tmpU1b = 0, count = 0;
538
539         rtw_write8(Adapter, REG_PCIE_MIX_CFG_8821C, Addr | BIT6);
540         tmpU1b = rtw_read8(Adapter, REG_PCIE_MIX_CFG_8821C) & BIT6;
541         count = 0;
542         while (tmpU1b && count < 20) {
543                 rtw_udelay_os(10);
544                 tmpU1b = rtw_read8(Adapter, REG_PCIE_MIX_CFG_8821C) & BIT6;
545                 count++;
546         }
547         if (tmpU1b == 0)
548                 ret = rtw_read16(Adapter, REG_MDIO_V1_8821C);
549
550         return ret;
551 }
552
553
554 static VOID
555 hal_mdio_write_8821ce(PADAPTER Adapter, u8 Addr, u16 Data)
556 {
557         u1Byte tmpU1b = 0, count = 0;
558
559         rtw_write16(Adapter, REG_MDIO_V1_8821C, Data);
560         rtw_write8(Adapter, REG_PCIE_MIX_CFG_8821C, Addr | BIT5);
561         tmpU1b = rtw_read8(Adapter, REG_PCIE_MIX_CFG_8821C) & BIT5;
562         count = 0;
563         while (tmpU1b && count < 20) {
564                 rtw_udelay_os(10);
565                 tmpU1b = rtw_read8(Adapter, REG_PCIE_MIX_CFG_8821C) & BIT5;
566                 count++;
567         }
568 }
569
570
571 static void hal_dbi_write_8821ce(PADAPTER Adapter, u16 Addr, u8 Data)
572 {
573         u1Byte tmpU1b = 0, count = 0;
574         u2Byte WriteAddr = 0, Remainder = Addr % 4;
575
576         /* Write DBI 1Byte Data */
577         WriteAddr = REG_DBI_WDATA_V1_8821C + Remainder;
578         rtw_write8(Adapter, WriteAddr, Data);
579
580         /* Write DBI 2Byte Address & Write Enable */
581         WriteAddr = (Addr & 0xfffc) | (BIT0 << (Remainder + 12));
582         rtw_write16(Adapter, REG_DBI_FLAG_V1_8821C, WriteAddr);
583
584         /* Write DBI Write Flag */
585         rtw_write8(Adapter, REG_DBI_FLAG_V1_8821C + 2, 0x1);
586
587         tmpU1b = rtw_read8(Adapter, REG_DBI_FLAG_V1_8821C + 2);
588         count = 0;
589         while (tmpU1b && count < 20) {
590                 rtw_udelay_os(10);
591                 tmpU1b = rtw_read8(Adapter, REG_DBI_FLAG_V1_8821C + 2);
592                 count++;
593         }
594 }
595
596 static u8 hal_dbi_read_8821ce(PADAPTER Adapter, u16 Addr)
597 {
598         u16 ReadAddr = Addr & 0xfffc;
599         u8 ret = 0, tmpU1b = 0, count = 0;
600
601         rtw_write16(Adapter, REG_DBI_FLAG_V1_8821C, ReadAddr);
602         rtw_write8(Adapter, REG_DBI_FLAG_V1_8821C + 2, 0x2);
603         tmpU1b = rtw_read8(Adapter, REG_DBI_FLAG_V1_8821C + 2);
604         count = 0;
605         while (tmpU1b && count < 20) {
606                 rtw_udelay_os(10);
607                 tmpU1b = rtw_read8(Adapter, REG_DBI_FLAG_V1_8821C + 2);
608                 count++;
609         }
610         if (tmpU1b == 0) {
611                 ReadAddr = REG_DBI_RDATA_V1_8821C + Addr % 4;
612                 ret = rtw_read8(Adapter, ReadAddr);
613         }
614
615         return ret;
616 }
617
618 /*
619 *       Description:
620 *               Query setting of specified variable.
621 */
622 static u8 gethaldefvar(PADAPTER padapter, HAL_DEF_VARIABLE eVariable, PVOID pValue)
623 {
624         HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
625         u8 bResult = _SUCCESS;
626
627         switch (eVariable) {
628
629         case HAL_DEF_MAX_RECVBUF_SZ:
630                 *((u32 *)pValue) = MAX_RECVBUF_SZ;
631                 break;
632
633         case HW_VAR_MAX_RX_AMPDU_FACTOR:
634                 *(HT_CAP_AMPDU_FACTOR *)pValue = MAX_AMPDU_FACTOR_64K;
635                 break;
636         default:
637                 bResult = rtl8821c_gethaldefvar(padapter, eVariable, pValue);
638                 break;
639         }
640
641         return bResult;
642 }
643
644 /*
645  * Description:
646  *      Change default setting of specified variable.
647  */
648 static u8 sethaldefvar(PADAPTER adapter, HAL_DEF_VARIABLE eVariable, void *pval)
649 {
650         PHAL_DATA_TYPE hal = GET_HAL_DATA(adapter);
651         u8 bResult = _SUCCESS;
652
653         switch (eVariable) {
654         default:
655                 bResult = rtl8821c_sethaldefvar(adapter, eVariable, pval);
656                 break;
657         }
658
659         return bResult;
660 }
661
662 /*
663  * If variable not handled here,
664  * some variables will be processed in rtl8821c_sethwreg()
665  */
666 static u8 sethwreg(PADAPTER adapter, u8 variable, u8 *val)
667 {
668         PHAL_DATA_TYPE hal;
669         u8 ret = _SUCCESS;
670         u8 val8;
671
672
673         hal = GET_HAL_DATA(adapter);
674
675         switch (variable) {
676
677         case HW_VAR_DBI:
678         {
679                 u16 *pCmd;
680
681                 pCmd = (u16 *)val;
682                 hal_dbi_write_8821ce(adapter, pCmd[0], (u8)pCmd[1]);
683                 break;
684         }
685         case HW_VAR_MDIO:
686         {
687                 u16 *pCmd;
688
689                 pCmd = (u16 *)val;
690                 hal_mdio_write_8821ce(adapter, (u8)pCmd[0], pCmd[1]);
691                 break;
692         }
693 #ifdef CONFIG_LPS_LCLK
694         case HW_VAR_SET_RPWM:
695         {
696                 u8 ps_state = *((u8 *)val);
697                 /* rpwm value only use BIT0(clock bit) ,BIT6(Ack bit), and BIT7(Toggle bit) for 88e. */
698                 /* BIT0 value - 1: 32k, 0:40MHz. */
699                 /* BIT6 value - 1: report cpwm value after success set, 0:do not report. */
700                 /* BIT7 value - Toggle bit change. */
701                 /* modify by Thomas. 2012/4/2. */
702                 ps_state = ps_state & 0xC1;
703                 /* RTW_INFO("##### Change RPWM value to = %x for switch clk #####\n",ps_state); */
704                 rtw_write8(adapter, REG_PCIE_HRPWM1_V1_8821C, ps_state);
705                 break;
706         }
707 #endif
708
709         default:
710                 ret = rtl8821c_sethwreg(adapter, variable, val);
711                 break;
712         }
713
714         return ret;
715 }
716
717 /*
718  * If variable not handled here,
719  * some variables will be processed in GetHwReg8723B()
720  */
721 static void gethwreg(PADAPTER adapter, u8 variable, u8 *val)
722 {
723         PHAL_DATA_TYPE hal;
724
725
726         hal = GET_HAL_DATA(adapter);
727         switch (variable) {
728         case HW_VAR_DBI:
729                 *val = hal_dbi_read_8821ce(adapter, *((u16 *)(val)));
730                 break;
731         case HW_VAR_MDIO:
732                 *((u16 *)(val)) = hal_mdio_read_8821ce(adapter, *val);
733                 break;
734         case HW_VAR_L1OFF_NIC_SUPPORT:
735                 {
736                 u8 l1off;
737
738                 l1off = hal_dbi_read_8821ce(adapter, 0x168);
739                 if (l1off & (BIT2|BIT3))
740                         *val = _TRUE;
741                 else
742                         *val = _FALSE;
743                 }
744                 break;
745         case HW_VAR_L1OFF_CAPABILITY:
746                 {
747                 u8 l1off;
748
749                 l1off = hal_dbi_read_8821ce(adapter, 0x164);
750                 if (l1off & (BIT2|BIT3))
751                         *val = _TRUE;
752                 else
753                         *val = _FALSE;
754                 }
755                 break;
756
757 #ifdef CONFIG_LPS_LCLK
758         case HW_VAR_CPWM:
759                 *val = rtw_read8(adapter, REG_PCIE_HCPWM1_V1_8821C);
760                 break;
761 #endif
762
763         default:
764                 rtl8821c_gethwreg(adapter, variable, val);
765                 break;
766         }
767 }
768
769 void rtl8821ce_set_hal_ops(PADAPTER padapter)
770 {
771         struct hal_ops *ops;
772         int err;
773
774         err = rtl8821ce_halmac_init_adapter(padapter);
775         if (err) {
776                 RTW_INFO("%s: [ERROR]HALMAC initialize FAIL!\n", __func__);
777                 return;
778         }
779
780         rtl8821c_set_hal_ops(padapter);
781
782         ops = &padapter->hal_func;
783
784         ops->hal_init = rtl8821ce_hal_init;
785         ops->hal_deinit = rtl8821ce_hal_deinit;
786         ops->inirp_init = rtl8821ce_init_bd;
787         ops->inirp_deinit = rtl8821ce_free_bd;
788         ops->irp_reset = rtl8821ce_reset_bd;
789         ops->init_xmit_priv = rtl8821ce_init_xmit_priv;
790         ops->free_xmit_priv = rtl8821ce_free_xmit_priv;
791         ops->init_recv_priv = rtl8821ce_init_recv_priv;
792         ops->free_recv_priv = rtl8821ce_free_recv_priv;
793
794 #ifdef CONFIG_RTW_SW_LED
795         ops->InitSwLeds = rtl8821ce_InitSwLeds;
796         ops->DeInitSwLeds = rtl8821ce_DeInitSwLeds;
797 #endif
798
799         ops->init_default_value = rtl8821ce_init_default_value;
800         ops->intf_chip_configure = intf_chip_configure;
801         ops->read_adapter_info = read_adapter_info;
802
803         ops->enable_interrupt = rtl8821ce_enable_interrupt;
804         ops->disable_interrupt = rtl8821ce_disable_interrupt;
805         ops->interrupt_handler = rtl8821ce_interrupt;
806         /*
807         * ops->check_ips_status = check_ips_status;
808         */
809         ops->clear_interrupt = rtl8821ce_clear_interrupt;
810 #if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) ||\
811         defined(CONFIG_PCI_HCI)
812         /*
813         * ops->clear_interrupt = clear_interrupt_all;
814         */
815 #endif
816
817         ops->set_hw_reg_handler = sethwreg;
818         ops->GetHwRegHandler = gethwreg;
819         ops->get_hal_def_var_handler = gethaldefvar;
820         ops->SetHalDefVarHandler = sethaldefvar;
821
822         ops->hal_xmit = rtl8821ce_hal_xmit;
823         ops->mgnt_xmit = rtl8821ce_mgnt_xmit;
824         ops->hal_xmitframe_enqueue = rtl8821ce_hal_xmitframe_enqueue;
825 #ifdef CONFIG_HOSTAPD_MLME
826         ops->hostap_mgnt_xmit_entry = rtl8821ce_hostap_mgnt_xmit_entry;
827 #endif
828
829 #ifdef CONFIG_XMIT_THREAD_MODE
830         /* TODO */
831         ops->xmit_thread_handler = rtl8821ce_xmit_buf_handler;
832 #endif
833         ops->hal_set_l1ssbackdoor_handler = rtw_pci_aspm_config_l1off_general;
834 }