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