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