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