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