Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* Copyright(c) 2009-2012  Realtek Corporation.*/
0003 
0004 #include "../wifi.h"
0005 #include "../pci.h"
0006 #include "../base.h"
0007 #include "../core.h"
0008 #include "../efuse.h"
0009 #include "../rtl8192ce/reg.h"
0010 #include "../rtl8192ce/def.h"
0011 #include "fw_common.h"
0012 #include <linux/export.h>
0013 
0014 static void _rtl92c_enable_fw_download(struct ieee80211_hw *hw, bool enable)
0015 {
0016     struct rtl_priv *rtlpriv = rtl_priv(hw);
0017     struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
0018 
0019     if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CU) {
0020         u32 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
0021 
0022         if (enable)
0023             value32 |= MCUFWDL_EN;
0024         else
0025             value32 &= ~MCUFWDL_EN;
0026         rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
0027     } else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CE) {
0028         u8 tmp;
0029 
0030         if (enable) {
0031             tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
0032             rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1,
0033                        tmp | 0x04);
0034 
0035             tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
0036             rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01);
0037 
0038             tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);
0039             rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);
0040         } else {
0041             tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
0042             rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);
0043 
0044             rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00);
0045         }
0046     }
0047 }
0048 
0049 static void _rtl92c_write_fw(struct ieee80211_hw *hw,
0050                  enum version_8192c version, u8 *buffer, u32 size)
0051 {
0052     struct rtl_priv *rtlpriv = rtl_priv(hw);
0053     struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
0054     bool is_version_b;
0055     u8 *bufferptr = (u8 *)buffer;
0056 
0057     rtl_dbg(rtlpriv, COMP_FW, DBG_TRACE, "FW size is %d bytes,\n", size);
0058     is_version_b = IS_NORMAL_CHIP(version);
0059     if (is_version_b) {
0060         u32 pagenums, remainsize;
0061         u32 page, offset;
0062 
0063         if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CE)
0064             rtl_fill_dummy(bufferptr, &size);
0065 
0066         pagenums = size / FW_8192C_PAGE_SIZE;
0067         remainsize = size % FW_8192C_PAGE_SIZE;
0068 
0069         if (pagenums > 4)
0070             pr_err("Page numbers should not greater then 4\n");
0071 
0072         for (page = 0; page < pagenums; page++) {
0073             offset = page * FW_8192C_PAGE_SIZE;
0074             rtl_fw_page_write(hw, page, (bufferptr + offset),
0075                       FW_8192C_PAGE_SIZE);
0076         }
0077 
0078         if (remainsize) {
0079             offset = pagenums * FW_8192C_PAGE_SIZE;
0080             page = pagenums;
0081             rtl_fw_page_write(hw, page, (bufferptr + offset),
0082                       remainsize);
0083         }
0084     } else {
0085         rtl_fw_block_write(hw, buffer, size);
0086     }
0087 }
0088 
0089 static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw)
0090 {
0091     struct rtl_priv *rtlpriv = rtl_priv(hw);
0092     int err = -EIO;
0093     u32 counter = 0;
0094     u32 value32;
0095 
0096     do {
0097         value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
0098     } while ((counter++ < FW_8192C_POLLING_TIMEOUT_COUNT) &&
0099          (!(value32 & FWDL_CHKSUM_RPT)));
0100 
0101     if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) {
0102         pr_err("chksum report fail! REG_MCUFWDL:0x%08x .\n",
0103                value32);
0104         goto exit;
0105     }
0106     value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
0107     value32 |= MCUFWDL_RDY;
0108     value32 &= ~WINTINI_RDY;
0109     rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
0110 
0111     counter = 0;
0112 
0113     do {
0114         value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
0115         if (value32 & WINTINI_RDY)
0116             return 0;
0117 
0118         mdelay(FW_8192C_POLLING_DELAY);
0119 
0120     } while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT);
0121 
0122     pr_err("Polling FW ready fail! REG_MCUFWDL:0x%08x.\n",
0123            value32);
0124 
0125 exit:
0126     return err;
0127 }
0128 
0129 int rtl92c_download_fw(struct ieee80211_hw *hw)
0130 {
0131     struct rtl_priv *rtlpriv = rtl_priv(hw);
0132     struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
0133     struct rtlwifi_firmware_header *pfwheader;
0134     u8 *pfwdata;
0135     u32 fwsize;
0136     int err;
0137     enum version_8192c version = rtlhal->version;
0138 
0139     if (!rtlhal->pfirmware)
0140         return 1;
0141 
0142     pfwheader = (struct rtlwifi_firmware_header *)rtlhal->pfirmware;
0143     pfwdata = (u8 *)rtlhal->pfirmware;
0144     fwsize = rtlhal->fwsize;
0145     if (IS_FW_HEADER_EXIST(pfwheader)) {
0146         rtl_dbg(rtlpriv, COMP_FW, DBG_DMESG,
0147             "Firmware Version(%d), Signature(%#x),Size(%d)\n",
0148             pfwheader->version, pfwheader->signature,
0149             (int)sizeof(struct rtlwifi_firmware_header));
0150 
0151         rtlhal->fw_version = le16_to_cpu(pfwheader->version);
0152         rtlhal->fw_subversion = pfwheader->subversion;
0153         pfwdata = pfwdata + sizeof(struct rtlwifi_firmware_header);
0154         fwsize = fwsize - sizeof(struct rtlwifi_firmware_header);
0155     }
0156 
0157     _rtl92c_enable_fw_download(hw, true);
0158     _rtl92c_write_fw(hw, version, pfwdata, fwsize);
0159     _rtl92c_enable_fw_download(hw, false);
0160 
0161     err = _rtl92c_fw_free_to_go(hw);
0162     if (err)
0163         pr_err("Firmware is not ready to run!\n");
0164 
0165     return 0;
0166 }
0167 EXPORT_SYMBOL(rtl92c_download_fw);
0168 
0169 static bool _rtl92c_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
0170 {
0171     struct rtl_priv *rtlpriv = rtl_priv(hw);
0172     u8 val_hmetfr, val_mcutst_1;
0173     bool result = false;
0174 
0175     val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
0176     val_mcutst_1 = rtl_read_byte(rtlpriv, (REG_MCUTST_1 + boxnum));
0177 
0178     if (((val_hmetfr >> boxnum) & BIT(0)) == 0 && val_mcutst_1 == 0)
0179         result = true;
0180     return result;
0181 }
0182 
0183 static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw,
0184                   u8 element_id, u32 cmd_len, u8 *cmdbuffer)
0185 {
0186     struct rtl_priv *rtlpriv = rtl_priv(hw);
0187     struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
0188     u8 boxnum;
0189     u16 box_reg = 0, box_extreg = 0;
0190     u8 u1b_tmp;
0191     bool isfw_read = false;
0192     u8 buf_index = 0;
0193     bool bwrite_sucess = false;
0194     u8 wait_h2c_limmit = 100;
0195     u8 wait_writeh2c_limmit = 100;
0196     u8 boxcontent[4], boxextcontent[2];
0197     u32 h2c_waitcounter = 0;
0198     unsigned long flag;
0199     u8 idx;
0200 
0201     rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD, "come in\n");
0202 
0203     while (true) {
0204         spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
0205         if (rtlhal->h2c_setinprogress) {
0206             rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD,
0207                 "H2C set in progress! Wait to set..element_id(%d).\n",
0208                 element_id);
0209             while (rtlhal->h2c_setinprogress) {
0210                 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
0211                                flag);
0212                 h2c_waitcounter++;
0213                 rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD,
0214                     "Wait 100 us (%d times)...\n",
0215                      h2c_waitcounter);
0216                 udelay(100);
0217 
0218                 if (h2c_waitcounter > 1000)
0219                     return;
0220                 spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
0221                           flag);
0222             }
0223             spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
0224         } else {
0225             rtlhal->h2c_setinprogress = true;
0226             spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
0227             break;
0228         }
0229     }
0230 
0231     while (!bwrite_sucess) {
0232         wait_writeh2c_limmit--;
0233         if (wait_writeh2c_limmit == 0) {
0234             pr_err("Write H2C fail because no trigger for FW INT!\n");
0235             break;
0236         }
0237 
0238         boxnum = rtlhal->last_hmeboxnum;
0239         switch (boxnum) {
0240         case 0:
0241             box_reg = REG_HMEBOX_0;
0242             box_extreg = REG_HMEBOX_EXT_0;
0243             break;
0244         case 1:
0245             box_reg = REG_HMEBOX_1;
0246             box_extreg = REG_HMEBOX_EXT_1;
0247             break;
0248         case 2:
0249             box_reg = REG_HMEBOX_2;
0250             box_extreg = REG_HMEBOX_EXT_2;
0251             break;
0252         case 3:
0253             box_reg = REG_HMEBOX_3;
0254             box_extreg = REG_HMEBOX_EXT_3;
0255             break;
0256         default:
0257             rtl_dbg(rtlpriv, COMP_ERR, DBG_LOUD,
0258                 "switch case %#x not processed\n", boxnum);
0259             break;
0260         }
0261 
0262         isfw_read = _rtl92c_check_fw_read_last_h2c(hw, boxnum);
0263         while (!isfw_read) {
0264             wait_h2c_limmit--;
0265             if (wait_h2c_limmit == 0) {
0266                 rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD,
0267                     "Waiting too long for FW read clear HMEBox(%d)!\n",
0268                     boxnum);
0269                 break;
0270             }
0271 
0272             udelay(10);
0273 
0274             isfw_read = _rtl92c_check_fw_read_last_h2c(hw, boxnum);
0275             u1b_tmp = rtl_read_byte(rtlpriv, 0x1BF);
0276             rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD,
0277                 "Waiting for FW read clear HMEBox(%d)!!! 0x1BF = %2x\n",
0278                 boxnum, u1b_tmp);
0279         }
0280 
0281         if (!isfw_read) {
0282             rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD,
0283                 "Write H2C register BOX[%d] fail!!!!! Fw do not read.\n",
0284                 boxnum);
0285             break;
0286         }
0287 
0288         memset(boxcontent, 0, sizeof(boxcontent));
0289         memset(boxextcontent, 0, sizeof(boxextcontent));
0290         boxcontent[0] = element_id;
0291         rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD,
0292             "Write element_id box_reg(%4x) = %2x\n",
0293             box_reg, element_id);
0294 
0295         switch (cmd_len) {
0296         case 1:
0297             boxcontent[0] &= ~(BIT(7));
0298             memcpy((u8 *)(boxcontent) + 1,
0299                    cmdbuffer + buf_index, 1);
0300 
0301             for (idx = 0; idx < 4; idx++) {
0302                 rtl_write_byte(rtlpriv, box_reg + idx,
0303                            boxcontent[idx]);
0304             }
0305             break;
0306         case 2:
0307             boxcontent[0] &= ~(BIT(7));
0308             memcpy((u8 *)(boxcontent) + 1,
0309                    cmdbuffer + buf_index, 2);
0310 
0311             for (idx = 0; idx < 4; idx++) {
0312                 rtl_write_byte(rtlpriv, box_reg + idx,
0313                            boxcontent[idx]);
0314             }
0315             break;
0316         case 3:
0317             boxcontent[0] &= ~(BIT(7));
0318             memcpy((u8 *)(boxcontent) + 1,
0319                    cmdbuffer + buf_index, 3);
0320 
0321             for (idx = 0; idx < 4; idx++) {
0322                 rtl_write_byte(rtlpriv, box_reg + idx,
0323                            boxcontent[idx]);
0324             }
0325             break;
0326         case 4:
0327             boxcontent[0] |= (BIT(7));
0328             memcpy((u8 *)(boxextcontent),
0329                    cmdbuffer + buf_index, 2);
0330             memcpy((u8 *)(boxcontent) + 1,
0331                    cmdbuffer + buf_index + 2, 2);
0332 
0333             for (idx = 0; idx < 2; idx++) {
0334                 rtl_write_byte(rtlpriv, box_extreg + idx,
0335                            boxextcontent[idx]);
0336             }
0337 
0338             for (idx = 0; idx < 4; idx++) {
0339                 rtl_write_byte(rtlpriv, box_reg + idx,
0340                            boxcontent[idx]);
0341             }
0342             break;
0343         case 5:
0344             boxcontent[0] |= (BIT(7));
0345             memcpy((u8 *)(boxextcontent),
0346                    cmdbuffer + buf_index, 2);
0347             memcpy((u8 *)(boxcontent) + 1,
0348                    cmdbuffer + buf_index + 2, 3);
0349 
0350             for (idx = 0; idx < 2; idx++) {
0351                 rtl_write_byte(rtlpriv, box_extreg + idx,
0352                            boxextcontent[idx]);
0353             }
0354 
0355             for (idx = 0; idx < 4; idx++) {
0356                 rtl_write_byte(rtlpriv, box_reg + idx,
0357                            boxcontent[idx]);
0358             }
0359             break;
0360         default:
0361             rtl_dbg(rtlpriv, COMP_ERR, DBG_LOUD,
0362                 "switch case %#x not processed\n", cmd_len);
0363             break;
0364         }
0365 
0366         bwrite_sucess = true;
0367 
0368         rtlhal->last_hmeboxnum = boxnum + 1;
0369         if (rtlhal->last_hmeboxnum == 4)
0370             rtlhal->last_hmeboxnum = 0;
0371 
0372         rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD,
0373             "pHalData->last_hmeboxnum  = %d\n",
0374             rtlhal->last_hmeboxnum);
0375     }
0376 
0377     spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
0378     rtlhal->h2c_setinprogress = false;
0379     spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
0380 
0381     rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n");
0382 }
0383 
0384 void rtl92c_fill_h2c_cmd(struct ieee80211_hw *hw,
0385              u8 element_id, u32 cmd_len, u8 *cmdbuffer)
0386 {
0387     struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
0388     u32 tmp_cmdbuf[2];
0389 
0390     if (!rtlhal->fw_ready) {
0391         WARN_ONCE(true,
0392               "rtl8192c-common: return H2C cmd because of Fw download fail!!!\n");
0393         return;
0394     }
0395 
0396     memset(tmp_cmdbuf, 0, 8);
0397     memcpy(tmp_cmdbuf, cmdbuffer, cmd_len);
0398     _rtl92c_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
0399 
0400     return;
0401 }
0402 EXPORT_SYMBOL(rtl92c_fill_h2c_cmd);
0403 
0404 void rtl92c_firmware_selfreset(struct ieee80211_hw *hw)
0405 {
0406     u8 u1b_tmp;
0407     u8 delay = 100;
0408     struct rtl_priv *rtlpriv = rtl_priv(hw);
0409 
0410     rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20);
0411     u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
0412 
0413     while (u1b_tmp & BIT(2)) {
0414         delay--;
0415         if (delay == 0) {
0416             WARN_ONCE(true, "rtl8192c-common: 8051 reset fail.\n");
0417             break;
0418         }
0419         udelay(50);
0420         u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
0421     }
0422 }
0423 EXPORT_SYMBOL(rtl92c_firmware_selfreset);
0424 
0425 void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
0426 {
0427     struct rtl_priv *rtlpriv = rtl_priv(hw);
0428     u8 u1_h2c_set_pwrmode[3] = { 0 };
0429     struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
0430 
0431     rtl_dbg(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode);
0432 
0433     SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode);
0434     SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode,
0435         (rtlpriv->mac80211.p2p) ? ppsc->smart_ps : 1);
0436     SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode,
0437                           ppsc->reg_max_lps_awakeintvl);
0438 
0439     RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
0440               "rtl92c_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode\n",
0441               u1_h2c_set_pwrmode, 3);
0442     rtl92c_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode);
0443 }
0444 EXPORT_SYMBOL(rtl92c_set_fw_pwrmode_cmd);
0445 
0446 #define BEACON_PG       0 /*->1*/
0447 #define PSPOLL_PG       2
0448 #define NULL_PG         3
0449 #define PROBERSP_PG     4 /*->5*/
0450 
0451 #define TOTAL_RESERVED_PKT_LEN  768
0452 
0453 static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
0454     /* page 0 beacon */
0455     0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0456     0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
0457     0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08,
0458     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0459     0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
0460     0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
0461     0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
0462     0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
0463     0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
0464     0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
0465     0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0466     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0467     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0468     0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
0469     0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0470     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0471 
0472     /* page 1 beacon */
0473     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0474     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0475     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0476     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0477     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0478     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0479     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0480     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0481     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0482     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0483     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0484     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0485     0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00,
0486     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0487     0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0488     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0489 
0490     /* page 2  ps-poll */
0491     0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10,
0492     0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
0493     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0494     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0495     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0496     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0497     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0498     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0499     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0500     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0501     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0502     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0503     0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
0504     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
0505     0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0506     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0507 
0508     /* page 3  null */
0509     0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
0510     0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
0511     0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
0512     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0513     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0514     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0515     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0516     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0517     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0518     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0519     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0520     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0521     0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
0522     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
0523     0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0524     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0525 
0526     /* page 4  probe_resp */
0527     0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
0528     0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
0529     0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
0530     0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
0531     0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
0532     0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
0533     0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
0534     0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
0535     0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
0536     0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
0537     0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0538     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0539     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0540     0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
0541     0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0542     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0543 
0544     /* page 5  probe_resp */
0545     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0546     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0547     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0548     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0549     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0550     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0551     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0552     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0553     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0554     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0555     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0556     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0557     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0558     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0559     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0560     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0561 };
0562 
0563 void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw,
0564      bool (*cmd_send_packet)(struct ieee80211_hw *, struct sk_buff *))
0565 {
0566     struct rtl_priv *rtlpriv = rtl_priv(hw);
0567     struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
0568     struct sk_buff *skb = NULL;
0569 
0570     u32 totalpacketlen;
0571     bool rtstatus;
0572     u8 u1rsvdpageloc[3] = { 0 };
0573     bool b_dlok = false;
0574 
0575     u8 *beacon;
0576     u8 *p_pspoll;
0577     u8 *nullfunc;
0578     u8 *p_probersp;
0579     /*---------------------------------------------------------
0580                 (1) beacon
0581     ---------------------------------------------------------*/
0582     beacon = &reserved_page_packet[BEACON_PG * 128];
0583     SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
0584     SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
0585 
0586     /*-------------------------------------------------------
0587                 (2) ps-poll
0588     --------------------------------------------------------*/
0589     p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
0590     SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
0591     SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
0592     SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
0593 
0594     SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1rsvdpageloc, PSPOLL_PG);
0595 
0596     /*--------------------------------------------------------
0597                 (3) null data
0598     ---------------------------------------------------------*/
0599     nullfunc = &reserved_page_packet[NULL_PG * 128];
0600     SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
0601     SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
0602     SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
0603 
0604     SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1rsvdpageloc, NULL_PG);
0605 
0606     /*---------------------------------------------------------
0607                 (4) probe response
0608     ----------------------------------------------------------*/
0609     p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
0610     SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
0611     SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
0612     SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
0613 
0614     SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1rsvdpageloc, PROBERSP_PG);
0615 
0616     totalpacketlen = TOTAL_RESERVED_PKT_LEN;
0617 
0618     RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
0619               "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
0620               &reserved_page_packet[0], totalpacketlen);
0621     RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
0622               "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
0623               u1rsvdpageloc, 3);
0624 
0625     skb = dev_alloc_skb(totalpacketlen);
0626     if (!skb)
0627         return;
0628     skb_put_data(skb, &reserved_page_packet, totalpacketlen);
0629 
0630     if (cmd_send_packet)
0631         rtstatus = cmd_send_packet(hw, skb);
0632     else
0633         rtstatus = rtl_cmd_send_packet(hw, skb);
0634 
0635     if (rtstatus)
0636         b_dlok = true;
0637 
0638     if (b_dlok) {
0639         rtl_dbg(rtlpriv, COMP_POWER, DBG_LOUD,
0640             "Set RSVD page location to Fw.\n");
0641         RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
0642                 "H2C_RSVDPAGE:\n",
0643                 u1rsvdpageloc, 3);
0644         rtl92c_fill_h2c_cmd(hw, H2C_RSVDPAGE,
0645                     sizeof(u1rsvdpageloc), u1rsvdpageloc);
0646     } else
0647         rtl_dbg(rtlpriv, COMP_ERR, DBG_WARNING,
0648             "Set RSVD page location to Fw FAIL!!!!!!.\n");
0649 }
0650 EXPORT_SYMBOL(rtl92c_set_fw_rsvdpagepkt);
0651 
0652 void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
0653 {
0654     u8 u1_joinbssrpt_parm[1] = { 0 };
0655 
0656     SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
0657 
0658     rtl92c_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm);
0659 }
0660 EXPORT_SYMBOL(rtl92c_set_fw_joinbss_report_cmd);
0661 
0662 static void rtl92c_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw, u8 ctwindow)
0663 {
0664     u8 u1_ctwindow_period[1] = { ctwindow};
0665 
0666     rtl92c_fill_h2c_cmd(hw, H2C_P2P_PS_CTW_CMD, 1, u1_ctwindow_period);
0667 }
0668 
0669 /* refactored routine */
0670 static void set_noa_data(struct rtl_priv *rtlpriv,
0671              struct rtl_p2p_ps_info *p2pinfo,
0672              struct p2p_ps_offload_t *p2p_ps_offload)
0673 {
0674     int i;
0675     u32 start_time, tsf_low;
0676 
0677     /* hw only support 2 set of NoA */
0678     for (i = 0 ; i < p2pinfo->noa_num ; i++) {
0679         /* To control the reg setting for which NOA*/
0680         rtl_write_byte(rtlpriv, 0x5cf, (i << 4));
0681         if (i == 0)
0682             p2p_ps_offload->noa0_en = 1;
0683         else
0684             p2p_ps_offload->noa1_en = 1;
0685 
0686         /* config P2P NoA Descriptor Register */
0687         rtl_write_dword(rtlpriv, 0x5E0,
0688                 p2pinfo->noa_duration[i]);
0689         rtl_write_dword(rtlpriv, 0x5E4,
0690                 p2pinfo->noa_interval[i]);
0691 
0692         /*Get Current TSF value */
0693         tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
0694 
0695         start_time = p2pinfo->noa_start_time[i];
0696         if (p2pinfo->noa_count_type[i] != 1) {
0697             while (start_time <= (tsf_low+(50*1024))) {
0698                 start_time += p2pinfo->noa_interval[i];
0699                 if (p2pinfo->noa_count_type[i] != 255)
0700                     p2pinfo->noa_count_type[i]--;
0701             }
0702         }
0703         rtl_write_dword(rtlpriv, 0x5E8, start_time);
0704         rtl_write_dword(rtlpriv, 0x5EC,
0705                 p2pinfo->noa_count_type[i]);
0706     }
0707 }
0708 
0709 void rtl92c_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
0710 {
0711     struct rtl_priv *rtlpriv = rtl_priv(hw);
0712     struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
0713     struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
0714     struct rtl_p2p_ps_info *p2pinfo = &(rtlps->p2p_ps_info);
0715     struct p2p_ps_offload_t *p2p_ps_offload = &rtlhal->p2p_ps_offload;
0716     u16 ctwindow;
0717 
0718     switch (p2p_ps_state) {
0719     case P2P_PS_DISABLE:
0720             rtl_dbg(rtlpriv, COMP_FW, DBG_LOUD,
0721                 "P2P_PS_DISABLE\n");
0722             memset(p2p_ps_offload, 0, sizeof(*p2p_ps_offload));
0723             break;
0724     case P2P_PS_ENABLE:
0725             rtl_dbg(rtlpriv, COMP_FW, DBG_LOUD,
0726                 "P2P_PS_ENABLE\n");
0727             /* update CTWindow value. */
0728             if (p2pinfo->ctwindow > 0) {
0729                 p2p_ps_offload->ctwindow_en = 1;
0730                 ctwindow = p2pinfo->ctwindow;
0731                 rtl92c_set_p2p_ctw_period_cmd(hw, ctwindow);
0732             }
0733             /* call refactored routine */
0734             set_noa_data(rtlpriv, p2pinfo, p2p_ps_offload);
0735 
0736             if ((p2pinfo->opp_ps == 1) || (p2pinfo->noa_num > 0)) {
0737                 /* rst p2p circuit */
0738                 rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST,
0739                            BIT(4));
0740 
0741                 p2p_ps_offload->offload_en = 1;
0742 
0743                 if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) {
0744                     p2p_ps_offload->role = 1;
0745                     p2p_ps_offload->allstasleep = 0;
0746                 } else {
0747                     p2p_ps_offload->role = 0;
0748                 }
0749 
0750                 p2p_ps_offload->discovery = 0;
0751             }
0752             break;
0753     case P2P_PS_SCAN:
0754             rtl_dbg(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN\n");
0755             p2p_ps_offload->discovery = 1;
0756             break;
0757     case P2P_PS_SCAN_DONE:
0758             rtl_dbg(rtlpriv, COMP_FW, DBG_LOUD,
0759                 "P2P_PS_SCAN_DONE\n");
0760             p2p_ps_offload->discovery = 0;
0761             p2pinfo->p2p_ps_state = P2P_PS_ENABLE;
0762             break;
0763     default:
0764             break;
0765     }
0766 
0767     rtl92c_fill_h2c_cmd(hw, H2C_P2P_PS_OFFLOAD, 1, (u8 *)p2p_ps_offload);
0768 
0769 }
0770 EXPORT_SYMBOL_GPL(rtl92c_set_p2p_ps_offload_cmd);