linux/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/fw.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/* Copyright(c) 2009-2013  Realtek Corporation.*/
   3
   4#include "../wifi.h"
   5#include "../pci.h"
   6#include "../base.h"
   7#include "../core.h"
   8#include "../efuse.h"
   9#include "reg.h"
  10#include "def.h"
  11#include "fw.h"
  12
  13static void _rtl88e_enable_fw_download(struct ieee80211_hw *hw, bool enable)
  14{
  15        struct rtl_priv *rtlpriv = rtl_priv(hw);
  16        u8 tmp;
  17
  18        if (enable) {
  19                tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
  20                rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmp | 0x04);
  21
  22                tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
  23                rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01);
  24
  25                tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);
  26                rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);
  27        } else {
  28                tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
  29                rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);
  30
  31                rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00);
  32        }
  33}
  34
  35static void _rtl88e_write_fw(struct ieee80211_hw *hw,
  36                             enum version_8188e version, u8 *buffer, u32 size)
  37{
  38        struct rtl_priv *rtlpriv = rtl_priv(hw);
  39        u8 *bufferptr = (u8 *)buffer;
  40        u32 pagenums, remainsize;
  41        u32 page, offset;
  42
  43        RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "FW size is %d bytes,\n", size);
  44
  45        rtl_fill_dummy(bufferptr, &size);
  46
  47        pagenums = size / FW_8192C_PAGE_SIZE;
  48        remainsize = size % FW_8192C_PAGE_SIZE;
  49
  50        if (pagenums > 8)
  51                pr_err("Page numbers should not greater then 8\n");
  52
  53        for (page = 0; page < pagenums; page++) {
  54                offset = page * FW_8192C_PAGE_SIZE;
  55                rtl_fw_page_write(hw, page, (bufferptr + offset),
  56                                  FW_8192C_PAGE_SIZE);
  57        }
  58
  59        if (remainsize) {
  60                offset = pagenums * FW_8192C_PAGE_SIZE;
  61                page = pagenums;
  62                rtl_fw_page_write(hw, page, (bufferptr + offset), remainsize);
  63        }
  64}
  65
  66static int _rtl88e_fw_free_to_go(struct ieee80211_hw *hw)
  67{
  68        struct rtl_priv *rtlpriv = rtl_priv(hw);
  69        int err = -EIO;
  70        u32 counter = 0;
  71        u32 value32;
  72
  73        do {
  74                value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
  75        } while ((counter++ < FW_8192C_POLLING_TIMEOUT_COUNT) &&
  76                 (!(value32 & FWDL_CHKSUM_RPT)));
  77
  78        if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) {
  79                pr_err("chksum report fail! REG_MCUFWDL:0x%08x .\n",
  80                       value32);
  81                goto exit;
  82        }
  83        value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
  84        value32 |= MCUFWDL_RDY;
  85        value32 &= ~WINTINI_RDY;
  86        rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
  87
  88        rtl88e_firmware_selfreset(hw);
  89        counter = 0;
  90
  91        do {
  92                value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
  93                if (value32 & WINTINI_RDY)
  94                        return 0;
  95
  96                udelay(FW_8192C_POLLING_DELAY);
  97
  98        } while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT);
  99
 100        pr_err("Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n",
 101               value32);
 102
 103exit:
 104        return err;
 105}
 106
 107int rtl88e_download_fw(struct ieee80211_hw *hw,
 108                       bool buse_wake_on_wlan_fw)
 109{
 110        struct rtl_priv *rtlpriv = rtl_priv(hw);
 111        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 112        struct rtlwifi_firmware_header *pfwheader;
 113        u8 *pfwdata;
 114        u32 fwsize;
 115        int err;
 116        enum version_8188e version = rtlhal->version;
 117
 118        if (!rtlhal->pfirmware)
 119                return 1;
 120
 121        pfwheader = (struct rtlwifi_firmware_header *)rtlhal->pfirmware;
 122        rtlhal->fw_version = le16_to_cpu(pfwheader->version);
 123        rtlhal->fw_subversion = pfwheader->subversion;
 124        pfwdata = rtlhal->pfirmware;
 125        fwsize = rtlhal->fwsize;
 126        RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
 127                 "normal Firmware SIZE %d\n", fwsize);
 128
 129        if (IS_FW_HEADER_EXIST(pfwheader)) {
 130                RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
 131                         "Firmware Version(%d), Signature(%#x), Size(%d)\n",
 132                          pfwheader->version, pfwheader->signature,
 133                          (int)sizeof(struct rtlwifi_firmware_header));
 134
 135                pfwdata = pfwdata + sizeof(struct rtlwifi_firmware_header);
 136                fwsize = fwsize - sizeof(struct rtlwifi_firmware_header);
 137        }
 138
 139        if (rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) {
 140                rtl_write_byte(rtlpriv, REG_MCUFWDL, 0);
 141                rtl88e_firmware_selfreset(hw);
 142        }
 143        _rtl88e_enable_fw_download(hw, true);
 144        _rtl88e_write_fw(hw, version, pfwdata, fwsize);
 145        _rtl88e_enable_fw_download(hw, false);
 146
 147        err = _rtl88e_fw_free_to_go(hw);
 148        if (err)
 149                pr_err("Firmware is not ready to run!\n");
 150
 151        return 0;
 152}
 153
 154static bool _rtl88e_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
 155{
 156        struct rtl_priv *rtlpriv = rtl_priv(hw);
 157        u8 val_hmetfr;
 158
 159        val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
 160        if (((val_hmetfr >> boxnum) & BIT(0)) == 0)
 161                return true;
 162        return false;
 163}
 164
 165static void _rtl88e_fill_h2c_command(struct ieee80211_hw *hw,
 166                                     u8 element_id, u32 cmd_len,
 167                                     u8 *cmd_b)
 168{
 169        struct rtl_priv *rtlpriv = rtl_priv(hw);
 170        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 171        u8 boxnum;
 172        u16 box_reg = 0, box_extreg = 0;
 173        u8 u1b_tmp;
 174        bool isfw_read = false;
 175        u8 buf_index = 0;
 176        bool write_sucess = false;
 177        u8 wait_h2c_limmit = 100;
 178        u8 wait_writeh2c_limit = 100;
 179        u8 boxcontent[4], boxextcontent[4];
 180        u32 h2c_waitcounter = 0;
 181        unsigned long flag;
 182        u8 idx;
 183
 184        RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "come in\n");
 185
 186        while (true) {
 187                spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
 188                if (rtlhal->h2c_setinprogress) {
 189                        RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
 190                                 "H2C set in progress! Wait to set..element_id(%d).\n",
 191                                 element_id);
 192
 193                        while (rtlhal->h2c_setinprogress) {
 194                                spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
 195                                                       flag);
 196                                h2c_waitcounter++;
 197                                RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
 198                                         "Wait 100 us (%d times)...\n",
 199                                         h2c_waitcounter);
 200                                udelay(100);
 201
 202                                if (h2c_waitcounter > 1000)
 203                                        return;
 204                                spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
 205                                                  flag);
 206                        }
 207                        spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
 208                } else {
 209                        rtlhal->h2c_setinprogress = true;
 210                        spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
 211                        break;
 212                }
 213        }
 214
 215        while (!write_sucess) {
 216                wait_writeh2c_limit--;
 217                if (wait_writeh2c_limit == 0) {
 218                        pr_err("Write H2C fail because no trigger for FW INT!\n");
 219                        break;
 220                }
 221
 222                boxnum = rtlhal->last_hmeboxnum;
 223                switch (boxnum) {
 224                case 0:
 225                        box_reg = REG_HMEBOX_0;
 226                        box_extreg = REG_HMEBOX_EXT_0;
 227                        break;
 228                case 1:
 229                        box_reg = REG_HMEBOX_1;
 230                        box_extreg = REG_HMEBOX_EXT_1;
 231                        break;
 232                case 2:
 233                        box_reg = REG_HMEBOX_2;
 234                        box_extreg = REG_HMEBOX_EXT_2;
 235                        break;
 236                case 3:
 237                        box_reg = REG_HMEBOX_3;
 238                        box_extreg = REG_HMEBOX_EXT_3;
 239                        break;
 240                default:
 241                        RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
 242                                 "switch case %#x not processed\n", boxnum);
 243                        break;
 244                }
 245                isfw_read = _rtl88e_check_fw_read_last_h2c(hw, boxnum);
 246                while (!isfw_read) {
 247                        wait_h2c_limmit--;
 248                        if (wait_h2c_limmit == 0) {
 249                                RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
 250                                         "Waiting too long for FW read clear HMEBox(%d)!\n",
 251                                         boxnum);
 252                                break;
 253                        }
 254
 255                        udelay(10);
 256
 257                        isfw_read = _rtl88e_check_fw_read_last_h2c(hw, boxnum);
 258                        u1b_tmp = rtl_read_byte(rtlpriv, 0x130);
 259                        RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
 260                                 "Waiting for FW read clear HMEBox(%d)!!! 0x130 = %2x\n",
 261                                 boxnum, u1b_tmp);
 262                }
 263
 264                if (!isfw_read) {
 265                        RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
 266                                 "Write H2C register BOX[%d] fail!!!!! Fw do not read.\n",
 267                                 boxnum);
 268                        break;
 269                }
 270
 271                memset(boxcontent, 0, sizeof(boxcontent));
 272                memset(boxextcontent, 0, sizeof(boxextcontent));
 273                boxcontent[0] = element_id;
 274                RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
 275                         "Write element_id box_reg(%4x) = %2x\n",
 276                         box_reg, element_id);
 277
 278                switch (cmd_len) {
 279                case 1:
 280                case 2:
 281                case 3:
 282                        /*boxcontent[0] &= ~(BIT(7));*/
 283                        memcpy((u8 *)(boxcontent) + 1,
 284                               cmd_b + buf_index, cmd_len);
 285
 286                        for (idx = 0; idx < 4; idx++) {
 287                                rtl_write_byte(rtlpriv, box_reg + idx,
 288                                               boxcontent[idx]);
 289                        }
 290                        break;
 291                case 4:
 292                case 5:
 293                case 6:
 294                case 7:
 295                        /*boxcontent[0] |= (BIT(7));*/
 296                        memcpy((u8 *)(boxextcontent),
 297                               cmd_b + buf_index+3, cmd_len-3);
 298                        memcpy((u8 *)(boxcontent) + 1,
 299                               cmd_b + buf_index, 3);
 300
 301                        for (idx = 0; idx < 2; idx++) {
 302                                rtl_write_byte(rtlpriv, box_extreg + idx,
 303                                               boxextcontent[idx]);
 304                        }
 305
 306                        for (idx = 0; idx < 4; idx++) {
 307                                rtl_write_byte(rtlpriv, box_reg + idx,
 308                                               boxcontent[idx]);
 309                        }
 310                        break;
 311                default:
 312                        RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
 313                                 "switch case %#x not processed\n", cmd_len);
 314                        break;
 315                }
 316
 317                write_sucess = true;
 318
 319                rtlhal->last_hmeboxnum = boxnum + 1;
 320                if (rtlhal->last_hmeboxnum == 4)
 321                        rtlhal->last_hmeboxnum = 0;
 322
 323                RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
 324                         "pHalData->last_hmeboxnum  = %d\n",
 325                          rtlhal->last_hmeboxnum);
 326        }
 327
 328        spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
 329        rtlhal->h2c_setinprogress = false;
 330        spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
 331
 332        RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n");
 333}
 334
 335void rtl88e_fill_h2c_cmd(struct ieee80211_hw *hw,
 336                         u8 element_id, u32 cmd_len, u8 *cmdbuffer)
 337{
 338        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 339        u32 tmp_cmdbuf[2];
 340
 341        if (!rtlhal->fw_ready) {
 342                WARN_ONCE(true,
 343                          "rtl8188ee: error H2C cmd because of Fw download fail!!!\n");
 344                return;
 345        }
 346
 347        memset(tmp_cmdbuf, 0, 8);
 348        memcpy(tmp_cmdbuf, cmdbuffer, cmd_len);
 349        _rtl88e_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
 350
 351        return;
 352}
 353
 354void rtl88e_firmware_selfreset(struct ieee80211_hw *hw)
 355{
 356        u8 u1b_tmp;
 357        struct rtl_priv *rtlpriv = rtl_priv(hw);
 358
 359        u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN+1);
 360        rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN+1, (u1b_tmp & (~BIT(2))));
 361        rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN+1, (u1b_tmp | BIT(2)));
 362        RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
 363                 "8051Reset88E(): 8051 reset success\n");
 364
 365}
 366
 367void rtl88e_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
 368{
 369        struct rtl_priv *rtlpriv = rtl_priv(hw);
 370        u8 u1_h2c_set_pwrmode[H2C_88E_PWEMODE_LENGTH] = { 0 };
 371        struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
 372        u8 rlbm, power_state = 0;
 373        RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode);
 374
 375        SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, ((mode) ? 1 : 0));
 376        rlbm = 0;/*YJ, temp, 120316. FW now not support RLBM=2.*/
 377        SET_H2CCMD_PWRMODE_PARM_RLBM(u1_h2c_set_pwrmode, rlbm);
 378        SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode,
 379                (rtlpriv->mac80211.p2p) ? ppsc->smart_ps : 1);
 380        SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(u1_h2c_set_pwrmode,
 381                ppsc->reg_max_lps_awakeintvl);
 382        SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(u1_h2c_set_pwrmode, 0);
 383        if (mode == FW_PS_ACTIVE_MODE)
 384                power_state |= FW_PWR_STATE_ACTIVE;
 385        else
 386                power_state |= FW_PWR_STATE_RF_OFF;
 387
 388        SET_H2CCMD_PWRMODE_PARM_PWR_STATE(u1_h2c_set_pwrmode, power_state);
 389
 390        RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
 391                      "rtl92c_set_fw_pwrmode(): u1_h2c_set_pwrmode\n",
 392                      u1_h2c_set_pwrmode, H2C_88E_PWEMODE_LENGTH);
 393        rtl88e_fill_h2c_cmd(hw, H2C_88E_SETPWRMODE,
 394                            H2C_88E_PWEMODE_LENGTH, u1_h2c_set_pwrmode);
 395}
 396
 397void rtl88e_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
 398{
 399        u8 u1_joinbssrpt_parm[1] = { 0 };
 400
 401        SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
 402
 403        rtl88e_fill_h2c_cmd(hw, H2C_88E_JOINBSSRPT, 1, u1_joinbssrpt_parm);
 404}
 405
 406void rtl88e_set_fw_ap_off_load_cmd(struct ieee80211_hw *hw,
 407                                   u8 ap_offload_enable)
 408{
 409        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 410        u8 u1_apoffload_parm[H2C_88E_AP_OFFLOAD_LENGTH] = { 0 };
 411
 412        SET_H2CCMD_AP_OFFLOAD_ON(u1_apoffload_parm, ap_offload_enable);
 413        SET_H2CCMD_AP_OFFLOAD_HIDDEN(u1_apoffload_parm, mac->hiddenssid);
 414        SET_H2CCMD_AP_OFFLOAD_DENYANY(u1_apoffload_parm, 0);
 415
 416        rtl88e_fill_h2c_cmd(hw, H2C_88E_AP_OFFLOAD,
 417                            H2C_88E_AP_OFFLOAD_LENGTH, u1_apoffload_parm);
 418
 419}
 420
 421#define BEACON_PG               0 /* ->1 */
 422#define PSPOLL_PG               2
 423#define NULL_PG                 3
 424#define PROBERSP_PG             4 /* ->5 */
 425
 426#define TOTAL_RESERVED_PKT_LEN  768
 427
 428static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
 429        /* page 0 beacon */
 430        0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
 431        0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
 432        0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08,
 433        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 434        0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
 435        0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
 436        0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
 437        0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
 438        0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
 439        0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
 440        0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 441        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 442        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 443        0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
 444        0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 445        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 446
 447        /* page 1 beacon */
 448        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 449        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 450        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 451        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 452        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 453        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 454        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 455        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 456        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 457        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 458        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 459        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 460        0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00,
 461        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 462        0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 463        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 464
 465        /* page 2  ps-poll */
 466        0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10,
 467        0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
 468        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 469        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 470        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 471        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 472        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 473        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 474        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 475        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 476        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 477        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 478        0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
 479        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
 480        0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 481        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 482
 483        /* page 3  null */
 484        0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
 485        0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
 486        0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
 487        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 488        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 489        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 490        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 491        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 492        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 493        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 494        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 495        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 496        0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
 497        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
 498        0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 499        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 500
 501        /* page 4  probe_resp */
 502        0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
 503        0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
 504        0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
 505        0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
 506        0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
 507        0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
 508        0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
 509        0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
 510        0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
 511        0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
 512        0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 513        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 514        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 515        0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
 516        0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 517        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 518
 519        /* page 5  probe_resp */
 520        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 521        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 522        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 523        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 524        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 525        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 526        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 527        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 528        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 529        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 530        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 531        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 532        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 533        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 534        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 535        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 536};
 537
 538void rtl88e_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished)
 539{
 540        struct rtl_priv *rtlpriv = rtl_priv(hw);
 541        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 542        struct sk_buff *skb = NULL;
 543        u32 totalpacketlen;
 544        bool rtstatus;
 545        u8 u1rsvdpageloc[5] = { 0 };
 546        bool b_dlok = false;
 547        u8 *beacon;
 548        u8 *p_pspoll;
 549        u8 *nullfunc;
 550        u8 *p_probersp;
 551
 552        /*---------------------------------------------------------
 553         *                      (1) beacon
 554         *---------------------------------------------------------
 555         */
 556        beacon = &reserved_page_packet[BEACON_PG * 128];
 557        SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
 558        SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
 559
 560        /*-------------------------------------------------------
 561         *                      (2) ps-poll
 562         *--------------------------------------------------------
 563         */
 564        p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
 565        SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
 566        SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
 567        SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
 568
 569        SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1rsvdpageloc, PSPOLL_PG);
 570
 571        /*--------------------------------------------------------
 572         *                      (3) null data
 573         *---------------------------------------------------------
 574         */
 575        nullfunc = &reserved_page_packet[NULL_PG * 128];
 576        SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
 577        SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
 578        SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
 579
 580        SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1rsvdpageloc, NULL_PG);
 581
 582        /*---------------------------------------------------------
 583         *                      (4) probe response
 584         *----------------------------------------------------------
 585         */
 586        p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
 587        SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
 588        SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
 589        SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
 590
 591        SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1rsvdpageloc, PROBERSP_PG);
 592
 593        totalpacketlen = TOTAL_RESERVED_PKT_LEN;
 594
 595        RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
 596                      "rtl88e_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
 597                      &reserved_page_packet[0], totalpacketlen);
 598        RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
 599                      "rtl88e_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
 600                      u1rsvdpageloc, 3);
 601
 602        skb = dev_alloc_skb(totalpacketlen);
 603        if (!skb)
 604                return;
 605        skb_put_data(skb, &reserved_page_packet, totalpacketlen);
 606
 607        rtstatus = rtl_cmd_send_packet(hw, skb);
 608
 609        if (rtstatus)
 610                b_dlok = true;
 611
 612        if (b_dlok) {
 613                RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
 614                         "Set RSVD page location to Fw.\n");
 615                RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
 616                              "H2C_RSVDPAGE:\n", u1rsvdpageloc, 3);
 617                rtl88e_fill_h2c_cmd(hw, H2C_88E_RSVDPAGE,
 618                                    sizeof(u1rsvdpageloc), u1rsvdpageloc);
 619        } else
 620                RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
 621                         "Set RSVD page location to Fw FAIL!!!!!!.\n");
 622}
 623
 624/*Should check FW support p2p or not.*/
 625static void rtl88e_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw, u8 ctwindow)
 626{
 627        u8 u1_ctwindow_period[1] = { ctwindow};
 628
 629        rtl88e_fill_h2c_cmd(hw, H2C_88E_P2P_PS_CTW_CMD, 1, u1_ctwindow_period);
 630
 631}
 632
 633void rtl88e_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
 634{
 635        struct rtl_priv *rtlpriv = rtl_priv(hw);
 636        struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
 637        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 638        struct rtl_p2p_ps_info *p2pinfo = &(rtlps->p2p_ps_info);
 639        struct p2p_ps_offload_t *p2p_ps_offload = &rtlhal->p2p_ps_offload;
 640        u8      i;
 641        u16     ctwindow;
 642        u32     start_time, tsf_low;
 643
 644        switch (p2p_ps_state) {
 645        case P2P_PS_DISABLE:
 646                RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_DISABLE\n");
 647                memset(p2p_ps_offload, 0, sizeof(*p2p_ps_offload));
 648                break;
 649        case P2P_PS_ENABLE:
 650                RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_ENABLE\n");
 651                /* update CTWindow value. */
 652                if (p2pinfo->ctwindow > 0) {
 653                        p2p_ps_offload->ctwindow_en = 1;
 654                        ctwindow = p2pinfo->ctwindow;
 655                        rtl88e_set_p2p_ctw_period_cmd(hw, ctwindow);
 656                }
 657
 658                /* hw only support 2 set of NoA */
 659                for (i = 0 ; i < p2pinfo->noa_num; i++) {
 660                        /* To control the register setting for which NOA*/
 661                        rtl_write_byte(rtlpriv, 0x5cf, (i << 4));
 662                        if (i == 0)
 663                                p2p_ps_offload->noa0_en = 1;
 664                        else
 665                                p2p_ps_offload->noa1_en = 1;
 666
 667                        /* config P2P NoA Descriptor Register */
 668                        rtl_write_dword(rtlpriv, 0x5E0,
 669                                        p2pinfo->noa_duration[i]);
 670                        rtl_write_dword(rtlpriv, 0x5E4,
 671                                        p2pinfo->noa_interval[i]);
 672
 673                        /*Get Current TSF value */
 674                        tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
 675
 676                        start_time = p2pinfo->noa_start_time[i];
 677                        if (p2pinfo->noa_count_type[i] != 1) {
 678                                while (start_time <= (tsf_low+(50*1024))) {
 679                                        start_time += p2pinfo->noa_interval[i];
 680                                        if (p2pinfo->noa_count_type[i] != 255)
 681                                                p2pinfo->noa_count_type[i]--;
 682                                }
 683                        }
 684                        rtl_write_dword(rtlpriv, 0x5E8, start_time);
 685                        rtl_write_dword(rtlpriv, 0x5EC,
 686                                        p2pinfo->noa_count_type[i]);
 687                }
 688
 689                if ((p2pinfo->opp_ps == 1) || (p2pinfo->noa_num > 0)) {
 690                        /* rst p2p circuit */
 691                        rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, BIT(4));
 692
 693                        p2p_ps_offload->offload_en = 1;
 694
 695                        if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) {
 696                                p2p_ps_offload->role = 1;
 697                                p2p_ps_offload->allstasleep = -1;
 698                        } else {
 699                                p2p_ps_offload->role = 0;
 700                        }
 701
 702                        p2p_ps_offload->discovery = 0;
 703                }
 704                break;
 705        case P2P_PS_SCAN:
 706                RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN\n");
 707                p2p_ps_offload->discovery = 1;
 708                break;
 709        case P2P_PS_SCAN_DONE:
 710                RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN_DONE\n");
 711                p2p_ps_offload->discovery = 0;
 712                p2pinfo->p2p_ps_state = P2P_PS_ENABLE;
 713                break;
 714        default:
 715                break;
 716        }
 717
 718        rtl88e_fill_h2c_cmd(hw, H2C_88E_P2P_PS_OFFLOAD, 1,
 719                            (u8 *)p2p_ps_offload);
 720
 721}
 722