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