linux/drivers/net/wireless/rtlwifi/rtl8192ee/fw.c
<<
>>
Prefs
   1/******************************************************************************
   2 *
   3 * Copyright(c) 2009-2014  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#include "dm.h"
  34
  35static void _rtl92ee_enable_fw_download(struct ieee80211_hw *hw, bool enable)
  36{
  37        struct rtl_priv *rtlpriv = rtl_priv(hw);
  38        u8 tmp;
  39
  40        if (enable) {
  41                rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x05);
  42
  43                tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);
  44                rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);
  45        } else {
  46                tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
  47                rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);
  48        }
  49}
  50
  51static void _rtl92ee_fw_block_write(struct ieee80211_hw *hw,
  52                                    const u8 *buffer, u32 size)
  53{
  54        struct rtl_priv *rtlpriv = rtl_priv(hw);
  55        u32 blocksize = sizeof(u32);
  56        u8 *bufferptr = (u8 *)buffer;
  57        u32 *pu4byteptr = (u32 *)buffer;
  58        u32 i, offset, blockcount, remainsize;
  59
  60        blockcount = size / blocksize;
  61        remainsize = size % blocksize;
  62
  63        for (i = 0; i < blockcount; i++) {
  64                offset = i * blocksize;
  65                rtl_write_dword(rtlpriv, (FW_8192C_START_ADDRESS + offset),
  66                                *(pu4byteptr + i));
  67        }
  68
  69        if (remainsize) {
  70                offset = blockcount * blocksize;
  71                bufferptr += offset;
  72                for (i = 0; i < remainsize; i++) {
  73                        rtl_write_byte(rtlpriv,
  74                                       (FW_8192C_START_ADDRESS + offset + i),
  75                                       *(bufferptr + i));
  76                }
  77        }
  78}
  79
  80static void _rtl92ee_fw_page_write(struct ieee80211_hw *hw, u32 page,
  81                                   const u8 *buffer, u32 size)
  82{
  83        struct rtl_priv *rtlpriv = rtl_priv(hw);
  84        u8 value8;
  85        u8 u8page = (u8)(page & 0x07);
  86
  87        value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page;
  88        rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8);
  89
  90        _rtl92ee_fw_block_write(hw, buffer, size);
  91}
  92
  93static void _rtl92ee_fill_dummy(u8 *pfwbuf, u32 *pfwlen)
  94{
  95        u32 fwlen = *pfwlen;
  96        u8 remain = (u8)(fwlen % 4);
  97
  98        remain = (remain == 0) ? 0 : (4 - remain);
  99
 100        while (remain > 0) {
 101                pfwbuf[fwlen] = 0;
 102                fwlen++;
 103                remain--;
 104        }
 105
 106        *pfwlen = fwlen;
 107}
 108
 109static void _rtl92ee_write_fw(struct ieee80211_hw *hw,
 110                              enum version_8192e version,
 111                              u8 *buffer, u32 size)
 112{
 113        struct rtl_priv *rtlpriv = rtl_priv(hw);
 114        u8 *bufferptr = (u8 *)buffer;
 115        u32 pagenums, remainsize;
 116        u32 page, offset;
 117
 118        RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD , "FW size is %d bytes,\n", size);
 119
 120        _rtl92ee_fill_dummy(bufferptr, &size);
 121
 122        pagenums = size / FW_8192C_PAGE_SIZE;
 123        remainsize = size % FW_8192C_PAGE_SIZE;
 124
 125        if (pagenums > 8) {
 126                RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 127                         "Page numbers should not greater then 8\n");
 128        }
 129
 130        for (page = 0; page < pagenums; page++) {
 131                offset = page * FW_8192C_PAGE_SIZE;
 132                _rtl92ee_fw_page_write(hw, page, (bufferptr + offset),
 133                                       FW_8192C_PAGE_SIZE);
 134                udelay(2);
 135        }
 136
 137        if (remainsize) {
 138                offset = pagenums * FW_8192C_PAGE_SIZE;
 139                page = pagenums;
 140                _rtl92ee_fw_page_write(hw, page, (bufferptr + offset),
 141                                       remainsize);
 142        }
 143}
 144
 145static int _rtl92ee_fw_free_to_go(struct ieee80211_hw *hw)
 146{
 147        struct rtl_priv *rtlpriv = rtl_priv(hw);
 148        int err = -EIO;
 149        u32 counter = 0;
 150        u32 value32;
 151
 152        do {
 153                value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
 154        } while ((counter++ < FW_8192C_POLLING_TIMEOUT_COUNT) &&
 155                 (!(value32 & FWDL_CHKSUM_RPT)));
 156
 157        if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) {
 158                RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 159                         "chksum report faill ! REG_MCUFWDL:0x%08x .\n",
 160                          value32);
 161                goto exit;
 162        }
 163
 164        RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
 165                 "Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32);
 166
 167        value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
 168        value32 |= MCUFWDL_RDY;
 169        value32 &= ~WINTINI_RDY;
 170        rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
 171
 172        rtl92ee_firmware_selfreset(hw);
 173        counter = 0;
 174
 175        do {
 176                value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
 177                if (value32 & WINTINI_RDY) {
 178                        RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD ,
 179                                 "Polling FW ready success!! REG_MCUFWDL:0x%08x. count = %d\n",
 180                                 value32, counter);
 181                        err = 0;
 182                        goto exit;
 183                }
 184
 185                udelay(FW_8192C_POLLING_DELAY*10);
 186
 187        } while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT);
 188
 189        RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 190                 "Polling FW ready fail!! REG_MCUFWDL:0x%08x. count = %d\n",
 191                 value32, counter);
 192
 193exit:
 194        return err;
 195}
 196
 197int rtl92ee_download_fw(struct ieee80211_hw *hw, bool buse_wake_on_wlan_fw)
 198{
 199        struct rtl_priv *rtlpriv = rtl_priv(hw);
 200        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 201        struct rtl92c_firmware_header *pfwheader;
 202        u8 *pfwdata;
 203        u32 fwsize;
 204        int err;
 205        enum version_8192e version = rtlhal->version;
 206
 207        if (!rtlhal->pfirmware)
 208                return 1;
 209
 210        pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware;
 211        rtlhal->fw_version = pfwheader->version;
 212        rtlhal->fw_subversion = pfwheader->subversion;
 213        pfwdata = (u8 *)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 rtl92c_firmware_header));
 223
 224                pfwdata = pfwdata + sizeof(struct rtl92c_firmware_header);
 225                fwsize = fwsize - sizeof(struct rtl92c_firmware_header);
 226        } else {
 227                RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
 228                         "Firmware no Header, Signature(%#x)\n",
 229                          pfwheader->signature);
 230        }
 231
 232        if (rtlhal->mac_func_enable) {
 233                if (rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) {
 234                        rtl_write_byte(rtlpriv, REG_MCUFWDL, 0);
 235                        rtl92ee_firmware_selfreset(hw);
 236                }
 237        }
 238        _rtl92ee_enable_fw_download(hw, true);
 239        _rtl92ee_write_fw(hw, version, pfwdata, fwsize);
 240        _rtl92ee_enable_fw_download(hw, false);
 241
 242        err = _rtl92ee_fw_free_to_go(hw);
 243        if (err) {
 244                RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 245                         "Firmware is not ready to run!\n");
 246        } else {
 247                RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD ,
 248                         "Firmware is ready to run!\n");
 249        }
 250
 251        return 0;
 252}
 253
 254static bool _rtl92ee_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
 255{
 256        struct rtl_priv *rtlpriv = rtl_priv(hw);
 257        u8 val_hmetfr;
 258        bool result = false;
 259
 260        val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
 261        if (((val_hmetfr >> boxnum) & BIT(0)) == 0)
 262                result = true;
 263        return result;
 264}
 265
 266static void _rtl92ee_fill_h2c_command(struct ieee80211_hw *hw, u8 element_id,
 267                                      u32 cmd_len, u8 *cmdbuffer)
 268{
 269        struct rtl_priv *rtlpriv = rtl_priv(hw);
 270        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 271        struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
 272        u8 boxnum;
 273        u16 box_reg = 0, box_extreg = 0;
 274        u8 u1b_tmp;
 275        bool isfw_read = false;
 276        u8 buf_index = 0;
 277        bool bwrite_sucess = false;
 278        u8 wait_h2c_limmit = 100;
 279        u8 boxcontent[4], boxextcontent[4];
 280        u32 h2c_waitcounter = 0;
 281        unsigned long flag;
 282        u8 idx;
 283
 284        if (ppsc->dot11_psmode != EACTIVE ||
 285            ppsc->inactive_pwrstate == ERFOFF) {
 286                RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD ,
 287                         "FillH2CCommand8192E(): Return because RF is off!!!\n");
 288                return;
 289        }
 290
 291        RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD , "come in\n");
 292
 293        /* 1. Prevent race condition in setting H2C cmd.
 294         * (copy from MgntActSet_RF_State().)
 295         */
 296        while (true) {
 297                spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
 298                if (rtlhal->h2c_setinprogress) {
 299                        RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD ,
 300                                 "H2C set in progress! Wait to set..element_id(%d).\n",
 301                                  element_id);
 302
 303                        while (rtlhal->h2c_setinprogress) {
 304                                spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
 305                                                       flag);
 306                                h2c_waitcounter++;
 307                                RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD ,
 308                                         "Wait 100 us (%d times)...\n",
 309                                          h2c_waitcounter);
 310                                udelay(100);
 311
 312                                if (h2c_waitcounter > 1000)
 313                                        return;
 314                                spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
 315                                                  flag);
 316                        }
 317                        spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
 318                } else {
 319                        rtlhal->h2c_setinprogress = true;
 320                        spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
 321                        break;
 322                }
 323        }
 324
 325        while (!bwrite_sucess) {
 326                /* 2. Find the last BOX number which has been writen. */
 327                boxnum = rtlhal->last_hmeboxnum;
 328                switch (boxnum) {
 329                case 0:
 330                        box_reg = REG_HMEBOX_0;
 331                        box_extreg = REG_HMEBOX_EXT_0;
 332                        break;
 333                case 1:
 334                        box_reg = REG_HMEBOX_1;
 335                        box_extreg = REG_HMEBOX_EXT_1;
 336                        break;
 337                case 2:
 338                        box_reg = REG_HMEBOX_2;
 339                        box_extreg = REG_HMEBOX_EXT_2;
 340                        break;
 341                case 3:
 342                        box_reg = REG_HMEBOX_3;
 343                        box_extreg = REG_HMEBOX_EXT_3;
 344                        break;
 345                default:
 346                        RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
 347                                 "switch case not process\n");
 348                        break;
 349                }
 350
 351                /* 3. Check if the box content is empty. */
 352                isfw_read = false;
 353                u1b_tmp = rtl_read_byte(rtlpriv, REG_CR);
 354
 355                if (u1b_tmp != 0xea) {
 356                        isfw_read = true;
 357                } else {
 358                        if (rtl_read_byte(rtlpriv, REG_TXDMA_STATUS) == 0xea ||
 359                            rtl_read_byte(rtlpriv, REG_TXPKT_EMPTY) == 0xea)
 360                                rtl_write_byte(rtlpriv, REG_SYS_CFG1 + 3, 0xff);
 361                }
 362
 363                if (isfw_read) {
 364                        wait_h2c_limmit = 100;
 365                        isfw_read = _rtl92ee_check_fw_read_last_h2c(hw, boxnum);
 366                        while (!isfw_read) {
 367                                wait_h2c_limmit--;
 368                                if (wait_h2c_limmit == 0) {
 369                                        RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD ,
 370                                                 "Waiting too long for FW read clear HMEBox(%d)!!!\n",
 371                                                 boxnum);
 372                                        break;
 373                                }
 374                                udelay(10);
 375                                isfw_read =
 376                                  _rtl92ee_check_fw_read_last_h2c(hw, boxnum);
 377                                u1b_tmp = rtl_read_byte(rtlpriv, 0x130);
 378                                RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD ,
 379                                         "Waiting for FW read clear HMEBox(%d)!!! 0x130 = %2x\n",
 380                                         boxnum, u1b_tmp);
 381                        }
 382                }
 383
 384                /* If Fw has not read the last
 385                 * H2C cmd, break and give up this H2C.
 386                 */
 387                if (!isfw_read) {
 388                        RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD ,
 389                                 "Write H2C reg BOX[%d] fail,Fw don't read.\n",
 390                                 boxnum);
 391                        break;
 392                }
 393                /* 4. Fill the H2C cmd into box */
 394                memset(boxcontent, 0, sizeof(boxcontent));
 395                memset(boxextcontent, 0, sizeof(boxextcontent));
 396                boxcontent[0] = element_id;
 397                RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD ,
 398                         "Write element_id box_reg(%4x) = %2x\n",
 399                          box_reg, element_id);
 400
 401                switch (cmd_len) {
 402                case 1:
 403                case 2:
 404                case 3:
 405                        /*boxcontent[0] &= ~(BIT(7));*/
 406                        memcpy((u8 *)(boxcontent) + 1,
 407                               cmdbuffer + buf_index, cmd_len);
 408
 409                        for (idx = 0; idx < 4; idx++) {
 410                                rtl_write_byte(rtlpriv, box_reg + idx,
 411                                               boxcontent[idx]);
 412                        }
 413                        break;
 414                case 4:
 415                case 5:
 416                case 6:
 417                case 7:
 418                        /*boxcontent[0] |= (BIT(7));*/
 419                        memcpy((u8 *)(boxextcontent),
 420                               cmdbuffer + buf_index+3, cmd_len-3);
 421                        memcpy((u8 *)(boxcontent) + 1,
 422                               cmdbuffer + buf_index, 3);
 423
 424                        for (idx = 0; idx < 4; idx++) {
 425                                rtl_write_byte(rtlpriv, box_extreg + idx,
 426                                               boxextcontent[idx]);
 427                        }
 428
 429                        for (idx = 0; idx < 4; idx++) {
 430                                rtl_write_byte(rtlpriv, box_reg + idx,
 431                                               boxcontent[idx]);
 432                        }
 433                        break;
 434                default:
 435                        RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
 436                                 "switch case not process\n");
 437                        break;
 438                }
 439
 440                bwrite_sucess = true;
 441
 442                rtlhal->last_hmeboxnum = boxnum + 1;
 443                if (rtlhal->last_hmeboxnum == 4)
 444                        rtlhal->last_hmeboxnum = 0;
 445
 446                RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD ,
 447                         "pHalData->last_hmeboxnum  = %d\n",
 448                          rtlhal->last_hmeboxnum);
 449        }
 450
 451        spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
 452        rtlhal->h2c_setinprogress = false;
 453        spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
 454
 455        RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD , "go out\n");
 456}
 457
 458void rtl92ee_fill_h2c_cmd(struct ieee80211_hw *hw,
 459                          u8 element_id, u32 cmd_len, u8 *cmdbuffer)
 460{
 461        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 462        u32 tmp_cmdbuf[2];
 463
 464        if (!rtlhal->fw_ready) {
 465                RT_ASSERT(false,
 466                          "return H2C cmd because of Fw download fail!!!\n");
 467                return;
 468        }
 469
 470        memset(tmp_cmdbuf, 0, 8);
 471        memcpy(tmp_cmdbuf, cmdbuffer, cmd_len);
 472        _rtl92ee_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
 473}
 474
 475void rtl92ee_firmware_selfreset(struct ieee80211_hw *hw)
 476{
 477        u8 u1b_tmp;
 478        struct rtl_priv *rtlpriv = rtl_priv(hw);
 479
 480        u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1);
 481        rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, (u1b_tmp & (~BIT(0))));
 482
 483        u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
 484        rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, (u1b_tmp & (~BIT(2))));
 485
 486        udelay(50);
 487
 488        u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1);
 489        rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, (u1b_tmp | BIT(0)));
 490
 491        u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
 492        rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, (u1b_tmp | BIT(2)));
 493
 494        RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD ,
 495                 "  _8051Reset92E(): 8051 reset success .\n");
 496}
 497
 498void rtl92ee_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
 499{
 500        struct rtl_priv *rtlpriv = rtl_priv(hw);
 501        u8 u1_h2c_set_pwrmode[H2C_92E_PWEMODE_LENGTH] = { 0 };
 502        struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
 503        u8 rlbm , power_state = 0;
 504
 505        RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD , "FW LPS mode = %d\n", mode);
 506
 507        SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, ((mode) ? 1 : 0));
 508        rlbm = 0;/*YJ,temp,120316. FW now not support RLBM=2.*/
 509        SET_H2CCMD_PWRMODE_PARM_RLBM(u1_h2c_set_pwrmode, rlbm);
 510        SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode,
 511                                         (rtlpriv->mac80211.p2p) ?
 512                                         ppsc->smart_ps : 1);
 513        SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(u1_h2c_set_pwrmode,
 514                                               ppsc->reg_max_lps_awakeintvl);
 515        SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(u1_h2c_set_pwrmode, 0);
 516        if (mode == FW_PS_ACTIVE_MODE)
 517                power_state |= FW_PWR_STATE_ACTIVE;
 518        else
 519                power_state |= FW_PWR_STATE_RF_OFF;
 520        SET_H2CCMD_PWRMODE_PARM_PWR_STATE(u1_h2c_set_pwrmode, power_state);
 521
 522        RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
 523                      "rtl92c_set_fw_pwrmode(): u1_h2c_set_pwrmode\n",
 524                      u1_h2c_set_pwrmode, H2C_92E_PWEMODE_LENGTH);
 525        rtl92ee_fill_h2c_cmd(hw, H2C_92E_SETPWRMODE, H2C_92E_PWEMODE_LENGTH,
 526                             u1_h2c_set_pwrmode);
 527}
 528
 529void rtl92ee_set_fw_media_status_rpt_cmd(struct ieee80211_hw *hw, u8 mstatus)
 530{
 531        u8 parm[3] = { 0 , 0 , 0 };
 532        /* parm[0]: bit0=0-->Disconnect, bit0=1-->Connect
 533         *          bit1=0-->update Media Status to MACID
 534         *          bit1=1-->update Media Status from MACID to MACID_End
 535         * parm[1]: MACID, if this is INFRA_STA, MacID = 0
 536         * parm[2]: MACID_End
 537         */
 538
 539        SET_H2CCMD_MSRRPT_PARM_OPMODE(parm, mstatus);
 540        SET_H2CCMD_MSRRPT_PARM_MACID_IND(parm, 0);
 541
 542        rtl92ee_fill_h2c_cmd(hw, H2C_92E_MSRRPT, 3, parm);
 543}
 544
 545#define BEACON_PG               0 /* ->1 */
 546#define PSPOLL_PG               2
 547#define NULL_PG                 3
 548#define PROBERSP_PG             4 /* ->5 */
 549
 550#define TOTAL_RESERVED_PKT_LEN  768
 551
 552static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
 553        /* page 0 beacon */
 554        0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
 555        0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x02, 0xB1, 0x78,
 556        0xEC, 0x1A, 0x59, 0x0B, 0xAD, 0xD4, 0x20, 0x00,
 557        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 558        0x64, 0x00, 0x10, 0x04, 0x00, 0x05, 0x54, 0x65,
 559        0x73, 0x74, 0x32, 0x01, 0x08, 0x82, 0x84, 0x0B,
 560        0x16, 0x24, 0x30, 0x48, 0x6C, 0x03, 0x01, 0x06,
 561        0x06, 0x02, 0x00, 0x00, 0x2A, 0x01, 0x02, 0x32,
 562        0x04, 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C,
 563        0x09, 0x03, 0xFF, 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, 0x3D, 0x00, 0xDD, 0x07, 0x00, 0xE0, 0x4C,
 567        0x02, 0x02, 0x00, 0x00, 0xDD, 0x18, 0x00, 0x50,
 568        0xF2, 0x01, 0x01, 0x00, 0x00, 0x50, 0xF2, 0x04,
 569        0x01, 0x00, 0x00, 0x50, 0xF2, 0x04, 0x01, 0x00,
 570
 571        /* page 1 beacon */
 572        0x00, 0x50, 0xF2, 0x02, 0x00, 0x00, 0x00, 0x00,
 573        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 574        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 575        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 576        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 577        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 578        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 579        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 580        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 581        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 582        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 583        0x10, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00,
 584        0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 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
 589        /* page 2  ps-poll */
 590        0xA4, 0x10, 0x01, 0xC0, 0xEC, 0x1A, 0x59, 0x0B,
 591        0xAD, 0xD4, 0x00, 0xE0, 0x4C, 0x02, 0xB1, 0x78,
 592        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 593        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 594        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 595        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 596        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 597        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 598        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 599        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 600        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 601        0x18, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00,
 602        0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
 603        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 604        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 605        0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 606
 607        /* page 3  null */
 608        0x48, 0x01, 0x00, 0x00, 0xEC, 0x1A, 0x59, 0x0B,
 609        0xAD, 0xD4, 0x00, 0xE0, 0x4C, 0x02, 0xB1, 0x78,
 610        0xEC, 0x1A, 0x59, 0x0B, 0xAD, 0xD4, 0x00, 0x00,
 611        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 612        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 613        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 614        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 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        0x72, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00,
 620        0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
 621        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 622        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 623        0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 624
 625        /* page 4  probe_resp */
 626        0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
 627        0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
 628        0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
 629        0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
 630        0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
 631        0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
 632        0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
 633        0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
 634        0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
 635        0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
 636        0x03, 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        0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
 640        0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 641        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 642
 643        /* page 5  probe_resp */
 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        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 650        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 651        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 652        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 653        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 654        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 655        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 656        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 657        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 658        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 659        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 660};
 661
 662void rtl92ee_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished)
 663{
 664        struct rtl_priv *rtlpriv = rtl_priv(hw);
 665        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 666        struct sk_buff *skb = NULL;
 667
 668        u32 totalpacketlen;
 669        bool rtstatus;
 670        u8 u1rsvdpageloc[5] = { 0 };
 671        bool b_dlok = false;
 672
 673        u8 *beacon;
 674        u8 *p_pspoll;
 675        u8 *nullfunc;
 676        u8 *p_probersp;
 677        /*---------------------------------------------------------
 678         *                      (1) beacon
 679         *---------------------------------------------------------
 680         */
 681        beacon = &reserved_page_packet[BEACON_PG * 128];
 682        SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
 683        SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
 684
 685        /*-------------------------------------------------------
 686         *                      (2) ps-poll
 687         *--------------------------------------------------------
 688         */
 689        p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
 690        SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
 691        SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
 692        SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
 693
 694        SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1rsvdpageloc, PSPOLL_PG);
 695
 696        /*--------------------------------------------------------
 697         *                      (3) null data
 698         *---------------------------------------------------------
 699         */
 700        nullfunc = &reserved_page_packet[NULL_PG * 128];
 701        SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
 702        SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
 703        SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
 704
 705        SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1rsvdpageloc, NULL_PG);
 706
 707        /*---------------------------------------------------------
 708         *                      (4) probe response
 709         *----------------------------------------------------------
 710         */
 711        p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
 712        SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
 713        SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
 714        SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
 715
 716        SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1rsvdpageloc, PROBERSP_PG);
 717
 718        totalpacketlen = TOTAL_RESERVED_PKT_LEN;
 719
 720        RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD ,
 721                      "rtl92ee_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
 722                      &reserved_page_packet[0], totalpacketlen);
 723        RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD ,
 724                      "rtl92ee_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
 725                      u1rsvdpageloc, 3);
 726
 727        skb = dev_alloc_skb(totalpacketlen);
 728        memcpy((u8 *)skb_put(skb, totalpacketlen),
 729               &reserved_page_packet, totalpacketlen);
 730
 731        rtstatus = rtl_cmd_send_packet(hw, skb);
 732
 733        if (rtstatus)
 734                b_dlok = true;
 735
 736        if (b_dlok) {
 737                RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD ,
 738                         "Set RSVD page location to Fw.\n");
 739                RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD ,
 740                              "H2C_RSVDPAGE:\n", u1rsvdpageloc, 3);
 741                rtl92ee_fill_h2c_cmd(hw, H2C_92E_RSVDPAGE,
 742                                     sizeof(u1rsvdpageloc), u1rsvdpageloc);
 743        } else {
 744                RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
 745                         "Set RSVD page location to Fw FAIL!!!!!!.\n");
 746        }
 747}
 748
 749/*Shoud check FW support p2p or not.*/
 750static void rtl92ee_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw, u8 ctwindow)
 751{
 752        u8 u1_ctwindow_period[1] = {ctwindow};
 753
 754        rtl92ee_fill_h2c_cmd(hw, H2C_92E_P2P_PS_CTW_CMD, 1, u1_ctwindow_period);
 755}
 756
 757void rtl92ee_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
 758{
 759        struct rtl_priv *rtlpriv = rtl_priv(hw);
 760        struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
 761        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 762        struct rtl_p2p_ps_info *p2pinfo = &rtlps->p2p_ps_info;
 763        struct p2p_ps_offload_t *p2p_ps_offload = &rtlhal->p2p_ps_offload;
 764        u8 i;
 765        u16 ctwindow;
 766        u32 start_time, tsf_low;
 767
 768        switch (p2p_ps_state) {
 769        case P2P_PS_DISABLE:
 770                RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD , "P2P_PS_DISABLE\n");
 771                memset(p2p_ps_offload, 0, sizeof(*p2p_ps_offload));
 772                break;
 773        case P2P_PS_ENABLE:
 774                RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD , "P2P_PS_ENABLE\n");
 775                /* update CTWindow value. */
 776                if (p2pinfo->ctwindow > 0) {
 777                        p2p_ps_offload->ctwindow_en = 1;
 778                        ctwindow = p2pinfo->ctwindow;
 779                        rtl92ee_set_p2p_ctw_period_cmd(hw, ctwindow);
 780                }
 781                /* hw only support 2 set of NoA */
 782                for (i = 0 ; i < p2pinfo->noa_num ; i++) {
 783                        /* To control the register setting for which NOA*/
 784                        rtl_write_byte(rtlpriv, 0x5cf, (i << 4));
 785                        if (i == 0)
 786                                p2p_ps_offload->noa0_en = 1;
 787                        else
 788                                p2p_ps_offload->noa1_en = 1;
 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                        p2p_ps_offload->offload_en = 1;
 814
 815                        if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) {
 816                                p2p_ps_offload->role = 1;
 817                                p2p_ps_offload->allstasleep = 0;
 818                        } else {
 819                                p2p_ps_offload->role = 0;
 820                        }
 821                        p2p_ps_offload->discovery = 0;
 822                }
 823                break;
 824        case P2P_PS_SCAN:
 825                RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD , "P2P_PS_SCAN\n");
 826                p2p_ps_offload->discovery = 1;
 827                break;
 828        case P2P_PS_SCAN_DONE:
 829                RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD , "P2P_PS_SCAN_DONE\n");
 830                p2p_ps_offload->discovery = 0;
 831                p2pinfo->p2p_ps_state = P2P_PS_ENABLE;
 832                break;
 833        default:
 834                break;
 835        }
 836        rtl92ee_fill_h2c_cmd(hw, H2C_92E_P2P_PS_OFFLOAD, 1,
 837                             (u8 *)p2p_ps_offload);
 838}
 839
 840static void _rtl92ee_c2h_ra_report_handler(struct ieee80211_hw *hw,
 841                                           u8 *cmd_buf, u8 cmd_len)
 842{
 843        u8 rate = cmd_buf[0] & 0x3F;
 844        bool collision_state = cmd_buf[3] & BIT(0);
 845
 846        rtl92ee_dm_dynamic_arfb_select(hw, rate, collision_state);
 847}
 848
 849static void _rtl92ee_c2h_content_parsing(struct ieee80211_hw *hw, u8 c2h_cmd_id,
 850                                         u8 c2h_cmd_len, u8 *tmp_buf)
 851{
 852        struct rtl_priv *rtlpriv = rtl_priv(hw);
 853
 854        switch (c2h_cmd_id) {
 855        case C2H_8192E_DBG:
 856                RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
 857                         "[C2H], C2H_8723BE_DBG!!\n");
 858                break;
 859        case C2H_8192E_TXBF:
 860                RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
 861                         "[C2H], C2H_8192E_TXBF!!\n");
 862                break;
 863        case C2H_8192E_TX_REPORT:
 864                RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE ,
 865                         "[C2H], C2H_8723BE_TX_REPORT!\n");
 866                break;
 867        case C2H_8192E_BT_INFO:
 868                RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
 869                         "[C2H], C2H_8723BE_BT_INFO!!\n");
 870                rtlpriv->btcoexist.btc_ops->btc_btinfo_notify(rtlpriv, tmp_buf,
 871                                                              c2h_cmd_len);
 872                break;
 873        case C2H_8192E_BT_MP:
 874                RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
 875                         "[C2H], C2H_8723BE_BT_MP!!\n");
 876                break;
 877        case C2H_8192E_RA_RPT:
 878                _rtl92ee_c2h_ra_report_handler(hw, tmp_buf, c2h_cmd_len);
 879                break;
 880        default:
 881                RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
 882                         "[C2H], Unkown packet!! CmdId(%#X)!\n", c2h_cmd_id);
 883                break;
 884        }
 885}
 886
 887void rtl92ee_c2h_packet_handler(struct ieee80211_hw *hw, u8 *buffer, u8 len)
 888{
 889        struct rtl_priv *rtlpriv = rtl_priv(hw);
 890        u8 c2h_cmd_id = 0, c2h_cmd_seq = 0, c2h_cmd_len = 0;
 891        u8 *tmp_buf = NULL;
 892
 893        c2h_cmd_id = buffer[0];
 894        c2h_cmd_seq = buffer[1];
 895        c2h_cmd_len = len - 2;
 896        tmp_buf = buffer + 2;
 897
 898        RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
 899                 "[C2H packet], c2hCmdId=0x%x, c2hCmdSeq=0x%x, c2hCmdLen=%d\n",
 900                 c2h_cmd_id, c2h_cmd_seq, c2h_cmd_len);
 901
 902        RT_PRINT_DATA(rtlpriv, COMP_FW, DBG_TRACE,
 903                      "[C2H packet], Content Hex:\n", tmp_buf, c2h_cmd_len);
 904
 905        _rtl92ee_c2h_content_parsing(hw, c2h_cmd_id, c2h_cmd_len, tmp_buf);
 906}
 907