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