linux/drivers/net/wireless/rtlwifi/rtl8723ae/fw.c
<<
>>
Prefs
   1/******************************************************************************
   2 *
   3 * Copyright(c) 2009-2012  Realtek Corporation.
   4 *
   5 * This program is free software; you can redistribute it and/or modify it
   6 * under the terms of version 2 of the GNU General Public License as
   7 * published by the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope that it will be useful, but WITHOUT
  10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  12 * more details.
  13 *
  14 * 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 * The full GNU General Public License is included in this distribution in the
  19 * file called LICENSE.
  20 *
  21 * Contact Information:
  22 * wlanfae <wlanfae@realtek.com>
  23 * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
  24 * Hsinchu 300, Taiwan.
  25 *
  26 * Larry Finger <Larry.Finger@lwfinger.net>
  27 *
  28 ****************************************************************************
  29 */
  30
  31#include "../wifi.h"
  32#include "../pci.h"
  33#include "../base.h"
  34#include "reg.h"
  35#include "def.h"
  36#include "fw.h"
  37
  38static void _rtl8723ae_enable_fw_download(struct ieee80211_hw *hw, bool enable)
  39{
  40        struct rtl_priv *rtlpriv = rtl_priv(hw);
  41        u8 tmp;
  42        if (enable) {
  43                tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
  44                rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmp | 0x04);
  45
  46                tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
  47                rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01);
  48
  49                tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);
  50                rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);
  51        } else {
  52                tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
  53                rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);
  54
  55                rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00);
  56        }
  57}
  58
  59static void _rtl8723ae_fw_block_write(struct ieee80211_hw *hw,
  60                                      const u8 *buffer, u32 size)
  61{
  62        struct rtl_priv *rtlpriv = rtl_priv(hw);
  63        u32 blockSize = sizeof(u32);
  64        u8 *bufferPtr = (u8 *) buffer;
  65        u32 *pu4BytePtr = (u32 *) buffer;
  66        u32 i, offset, blockCount, remainSize;
  67
  68        blockCount = size / blockSize;
  69        remainSize = size % blockSize;
  70
  71        for (i = 0; i < blockCount; i++) {
  72                offset = i * blockSize;
  73                rtl_write_dword(rtlpriv, (FW_8192C_START_ADDRESS + offset),
  74                                *(pu4BytePtr + i));
  75        }
  76
  77        if (remainSize) {
  78                offset = blockCount * blockSize;
  79                bufferPtr += offset;
  80                for (i = 0; i < remainSize; i++) {
  81                        rtl_write_byte(rtlpriv, (FW_8192C_START_ADDRESS +
  82                                                 offset + i), *(bufferPtr + i));
  83                }
  84        }
  85}
  86
  87static void _rtl8723ae_fw_page_write(struct ieee80211_hw *hw,
  88                                     u32 page, const u8 *buffer, u32 size)
  89{
  90        struct rtl_priv *rtlpriv = rtl_priv(hw);
  91        u8 value8;
  92        u8 u8page = (u8) (page & 0x07);
  93
  94        value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page;
  95
  96        rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8);
  97        _rtl8723ae_fw_block_write(hw, buffer, size);
  98}
  99
 100static void _rtl8723ae_write_fw(struct ieee80211_hw *hw,
 101                                enum version_8723e version, u8 *buffer,
 102                                u32 size)
 103{
 104        struct rtl_priv *rtlpriv = rtl_priv(hw);
 105        u8 *bufferPtr = (u8 *) buffer;
 106        u32 page_nums, remain_size;
 107        u32 page, offset;
 108
 109        RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "FW size is %d bytes,\n", size);
 110
 111        page_nums = size / FW_8192C_PAGE_SIZE;
 112        remain_size = size % FW_8192C_PAGE_SIZE;
 113
 114        if (page_nums > 6) {
 115                RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 116                         "Page numbers should not be greater then 6\n");
 117        }
 118
 119        for (page = 0; page < page_nums; page++) {
 120                offset = page * FW_8192C_PAGE_SIZE;
 121                _rtl8723ae_fw_page_write(hw, page, (bufferPtr + offset),
 122                                         FW_8192C_PAGE_SIZE);
 123        }
 124
 125        if (remain_size) {
 126                offset = page_nums * FW_8192C_PAGE_SIZE;
 127                page = page_nums;
 128                _rtl8723ae_fw_page_write(hw, page, (bufferPtr + offset),
 129                                         remain_size);
 130        }
 131
 132        RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "FW write done.\n");
 133}
 134
 135static int _rtl8723ae_fw_free_to_go(struct ieee80211_hw *hw)
 136{
 137        struct rtl_priv *rtlpriv = rtl_priv(hw);
 138        int err = -EIO;
 139        u32 counter = 0;
 140        u32 value32;
 141
 142        do {
 143                value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
 144        } while ((counter++ < FW_8192C_POLLING_TIMEOUT_COUNT) &&
 145                 (!(value32 & FWDL_ChkSum_rpt)));
 146
 147        if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) {
 148                RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 149                         "chksum report faill ! REG_MCUFWDL:0x%08x .\n",
 150                         value32);
 151                goto exit;
 152        }
 153
 154        RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
 155                 "Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32);
 156
 157        value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
 158        value32 |= MCUFWDL_RDY;
 159        value32 &= ~WINTINI_RDY;
 160        rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
 161
 162        counter = 0;
 163
 164        do {
 165                value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
 166                if (value32 & WINTINI_RDY) {
 167                        RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
 168                                 "Polling FW ready success!! REG_MCUFWDL:0x%08x .\n",
 169                                 value32);
 170                        err = 0;
 171                        goto exit;
 172                }
 173
 174                mdelay(FW_8192C_POLLING_DELAY);
 175
 176        } while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT);
 177
 178        RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 179                 "Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n", value32);
 180
 181exit:
 182        return err;
 183}
 184
 185int rtl8723ae_download_fw(struct ieee80211_hw *hw)
 186{
 187        struct rtl_priv *rtlpriv = rtl_priv(hw);
 188        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 189        struct rtl8723ae_firmware_header *pfwheader;
 190        u8 *pfwdata;
 191        u32 fwsize;
 192        int err;
 193        enum version_8723e version = rtlhal->version;
 194
 195        if (!rtlhal->pfirmware)
 196                return 1;
 197
 198        pfwheader = (struct rtl8723ae_firmware_header *)rtlhal->pfirmware;
 199        pfwdata = (u8 *) rtlhal->pfirmware;
 200        fwsize = rtlhal->fwsize;
 201
 202        if (IS_FW_HEADER_EXIST(pfwheader)) {
 203                RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
 204                         "Firmware Version(%d), Signature(%#x),Size(%d)\n",
 205                         pfwheader->version, pfwheader->signature,
 206                         (int)sizeof(struct rtl8723ae_firmware_header));
 207
 208                pfwdata = pfwdata + sizeof(struct rtl8723ae_firmware_header);
 209                fwsize = fwsize - sizeof(struct rtl8723ae_firmware_header);
 210        }
 211
 212        if (rtl_read_byte(rtlpriv, REG_MCUFWDL)&BIT(7)) {
 213                rtl8723ae_firmware_selfreset(hw);
 214                rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00);
 215        }
 216        _rtl8723ae_enable_fw_download(hw, true);
 217        _rtl8723ae_write_fw(hw, version, pfwdata, fwsize);
 218        _rtl8723ae_enable_fw_download(hw, false);
 219
 220        err = _rtl8723ae_fw_free_to_go(hw);
 221        if (err) {
 222                RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 223                         "Firmware is not ready to run!\n");
 224        } else {
 225                RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
 226                         "Firmware is ready to run!\n");
 227        }
 228        return 0;
 229}
 230
 231static bool rtl8723ae_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
 232{
 233        struct rtl_priv *rtlpriv = rtl_priv(hw);
 234        u8 val_hmetfr, val_mcutst_1;
 235        bool result = false;
 236
 237        val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
 238        val_mcutst_1 = rtl_read_byte(rtlpriv, (REG_MCUTST_1 + boxnum));
 239
 240        if (((val_hmetfr >> boxnum) & BIT(0)) == 0 && val_mcutst_1 == 0)
 241                result = true;
 242        return result;
 243}
 244
 245static void _rtl8723ae_fill_h2c_command(struct ieee80211_hw *hw,
 246                                        u8 element_id, u32 cmd_len,
 247                                        u8 *p_cmdbuffer)
 248{
 249        struct rtl_priv *rtlpriv = rtl_priv(hw);
 250        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 251        u8 boxnum;
 252        u16 box_reg = 0, box_extreg = 0;
 253        u8 u1tmp;
 254        bool isfw_rd = false;
 255        bool bwrite_success = false;
 256        u8 wait_h2c_limmit = 100;
 257        u8 wait_writeh2c_limmit = 100;
 258        u8 boxcontent[4], boxextcontent[2];
 259        u32 h2c_waitcounter = 0;
 260        unsigned long flag;
 261        u8 idx;
 262
 263        RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "come in\n");
 264
 265        while (true) {
 266                spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
 267                if (rtlhal->h2c_setinprogress) {
 268                        RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
 269                                 "H2C set in progress! Wait to set..element_id(%d).\n",
 270                                 element_id);
 271
 272                        while (rtlhal->h2c_setinprogress) {
 273                                spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
 274                                                       flag);
 275                                h2c_waitcounter++;
 276                                RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
 277                                         "Wait 100 us (%d times)...\n",
 278                                         h2c_waitcounter);
 279                                udelay(100);
 280
 281                                if (h2c_waitcounter > 1000)
 282                                        return;
 283                                spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
 284                                                  flag);
 285                        }
 286                        spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
 287                } else {
 288                        rtlhal->h2c_setinprogress = true;
 289                        spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
 290                        break;
 291                }
 292        }
 293
 294        while (!bwrite_success) {
 295                wait_writeh2c_limmit--;
 296                if (wait_writeh2c_limmit == 0) {
 297                        RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 298                                 "Write H2C fail because no trigger "
 299                                 "for FW INT!\n");
 300                        break;
 301                }
 302
 303                boxnum = rtlhal->last_hmeboxnum;
 304                switch (boxnum) {
 305                case 0:
 306                        box_reg = REG_HMEBOX_0;
 307                        box_extreg = REG_HMEBOX_EXT_0;
 308                        break;
 309                case 1:
 310                        box_reg = REG_HMEBOX_1;
 311                        box_extreg = REG_HMEBOX_EXT_1;
 312                        break;
 313                case 2:
 314                        box_reg = REG_HMEBOX_2;
 315                        box_extreg = REG_HMEBOX_EXT_2;
 316                        break;
 317                case 3:
 318                        box_reg = REG_HMEBOX_3;
 319                        box_extreg = REG_HMEBOX_EXT_3;
 320                        break;
 321                default:
 322                        RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 323                                 "switch case not processed\n");
 324                        break;
 325                }
 326
 327                isfw_rd = rtl8723ae_check_fw_read_last_h2c(hw, boxnum);
 328                while (!isfw_rd) {
 329
 330                        wait_h2c_limmit--;
 331                        if (wait_h2c_limmit == 0) {
 332                                RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
 333                                         "Wating too long for FW read clear HMEBox(%d)!\n",
 334                                         boxnum);
 335                                break;
 336                        }
 337
 338                        udelay(10);
 339
 340                        isfw_rd = rtl8723ae_check_fw_read_last_h2c(hw, boxnum);
 341                        u1tmp = rtl_read_byte(rtlpriv, 0x1BF);
 342                        RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
 343                                 "Wating for FW read clear HMEBox(%d)!!! "
 344                                 "0x1BF = %2x\n", boxnum, u1tmp);
 345                }
 346
 347                if (!isfw_rd) {
 348                        RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
 349                                 "Write H2C register BOX[%d] fail!!!!! "
 350                                 "Fw do not read.\n", boxnum);
 351                        break;
 352                }
 353
 354                memset(boxcontent, 0, sizeof(boxcontent));
 355                memset(boxextcontent, 0, sizeof(boxextcontent));
 356                boxcontent[0] = element_id;
 357                RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
 358                         "Write element_id box_reg(%4x) = %2x\n",
 359                          box_reg, element_id);
 360
 361                switch (cmd_len) {
 362                case 1:
 363                        boxcontent[0] &= ~(BIT(7));
 364                        memcpy((u8 *) (boxcontent) + 1,
 365                               p_cmdbuffer, 1);
 366
 367                        for (idx = 0; idx < 4; idx++) {
 368                                rtl_write_byte(rtlpriv, box_reg + idx,
 369                                               boxcontent[idx]);
 370                        }
 371                        break;
 372                case 2:
 373                        boxcontent[0] &= ~(BIT(7));
 374                        memcpy((u8 *) (boxcontent) + 1,
 375                               p_cmdbuffer, 2);
 376
 377                        for (idx = 0; idx < 4; idx++) {
 378                                rtl_write_byte(rtlpriv, box_reg + idx,
 379                                               boxcontent[idx]);
 380                        }
 381                        break;
 382                case 3:
 383                        boxcontent[0] &= ~(BIT(7));
 384                        memcpy((u8 *) (boxcontent) + 1,
 385                               p_cmdbuffer, 3);
 386
 387                        for (idx = 0; idx < 4; idx++) {
 388                                rtl_write_byte(rtlpriv, box_reg + idx,
 389                                               boxcontent[idx]);
 390                        }
 391                        break;
 392                case 4:
 393                        boxcontent[0] |= (BIT(7));
 394                        memcpy((u8 *) (boxextcontent),
 395                               p_cmdbuffer, 2);
 396                        memcpy((u8 *) (boxcontent) + 1,
 397                               p_cmdbuffer + 2, 2);
 398
 399                        for (idx = 0; idx < 2; idx++) {
 400                                rtl_write_byte(rtlpriv, box_extreg + idx,
 401                                               boxextcontent[idx]);
 402                        }
 403
 404                        for (idx = 0; idx < 4; idx++) {
 405                                rtl_write_byte(rtlpriv, box_reg + idx,
 406                                               boxcontent[idx]);
 407                        }
 408                        break;
 409                case 5:
 410                        boxcontent[0] |= (BIT(7));
 411                        memcpy((u8 *) (boxextcontent),
 412                               p_cmdbuffer, 2);
 413                        memcpy((u8 *) (boxcontent) + 1,
 414                               p_cmdbuffer + 2, 3);
 415
 416                        for (idx = 0; idx < 2; idx++) {
 417                                rtl_write_byte(rtlpriv, box_extreg + idx,
 418                                               boxextcontent[idx]);
 419                        }
 420
 421                        for (idx = 0; idx < 4; idx++) {
 422                                rtl_write_byte(rtlpriv, box_reg + idx,
 423                                               boxcontent[idx]);
 424                        }
 425                        break;
 426                default:
 427                        RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 428                                 "switch case not process\n");
 429                        break;
 430                }
 431
 432                bwrite_success = true;
 433
 434                rtlhal->last_hmeboxnum = boxnum + 1;
 435                if (rtlhal->last_hmeboxnum == 4)
 436                        rtlhal->last_hmeboxnum = 0;
 437
 438                RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
 439                         "pHalData->last_hmeboxnum  = %d\n",
 440                         rtlhal->last_hmeboxnum);
 441        }
 442
 443        spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
 444        rtlhal->h2c_setinprogress = false;
 445        spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
 446
 447        RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n");
 448}
 449
 450void rtl8723ae_fill_h2c_cmd(struct ieee80211_hw *hw,
 451                            u8 element_id, u32 cmd_len, u8 *p_cmdbuffer)
 452{
 453        struct rtl_priv *rtlpriv = rtl_priv(hw);
 454        struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
 455
 456        if (rtlhal->fw_ready == false) {
 457                RT_ASSERT(false,
 458                         "return H2C cmd because of Fw download fail!!!\n");
 459                return;
 460        }
 461
 462        _rtl8723ae_fill_h2c_command(hw, element_id, cmd_len, p_cmdbuffer);
 463        return;
 464}
 465
 466void rtl8723ae_firmware_selfreset(struct ieee80211_hw *hw)
 467{
 468        u8 u1tmp;
 469        u8 delay = 100;
 470        struct rtl_priv *rtlpriv = rtl_priv(hw);
 471
 472        rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20);
 473        u1tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
 474
 475        while (u1tmp & BIT(2)) {
 476                delay--;
 477                if (delay == 0)
 478                        break;
 479                udelay(50);
 480                u1tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
 481        }
 482        if (delay == 0) {
 483                u1tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
 484                rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, u1tmp&(~BIT(2)));
 485        }
 486}
 487
 488void rtl8723ae_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
 489{
 490        struct rtl_priv *rtlpriv = rtl_priv(hw);
 491        u8 u1_h2c_set_pwrmode[3] = { 0 };
 492        struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
 493
 494        RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode);
 495
 496        SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode);
 497        SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode,
 498                                         (rtlpriv->mac80211.p2p) ?
 499                                         ppsc->smart_ps : 1);
 500        SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode,
 501                                              ppsc->reg_max_lps_awakeintvl);
 502
 503        RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
 504                      "rtl8723ae_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode\n",
 505                      u1_h2c_set_pwrmode, 3);
 506        rtl8723ae_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode);
 507
 508}
 509
 510static bool _rtl8723ae_cmd_send_packet(struct ieee80211_hw *hw,
 511                                       struct sk_buff *skb)
 512{
 513        struct rtl_priv *rtlpriv = rtl_priv(hw);
 514        struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 515        struct rtl8192_tx_ring *ring;
 516        struct rtl_tx_desc *pdesc;
 517        unsigned long flags;
 518        struct sk_buff *pskb = NULL;
 519
 520        ring = &rtlpci->tx_ring[BEACON_QUEUE];
 521
 522        pskb = __skb_dequeue(&ring->queue);
 523        if (pskb)
 524                kfree_skb(pskb);
 525
 526        spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
 527
 528        pdesc = &ring->desc[0];
 529
 530        rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb);
 531
 532        __skb_queue_tail(&ring->queue, skb);
 533
 534        spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
 535
 536        rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE);
 537
 538        return true;
 539}
 540
 541static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
 542        /* page 0 beacon */
 543        0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
 544        0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
 545        0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08,
 546        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 547        0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
 548        0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
 549        0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
 550        0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
 551        0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
 552        0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
 553        0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 554        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 555        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 556        0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
 557        0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 558        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 559
 560        /* page 1 beacon */
 561        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 562        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 563        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 564        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 565        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 566        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 567        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 568        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 569        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 570        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 571        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 572        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 573        0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00,
 574        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 575        0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 576        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 577
 578        /* page 2  ps-poll */
 579        0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10,
 580        0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
 581        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 582        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 583        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 584        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 585        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 586        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 587        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 588        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 589        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 590        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 591        0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
 592        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
 593        0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 594        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 595
 596        /* page 3  null */
 597        0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
 598        0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
 599        0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
 600        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 601        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 602        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 603        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 604        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 605        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 606        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 607        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 608        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 609        0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
 610        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
 611        0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 612        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 613
 614        /* page 4  probe_resp */
 615        0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
 616        0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
 617        0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
 618        0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
 619        0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
 620        0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
 621        0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
 622        0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
 623        0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
 624        0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
 625        0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 626        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 627        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 628        0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
 629        0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 630        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 631
 632        /* page 5  probe_resp */
 633        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 634        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 635        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 636        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 637        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 638        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 639        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 640        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 641        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 642        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 643        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 644        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 645        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 646        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 647        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 648        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 649};
 650
 651void rtl8723ae_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished)
 652{
 653        struct rtl_priv *rtlpriv = rtl_priv(hw);
 654        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 655        struct sk_buff *skb = NULL;
 656
 657        u32 totalpacketlen;
 658        bool rtstatus;
 659        u8 u1RsvdPageLoc[3] = { 0 };
 660        bool dlok = false;
 661
 662        u8 *beacon;
 663        u8 *p_pspoll;
 664        u8 *nullfunc;
 665        u8 *p_probersp;
 666        /*---------------------------------------------------------
 667                                (1) beacon
 668        ---------------------------------------------------------
 669        */
 670        beacon = &reserved_page_packet[BEACON_PG * 128];
 671        SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
 672        SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
 673
 674        /*-------------------------------------------------------
 675                                (2) ps-poll
 676        --------------------------------------------------------
 677        */
 678        p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
 679        SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
 680        SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
 681        SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
 682
 683        SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PSPOLL_PG);
 684
 685        /*--------------------------------------------------------
 686                                (3) null data
 687        ---------------------------------------------------------i
 688        */
 689        nullfunc = &reserved_page_packet[NULL_PG * 128];
 690        SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
 691        SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
 692        SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
 693
 694        SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1RsvdPageLoc, NULL_PG);
 695
 696        /*---------------------------------------------------------
 697                                (4) probe response
 698        ----------------------------------------------------------
 699        */
 700        p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
 701        SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
 702        SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
 703        SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
 704
 705        SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1RsvdPageLoc, PROBERSP_PG);
 706
 707        totalpacketlen = TOTAL_RESERVED_PKT_LEN;
 708
 709        RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
 710                      "rtl8723ae_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
 711                      &reserved_page_packet[0], totalpacketlen);
 712        RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
 713                      "rtl8723ae_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
 714                      u1RsvdPageLoc, 3);
 715
 716        skb = dev_alloc_skb(totalpacketlen);
 717        memcpy((u8 *) skb_put(skb, totalpacketlen),
 718               &reserved_page_packet, totalpacketlen);
 719
 720        rtstatus = _rtl8723ae_cmd_send_packet(hw, skb);
 721
 722        if (rtstatus)
 723                dlok = true;
 724
 725        if (dlok) {
 726                RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
 727                         "Set RSVD page location to Fw.\n");
 728                RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
 729                                "H2C_RSVDPAGE:\n",
 730                                u1RsvdPageLoc, 3);
 731                rtl8723ae_fill_h2c_cmd(hw, H2C_RSVDPAGE,
 732                                       sizeof(u1RsvdPageLoc), u1RsvdPageLoc);
 733        } else
 734                RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
 735                         "Set RSVD page location to Fw FAIL!!!!!!.\n");
 736}
 737
 738void rtl8723ae_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
 739{
 740        u8 u1_joinbssrpt_parm[1] = { 0 };
 741
 742        SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
 743
 744        rtl8723ae_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm);
 745}
 746
 747static void rtl8723e_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw,
 748                                            u8 ctwindow)
 749{
 750        u8 u1_ctwindow_period[1] = {ctwindow};
 751
 752        rtl8723ae_fill_h2c_cmd(hw, H2C_P2P_PS_CTW_CMD, 1, u1_ctwindow_period);
 753}
 754
 755void rtl8723ae_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
 756{
 757        struct rtl_priv *rtlpriv = rtl_priv(hw);
 758        struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
 759        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 760        struct rtl_p2p_ps_info *p2pinfo = &(rtlps->p2p_ps_info);
 761        struct p2p_ps_offload_t *p2p_ps_offload = &rtlhal->p2p_ps_offload;
 762        u8      i;
 763        u16     ctwindow;
 764        u32     start_time, tsf_low;
 765
 766        switch (p2p_ps_state) {
 767        case P2P_PS_DISABLE:
 768                RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_DISABLE\n");
 769                memset(p2p_ps_offload, 0, sizeof(struct p2p_ps_offload_t));
 770                break;
 771        case P2P_PS_ENABLE:
 772                RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_ENABLE\n");
 773                /* update CTWindow value. */
 774                if (p2pinfo->ctwindow > 0) {
 775                        p2p_ps_offload->ctwindow_en = 1;
 776                        ctwindow = p2pinfo->ctwindow;
 777                        rtl8723e_set_p2p_ctw_period_cmd(hw, ctwindow);
 778                }
 779
 780                /* hw only support 2 set of NoA */
 781                for (i = 0; i < p2pinfo->noa_num; i++) {
 782                        /* To control the register setting for which NOA*/
 783                        rtl_write_byte(rtlpriv, 0x5cf, (i << 4));
 784                        if (i == 0)
 785                                p2p_ps_offload->noa0_en = 1;
 786                        else
 787                                p2p_ps_offload->noa1_en = 1;
 788
 789                        /* config P2P NoA Descriptor Register */
 790                        rtl_write_dword(rtlpriv, 0x5E0,
 791                                        p2pinfo->noa_duration[i]);
 792                        rtl_write_dword(rtlpriv, 0x5E4,
 793                                        p2pinfo->noa_interval[i]);
 794
 795                        /*Get Current TSF value */
 796                        tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
 797
 798                        start_time = p2pinfo->noa_start_time[i];
 799                        if (p2pinfo->noa_count_type[i] != 1) {
 800                                while (start_time <= (tsf_low+(50*1024))) {
 801                                        start_time += p2pinfo->noa_interval[i];
 802                                        if (p2pinfo->noa_count_type[i] != 255)
 803                                                p2pinfo->noa_count_type[i]--;
 804                                }
 805                        }
 806                        rtl_write_dword(rtlpriv, 0x5E8, start_time);
 807                        rtl_write_dword(rtlpriv, 0x5EC,
 808                                        p2pinfo->noa_count_type[i]);
 809                }
 810                if ((p2pinfo->opp_ps == 1) || (p2pinfo->noa_num > 0)) {
 811                        /* rst p2p circuit */
 812                        rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, BIT(4));
 813
 814                        p2p_ps_offload->offload_en = 1;
 815
 816                        if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) {
 817                                p2p_ps_offload->role = 1;
 818                                p2p_ps_offload->allstasleep = 0;
 819                        } else {
 820                                p2p_ps_offload->role = 0;
 821                        }
 822                        p2p_ps_offload->discovery = 0;
 823                }
 824                break;
 825        case P2P_PS_SCAN:
 826                RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN\n");
 827                p2p_ps_offload->discovery = 1;
 828                break;
 829        case P2P_PS_SCAN_DONE:
 830                RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN_DONE\n");
 831                p2p_ps_offload->discovery = 0;
 832                p2pinfo->p2p_ps_state = P2P_PS_ENABLE;
 833                break;
 834        default:
 835                break;
 836        }
 837        rtl8723ae_fill_h2c_cmd(hw, H2C_P2P_PS_OFFLOAD, 1, (u8 *)p2p_ps_offload);
 838}
 839