linux/drivers/staging/rtl8723bs/hal/sdio_ops.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/******************************************************************************
   3 *
   4 * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
   5 *
   6 *******************************************************************************/
   7#define _SDIO_OPS_C_
   8
   9#include <drv_types.h>
  10#include <rtw_debug.h>
  11#include <rtl8723b_hal.h>
  12
  13/* define SDIO_DEBUG_IO 1 */
  14
  15
  16/*  */
  17/*  Description: */
  18/*      The following mapping is for SDIO host local register space. */
  19/*  */
  20/*  Creadted by Roger, 2011.01.31. */
  21/*  */
  22static void HalSdioGetCmdAddr8723BSdio(
  23        struct adapter *adapter,
  24        u8 device_id,
  25        u32 addr,
  26        u32 *cmdaddr
  27)
  28{
  29        switch (device_id) {
  30        case SDIO_LOCAL_DEVICE_ID:
  31                *cmdaddr = ((SDIO_LOCAL_DEVICE_ID << 13) | (addr & SDIO_LOCAL_MSK));
  32                break;
  33
  34        case WLAN_IOREG_DEVICE_ID:
  35                *cmdaddr = ((WLAN_IOREG_DEVICE_ID << 13) | (addr & WLAN_IOREG_MSK));
  36                break;
  37
  38        case WLAN_TX_HIQ_DEVICE_ID:
  39                *cmdaddr = ((WLAN_TX_HIQ_DEVICE_ID << 13) | (addr & WLAN_FIFO_MSK));
  40                break;
  41
  42        case WLAN_TX_MIQ_DEVICE_ID:
  43                *cmdaddr = ((WLAN_TX_MIQ_DEVICE_ID << 13) | (addr & WLAN_FIFO_MSK));
  44                break;
  45
  46        case WLAN_TX_LOQ_DEVICE_ID:
  47                *cmdaddr = ((WLAN_TX_LOQ_DEVICE_ID << 13) | (addr & WLAN_FIFO_MSK));
  48                break;
  49
  50        case WLAN_RX0FF_DEVICE_ID:
  51                *cmdaddr = ((WLAN_RX0FF_DEVICE_ID << 13) | (addr & WLAN_RX0FF_MSK));
  52                break;
  53
  54        default:
  55                break;
  56        }
  57}
  58
  59static u8 get_deviceid(u32 addr)
  60{
  61        u8 devide_id;
  62        u16 pseudo_id;
  63
  64
  65        pseudo_id = (u16)(addr >> 16);
  66        switch (pseudo_id) {
  67        case 0x1025:
  68                devide_id = SDIO_LOCAL_DEVICE_ID;
  69                break;
  70
  71        case 0x1026:
  72                devide_id = WLAN_IOREG_DEVICE_ID;
  73                break;
  74
  75/*              case 0x1027: */
  76/*                      devide_id = SDIO_FIRMWARE_FIFO; */
  77/*                      break; */
  78
  79        case 0x1031:
  80                devide_id = WLAN_TX_HIQ_DEVICE_ID;
  81                break;
  82
  83        case 0x1032:
  84                devide_id = WLAN_TX_MIQ_DEVICE_ID;
  85                break;
  86
  87        case 0x1033:
  88                devide_id = WLAN_TX_LOQ_DEVICE_ID;
  89                break;
  90
  91        case 0x1034:
  92                devide_id = WLAN_RX0FF_DEVICE_ID;
  93                break;
  94
  95        default:
  96/*                      devide_id = (u8)((addr >> 13) & 0xF); */
  97                devide_id = WLAN_IOREG_DEVICE_ID;
  98                break;
  99        }
 100
 101        return devide_id;
 102}
 103
 104/*
 105 * Ref:
 106 *HalSdioGetCmdAddr8723BSdio()
 107 */
 108static u32 _cvrt2ftaddr(const u32 addr, u8 *pdevice_id, u16 *poffset)
 109{
 110        u8 device_id;
 111        u16 offset;
 112        u32 ftaddr;
 113
 114
 115        device_id = get_deviceid(addr);
 116        offset = 0;
 117
 118        switch (device_id) {
 119        case SDIO_LOCAL_DEVICE_ID:
 120                offset = addr & SDIO_LOCAL_MSK;
 121                break;
 122
 123        case WLAN_TX_HIQ_DEVICE_ID:
 124        case WLAN_TX_MIQ_DEVICE_ID:
 125        case WLAN_TX_LOQ_DEVICE_ID:
 126                offset = addr & WLAN_FIFO_MSK;
 127                break;
 128
 129        case WLAN_RX0FF_DEVICE_ID:
 130                offset = addr & WLAN_RX0FF_MSK;
 131                break;
 132
 133        case WLAN_IOREG_DEVICE_ID:
 134        default:
 135                device_id = WLAN_IOREG_DEVICE_ID;
 136                offset = addr & WLAN_IOREG_MSK;
 137                break;
 138        }
 139        ftaddr = (device_id << 13) | offset;
 140
 141        if (pdevice_id)
 142                *pdevice_id = device_id;
 143        if (poffset)
 144                *poffset = offset;
 145
 146        return ftaddr;
 147}
 148
 149static u8 sdio_read8(struct intf_hdl *intfhdl, u32 addr)
 150{
 151        u32 ftaddr;
 152        ftaddr = _cvrt2ftaddr(addr, NULL, NULL);
 153
 154        return sd_read8(intfhdl, ftaddr, NULL);
 155}
 156
 157static u16 sdio_read16(struct intf_hdl *intfhdl, u32 addr)
 158{
 159        u32 ftaddr;
 160        __le16 le_tmp;
 161
 162        ftaddr = _cvrt2ftaddr(addr, NULL, NULL);
 163        sd_cmd52_read(intfhdl, ftaddr, 2, (u8 *)&le_tmp);
 164
 165        return le16_to_cpu(le_tmp);
 166}
 167
 168static u32 sdio_read32(struct intf_hdl *intfhdl, u32 addr)
 169{
 170        struct adapter *adapter;
 171        u8 mac_pwr_ctrl_on;
 172        u8 device_id;
 173        u16 offset;
 174        u32 ftaddr;
 175        u8 shift;
 176        u32 val;
 177        s32 err;
 178        __le32 le_tmp;
 179
 180        adapter = intfhdl->padapter;
 181        ftaddr = _cvrt2ftaddr(addr, &device_id, &offset);
 182
 183        rtw_hal_get_hwreg(adapter, HW_VAR_APFM_ON_MAC, &mac_pwr_ctrl_on);
 184        if (
 185                ((device_id == WLAN_IOREG_DEVICE_ID) && (offset < 0x100)) ||
 186                (!mac_pwr_ctrl_on) ||
 187                (adapter_to_pwrctl(adapter)->bFwCurrentInPSMode)
 188        ) {
 189                err = sd_cmd52_read(intfhdl, ftaddr, 4, (u8 *)&le_tmp);
 190#ifdef SDIO_DEBUG_IO
 191                if (!err) {
 192#endif
 193                        return le32_to_cpu(le_tmp);
 194#ifdef SDIO_DEBUG_IO
 195                }
 196
 197                DBG_8192C(KERN_ERR "%s: Mac Power off, Read FAIL(%d)! addr = 0x%x\n", __func__, err, addr);
 198                return SDIO_ERR_VAL32;
 199#endif
 200        }
 201
 202        /*  4 bytes alignment */
 203        shift = ftaddr & 0x3;
 204        if (shift == 0) {
 205                val = sd_read32(intfhdl, ftaddr, NULL);
 206        } else {
 207                u8 *tmpbuf;
 208
 209                tmpbuf = rtw_malloc(8);
 210                if (!tmpbuf) {
 211                        DBG_8192C(KERN_ERR "%s: Allocate memory FAIL!(size =8) addr = 0x%x\n", __func__, addr);
 212                        return SDIO_ERR_VAL32;
 213                }
 214
 215                ftaddr &= ~(u16)0x3;
 216                sd_read(intfhdl, ftaddr, 8, tmpbuf);
 217                memcpy(&le_tmp, tmpbuf + shift, 4);
 218                val = le32_to_cpu(le_tmp);
 219
 220                kfree(tmpbuf);
 221        }
 222        return val;
 223}
 224
 225static s32 sdio_readN(struct intf_hdl *intfhdl, u32 addr, u32 cnt, u8 *buf)
 226{
 227        struct adapter *adapter;
 228        u8 mac_pwr_ctrl_on;
 229        u8 device_id;
 230        u16 offset;
 231        u32 ftaddr;
 232        u8 shift;
 233        s32 err;
 234
 235        adapter = intfhdl->padapter;
 236        err = 0;
 237
 238        ftaddr = _cvrt2ftaddr(addr, &device_id, &offset);
 239
 240        rtw_hal_get_hwreg(adapter, HW_VAR_APFM_ON_MAC, &mac_pwr_ctrl_on);
 241        if (
 242                ((device_id == WLAN_IOREG_DEVICE_ID) && (offset < 0x100)) ||
 243                (!mac_pwr_ctrl_on) ||
 244                (adapter_to_pwrctl(adapter)->bFwCurrentInPSMode)
 245        )
 246                return sd_cmd52_read(intfhdl, ftaddr, cnt, buf);
 247
 248        /*  4 bytes alignment */
 249        shift = ftaddr & 0x3;
 250        if (shift == 0) {
 251                err = sd_read(intfhdl, ftaddr, cnt, buf);
 252        } else {
 253                u8 *tmpbuf;
 254                u32 n;
 255
 256                ftaddr &= ~(u16)0x3;
 257                n = cnt + shift;
 258                tmpbuf = rtw_malloc(n);
 259                if (!tmpbuf)
 260                        return -1;
 261
 262                err = sd_read(intfhdl, ftaddr, n, tmpbuf);
 263                if (!err)
 264                        memcpy(buf, tmpbuf + shift, cnt);
 265                kfree(tmpbuf);
 266        }
 267        return err;
 268}
 269
 270static s32 sdio_write8(struct intf_hdl *intfhdl, u32 addr, u8 val)
 271{
 272        u32 ftaddr;
 273        s32 err;
 274
 275        ftaddr = _cvrt2ftaddr(addr, NULL, NULL);
 276        sd_write8(intfhdl, ftaddr, val, &err);
 277
 278        return err;
 279}
 280
 281static s32 sdio_write16(struct intf_hdl *intfhdl, u32 addr, u16 val)
 282{
 283        u32 ftaddr;
 284        __le16 le_tmp;
 285
 286        ftaddr = _cvrt2ftaddr(addr, NULL, NULL);
 287        le_tmp = cpu_to_le16(val);
 288        return sd_cmd52_write(intfhdl, ftaddr, 2, (u8 *)&le_tmp);
 289}
 290
 291static s32 sdio_write32(struct intf_hdl *intfhdl, u32 addr, u32 val)
 292{
 293        struct adapter *adapter;
 294        u8 mac_pwr_ctrl_on;
 295        u8 device_id;
 296        u16 offset;
 297        u32 ftaddr;
 298        u8 shift;
 299        s32 err;
 300        __le32 le_tmp;
 301
 302        adapter = intfhdl->padapter;
 303        err = 0;
 304
 305        ftaddr = _cvrt2ftaddr(addr, &device_id, &offset);
 306
 307        rtw_hal_get_hwreg(adapter, HW_VAR_APFM_ON_MAC, &mac_pwr_ctrl_on);
 308        if (
 309                ((device_id == WLAN_IOREG_DEVICE_ID) && (offset < 0x100)) ||
 310                (!mac_pwr_ctrl_on) ||
 311                (adapter_to_pwrctl(adapter)->bFwCurrentInPSMode)
 312        ) {
 313                le_tmp = cpu_to_le32(val);
 314
 315                return sd_cmd52_write(intfhdl, ftaddr, 4, (u8 *)&le_tmp);
 316        }
 317
 318        /*  4 bytes alignment */
 319        shift = ftaddr & 0x3;
 320        if (shift == 0) {
 321                sd_write32(intfhdl, ftaddr, val, &err);
 322        } else {
 323                le_tmp = cpu_to_le32(val);
 324                err = sd_cmd52_write(intfhdl, ftaddr, 4, (u8 *)&le_tmp);
 325        }
 326        return err;
 327}
 328
 329static s32 sdio_writeN(struct intf_hdl *intfhdl, u32 addr, u32 cnt, u8 *buf)
 330{
 331        struct adapter *adapter;
 332        u8 mac_pwr_ctrl_on;
 333        u8 device_id;
 334        u16 offset;
 335        u32 ftaddr;
 336        u8 shift;
 337        s32 err;
 338
 339        adapter = intfhdl->padapter;
 340        err = 0;
 341
 342        ftaddr = _cvrt2ftaddr(addr, &device_id, &offset);
 343
 344        rtw_hal_get_hwreg(adapter, HW_VAR_APFM_ON_MAC, &mac_pwr_ctrl_on);
 345        if (
 346                ((device_id == WLAN_IOREG_DEVICE_ID) && (offset < 0x100)) ||
 347                (!mac_pwr_ctrl_on) ||
 348                (adapter_to_pwrctl(adapter)->bFwCurrentInPSMode)
 349        )
 350                return sd_cmd52_write(intfhdl, ftaddr, cnt, buf);
 351
 352        shift = ftaddr & 0x3;
 353        if (shift == 0) {
 354                err = sd_write(intfhdl, ftaddr, cnt, buf);
 355        } else {
 356                u8 *tmpbuf;
 357                u32 n;
 358
 359                ftaddr &= ~(u16)0x3;
 360                n = cnt + shift;
 361                tmpbuf = rtw_malloc(n);
 362                if (!tmpbuf)
 363                        return -1;
 364                err = sd_read(intfhdl, ftaddr, 4, tmpbuf);
 365                if (err) {
 366                        kfree(tmpbuf);
 367                        return err;
 368                }
 369                memcpy(tmpbuf + shift, buf, cnt);
 370                err = sd_write(intfhdl, ftaddr, n, tmpbuf);
 371                kfree(tmpbuf);
 372        }
 373        return err;
 374}
 375
 376static u8 sdio_f0_read8(struct intf_hdl *intfhdl, u32 addr)
 377{
 378        return sd_f0_read8(intfhdl, addr, NULL);
 379}
 380
 381static void sdio_read_mem(
 382        struct intf_hdl *intfhdl,
 383        u32 addr,
 384        u32 cnt,
 385        u8 *rmem
 386)
 387{
 388        s32 err;
 389
 390        err = sdio_readN(intfhdl, addr, cnt, rmem);
 391        /* TODO: Report error is err not zero */
 392}
 393
 394static void sdio_write_mem(
 395        struct intf_hdl *intfhdl,
 396        u32 addr,
 397        u32 cnt,
 398        u8 *wmem
 399)
 400{
 401        sdio_writeN(intfhdl, addr, cnt, wmem);
 402}
 403
 404/*
 405 * Description:
 406 *Read from RX FIFO
 407 *Round read size to block size,
 408 *and make sure data transfer will be done in one command.
 409 *
 410 * Parameters:
 411 *intfhdl       a pointer of intf_hdl
 412 *addr          port ID
 413 *cnt                   size to read
 414 *rmem          address to put data
 415 *
 416 * Return:
 417 *_SUCCESS(1)           Success
 418 *_FAIL(0)              Fail
 419 */
 420static u32 sdio_read_port(
 421        struct intf_hdl *intfhdl,
 422        u32 addr,
 423        u32 cnt,
 424        u8 *mem
 425)
 426{
 427        struct adapter *adapter;
 428        struct sdio_data *psdio;
 429        struct hal_com_data *hal;
 430        u32 oldcnt;
 431        s32 err;
 432
 433
 434        adapter = intfhdl->padapter;
 435        psdio = &adapter_to_dvobj(adapter)->intf_data;
 436        hal = GET_HAL_DATA(adapter);
 437
 438        HalSdioGetCmdAddr8723BSdio(adapter, addr, hal->SdioRxFIFOCnt++, &addr);
 439
 440        oldcnt = cnt;
 441        if (cnt > psdio->block_transfer_len)
 442                cnt = _RND(cnt, psdio->block_transfer_len);
 443/*      cnt = sdio_align_size(cnt); */
 444
 445        err = _sd_read(intfhdl, addr, cnt, mem);
 446
 447        if (err)
 448                return _FAIL;
 449        return _SUCCESS;
 450}
 451
 452/*
 453 * Description:
 454 *Write to TX FIFO
 455 *Align write size block size,
 456 *and make sure data could be written in one command.
 457 *
 458 * Parameters:
 459 *intfhdl       a pointer of intf_hdl
 460 *addr          port ID
 461 *cnt                   size to write
 462 *wmem          data pointer to write
 463 *
 464 * Return:
 465 *_SUCCESS(1)           Success
 466 *_FAIL(0)              Fail
 467 */
 468static u32 sdio_write_port(
 469        struct intf_hdl *intfhdl,
 470        u32 addr,
 471        u32 cnt,
 472        u8 *mem
 473)
 474{
 475        struct adapter *adapter;
 476        struct sdio_data *psdio;
 477        s32 err;
 478        struct xmit_buf *xmitbuf = (struct xmit_buf *)mem;
 479
 480        adapter = intfhdl->padapter;
 481        psdio = &adapter_to_dvobj(adapter)->intf_data;
 482
 483        if (!adapter->hw_init_completed) {
 484                DBG_871X("%s [addr = 0x%x cnt =%d] adapter->hw_init_completed == false\n", __func__, addr, cnt);
 485                return _FAIL;
 486        }
 487
 488        cnt = _RND4(cnt);
 489        HalSdioGetCmdAddr8723BSdio(adapter, addr, cnt >> 2, &addr);
 490
 491        if (cnt > psdio->block_transfer_len)
 492                cnt = _RND(cnt, psdio->block_transfer_len);
 493/*      cnt = sdio_align_size(cnt); */
 494
 495        err = sd_write(intfhdl, addr, cnt, xmitbuf->pdata);
 496
 497        rtw_sctx_done_err(
 498                &xmitbuf->sctx,
 499                err ? RTW_SCTX_DONE_WRITE_PORT_ERR : RTW_SCTX_DONE_SUCCESS
 500        );
 501
 502        if (err)
 503                return _FAIL;
 504        return _SUCCESS;
 505}
 506
 507void sdio_set_intf_ops(struct adapter *adapter, struct _io_ops *ops)
 508{
 509        ops->_read8 = &sdio_read8;
 510        ops->_read16 = &sdio_read16;
 511        ops->_read32 = &sdio_read32;
 512        ops->_read_mem = &sdio_read_mem;
 513        ops->_read_port = &sdio_read_port;
 514
 515        ops->_write8 = &sdio_write8;
 516        ops->_write16 = &sdio_write16;
 517        ops->_write32 = &sdio_write32;
 518        ops->_writeN = &sdio_writeN;
 519        ops->_write_mem = &sdio_write_mem;
 520        ops->_write_port = &sdio_write_port;
 521
 522        ops->_sd_f0_read8 = sdio_f0_read8;
 523}
 524
 525/*
 526 * Todo: align address to 4 bytes.
 527 */
 528static s32 _sdio_local_read(
 529        struct adapter *adapter,
 530        u32 addr,
 531        u32 cnt,
 532        u8 *buf
 533)
 534{
 535        struct intf_hdl *intfhdl;
 536        u8 mac_pwr_ctrl_on;
 537        s32 err;
 538        u8 *tmpbuf;
 539        u32 n;
 540
 541
 542        intfhdl = &adapter->iopriv.intf;
 543
 544        HalSdioGetCmdAddr8723BSdio(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr);
 545
 546        rtw_hal_get_hwreg(adapter, HW_VAR_APFM_ON_MAC, &mac_pwr_ctrl_on);
 547        if (!mac_pwr_ctrl_on)
 548                return _sd_cmd52_read(intfhdl, addr, cnt, buf);
 549
 550        n = RND4(cnt);
 551        tmpbuf = rtw_malloc(n);
 552        if (!tmpbuf)
 553                return -1;
 554
 555        err = _sd_read(intfhdl, addr, n, tmpbuf);
 556        if (!err)
 557                memcpy(buf, tmpbuf, cnt);
 558
 559        kfree(tmpbuf);
 560
 561        return err;
 562}
 563
 564/*
 565 * Todo: align address to 4 bytes.
 566 */
 567s32 sdio_local_read(
 568        struct adapter *adapter,
 569        u32 addr,
 570        u32 cnt,
 571        u8 *buf
 572)
 573{
 574        struct intf_hdl *intfhdl;
 575        u8 mac_pwr_ctrl_on;
 576        s32 err;
 577        u8 *tmpbuf;
 578        u32 n;
 579
 580        intfhdl = &adapter->iopriv.intf;
 581
 582        HalSdioGetCmdAddr8723BSdio(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr);
 583
 584        rtw_hal_get_hwreg(adapter, HW_VAR_APFM_ON_MAC, &mac_pwr_ctrl_on);
 585        if (
 586                (!mac_pwr_ctrl_on) ||
 587                (adapter_to_pwrctl(adapter)->bFwCurrentInPSMode)
 588        )
 589                return sd_cmd52_read(intfhdl, addr, cnt, buf);
 590
 591        n = RND4(cnt);
 592        tmpbuf = rtw_malloc(n);
 593        if (!tmpbuf)
 594                return -1;
 595
 596        err = sd_read(intfhdl, addr, n, tmpbuf);
 597        if (!err)
 598                memcpy(buf, tmpbuf, cnt);
 599
 600        kfree(tmpbuf);
 601
 602        return err;
 603}
 604
 605/*
 606 * Todo: align address to 4 bytes.
 607 */
 608s32 sdio_local_write(
 609        struct adapter *adapter,
 610        u32 addr,
 611        u32 cnt,
 612        u8 *buf
 613)
 614{
 615        struct intf_hdl *intfhdl;
 616        u8 mac_pwr_ctrl_on;
 617        s32 err;
 618        u8 *tmpbuf;
 619
 620        if (addr & 0x3)
 621                DBG_8192C("%s, address must be 4 bytes alignment\n", __func__);
 622
 623        if (cnt  & 0x3)
 624                DBG_8192C("%s, size must be the multiple of 4\n", __func__);
 625
 626        intfhdl = &adapter->iopriv.intf;
 627
 628        HalSdioGetCmdAddr8723BSdio(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr);
 629
 630        rtw_hal_get_hwreg(adapter, HW_VAR_APFM_ON_MAC, &mac_pwr_ctrl_on);
 631        if (
 632                (!mac_pwr_ctrl_on) ||
 633                (adapter_to_pwrctl(adapter)->bFwCurrentInPSMode)
 634        )
 635                return sd_cmd52_write(intfhdl, addr, cnt, buf);
 636
 637        tmpbuf = rtw_malloc(cnt);
 638        if (!tmpbuf)
 639                return -1;
 640
 641        memcpy(tmpbuf, buf, cnt);
 642
 643        err = sd_write(intfhdl, addr, cnt, tmpbuf);
 644
 645        kfree(tmpbuf);
 646
 647        return err;
 648}
 649
 650u8 SdioLocalCmd52Read1Byte(struct adapter *adapter, u32 addr)
 651{
 652        u8 val = 0;
 653        struct intf_hdl *intfhdl = &adapter->iopriv.intf;
 654
 655        HalSdioGetCmdAddr8723BSdio(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr);
 656        sd_cmd52_read(intfhdl, addr, 1, &val);
 657
 658        return val;
 659}
 660
 661static u16 SdioLocalCmd52Read2Byte(struct adapter *adapter, u32 addr)
 662{
 663        __le16 val = 0;
 664        struct intf_hdl *intfhdl = &adapter->iopriv.intf;
 665
 666        HalSdioGetCmdAddr8723BSdio(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr);
 667        sd_cmd52_read(intfhdl, addr, 2, (u8 *)&val);
 668
 669        return le16_to_cpu(val);
 670}
 671
 672static u32 SdioLocalCmd53Read4Byte(struct adapter *adapter, u32 addr)
 673{
 674
 675        u8 mac_pwr_ctrl_on;
 676        u32 val = 0;
 677        struct intf_hdl *intfhdl = &adapter->iopriv.intf;
 678        __le32 le_tmp;
 679
 680        HalSdioGetCmdAddr8723BSdio(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr);
 681        rtw_hal_get_hwreg(adapter, HW_VAR_APFM_ON_MAC, &mac_pwr_ctrl_on);
 682        if (!mac_pwr_ctrl_on || adapter_to_pwrctl(adapter)->bFwCurrentInPSMode) {
 683                sd_cmd52_read(intfhdl, addr, 4, (u8 *)&le_tmp);
 684                val = le32_to_cpu(le_tmp);
 685        } else {
 686                val = sd_read32(intfhdl, addr, NULL);
 687        }
 688        return val;
 689}
 690
 691void SdioLocalCmd52Write1Byte(struct adapter *adapter, u32 addr, u8 v)
 692{
 693        struct intf_hdl *intfhdl = &adapter->iopriv.intf;
 694
 695        HalSdioGetCmdAddr8723BSdio(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr);
 696        sd_cmd52_write(intfhdl, addr, 1, &v);
 697}
 698
 699static void SdioLocalCmd52Write4Byte(struct adapter *adapter, u32 addr, u32 v)
 700{
 701        struct intf_hdl *intfhdl = &adapter->iopriv.intf;
 702        __le32 le_tmp;
 703
 704        HalSdioGetCmdAddr8723BSdio(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr);
 705        le_tmp = cpu_to_le32(v);
 706        sd_cmd52_write(intfhdl, addr, 4, (u8 *)&le_tmp);
 707}
 708
 709static s32 ReadInterrupt8723BSdio(struct adapter *adapter, u32 *phisr)
 710{
 711        u32 hisr, himr;
 712        u8 val8, hisr_len;
 713
 714
 715        if (!phisr)
 716                return false;
 717
 718        himr = GET_HAL_DATA(adapter)->sdio_himr;
 719
 720        /*  decide how many bytes need to be read */
 721        hisr_len = 0;
 722        while (himr) {
 723                hisr_len++;
 724                himr >>= 8;
 725        }
 726
 727        hisr = 0;
 728        while (hisr_len != 0) {
 729                hisr_len--;
 730                val8 = SdioLocalCmd52Read1Byte(adapter, SDIO_REG_HISR + hisr_len);
 731                hisr |= (val8 << (8 * hisr_len));
 732        }
 733
 734        *phisr = hisr;
 735
 736        return true;
 737}
 738
 739/*  */
 740/*      Description: */
 741/*              Initialize SDIO Host Interrupt Mask configuration variables for future use. */
 742/*  */
 743/*      Assumption: */
 744/*              Using SDIO Local register ONLY for configuration. */
 745/*  */
 746/*      Created by Roger, 2011.02.11. */
 747/*  */
 748void InitInterrupt8723BSdio(struct adapter *adapter)
 749{
 750        struct hal_com_data *haldata;
 751
 752
 753        haldata = GET_HAL_DATA(adapter);
 754        haldata->sdio_himr = (u32)(             \
 755                                                                SDIO_HIMR_RX_REQUEST_MSK                        |
 756                                                                SDIO_HIMR_AVAL_MSK                                      |
 757/*                                                              SDIO_HIMR_TXERR_MSK                             | */
 758/*                                                              SDIO_HIMR_RXERR_MSK                             | */
 759/*                                                              SDIO_HIMR_TXFOVW_MSK                            | */
 760/*                                                              SDIO_HIMR_RXFOVW_MSK                            | */
 761/*                                                              SDIO_HIMR_TXBCNOK_MSK                           | */
 762/*                                                              SDIO_HIMR_TXBCNERR_MSK                  | */
 763/*                                                              SDIO_HIMR_BCNERLY_INT_MSK                       | */
 764/*                                                              SDIO_HIMR_C2HCMD_MSK                            | */
 765/*                                                              SDIO_HIMR_HSISR_IND_MSK                 | */
 766/*                                                              SDIO_HIMR_GTINT3_IND_MSK                        | */
 767/*                                                              SDIO_HIMR_GTINT4_IND_MSK                        | */
 768/*                                                              SDIO_HIMR_PSTIMEOUT_MSK                 | */
 769/*                                                              SDIO_HIMR_OCPINT_MSK                            | */
 770/*                                                              SDIO_HIMR_ATIMEND_MSK                           | */
 771/*                                                              SDIO_HIMR_ATIMEND_E_MSK                 | */
 772/*                                                              SDIO_HIMR_CTWEND_MSK                            | */
 773                                                                0);
 774}
 775
 776/*  */
 777/*      Description: */
 778/*              Initialize System Host Interrupt Mask configuration variables for future use. */
 779/*  */
 780/*      Created by Roger, 2011.08.03. */
 781/*  */
 782void InitSysInterrupt8723BSdio(struct adapter *adapter)
 783{
 784        struct hal_com_data *haldata;
 785
 786
 787        haldata = GET_HAL_DATA(adapter);
 788
 789        haldata->SysIntrMask = (                \
 790/*                                                      HSIMR_GPIO12_0_INT_EN                   | */
 791/*                                                      HSIMR_SPS_OCP_INT_EN                    | */
 792/*                                                      HSIMR_RON_INT_EN                                | */
 793/*                                                      HSIMR_PDNINT_EN                         | */
 794/*                                                      HSIMR_GPIO9_INT_EN                              | */
 795                                                        0);
 796}
 797
 798/*  */
 799/*      Description: */
 800/*              Enalbe SDIO Host Interrupt Mask configuration on SDIO local domain. */
 801/*  */
 802/*      Assumption: */
 803/*              1. Using SDIO Local register ONLY for configuration. */
 804/*              2. PASSIVE LEVEL */
 805/*  */
 806/*      Created by Roger, 2011.02.11. */
 807/*  */
 808void EnableInterrupt8723BSdio(struct adapter *adapter)
 809{
 810        struct hal_com_data *haldata;
 811        __le32 himr;
 812        u32 tmp;
 813
 814        haldata = GET_HAL_DATA(adapter);
 815
 816        himr = cpu_to_le32(haldata->sdio_himr);
 817        sdio_local_write(adapter, SDIO_REG_HIMR, 4, (u8 *)&himr);
 818
 819        RT_TRACE(
 820                _module_hci_ops_c_,
 821                _drv_notice_,
 822                (
 823                        "%s: enable SDIO HIMR = 0x%08X\n",
 824                        __func__,
 825                        haldata->sdio_himr
 826                )
 827        );
 828
 829        /*  Update current system IMR settings */
 830        tmp = rtw_read32(adapter, REG_HSIMR);
 831        rtw_write32(adapter, REG_HSIMR, tmp | haldata->SysIntrMask);
 832
 833        RT_TRACE(
 834                _module_hci_ops_c_,
 835                _drv_notice_,
 836                (
 837                        "%s: enable HSIMR = 0x%08X\n",
 838                        __func__,
 839                        haldata->SysIntrMask
 840                )
 841        );
 842
 843        /*  */
 844        /*  <Roger_Notes> There are some C2H CMDs have been sent before system interrupt is enabled, e.g., C2H, CPWM. */
 845        /*  So we need to clear all C2H events that FW has notified, otherwise FW won't schedule any commands anymore. */
 846        /*  2011.10.19. */
 847        /*  */
 848        rtw_write8(adapter, REG_C2HEVT_CLEAR, C2H_EVT_HOST_CLOSE);
 849}
 850
 851/*  */
 852/*      Description: */
 853/*              Disable SDIO Host IMR configuration to mask unnecessary interrupt service. */
 854/*  */
 855/*      Assumption: */
 856/*              Using SDIO Local register ONLY for configuration. */
 857/*  */
 858/*      Created by Roger, 2011.02.11. */
 859/*  */
 860void DisableInterrupt8723BSdio(struct adapter *adapter)
 861{
 862        __le32 himr;
 863
 864        himr = cpu_to_le32(SDIO_HIMR_DISABLED);
 865        sdio_local_write(adapter, SDIO_REG_HIMR, 4, (u8 *)&himr);
 866}
 867
 868/*  */
 869/*      Description: */
 870/*              Using 0x100 to check the power status of FW. */
 871/*  */
 872/*      Assumption: */
 873/*              Using SDIO Local register ONLY for configuration. */
 874/*  */
 875/*      Created by Isaac, 2013.09.10. */
 876/*  */
 877u8 CheckIPSStatus(struct adapter *adapter)
 878{
 879        DBG_871X(
 880                "%s(): Read 0x100 = 0x%02x 0x86 = 0x%02x\n",
 881                __func__,
 882                rtw_read8(adapter, 0x100),
 883                rtw_read8(adapter, 0x86)
 884        );
 885
 886        if (rtw_read8(adapter, 0x100) == 0xEA)
 887                return true;
 888        else
 889                return false;
 890}
 891
 892static struct recv_buf *sd_recv_rxfifo(struct adapter *adapter, u32 size)
 893{
 894        u32 readsize, ret;
 895        u8 *readbuf;
 896        struct recv_priv *recv_priv;
 897        struct recv_buf *recvbuf;
 898
 899
 900        /*  Patch for some SDIO Host 4 bytes issue */
 901        /*  ex. RK3188 */
 902        readsize = RND4(size);
 903
 904        /* 3 1. alloc recvbuf */
 905        recv_priv = &adapter->recvpriv;
 906        recvbuf = rtw_dequeue_recvbuf(&recv_priv->free_recv_buf_queue);
 907        if (!recvbuf) {
 908                DBG_871X_LEVEL(_drv_err_, "%s: alloc recvbuf FAIL!\n", __func__);
 909                return NULL;
 910        }
 911
 912        /* 3 2. alloc skb */
 913        if (!recvbuf->pskb) {
 914                SIZE_PTR tmpaddr = 0;
 915                SIZE_PTR alignment = 0;
 916
 917                recvbuf->pskb = rtw_skb_alloc(MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ);
 918
 919                if (recvbuf->pskb) {
 920                        recvbuf->pskb->dev = adapter->pnetdev;
 921
 922                        tmpaddr = (SIZE_PTR)recvbuf->pskb->data;
 923                        alignment = tmpaddr & (RECVBUFF_ALIGN_SZ - 1);
 924                        skb_reserve(recvbuf->pskb, (RECVBUFF_ALIGN_SZ - alignment));
 925                }
 926
 927                if (!recvbuf->pskb) {
 928                        DBG_871X("%s: alloc_skb fail! read =%d\n", __func__, readsize);
 929                        return NULL;
 930                }
 931        }
 932
 933        /* 3 3. read data from rxfifo */
 934        readbuf = recvbuf->pskb->data;
 935        ret = sdio_read_port(&adapter->iopriv.intf, WLAN_RX0FF_DEVICE_ID, readsize, readbuf);
 936        if (ret == _FAIL) {
 937                RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("%s: read port FAIL!\n", __func__));
 938                return NULL;
 939        }
 940
 941
 942        /* 3 4. init recvbuf */
 943        recvbuf->len = size;
 944        recvbuf->phead = recvbuf->pskb->head;
 945        recvbuf->pdata = recvbuf->pskb->data;
 946        skb_set_tail_pointer(recvbuf->pskb, size);
 947        recvbuf->ptail = skb_tail_pointer(recvbuf->pskb);
 948        recvbuf->pend = skb_end_pointer(recvbuf->pskb);
 949
 950        return recvbuf;
 951}
 952
 953static void sd_rxhandler(struct adapter *adapter, struct recv_buf *recvbuf)
 954{
 955        struct recv_priv *recv_priv;
 956        struct __queue *pending_queue;
 957
 958        recv_priv = &adapter->recvpriv;
 959        pending_queue = &recv_priv->recv_buf_pending_queue;
 960
 961        /* 3 1. enqueue recvbuf */
 962        rtw_enqueue_recvbuf(recvbuf, pending_queue);
 963
 964        /* 3 2. schedule tasklet */
 965        tasklet_schedule(&recv_priv->recv_tasklet);
 966}
 967
 968void sd_int_dpc(struct adapter *adapter)
 969{
 970        struct hal_com_data *hal;
 971        struct dvobj_priv *dvobj;
 972        struct intf_hdl *intfhdl = &adapter->iopriv.intf;
 973        struct pwrctrl_priv *pwrctl;
 974
 975
 976        hal = GET_HAL_DATA(adapter);
 977        dvobj = adapter_to_dvobj(adapter);
 978        pwrctl = dvobj_to_pwrctl(dvobj);
 979
 980        if (hal->sdio_hisr & SDIO_HISR_AVAL) {
 981                u8 freepage[4];
 982
 983                _sdio_local_read(adapter, SDIO_REG_FREE_TXPG, 4, freepage);
 984                complete(&(adapter->xmitpriv.xmit_comp));
 985        }
 986
 987        if (hal->sdio_hisr & SDIO_HISR_CPWM1) {
 988                struct reportpwrstate_parm report;
 989
 990                u8 bcancelled;
 991                _cancel_timer(&(pwrctl->pwr_rpwm_timer), &bcancelled);
 992
 993                report.state = SdioLocalCmd52Read1Byte(adapter, SDIO_REG_HCPWM1_8723B);
 994
 995                /* cpwm_int_hdl(adapter, &report); */
 996                _set_workitem(&(pwrctl->cpwm_event));
 997        }
 998
 999        if (hal->sdio_hisr & SDIO_HISR_TXERR) {
1000                u8 *status;
1001                u32 addr;
1002
1003                status = rtw_malloc(4);
1004                if (status) {
1005                        addr = REG_TXDMA_STATUS;
1006                        HalSdioGetCmdAddr8723BSdio(adapter, WLAN_IOREG_DEVICE_ID, addr, &addr);
1007                        _sd_read(intfhdl, addr, 4, status);
1008                        _sd_write(intfhdl, addr, 4, status);
1009                        DBG_8192C("%s: SDIO_HISR_TXERR (0x%08x)\n", __func__, le32_to_cpu(*(u32 *)status));
1010                        kfree(status);
1011                } else {
1012                        DBG_8192C("%s: SDIO_HISR_TXERR, but can't allocate memory to read status!\n", __func__);
1013                }
1014        }
1015
1016        if (hal->sdio_hisr & SDIO_HISR_TXBCNOK)
1017                DBG_8192C("%s: SDIO_HISR_TXBCNOK\n", __func__);
1018
1019        if (hal->sdio_hisr & SDIO_HISR_TXBCNERR)
1020                DBG_8192C("%s: SDIO_HISR_TXBCNERR\n", __func__);
1021#ifndef CONFIG_C2H_PACKET_EN
1022        if (hal->sdio_hisr & SDIO_HISR_C2HCMD) {
1023                struct c2h_evt_hdr_88xx *c2h_evt;
1024
1025                DBG_8192C("%s: C2H Command\n", __func__);
1026                c2h_evt = rtw_zmalloc(16);
1027                if (c2h_evt) {
1028                        if (c2h_evt_read_88xx(adapter, (u8 *)c2h_evt) == _SUCCESS) {
1029                                if (c2h_id_filter_ccx_8723b((u8 *)c2h_evt)) {
1030                                        /* Handle CCX report here */
1031                                        rtw_hal_c2h_handler(adapter, (u8 *)c2h_evt);
1032                                        kfree((u8 *)c2h_evt);
1033                                } else {
1034                                        rtw_c2h_wk_cmd(adapter, (u8 *)c2h_evt);
1035                                }
1036                        }
1037                } else {
1038                        /* Error handling for malloc fail */
1039                        if (rtw_cbuf_push(adapter->evtpriv.c2h_queue, NULL) != _SUCCESS)
1040                                DBG_871X("%s rtw_cbuf_push fail\n", __func__);
1041                        _set_workitem(&adapter->evtpriv.c2h_wk);
1042                }
1043        }
1044#endif
1045
1046        if (hal->sdio_hisr & SDIO_HISR_RXFOVW)
1047                DBG_8192C("%s: Rx Overflow\n", __func__);
1048
1049        if (hal->sdio_hisr & SDIO_HISR_RXERR)
1050                DBG_8192C("%s: Rx Error\n", __func__);
1051
1052
1053        if (hal->sdio_hisr & SDIO_HISR_RX_REQUEST) {
1054                struct recv_buf *recvbuf;
1055                int alloc_fail_time = 0;
1056                u32 hisr;
1057
1058/*              DBG_8192C("%s: RX Request, size =%d\n", __func__, hal->SdioRxFIFOSize); */
1059                hal->sdio_hisr ^= SDIO_HISR_RX_REQUEST;
1060                do {
1061                        hal->SdioRxFIFOSize = SdioLocalCmd52Read2Byte(adapter, SDIO_REG_RX0_REQ_LEN);
1062                        if (hal->SdioRxFIFOSize != 0) {
1063                                recvbuf = sd_recv_rxfifo(adapter, hal->SdioRxFIFOSize);
1064                                if (recvbuf)
1065                                        sd_rxhandler(adapter, recvbuf);
1066                                else {
1067                                        alloc_fail_time++;
1068                                        DBG_871X("recvbuf is Null for %d times because alloc memory failed\n", alloc_fail_time);
1069                                        if (alloc_fail_time >= 10)
1070                                                break;
1071                                }
1072                                hal->SdioRxFIFOSize = 0;
1073                        } else
1074                                break;
1075
1076                        hisr = 0;
1077                        ReadInterrupt8723BSdio(adapter, &hisr);
1078                        hisr &= SDIO_HISR_RX_REQUEST;
1079                        if (!hisr)
1080                                break;
1081                } while (1);
1082
1083                if (alloc_fail_time == 10)
1084                        DBG_871X("exit because alloc memory failed more than 10 times\n");
1085
1086        }
1087}
1088
1089void sd_int_hdl(struct adapter *adapter)
1090{
1091        struct hal_com_data *hal;
1092
1093
1094        if (
1095                (adapter->bDriverStopped) || (adapter->bSurpriseRemoved)
1096        )
1097                return;
1098
1099        hal = GET_HAL_DATA(adapter);
1100
1101        hal->sdio_hisr = 0;
1102        ReadInterrupt8723BSdio(adapter, &hal->sdio_hisr);
1103
1104        if (hal->sdio_hisr & hal->sdio_himr) {
1105                u32 v32;
1106
1107                hal->sdio_hisr &= hal->sdio_himr;
1108
1109                /*  clear HISR */
1110                v32 = hal->sdio_hisr & MASK_SDIO_HISR_CLEAR;
1111                if (v32)
1112                        SdioLocalCmd52Write4Byte(adapter, SDIO_REG_HISR, v32);
1113
1114                sd_int_dpc(adapter);
1115        } else {
1116                RT_TRACE(_module_hci_ops_c_, _drv_err_,
1117                                ("%s: HISR(0x%08x) and HIMR(0x%08x) not match!\n",
1118                                __func__, hal->sdio_hisr, hal->sdio_himr));
1119        }
1120}
1121
1122/*  */
1123/*      Description: */
1124/*              Query SDIO Local register to query current the number of Free TxPacketBuffer page. */
1125/*  */
1126/*      Assumption: */
1127/*              1. Running at PASSIVE_LEVEL */
1128/*              2. RT_TX_SPINLOCK is NOT acquired. */
1129/*  */
1130/*      Created by Roger, 2011.01.28. */
1131/*  */
1132u8 HalQueryTxBufferStatus8723BSdio(struct adapter *adapter)
1133{
1134        struct hal_com_data *hal;
1135        u32 numof_free_page;
1136        /* _irql irql; */
1137
1138
1139        hal = GET_HAL_DATA(adapter);
1140
1141        numof_free_page = SdioLocalCmd53Read4Byte(adapter, SDIO_REG_FREE_TXPG);
1142
1143        /* spin_lock_bh(&phal->SdioTxFIFOFreePageLock); */
1144        memcpy(hal->SdioTxFIFOFreePage, &numof_free_page, 4);
1145        RT_TRACE(_module_hci_ops_c_, _drv_notice_,
1146                        ("%s: Free page for HIQ(%#x), MIDQ(%#x), LOWQ(%#x), PUBQ(%#x)\n",
1147                        __func__,
1148                        hal->SdioTxFIFOFreePage[HI_QUEUE_IDX],
1149                        hal->SdioTxFIFOFreePage[MID_QUEUE_IDX],
1150                        hal->SdioTxFIFOFreePage[LOW_QUEUE_IDX],
1151                        hal->SdioTxFIFOFreePage[PUBLIC_QUEUE_IDX]));
1152        /* spin_unlock_bh(&hal->SdioTxFIFOFreePageLock); */
1153
1154        return true;
1155}
1156
1157/*  */
1158/*      Description: */
1159/*              Query SDIO Local register to get the current number of TX OQT Free Space. */
1160/*  */
1161void HalQueryTxOQTBufferStatus8723BSdio(struct adapter *adapter)
1162{
1163        struct hal_com_data *haldata = GET_HAL_DATA(adapter);
1164
1165        haldata->SdioTxOQTFreeSpace = SdioLocalCmd52Read1Byte(adapter, SDIO_REG_OQT_FREE_PG);
1166}
1167
1168#if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN)
1169u8 RecvOnePkt(struct adapter *adapter, u32 size)
1170{
1171        struct recv_buf *recvbuf;
1172        struct dvobj_priv *sddev;
1173        struct sdio_func *func;
1174
1175        u8 res = false;
1176
1177        DBG_871X("+%s: size: %d+\n", __func__, size);
1178
1179        if (!adapter) {
1180                DBG_871X(KERN_ERR "%s: adapter is NULL!\n", __func__);
1181                return false;
1182        }
1183
1184        sddev = adapter_to_dvobj(adapter);
1185        psdio_data = &sddev->intf_data;
1186        func = psdio_data->func;
1187
1188        if (size) {
1189                sdio_claim_host(func);
1190                recvbuf = sd_recv_rxfifo(adapter, size);
1191
1192                if (recvbuf) {
1193                        /* printk("Completed Recv One Pkt.\n"); */
1194                        sd_rxhandler(adapter, recvbuf);
1195                        res = true;
1196                } else {
1197                        res = false;
1198                }
1199                sdio_release_host(func);
1200        }
1201        DBG_871X("-%s-\n", __func__);
1202        return res;
1203}
1204#endif /* CONFIG_WOWLAN */
1205