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