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