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