net: wireless: rockchip_wlan: add rtl8723ds support
[firefly-linux-kernel-4.4.55.git] / drivers / net / wireless / rockchip_wlan / rtl8723ds / hal / rtl8723d / sdio / sdio_ops.c
1 /******************************************************************************
2  *
3  * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
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  * You should have received a copy of the GNU General Public License along with
15  * this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
17  *
18  *******************************************************************************/
19 #define _SDIO_OPS_C_
20
21 #include <rtl8723d_hal.h>
22
23 /* #define SDIO_DEBUG_IO 1 */
24
25
26 /*
27  * Description:
28  *      The following mapping is for SDIO host local register space.
29  *
30  * Creadted by Roger, 2011.01.31.
31  *   */
32 static void HalSdioGetCmdAddr8723DSdio(
33         IN      PADAPTER                        padapter,
34         IN      u8                              DeviceID,
35         IN      u32                             Addr,
36         OUT     u32                             *pCmdAddr
37 )
38 {
39         switch (DeviceID) {
40         case SDIO_LOCAL_DEVICE_ID:
41                 *pCmdAddr = ((SDIO_LOCAL_DEVICE_ID << 13) | (Addr & SDIO_LOCAL_MSK));
42                 break;
43
44         case WLAN_IOREG_DEVICE_ID:
45                 *pCmdAddr = ((WLAN_IOREG_DEVICE_ID << 13) | (Addr & WLAN_IOREG_MSK));
46                 break;
47
48         case WLAN_TX_HIQ_DEVICE_ID:
49                 *pCmdAddr = ((WLAN_TX_HIQ_DEVICE_ID << 13) | (Addr & WLAN_FIFO_MSK));
50                 break;
51
52         case WLAN_TX_MIQ_DEVICE_ID:
53                 *pCmdAddr = ((WLAN_TX_MIQ_DEVICE_ID << 13) | (Addr & WLAN_FIFO_MSK));
54                 break;
55
56         case WLAN_TX_LOQ_DEVICE_ID:
57                 *pCmdAddr = ((WLAN_TX_LOQ_DEVICE_ID << 13) | (Addr & WLAN_FIFO_MSK));
58                 break;
59
60         case WLAN_RX0FF_DEVICE_ID:
61                 *pCmdAddr = ((WLAN_RX0FF_DEVICE_ID << 13) | (Addr & WLAN_RX0FF_MSK));
62                 break;
63
64         default:
65                 break;
66         }
67 }
68
69 static u8 get_deviceid(u32 addr)
70 {
71         u8 devideId;
72         u16 pseudoId;
73
74
75         pseudoId = (u16)(addr >> 16);
76         switch (pseudoId) {
77         case 0x1025:
78                 devideId = SDIO_LOCAL_DEVICE_ID;
79                 break;
80
81         case 0x1026:
82                 devideId = WLAN_IOREG_DEVICE_ID;
83                 break;
84
85         /*              case 0x1027:
86          *                      devideId = SDIO_FIRMWARE_FIFO;
87          *                      break; */
88
89         case 0x1031:
90                 devideId = WLAN_TX_HIQ_DEVICE_ID;
91                 break;
92
93         case 0x1032:
94                 devideId = WLAN_TX_MIQ_DEVICE_ID;
95                 break;
96
97         case 0x1033:
98                 devideId = WLAN_TX_LOQ_DEVICE_ID;
99                 break;
100
101         case 0x1034:
102                 devideId = WLAN_RX0FF_DEVICE_ID;
103                 break;
104
105         default:
106                 /*                      devideId = (u8)((addr >> 13) & 0xF); */
107                 devideId = WLAN_IOREG_DEVICE_ID;
108                 break;
109         }
110
111         return devideId;
112 }
113
114 /*
115  * Ref:
116  *      HalSdioGetCmdAddr8723DSdio()
117  */
118 static u32 _cvrt2ftaddr(const u32 addr, u8 *pdeviceId, u16 *poffset)
119 {
120         u8 deviceId;
121         u16 offset;
122         u32 ftaddr;
123
124
125         deviceId = get_deviceid(addr);
126         offset = 0;
127
128         switch (deviceId) {
129         case SDIO_LOCAL_DEVICE_ID:
130                 offset = addr & SDIO_LOCAL_MSK;
131                 break;
132
133         case WLAN_TX_HIQ_DEVICE_ID:
134         case WLAN_TX_MIQ_DEVICE_ID:
135         case WLAN_TX_LOQ_DEVICE_ID:
136                 offset = addr & WLAN_FIFO_MSK;
137                 break;
138
139         case WLAN_RX0FF_DEVICE_ID:
140                 offset = addr & WLAN_RX0FF_MSK;
141                 break;
142
143         case WLAN_IOREG_DEVICE_ID:
144         default:
145                 deviceId = WLAN_IOREG_DEVICE_ID;
146                 offset = addr & WLAN_IOREG_MSK;
147                 break;
148         }
149         ftaddr = (deviceId << 13) | offset;
150
151         if (pdeviceId)
152                 *pdeviceId = deviceId;
153         if (poffset)
154                 *poffset = offset;
155
156         return ftaddr;
157 }
158
159 u8 sdio_read8(struct intf_hdl *pintfhdl, u32 addr)
160 {
161         u32 ftaddr;
162         u8 val;
163
164         ftaddr = _cvrt2ftaddr(addr, NULL, NULL);
165         val = sd_read8(pintfhdl, ftaddr, NULL);
166
167
168         return val;
169 }
170
171 u16 sdio_read16(struct intf_hdl *pintfhdl, u32 addr)
172 {
173         u32 ftaddr;
174         u16 val;
175
176         ftaddr = _cvrt2ftaddr(addr, NULL, NULL);
177         val = 0;
178         sd_cmd52_read(pintfhdl, ftaddr, 2, (u8 *)&val);
179         val = le16_to_cpu(val);
180
181
182         return val;
183 }
184
185 u32 sdio_read32(struct intf_hdl *pintfhdl, u32 addr)
186 {
187         PADAPTER padapter;
188         u8 bMacPwrCtrlOn;
189         u8 deviceId;
190         u16 offset;
191         u32 ftaddr;
192         u8 shift;
193         u32 val;
194         s32 err;
195
196
197         padapter = pintfhdl->padapter;
198         ftaddr = _cvrt2ftaddr(addr, &deviceId, &offset);
199
200         bMacPwrCtrlOn = _FALSE;
201         rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn);
202         if (((deviceId == WLAN_IOREG_DEVICE_ID) && (offset < 0x100))
203             || (_FALSE == bMacPwrCtrlOn)
204 #ifdef CONFIG_LPS_LCLK
205             || (_TRUE == adapter_to_pwrctl(padapter)->bFwCurrentInPSMode)
206 #endif
207            ) {
208                 val = 0;
209                 err = sd_cmd52_read(pintfhdl, ftaddr, 4, (u8 *)&val);
210 #ifdef SDIO_DEBUG_IO
211                 if (!err) {
212 #endif
213                         val = le32_to_cpu(val);
214                         return val;
215 #ifdef SDIO_DEBUG_IO
216                 }
217
218                 RTW_ERR("%s: Mac Power off, Read FAIL(%d)! addr=0x%x\n",
219                         __func__, err, addr);
220
221                 return SDIO_ERR_VAL32;
222 #endif
223         }
224
225         /* 4 bytes alignment */
226         shift = ftaddr & 0x3;
227         if (shift == 0)
228                 val = sd_read32(pintfhdl, ftaddr, NULL);
229         else {
230                 u8 *ptmpbuf;
231
232                 ptmpbuf = (u8 *)rtw_malloc(8);
233                 if (NULL == ptmpbuf) {
234                         RTW_ERR("%s: Allocate memory FAIL!(size=8) addr=0x%x\n",
235                                 __func__, addr);
236                         return SDIO_ERR_VAL32;
237                 }
238
239                 ftaddr &= ~(u16)0x3;
240                 sd_read(pintfhdl, ftaddr, 8, ptmpbuf);
241                 _rtw_memcpy(&val, ptmpbuf + shift, 4);
242                 val = le32_to_cpu(val);
243
244                 rtw_mfree(ptmpbuf, 8);
245         }
246
247
248         return val;
249 }
250
251 s32 sdio_readN(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pbuf)
252 {
253         PADAPTER padapter;
254         u8 bMacPwrCtrlOn;
255         u8 deviceId;
256         u16 offset;
257         u32 ftaddr;
258         u8 shift;
259         s32 err;
260
261
262         padapter = pintfhdl->padapter;
263         err = 0;
264
265         ftaddr = _cvrt2ftaddr(addr, &deviceId, &offset);
266
267         bMacPwrCtrlOn = _FALSE;
268         rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn);
269         if (((deviceId == WLAN_IOREG_DEVICE_ID) && (offset < 0x100))
270             || (_FALSE == bMacPwrCtrlOn)
271 #ifdef CONFIG_LPS_LCLK
272             || (_TRUE == adapter_to_pwrctl(padapter)->bFwCurrentInPSMode)
273 #endif
274            ) {
275                 err = sd_cmd52_read(pintfhdl, ftaddr, cnt, pbuf);
276                 return err;
277         }
278
279         /* 4 bytes alignment */
280         shift = ftaddr & 0x3;
281         if (shift == 0)
282                 err = sd_read(pintfhdl, ftaddr, cnt, pbuf);
283         else {
284                 u8 *ptmpbuf;
285                 u32 n;
286
287                 ftaddr &= ~(u16)0x3;
288                 n = cnt + shift;
289                 ptmpbuf = rtw_malloc(n);
290                 if (NULL == ptmpbuf)
291                         return -1;
292                 err = sd_read(pintfhdl, ftaddr, n, ptmpbuf);
293                 if (!err)
294                         _rtw_memcpy(pbuf, ptmpbuf + shift, cnt);
295                 rtw_mfree(ptmpbuf, n);
296         }
297
298
299         return err;
300 }
301
302 s32 sdio_write8(struct intf_hdl *pintfhdl, u32 addr, u8 val)
303 {
304         u32 ftaddr;
305         s32 err;
306
307         ftaddr = _cvrt2ftaddr(addr, NULL, NULL);
308         err = 0;
309         sd_write8(pintfhdl, ftaddr, val, &err);
310
311
312         return err;
313 }
314
315 s32 sdio_write16(struct intf_hdl *pintfhdl, u32 addr, u16 val)
316 {
317         u32 ftaddr;
318         u8 shift;
319         s32 err;
320
321         ftaddr = _cvrt2ftaddr(addr, NULL, NULL);
322         val = cpu_to_le16(val);
323         err = sd_cmd52_write(pintfhdl, ftaddr, 2, (u8 *)&val);
324
325
326         return err;
327 }
328
329 s32 sdio_write32(struct intf_hdl *pintfhdl, u32 addr, u32 val)
330 {
331         PADAPTER padapter;
332         u8 bMacPwrCtrlOn;
333         u8 deviceId;
334         u16 offset;
335         u32 ftaddr;
336         u8 shift;
337         s32 err;
338
339
340         padapter = pintfhdl->padapter;
341         err = 0;
342
343         ftaddr = _cvrt2ftaddr(addr, &deviceId, &offset);
344
345         bMacPwrCtrlOn = _FALSE;
346         rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn);
347         if (((deviceId == WLAN_IOREG_DEVICE_ID) && (offset < 0x100))
348             || (_FALSE == bMacPwrCtrlOn)
349 #ifdef CONFIG_LPS_LCLK
350             || (_TRUE == adapter_to_pwrctl(padapter)->bFwCurrentInPSMode)
351 #endif
352            ) {
353                 val = cpu_to_le32(val);
354                 err = sd_cmd52_write(pintfhdl, ftaddr, 4, (u8 *)&val);
355                 return err;
356         }
357
358         /* 4 bytes alignment */
359         shift = ftaddr & 0x3;
360 #if 1
361         if (shift == 0)
362                 sd_write32(pintfhdl, ftaddr, val, &err);
363         else {
364                 val = cpu_to_le32(val);
365                 err = sd_cmd52_write(pintfhdl, ftaddr, 4, (u8 *)&val);
366         }
367 #else
368         if (shift == 0)
369                 sd_write32(pintfhdl, ftaddr, val, &err);
370         else {
371                 u8 *ptmpbuf;
372
373                 ptmpbuf = (u8 *)rtw_malloc(8);
374                 if (NULL == ptmpbuf)
375                         return -1;
376
377                 ftaddr &= ~(u16)0x3;
378                 err = sd_read(pintfhdl, ftaddr, 8, ptmpbuf);
379                 if (err) {
380                         rtw_mfree(ptmpbuf, 8);
381                         return err;
382                 }
383                 val = cpu_to_le32(val);
384                 _rtw_memcpy(ptmpbuf + shift, &val, 4);
385                 err = sd_write(pintfhdl, ftaddr, 8, ptmpbuf);
386
387                 rtw_mfree(ptmpbuf, 8);
388         }
389 #endif
390
391
392         return err;
393 }
394
395 s32 sdio_writeN(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pbuf)
396 {
397         PADAPTER padapter;
398         u8 bMacPwrCtrlOn;
399         u8 deviceId;
400         u16 offset;
401         u32 ftaddr;
402         u8 shift;
403         s32 err;
404
405
406         padapter = pintfhdl->padapter;
407         err = 0;
408
409         ftaddr = _cvrt2ftaddr(addr, &deviceId, &offset);
410
411         bMacPwrCtrlOn = _FALSE;
412         rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn);
413         if (((deviceId == WLAN_IOREG_DEVICE_ID) && (offset < 0x100))
414             || (_FALSE == bMacPwrCtrlOn)
415 #ifdef CONFIG_LPS_LCLK
416             || (_TRUE == adapter_to_pwrctl(padapter)->bFwCurrentInPSMode)
417 #endif
418            ) {
419                 err = sd_cmd52_write(pintfhdl, ftaddr, cnt, pbuf);
420                 return err;
421         }
422
423         shift = ftaddr & 0x3;
424         if (shift == 0)
425                 err = sd_write(pintfhdl, ftaddr, cnt, pbuf);
426         else {
427                 u8 *ptmpbuf;
428                 u32 n;
429
430                 ftaddr &= ~(u16)0x3;
431                 n = cnt + shift;
432                 ptmpbuf = rtw_malloc(n);
433                 if (NULL == ptmpbuf)
434                         return -1;
435                 err = sd_read(pintfhdl, ftaddr, 4, ptmpbuf);
436                 if (err) {
437                         rtw_mfree(ptmpbuf, n);
438                         return err;
439                 }
440                 _rtw_memcpy(ptmpbuf + shift, pbuf, cnt);
441                 err = sd_write(pintfhdl, ftaddr, n, ptmpbuf);
442                 rtw_mfree(ptmpbuf, n);
443         }
444
445
446         return err;
447 }
448
449 u8 sdio_f0_read8(struct intf_hdl *pintfhdl, u32 addr)
450 {
451         u32 ftaddr;
452         u8 val;
453
454         val = sd_f0_read8(pintfhdl, addr, NULL);
455
456
457         return val;
458 }
459
460 void sdio_read_mem(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem)
461 {
462         s32 err;
463
464
465         err = sdio_readN(pintfhdl, addr, cnt, rmem);
466
467 }
468
469 void sdio_write_mem(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem)
470 {
471
472         sdio_writeN(pintfhdl, addr, cnt, wmem);
473
474 }
475
476 /*
477  * Description:
478  *      Read from RX FIFO
479  *      Round read size to block size,
480  *      and make sure data transfer will be done in one command.
481  *
482  * Parameters:
483  *      pintfhdl        a pointer of intf_hdl
484  *      addr            port ID
485  *      cnt                     size to read
486  *      rmem            address to put data
487  *
488  * Return:
489  *      _SUCCESS(1)             Success
490  *      _FAIL(0)                Fail
491  */
492 static u32 sdio_read_port(
493         struct intf_hdl *pintfhdl,
494         u32 addr,
495         u32 cnt,
496         u8 *mem)
497 {
498         PADAPTER padapter;
499         PSDIO_DATA psdio;
500         PHAL_DATA_TYPE phal;
501         u32 oldcnt;
502 #ifdef SDIO_DYNAMIC_ALLOC_MEM
503         u8 *oldmem;
504 #endif
505         s32 err;
506
507
508         padapter = pintfhdl->padapter;
509         psdio = &adapter_to_dvobj(padapter)->intf_data;
510         phal = GET_HAL_DATA(padapter);
511
512         HalSdioGetCmdAddr8723DSdio(padapter, addr, phal->SdioRxFIFOCnt++, &addr);
513
514         oldcnt = cnt;
515         if (cnt > psdio->block_transfer_len)
516                 cnt = _RND(cnt, psdio->block_transfer_len);
517         /*      cnt = sdio_align_size(cnt); */
518
519         if (oldcnt != cnt) {
520 #ifdef SDIO_DYNAMIC_ALLOC_MEM
521                 oldmem = mem;
522                 mem = rtw_malloc(cnt);
523                 if (mem == NULL) {
524                         RTW_WARN("%s: allocate memory %d bytes fail!\n",
525                                  __func__, cnt);
526                         mem = oldmem;
527                         oldmem == NULL;
528                 }
529 #else
530                 /* in this case, caller should gurante the buffer is big enough */
531                 /* to receive data after alignment */
532 #endif
533         }
534
535         err = _sd_read(pintfhdl, addr, cnt, mem);
536
537 #ifdef SDIO_DYNAMIC_ALLOC_MEM
538         if ((oldcnt != cnt) && (oldmem)) {
539                 _rtw_memcpy(oldmem, mem, oldcnt);
540                 rtw_mfree(mem, cnt);
541         }
542 #endif
543
544         if (err)
545                 return _FAIL;
546         return _SUCCESS;
547 }
548
549 /*
550  * Description:
551  *      Write to TX FIFO
552  *      Align write size block size,
553  *      and make sure data could be written in one command.
554  *
555  * Parameters:
556  *      pintfhdl        a pointer of intf_hdl
557  *      addr            port ID
558  *      cnt                     size to write
559  *      wmem            data pointer to write
560  *
561  * Return:
562  *      _SUCCESS(1)             Success
563  *      _FAIL(0)                Fail
564  */
565 static u32 sdio_write_port(
566         struct intf_hdl *pintfhdl,
567         u32 addr,
568         u32 cnt,
569         u8 *mem)
570 {
571         PADAPTER padapter;
572         PSDIO_DATA psdio;
573         s32 err;
574         struct xmit_buf *xmitbuf = (struct xmit_buf *)mem;
575
576         padapter = pintfhdl->padapter;
577         psdio = &adapter_to_dvobj(padapter)->intf_data;
578
579 #ifndef CONFIG_DLFW_TXPKT
580         if (!rtw_is_hw_init_completed(padapter)) {
581                 RTW_INFO("%s [addr=0x%x cnt=%d] hw_init_completed is FALSE\n",
582                          __func__, addr, cnt);
583                 return _FAIL;
584         }
585 #endif
586
587         cnt = _RND4(cnt);
588         HalSdioGetCmdAddr8723DSdio(padapter, addr, cnt >> 2, &addr);
589
590         if (cnt > psdio->block_transfer_len)
591                 cnt = _RND(cnt, psdio->block_transfer_len);
592         /*      cnt = sdio_align_size(cnt); */
593
594         err = sd_write(pintfhdl, addr, cnt, xmitbuf->pdata);
595
596         rtw_sctx_done_err(&xmitbuf->sctx,
597                   err ? RTW_SCTX_DONE_WRITE_PORT_ERR : RTW_SCTX_DONE_SUCCESS);
598
599         if (err)
600                 return _FAIL;
601         return _SUCCESS;
602 }
603
604 void sdio_set_intf_ops(_adapter *padapter, struct _io_ops *pops)
605 {
606
607         pops->_read8 = &sdio_read8;
608         pops->_read16 = &sdio_read16;
609         pops->_read32 = &sdio_read32;
610         pops->_read_mem = &sdio_read_mem;
611         pops->_read_port = &sdio_read_port;
612
613         pops->_write8 = &sdio_write8;
614         pops->_write16 = &sdio_write16;
615         pops->_write32 = &sdio_write32;
616         pops->_writeN = &sdio_writeN;
617         pops->_write_mem = &sdio_write_mem;
618         pops->_write_port = &sdio_write_port;
619
620         pops->_sd_f0_read8 = sdio_f0_read8;
621
622 }
623
624 /*
625  * Todo: align address to 4 bytes.
626  */
627 s32 _sdio_local_read(
628         PADAPTER        padapter,
629         u32                     addr,
630         u32                     cnt,
631         u8                      *pbuf)
632 {
633         struct intf_hdl *pintfhdl;
634         u8 bMacPwrCtrlOn;
635         s32 err;
636         u8 *ptmpbuf;
637         u32 n;
638
639
640         pintfhdl = &padapter->iopriv.intf;
641
642         HalSdioGetCmdAddr8723DSdio(padapter, SDIO_LOCAL_DEVICE_ID, addr, &addr);
643
644         bMacPwrCtrlOn = _FALSE;
645         rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn);
646         if (_FALSE == bMacPwrCtrlOn) {
647                 err = _sd_cmd52_read(pintfhdl, addr, cnt, pbuf);
648                 return err;
649         }
650
651         n = RND4(cnt);
652         ptmpbuf = (u8 *)rtw_malloc(n);
653         if (!ptmpbuf)
654                 return -1;
655
656         err = _sd_read(pintfhdl, addr, n, ptmpbuf);
657         if (!err)
658                 _rtw_memcpy(pbuf, ptmpbuf, cnt);
659
660         if (ptmpbuf)
661                 rtw_mfree(ptmpbuf, n);
662
663         return err;
664 }
665
666 /*
667  * Todo: align address to 4 bytes.
668  */
669 s32 sdio_local_read(
670         PADAPTER        padapter,
671         u32                     addr,
672         u32                     cnt,
673         u8                      *pbuf)
674 {
675         struct intf_hdl *pintfhdl;
676         u8 bMacPwrCtrlOn;
677         s32 err;
678         u8 *ptmpbuf;
679         u32 n;
680
681         pintfhdl = &padapter->iopriv.intf;
682
683         HalSdioGetCmdAddr8723DSdio(padapter, SDIO_LOCAL_DEVICE_ID, addr, &addr);
684
685         bMacPwrCtrlOn = _FALSE;
686         rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn);
687         if ((_FALSE == bMacPwrCtrlOn)
688 #ifdef CONFIG_LPS_LCLK
689             || (_TRUE == adapter_to_pwrctl(padapter)->bFwCurrentInPSMode)
690 #endif
691            ) {
692                 err = sd_cmd52_read(pintfhdl, addr, cnt, pbuf);
693                 return err;
694         }
695
696         n = RND4(cnt);
697         ptmpbuf = (u8 *)rtw_malloc(n);
698         if (!ptmpbuf)
699                 return -1;
700
701         err = sd_read(pintfhdl, addr, n, ptmpbuf);
702         if (!err)
703                 _rtw_memcpy(pbuf, ptmpbuf, cnt);
704
705         if (ptmpbuf)
706                 rtw_mfree(ptmpbuf, n);
707
708         return err;
709 }
710
711 /*
712  * Todo: align address to 4 bytes.
713  */
714 s32 _sdio_local_write(
715         PADAPTER        padapter,
716         u32                     addr,
717         u32                     cnt,
718         u8                      *pbuf)
719 {
720         struct intf_hdl *pintfhdl;
721         u8 bMacPwrCtrlOn;
722         s32 err;
723         u8 *ptmpbuf;
724
725         if (addr & 0x3)
726                 RTW_INFO("%s, address must be 4 bytes alignment\n", __func__);
727
728         if (cnt  & 0x3)
729                 RTW_INFO("%s, size must be the multiple of 4\n", __func__);
730
731         pintfhdl = &padapter->iopriv.intf;
732
733         HalSdioGetCmdAddr8723DSdio(padapter, SDIO_LOCAL_DEVICE_ID, addr, &addr);
734
735         bMacPwrCtrlOn = _FALSE;
736         rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn);
737         if ((_FALSE == bMacPwrCtrlOn)
738 #ifdef CONFIG_LPS_LCLK
739             || (_TRUE == adapter_to_pwrctl(padapter)->bFwCurrentInPSMode)
740 #endif
741            ) {
742                 err = _sd_cmd52_write(pintfhdl, addr, cnt, pbuf);
743                 return err;
744         }
745
746         ptmpbuf = (u8 *)rtw_malloc(cnt);
747         if (!ptmpbuf)
748                 return -1;
749
750         _rtw_memcpy(ptmpbuf, pbuf, cnt);
751
752         err = _sd_write(pintfhdl, addr, cnt, ptmpbuf);
753
754         if (ptmpbuf)
755                 rtw_mfree(ptmpbuf, cnt);
756
757         return err;
758 }
759
760 /*
761  * Todo: align address to 4 bytes.
762  */
763 s32 sdio_local_write(
764         PADAPTER        padapter,
765         u32             addr,
766         u32             cnt,
767         u8              *pbuf)
768 {
769         struct intf_hdl *pintfhdl;
770         u8 bMacPwrCtrlOn;
771         s32 err;
772         u8 *ptmpbuf;
773
774         if (addr & 0x3)
775                 RTW_INFO("%s, address must be 4 bytes alignment\n", __func__);
776
777         if (cnt  & 0x3)
778                 RTW_INFO("%s, size must be the multiple of 4\n", __func__);
779
780         pintfhdl = &padapter->iopriv.intf;
781
782         HalSdioGetCmdAddr8723DSdio(padapter, SDIO_LOCAL_DEVICE_ID, addr, &addr);
783
784         bMacPwrCtrlOn = _FALSE;
785         rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn);
786         if ((_FALSE == bMacPwrCtrlOn)
787 #ifdef CONFIG_LPS_LCLK
788             || (_TRUE == adapter_to_pwrctl(padapter)->bFwCurrentInPSMode)
789 #endif
790            ) {
791                 err = sd_cmd52_write(pintfhdl, addr, cnt, pbuf);
792                 return err;
793         }
794
795         ptmpbuf = (u8 *)rtw_malloc(cnt);
796         if (!ptmpbuf)
797                 return -1;
798
799         _rtw_memcpy(ptmpbuf, pbuf, cnt);
800
801         err = sd_write(pintfhdl, addr, cnt, ptmpbuf);
802
803         if (ptmpbuf)
804                 rtw_mfree(ptmpbuf, cnt);
805
806         return err;
807 }
808
809 u8 SdioLocalCmd52Read1Byte(PADAPTER padapter, u32 addr)
810 {
811         u8 val = 0;
812         struct intf_hdl *pintfhdl = &padapter->iopriv.intf;
813
814         HalSdioGetCmdAddr8723DSdio(padapter, SDIO_LOCAL_DEVICE_ID, addr, &addr);
815         sd_cmd52_read(pintfhdl, addr, 1, &val);
816
817         return val;
818 }
819
820 u16 SdioLocalCmd52Read2Byte(PADAPTER padapter, u32 addr)
821 {
822         u16 val = 0;
823         struct intf_hdl *pintfhdl = &padapter->iopriv.intf;
824
825         HalSdioGetCmdAddr8723DSdio(padapter, SDIO_LOCAL_DEVICE_ID, addr, &addr);
826         sd_cmd52_read(pintfhdl, addr, 2, (u8 *)&val);
827
828         val = le16_to_cpu(val);
829
830         return val;
831 }
832
833 u32 SdioLocalCmd52Read4Byte(PADAPTER padapter, u32 addr)
834 {
835         u32 val = 0;
836         struct intf_hdl *pintfhdl = &padapter->iopriv.intf;
837
838         HalSdioGetCmdAddr8723DSdio(padapter, SDIO_LOCAL_DEVICE_ID, addr, &addr);
839         sd_cmd52_read(pintfhdl, addr, 4, (u8 *)&val);
840
841         val = le32_to_cpu(val);
842
843         return val;
844 }
845
846 u32 SdioLocalCmd53Read4Byte(PADAPTER padapter, u32 addr)
847 {
848
849         u8 bMacPwrCtrlOn;
850         u32 val = 0;
851         struct intf_hdl *pintfhdl = &padapter->iopriv.intf;
852
853         HalSdioGetCmdAddr8723DSdio(padapter, SDIO_LOCAL_DEVICE_ID, addr, &addr);
854         bMacPwrCtrlOn = _FALSE;
855         rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn);
856         if ((_FALSE == bMacPwrCtrlOn)
857 #ifdef CONFIG_LPS_LCLK
858             || (_TRUE == adapter_to_pwrctl(padapter)->bFwCurrentInPSMode)
859 #endif
860            ) {
861                 sd_cmd52_read(pintfhdl, addr, 4, (u8 *)&val);
862                 val = le32_to_cpu(val);
863         } else
864                 val = sd_read32(pintfhdl, addr, NULL);
865
866         return val;
867 }
868
869 void SdioLocalCmd52Write1Byte(PADAPTER padapter, u32 addr, u8 v)
870 {
871         struct intf_hdl *pintfhdl = &padapter->iopriv.intf;
872
873         HalSdioGetCmdAddr8723DSdio(padapter, SDIO_LOCAL_DEVICE_ID, addr, &addr);
874         sd_cmd52_write(pintfhdl, addr, 1, &v);
875 }
876
877 void SdioLocalCmd52Write2Byte(PADAPTER padapter, u32 addr, u16 v)
878 {
879         struct intf_hdl *pintfhdl = &padapter->iopriv.intf;
880
881         HalSdioGetCmdAddr8723DSdio(padapter, SDIO_LOCAL_DEVICE_ID, addr, &addr);
882         v = cpu_to_le16(v);
883         sd_cmd52_write(pintfhdl, addr, 2, (u8 *)&v);
884 }
885
886 void SdioLocalCmd52Write4Byte(PADAPTER padapter, u32 addr, u32 v)
887 {
888         struct intf_hdl *pintfhdl = &padapter->iopriv.intf;
889
890         HalSdioGetCmdAddr8723DSdio(padapter, SDIO_LOCAL_DEVICE_ID, addr, &addr);
891         v = cpu_to_le32(v);
892         sd_cmd52_write(pintfhdl, addr, 4, (u8 *)&v);
893 }
894
895 #if 0
896 void
897 DumpLoggedInterruptHistory8723Sdio(
898         PADAPTER                padapter
899 )
900 {
901         HAL_DATA_TYPE   *pHalData = GET_HAL_DATA(padapter);
902         u4Byte                          DebugLevel = DBG_LOUD;
903
904         if (DBG_Var.DbgPrintIsr == 0)
905                 return;
906
907         DBG_ChkDrvResource(padapter);
908
909
910
911 }
912
913 void
914 LogInterruptHistory8723Sdio(
915         PADAPTER                        padapter,
916         PRT_ISR_CONTENT pIsrContent
917 )
918 {
919         HAL_DATA_TYPE   *pHalData = GET_HAL_DATA(padapter);
920
921         if ((pHalData->IntrMask[0] & SDIO_HIMR_RX_REQUEST_MSK) &&
922             (pIsrContent->IntArray[0] & SDIO_HISR_RX_REQUEST))
923                 pHalData->InterruptLog.nISR_RX_REQUEST++;
924         if ((pHalData->IntrMask[0] & SDIO_HIMR_AVAL_MSK) &&
925             (pIsrContent->IntArray[0] & SDIO_HISR_AVAL))
926                 pHalData->InterruptLog.nISR_AVAL++;
927         if ((pHalData->IntrMask[0] & SDIO_HIMR_TXERR_MSK) &&
928             (pIsrContent->IntArray[0] & SDIO_HISR_TXERR))
929                 pHalData->InterruptLog.nISR_TXERR++;
930         if ((pHalData->IntrMask[0] & SDIO_HIMR_RXERR_MSK) &&
931             (pIsrContent->IntArray[0] & SDIO_HISR_RXERR))
932                 pHalData->InterruptLog.nISR_RXERR++;
933         if ((pHalData->IntrMask[0] & SDIO_HIMR_TXFOVW_MSK) &&
934             (pIsrContent->IntArray[0] & SDIO_HISR_TXFOVW))
935                 pHalData->InterruptLog.nISR_TXFOVW++;
936         if ((pHalData->IntrMask[0] & SDIO_HIMR_RXFOVW_MSK) &&
937             (pIsrContent->IntArray[0] & SDIO_HISR_RXFOVW))
938                 pHalData->InterruptLog.nISR_RXFOVW++;
939         if ((pHalData->IntrMask[0] & SDIO_HIMR_TXBCNOK_MSK) &&
940             (pIsrContent->IntArray[0] & SDIO_HISR_TXBCNOK))
941                 pHalData->InterruptLog.nISR_TXBCNOK++;
942         if ((pHalData->IntrMask[0] & SDIO_HIMR_TXBCNERR_MSK) &&
943             (pIsrContent->IntArray[0] & SDIO_HISR_TXBCNERR))
944                 pHalData->InterruptLog.nISR_TXBCNERR++;
945         if ((pHalData->IntrMask[0] & SDIO_HIMR_BCNERLY_INT_MSK) &&
946             (pIsrContent->IntArray[0] & SDIO_HISR_BCNERLY_INT))
947                 pHalData->InterruptLog.nISR_BCNERLY_INT++;
948         if ((pHalData->IntrMask[0] & SDIO_HIMR_C2HCMD_MSK) &&
949             (pIsrContent->IntArray[0] & SDIO_HISR_C2HCMD))
950                 pHalData->InterruptLog.nISR_C2HCMD++;
951         if ((pHalData->IntrMask[0] & SDIO_HIMR_CPWM1_MSK) &&
952             (pIsrContent->IntArray[0] & SDIO_HISR_CPWM1))
953                 pHalData->InterruptLog.nISR_CPWM1++;
954         if ((pHalData->IntrMask[0] & SDIO_HIMR_CPWM2_MSK) &&
955             (pIsrContent->IntArray[0] & SDIO_HISR_CPWM2))
956                 pHalData->InterruptLog.nISR_CPWM2++;
957         if ((pHalData->IntrMask[0] & SDIO_HIMR_HSISR_IND_MSK) &&
958             (pIsrContent->IntArray[0] & SDIO_HISR_HSISR_IND))
959                 pHalData->InterruptLog.nISR_HSISR_IND++;
960         if ((pHalData->IntrMask[0] & SDIO_HIMR_GTINT3_IND_MSK) &&
961             (pIsrContent->IntArray[0] & SDIO_HISR_GTINT3_IND))
962                 pHalData->InterruptLog.nISR_GTINT3_IND++;
963         if ((pHalData->IntrMask[0] & SDIO_HIMR_GTINT4_IND_MSK) &&
964             (pIsrContent->IntArray[0] & SDIO_HISR_GTINT4_IND))
965                 pHalData->InterruptLog.nISR_GTINT4_IND++;
966         if ((pHalData->IntrMask[0] & SDIO_HIMR_PSTIMEOUT_MSK) &&
967             (pIsrContent->IntArray[0] & SDIO_HISR_PSTIMEOUT))
968                 pHalData->InterruptLog.nISR_PSTIMEOUT++;
969         if ((pHalData->IntrMask[0] & SDIO_HIMR_OCPINT_MSK) &&
970             (pIsrContent->IntArray[0] & SDIO_HISR_OCPINT))
971                 pHalData->InterruptLog.nISR_OCPINT++;
972         if ((pHalData->IntrMask[0] & SDIO_HIMR_ATIMEND_MSK) &&
973             (pIsrContent->IntArray[0] & SDIO_HISR_ATIMEND))
974                 pHalData->InterruptLog.nISR_ATIMEND++;
975         if ((pHalData->IntrMask[0] & SDIO_HIMR_ATIMEND_E_MSK) &&
976             (pIsrContent->IntArray[0] & SDIO_HISR_ATIMEND_E))
977                 pHalData->InterruptLog.nISR_ATIMEND_E++;
978         if ((pHalData->IntrMask[0] & SDIO_HIMR_CTWEND_MSK) &&
979             (pIsrContent->IntArray[0] & SDIO_HISR_CTWEND))
980                 pHalData->InterruptLog.nISR_CTWEND++;
981
982 }
983
984 void
985 DumpHardwareProfile8723Sdio(
986         IN      PADAPTER                padapter
987 )
988 {
989         DumpLoggedInterruptHistory8723Sdio(padapter);
990 }
991 #endif
992
993 static s32 ReadInterrupt8723DSdio(PADAPTER padapter, u32 *phisr)
994 {
995         u32 hisr, himr;
996         u8 val8, hisr_len;
997
998
999         if (phisr == NULL)
1000                 return _FALSE;
1001
1002         himr = GET_HAL_DATA(padapter)->sdio_himr;
1003
1004         /* decide how many bytes need to be read */
1005         hisr_len = 0;
1006         while (himr) {
1007                 hisr_len++;
1008                 himr >>= 8;
1009         }
1010
1011         hisr = 0;
1012         while (hisr_len != 0) {
1013                 hisr_len--;
1014                 val8 = SdioLocalCmd52Read1Byte(padapter, SDIO_REG_HISR + hisr_len);
1015                 hisr |= (val8 << (8 * hisr_len));
1016         }
1017
1018         *phisr = hisr;
1019
1020         return _TRUE;
1021 }
1022
1023 /*
1024  *      Description:
1025  *              Initialize SDIO Host Interrupt Mask configuration variables for future use.
1026  *
1027  *      Assumption:
1028  *              Using SDIO Local register ONLY for configuration.
1029  *
1030  *      Created by Roger, 2011.02.11.
1031  *   */
1032 void InitInterrupt8723DSdio(PADAPTER padapter)
1033 {
1034         PHAL_DATA_TYPE pHalData;
1035
1036
1037         pHalData = GET_HAL_DATA(padapter);
1038         pHalData->sdio_himr = (u32)(
1039                                       SDIO_HIMR_RX_REQUEST_MSK                  |
1040 #ifdef CONFIG_SDIO_TX_ENABLE_AVAL_INT
1041                                       SDIO_HIMR_AVAL_MSK                                        |
1042 #endif
1043                                       /*                                                                SDIO_HIMR_TXERR_MSK                             |
1044                                        *                                                                SDIO_HIMR_RXERR_MSK                             |
1045                                        *                                                                SDIO_HIMR_TXFOVW_MSK                            |
1046                                        *                                                                SDIO_HIMR_RXFOVW_MSK                            |
1047                                        *                                                                SDIO_HIMR_TXBCNOK_MSK                           |
1048                                        *                                                                SDIO_HIMR_TXBCNERR_MSK                  |
1049                                        *                                                                SDIO_HIMR_BCNERLY_INT_MSK                       |
1050                                        *                                                                SDIO_HIMR_C2HCMD_MSK                            | */
1051 #if defined(CONFIG_LPS_LCLK) && !defined(CONFIG_DETECT_CPWM_BY_POLLING)
1052                                       SDIO_HIMR_CPWM1_MSK                               |
1053                                       /*                                                                SDIO_HIMR_CPWM2_MSK                             | */
1054 #endif /* CONFIG_LPS_LCLK && !CONFIG_DETECT_CPWM_BY_POLLING
1055  *                                                              SDIO_HIMR_HSISR_IND_MSK                 |
1056  *                                                              SDIO_HIMR_GTINT3_IND_MSK                        |
1057  *                                                              SDIO_HIMR_GTINT4_IND_MSK                        |
1058  *                                                              SDIO_HIMR_PSTIMEOUT_MSK                 |
1059  *                                                              SDIO_HIMR_OCPINT_MSK                            |
1060  *                                                              SDIO_HIMR_ATIMEND_MSK                           |
1061  *                                                              SDIO_HIMR_ATIMEND_E_MSK                 |
1062  *                                                              SDIO_HIMR_CTWEND_MSK                            | */
1063                                       0);
1064 }
1065
1066 /*
1067  *      Description:
1068  *              Initialize System Host Interrupt Mask configuration variables for future use.
1069  *
1070  *      Created by Roger, 2011.08.03.
1071  *   */
1072 void InitSysInterrupt8723DSdio(PADAPTER padapter)
1073 {
1074         PHAL_DATA_TYPE pHalData;
1075
1076
1077         pHalData = GET_HAL_DATA(padapter);
1078
1079         pHalData->SysIntrMask = (
1080                                         /*                                                      HSIMR_GPIO12_0_INT_EN                   |
1081                                          *                                                      HSIMR_SPS_OCP_INT_EN                    |
1082                                          *                                                      HSIMR_RON_INT_EN                                |
1083                                          *                                                      HSIMR_PDNINT_EN                         |
1084                                          *                                                      HSIMR_GPIO9_INT_EN                              | */
1085                                         0);
1086 }
1087
1088 #ifdef CONFIG_WOWLAN
1089 /*
1090  *      Description:
1091  *              Clear corresponding SDIO Host ISR interrupt service.
1092  *
1093  *      Assumption:
1094  *              Using SDIO Local register ONLY for configuration.
1095  *
1096  *      Created by Roger, 2011.02.11.
1097  *   */
1098 void ClearInterrupt8723DSdio(PADAPTER padapter)
1099 {
1100         PHAL_DATA_TYPE pHalData;
1101         u8 *clear;
1102         u8 val_8 = 0;
1103         u32 val_32 = 0;
1104
1105         if (rtw_is_surprise_removed(padapter))
1106                 return;
1107
1108         pHalData = GET_HAL_DATA(padapter);
1109         clear = rtw_zmalloc(4);
1110
1111         /* Clear corresponding HISR Content if needed */
1112         val_8 = SdioLocalCmd52Read1Byte(padapter, SDIO_REG_HISR + 2);
1113
1114         val_32 = pHalData->sdio_hisr & MASK_SDIO_HISR_CLEAR;
1115
1116         if (val_8 && BIT3)
1117                 *(u32 *)clear = cpu_to_le32(val_32 | SDIO_HISR_CPWM2);
1118         else
1119                 *(u32 *)clear = cpu_to_le32(val_32);
1120
1121         if (*(u32 *)clear) {
1122                 /* Perform write one clear operation */
1123                 sdio_local_write(padapter, SDIO_REG_HISR, 4, clear);
1124         }
1125
1126         rtw_mfree(clear, 4);
1127 }
1128 #endif
1129
1130 /*
1131  *      Description:
1132  *              Clear corresponding system Host ISR interrupt service.
1133  *
1134  *
1135  *      Created by Roger, 2011.02.11.
1136  *   */
1137 void ClearSysInterrupt8723DSdio(PADAPTER padapter)
1138 {
1139         PHAL_DATA_TYPE pHalData;
1140         u32 clear;
1141
1142
1143         if (rtw_is_surprise_removed(padapter))
1144                 return;
1145
1146         pHalData = GET_HAL_DATA(padapter);
1147
1148         /* Clear corresponding HISR Content if needed */
1149         clear = pHalData->SysIntrStatus & MASK_HSISR_CLEAR;
1150         if (clear) {
1151                 /* Perform write one clear operation */
1152                 rtw_write32(padapter, REG_HSISR, clear);
1153         }
1154 }
1155
1156 /*
1157  *      Description:
1158  *              Enalbe SDIO Host Interrupt Mask configuration on SDIO local domain.
1159  *
1160  *      Assumption:
1161  *              1. Using SDIO Local register ONLY for configuration.
1162  *              2. PASSIVE LEVEL
1163  *
1164  *      Created by Roger, 2011.02.11.
1165  *   */
1166 void EnableInterrupt8723DSdio(PADAPTER padapter)
1167 {
1168         PHAL_DATA_TYPE pHalData;
1169         u32 himr;
1170
1171         pHalData = GET_HAL_DATA(padapter);
1172
1173         himr = cpu_to_le32(pHalData->sdio_himr);
1174         sdio_local_write(padapter, SDIO_REG_HIMR, 4, (u8 *)&himr);
1175
1176
1177         /* Update current system IMR settings */
1178         himr = rtw_read32(padapter, REG_HSIMR);
1179         rtw_write32(padapter, REG_HSIMR, himr | pHalData->SysIntrMask);
1180
1181
1182         /* */
1183         /* <Roger_Notes> There are some C2H CMDs have been sent before system interrupt is enabled, e.g., C2H, CPWM. */
1184         /* So we need to clear all C2H events that FW has notified, otherwise FW won't schedule any commands anymore. */
1185         /* 2011.10.19. */
1186         /* */
1187         rtw_write8(padapter, REG_C2HEVT_CLEAR, C2H_EVT_HOST_CLOSE);
1188 }
1189
1190 /*
1191  *      Description:
1192  *              Disable SDIO Host IMR configuration to mask unnecessary interrupt service.
1193  *
1194  *      Assumption:
1195  *              Using SDIO Local register ONLY for configuration.
1196  *
1197  *      Created by Roger, 2011.02.11.
1198  *   */
1199 void DisableInterrupt8723DSdio(PADAPTER padapter)
1200 {
1201         u32 himr;
1202
1203         himr = cpu_to_le32(SDIO_HIMR_DISABLED);
1204         sdio_local_write(padapter, SDIO_REG_HIMR, 4, (u8 *)&himr);
1205
1206 }
1207
1208 /*
1209  *      Description:
1210  *              Using 0x100 to check the power status of FW.
1211  *
1212  *      Assumption:
1213  *              Using SDIO Local register ONLY for configuration.
1214  *
1215  *      Created by Isaac, 2013.09.10.
1216  *   */
1217 u8 CheckIPSStatus(PADAPTER padapter)
1218 {
1219         RTW_INFO("%s(): Read 0x100=0x%02x 0x86=0x%02x\n", __func__,
1220                  rtw_read8(padapter, 0x100), rtw_read8(padapter, 0x86));
1221
1222         if (rtw_read8(padapter, 0x100) == 0xEA)
1223                 return _TRUE;
1224         else
1225                 return _FALSE;
1226 }
1227
1228 #ifdef CONFIG_WOWLAN
1229 void DisableInterruptButCpwm28723DSdio(PADAPTER padapter)
1230 {
1231         u32 himr, tmp;
1232
1233         sdio_local_read(padapter, SDIO_REG_HIMR, 4, (u8 *)&tmp);
1234         RTW_INFO("DisableInterruptButCpwm28723DSdio(): Read SDIO_REG_HIMR: 0x%08x\n", tmp);
1235
1236         himr = cpu_to_le32(SDIO_HIMR_DISABLED) | SDIO_HIMR_CPWM2_MSK;
1237         sdio_local_write(padapter, SDIO_REG_HIMR, 4, (u8 *)&himr);
1238
1239         sdio_local_read(padapter, SDIO_REG_HIMR, 4, (u8 *)&tmp);
1240         RTW_INFO("DisableInterruptButCpwm28723DSdio(): Read again SDIO_REG_HIMR: 0x%08x\n", tmp);
1241 }
1242 #endif /* CONFIG_WOWLAN
1243  *
1244  *      Description:
1245  *              Update SDIO Host Interrupt Mask configuration on SDIO local domain.
1246  *
1247  *      Assumption:
1248  *              1. Using SDIO Local register ONLY for configuration.
1249  *              2. PASSIVE LEVEL
1250  *
1251  *      Created by Roger, 2011.02.11.
1252  *   */
1253 void UpdateInterruptMask8723DSdio(PADAPTER padapter, u32 AddMSR, u32 RemoveMSR)
1254 {
1255         HAL_DATA_TYPE *pHalData;
1256
1257         pHalData = GET_HAL_DATA(padapter);
1258
1259         if (AddMSR)
1260                 pHalData->sdio_himr |= AddMSR;
1261
1262         if (RemoveMSR)
1263                 pHalData->sdio_himr &= (~RemoveMSR);
1264
1265         DisableInterrupt8723DSdio(padapter);
1266         EnableInterrupt8723DSdio(padapter);
1267 }
1268
1269 #ifdef CONFIG_MAC_LOOPBACK_DRIVER
1270 static void sd_recv_loopback(PADAPTER padapter, u32 size)
1271 {
1272         PLOOPBACKDATA ploopback;
1273         u32 readsize, allocsize;
1274         u8 *preadbuf;
1275
1276
1277         readsize = size;
1278         RTW_INFO("%s: read size=%d\n", __func__, readsize);
1279         allocsize = _RND(readsize, adapter_to_dvobj(padapter)->intf_data.block_transfer_len);
1280
1281         ploopback = padapter->ploopback;
1282         if (ploopback) {
1283                 ploopback->rxsize = readsize;
1284                 preadbuf = ploopback->rxbuf;
1285         } else {
1286                 preadbuf = rtw_malloc(allocsize);
1287                 if (preadbuf == NULL) {
1288                         RTW_INFO("%s: malloc fail size=%d\n", __func__, allocsize);
1289                         return;
1290                 }
1291         }
1292
1293         /*      rtw_read_port(padapter, WLAN_RX0FF_DEVICE_ID, readsize, preadbuf); */
1294         sdio_read_port(&padapter->iopriv.intf, WLAN_RX0FF_DEVICE_ID, readsize, preadbuf);
1295
1296         if (ploopback)
1297                 _rtw_up_sema(&ploopback->sema);
1298         else {
1299                 u32 i;
1300
1301                 RTW_INFO("%s: drop pkt\n", __func__);
1302                 for (i = 0; i < readsize; i += 4) {
1303                         RTW_INFO("%08X", *(u32 *)(preadbuf + i));
1304                         if ((i + 4) & 0x1F)
1305                                 printk(KERN_ERR " ");
1306                         else
1307                                 printk(KERN_ERR "\n");
1308                 }
1309                 printk(KERN_ERR "\n");
1310                 rtw_mfree(preadbuf, allocsize);
1311         }
1312 }
1313 #endif /* CONFIG_MAC_LOOPBACK_DRIVER */
1314
1315 #ifdef CONFIG_SDIO_RX_COPY
1316 static struct recv_buf *sd_recv_rxfifo(PADAPTER padapter, u32 size)
1317 {
1318         u32 readsize, ret;
1319         u8 *preadbuf;
1320         struct recv_priv *precvpriv;
1321         struct recv_buf *precvbuf;
1322
1323
1324 #if 0
1325         readsize = size;
1326 #else
1327         /* Patch for some SDIO Host 4 bytes issue */
1328         /* ex. RK3188 */
1329         readsize = RND4(size);
1330 #endif
1331
1332         /* 3 1. alloc recvbuf */
1333         precvpriv = &padapter->recvpriv;
1334         precvbuf = rtw_dequeue_recvbuf(&precvpriv->free_recv_buf_queue);
1335         if (precvbuf == NULL) {
1336                 RTW_ERR("%s: alloc recvbuf FAIL!\n", __func__);
1337                 return NULL;
1338         }
1339
1340         /* 3 2. alloc skb */
1341         if (precvbuf->pskb == NULL) {
1342                 SIZE_PTR tmpaddr = 0;
1343                 SIZE_PTR alignment = 0;
1344
1345                 precvbuf->pskb = rtw_skb_alloc(MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ);
1346                 if (precvbuf->pskb == NULL) {
1347                         RTW_INFO("%s: alloc_skb fail! read=%d\n", __func__, readsize);
1348                         rtw_enqueue_recvbuf(precvbuf, &precvpriv->free_recv_buf_queue);
1349                         return NULL;
1350                 }
1351
1352                 precvbuf->pskb->dev = padapter->pnetdev;
1353
1354                 tmpaddr = (SIZE_PTR)precvbuf->pskb->data;
1355                 alignment = tmpaddr & (RECVBUFF_ALIGN_SZ - 1);
1356                 skb_reserve(precvbuf->pskb, (RECVBUFF_ALIGN_SZ - alignment));
1357         }
1358
1359         /* 3 3. read data from rxfifo */
1360         preadbuf = precvbuf->pskb->data;
1361         /*      rtw_read_port(padapter, WLAN_RX0FF_DEVICE_ID, readsize, preadbuf); */
1362         ret = sdio_read_port(&padapter->iopriv.intf, WLAN_RX0FF_DEVICE_ID, readsize, preadbuf);
1363         if (ret == _FAIL) {
1364                 rtw_enqueue_recvbuf(precvbuf, &precvpriv->free_recv_buf_queue);
1365                 return NULL;
1366         }
1367
1368         /* 3 4. init recvbuf */
1369         precvbuf->len = size;
1370         precvbuf->phead = precvbuf->pskb->head;
1371         precvbuf->pdata = precvbuf->pskb->data;
1372         skb_set_tail_pointer(precvbuf->pskb, size);
1373         precvbuf->ptail = skb_tail_pointer(precvbuf->pskb);
1374         precvbuf->pend = skb_end_pointer(precvbuf->pskb);
1375
1376         return precvbuf;
1377 }
1378 #else /* !CONFIG_SDIO_RX_COPY */
1379 static struct recv_buf *sd_recv_rxfifo(PADAPTER padapter, u32 size)
1380 {
1381         u32 sdioblksize, readsize, allocsize, ret;
1382         u8 *preadbuf;
1383         _pkt *ppkt;
1384         struct recv_priv *precvpriv;
1385         struct recv_buf *precvbuf;
1386
1387
1388         sdioblksize = adapter_to_dvobj(padapter)->intf_data.block_transfer_len;
1389 #if 0
1390         readsize = size;
1391 #else
1392         /* Patch for some SDIO Host 4 bytes issue */
1393         /* ex. RK3188 */
1394         readsize = RND4(size);
1395 #endif
1396
1397         /* 3 1. alloc skb */
1398         /* align to block size */
1399         if (readsize > sdioblksize)
1400                 allocsize = _RND(readsize, sdioblksize);
1401         else
1402                 allocsize = readsize;
1403
1404         ppkt = rtw_skb_alloc(allocsize);
1405
1406         if (ppkt == NULL) {
1407                 return NULL;
1408         }
1409
1410         /* 3 2. read data from rxfifo */
1411         preadbuf = skb_put(ppkt, size);
1412         /*      rtw_read_port(padapter, WLAN_RX0FF_DEVICE_ID, readsize, preadbuf); */
1413         ret = sdio_read_port(&padapter->iopriv.intf, WLAN_RX0FF_DEVICE_ID, readsize, preadbuf);
1414         if (ret == _FAIL) {
1415                 rtw_skb_free(ppkt);
1416                 return NULL;
1417         }
1418
1419         /* 3 3. alloc recvbuf */
1420         precvpriv = &padapter->recvpriv;
1421         precvbuf = rtw_dequeue_recvbuf(&precvpriv->free_recv_buf_queue);
1422         if (precvbuf == NULL) {
1423                 rtw_skb_free(ppkt);
1424                 RTW_ERR("%s: alloc recvbuf FAIL!\n", __func__);
1425                 return NULL;
1426         }
1427
1428         /* 3 4. init recvbuf */
1429         precvbuf->pskb = ppkt;
1430
1431         precvbuf->len = ppkt->len;
1432
1433         precvbuf->phead = ppkt->head;
1434         precvbuf->pdata = ppkt->data;
1435         precvbuf->ptail = skb_tail_pointer(precvbuf->pskb);
1436         precvbuf->pend = skb_end_pointer(precvbuf->pskb);
1437
1438         return precvbuf;
1439 }
1440 #endif /* !CONFIG_SDIO_RX_COPY */
1441
1442 static void sd_rxhandler(PADAPTER padapter, struct recv_buf *precvbuf)
1443 {
1444         struct recv_priv *precvpriv;
1445         _queue *ppending_queue;
1446
1447
1448         precvpriv = &padapter->recvpriv;
1449         ppending_queue = &precvpriv->recv_buf_pending_queue;
1450
1451         /* 3 1. enqueue recvbuf */
1452         rtw_enqueue_recvbuf(precvbuf, ppending_queue);
1453
1454         /* 3 2. schedule tasklet */
1455 #ifdef PLATFORM_LINUX
1456         tasklet_schedule(&precvpriv->recv_tasklet);
1457 #endif
1458 }
1459
1460 void sd_int_dpc(PADAPTER padapter)
1461 {
1462         PHAL_DATA_TYPE phal;
1463         struct dvobj_priv *dvobj;
1464         struct intf_hdl *pintfhdl = &padapter->iopriv.intf;
1465         struct pwrctrl_priv *pwrctl;
1466
1467
1468         phal = GET_HAL_DATA(padapter);
1469         dvobj = adapter_to_dvobj(padapter);
1470         pwrctl = dvobj_to_pwrctl(dvobj);
1471
1472 #ifdef CONFIG_SDIO_TX_ENABLE_AVAL_INT
1473         if (phal->sdio_hisr & SDIO_HISR_AVAL) {
1474                 /* _irqL irql; */
1475                 u8      freepage[4];
1476
1477                 _sdio_local_read(padapter, SDIO_REG_FREE_TXPG, 4, freepage);
1478                 /* _enter_critical_bh(&phal->SdioTxFIFOFreePageLock, &irql); */
1479                 /* _rtw_memcpy(phal->SdioTxFIFOFreePage, freepage, 4); */
1480                 /* _exit_critical_bh(&phal->SdioTxFIFOFreePageLock, &irql); */
1481                 /* RTW_INFO("SDIO_HISR_AVAL, Tx Free Page = 0x%x%x%x%x\n", */
1482                 /*      freepage[0], */
1483                 /*      freepage[1], */
1484                 /*      freepage[2], */
1485                 /*      freepage[3]); */
1486                 _rtw_up_sema(&(padapter->xmitpriv.xmit_sema));
1487         }
1488 #endif
1489         if (phal->sdio_hisr & SDIO_HISR_CPWM1) {
1490                 struct reportpwrstate_parm report;
1491
1492 #ifdef CONFIG_LPS_RPWM_TIMER
1493                 u8 bcancelled;
1494
1495                 _cancel_timer(&(pwrctl->pwr_rpwm_timer), &bcancelled);
1496 #endif /* CONFIG_LPS_RPWM_TIMER */
1497
1498                 report.state = SdioLocalCmd52Read1Byte(padapter, SDIO_REG_HCPWM1_8723D);
1499
1500 #ifdef CONFIG_LPS_LCLK
1501                 /* cpwm_int_hdl(padapter, &report); */
1502                 _set_workitem(&(pwrctl->cpwm_event));
1503 #endif
1504         }
1505
1506         if (phal->sdio_hisr & SDIO_HISR_TXERR) {
1507                 u8 *status;
1508                 u32 addr;
1509
1510                 status = rtw_malloc(4);
1511                 if (status) {
1512                         addr = REG_TXDMA_STATUS;
1513                         HalSdioGetCmdAddr8723DSdio(padapter, WLAN_IOREG_DEVICE_ID, addr, &addr);
1514                         _sd_read(pintfhdl, addr, 4, status);
1515                         _sd_write(pintfhdl, addr, 4, status);
1516                         RTW_INFO("%s: SDIO_HISR_TXERR (0x%08x)\n", __func__, le32_to_cpu(*(u32 *)status));
1517                         rtw_mfree(status, 4);
1518                 } else
1519                         RTW_INFO("%s: SDIO_HISR_TXERR, but can't allocate memory to read status!\n", __func__);
1520         }
1521
1522         if (phal->sdio_hisr & SDIO_HISR_TXBCNOK)
1523                 RTW_INFO("%s: SDIO_HISR_TXBCNOK\n", __func__);
1524
1525         if (phal->sdio_hisr & SDIO_HISR_TXBCNERR)
1526                 RTW_INFO("%s: SDIO_HISR_TXBCNERR\n", __func__);
1527
1528 #ifdef CONFIG_FW_C2H_REG
1529         if (phal->sdio_hisr & SDIO_HISR_C2HCMD) {
1530                 RTW_INFO("%s: C2H Command\n", __func__);
1531                 sd_c2h_hisr_hdl(padapter);
1532         }
1533 #endif
1534
1535         if (phal->sdio_hisr & SDIO_HISR_RXFOVW)
1536                 RTW_INFO("%s: Rx Overflow\n", __func__);
1537         if (phal->sdio_hisr & SDIO_HISR_RXERR)
1538                 RTW_INFO("%s: Rx Error\n", __func__);
1539
1540         if (phal->sdio_hisr & SDIO_HISR_RX_REQUEST) {
1541                 struct recv_buf *precvbuf;
1542                 int alloc_fail_time = 0;
1543                 u32 hisr;
1544
1545                 phal->sdio_hisr ^= SDIO_HISR_RX_REQUEST;
1546                 do {
1547                         phal->SdioRxFIFOSize = SdioLocalCmd52Read2Byte(padapter, SDIO_REG_RX0_REQ_LEN);
1548                         if (phal->SdioRxFIFOSize != 0) {
1549 #ifdef CONFIG_MAC_LOOPBACK_DRIVER
1550                                 sd_recv_loopback(padapter, phal->SdioRxFIFOSize);
1551 #else
1552                                 precvbuf = sd_recv_rxfifo(padapter, phal->SdioRxFIFOSize);
1553                                 if (precvbuf)
1554                                         sd_rxhandler(padapter, precvbuf);
1555                                 else {
1556                                         alloc_fail_time++;
1557                                         RTW_INFO("%s: recv fail!(time=%d)\n", __func__, alloc_fail_time);
1558                                         if (alloc_fail_time >= 10)
1559                                                 break;
1560                                 }
1561                                 phal->SdioRxFIFOSize = 0;
1562 #endif
1563                         } else
1564                                 break;
1565
1566                         hisr = 0;
1567                         ReadInterrupt8723DSdio(padapter, &hisr);
1568                         hisr &= SDIO_HISR_RX_REQUEST;
1569                         if (!hisr)
1570                                 break;
1571                 } while (1);
1572
1573                 if (alloc_fail_time == 10)
1574                         RTW_INFO("%s: exit because recv failed more than 10 times!\n", __func__);
1575         }
1576 }
1577
1578 void sd_int_hdl(PADAPTER padapter)
1579 {
1580         PHAL_DATA_TYPE phal;
1581
1582
1583         if (RTW_CANNOT_RUN(padapter))
1584                 return;
1585
1586         phal = GET_HAL_DATA(padapter);
1587
1588         phal->sdio_hisr = 0;
1589         ReadInterrupt8723DSdio(padapter, &phal->sdio_hisr);
1590
1591         if (phal->sdio_hisr & phal->sdio_himr) {
1592                 u32 v32;
1593
1594                 phal->sdio_hisr &= phal->sdio_himr;
1595
1596                 /* clear HISR */
1597                 v32 = phal->sdio_hisr & MASK_SDIO_HISR_CLEAR;
1598                 if (v32)
1599                         SdioLocalCmd52Write4Byte(padapter, SDIO_REG_HISR, v32);
1600
1601                 sd_int_dpc(padapter);
1602         }
1603 }
1604
1605 /*
1606  *      Description:
1607  *              Query SDIO Local register to query current the number of Free TxPacketBuffer page.
1608  *
1609  *      Assumption:
1610  *              1. Running at PASSIVE_LEVEL
1611  *              2. RT_TX_SPINLOCK is NOT acquired.
1612  *
1613  *      Created by Roger, 2011.01.28.
1614  *   */
1615 u8 HalQueryTxBufferStatus8723DSdio(PADAPTER padapter)
1616 {
1617         PHAL_DATA_TYPE phal;
1618         u32 NumOfFreePage;
1619         /* _irqL irql; */
1620
1621
1622         phal = GET_HAL_DATA(padapter);
1623
1624         NumOfFreePage = SdioLocalCmd53Read4Byte(padapter, SDIO_REG_FREE_TXPG);
1625
1626         /* _enter_critical_bh(&phal->SdioTxFIFOFreePageLock, &irql); */
1627         _rtw_memcpy(phal->SdioTxFIFOFreePage, &NumOfFreePage, 4);
1628         /* _exit_critical_bh(&phal->SdioTxFIFOFreePageLock, &irql); */
1629
1630         return _TRUE;
1631 }
1632
1633 /*
1634  *      Description:
1635  *              Query SDIO Local register to get the current number of TX OQT Free Space.
1636  *   */
1637 u8 HalQueryTxOQTBufferStatus8723DSdio(PADAPTER padapter)
1638 {
1639         HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
1640
1641         pHalData->SdioTxOQTFreeSpace = SdioLocalCmd52Read1Byte(padapter, SDIO_REG_OQT_FREE_PG);
1642         return _TRUE;
1643 }
1644
1645 #if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN)
1646 u8 RecvOnePkt(PADAPTER padapter, u32 size)
1647 {
1648         struct recv_buf *precvbuf;
1649         struct dvobj_priv *psddev;
1650         PSDIO_DATA psdio_data;
1651         struct sdio_func *func;
1652
1653         u8 res = _FALSE;
1654
1655         RTW_INFO("+%s: size: %d+\n", __func__, size);
1656
1657         if (padapter == NULL) {
1658                 RTW_INFO(KERN_ERR "%s: padapter is NULL!\n", __func__);
1659                 return _FALSE;
1660         }
1661
1662         psddev = adapter_to_dvobj(padapter);
1663         psdio_data = &psddev->intf_data;
1664         func = psdio_data->func;
1665
1666         if (size) {
1667                 sdio_claim_host(func);
1668                 precvbuf = sd_recv_rxfifo(padapter, size);
1669
1670                 if (precvbuf) {
1671                         /* printk("Completed Recv One Pkt.\n"); */
1672                         sd_rxhandler(padapter, precvbuf);
1673                         res = _TRUE;
1674                 } else
1675                         res = _FALSE;
1676                 sdio_release_host(func);
1677         }
1678         RTW_INFO("-%s-\n", __func__);
1679         return res;
1680 }
1681 #endif /* CONFIG_WOWLAN */