1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /****************************************************************************** |
3 | * |
4 | * Copyright(c) 2007 - 2013 Realtek Corporation. All rights reserved. |
5 | * |
6 | ******************************************************************************/ |
7 | |
8 | #include <linux/firmware.h> |
9 | #include <linux/slab.h> |
10 | #include <drv_types.h> |
11 | #include <rtw_debug.h> |
12 | #include <rtl8723b_hal.h> |
13 | #include "hal_com_h2c.h" |
14 | |
15 | static void _FWDownloadEnable(struct adapter *padapter, bool enable) |
16 | { |
17 | u8 tmp, count = 0; |
18 | |
19 | if (enable) { |
20 | /* 8051 enable */ |
21 | tmp = rtw_read8(adapter: padapter, REG_SYS_FUNC_EN+1); |
22 | rtw_write8(adapter: padapter, REG_SYS_FUNC_EN+1, val: tmp|0x04); |
23 | |
24 | tmp = rtw_read8(adapter: padapter, REG_MCUFWDL); |
25 | rtw_write8(adapter: padapter, REG_MCUFWDL, val: tmp|0x01); |
26 | |
27 | do { |
28 | tmp = rtw_read8(adapter: padapter, REG_MCUFWDL); |
29 | if (tmp & 0x01) |
30 | break; |
31 | rtw_write8(adapter: padapter, REG_MCUFWDL, val: tmp|0x01); |
32 | msleep(msecs: 1); |
33 | } while (count++ < 100); |
34 | |
35 | /* 8051 reset */ |
36 | tmp = rtw_read8(adapter: padapter, REG_MCUFWDL+2); |
37 | rtw_write8(adapter: padapter, REG_MCUFWDL+2, val: tmp&0xf7); |
38 | } else { |
39 | /* MCU firmware download disable. */ |
40 | tmp = rtw_read8(adapter: padapter, REG_MCUFWDL); |
41 | rtw_write8(adapter: padapter, REG_MCUFWDL, val: tmp&0xfe); |
42 | } |
43 | } |
44 | |
45 | static int _BlockWrite(struct adapter *padapter, void *buffer, u32 buffSize) |
46 | { |
47 | int ret = _SUCCESS; |
48 | |
49 | u32 blockSize_p1 = 4; /* (Default) Phase #1 : PCI muse use 4-byte write to download FW */ |
50 | u32 blockSize_p2 = 8; /* Phase #2 : Use 8-byte, if Phase#1 use big size to write FW. */ |
51 | u32 blockSize_p3 = 1; /* Phase #3 : Use 1-byte, the remnant of FW image. */ |
52 | u32 blockCount_p1 = 0, blockCount_p2 = 0, blockCount_p3 = 0; |
53 | u32 remainSize_p1 = 0, remainSize_p2 = 0; |
54 | u8 *bufferPtr = buffer; |
55 | u32 i = 0, offset = 0; |
56 | |
57 | /* printk("====>%s %d\n", __func__, __LINE__); */ |
58 | |
59 | /* 3 Phase #1 */ |
60 | blockCount_p1 = buffSize / blockSize_p1; |
61 | remainSize_p1 = buffSize % blockSize_p1; |
62 | |
63 | for (i = 0; i < blockCount_p1; i++) { |
64 | ret = rtw_write32(adapter: padapter, addr: (FW_8723B_START_ADDRESS + i * blockSize_p1), val: *((u32 *)(bufferPtr + i * blockSize_p1))); |
65 | if (ret == _FAIL) { |
66 | printk("====>%s %d i:%d\n" , __func__, __LINE__, i); |
67 | goto exit; |
68 | } |
69 | } |
70 | |
71 | /* 3 Phase #2 */ |
72 | if (remainSize_p1) { |
73 | offset = blockCount_p1 * blockSize_p1; |
74 | |
75 | blockCount_p2 = remainSize_p1/blockSize_p2; |
76 | remainSize_p2 = remainSize_p1%blockSize_p2; |
77 | } |
78 | |
79 | /* 3 Phase #3 */ |
80 | if (remainSize_p2) { |
81 | offset = (blockCount_p1 * blockSize_p1) + (blockCount_p2 * blockSize_p2); |
82 | |
83 | blockCount_p3 = remainSize_p2 / blockSize_p3; |
84 | |
85 | for (i = 0; i < blockCount_p3; i++) { |
86 | ret = rtw_write8(adapter: padapter, addr: (FW_8723B_START_ADDRESS + offset + i), val: *(bufferPtr + offset + i)); |
87 | |
88 | if (ret == _FAIL) { |
89 | printk("====>%s %d i:%d\n" , __func__, __LINE__, i); |
90 | goto exit; |
91 | } |
92 | } |
93 | } |
94 | exit: |
95 | return ret; |
96 | } |
97 | |
98 | static int _PageWrite( |
99 | struct adapter *padapter, |
100 | u32 page, |
101 | void *buffer, |
102 | u32 size |
103 | ) |
104 | { |
105 | u8 value8; |
106 | u8 u8Page = (u8) (page & 0x07); |
107 | |
108 | value8 = (rtw_read8(adapter: padapter, REG_MCUFWDL+2) & 0xF8) | u8Page; |
109 | rtw_write8(adapter: padapter, REG_MCUFWDL+2, val: value8); |
110 | |
111 | return _BlockWrite(padapter, buffer, buffSize: size); |
112 | } |
113 | |
114 | static int _WriteFW(struct adapter *padapter, void *buffer, u32 size) |
115 | { |
116 | /* Since we need dynamic decide method of dwonload fw, so we call this function to get chip version. */ |
117 | /* We can remove _ReadChipVersion from ReadpadapterInfo8192C later. */ |
118 | int ret = _SUCCESS; |
119 | u32 pageNums, remainSize; |
120 | u32 page, offset; |
121 | u8 *bufferPtr = buffer; |
122 | |
123 | pageNums = size / MAX_DLFW_PAGE_SIZE; |
124 | remainSize = size % MAX_DLFW_PAGE_SIZE; |
125 | |
126 | for (page = 0; page < pageNums; page++) { |
127 | offset = page * MAX_DLFW_PAGE_SIZE; |
128 | ret = _PageWrite(padapter, page, buffer: bufferPtr+offset, MAX_DLFW_PAGE_SIZE); |
129 | |
130 | if (ret == _FAIL) { |
131 | printk("====>%s %d\n" , __func__, __LINE__); |
132 | goto exit; |
133 | } |
134 | } |
135 | |
136 | if (remainSize) { |
137 | offset = pageNums * MAX_DLFW_PAGE_SIZE; |
138 | page = pageNums; |
139 | ret = _PageWrite(padapter, page, buffer: bufferPtr+offset, size: remainSize); |
140 | |
141 | if (ret == _FAIL) { |
142 | printk("====>%s %d\n" , __func__, __LINE__); |
143 | goto exit; |
144 | } |
145 | } |
146 | |
147 | exit: |
148 | return ret; |
149 | } |
150 | |
151 | void _8051Reset8723(struct adapter *padapter) |
152 | { |
153 | u8 cpu_rst; |
154 | u8 io_rst; |
155 | |
156 | |
157 | /* Reset 8051(WLMCU) IO wrapper */ |
158 | /* 0x1c[8] = 0 */ |
159 | /* Suggested by Isaac@SD1 and Gimmy@SD1, coding by Lucas@20130624 */ |
160 | io_rst = rtw_read8(adapter: padapter, REG_RSV_CTRL+1); |
161 | io_rst &= ~BIT(0); |
162 | rtw_write8(adapter: padapter, REG_RSV_CTRL+1, val: io_rst); |
163 | |
164 | cpu_rst = rtw_read8(adapter: padapter, REG_SYS_FUNC_EN+1); |
165 | cpu_rst &= ~BIT(2); |
166 | rtw_write8(adapter: padapter, REG_SYS_FUNC_EN+1, val: cpu_rst); |
167 | |
168 | /* Enable 8051 IO wrapper */ |
169 | /* 0x1c[8] = 1 */ |
170 | io_rst = rtw_read8(adapter: padapter, REG_RSV_CTRL+1); |
171 | io_rst |= BIT(0); |
172 | rtw_write8(adapter: padapter, REG_RSV_CTRL+1, val: io_rst); |
173 | |
174 | cpu_rst = rtw_read8(adapter: padapter, REG_SYS_FUNC_EN+1); |
175 | cpu_rst |= BIT(2); |
176 | rtw_write8(adapter: padapter, REG_SYS_FUNC_EN+1, val: cpu_rst); |
177 | } |
178 | |
179 | u8 g_fwdl_chksum_fail; |
180 | |
181 | static s32 polling_fwdl_chksum( |
182 | struct adapter *adapter, u32 min_cnt, u32 timeout_ms |
183 | ) |
184 | { |
185 | s32 ret = _FAIL; |
186 | u32 value32; |
187 | unsigned long start = jiffies; |
188 | u32 cnt = 0; |
189 | |
190 | /* polling CheckSum report */ |
191 | do { |
192 | cnt++; |
193 | value32 = rtw_read32(adapter, REG_MCUFWDL); |
194 | if (value32 & FWDL_ChkSum_rpt || adapter->bSurpriseRemoved || adapter->bDriverStopped) |
195 | break; |
196 | yield(); |
197 | } while (jiffies_to_msecs(j: jiffies-start) < timeout_ms || cnt < min_cnt); |
198 | |
199 | if (!(value32 & FWDL_ChkSum_rpt)) { |
200 | goto exit; |
201 | } |
202 | |
203 | if (g_fwdl_chksum_fail) { |
204 | g_fwdl_chksum_fail--; |
205 | goto exit; |
206 | } |
207 | |
208 | ret = _SUCCESS; |
209 | |
210 | exit: |
211 | |
212 | return ret; |
213 | } |
214 | |
215 | u8 g_fwdl_wintint_rdy_fail; |
216 | |
217 | static s32 _FWFreeToGo(struct adapter *adapter, u32 min_cnt, u32 timeout_ms) |
218 | { |
219 | s32 ret = _FAIL; |
220 | u32 value32; |
221 | unsigned long start = jiffies; |
222 | u32 cnt = 0; |
223 | |
224 | value32 = rtw_read32(adapter, REG_MCUFWDL); |
225 | value32 |= MCUFWDL_RDY; |
226 | value32 &= ~WINTINI_RDY; |
227 | rtw_write32(adapter, REG_MCUFWDL, val: value32); |
228 | |
229 | _8051Reset8723(padapter: adapter); |
230 | |
231 | /* polling for FW ready */ |
232 | do { |
233 | cnt++; |
234 | value32 = rtw_read32(adapter, REG_MCUFWDL); |
235 | if (value32 & WINTINI_RDY || adapter->bSurpriseRemoved || adapter->bDriverStopped) |
236 | break; |
237 | yield(); |
238 | } while (jiffies_to_msecs(j: jiffies - start) < timeout_ms || cnt < min_cnt); |
239 | |
240 | if (!(value32 & WINTINI_RDY)) { |
241 | goto exit; |
242 | } |
243 | |
244 | if (g_fwdl_wintint_rdy_fail) { |
245 | g_fwdl_wintint_rdy_fail--; |
246 | goto exit; |
247 | } |
248 | |
249 | ret = _SUCCESS; |
250 | |
251 | exit: |
252 | |
253 | return ret; |
254 | } |
255 | |
256 | #define IS_FW_81xxC(padapter) (((GET_HAL_DATA(padapter))->FirmwareSignature & 0xFFF0) == 0x88C0) |
257 | |
258 | void rtl8723b_FirmwareSelfReset(struct adapter *padapter) |
259 | { |
260 | struct hal_com_data *pHalData = GET_HAL_DATA(padapter); |
261 | u8 u1bTmp; |
262 | u8 Delay = 100; |
263 | |
264 | if ( |
265 | !(IS_FW_81xxC(padapter) && ((pHalData->FirmwareVersion < 0x21) || (pHalData->FirmwareVersion == 0x21 && pHalData->FirmwareSubVersion < 0x01))) |
266 | ) { /* after 88C Fw v33.1 */ |
267 | /* 0x1cf = 0x20. Inform 8051 to reset. 2009.12.25. tynli_test */ |
268 | rtw_write8(adapter: padapter, REG_HMETFR+3, val: 0x20); |
269 | |
270 | u1bTmp = rtw_read8(adapter: padapter, REG_SYS_FUNC_EN+1); |
271 | while (u1bTmp & BIT2) { |
272 | Delay--; |
273 | if (Delay == 0) |
274 | break; |
275 | udelay(50); |
276 | u1bTmp = rtw_read8(adapter: padapter, REG_SYS_FUNC_EN+1); |
277 | } |
278 | |
279 | if (Delay == 0) { |
280 | /* force firmware reset */ |
281 | u1bTmp = rtw_read8(adapter: padapter, REG_SYS_FUNC_EN+1); |
282 | rtw_write8(adapter: padapter, REG_SYS_FUNC_EN+1, val: u1bTmp&(~BIT2)); |
283 | } |
284 | } |
285 | } |
286 | |
287 | /* */ |
288 | /* Description: */ |
289 | /* Download 8192C firmware code. */ |
290 | /* */ |
291 | /* */ |
292 | s32 rtl8723b_FirmwareDownload(struct adapter *padapter, bool bUsedWoWLANFw) |
293 | { |
294 | s32 rtStatus = _SUCCESS; |
295 | u8 write_fw = 0; |
296 | unsigned long fwdl_start_time; |
297 | struct hal_com_data *pHalData = GET_HAL_DATA(padapter); |
298 | struct rt_firmware *pFirmware; |
299 | struct rt_firmware *pBTFirmware; |
300 | struct rt_firmware_hdr *pFwHdr = NULL; |
301 | u8 *pFirmwareBuf; |
302 | u32 FirmwareLen; |
303 | const struct firmware *fw; |
304 | struct device *device = dvobj_to_dev(dvobj: padapter->dvobj); |
305 | u8 *fwfilepath; |
306 | struct dvobj_priv *psdpriv = padapter->dvobj; |
307 | struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; |
308 | u8 tmp_ps; |
309 | |
310 | pFirmware = kzalloc(size: sizeof(struct rt_firmware), GFP_KERNEL); |
311 | if (!pFirmware) |
312 | return _FAIL; |
313 | pBTFirmware = kzalloc(size: sizeof(struct rt_firmware), GFP_KERNEL); |
314 | if (!pBTFirmware) { |
315 | kfree(objp: pFirmware); |
316 | return _FAIL; |
317 | } |
318 | tmp_ps = rtw_read8(adapter: padapter, addr: 0xa3); |
319 | tmp_ps &= 0xf8; |
320 | tmp_ps |= 0x02; |
321 | /* 1. write 0xA3[:2:0] = 3b'010 */ |
322 | rtw_write8(adapter: padapter, addr: 0xa3, val: tmp_ps); |
323 | /* 2. read power_state = 0xA0[1:0] */ |
324 | tmp_ps = rtw_read8(adapter: padapter, addr: 0xa0); |
325 | tmp_ps &= 0x03; |
326 | if (tmp_ps != 0x01) |
327 | pdbgpriv->dbg_downloadfw_pwr_state_cnt++; |
328 | |
329 | fwfilepath = "rtlwifi/rtl8723bs_nic.bin" ; |
330 | |
331 | pr_info("rtl8723bs: acquire FW from file:%s\n" , fwfilepath); |
332 | |
333 | rtStatus = request_firmware(fw: &fw, name: fwfilepath, device); |
334 | if (rtStatus) { |
335 | pr_err("Request firmware failed with error 0x%x\n" , rtStatus); |
336 | rtStatus = _FAIL; |
337 | goto exit; |
338 | } |
339 | |
340 | if (!fw) { |
341 | pr_err("Firmware %s not available\n" , fwfilepath); |
342 | rtStatus = _FAIL; |
343 | goto exit; |
344 | } |
345 | |
346 | if (fw->size > FW_8723B_SIZE) { |
347 | rtStatus = _FAIL; |
348 | goto exit; |
349 | } |
350 | |
351 | pFirmware->fw_buffer_sz = kmemdup(p: fw->data, size: fw->size, GFP_KERNEL); |
352 | if (!pFirmware->fw_buffer_sz) { |
353 | rtStatus = _FAIL; |
354 | goto exit; |
355 | } |
356 | |
357 | pFirmware->fw_length = fw->size; |
358 | release_firmware(fw); |
359 | if (pFirmware->fw_length > FW_8723B_SIZE) { |
360 | rtStatus = _FAIL; |
361 | netdev_emerg(dev: padapter->pnetdev, |
362 | format: "Firmware size:%u exceed %u\n" , |
363 | pFirmware->fw_length, FW_8723B_SIZE); |
364 | goto release_fw1; |
365 | } |
366 | |
367 | pFirmwareBuf = pFirmware->fw_buffer_sz; |
368 | FirmwareLen = pFirmware->fw_length; |
369 | |
370 | /* To Check Fw header. Added by tynli. 2009.12.04. */ |
371 | pFwHdr = (struct rt_firmware_hdr *)pFirmwareBuf; |
372 | |
373 | pHalData->FirmwareVersion = le16_to_cpu(pFwHdr->version); |
374 | pHalData->FirmwareSubVersion = le16_to_cpu(pFwHdr->subversion); |
375 | pHalData->FirmwareSignature = le16_to_cpu(pFwHdr->signature); |
376 | |
377 | if (IS_FW_HEADER_EXIST_8723B(pFwHdr)) { |
378 | /* Shift 32 bytes for FW header */ |
379 | pFirmwareBuf = pFirmwareBuf + 32; |
380 | FirmwareLen = FirmwareLen - 32; |
381 | } |
382 | |
383 | /* Suggested by Filen. If 8051 is running in RAM code, driver should inform Fw to reset by itself, */ |
384 | /* or it will cause download Fw fail. 2010.02.01. by tynli. */ |
385 | if (rtw_read8(adapter: padapter, REG_MCUFWDL) & RAM_DL_SEL) { /* 8051 RAM code */ |
386 | rtw_write8(adapter: padapter, REG_MCUFWDL, val: 0x00); |
387 | rtl8723b_FirmwareSelfReset(padapter); |
388 | } |
389 | |
390 | _FWDownloadEnable(padapter, enable: true); |
391 | fwdl_start_time = jiffies; |
392 | while ( |
393 | !padapter->bDriverStopped && |
394 | !padapter->bSurpriseRemoved && |
395 | (write_fw++ < 3 || jiffies_to_msecs(j: jiffies - fwdl_start_time) < 500) |
396 | ) { |
397 | /* reset FWDL chksum */ |
398 | rtw_write8(adapter: padapter, REG_MCUFWDL, val: rtw_read8(adapter: padapter, REG_MCUFWDL)|FWDL_ChkSum_rpt); |
399 | |
400 | rtStatus = _WriteFW(padapter, buffer: pFirmwareBuf, size: FirmwareLen); |
401 | if (rtStatus != _SUCCESS) |
402 | continue; |
403 | |
404 | rtStatus = polling_fwdl_chksum(adapter: padapter, min_cnt: 5, timeout_ms: 50); |
405 | if (rtStatus == _SUCCESS) |
406 | break; |
407 | } |
408 | _FWDownloadEnable(padapter, enable: false); |
409 | if (_SUCCESS != rtStatus) |
410 | goto fwdl_stat; |
411 | |
412 | rtStatus = _FWFreeToGo(adapter: padapter, min_cnt: 10, timeout_ms: 200); |
413 | if (_SUCCESS != rtStatus) |
414 | goto fwdl_stat; |
415 | |
416 | fwdl_stat: |
417 | |
418 | exit: |
419 | kfree(objp: pFirmware->fw_buffer_sz); |
420 | kfree(objp: pFirmware); |
421 | release_fw1: |
422 | kfree(objp: pBTFirmware); |
423 | return rtStatus; |
424 | } |
425 | |
426 | void rtl8723b_InitializeFirmwareVars(struct adapter *padapter) |
427 | { |
428 | struct hal_com_data *pHalData = GET_HAL_DATA(padapter); |
429 | |
430 | /* Init Fw LPS related. */ |
431 | adapter_to_pwrctl(padapter)->fw_current_in_ps_mode = false; |
432 | |
433 | /* Init H2C cmd. */ |
434 | rtw_write8(adapter: padapter, REG_HMETFR, val: 0x0f); |
435 | |
436 | /* Init H2C counter. by tynli. 2009.12.09. */ |
437 | pHalData->LastHMEBoxNum = 0; |
438 | /* pHalData->H2CQueueHead = 0; */ |
439 | /* pHalData->H2CQueueTail = 0; */ |
440 | /* pHalData->H2CStopInsertQueue = false; */ |
441 | } |
442 | |
443 | static void rtl8723b_free_hal_data(struct adapter *padapter) |
444 | { |
445 | } |
446 | |
447 | /* */ |
448 | /* Efuse related code */ |
449 | /* */ |
450 | static u8 hal_EfuseSwitchToBank( |
451 | struct adapter *padapter, u8 bank, bool bPseudoTest |
452 | ) |
453 | { |
454 | u8 bRet = false; |
455 | u32 value32 = 0; |
456 | #ifdef HAL_EFUSE_MEMORY |
457 | struct hal_com_data *pHalData = GET_HAL_DATA(padapter); |
458 | struct efuse_hal *pEfuseHal = &pHalData->EfuseHal; |
459 | #endif |
460 | |
461 | |
462 | if (bPseudoTest) { |
463 | #ifdef HAL_EFUSE_MEMORY |
464 | pEfuseHal->fakeEfuseBank = bank; |
465 | #else |
466 | fakeEfuseBank = bank; |
467 | #endif |
468 | bRet = true; |
469 | } else { |
470 | value32 = rtw_read32(adapter: padapter, EFUSE_TEST); |
471 | bRet = true; |
472 | switch (bank) { |
473 | case 0: |
474 | value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_WIFI_SEL_0); |
475 | break; |
476 | case 1: |
477 | value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_BT_SEL_0); |
478 | break; |
479 | case 2: |
480 | value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_BT_SEL_1); |
481 | break; |
482 | case 3: |
483 | value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_BT_SEL_2); |
484 | break; |
485 | default: |
486 | value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_WIFI_SEL_0); |
487 | bRet = false; |
488 | break; |
489 | } |
490 | rtw_write32(adapter: padapter, EFUSE_TEST, val: value32); |
491 | } |
492 | |
493 | return bRet; |
494 | } |
495 | |
496 | static void Hal_GetEfuseDefinition( |
497 | struct adapter *padapter, |
498 | u8 efuseType, |
499 | u8 type, |
500 | void *pOut, |
501 | bool bPseudoTest |
502 | ) |
503 | { |
504 | switch (type) { |
505 | case TYPE_EFUSE_MAX_SECTION: |
506 | { |
507 | u8 *pMax_section; |
508 | pMax_section = pOut; |
509 | |
510 | if (efuseType == EFUSE_WIFI) |
511 | *pMax_section = EFUSE_MAX_SECTION_8723B; |
512 | else |
513 | *pMax_section = EFUSE_BT_MAX_SECTION; |
514 | } |
515 | break; |
516 | |
517 | case TYPE_EFUSE_REAL_CONTENT_LEN: |
518 | { |
519 | u16 *pu2Tmp; |
520 | pu2Tmp = pOut; |
521 | |
522 | if (efuseType == EFUSE_WIFI) |
523 | *pu2Tmp = EFUSE_REAL_CONTENT_LEN_8723B; |
524 | else |
525 | *pu2Tmp = EFUSE_BT_REAL_CONTENT_LEN; |
526 | } |
527 | break; |
528 | |
529 | case TYPE_AVAILABLE_EFUSE_BYTES_BANK: |
530 | { |
531 | u16 *pu2Tmp; |
532 | pu2Tmp = pOut; |
533 | |
534 | if (efuseType == EFUSE_WIFI) |
535 | *pu2Tmp = (EFUSE_REAL_CONTENT_LEN_8723B-EFUSE_OOB_PROTECT_BYTES); |
536 | else |
537 | *pu2Tmp = (EFUSE_BT_REAL_BANK_CONTENT_LEN-EFUSE_PROTECT_BYTES_BANK); |
538 | } |
539 | break; |
540 | |
541 | case TYPE_AVAILABLE_EFUSE_BYTES_TOTAL: |
542 | { |
543 | u16 *pu2Tmp; |
544 | pu2Tmp = pOut; |
545 | |
546 | if (efuseType == EFUSE_WIFI) |
547 | *pu2Tmp = (EFUSE_REAL_CONTENT_LEN_8723B-EFUSE_OOB_PROTECT_BYTES); |
548 | else |
549 | *pu2Tmp = (EFUSE_BT_REAL_CONTENT_LEN-(EFUSE_PROTECT_BYTES_BANK*3)); |
550 | } |
551 | break; |
552 | |
553 | case TYPE_EFUSE_MAP_LEN: |
554 | { |
555 | u16 *pu2Tmp; |
556 | pu2Tmp = pOut; |
557 | |
558 | if (efuseType == EFUSE_WIFI) |
559 | *pu2Tmp = EFUSE_MAX_MAP_LEN; |
560 | else |
561 | *pu2Tmp = EFUSE_BT_MAP_LEN; |
562 | } |
563 | break; |
564 | |
565 | case TYPE_EFUSE_PROTECT_BYTES_BANK: |
566 | { |
567 | u8 *pu1Tmp; |
568 | pu1Tmp = pOut; |
569 | |
570 | if (efuseType == EFUSE_WIFI) |
571 | *pu1Tmp = EFUSE_OOB_PROTECT_BYTES; |
572 | else |
573 | *pu1Tmp = EFUSE_PROTECT_BYTES_BANK; |
574 | } |
575 | break; |
576 | |
577 | case TYPE_EFUSE_CONTENT_LEN_BANK: |
578 | { |
579 | u16 *pu2Tmp; |
580 | pu2Tmp = pOut; |
581 | |
582 | if (efuseType == EFUSE_WIFI) |
583 | *pu2Tmp = EFUSE_REAL_CONTENT_LEN_8723B; |
584 | else |
585 | *pu2Tmp = EFUSE_BT_REAL_BANK_CONTENT_LEN; |
586 | } |
587 | break; |
588 | |
589 | default: |
590 | { |
591 | u8 *pu1Tmp; |
592 | pu1Tmp = pOut; |
593 | *pu1Tmp = 0; |
594 | } |
595 | break; |
596 | } |
597 | } |
598 | |
599 | #define VOLTAGE_V25 0x03 |
600 | |
601 | /* */ |
602 | /* The following is for compile ok */ |
603 | /* That should be merged with the original in the future */ |
604 | /* */ |
605 | #define EFUSE_ACCESS_ON_8723 0x69 /* For RTL8723 only. */ |
606 | #define REG_EFUSE_ACCESS_8723 0x00CF /* Efuse access protection for RTL8723 */ |
607 | |
608 | /* */ |
609 | static void Hal_BT_EfusePowerSwitch( |
610 | struct adapter *padapter, u8 bWrite, u8 PwrState |
611 | ) |
612 | { |
613 | u8 tempval; |
614 | if (PwrState) { |
615 | /* enable BT power cut */ |
616 | /* 0x6A[14] = 1 */ |
617 | tempval = rtw_read8(adapter: padapter, addr: 0x6B); |
618 | tempval |= BIT(6); |
619 | rtw_write8(adapter: padapter, addr: 0x6B, val: tempval); |
620 | |
621 | /* Attention!! Between 0x6A[14] and 0x6A[15] setting need 100us delay */ |
622 | /* So don't write 0x6A[14]= 1 and 0x6A[15]= 0 together! */ |
623 | msleep(msecs: 1); |
624 | /* disable BT output isolation */ |
625 | /* 0x6A[15] = 0 */ |
626 | tempval = rtw_read8(adapter: padapter, addr: 0x6B); |
627 | tempval &= ~BIT(7); |
628 | rtw_write8(adapter: padapter, addr: 0x6B, val: tempval); |
629 | } else { |
630 | /* enable BT output isolation */ |
631 | /* 0x6A[15] = 1 */ |
632 | tempval = rtw_read8(adapter: padapter, addr: 0x6B); |
633 | tempval |= BIT(7); |
634 | rtw_write8(adapter: padapter, addr: 0x6B, val: tempval); |
635 | |
636 | /* Attention!! Between 0x6A[14] and 0x6A[15] setting need 100us delay */ |
637 | /* So don't write 0x6A[14]= 1 and 0x6A[15]= 0 together! */ |
638 | |
639 | /* disable BT power cut */ |
640 | /* 0x6A[14] = 1 */ |
641 | tempval = rtw_read8(adapter: padapter, addr: 0x6B); |
642 | tempval &= ~BIT(6); |
643 | rtw_write8(adapter: padapter, addr: 0x6B, val: tempval); |
644 | } |
645 | |
646 | } |
647 | static void Hal_EfusePowerSwitch( |
648 | struct adapter *padapter, u8 bWrite, u8 PwrState |
649 | ) |
650 | { |
651 | u8 tempval; |
652 | u16 tmpV16; |
653 | |
654 | |
655 | if (PwrState) { |
656 | /* To avoid cannot access efuse registers after disable/enable several times during DTM test. */ |
657 | /* Suggested by SD1 IsaacHsu. 2013.07.08, added by tynli. */ |
658 | tempval = rtw_read8(adapter: padapter, SDIO_LOCAL_BASE|SDIO_REG_HSUS_CTRL); |
659 | if (tempval & BIT(0)) { /* SDIO local register is suspend */ |
660 | u8 count = 0; |
661 | |
662 | |
663 | tempval &= ~BIT(0); |
664 | rtw_write8(adapter: padapter, SDIO_LOCAL_BASE|SDIO_REG_HSUS_CTRL, val: tempval); |
665 | |
666 | /* check 0x86[1:0]= 10'2h, wait power state to leave suspend */ |
667 | do { |
668 | tempval = rtw_read8(adapter: padapter, SDIO_LOCAL_BASE|SDIO_REG_HSUS_CTRL); |
669 | tempval &= 0x3; |
670 | if (tempval == 0x02) |
671 | break; |
672 | |
673 | count++; |
674 | if (count >= 100) |
675 | break; |
676 | |
677 | mdelay(10); |
678 | } while (1); |
679 | } |
680 | |
681 | rtw_write8(adapter: padapter, REG_EFUSE_ACCESS_8723, EFUSE_ACCESS_ON_8723); |
682 | |
683 | /* Reset: 0x0000h[28], default valid */ |
684 | tmpV16 = rtw_read16(adapter: padapter, REG_SYS_FUNC_EN); |
685 | if (!(tmpV16 & FEN_ELDR)) { |
686 | tmpV16 |= FEN_ELDR; |
687 | rtw_write16(adapter: padapter, REG_SYS_FUNC_EN, val: tmpV16); |
688 | } |
689 | |
690 | /* Clock: Gated(0x0008h[5]) 8M(0x0008h[1]) clock from ANA, default valid */ |
691 | tmpV16 = rtw_read16(adapter: padapter, REG_SYS_CLKR); |
692 | if ((!(tmpV16 & LOADER_CLK_EN)) || (!(tmpV16 & ANA8M))) { |
693 | tmpV16 |= (LOADER_CLK_EN | ANA8M); |
694 | rtw_write16(adapter: padapter, REG_SYS_CLKR, val: tmpV16); |
695 | } |
696 | |
697 | if (bWrite) { |
698 | /* Enable LDO 2.5V before read/write action */ |
699 | tempval = rtw_read8(adapter: padapter, EFUSE_TEST+3); |
700 | tempval &= 0x0F; |
701 | tempval |= (VOLTAGE_V25 << 4); |
702 | rtw_write8(adapter: padapter, EFUSE_TEST+3, val: (tempval | 0x80)); |
703 | |
704 | /* rtw_write8(padapter, REG_EFUSE_ACCESS, EFUSE_ACCESS_ON); */ |
705 | } |
706 | } else { |
707 | rtw_write8(adapter: padapter, REG_EFUSE_ACCESS, EFUSE_ACCESS_OFF); |
708 | |
709 | if (bWrite) { |
710 | /* Disable LDO 2.5V after read/write action */ |
711 | tempval = rtw_read8(adapter: padapter, EFUSE_TEST+3); |
712 | rtw_write8(adapter: padapter, EFUSE_TEST+3, val: (tempval & 0x7F)); |
713 | } |
714 | |
715 | } |
716 | } |
717 | |
718 | static void hal_ReadEFuse_WiFi( |
719 | struct adapter *padapter, |
720 | u16 _offset, |
721 | u16 _size_byte, |
722 | u8 *pbuf, |
723 | bool bPseudoTest |
724 | ) |
725 | { |
726 | #ifdef HAL_EFUSE_MEMORY |
727 | struct hal_com_data *pHalData = GET_HAL_DATA(padapter); |
728 | struct efuse_hal *pEfuseHal = &pHalData->EfuseHal; |
729 | #endif |
730 | u8 *efuseTbl = NULL; |
731 | u16 eFuse_Addr = 0; |
732 | u8 offset, wden; |
733 | u8 , efuseExtHdr, efuseData; |
734 | u16 i, total, used; |
735 | u8 efuse_usage = 0; |
736 | |
737 | /* */ |
738 | /* Do NOT excess total size of EFuse table. Added by Roger, 2008.11.10. */ |
739 | /* */ |
740 | if ((_offset + _size_byte) > EFUSE_MAX_MAP_LEN) |
741 | return; |
742 | |
743 | efuseTbl = rtw_malloc(EFUSE_MAX_MAP_LEN); |
744 | if (!efuseTbl) |
745 | return; |
746 | |
747 | /* 0xff will be efuse default value instead of 0x00. */ |
748 | memset(efuseTbl, 0xFF, EFUSE_MAX_MAP_LEN); |
749 | |
750 | /* switch bank back to bank 0 for later BT and wifi use. */ |
751 | hal_EfuseSwitchToBank(padapter, bank: 0, bPseudoTest); |
752 | |
753 | while (AVAILABLE_EFUSE_ADDR(eFuse_Addr)) { |
754 | efuse_OneByteRead(padapter, addr: eFuse_Addr++, data: &efuseHeader, bPseudoTest); |
755 | if (efuseHeader == 0xFF) |
756 | break; |
757 | |
758 | /* Check PG header for section num. */ |
759 | if (EXT_HEADER(efuseHeader)) { /* extended header */ |
760 | offset = GET_HDR_OFFSET_2_0(efuseHeader); |
761 | |
762 | efuse_OneByteRead(padapter, addr: eFuse_Addr++, data: &efuseExtHdr, bPseudoTest); |
763 | if (ALL_WORDS_DISABLED(efuseExtHdr)) |
764 | continue; |
765 | |
766 | offset |= ((efuseExtHdr & 0xF0) >> 1); |
767 | wden = (efuseExtHdr & 0x0F); |
768 | } else { |
769 | offset = ((efuseHeader >> 4) & 0x0f); |
770 | wden = (efuseHeader & 0x0f); |
771 | } |
772 | |
773 | if (offset < EFUSE_MAX_SECTION_8723B) { |
774 | u16 addr; |
775 | /* Get word enable value from PG header */ |
776 | |
777 | addr = offset * PGPKT_DATA_SIZE; |
778 | for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) { |
779 | /* Check word enable condition in the section */ |
780 | if (!(wden & (0x01<<i))) { |
781 | efuse_OneByteRead(padapter, addr: eFuse_Addr++, data: &efuseData, bPseudoTest); |
782 | efuseTbl[addr] = efuseData; |
783 | |
784 | efuse_OneByteRead(padapter, addr: eFuse_Addr++, data: &efuseData, bPseudoTest); |
785 | efuseTbl[addr+1] = efuseData; |
786 | } |
787 | addr += 2; |
788 | } |
789 | } else { |
790 | eFuse_Addr += Efuse_CalculateWordCnts(word_en: wden)*2; |
791 | } |
792 | } |
793 | |
794 | /* Copy from Efuse map to output pointer memory!!! */ |
795 | for (i = 0; i < _size_byte; i++) |
796 | pbuf[i] = efuseTbl[_offset+i]; |
797 | |
798 | /* Calculate Efuse utilization */ |
799 | EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, type: TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, pOut: &total, bPseudoTest); |
800 | used = eFuse_Addr - 1; |
801 | efuse_usage = (u8)((used*100)/total); |
802 | if (bPseudoTest) { |
803 | #ifdef HAL_EFUSE_MEMORY |
804 | pEfuseHal->fakeEfuseUsedBytes = used; |
805 | #else |
806 | fakeEfuseUsedBytes = used; |
807 | #endif |
808 | } else { |
809 | rtw_hal_set_hwreg(padapter, variable: HW_VAR_EFUSE_BYTES, val: (u8 *)&used); |
810 | rtw_hal_set_hwreg(padapter, variable: HW_VAR_EFUSE_USAGE, val: (u8 *)&efuse_usage); |
811 | } |
812 | |
813 | kfree(objp: efuseTbl); |
814 | } |
815 | |
816 | static void hal_ReadEFuse_BT( |
817 | struct adapter *padapter, |
818 | u16 _offset, |
819 | u16 _size_byte, |
820 | u8 *pbuf, |
821 | bool bPseudoTest |
822 | ) |
823 | { |
824 | #ifdef HAL_EFUSE_MEMORY |
825 | struct hal_com_data *pHalData = GET_HAL_DATA(padapter); |
826 | struct efuse_hal *pEfuseHal = &pHalData->EfuseHal; |
827 | #endif |
828 | u8 *efuseTbl; |
829 | u8 bank; |
830 | u16 eFuse_Addr; |
831 | u8 , efuseExtHdr, efuseData; |
832 | u8 offset, wden; |
833 | u16 i, total, used; |
834 | u8 efuse_usage; |
835 | |
836 | |
837 | /* */ |
838 | /* Do NOT excess total size of EFuse table. Added by Roger, 2008.11.10. */ |
839 | /* */ |
840 | if ((_offset + _size_byte) > EFUSE_BT_MAP_LEN) |
841 | return; |
842 | |
843 | efuseTbl = rtw_malloc(EFUSE_BT_MAP_LEN); |
844 | if (!efuseTbl) |
845 | return; |
846 | |
847 | /* 0xff will be efuse default value instead of 0x00. */ |
848 | memset(efuseTbl, 0xFF, EFUSE_BT_MAP_LEN); |
849 | |
850 | EFUSE_GetEfuseDefinition(padapter, EFUSE_BT, type: TYPE_AVAILABLE_EFUSE_BYTES_BANK, pOut: &total, bPseudoTest); |
851 | |
852 | for (bank = 1; bank < 3; bank++) { /* 8723b Max bake 0~2 */ |
853 | if (hal_EfuseSwitchToBank(padapter, bank, bPseudoTest) == false) |
854 | goto exit; |
855 | |
856 | eFuse_Addr = 0; |
857 | |
858 | while (AVAILABLE_EFUSE_ADDR(eFuse_Addr)) { |
859 | efuse_OneByteRead(padapter, addr: eFuse_Addr++, data: &efuseHeader, bPseudoTest); |
860 | if (efuseHeader == 0xFF) |
861 | break; |
862 | |
863 | /* Check PG header for section num. */ |
864 | if (EXT_HEADER(efuseHeader)) { /* extended header */ |
865 | offset = GET_HDR_OFFSET_2_0(efuseHeader); |
866 | |
867 | efuse_OneByteRead(padapter, addr: eFuse_Addr++, data: &efuseExtHdr, bPseudoTest); |
868 | if (ALL_WORDS_DISABLED(efuseExtHdr)) |
869 | continue; |
870 | |
871 | |
872 | offset |= ((efuseExtHdr & 0xF0) >> 1); |
873 | wden = (efuseExtHdr & 0x0F); |
874 | } else { |
875 | offset = ((efuseHeader >> 4) & 0x0f); |
876 | wden = (efuseHeader & 0x0f); |
877 | } |
878 | |
879 | if (offset < EFUSE_BT_MAX_SECTION) { |
880 | u16 addr; |
881 | |
882 | addr = offset * PGPKT_DATA_SIZE; |
883 | for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) { |
884 | /* Check word enable condition in the section */ |
885 | if (!(wden & (0x01<<i))) { |
886 | efuse_OneByteRead(padapter, addr: eFuse_Addr++, data: &efuseData, bPseudoTest); |
887 | efuseTbl[addr] = efuseData; |
888 | |
889 | efuse_OneByteRead(padapter, addr: eFuse_Addr++, data: &efuseData, bPseudoTest); |
890 | efuseTbl[addr+1] = efuseData; |
891 | } |
892 | addr += 2; |
893 | } |
894 | } else { |
895 | eFuse_Addr += Efuse_CalculateWordCnts(word_en: wden)*2; |
896 | } |
897 | } |
898 | |
899 | if ((eFuse_Addr - 1) < total) |
900 | break; |
901 | |
902 | } |
903 | |
904 | /* switch bank back to bank 0 for later BT and wifi use. */ |
905 | hal_EfuseSwitchToBank(padapter, bank: 0, bPseudoTest); |
906 | |
907 | /* Copy from Efuse map to output pointer memory!!! */ |
908 | for (i = 0; i < _size_byte; i++) |
909 | pbuf[i] = efuseTbl[_offset+i]; |
910 | |
911 | /* */ |
912 | /* Calculate Efuse utilization. */ |
913 | /* */ |
914 | EFUSE_GetEfuseDefinition(padapter, EFUSE_BT, type: TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, pOut: &total, bPseudoTest); |
915 | used = (EFUSE_BT_REAL_BANK_CONTENT_LEN*(bank-1)) + eFuse_Addr - 1; |
916 | efuse_usage = (u8)((used*100)/total); |
917 | if (bPseudoTest) { |
918 | #ifdef HAL_EFUSE_MEMORY |
919 | pEfuseHal->fakeBTEfuseUsedBytes = used; |
920 | #else |
921 | fakeBTEfuseUsedBytes = used; |
922 | #endif |
923 | } else { |
924 | rtw_hal_set_hwreg(padapter, variable: HW_VAR_EFUSE_BT_BYTES, val: (u8 *)&used); |
925 | rtw_hal_set_hwreg(padapter, variable: HW_VAR_EFUSE_BT_USAGE, val: (u8 *)&efuse_usage); |
926 | } |
927 | |
928 | exit: |
929 | kfree(objp: efuseTbl); |
930 | } |
931 | |
932 | static void Hal_ReadEFuse( |
933 | struct adapter *padapter, |
934 | u8 efuseType, |
935 | u16 _offset, |
936 | u16 _size_byte, |
937 | u8 *pbuf, |
938 | bool bPseudoTest |
939 | ) |
940 | { |
941 | if (efuseType == EFUSE_WIFI) |
942 | hal_ReadEFuse_WiFi(padapter, _offset, _size_byte, pbuf, bPseudoTest); |
943 | else |
944 | hal_ReadEFuse_BT(padapter, _offset, _size_byte, pbuf, bPseudoTest); |
945 | } |
946 | |
947 | static u16 hal_EfuseGetCurrentSize_WiFi( |
948 | struct adapter *padapter, bool bPseudoTest |
949 | ) |
950 | { |
951 | #ifdef HAL_EFUSE_MEMORY |
952 | struct hal_com_data *pHalData = GET_HAL_DATA(padapter); |
953 | struct efuse_hal *pEfuseHal = &pHalData->EfuseHal; |
954 | #endif |
955 | u16 efuse_addr = 0; |
956 | u16 start_addr = 0; /* for debug */ |
957 | u8 hworden = 0; |
958 | u8 efuse_data, word_cnts = 0; |
959 | u32 count = 0; /* for debug */ |
960 | |
961 | |
962 | if (bPseudoTest) { |
963 | #ifdef HAL_EFUSE_MEMORY |
964 | efuse_addr = (u16)pEfuseHal->fakeEfuseUsedBytes; |
965 | #else |
966 | efuse_addr = (u16)fakeEfuseUsedBytes; |
967 | #endif |
968 | } else |
969 | rtw_hal_get_hwreg(padapter, variable: HW_VAR_EFUSE_BYTES, val: (u8 *)&efuse_addr); |
970 | |
971 | start_addr = efuse_addr; |
972 | |
973 | /* switch bank back to bank 0 for later BT and wifi use. */ |
974 | hal_EfuseSwitchToBank(padapter, bank: 0, bPseudoTest); |
975 | |
976 | count = 0; |
977 | while (AVAILABLE_EFUSE_ADDR(efuse_addr)) { |
978 | if (efuse_OneByteRead(padapter, addr: efuse_addr, data: &efuse_data, bPseudoTest) == false) |
979 | goto error; |
980 | |
981 | if (efuse_data == 0xFF) |
982 | break; |
983 | |
984 | if ((start_addr != 0) && (efuse_addr == start_addr)) { |
985 | count++; |
986 | |
987 | efuse_data = 0xFF; |
988 | if (count < 4) { |
989 | /* try again! */ |
990 | |
991 | if (count > 2) { |
992 | /* try again form address 0 */ |
993 | efuse_addr = 0; |
994 | start_addr = 0; |
995 | } |
996 | |
997 | continue; |
998 | } |
999 | |
1000 | goto error; |
1001 | } |
1002 | |
1003 | if (EXT_HEADER(efuse_data)) { |
1004 | efuse_addr++; |
1005 | efuse_OneByteRead(padapter, addr: efuse_addr, data: &efuse_data, bPseudoTest); |
1006 | if (ALL_WORDS_DISABLED(efuse_data)) |
1007 | continue; |
1008 | |
1009 | hworden = efuse_data & 0x0F; |
1010 | } else { |
1011 | hworden = efuse_data & 0x0F; |
1012 | } |
1013 | |
1014 | word_cnts = Efuse_CalculateWordCnts(word_en: hworden); |
1015 | efuse_addr += (word_cnts*2)+1; |
1016 | } |
1017 | |
1018 | if (bPseudoTest) { |
1019 | #ifdef HAL_EFUSE_MEMORY |
1020 | pEfuseHal->fakeEfuseUsedBytes = efuse_addr; |
1021 | #else |
1022 | fakeEfuseUsedBytes = efuse_addr; |
1023 | #endif |
1024 | } else |
1025 | rtw_hal_set_hwreg(padapter, variable: HW_VAR_EFUSE_BYTES, val: (u8 *)&efuse_addr); |
1026 | |
1027 | goto exit; |
1028 | |
1029 | error: |
1030 | /* report max size to prevent write efuse */ |
1031 | EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, type: TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, pOut: &efuse_addr, bPseudoTest); |
1032 | |
1033 | exit: |
1034 | |
1035 | return efuse_addr; |
1036 | } |
1037 | |
1038 | static u16 hal_EfuseGetCurrentSize_BT(struct adapter *padapter, u8 bPseudoTest) |
1039 | { |
1040 | #ifdef HAL_EFUSE_MEMORY |
1041 | struct hal_com_data *pHalData = GET_HAL_DATA(padapter); |
1042 | struct efuse_hal *pEfuseHal = &pHalData->EfuseHal; |
1043 | #endif |
1044 | u16 btusedbytes; |
1045 | u16 efuse_addr; |
1046 | u8 bank, startBank; |
1047 | u8 hworden = 0; |
1048 | u8 efuse_data, word_cnts = 0; |
1049 | u16 retU2 = 0; |
1050 | |
1051 | if (bPseudoTest) { |
1052 | #ifdef HAL_EFUSE_MEMORY |
1053 | btusedbytes = pEfuseHal->fakeBTEfuseUsedBytes; |
1054 | #else |
1055 | btusedbytes = fakeBTEfuseUsedBytes; |
1056 | #endif |
1057 | } else |
1058 | rtw_hal_get_hwreg(padapter, variable: HW_VAR_EFUSE_BT_BYTES, val: (u8 *)&btusedbytes); |
1059 | |
1060 | efuse_addr = (u16)((btusedbytes%EFUSE_BT_REAL_BANK_CONTENT_LEN)); |
1061 | startBank = (u8)(1+(btusedbytes/EFUSE_BT_REAL_BANK_CONTENT_LEN)); |
1062 | |
1063 | EFUSE_GetEfuseDefinition(padapter, EFUSE_BT, type: TYPE_AVAILABLE_EFUSE_BYTES_BANK, pOut: &retU2, bPseudoTest); |
1064 | |
1065 | for (bank = startBank; bank < 3; bank++) { |
1066 | if (hal_EfuseSwitchToBank(padapter, bank, bPseudoTest) == false) |
1067 | /* bank = EFUSE_MAX_BANK; */ |
1068 | break; |
1069 | |
1070 | /* only when bank is switched we have to reset the efuse_addr. */ |
1071 | if (bank != startBank) |
1072 | efuse_addr = 0; |
1073 | #if 1 |
1074 | |
1075 | while (AVAILABLE_EFUSE_ADDR(efuse_addr)) { |
1076 | if (efuse_OneByteRead(padapter, addr: efuse_addr, |
1077 | data: &efuse_data, bPseudoTest) == false) |
1078 | /* bank = EFUSE_MAX_BANK; */ |
1079 | break; |
1080 | |
1081 | if (efuse_data == 0xFF) |
1082 | break; |
1083 | |
1084 | if (EXT_HEADER(efuse_data)) { |
1085 | efuse_addr++; |
1086 | efuse_OneByteRead(padapter, addr: efuse_addr, data: &efuse_data, bPseudoTest); |
1087 | |
1088 | if (ALL_WORDS_DISABLED(efuse_data)) { |
1089 | efuse_addr++; |
1090 | continue; |
1091 | } |
1092 | |
1093 | hworden = efuse_data & 0x0F; |
1094 | } else { |
1095 | hworden = efuse_data & 0x0F; |
1096 | } |
1097 | |
1098 | word_cnts = Efuse_CalculateWordCnts(word_en: hworden); |
1099 | /* read next header */ |
1100 | efuse_addr += (word_cnts*2)+1; |
1101 | } |
1102 | #else |
1103 | while ( |
1104 | bContinual && |
1105 | efuse_OneByteRead(padapter, efuse_addr, &efuse_data, bPseudoTest) && |
1106 | AVAILABLE_EFUSE_ADDR(efuse_addr) |
1107 | ) { |
1108 | if (efuse_data != 0xFF) { |
1109 | if ((efuse_data&0x1F) == 0x0F) { /* extended header */ |
1110 | efuse_addr++; |
1111 | efuse_OneByteRead(padapter, efuse_addr, &efuse_data, bPseudoTest); |
1112 | if ((efuse_data & 0x0F) == 0x0F) { |
1113 | efuse_addr++; |
1114 | continue; |
1115 | } else { |
1116 | hworden = efuse_data & 0x0F; |
1117 | } |
1118 | } else { |
1119 | hworden = efuse_data & 0x0F; |
1120 | } |
1121 | word_cnts = Efuse_CalculateWordCnts(hworden); |
1122 | /* read next header */ |
1123 | efuse_addr = efuse_addr + (word_cnts*2)+1; |
1124 | } else |
1125 | bContinual = false; |
1126 | } |
1127 | #endif |
1128 | |
1129 | |
1130 | /* Check if we need to check next bank efuse */ |
1131 | if (efuse_addr < retU2) |
1132 | break; /* don't need to check next bank. */ |
1133 | } |
1134 | |
1135 | retU2 = ((bank-1)*EFUSE_BT_REAL_BANK_CONTENT_LEN)+efuse_addr; |
1136 | if (bPseudoTest) { |
1137 | pEfuseHal->fakeBTEfuseUsedBytes = retU2; |
1138 | } else { |
1139 | pEfuseHal->BTEfuseUsedBytes = retU2; |
1140 | } |
1141 | |
1142 | return retU2; |
1143 | } |
1144 | |
1145 | static u16 Hal_EfuseGetCurrentSize( |
1146 | struct adapter *padapter, u8 efuseType, bool bPseudoTest |
1147 | ) |
1148 | { |
1149 | u16 ret = 0; |
1150 | |
1151 | if (efuseType == EFUSE_WIFI) |
1152 | ret = hal_EfuseGetCurrentSize_WiFi(padapter, bPseudoTest); |
1153 | else |
1154 | ret = hal_EfuseGetCurrentSize_BT(padapter, bPseudoTest); |
1155 | |
1156 | return ret; |
1157 | } |
1158 | |
1159 | static u8 Hal_EfuseWordEnableDataWrite( |
1160 | struct adapter *padapter, |
1161 | u16 efuse_addr, |
1162 | u8 word_en, |
1163 | u8 *data, |
1164 | bool bPseudoTest |
1165 | ) |
1166 | { |
1167 | u16 tmpaddr = 0; |
1168 | u16 start_addr = efuse_addr; |
1169 | u8 badworden = 0x0F; |
1170 | u8 tmpdata[PGPKT_DATA_SIZE]; |
1171 | |
1172 | memset(tmpdata, 0xFF, PGPKT_DATA_SIZE); |
1173 | |
1174 | if (!(word_en & BIT(0))) { |
1175 | tmpaddr = start_addr; |
1176 | efuse_OneByteWrite(padapter, addr: start_addr++, data: data[0], bPseudoTest); |
1177 | efuse_OneByteWrite(padapter, addr: start_addr++, data: data[1], bPseudoTest); |
1178 | |
1179 | efuse_OneByteRead(padapter, addr: tmpaddr, data: &tmpdata[0], bPseudoTest); |
1180 | efuse_OneByteRead(padapter, addr: tmpaddr+1, data: &tmpdata[1], bPseudoTest); |
1181 | if ((data[0] != tmpdata[0]) || (data[1] != tmpdata[1])) { |
1182 | badworden &= (~BIT(0)); |
1183 | } |
1184 | } |
1185 | if (!(word_en & BIT(1))) { |
1186 | tmpaddr = start_addr; |
1187 | efuse_OneByteWrite(padapter, addr: start_addr++, data: data[2], bPseudoTest); |
1188 | efuse_OneByteWrite(padapter, addr: start_addr++, data: data[3], bPseudoTest); |
1189 | |
1190 | efuse_OneByteRead(padapter, addr: tmpaddr, data: &tmpdata[2], bPseudoTest); |
1191 | efuse_OneByteRead(padapter, addr: tmpaddr+1, data: &tmpdata[3], bPseudoTest); |
1192 | if ((data[2] != tmpdata[2]) || (data[3] != tmpdata[3])) { |
1193 | badworden &= (~BIT(1)); |
1194 | } |
1195 | } |
1196 | |
1197 | if (!(word_en & BIT(2))) { |
1198 | tmpaddr = start_addr; |
1199 | efuse_OneByteWrite(padapter, addr: start_addr++, data: data[4], bPseudoTest); |
1200 | efuse_OneByteWrite(padapter, addr: start_addr++, data: data[5], bPseudoTest); |
1201 | |
1202 | efuse_OneByteRead(padapter, addr: tmpaddr, data: &tmpdata[4], bPseudoTest); |
1203 | efuse_OneByteRead(padapter, addr: tmpaddr+1, data: &tmpdata[5], bPseudoTest); |
1204 | if ((data[4] != tmpdata[4]) || (data[5] != tmpdata[5])) { |
1205 | badworden &= (~BIT(2)); |
1206 | } |
1207 | } |
1208 | |
1209 | if (!(word_en & BIT(3))) { |
1210 | tmpaddr = start_addr; |
1211 | efuse_OneByteWrite(padapter, addr: start_addr++, data: data[6], bPseudoTest); |
1212 | efuse_OneByteWrite(padapter, addr: start_addr++, data: data[7], bPseudoTest); |
1213 | |
1214 | efuse_OneByteRead(padapter, addr: tmpaddr, data: &tmpdata[6], bPseudoTest); |
1215 | efuse_OneByteRead(padapter, addr: tmpaddr+1, data: &tmpdata[7], bPseudoTest); |
1216 | if ((data[6] != tmpdata[6]) || (data[7] != tmpdata[7])) { |
1217 | badworden &= (~BIT(3)); |
1218 | } |
1219 | } |
1220 | |
1221 | return badworden; |
1222 | } |
1223 | |
1224 | static s32 Hal_EfusePgPacketRead( |
1225 | struct adapter *padapter, |
1226 | u8 offset, |
1227 | u8 *data, |
1228 | bool bPseudoTest |
1229 | ) |
1230 | { |
1231 | u8 efuse_data, word_cnts = 0; |
1232 | u16 efuse_addr = 0; |
1233 | u8 hoffset = 0, hworden = 0; |
1234 | u8 i; |
1235 | u8 max_section = 0; |
1236 | s32 ret; |
1237 | |
1238 | |
1239 | if (!data) |
1240 | return false; |
1241 | |
1242 | EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, type: TYPE_EFUSE_MAX_SECTION, pOut: &max_section, bPseudoTest); |
1243 | if (offset > max_section) |
1244 | return false; |
1245 | |
1246 | memset(data, 0xFF, PGPKT_DATA_SIZE); |
1247 | ret = true; |
1248 | |
1249 | /* */ |
1250 | /* <Roger_TODO> Efuse has been pre-programmed dummy 5Bytes at the end of Efuse by CP. */ |
1251 | /* Skip dummy parts to prevent unexpected data read from Efuse. */ |
1252 | /* By pass right now. 2009.02.19. */ |
1253 | /* */ |
1254 | while (AVAILABLE_EFUSE_ADDR(efuse_addr)) { |
1255 | if (efuse_OneByteRead(padapter, addr: efuse_addr++, data: &efuse_data, bPseudoTest) == false) { |
1256 | ret = false; |
1257 | break; |
1258 | } |
1259 | |
1260 | if (efuse_data == 0xFF) |
1261 | break; |
1262 | |
1263 | if (EXT_HEADER(efuse_data)) { |
1264 | hoffset = GET_HDR_OFFSET_2_0(efuse_data); |
1265 | efuse_OneByteRead(padapter, addr: efuse_addr++, data: &efuse_data, bPseudoTest); |
1266 | if (ALL_WORDS_DISABLED(efuse_data)) |
1267 | continue; |
1268 | |
1269 | hoffset |= ((efuse_data & 0xF0) >> 1); |
1270 | hworden = efuse_data & 0x0F; |
1271 | } else { |
1272 | hoffset = (efuse_data>>4) & 0x0F; |
1273 | hworden = efuse_data & 0x0F; |
1274 | } |
1275 | |
1276 | if (hoffset == offset) { |
1277 | for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) { |
1278 | /* Check word enable condition in the section */ |
1279 | if (!(hworden & (0x01<<i))) { |
1280 | efuse_OneByteRead(padapter, addr: efuse_addr++, data: &efuse_data, bPseudoTest); |
1281 | data[i*2] = efuse_data; |
1282 | |
1283 | efuse_OneByteRead(padapter, addr: efuse_addr++, data: &efuse_data, bPseudoTest); |
1284 | data[(i*2)+1] = efuse_data; |
1285 | } |
1286 | } |
1287 | } else { |
1288 | word_cnts = Efuse_CalculateWordCnts(word_en: hworden); |
1289 | efuse_addr += word_cnts*2; |
1290 | } |
1291 | } |
1292 | |
1293 | return ret; |
1294 | } |
1295 | |
1296 | static u8 hal_EfusePgCheckAvailableAddr( |
1297 | struct adapter *padapter, u8 efuseType, u8 bPseudoTest |
1298 | ) |
1299 | { |
1300 | u16 max_available = 0; |
1301 | u16 current_size; |
1302 | |
1303 | |
1304 | EFUSE_GetEfuseDefinition(padapter, efuseType, type: TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, pOut: &max_available, bPseudoTest); |
1305 | |
1306 | current_size = Efuse_GetCurrentSize(padapter, efuseType, bPseudoTest); |
1307 | if (current_size >= max_available) |
1308 | return false; |
1309 | |
1310 | return true; |
1311 | } |
1312 | |
1313 | static void hal_EfuseConstructPGPkt( |
1314 | u8 offset, |
1315 | u8 word_en, |
1316 | u8 *pData, |
1317 | struct pgpkt_struct *pTargetPkt |
1318 | ) |
1319 | { |
1320 | memset(pTargetPkt->data, 0xFF, PGPKT_DATA_SIZE); |
1321 | pTargetPkt->offset = offset; |
1322 | pTargetPkt->word_en = word_en; |
1323 | efuse_WordEnableDataRead(word_en, sourdata: pData, targetdata: pTargetPkt->data); |
1324 | pTargetPkt->word_cnts = Efuse_CalculateWordCnts(word_en: pTargetPkt->word_en); |
1325 | } |
1326 | |
1327 | static u8 hal_EfusePartialWriteCheck( |
1328 | struct adapter *padapter, |
1329 | u8 efuseType, |
1330 | u16 *pAddr, |
1331 | struct pgpkt_struct *pTargetPkt, |
1332 | u8 bPseudoTest |
1333 | ) |
1334 | { |
1335 | struct hal_com_data *pHalData = GET_HAL_DATA(padapter); |
1336 | struct efuse_hal *pEfuseHal = &pHalData->EfuseHal; |
1337 | u8 bRet = false; |
1338 | u16 startAddr = 0, efuse_max_available_len = 0, efuse_max = 0; |
1339 | u8 efuse_data = 0; |
1340 | |
1341 | EFUSE_GetEfuseDefinition(padapter, efuseType, type: TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, pOut: &efuse_max_available_len, bPseudoTest); |
1342 | EFUSE_GetEfuseDefinition(padapter, efuseType, type: TYPE_EFUSE_CONTENT_LEN_BANK, pOut: &efuse_max, bPseudoTest); |
1343 | |
1344 | if (efuseType == EFUSE_WIFI) { |
1345 | if (bPseudoTest) { |
1346 | #ifdef HAL_EFUSE_MEMORY |
1347 | startAddr = (u16)pEfuseHal->fakeEfuseUsedBytes; |
1348 | #else |
1349 | startAddr = (u16)fakeEfuseUsedBytes; |
1350 | #endif |
1351 | } else |
1352 | rtw_hal_get_hwreg(padapter, variable: HW_VAR_EFUSE_BYTES, val: (u8 *)&startAddr); |
1353 | } else { |
1354 | if (bPseudoTest) { |
1355 | #ifdef HAL_EFUSE_MEMORY |
1356 | startAddr = (u16)pEfuseHal->fakeBTEfuseUsedBytes; |
1357 | #else |
1358 | startAddr = (u16)fakeBTEfuseUsedBytes; |
1359 | #endif |
1360 | } else |
1361 | rtw_hal_get_hwreg(padapter, variable: HW_VAR_EFUSE_BT_BYTES, val: (u8 *)&startAddr); |
1362 | } |
1363 | startAddr %= efuse_max; |
1364 | |
1365 | while (1) { |
1366 | if (startAddr >= efuse_max_available_len) { |
1367 | bRet = false; |
1368 | break; |
1369 | } |
1370 | |
1371 | if (efuse_OneByteRead(padapter, addr: startAddr, data: &efuse_data, bPseudoTest) && (efuse_data != 0xFF)) { |
1372 | #if 1 |
1373 | bRet = false; |
1374 | break; |
1375 | #else |
1376 | if (EXT_HEADER(efuse_data)) { |
1377 | cur_header = efuse_data; |
1378 | startAddr++; |
1379 | efuse_OneByteRead(padapter, startAddr, &efuse_data, bPseudoTest); |
1380 | if (ALL_WORDS_DISABLED(efuse_data)) { |
1381 | bRet = false; |
1382 | break; |
1383 | } else { |
1384 | curPkt.offset = ((cur_header & 0xE0) >> 5) | ((efuse_data & 0xF0) >> 1); |
1385 | curPkt.word_en = efuse_data & 0x0F; |
1386 | } |
1387 | } else { |
1388 | cur_header = efuse_data; |
1389 | curPkt.offset = (cur_header>>4) & 0x0F; |
1390 | curPkt.word_en = cur_header & 0x0F; |
1391 | } |
1392 | |
1393 | curPkt.word_cnts = Efuse_CalculateWordCnts(curPkt.word_en); |
1394 | /* if same header is found but no data followed */ |
1395 | /* write some part of data followed by the header. */ |
1396 | if ( |
1397 | (curPkt.offset == pTargetPkt->offset) && |
1398 | (hal_EfuseCheckIfDatafollowed(padapter, curPkt.word_cnts, startAddr+1, bPseudoTest) == false) && |
1399 | wordEnMatched(pTargetPkt, &curPkt, &matched_wden) == true |
1400 | ) { |
1401 | /* Here to write partial data */ |
1402 | badworden = Efuse_WordEnableDataWrite(padapter, startAddr+1, matched_wden, pTargetPkt->data, bPseudoTest); |
1403 | if (badworden != 0x0F) { |
1404 | u32 PgWriteSuccess = 0; |
1405 | /* if write fail on some words, write these bad words again */ |
1406 | if (efuseType == EFUSE_WIFI) |
1407 | PgWriteSuccess = Efuse_PgPacketWrite(padapter, pTargetPkt->offset, badworden, pTargetPkt->data, bPseudoTest); |
1408 | else |
1409 | PgWriteSuccess = Efuse_PgPacketWrite_BT(padapter, pTargetPkt->offset, badworden, pTargetPkt->data, bPseudoTest); |
1410 | |
1411 | if (!PgWriteSuccess) { |
1412 | bRet = false; /* write fail, return */ |
1413 | break; |
1414 | } |
1415 | } |
1416 | /* partial write ok, update the target packet for later use */ |
1417 | for (i = 0; i < 4; i++) { |
1418 | if ((matched_wden & (0x1<<i)) == 0) { /* this word has been written */ |
1419 | pTargetPkt->word_en |= (0x1<<i); /* disable the word */ |
1420 | } |
1421 | } |
1422 | pTargetPkt->word_cnts = Efuse_CalculateWordCnts(pTargetPkt->word_en); |
1423 | } |
1424 | /* read from next header */ |
1425 | startAddr = startAddr + (curPkt.word_cnts*2) + 1; |
1426 | #endif |
1427 | } else { |
1428 | /* not used header, 0xff */ |
1429 | *pAddr = startAddr; |
1430 | bRet = true; |
1431 | break; |
1432 | } |
1433 | } |
1434 | |
1435 | return bRet; |
1436 | } |
1437 | |
1438 | static u8 ( |
1439 | struct adapter *padapter, |
1440 | u8 efuseType, |
1441 | u16 *pAddr, |
1442 | struct pgpkt_struct *pTargetPkt, |
1443 | u8 bPseudoTest |
1444 | ) |
1445 | { |
1446 | u8 = 0, = 0; |
1447 | u16 efuse_addr = *pAddr; |
1448 | u8 repeatcnt = 0; |
1449 | |
1450 | pg_header = ((pTargetPkt->offset << 4) & 0xf0) | pTargetPkt->word_en; |
1451 | |
1452 | do { |
1453 | efuse_OneByteWrite(padapter, addr: efuse_addr, data: pg_header, bPseudoTest); |
1454 | efuse_OneByteRead(padapter, addr: efuse_addr, data: &tmp_header, bPseudoTest); |
1455 | if (tmp_header != 0xFF) |
1456 | break; |
1457 | if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) |
1458 | return false; |
1459 | |
1460 | } while (1); |
1461 | |
1462 | if (tmp_header != pg_header) |
1463 | return false; |
1464 | |
1465 | *pAddr = efuse_addr; |
1466 | |
1467 | return true; |
1468 | } |
1469 | |
1470 | static u8 ( |
1471 | struct adapter *padapter, |
1472 | u8 efuseType, |
1473 | u16 *pAddr, |
1474 | struct pgpkt_struct *pTargetPkt, |
1475 | u8 bPseudoTest |
1476 | ) |
1477 | { |
1478 | u16 efuse_addr, efuse_max_available_len = 0; |
1479 | u8 = 0, = 0; |
1480 | u8 repeatcnt = 0; |
1481 | |
1482 | EFUSE_GetEfuseDefinition(padapter, efuseType, type: TYPE_AVAILABLE_EFUSE_BYTES_BANK, pOut: &efuse_max_available_len, bPseudoTest); |
1483 | |
1484 | efuse_addr = *pAddr; |
1485 | if (efuse_addr >= efuse_max_available_len) |
1486 | return false; |
1487 | |
1488 | pg_header = ((pTargetPkt->offset & 0x07) << 5) | 0x0F; |
1489 | |
1490 | do { |
1491 | efuse_OneByteWrite(padapter, addr: efuse_addr, data: pg_header, bPseudoTest); |
1492 | efuse_OneByteRead(padapter, addr: efuse_addr, data: &tmp_header, bPseudoTest); |
1493 | if (tmp_header != 0xFF) |
1494 | break; |
1495 | if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) |
1496 | return false; |
1497 | |
1498 | } while (1); |
1499 | |
1500 | if (tmp_header != pg_header) |
1501 | return false; |
1502 | |
1503 | /* to write ext_header */ |
1504 | efuse_addr++; |
1505 | pg_header = ((pTargetPkt->offset & 0x78) << 1) | pTargetPkt->word_en; |
1506 | |
1507 | do { |
1508 | efuse_OneByteWrite(padapter, addr: efuse_addr, data: pg_header, bPseudoTest); |
1509 | efuse_OneByteRead(padapter, addr: efuse_addr, data: &tmp_header, bPseudoTest); |
1510 | if (tmp_header != 0xFF) |
1511 | break; |
1512 | if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) |
1513 | return false; |
1514 | |
1515 | } while (1); |
1516 | |
1517 | if (tmp_header != pg_header) /* offset PG fail */ |
1518 | return false; |
1519 | |
1520 | *pAddr = efuse_addr; |
1521 | |
1522 | return true; |
1523 | } |
1524 | |
1525 | static u8 ( |
1526 | struct adapter *padapter, |
1527 | u8 efuseType, |
1528 | u16 *pAddr, |
1529 | struct pgpkt_struct *pTargetPkt, |
1530 | u8 bPseudoTest |
1531 | ) |
1532 | { |
1533 | u8 bRet = false; |
1534 | |
1535 | if (pTargetPkt->offset >= EFUSE_MAX_SECTION_BASE) |
1536 | bRet = hal_EfusePgPacketWrite2ByteHeader(padapter, efuseType, pAddr, pTargetPkt, bPseudoTest); |
1537 | else |
1538 | bRet = hal_EfusePgPacketWrite1ByteHeader(padapter, efuseType, pAddr, pTargetPkt, bPseudoTest); |
1539 | |
1540 | return bRet; |
1541 | } |
1542 | |
1543 | static u8 hal_EfusePgPacketWriteData( |
1544 | struct adapter *padapter, |
1545 | u8 efuseType, |
1546 | u16 *pAddr, |
1547 | struct pgpkt_struct *pTargetPkt, |
1548 | u8 bPseudoTest |
1549 | ) |
1550 | { |
1551 | u16 efuse_addr; |
1552 | u8 badworden; |
1553 | |
1554 | |
1555 | efuse_addr = *pAddr; |
1556 | badworden = Efuse_WordEnableDataWrite(padapter, efuse_addr: efuse_addr+1, word_en: pTargetPkt->word_en, data: pTargetPkt->data, bPseudoTest); |
1557 | if (badworden != 0x0F) |
1558 | return false; |
1559 | |
1560 | return true; |
1561 | } |
1562 | |
1563 | static s32 Hal_EfusePgPacketWrite( |
1564 | struct adapter *padapter, |
1565 | u8 offset, |
1566 | u8 word_en, |
1567 | u8 *pData, |
1568 | bool bPseudoTest |
1569 | ) |
1570 | { |
1571 | struct pgpkt_struct targetPkt; |
1572 | u16 startAddr = 0; |
1573 | u8 efuseType = EFUSE_WIFI; |
1574 | |
1575 | if (!hal_EfusePgCheckAvailableAddr(padapter, efuseType, bPseudoTest)) |
1576 | return false; |
1577 | |
1578 | hal_EfuseConstructPGPkt(offset, word_en, pData, pTargetPkt: &targetPkt); |
1579 | |
1580 | if (!hal_EfusePartialWriteCheck(padapter, efuseType, pAddr: &startAddr, pTargetPkt: &targetPkt, bPseudoTest)) |
1581 | return false; |
1582 | |
1583 | if (!hal_EfusePgPacketWriteHeader(padapter, efuseType, pAddr: &startAddr, pTargetPkt: &targetPkt, bPseudoTest)) |
1584 | return false; |
1585 | |
1586 | if (!hal_EfusePgPacketWriteData(padapter, efuseType, pAddr: &startAddr, pTargetPkt: &targetPkt, bPseudoTest)) |
1587 | return false; |
1588 | |
1589 | return true; |
1590 | } |
1591 | |
1592 | static bool Hal_EfusePgPacketWrite_BT( |
1593 | struct adapter *padapter, |
1594 | u8 offset, |
1595 | u8 word_en, |
1596 | u8 *pData, |
1597 | bool bPseudoTest |
1598 | ) |
1599 | { |
1600 | struct pgpkt_struct targetPkt; |
1601 | u16 startAddr = 0; |
1602 | u8 efuseType = EFUSE_BT; |
1603 | |
1604 | if (!hal_EfusePgCheckAvailableAddr(padapter, efuseType, bPseudoTest)) |
1605 | return false; |
1606 | |
1607 | hal_EfuseConstructPGPkt(offset, word_en, pData, pTargetPkt: &targetPkt); |
1608 | |
1609 | if (!hal_EfusePartialWriteCheck(padapter, efuseType, pAddr: &startAddr, pTargetPkt: &targetPkt, bPseudoTest)) |
1610 | return false; |
1611 | |
1612 | if (!hal_EfusePgPacketWriteHeader(padapter, efuseType, pAddr: &startAddr, pTargetPkt: &targetPkt, bPseudoTest)) |
1613 | return false; |
1614 | |
1615 | if (!hal_EfusePgPacketWriteData(padapter, efuseType, pAddr: &startAddr, pTargetPkt: &targetPkt, bPseudoTest)) |
1616 | return false; |
1617 | |
1618 | return true; |
1619 | } |
1620 | |
1621 | static struct hal_version ReadChipVersion8723B(struct adapter *padapter) |
1622 | { |
1623 | u32 value32; |
1624 | struct hal_version ChipVersion; |
1625 | struct hal_com_data *pHalData; |
1626 | |
1627 | /* YJ, TODO, move read chip type here */ |
1628 | pHalData = GET_HAL_DATA(padapter); |
1629 | |
1630 | value32 = rtw_read32(adapter: padapter, REG_SYS_CFG); |
1631 | ChipVersion.ICType = CHIP_8723B; |
1632 | ChipVersion.ChipType = ((value32 & RTL_ID) ? TEST_CHIP : NORMAL_CHIP); |
1633 | ChipVersion.VendorType = ((value32 & VENDOR_ID) ? CHIP_VENDOR_UMC : CHIP_VENDOR_TSMC); |
1634 | ChipVersion.CUTVersion = (value32 & CHIP_VER_RTL_MASK)>>CHIP_VER_RTL_SHIFT; /* IC version (CUT) */ |
1635 | |
1636 | /* For regulator mode. by tynli. 2011.01.14 */ |
1637 | pHalData->RegulatorMode = ((value32 & SPS_SEL) ? RT_LDO_REGULATOR : RT_SWITCHING_REGULATOR); |
1638 | |
1639 | value32 = rtw_read32(adapter: padapter, REG_GPIO_OUTSTS); |
1640 | ChipVersion.ROMVer = ((value32 & RF_RL_ID) >> 20); /* ROM code version. */ |
1641 | |
1642 | /* For multi-function consideration. Added by Roger, 2010.10.06. */ |
1643 | pHalData->MultiFunc = RT_MULTI_FUNC_NONE; |
1644 | value32 = rtw_read32(adapter: padapter, REG_MULTI_FUNC_CTRL); |
1645 | pHalData->MultiFunc |= ((value32 & WL_FUNC_EN) ? RT_MULTI_FUNC_WIFI : 0); |
1646 | pHalData->MultiFunc |= ((value32 & BT_FUNC_EN) ? RT_MULTI_FUNC_BT : 0); |
1647 | pHalData->MultiFunc |= ((value32 & GPS_FUNC_EN) ? RT_MULTI_FUNC_GPS : 0); |
1648 | pHalData->PolarityCtl = ((value32 & WL_HWPDN_SL) ? RT_POLARITY_HIGH_ACT : RT_POLARITY_LOW_ACT); |
1649 | #if 1 |
1650 | dump_chip_info(ChipVersion); |
1651 | #endif |
1652 | pHalData->VersionID = ChipVersion; |
1653 | |
1654 | return ChipVersion; |
1655 | } |
1656 | |
1657 | static void rtl8723b_read_chip_version(struct adapter *padapter) |
1658 | { |
1659 | ReadChipVersion8723B(padapter); |
1660 | } |
1661 | |
1662 | void rtl8723b_InitBeaconParameters(struct adapter *padapter) |
1663 | { |
1664 | struct hal_com_data *pHalData = GET_HAL_DATA(padapter); |
1665 | u16 val16; |
1666 | u8 val8; |
1667 | |
1668 | |
1669 | val8 = DIS_TSF_UDT; |
1670 | val16 = val8 | (val8 << 8); /* port0 and port1 */ |
1671 | |
1672 | /* Enable prot0 beacon function for PSTDMA */ |
1673 | val16 |= EN_BCN_FUNCTION; |
1674 | |
1675 | rtw_write16(adapter: padapter, REG_BCN_CTRL, val: val16); |
1676 | |
1677 | /* TODO: Remove these magic number */ |
1678 | rtw_write16(adapter: padapter, REG_TBTT_PROHIBIT, val: 0x6404);/* ms */ |
1679 | /* Firmware will control REG_DRVERLYINT when power saving is enable, */ |
1680 | /* so don't set this register on STA mode. */ |
1681 | if (check_fwstate(pmlmepriv: &padapter->mlmepriv, WIFI_STATION_STATE) == false) |
1682 | rtw_write8(adapter: padapter, REG_DRVERLYINT, DRIVER_EARLY_INT_TIME_8723B); /* 5ms */ |
1683 | rtw_write8(adapter: padapter, REG_BCNDMATIM, BCN_DMA_ATIME_INT_TIME_8723B); /* 2ms */ |
1684 | |
1685 | /* Suggested by designer timchen. Change beacon AIFS to the largest number */ |
1686 | /* because test chip does not contension before sending beacon. by tynli. 2009.11.03 */ |
1687 | rtw_write16(adapter: padapter, REG_BCNTCFG, val: 0x660F); |
1688 | |
1689 | pHalData->RegBcnCtrlVal = rtw_read8(adapter: padapter, REG_BCN_CTRL); |
1690 | pHalData->RegTxPause = rtw_read8(adapter: padapter, REG_TXPAUSE); |
1691 | pHalData->RegFwHwTxQCtrl = rtw_read8(adapter: padapter, REG_FWHW_TXQ_CTRL+2); |
1692 | pHalData->RegReg542 = rtw_read8(adapter: padapter, REG_TBTT_PROHIBIT+2); |
1693 | pHalData->RegCR_1 = rtw_read8(adapter: padapter, REG_CR+1); |
1694 | } |
1695 | |
1696 | void _InitBurstPktLen_8723BS(struct adapter *Adapter) |
1697 | { |
1698 | struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); |
1699 | |
1700 | rtw_write8(adapter: Adapter, addr: 0x4c7, val: rtw_read8(adapter: Adapter, addr: 0x4c7)|BIT(7)); /* enable single pkt ampdu */ |
1701 | rtw_write8(adapter: Adapter, REG_RX_PKT_LIMIT_8723B, val: 0x18); /* for VHT packet length 11K */ |
1702 | rtw_write8(adapter: Adapter, REG_MAX_AGGR_NUM_8723B, val: 0x1F); |
1703 | rtw_write8(adapter: Adapter, REG_PIFS_8723B, val: 0x00); |
1704 | rtw_write8(adapter: Adapter, REG_FWHW_TXQ_CTRL_8723B, val: rtw_read8(adapter: Adapter, REG_FWHW_TXQ_CTRL)&(~BIT(7))); |
1705 | if (pHalData->AMPDUBurstMode) |
1706 | rtw_write8(adapter: Adapter, REG_AMPDU_BURST_MODE_8723B, val: 0x5F); |
1707 | rtw_write8(adapter: Adapter, REG_AMPDU_MAX_TIME_8723B, val: 0x70); |
1708 | |
1709 | /* ARFB table 9 for 11ac 5G 2SS */ |
1710 | rtw_write32(adapter: Adapter, REG_ARFR0_8723B, val: 0x00000010); |
1711 | if (IS_NORMAL_CHIP(pHalData->VersionID)) |
1712 | rtw_write32(adapter: Adapter, REG_ARFR0_8723B+4, val: 0xfffff000); |
1713 | else |
1714 | rtw_write32(adapter: Adapter, REG_ARFR0_8723B+4, val: 0x3e0ff000); |
1715 | |
1716 | /* ARFB table 10 for 11ac 5G 1SS */ |
1717 | rtw_write32(adapter: Adapter, REG_ARFR1_8723B, val: 0x00000010); |
1718 | rtw_write32(adapter: Adapter, REG_ARFR1_8723B+4, val: 0x003ff000); |
1719 | } |
1720 | |
1721 | static void ResumeTxBeacon(struct adapter *padapter) |
1722 | { |
1723 | struct hal_com_data *pHalData = GET_HAL_DATA(padapter); |
1724 | |
1725 | pHalData->RegFwHwTxQCtrl |= BIT(6); |
1726 | rtw_write8(adapter: padapter, REG_FWHW_TXQ_CTRL+2, val: pHalData->RegFwHwTxQCtrl); |
1727 | rtw_write8(adapter: padapter, REG_TBTT_PROHIBIT+1, val: 0xff); |
1728 | pHalData->RegReg542 |= BIT(0); |
1729 | rtw_write8(adapter: padapter, REG_TBTT_PROHIBIT+2, val: pHalData->RegReg542); |
1730 | } |
1731 | |
1732 | static void StopTxBeacon(struct adapter *padapter) |
1733 | { |
1734 | struct hal_com_data *pHalData = GET_HAL_DATA(padapter); |
1735 | |
1736 | pHalData->RegFwHwTxQCtrl &= ~BIT(6); |
1737 | rtw_write8(adapter: padapter, REG_FWHW_TXQ_CTRL+2, val: pHalData->RegFwHwTxQCtrl); |
1738 | rtw_write8(adapter: padapter, REG_TBTT_PROHIBIT+1, val: 0x64); |
1739 | pHalData->RegReg542 &= ~BIT(0); |
1740 | rtw_write8(adapter: padapter, REG_TBTT_PROHIBIT+2, val: pHalData->RegReg542); |
1741 | |
1742 | CheckFwRsvdPageContent(padapter); /* 2010.06.23. Added by tynli. */ |
1743 | } |
1744 | |
1745 | static void _BeaconFunctionEnable(struct adapter *padapter, u8 Enable, u8 Linked) |
1746 | { |
1747 | rtw_write8(adapter: padapter, REG_BCN_CTRL, DIS_TSF_UDT | EN_BCN_FUNCTION | DIS_BCNQ_SUB); |
1748 | rtw_write8(adapter: padapter, REG_RD_CTRL+1, val: 0x6F); |
1749 | } |
1750 | |
1751 | static void rtl8723b_SetBeaconRelatedRegisters(struct adapter *padapter) |
1752 | { |
1753 | u8 val8; |
1754 | u32 value32; |
1755 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
1756 | struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; |
1757 | u32 bcn_ctrl_reg; |
1758 | |
1759 | /* reset TSF, enable update TSF, correcting TSF On Beacon */ |
1760 | |
1761 | /* REG_BCN_INTERVAL */ |
1762 | /* REG_BCNDMATIM */ |
1763 | /* REG_ATIMWND */ |
1764 | /* REG_TBTT_PROHIBIT */ |
1765 | /* REG_DRVERLYINT */ |
1766 | /* REG_BCN_MAX_ERR */ |
1767 | /* REG_BCNTCFG (0x510) */ |
1768 | /* REG_DUAL_TSF_RST */ |
1769 | /* REG_BCN_CTRL (0x550) */ |
1770 | |
1771 | |
1772 | bcn_ctrl_reg = REG_BCN_CTRL; |
1773 | |
1774 | /* */ |
1775 | /* ATIM window */ |
1776 | /* */ |
1777 | rtw_write16(adapter: padapter, REG_ATIMWND, val: 2); |
1778 | |
1779 | /* */ |
1780 | /* Beacon interval (in unit of TU). */ |
1781 | /* */ |
1782 | rtw_write16(adapter: padapter, REG_BCN_INTERVAL, val: pmlmeinfo->bcn_interval); |
1783 | |
1784 | rtl8723b_InitBeaconParameters(padapter); |
1785 | |
1786 | rtw_write8(adapter: padapter, REG_SLOT, val: 0x09); |
1787 | |
1788 | /* */ |
1789 | /* Reset TSF Timer to zero, added by Roger. 2008.06.24 */ |
1790 | /* */ |
1791 | value32 = rtw_read32(adapter: padapter, REG_TCR); |
1792 | value32 &= ~TSFRST; |
1793 | rtw_write32(adapter: padapter, REG_TCR, val: value32); |
1794 | |
1795 | value32 |= TSFRST; |
1796 | rtw_write32(adapter: padapter, REG_TCR, val: value32); |
1797 | |
1798 | /* NOTE: Fix test chip's bug (about contention windows's randomness) */ |
1799 | if (check_fwstate(pmlmepriv: &padapter->mlmepriv, WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE|WIFI_AP_STATE) == true) { |
1800 | rtw_write8(adapter: padapter, REG_RXTSF_OFFSET_CCK, val: 0x50); |
1801 | rtw_write8(adapter: padapter, REG_RXTSF_OFFSET_OFDM, val: 0x50); |
1802 | } |
1803 | |
1804 | _BeaconFunctionEnable(padapter, Enable: true, Linked: true); |
1805 | |
1806 | ResumeTxBeacon(padapter); |
1807 | val8 = rtw_read8(adapter: padapter, addr: bcn_ctrl_reg); |
1808 | val8 |= DIS_BCNQ_SUB; |
1809 | rtw_write8(adapter: padapter, addr: bcn_ctrl_reg, val: val8); |
1810 | } |
1811 | |
1812 | static void rtl8723b_GetHalODMVar( |
1813 | struct adapter *Adapter, |
1814 | enum hal_odm_variable eVariable, |
1815 | void *pValue1, |
1816 | void *pValue2 |
1817 | ) |
1818 | { |
1819 | GetHalODMVar(Adapter, eVariable, pValue1, pValue2); |
1820 | } |
1821 | |
1822 | static void rtl8723b_SetHalODMVar( |
1823 | struct adapter *Adapter, |
1824 | enum hal_odm_variable eVariable, |
1825 | void *pValue1, |
1826 | bool bSet |
1827 | ) |
1828 | { |
1829 | SetHalODMVar(Adapter, eVariable, pValue1, bSet); |
1830 | } |
1831 | |
1832 | static void hal_notch_filter_8723b(struct adapter *adapter, bool enable) |
1833 | { |
1834 | if (enable) |
1835 | rtw_write8(adapter, rOFDM0_RxDSP+1, val: rtw_read8(adapter, rOFDM0_RxDSP+1) | BIT1); |
1836 | else |
1837 | rtw_write8(adapter, rOFDM0_RxDSP+1, val: rtw_read8(adapter, rOFDM0_RxDSP+1) & ~BIT1); |
1838 | } |
1839 | |
1840 | static void UpdateHalRAMask8723B(struct adapter *padapter, u32 mac_id, u8 ) |
1841 | { |
1842 | u32 mask, rate_bitmap; |
1843 | u8 shortGIrate = false; |
1844 | struct sta_info *psta; |
1845 | struct hal_com_data *pHalData = GET_HAL_DATA(padapter); |
1846 | struct dm_priv *pdmpriv = &pHalData->dmpriv; |
1847 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
1848 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
1849 | |
1850 | if (mac_id >= NUM_STA) /* CAM_SIZE */ |
1851 | return; |
1852 | |
1853 | psta = pmlmeinfo->FW_sta_info[mac_id].psta; |
1854 | if (!psta) |
1855 | return; |
1856 | |
1857 | shortGIrate = query_ra_short_GI(psta); |
1858 | |
1859 | mask = psta->ra_mask; |
1860 | |
1861 | rate_bitmap = 0xffffffff; |
1862 | rate_bitmap = ODM_Get_Rate_Bitmap(pDM_Odm: &pHalData->odmpriv, macid: mac_id, ra_mask: mask, rssi_level); |
1863 | |
1864 | mask &= rate_bitmap; |
1865 | |
1866 | rate_bitmap = hal_btcoex_GetRaMask(padapter); |
1867 | mask &= ~rate_bitmap; |
1868 | |
1869 | if (pHalData->fw_ractrl) { |
1870 | rtl8723b_set_FwMacIdConfig_cmd(padapter, mac_id, raid: psta->raid, bw: psta->bw_mode, sgi: shortGIrate, mask); |
1871 | } |
1872 | |
1873 | /* set correct initial date rate for each mac_id */ |
1874 | pdmpriv->INIDATA_RATE[mac_id] = psta->init_rate; |
1875 | } |
1876 | |
1877 | |
1878 | void rtl8723b_set_hal_ops(struct hal_ops *pHalFunc) |
1879 | { |
1880 | pHalFunc->free_hal_data = &rtl8723b_free_hal_data; |
1881 | |
1882 | pHalFunc->dm_init = &rtl8723b_init_dm_priv; |
1883 | |
1884 | pHalFunc->read_chip_version = &rtl8723b_read_chip_version; |
1885 | |
1886 | pHalFunc->UpdateRAMaskHandler = &UpdateHalRAMask8723B; |
1887 | |
1888 | pHalFunc->set_bwmode_handler = &PHY_SetBWMode8723B; |
1889 | pHalFunc->set_channel_handler = &PHY_SwChnl8723B; |
1890 | pHalFunc->set_chnl_bw_handler = &PHY_SetSwChnlBWMode8723B; |
1891 | |
1892 | pHalFunc->set_tx_power_level_handler = &PHY_SetTxPowerLevel8723B; |
1893 | pHalFunc->get_tx_power_level_handler = &PHY_GetTxPowerLevel8723B; |
1894 | |
1895 | pHalFunc->hal_dm_watchdog = &rtl8723b_HalDmWatchDog; |
1896 | pHalFunc->hal_dm_watchdog_in_lps = &rtl8723b_HalDmWatchDog_in_LPS; |
1897 | |
1898 | |
1899 | pHalFunc->SetBeaconRelatedRegistersHandler = &rtl8723b_SetBeaconRelatedRegisters; |
1900 | |
1901 | pHalFunc->Add_RateATid = &rtl8723b_Add_RateATid; |
1902 | |
1903 | pHalFunc->run_thread = &rtl8723b_start_thread; |
1904 | pHalFunc->cancel_thread = &rtl8723b_stop_thread; |
1905 | |
1906 | pHalFunc->read_bbreg = &PHY_QueryBBReg_8723B; |
1907 | pHalFunc->write_bbreg = &PHY_SetBBReg_8723B; |
1908 | pHalFunc->read_rfreg = &PHY_QueryRFReg_8723B; |
1909 | pHalFunc->write_rfreg = &PHY_SetRFReg_8723B; |
1910 | |
1911 | /* Efuse related function */ |
1912 | pHalFunc->BTEfusePowerSwitch = &Hal_BT_EfusePowerSwitch; |
1913 | pHalFunc->EfusePowerSwitch = &Hal_EfusePowerSwitch; |
1914 | pHalFunc->ReadEFuse = &Hal_ReadEFuse; |
1915 | pHalFunc->EFUSEGetEfuseDefinition = &Hal_GetEfuseDefinition; |
1916 | pHalFunc->EfuseGetCurrentSize = &Hal_EfuseGetCurrentSize; |
1917 | pHalFunc->Efuse_PgPacketRead = &Hal_EfusePgPacketRead; |
1918 | pHalFunc->Efuse_PgPacketWrite = &Hal_EfusePgPacketWrite; |
1919 | pHalFunc->Efuse_WordEnableDataWrite = &Hal_EfuseWordEnableDataWrite; |
1920 | pHalFunc->Efuse_PgPacketWrite_BT = &Hal_EfusePgPacketWrite_BT; |
1921 | |
1922 | pHalFunc->GetHalODMVarHandler = &rtl8723b_GetHalODMVar; |
1923 | pHalFunc->SetHalODMVarHandler = &rtl8723b_SetHalODMVar; |
1924 | |
1925 | pHalFunc->xmit_thread_handler = &hal_xmit_handler; |
1926 | pHalFunc->hal_notch_filter = &hal_notch_filter_8723b; |
1927 | |
1928 | pHalFunc->c2h_handler = c2h_handler_8723b; |
1929 | pHalFunc->c2h_id_filter_ccx = c2h_id_filter_ccx_8723b; |
1930 | |
1931 | pHalFunc->fill_h2c_cmd = &FillH2CCmd8723B; |
1932 | } |
1933 | |
1934 | void rtl8723b_InitAntenna_Selection(struct adapter *padapter) |
1935 | { |
1936 | u8 val; |
1937 | |
1938 | val = rtw_read8(adapter: padapter, REG_LEDCFG2); |
1939 | /* Let 8051 take control antenna setting */ |
1940 | val |= BIT(7); /* DPDT_SEL_EN, 0x4C[23] */ |
1941 | rtw_write8(adapter: padapter, REG_LEDCFG2, val); |
1942 | } |
1943 | |
1944 | void rtl8723b_init_default_value(struct adapter *padapter) |
1945 | { |
1946 | struct hal_com_data *pHalData; |
1947 | struct dm_priv *pdmpriv; |
1948 | u8 i; |
1949 | |
1950 | |
1951 | pHalData = GET_HAL_DATA(padapter); |
1952 | pdmpriv = &pHalData->dmpriv; |
1953 | |
1954 | padapter->registrypriv.wireless_mode = WIRELESS_11BG_24N; |
1955 | |
1956 | /* init default value */ |
1957 | pHalData->fw_ractrl = false; |
1958 | pHalData->bIQKInitialized = false; |
1959 | if (!adapter_to_pwrctl(padapter)->bkeepfwalive) |
1960 | pHalData->LastHMEBoxNum = 0; |
1961 | |
1962 | pHalData->bIQKInitialized = false; |
1963 | |
1964 | /* init dm default value */ |
1965 | pdmpriv->TM_Trigger = 0;/* for IQK */ |
1966 | /* pdmpriv->binitialized = false; */ |
1967 | /* pdmpriv->prv_traffic_idx = 3; */ |
1968 | /* pdmpriv->initialize = 0; */ |
1969 | |
1970 | pdmpriv->ThermalValue_HP_index = 0; |
1971 | for (i = 0; i < HP_THERMAL_NUM; i++) |
1972 | pdmpriv->ThermalValue_HP[i] = 0; |
1973 | |
1974 | /* init Efuse variables */ |
1975 | pHalData->EfuseUsedBytes = 0; |
1976 | pHalData->EfuseUsedPercentage = 0; |
1977 | #ifdef HAL_EFUSE_MEMORY |
1978 | pHalData->EfuseHal.fakeEfuseBank = 0; |
1979 | pHalData->EfuseHal.fakeEfuseUsedBytes = 0; |
1980 | memset(pHalData->EfuseHal.fakeEfuseContent, 0xFF, EFUSE_MAX_HW_SIZE); |
1981 | memset(pHalData->EfuseHal.fakeEfuseInitMap, 0xFF, EFUSE_MAX_MAP_LEN); |
1982 | memset(pHalData->EfuseHal.fakeEfuseModifiedMap, 0xFF, EFUSE_MAX_MAP_LEN); |
1983 | pHalData->EfuseHal.BTEfuseUsedBytes = 0; |
1984 | pHalData->EfuseHal.BTEfuseUsedPercentage = 0; |
1985 | memset(pHalData->EfuseHal.BTEfuseContent, 0xFF, EFUSE_MAX_BT_BANK*EFUSE_MAX_HW_SIZE); |
1986 | memset(pHalData->EfuseHal.BTEfuseInitMap, 0xFF, EFUSE_BT_MAX_MAP_LEN); |
1987 | memset(pHalData->EfuseHal.BTEfuseModifiedMap, 0xFF, EFUSE_BT_MAX_MAP_LEN); |
1988 | pHalData->EfuseHal.fakeBTEfuseUsedBytes = 0; |
1989 | memset(pHalData->EfuseHal.fakeBTEfuseContent, 0xFF, EFUSE_MAX_BT_BANK*EFUSE_MAX_HW_SIZE); |
1990 | memset(pHalData->EfuseHal.fakeBTEfuseInitMap, 0xFF, EFUSE_BT_MAX_MAP_LEN); |
1991 | memset(pHalData->EfuseHal.fakeBTEfuseModifiedMap, 0xFF, EFUSE_BT_MAX_MAP_LEN); |
1992 | #endif |
1993 | } |
1994 | |
1995 | u8 GetEEPROMSize8723B(struct adapter *padapter) |
1996 | { |
1997 | u8 size = 0; |
1998 | u32 cr; |
1999 | |
2000 | cr = rtw_read16(adapter: padapter, REG_9346CR); |
2001 | /* 6: EEPROM used is 93C46, 4: boot from E-Fuse. */ |
2002 | size = (cr & BOOT_FROM_EEPROM) ? 6 : 4; |
2003 | |
2004 | return size; |
2005 | } |
2006 | |
2007 | /* */ |
2008 | /* */ |
2009 | /* LLT R/W/Init function */ |
2010 | /* */ |
2011 | /* */ |
2012 | s32 rtl8723b_InitLLTTable(struct adapter *padapter) |
2013 | { |
2014 | unsigned long start, passing_time; |
2015 | u32 val32; |
2016 | s32 ret; |
2017 | |
2018 | |
2019 | ret = _FAIL; |
2020 | |
2021 | val32 = rtw_read32(adapter: padapter, REG_AUTO_LLT); |
2022 | val32 |= BIT_AUTO_INIT_LLT; |
2023 | rtw_write32(adapter: padapter, REG_AUTO_LLT, val: val32); |
2024 | |
2025 | start = jiffies; |
2026 | |
2027 | do { |
2028 | val32 = rtw_read32(adapter: padapter, REG_AUTO_LLT); |
2029 | if (!(val32 & BIT_AUTO_INIT_LLT)) { |
2030 | ret = _SUCCESS; |
2031 | break; |
2032 | } |
2033 | |
2034 | passing_time = jiffies_to_msecs(j: jiffies - start); |
2035 | if (passing_time > 1000) |
2036 | break; |
2037 | |
2038 | msleep(msecs: 1); |
2039 | } while (1); |
2040 | |
2041 | return ret; |
2042 | } |
2043 | |
2044 | static void hal_get_chnl_group_8723b(u8 channel, u8 *group) |
2045 | { |
2046 | if (1 <= channel && channel <= 2) |
2047 | *group = 0; |
2048 | else if (3 <= channel && channel <= 5) |
2049 | *group = 1; |
2050 | else if (6 <= channel && channel <= 8) |
2051 | *group = 2; |
2052 | else if (9 <= channel && channel <= 11) |
2053 | *group = 3; |
2054 | else if (12 <= channel && channel <= 14) |
2055 | *group = 4; |
2056 | } |
2057 | |
2058 | void Hal_InitPGData(struct adapter *padapter, u8 *PROMContent) |
2059 | { |
2060 | struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); |
2061 | |
2062 | if (!pEEPROM->bautoload_fail_flag) { /* autoload OK. */ |
2063 | if (!pEEPROM->EepromOrEfuse) { |
2064 | /* Read EFUSE real map to shadow. */ |
2065 | EFUSE_ShadowMapUpdate(padapter, EFUSE_WIFI, bPseudoTest: false); |
2066 | memcpy((void *)PROMContent, (void *)pEEPROM->efuse_eeprom_data, HWSET_MAX_SIZE_8723B); |
2067 | } |
2068 | } else {/* autoload fail */ |
2069 | if (!pEEPROM->EepromOrEfuse) |
2070 | EFUSE_ShadowMapUpdate(padapter, EFUSE_WIFI, bPseudoTest: false); |
2071 | memcpy((void *)PROMContent, (void *)pEEPROM->efuse_eeprom_data, HWSET_MAX_SIZE_8723B); |
2072 | } |
2073 | } |
2074 | |
2075 | void Hal_EfuseParseIDCode(struct adapter *padapter, u8 *hwinfo) |
2076 | { |
2077 | struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); |
2078 | /* struct hal_com_data *pHalData = GET_HAL_DATA(padapter); */ |
2079 | u16 EEPROMId; |
2080 | |
2081 | |
2082 | /* Check 0x8129 again for making sure autoload status!! */ |
2083 | EEPROMId = le16_to_cpu(*((__le16 *)hwinfo)); |
2084 | if (EEPROMId != RTL_EEPROM_ID) { |
2085 | pEEPROM->bautoload_fail_flag = true; |
2086 | } else |
2087 | pEEPROM->bautoload_fail_flag = false; |
2088 | } |
2089 | |
2090 | static void Hal_ReadPowerValueFromPROM_8723B( |
2091 | struct adapter *Adapter, |
2092 | struct TxPowerInfo24G *pwrInfo24G, |
2093 | u8 *PROMContent, |
2094 | bool AutoLoadFail |
2095 | ) |
2096 | { |
2097 | struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); |
2098 | u32 rfPath, eeAddr = EEPROM_TX_PWR_INX_8723B, group, TxCount = 0; |
2099 | |
2100 | memset(pwrInfo24G, 0, sizeof(struct TxPowerInfo24G)); |
2101 | |
2102 | if (0xFF == PROMContent[eeAddr+1]) |
2103 | AutoLoadFail = true; |
2104 | |
2105 | if (AutoLoadFail) { |
2106 | for (rfPath = 0; rfPath < MAX_RF_PATH; rfPath++) { |
2107 | /* 2.4G default value */ |
2108 | for (group = 0; group < MAX_CHNL_GROUP_24G; group++) { |
2109 | pwrInfo24G->IndexCCK_Base[rfPath][group] = EEPROM_DEFAULT_24G_INDEX; |
2110 | pwrInfo24G->IndexBW40_Base[rfPath][group] = EEPROM_DEFAULT_24G_INDEX; |
2111 | } |
2112 | |
2113 | for (TxCount = 0; TxCount < MAX_TX_COUNT; TxCount++) { |
2114 | if (TxCount == 0) { |
2115 | pwrInfo24G->BW20_Diff[rfPath][0] = EEPROM_DEFAULT_24G_HT20_DIFF; |
2116 | pwrInfo24G->OFDM_Diff[rfPath][0] = EEPROM_DEFAULT_24G_OFDM_DIFF; |
2117 | } else { |
2118 | pwrInfo24G->BW20_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF; |
2119 | pwrInfo24G->BW40_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF; |
2120 | pwrInfo24G->CCK_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF; |
2121 | pwrInfo24G->OFDM_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF; |
2122 | } |
2123 | } |
2124 | } |
2125 | |
2126 | return; |
2127 | } |
2128 | |
2129 | pHalData->bTXPowerDataReadFromEEPORM = true; /* YJ, move, 120316 */ |
2130 | |
2131 | for (rfPath = 0; rfPath < MAX_RF_PATH; rfPath++) { |
2132 | /* 2 2.4G default value */ |
2133 | for (group = 0; group < MAX_CHNL_GROUP_24G; group++) { |
2134 | pwrInfo24G->IndexCCK_Base[rfPath][group] = PROMContent[eeAddr++]; |
2135 | if (pwrInfo24G->IndexCCK_Base[rfPath][group] == 0xFF) |
2136 | pwrInfo24G->IndexCCK_Base[rfPath][group] = EEPROM_DEFAULT_24G_INDEX; |
2137 | } |
2138 | |
2139 | for (group = 0; group < MAX_CHNL_GROUP_24G-1; group++) { |
2140 | pwrInfo24G->IndexBW40_Base[rfPath][group] = PROMContent[eeAddr++]; |
2141 | if (pwrInfo24G->IndexBW40_Base[rfPath][group] == 0xFF) |
2142 | pwrInfo24G->IndexBW40_Base[rfPath][group] = EEPROM_DEFAULT_24G_INDEX; |
2143 | } |
2144 | |
2145 | for (TxCount = 0; TxCount < MAX_TX_COUNT; TxCount++) { |
2146 | if (TxCount == 0) { |
2147 | pwrInfo24G->BW40_Diff[rfPath][TxCount] = 0; |
2148 | if (PROMContent[eeAddr] == 0xFF) |
2149 | pwrInfo24G->BW20_Diff[rfPath][TxCount] = EEPROM_DEFAULT_24G_HT20_DIFF; |
2150 | else { |
2151 | pwrInfo24G->BW20_Diff[rfPath][TxCount] = (PROMContent[eeAddr]&0xf0)>>4; |
2152 | if (pwrInfo24G->BW20_Diff[rfPath][TxCount] & BIT3) /* 4bit sign number to 8 bit sign number */ |
2153 | pwrInfo24G->BW20_Diff[rfPath][TxCount] |= 0xF0; |
2154 | } |
2155 | |
2156 | if (PROMContent[eeAddr] == 0xFF) |
2157 | pwrInfo24G->OFDM_Diff[rfPath][TxCount] = EEPROM_DEFAULT_24G_OFDM_DIFF; |
2158 | else { |
2159 | pwrInfo24G->OFDM_Diff[rfPath][TxCount] = (PROMContent[eeAddr]&0x0f); |
2160 | if (pwrInfo24G->OFDM_Diff[rfPath][TxCount] & BIT3) /* 4bit sign number to 8 bit sign number */ |
2161 | pwrInfo24G->OFDM_Diff[rfPath][TxCount] |= 0xF0; |
2162 | } |
2163 | pwrInfo24G->CCK_Diff[rfPath][TxCount] = 0; |
2164 | eeAddr++; |
2165 | } else { |
2166 | if (PROMContent[eeAddr] == 0xFF) |
2167 | pwrInfo24G->BW40_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF; |
2168 | else { |
2169 | pwrInfo24G->BW40_Diff[rfPath][TxCount] = (PROMContent[eeAddr]&0xf0)>>4; |
2170 | if (pwrInfo24G->BW40_Diff[rfPath][TxCount] & BIT3) /* 4bit sign number to 8 bit sign number */ |
2171 | pwrInfo24G->BW40_Diff[rfPath][TxCount] |= 0xF0; |
2172 | } |
2173 | |
2174 | if (PROMContent[eeAddr] == 0xFF) |
2175 | pwrInfo24G->BW20_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF; |
2176 | else { |
2177 | pwrInfo24G->BW20_Diff[rfPath][TxCount] = (PROMContent[eeAddr]&0x0f); |
2178 | if (pwrInfo24G->BW20_Diff[rfPath][TxCount] & BIT3) /* 4bit sign number to 8 bit sign number */ |
2179 | pwrInfo24G->BW20_Diff[rfPath][TxCount] |= 0xF0; |
2180 | } |
2181 | eeAddr++; |
2182 | |
2183 | if (PROMContent[eeAddr] == 0xFF) |
2184 | pwrInfo24G->OFDM_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF; |
2185 | else { |
2186 | pwrInfo24G->OFDM_Diff[rfPath][TxCount] = (PROMContent[eeAddr]&0xf0)>>4; |
2187 | if (pwrInfo24G->OFDM_Diff[rfPath][TxCount] & BIT3) /* 4bit sign number to 8 bit sign number */ |
2188 | pwrInfo24G->OFDM_Diff[rfPath][TxCount] |= 0xF0; |
2189 | } |
2190 | |
2191 | if (PROMContent[eeAddr] == 0xFF) |
2192 | pwrInfo24G->CCK_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF; |
2193 | else { |
2194 | pwrInfo24G->CCK_Diff[rfPath][TxCount] = (PROMContent[eeAddr]&0x0f); |
2195 | if (pwrInfo24G->CCK_Diff[rfPath][TxCount] & BIT3) /* 4bit sign number to 8 bit sign number */ |
2196 | pwrInfo24G->CCK_Diff[rfPath][TxCount] |= 0xF0; |
2197 | } |
2198 | eeAddr++; |
2199 | } |
2200 | } |
2201 | } |
2202 | } |
2203 | |
2204 | |
2205 | void Hal_EfuseParseTxPowerInfo_8723B( |
2206 | struct adapter *padapter, u8 *PROMContent, bool AutoLoadFail |
2207 | ) |
2208 | { |
2209 | struct hal_com_data *pHalData = GET_HAL_DATA(padapter); |
2210 | struct TxPowerInfo24G pwrInfo24G; |
2211 | u8 rfPath, ch, TxCount = 1; |
2212 | |
2213 | Hal_ReadPowerValueFromPROM_8723B(Adapter: padapter, pwrInfo24G: &pwrInfo24G, PROMContent, AutoLoadFail); |
2214 | for (rfPath = 0 ; rfPath < MAX_RF_PATH ; rfPath++) { |
2215 | for (ch = 0 ; ch < CHANNEL_MAX_NUMBER; ch++) { |
2216 | u8 group = 0; |
2217 | |
2218 | hal_get_chnl_group_8723b(channel: ch + 1, group: &group); |
2219 | |
2220 | if (ch == 14-1) { |
2221 | pHalData->Index24G_CCK_Base[rfPath][ch] = pwrInfo24G.IndexCCK_Base[rfPath][5]; |
2222 | pHalData->Index24G_BW40_Base[rfPath][ch] = pwrInfo24G.IndexBW40_Base[rfPath][group]; |
2223 | } else { |
2224 | pHalData->Index24G_CCK_Base[rfPath][ch] = pwrInfo24G.IndexCCK_Base[rfPath][group]; |
2225 | pHalData->Index24G_BW40_Base[rfPath][ch] = pwrInfo24G.IndexBW40_Base[rfPath][group]; |
2226 | } |
2227 | } |
2228 | |
2229 | for (TxCount = 0; TxCount < MAX_TX_COUNT; TxCount++) { |
2230 | pHalData->CCK_24G_Diff[rfPath][TxCount] = pwrInfo24G.CCK_Diff[rfPath][TxCount]; |
2231 | pHalData->OFDM_24G_Diff[rfPath][TxCount] = pwrInfo24G.OFDM_Diff[rfPath][TxCount]; |
2232 | pHalData->BW20_24G_Diff[rfPath][TxCount] = pwrInfo24G.BW20_Diff[rfPath][TxCount]; |
2233 | pHalData->BW40_24G_Diff[rfPath][TxCount] = pwrInfo24G.BW40_Diff[rfPath][TxCount]; |
2234 | } |
2235 | } |
2236 | |
2237 | /* 2010/10/19 MH Add Regulator recognize for CU. */ |
2238 | if (!AutoLoadFail) { |
2239 | pHalData->EEPROMRegulatory = (PROMContent[EEPROM_RF_BOARD_OPTION_8723B]&0x7); /* bit0~2 */ |
2240 | if (PROMContent[EEPROM_RF_BOARD_OPTION_8723B] == 0xFF) |
2241 | pHalData->EEPROMRegulatory = (EEPROM_DEFAULT_BOARD_OPTION&0x7); /* bit0~2 */ |
2242 | } else |
2243 | pHalData->EEPROMRegulatory = 0; |
2244 | } |
2245 | |
2246 | void Hal_EfuseParseBTCoexistInfo_8723B( |
2247 | struct adapter *padapter, u8 *hwinfo, bool AutoLoadFail |
2248 | ) |
2249 | { |
2250 | struct hal_com_data *pHalData = GET_HAL_DATA(padapter); |
2251 | u8 tempval; |
2252 | u32 tmpu4; |
2253 | |
2254 | if (!AutoLoadFail) { |
2255 | tmpu4 = rtw_read32(adapter: padapter, REG_MULTI_FUNC_CTRL); |
2256 | if (tmpu4 & BT_FUNC_EN) |
2257 | pHalData->EEPROMBluetoothCoexist = true; |
2258 | else |
2259 | pHalData->EEPROMBluetoothCoexist = false; |
2260 | |
2261 | pHalData->EEPROMBluetoothType = BT_RTL8723B; |
2262 | |
2263 | tempval = hwinfo[EEPROM_RF_BT_SETTING_8723B]; |
2264 | if (tempval != 0xFF) { |
2265 | pHalData->EEPROMBluetoothAntNum = tempval & BIT(0); |
2266 | /* EFUSE_0xC3[6] == 0, S1(Main)-RF_PATH_A; */ |
2267 | /* EFUSE_0xC3[6] == 1, S0(Aux)-RF_PATH_B */ |
2268 | if (tempval & BIT(6)) |
2269 | pHalData->ant_path = RF_PATH_B; |
2270 | else |
2271 | pHalData->ant_path = RF_PATH_A; |
2272 | } else { |
2273 | pHalData->EEPROMBluetoothAntNum = Ant_x1; |
2274 | if (pHalData->PackageType == PACKAGE_QFN68) |
2275 | pHalData->ant_path = RF_PATH_B; |
2276 | else |
2277 | pHalData->ant_path = RF_PATH_A; |
2278 | } |
2279 | } else { |
2280 | pHalData->EEPROMBluetoothCoexist = false; |
2281 | pHalData->EEPROMBluetoothType = BT_RTL8723B; |
2282 | pHalData->EEPROMBluetoothAntNum = Ant_x1; |
2283 | pHalData->ant_path = RF_PATH_A; |
2284 | } |
2285 | |
2286 | if (padapter->registrypriv.ant_num > 0) { |
2287 | switch (padapter->registrypriv.ant_num) { |
2288 | case 1: |
2289 | pHalData->EEPROMBluetoothAntNum = Ant_x1; |
2290 | break; |
2291 | case 2: |
2292 | pHalData->EEPROMBluetoothAntNum = Ant_x2; |
2293 | break; |
2294 | default: |
2295 | break; |
2296 | } |
2297 | } |
2298 | |
2299 | hal_btcoex_SetBTCoexist(padapter, bBtExist: pHalData->EEPROMBluetoothCoexist); |
2300 | hal_btcoex_SetPgAntNum(padapter, antNum: pHalData->EEPROMBluetoothAntNum == Ant_x2 ? 2 : 1); |
2301 | if (pHalData->EEPROMBluetoothAntNum == Ant_x1) |
2302 | hal_btcoex_SetSingleAntPath(padapter, singleAntPath: pHalData->ant_path); |
2303 | } |
2304 | |
2305 | void Hal_EfuseParseEEPROMVer_8723B( |
2306 | struct adapter *padapter, u8 *hwinfo, bool AutoLoadFail |
2307 | ) |
2308 | { |
2309 | struct hal_com_data *pHalData = GET_HAL_DATA(padapter); |
2310 | |
2311 | if (!AutoLoadFail) |
2312 | pHalData->EEPROMVersion = hwinfo[EEPROM_VERSION_8723B]; |
2313 | else |
2314 | pHalData->EEPROMVersion = 1; |
2315 | } |
2316 | |
2317 | |
2318 | |
2319 | void Hal_EfuseParsePackageType_8723B( |
2320 | struct adapter *padapter, u8 *hwinfo, bool AutoLoadFail |
2321 | ) |
2322 | { |
2323 | struct hal_com_data *pHalData = GET_HAL_DATA(padapter); |
2324 | u8 package; |
2325 | u8 efuseContent; |
2326 | |
2327 | Efuse_PowerSwitch(padapter, bWrite: false, PwrState: true); |
2328 | efuse_OneByteRead(padapter, addr: 0x1FB, data: &efuseContent, bPseudoTest: false); |
2329 | Efuse_PowerSwitch(padapter, bWrite: false, PwrState: false); |
2330 | |
2331 | package = efuseContent & 0x7; |
2332 | switch (package) { |
2333 | case 0x4: |
2334 | pHalData->PackageType = PACKAGE_TFBGA79; |
2335 | break; |
2336 | case 0x5: |
2337 | pHalData->PackageType = PACKAGE_TFBGA90; |
2338 | break; |
2339 | case 0x6: |
2340 | pHalData->PackageType = PACKAGE_QFN68; |
2341 | break; |
2342 | case 0x7: |
2343 | pHalData->PackageType = PACKAGE_TFBGA80; |
2344 | break; |
2345 | |
2346 | default: |
2347 | pHalData->PackageType = PACKAGE_DEFAULT; |
2348 | break; |
2349 | } |
2350 | } |
2351 | |
2352 | |
2353 | void Hal_EfuseParseVoltage_8723B( |
2354 | struct adapter *padapter, u8 *hwinfo, bool AutoLoadFail |
2355 | ) |
2356 | { |
2357 | struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); |
2358 | |
2359 | /* memcpy(pEEPROM->adjuseVoltageVal, &hwinfo[EEPROM_Voltage_ADDR_8723B], 1); */ |
2360 | pEEPROM->adjuseVoltageVal = (hwinfo[EEPROM_Voltage_ADDR_8723B] & 0xf0) >> 4; |
2361 | } |
2362 | |
2363 | void Hal_EfuseParseChnlPlan_8723B( |
2364 | struct adapter *padapter, u8 *hwinfo, bool AutoLoadFail |
2365 | ) |
2366 | { |
2367 | padapter->mlmepriv.ChannelPlan = hal_com_config_channel_plan( |
2368 | padapter, |
2369 | hw_channel_plan: hwinfo ? hwinfo[EEPROM_ChannelPlan_8723B] : 0xFF, |
2370 | sw_channel_plan: padapter->registrypriv.channel_plan, |
2371 | def_channel_plan: RT_CHANNEL_DOMAIN_WORLD_NULL, |
2372 | AutoLoadFail |
2373 | ); |
2374 | |
2375 | Hal_ChannelPlanToRegulation(Adapter: padapter, ChannelPlan: padapter->mlmepriv.ChannelPlan); |
2376 | } |
2377 | |
2378 | void Hal_EfuseParseCustomerID_8723B( |
2379 | struct adapter *padapter, u8 *hwinfo, bool AutoLoadFail |
2380 | ) |
2381 | { |
2382 | struct hal_com_data *pHalData = GET_HAL_DATA(padapter); |
2383 | |
2384 | if (!AutoLoadFail) |
2385 | pHalData->EEPROMCustomerID = hwinfo[EEPROM_CustomID_8723B]; |
2386 | else |
2387 | pHalData->EEPROMCustomerID = 0; |
2388 | } |
2389 | |
2390 | void Hal_EfuseParseAntennaDiversity_8723B( |
2391 | struct adapter *padapter, |
2392 | u8 *hwinfo, |
2393 | bool AutoLoadFail |
2394 | ) |
2395 | { |
2396 | } |
2397 | |
2398 | void Hal_EfuseParseXtal_8723B( |
2399 | struct adapter *padapter, u8 *hwinfo, bool AutoLoadFail |
2400 | ) |
2401 | { |
2402 | struct hal_com_data *pHalData = GET_HAL_DATA(padapter); |
2403 | |
2404 | if (!AutoLoadFail) { |
2405 | pHalData->CrystalCap = hwinfo[EEPROM_XTAL_8723B]; |
2406 | if (pHalData->CrystalCap == 0xFF) |
2407 | pHalData->CrystalCap = EEPROM_Default_CrystalCap_8723B; /* what value should 8812 set? */ |
2408 | } else |
2409 | pHalData->CrystalCap = EEPROM_Default_CrystalCap_8723B; |
2410 | } |
2411 | |
2412 | |
2413 | void Hal_EfuseParseThermalMeter_8723B( |
2414 | struct adapter *padapter, u8 *PROMContent, u8 AutoLoadFail |
2415 | ) |
2416 | { |
2417 | struct hal_com_data *pHalData = GET_HAL_DATA(padapter); |
2418 | |
2419 | /* */ |
2420 | /* ThermalMeter from EEPROM */ |
2421 | /* */ |
2422 | if (!AutoLoadFail) |
2423 | pHalData->EEPROMThermalMeter = PROMContent[EEPROM_THERMAL_METER_8723B]; |
2424 | else |
2425 | pHalData->EEPROMThermalMeter = EEPROM_Default_ThermalMeter_8723B; |
2426 | |
2427 | if ((pHalData->EEPROMThermalMeter == 0xff) || AutoLoadFail) { |
2428 | pHalData->bAPKThermalMeterIgnore = true; |
2429 | pHalData->EEPROMThermalMeter = EEPROM_Default_ThermalMeter_8723B; |
2430 | } |
2431 | } |
2432 | |
2433 | |
2434 | void Hal_ReadRFGainOffset( |
2435 | struct adapter *Adapter, u8 *PROMContent, bool AutoloadFail |
2436 | ) |
2437 | { |
2438 | /* */ |
2439 | /* BB_RF Gain Offset from EEPROM */ |
2440 | /* */ |
2441 | |
2442 | if (!AutoloadFail) { |
2443 | Adapter->eeprompriv.EEPROMRFGainOffset = PROMContent[EEPROM_RF_GAIN_OFFSET]; |
2444 | Adapter->eeprompriv.EEPROMRFGainVal = EFUSE_Read1Byte(padapter: Adapter, EEPROM_RF_GAIN_VAL); |
2445 | } else { |
2446 | Adapter->eeprompriv.EEPROMRFGainOffset = 0; |
2447 | Adapter->eeprompriv.EEPROMRFGainVal = 0xFF; |
2448 | } |
2449 | } |
2450 | |
2451 | u8 BWMapping_8723B(struct adapter *Adapter, struct pkt_attrib *pattrib) |
2452 | { |
2453 | u8 BWSettingOfDesc = 0; |
2454 | struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); |
2455 | |
2456 | if (pHalData->CurrentChannelBW == CHANNEL_WIDTH_40) { |
2457 | if (pattrib->bwmode == CHANNEL_WIDTH_40) |
2458 | BWSettingOfDesc = 1; |
2459 | else |
2460 | BWSettingOfDesc = 0; |
2461 | } else |
2462 | BWSettingOfDesc = 0; |
2463 | |
2464 | /* if (pTcb->bBTTxPacket) */ |
2465 | /* BWSettingOfDesc = 0; */ |
2466 | |
2467 | return BWSettingOfDesc; |
2468 | } |
2469 | |
2470 | u8 SCMapping_8723B(struct adapter *Adapter, struct pkt_attrib *pattrib) |
2471 | { |
2472 | u8 SCSettingOfDesc = 0; |
2473 | struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); |
2474 | |
2475 | if (pHalData->CurrentChannelBW == CHANNEL_WIDTH_40) { |
2476 | if (pattrib->bwmode == CHANNEL_WIDTH_40) { |
2477 | SCSettingOfDesc = HT_DATA_SC_DONOT_CARE; |
2478 | } else if (pattrib->bwmode == CHANNEL_WIDTH_20) { |
2479 | if (pHalData->nCur40MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_UPPER) { |
2480 | SCSettingOfDesc = HT_DATA_SC_20_UPPER_OF_40MHZ; |
2481 | } else if (pHalData->nCur40MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_LOWER) { |
2482 | SCSettingOfDesc = HT_DATA_SC_20_LOWER_OF_40MHZ; |
2483 | } else { |
2484 | SCSettingOfDesc = HT_DATA_SC_DONOT_CARE; |
2485 | } |
2486 | } |
2487 | } else { |
2488 | SCSettingOfDesc = HT_DATA_SC_DONOT_CARE; |
2489 | } |
2490 | |
2491 | return SCSettingOfDesc; |
2492 | } |
2493 | |
2494 | static void rtl8723b_cal_txdesc_chksum(struct tx_desc *ptxdesc) |
2495 | { |
2496 | u16 *usPtr = (u16 *)ptxdesc; |
2497 | u32 count; |
2498 | u32 index; |
2499 | u16 checksum = 0; |
2500 | |
2501 | |
2502 | /* Clear first */ |
2503 | ptxdesc->txdw7 &= cpu_to_le32(0xffff0000); |
2504 | |
2505 | /* checksum is always calculated by first 32 bytes, */ |
2506 | /* and it doesn't depend on TX DESC length. */ |
2507 | /* Thomas, Lucas@SD4, 20130515 */ |
2508 | count = 16; |
2509 | |
2510 | for (index = 0; index < count; index++) { |
2511 | checksum |= le16_to_cpu(*(__le16 *)(usPtr + index)); |
2512 | } |
2513 | |
2514 | ptxdesc->txdw7 |= cpu_to_le32(checksum & 0x0000ffff); |
2515 | } |
2516 | |
2517 | static u8 fill_txdesc_sectype(struct pkt_attrib *pattrib) |
2518 | { |
2519 | u8 sectype = 0; |
2520 | if ((pattrib->encrypt > 0) && !pattrib->bswenc) { |
2521 | switch (pattrib->encrypt) { |
2522 | /* SEC_TYPE */ |
2523 | case _WEP40_: |
2524 | case _WEP104_: |
2525 | case _TKIP_: |
2526 | case _TKIP_WTMIC_: |
2527 | sectype = 1; |
2528 | break; |
2529 | |
2530 | case _AES_: |
2531 | sectype = 3; |
2532 | break; |
2533 | |
2534 | case _NO_PRIVACY_: |
2535 | default: |
2536 | break; |
2537 | } |
2538 | } |
2539 | return sectype; |
2540 | } |
2541 | |
2542 | static void fill_txdesc_vcs_8723b(struct adapter *padapter, struct pkt_attrib *pattrib, struct txdesc_8723b *ptxdesc) |
2543 | { |
2544 | if (pattrib->vcs_mode) { |
2545 | switch (pattrib->vcs_mode) { |
2546 | case RTS_CTS: |
2547 | ptxdesc->rtsen = 1; |
2548 | /* ENABLE HW RTS */ |
2549 | ptxdesc->hw_rts_en = 1; |
2550 | break; |
2551 | |
2552 | case CTS_TO_SELF: |
2553 | ptxdesc->cts2self = 1; |
2554 | break; |
2555 | |
2556 | case NONE_VCS: |
2557 | default: |
2558 | break; |
2559 | } |
2560 | |
2561 | ptxdesc->rtsrate = 8; /* RTS Rate =24M */ |
2562 | ptxdesc->rts_ratefb_lmt = 0xF; |
2563 | |
2564 | if (padapter->mlmeextpriv.mlmext_info.preamble_mode == PREAMBLE_SHORT) |
2565 | ptxdesc->rts_short = 1; |
2566 | |
2567 | /* Set RTS BW */ |
2568 | if (pattrib->ht_en) |
2569 | ptxdesc->rts_sc = SCMapping_8723B(Adapter: padapter, pattrib); |
2570 | } |
2571 | } |
2572 | |
2573 | static void fill_txdesc_phy_8723b(struct adapter *padapter, struct pkt_attrib *pattrib, struct txdesc_8723b *ptxdesc) |
2574 | { |
2575 | if (pattrib->ht_en) { |
2576 | ptxdesc->data_bw = BWMapping_8723B(Adapter: padapter, pattrib); |
2577 | |
2578 | ptxdesc->data_sc = SCMapping_8723B(Adapter: padapter, pattrib); |
2579 | } |
2580 | } |
2581 | |
2582 | static void rtl8723b_fill_default_txdesc( |
2583 | struct xmit_frame *pxmitframe, u8 *pbuf |
2584 | ) |
2585 | { |
2586 | struct adapter *padapter; |
2587 | struct hal_com_data *pHalData; |
2588 | struct mlme_ext_priv *pmlmeext; |
2589 | struct mlme_ext_info *pmlmeinfo; |
2590 | struct pkt_attrib *pattrib; |
2591 | struct txdesc_8723b *ptxdesc; |
2592 | s32 bmcst; |
2593 | |
2594 | memset(pbuf, 0, TXDESC_SIZE); |
2595 | |
2596 | padapter = pxmitframe->padapter; |
2597 | pHalData = GET_HAL_DATA(padapter); |
2598 | pmlmeext = &padapter->mlmeextpriv; |
2599 | pmlmeinfo = &(pmlmeext->mlmext_info); |
2600 | |
2601 | pattrib = &pxmitframe->attrib; |
2602 | bmcst = is_multicast_ether_addr(addr: pattrib->ra); |
2603 | |
2604 | ptxdesc = (struct txdesc_8723b *)pbuf; |
2605 | |
2606 | if (pxmitframe->frame_tag == DATA_FRAMETAG) { |
2607 | u8 drv_userate = 0; |
2608 | |
2609 | ptxdesc->macid = pattrib->mac_id; /* CAM_ID(MAC_ID) */ |
2610 | ptxdesc->rate_id = pattrib->raid; |
2611 | ptxdesc->qsel = pattrib->qsel; |
2612 | ptxdesc->seq = pattrib->seqnum; |
2613 | |
2614 | ptxdesc->sectype = fill_txdesc_sectype(pattrib); |
2615 | fill_txdesc_vcs_8723b(padapter, pattrib, ptxdesc); |
2616 | |
2617 | if (pattrib->icmp_pkt == 1 && padapter->registrypriv.wifi_spec == 1) |
2618 | drv_userate = 1; |
2619 | |
2620 | if ( |
2621 | (pattrib->ether_type != 0x888e) && |
2622 | (pattrib->ether_type != 0x0806) && |
2623 | (pattrib->ether_type != 0x88B4) && |
2624 | (pattrib->dhcp_pkt != 1) && |
2625 | (drv_userate != 1) |
2626 | ) { |
2627 | /* Non EAP & ARP & DHCP type data packet */ |
2628 | |
2629 | if (pattrib->ampdu_en) { |
2630 | ptxdesc->agg_en = 1; /* AGG EN */ |
2631 | ptxdesc->max_agg_num = 0x1f; |
2632 | ptxdesc->ampdu_density = pattrib->ampdu_spacing; |
2633 | } else |
2634 | ptxdesc->bk = 1; /* AGG BK */ |
2635 | |
2636 | fill_txdesc_phy_8723b(padapter, pattrib, ptxdesc); |
2637 | |
2638 | ptxdesc->data_ratefb_lmt = 0x1F; |
2639 | |
2640 | if (!pHalData->fw_ractrl) { |
2641 | ptxdesc->userate = 1; |
2642 | |
2643 | if (pHalData->dmpriv.INIDATA_RATE[pattrib->mac_id] & BIT(7)) |
2644 | ptxdesc->data_short = 1; |
2645 | |
2646 | ptxdesc->datarate = pHalData->dmpriv.INIDATA_RATE[pattrib->mac_id] & 0x7F; |
2647 | } |
2648 | |
2649 | if (padapter->fix_rate != 0xFF) { /* modify data rate by iwpriv */ |
2650 | ptxdesc->userate = 1; |
2651 | if (padapter->fix_rate & BIT(7)) |
2652 | ptxdesc->data_short = 1; |
2653 | |
2654 | ptxdesc->datarate = (padapter->fix_rate & 0x7F); |
2655 | ptxdesc->disdatafb = 1; |
2656 | } |
2657 | |
2658 | if (pattrib->ldpc) |
2659 | ptxdesc->data_ldpc = 1; |
2660 | if (pattrib->stbc) |
2661 | ptxdesc->data_stbc = 1; |
2662 | } else { |
2663 | /* EAP data packet and ARP packet. */ |
2664 | /* Use the 1M data rate to send the EAP/ARP packet. */ |
2665 | /* This will maybe make the handshake smooth. */ |
2666 | |
2667 | ptxdesc->bk = 1; /* AGG BK */ |
2668 | ptxdesc->userate = 1; /* driver uses rate */ |
2669 | if (pmlmeinfo->preamble_mode == PREAMBLE_SHORT) |
2670 | ptxdesc->data_short = 1;/* DATA_SHORT */ |
2671 | ptxdesc->datarate = MRateToHwRate(rate: pmlmeext->tx_rate); |
2672 | } |
2673 | |
2674 | ptxdesc->usb_txagg_num = pxmitframe->agg_num; |
2675 | } else if (pxmitframe->frame_tag == MGNT_FRAMETAG) { |
2676 | ptxdesc->macid = pattrib->mac_id; /* CAM_ID(MAC_ID) */ |
2677 | ptxdesc->qsel = pattrib->qsel; |
2678 | ptxdesc->rate_id = pattrib->raid; /* Rate ID */ |
2679 | ptxdesc->seq = pattrib->seqnum; |
2680 | ptxdesc->userate = 1; /* driver uses rate, 1M */ |
2681 | |
2682 | ptxdesc->mbssid = pattrib->mbssid & 0xF; |
2683 | |
2684 | ptxdesc->rty_lmt_en = 1; /* retry limit enable */ |
2685 | if (pattrib->retry_ctrl) { |
2686 | ptxdesc->data_rt_lmt = 6; |
2687 | } else { |
2688 | ptxdesc->data_rt_lmt = 12; |
2689 | } |
2690 | |
2691 | ptxdesc->datarate = MRateToHwRate(rate: pmlmeext->tx_rate); |
2692 | |
2693 | /* CCX-TXRPT ack for xmit mgmt frames. */ |
2694 | if (pxmitframe->ack_report) { |
2695 | ptxdesc->spe_rpt = 1; |
2696 | ptxdesc->sw_define = (u8)(GET_PRIMARY_ADAPTER(padapter)->xmitpriv.seq_no); |
2697 | } |
2698 | } else { |
2699 | ptxdesc->macid = pattrib->mac_id; /* CAM_ID(MAC_ID) */ |
2700 | ptxdesc->rate_id = pattrib->raid; /* Rate ID */ |
2701 | ptxdesc->qsel = pattrib->qsel; |
2702 | ptxdesc->seq = pattrib->seqnum; |
2703 | ptxdesc->userate = 1; /* driver uses rate */ |
2704 | ptxdesc->datarate = MRateToHwRate(rate: pmlmeext->tx_rate); |
2705 | } |
2706 | |
2707 | ptxdesc->pktlen = pattrib->last_txcmdsz; |
2708 | ptxdesc->offset = TXDESC_SIZE + OFFSET_SZ; |
2709 | |
2710 | if (bmcst) |
2711 | ptxdesc->bmc = 1; |
2712 | |
2713 | /* 2009.11.05. tynli_test. Suggested by SD4 Filen for FW LPS. |
2714 | * (1) The sequence number of each non-Qos frame / broadcast / |
2715 | * multicast / mgnt frame should be controlled by Hw because Fw |
2716 | * will also send null data which we cannot control when Fw LPS |
2717 | * enable. |
2718 | * --> default enable non-Qos data sequence number. 2010.06.23. |
2719 | * by tynli. |
2720 | * (2) Enable HW SEQ control for beacon packet, because we use |
2721 | * Hw beacon. |
2722 | * (3) Use HW Qos SEQ to control the seq num of Ext port non-Qos |
2723 | * packets. |
2724 | * 2010.06.23. Added by tynli. |
2725 | */ |
2726 | if (!pattrib->qos_en) /* Hw set sequence number */ |
2727 | ptxdesc->en_hwseq = 1; /* HWSEQ_EN */ |
2728 | } |
2729 | |
2730 | /* Description: |
2731 | * |
2732 | * Parameters: |
2733 | * pxmitframe xmitframe |
2734 | * pbuf where to fill tx desc |
2735 | */ |
2736 | void rtl8723b_update_txdesc(struct xmit_frame *pxmitframe, u8 *pbuf) |
2737 | { |
2738 | struct tx_desc *pdesc; |
2739 | |
2740 | rtl8723b_fill_default_txdesc(pxmitframe, pbuf); |
2741 | pdesc = (struct tx_desc *)pbuf; |
2742 | rtl8723b_cal_txdesc_chksum(ptxdesc: pdesc); |
2743 | } |
2744 | |
2745 | /* */ |
2746 | /* Description: In normal chip, we should send some packet to Hw which will be used by Fw */ |
2747 | /* in FW LPS mode. The function is to fill the Tx descriptor of this packets, then */ |
2748 | /* Fw can tell Hw to send these packet derectly. */ |
2749 | /* Added by tynli. 2009.10.15. */ |
2750 | /* */ |
2751 | /* type1:pspoll, type2:null */ |
2752 | void rtl8723b_fill_fake_txdesc( |
2753 | struct adapter *padapter, |
2754 | u8 *pDesc, |
2755 | u32 BufferLen, |
2756 | u8 IsPsPoll, |
2757 | u8 IsBTQosNull, |
2758 | u8 bDataFrame |
2759 | ) |
2760 | { |
2761 | /* Clear all status */ |
2762 | memset(pDesc, 0, TXDESC_SIZE); |
2763 | |
2764 | SET_TX_DESC_FIRST_SEG_8723B(pDesc, 1); /* bFirstSeg; */ |
2765 | SET_TX_DESC_LAST_SEG_8723B(pDesc, 1); /* bLastSeg; */ |
2766 | |
2767 | SET_TX_DESC_OFFSET_8723B(pDesc, 0x28); /* Offset = 32 */ |
2768 | |
2769 | SET_TX_DESC_PKT_SIZE_8723B(pDesc, BufferLen); /* Buffer size + command header */ |
2770 | SET_TX_DESC_QUEUE_SEL_8723B(pDesc, QSLT_MGNT); /* Fixed queue of Mgnt queue */ |
2771 | |
2772 | /* Set NAVUSEHDR to prevent Ps-poll AId filed to be changed to error value by Hw. */ |
2773 | if (IsPsPoll) { |
2774 | SET_TX_DESC_NAV_USE_HDR_8723B(pDesc, 1); |
2775 | } else { |
2776 | SET_TX_DESC_HWSEQ_EN_8723B(pDesc, 1); /* Hw set sequence number */ |
2777 | SET_TX_DESC_HWSEQ_SEL_8723B(pDesc, 0); |
2778 | } |
2779 | |
2780 | if (IsBTQosNull) { |
2781 | SET_TX_DESC_BT_INT_8723B(pDesc, 1); |
2782 | } |
2783 | |
2784 | SET_TX_DESC_USE_RATE_8723B(pDesc, 1); /* use data rate which is set by Sw */ |
2785 | SET_TX_DESC_OWN_8723B((u8 *)pDesc, 1); |
2786 | |
2787 | SET_TX_DESC_TX_RATE_8723B(pDesc, DESC8723B_RATE1M); |
2788 | |
2789 | /* */ |
2790 | /* Encrypt the data frame if under security mode excepct null data. Suggested by CCW. */ |
2791 | /* */ |
2792 | if (bDataFrame) { |
2793 | u32 EncAlg; |
2794 | |
2795 | EncAlg = padapter->securitypriv.dot11PrivacyAlgrthm; |
2796 | switch (EncAlg) { |
2797 | case _NO_PRIVACY_: |
2798 | SET_TX_DESC_SEC_TYPE_8723B(pDesc, 0x0); |
2799 | break; |
2800 | case _WEP40_: |
2801 | case _WEP104_: |
2802 | case _TKIP_: |
2803 | SET_TX_DESC_SEC_TYPE_8723B(pDesc, 0x1); |
2804 | break; |
2805 | case _SMS4_: |
2806 | SET_TX_DESC_SEC_TYPE_8723B(pDesc, 0x2); |
2807 | break; |
2808 | case _AES_: |
2809 | SET_TX_DESC_SEC_TYPE_8723B(pDesc, 0x3); |
2810 | break; |
2811 | default: |
2812 | SET_TX_DESC_SEC_TYPE_8723B(pDesc, 0x0); |
2813 | break; |
2814 | } |
2815 | } |
2816 | |
2817 | /* USB interface drop packet if the checksum of descriptor isn't correct. */ |
2818 | /* Using this checksum can let hardware recovery from packet bulk out error (e.g. Cancel URC, Bulk out error.). */ |
2819 | rtl8723b_cal_txdesc_chksum(ptxdesc: (struct tx_desc *)pDesc); |
2820 | } |
2821 | |
2822 | static void hw_var_set_opmode(struct adapter *padapter, u8 variable, u8 *val) |
2823 | { |
2824 | u8 val8; |
2825 | u8 mode = *((u8 *)val); |
2826 | |
2827 | { |
2828 | /* disable Port0 TSF update */ |
2829 | val8 = rtw_read8(adapter: padapter, REG_BCN_CTRL); |
2830 | val8 |= DIS_TSF_UDT; |
2831 | rtw_write8(adapter: padapter, REG_BCN_CTRL, val: val8); |
2832 | |
2833 | /* set net_type */ |
2834 | Set_MSR(padapter, type: mode); |
2835 | |
2836 | if ((mode == _HW_STATE_STATION_) || (mode == _HW_STATE_NOLINK_)) { |
2837 | { |
2838 | StopTxBeacon(padapter); |
2839 | } |
2840 | |
2841 | /* disable atim wnd */ |
2842 | rtw_write8(adapter: padapter, REG_BCN_CTRL, DIS_TSF_UDT|EN_BCN_FUNCTION|DIS_ATIM); |
2843 | /* rtw_write8(padapter, REG_BCN_CTRL, 0x18); */ |
2844 | } else if (mode == _HW_STATE_ADHOC_) { |
2845 | ResumeTxBeacon(padapter); |
2846 | rtw_write8(adapter: padapter, REG_BCN_CTRL, DIS_TSF_UDT|EN_BCN_FUNCTION|DIS_BCNQ_SUB); |
2847 | } else if (mode == _HW_STATE_AP_) { |
2848 | |
2849 | ResumeTxBeacon(padapter); |
2850 | |
2851 | rtw_write8(adapter: padapter, REG_BCN_CTRL, DIS_TSF_UDT|DIS_BCNQ_SUB); |
2852 | |
2853 | /* Set RCR */ |
2854 | rtw_write32(adapter: padapter, REG_RCR, val: 0x7000208e);/* CBSSID_DATA must set to 0, reject ICV_ERR packet */ |
2855 | /* enable to rx data frame */ |
2856 | rtw_write16(adapter: padapter, REG_RXFLTMAP2, val: 0xFFFF); |
2857 | /* enable to rx ps-poll */ |
2858 | rtw_write16(adapter: padapter, REG_RXFLTMAP1, val: 0x0400); |
2859 | |
2860 | /* Beacon Control related register for first time */ |
2861 | rtw_write8(adapter: padapter, REG_BCNDMATIM, val: 0x02); /* 2ms */ |
2862 | |
2863 | /* rtw_write8(padapter, REG_BCN_MAX_ERR, 0xFF); */ |
2864 | rtw_write8(adapter: padapter, REG_ATIMWND, val: 0x0a); /* 10ms */ |
2865 | rtw_write16(adapter: padapter, REG_BCNTCFG, val: 0x00); |
2866 | rtw_write16(adapter: padapter, REG_TBTT_PROHIBIT, val: 0xff04); |
2867 | rtw_write16(adapter: padapter, REG_TSFTR_SYN_OFFSET, val: 0x7fff);/* +32767 (~32ms) */ |
2868 | |
2869 | /* reset TSF */ |
2870 | rtw_write8(adapter: padapter, REG_DUAL_TSF_RST, BIT(0)); |
2871 | |
2872 | /* enable BCN0 Function for if1 */ |
2873 | /* don't enable update TSF0 for if1 (due to TSF update when beacon/probe rsp are received) */ |
2874 | rtw_write8(adapter: padapter, REG_BCN_CTRL, val: (DIS_TSF_UDT|EN_BCN_FUNCTION|EN_TXBCN_RPT|DIS_BCNQ_SUB)); |
2875 | |
2876 | /* SW_BCN_SEL - Port0 */ |
2877 | /* rtw_write8(Adapter, REG_DWBCN1_CTRL_8192E+2, rtw_read8(Adapter, REG_DWBCN1_CTRL_8192E+2) & ~BIT4); */ |
2878 | rtw_hal_set_hwreg(padapter, variable: HW_VAR_DL_BCN_SEL, NULL); |
2879 | |
2880 | /* select BCN on port 0 */ |
2881 | rtw_write8( |
2882 | adapter: padapter, |
2883 | REG_CCK_CHECK_8723B, |
2884 | val: (rtw_read8(adapter: padapter, REG_CCK_CHECK_8723B)&~BIT_BCN_PORT_SEL) |
2885 | ); |
2886 | |
2887 | /* dis BCN1 ATIM WND if if2 is station */ |
2888 | val8 = rtw_read8(adapter: padapter, REG_BCN_CTRL_1); |
2889 | val8 |= DIS_ATIM; |
2890 | rtw_write8(adapter: padapter, REG_BCN_CTRL_1, val: val8); |
2891 | } |
2892 | } |
2893 | } |
2894 | |
2895 | static void hw_var_set_macaddr(struct adapter *padapter, u8 variable, u8 *val) |
2896 | { |
2897 | u8 idx = 0; |
2898 | u32 reg_macid; |
2899 | |
2900 | reg_macid = REG_MACID; |
2901 | |
2902 | for (idx = 0 ; idx < 6; idx++) |
2903 | rtw_write8(GET_PRIMARY_ADAPTER(padapter), addr: (reg_macid+idx), val: val[idx]); |
2904 | } |
2905 | |
2906 | static void hw_var_set_bssid(struct adapter *padapter, u8 variable, u8 *val) |
2907 | { |
2908 | u8 idx = 0; |
2909 | u32 reg_bssid; |
2910 | |
2911 | reg_bssid = REG_BSSID; |
2912 | |
2913 | for (idx = 0 ; idx < 6; idx++) |
2914 | rtw_write8(adapter: padapter, addr: (reg_bssid+idx), val: val[idx]); |
2915 | } |
2916 | |
2917 | static void hw_var_set_bcn_func(struct adapter *padapter, u8 variable, u8 *val) |
2918 | { |
2919 | u32 bcn_ctrl_reg; |
2920 | |
2921 | bcn_ctrl_reg = REG_BCN_CTRL; |
2922 | |
2923 | if (*(u8 *)val) |
2924 | rtw_write8(adapter: padapter, addr: bcn_ctrl_reg, val: (EN_BCN_FUNCTION | EN_TXBCN_RPT)); |
2925 | else { |
2926 | u8 val8; |
2927 | val8 = rtw_read8(adapter: padapter, addr: bcn_ctrl_reg); |
2928 | val8 &= ~(EN_BCN_FUNCTION | EN_TXBCN_RPT); |
2929 | |
2930 | /* Always enable port0 beacon function for PSTDMA */ |
2931 | if (REG_BCN_CTRL == bcn_ctrl_reg) |
2932 | val8 |= EN_BCN_FUNCTION; |
2933 | |
2934 | rtw_write8(adapter: padapter, addr: bcn_ctrl_reg, val: val8); |
2935 | } |
2936 | } |
2937 | |
2938 | static void hw_var_set_correct_tsf(struct adapter *padapter, u8 variable, u8 *val) |
2939 | { |
2940 | u8 val8; |
2941 | u64 tsf; |
2942 | struct mlme_ext_priv *pmlmeext; |
2943 | struct mlme_ext_info *pmlmeinfo; |
2944 | |
2945 | |
2946 | pmlmeext = &padapter->mlmeextpriv; |
2947 | pmlmeinfo = &pmlmeext->mlmext_info; |
2948 | |
2949 | tsf = pmlmeext->TSFValue-do_div(pmlmeext->TSFValue, (pmlmeinfo->bcn_interval*1024))-1024; /* us */ |
2950 | |
2951 | if ( |
2952 | ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) || |
2953 | ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) |
2954 | ) |
2955 | StopTxBeacon(padapter); |
2956 | |
2957 | { |
2958 | /* disable related TSF function */ |
2959 | val8 = rtw_read8(adapter: padapter, REG_BCN_CTRL); |
2960 | val8 &= ~EN_BCN_FUNCTION; |
2961 | rtw_write8(adapter: padapter, REG_BCN_CTRL, val: val8); |
2962 | |
2963 | rtw_write32(adapter: padapter, REG_TSFTR, val: tsf); |
2964 | rtw_write32(adapter: padapter, REG_TSFTR+4, val: tsf>>32); |
2965 | |
2966 | /* enable related TSF function */ |
2967 | val8 = rtw_read8(adapter: padapter, REG_BCN_CTRL); |
2968 | val8 |= EN_BCN_FUNCTION; |
2969 | rtw_write8(adapter: padapter, REG_BCN_CTRL, val: val8); |
2970 | } |
2971 | |
2972 | if ( |
2973 | ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) || |
2974 | ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) |
2975 | ) |
2976 | ResumeTxBeacon(padapter); |
2977 | } |
2978 | |
2979 | static void hw_var_set_mlme_disconnect(struct adapter *padapter, u8 variable, u8 *val) |
2980 | { |
2981 | u8 val8; |
2982 | |
2983 | /* Set RCR to not to receive data frame when NO LINK state */ |
2984 | /* rtw_write32(padapter, REG_RCR, rtw_read32(padapter, REG_RCR) & ~RCR_ADF); */ |
2985 | /* reject all data frames */ |
2986 | rtw_write16(adapter: padapter, REG_RXFLTMAP2, val: 0); |
2987 | |
2988 | /* reset TSF */ |
2989 | rtw_write8(adapter: padapter, REG_DUAL_TSF_RST, BIT(0)); |
2990 | |
2991 | /* disable update TSF */ |
2992 | val8 = rtw_read8(adapter: padapter, REG_BCN_CTRL); |
2993 | val8 |= DIS_TSF_UDT; |
2994 | rtw_write8(adapter: padapter, REG_BCN_CTRL, val: val8); |
2995 | } |
2996 | |
2997 | static void hw_var_set_mlme_sitesurvey(struct adapter *padapter, u8 variable, u8 *val) |
2998 | { |
2999 | u32 value_rcr, rcr_clear_bit, reg_bcn_ctl; |
3000 | u16 value_rxfltmap2; |
3001 | u8 val8; |
3002 | struct hal_com_data *pHalData; |
3003 | struct mlme_priv *pmlmepriv; |
3004 | |
3005 | |
3006 | pHalData = GET_HAL_DATA(padapter); |
3007 | pmlmepriv = &padapter->mlmepriv; |
3008 | |
3009 | reg_bcn_ctl = REG_BCN_CTRL; |
3010 | |
3011 | rcr_clear_bit = RCR_CBSSID_BCN; |
3012 | |
3013 | /* config RCR to receive different BSSID & not to receive data frame */ |
3014 | value_rxfltmap2 = 0; |
3015 | |
3016 | if ((check_fwstate(pmlmepriv, WIFI_AP_STATE) == true)) |
3017 | rcr_clear_bit = RCR_CBSSID_BCN; |
3018 | |
3019 | value_rcr = rtw_read32(adapter: padapter, REG_RCR); |
3020 | |
3021 | if (*((u8 *)val)) { |
3022 | /* under sitesurvey */ |
3023 | value_rcr &= ~(rcr_clear_bit); |
3024 | rtw_write32(adapter: padapter, REG_RCR, val: value_rcr); |
3025 | |
3026 | rtw_write16(adapter: padapter, REG_RXFLTMAP2, val: value_rxfltmap2); |
3027 | |
3028 | if (check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_ADHOC_STATE | WIFI_ADHOC_MASTER_STATE)) { |
3029 | /* disable update TSF */ |
3030 | val8 = rtw_read8(adapter: padapter, addr: reg_bcn_ctl); |
3031 | val8 |= DIS_TSF_UDT; |
3032 | rtw_write8(adapter: padapter, addr: reg_bcn_ctl, val: val8); |
3033 | } |
3034 | |
3035 | /* Save original RRSR setting. */ |
3036 | pHalData->RegRRSR = rtw_read16(adapter: padapter, REG_RRSR); |
3037 | } else { |
3038 | /* sitesurvey done */ |
3039 | if (check_fwstate(pmlmepriv, state: (_FW_LINKED|WIFI_AP_STATE))) |
3040 | /* enable to rx data frame */ |
3041 | rtw_write16(adapter: padapter, REG_RXFLTMAP2, val: 0xFFFF); |
3042 | |
3043 | if (check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_ADHOC_STATE | WIFI_ADHOC_MASTER_STATE)) { |
3044 | /* enable update TSF */ |
3045 | val8 = rtw_read8(adapter: padapter, addr: reg_bcn_ctl); |
3046 | val8 &= ~DIS_TSF_UDT; |
3047 | rtw_write8(adapter: padapter, addr: reg_bcn_ctl, val: val8); |
3048 | } |
3049 | |
3050 | value_rcr |= rcr_clear_bit; |
3051 | rtw_write32(adapter: padapter, REG_RCR, val: value_rcr); |
3052 | |
3053 | /* Restore original RRSR setting. */ |
3054 | rtw_write16(adapter: padapter, REG_RRSR, val: pHalData->RegRRSR); |
3055 | } |
3056 | } |
3057 | |
3058 | static void hw_var_set_mlme_join(struct adapter *padapter, u8 variable, u8 *val) |
3059 | { |
3060 | u8 val8; |
3061 | u16 val16; |
3062 | u32 val32; |
3063 | u8 RetryLimit; |
3064 | u8 type; |
3065 | struct mlme_priv *pmlmepriv; |
3066 | struct eeprom_priv *pEEPROM; |
3067 | |
3068 | |
3069 | RetryLimit = 0x30; |
3070 | type = *(u8 *)val; |
3071 | pmlmepriv = &padapter->mlmepriv; |
3072 | pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); |
3073 | |
3074 | if (type == 0) { /* prepare to join */ |
3075 | /* enable to rx data frame.Accept all data frame */ |
3076 | /* rtw_write32(padapter, REG_RCR, rtw_read32(padapter, REG_RCR)|RCR_ADF); */ |
3077 | rtw_write16(adapter: padapter, REG_RXFLTMAP2, val: 0xFFFF); |
3078 | |
3079 | val32 = rtw_read32(adapter: padapter, REG_RCR); |
3080 | if (padapter->in_cta_test) |
3081 | val32 &= ~(RCR_CBSSID_DATA | RCR_CBSSID_BCN);/* RCR_ADF */ |
3082 | else |
3083 | val32 |= RCR_CBSSID_DATA|RCR_CBSSID_BCN; |
3084 | rtw_write32(adapter: padapter, REG_RCR, val: val32); |
3085 | |
3086 | if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) |
3087 | RetryLimit = (pEEPROM->CustomerID == RT_CID_CCX) ? 7 : 48; |
3088 | else /* Ad-hoc Mode */ |
3089 | RetryLimit = 0x7; |
3090 | } else if (type == 1) /* joinbss_event call back when join res < 0 */ |
3091 | rtw_write16(adapter: padapter, REG_RXFLTMAP2, val: 0x00); |
3092 | else if (type == 2) { /* sta add event call back */ |
3093 | /* enable update TSF */ |
3094 | val8 = rtw_read8(adapter: padapter, REG_BCN_CTRL); |
3095 | val8 &= ~DIS_TSF_UDT; |
3096 | rtw_write8(adapter: padapter, REG_BCN_CTRL, val: val8); |
3097 | |
3098 | if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE)) |
3099 | RetryLimit = 0x7; |
3100 | } |
3101 | |
3102 | val16 = (RetryLimit << RETRY_LIMIT_SHORT_SHIFT) | (RetryLimit << RETRY_LIMIT_LONG_SHIFT); |
3103 | rtw_write16(adapter: padapter, REG_RL, val: val16); |
3104 | } |
3105 | |
3106 | void CCX_FwC2HTxRpt_8723b(struct adapter *padapter, u8 *pdata, u8 len) |
3107 | { |
3108 | |
3109 | #define GET_8723B_C2H_TX_RPT_LIFE_TIME_OVER(_Header) LE_BITS_TO_1BYTE((_Header + 0), 6, 1) |
3110 | #define GET_8723B_C2H_TX_RPT_RETRY_OVER(_Header) LE_BITS_TO_1BYTE((_Header + 0), 7, 1) |
3111 | |
3112 | if (GET_8723B_C2H_TX_RPT_RETRY_OVER(pdata) | GET_8723B_C2H_TX_RPT_LIFE_TIME_OVER(pdata)) { |
3113 | rtw_ack_tx_done(pxmitpriv: &padapter->xmitpriv, status: RTW_SCTX_DONE_CCX_PKT_FAIL); |
3114 | } |
3115 | /* |
3116 | else if (seq_no != padapter->xmitpriv.seq_no) { |
3117 | rtw_ack_tx_done(&padapter->xmitpriv, RTW_SCTX_DONE_CCX_PKT_FAIL); |
3118 | } |
3119 | */ |
3120 | else |
3121 | rtw_ack_tx_done(pxmitpriv: &padapter->xmitpriv, status: RTW_SCTX_DONE_SUCCESS); |
3122 | } |
3123 | |
3124 | s32 c2h_id_filter_ccx_8723b(u8 *buf) |
3125 | { |
3126 | struct c2h_evt_hdr_88xx *c2h_evt = (struct c2h_evt_hdr_88xx *)buf; |
3127 | s32 ret = false; |
3128 | if (c2h_evt->id == C2H_CCX_TX_RPT) |
3129 | ret = true; |
3130 | |
3131 | return ret; |
3132 | } |
3133 | |
3134 | |
3135 | s32 c2h_handler_8723b(struct adapter *padapter, u8 *buf) |
3136 | { |
3137 | struct c2h_evt_hdr_88xx *pC2hEvent = (struct c2h_evt_hdr_88xx *)buf; |
3138 | s32 ret = _SUCCESS; |
3139 | |
3140 | if (!pC2hEvent) { |
3141 | ret = _FAIL; |
3142 | goto exit; |
3143 | } |
3144 | |
3145 | switch (pC2hEvent->id) { |
3146 | case C2H_AP_RPT_RSP: |
3147 | break; |
3148 | case C2H_DBG: |
3149 | { |
3150 | } |
3151 | break; |
3152 | |
3153 | case C2H_CCX_TX_RPT: |
3154 | /* CCX_FwC2HTxRpt(padapter, QueueID, pC2hEvent->payload); */ |
3155 | break; |
3156 | |
3157 | case C2H_EXT_RA_RPT: |
3158 | /* C2HExtRaRptHandler(padapter, pC2hEvent->payload, C2hEvent.CmdLen); */ |
3159 | break; |
3160 | |
3161 | case C2H_HW_INFO_EXCH: |
3162 | break; |
3163 | |
3164 | case C2H_8723B_BT_INFO: |
3165 | hal_btcoex_BtInfoNotify(padapter, length: pC2hEvent->plen, tmpBuf: pC2hEvent->payload); |
3166 | break; |
3167 | |
3168 | default: |
3169 | break; |
3170 | } |
3171 | |
3172 | /* Clear event to notify FW we have read the command. */ |
3173 | /* Note: */ |
3174 | /* If this field isn't clear, the FW won't update the next command message. */ |
3175 | /* rtw_write8(padapter, REG_C2HEVT_CLEAR, C2H_EVT_HOST_CLOSE); */ |
3176 | exit: |
3177 | return ret; |
3178 | } |
3179 | |
3180 | static void process_c2h_event(struct adapter *padapter, struct c2h_evt_hdr_t *pC2hEvent, u8 *c2hBuf) |
3181 | { |
3182 | if (!c2hBuf) |
3183 | return; |
3184 | |
3185 | switch (pC2hEvent->CmdID) { |
3186 | case C2H_AP_RPT_RSP: |
3187 | break; |
3188 | case C2H_DBG: |
3189 | { |
3190 | } |
3191 | break; |
3192 | |
3193 | case C2H_CCX_TX_RPT: |
3194 | /* CCX_FwC2HTxRpt(padapter, QueueID, tmpBuf); */ |
3195 | break; |
3196 | |
3197 | case C2H_EXT_RA_RPT: |
3198 | /* C2HExtRaRptHandler(padapter, tmpBuf, C2hEvent.CmdLen); */ |
3199 | break; |
3200 | |
3201 | case C2H_HW_INFO_EXCH: |
3202 | break; |
3203 | |
3204 | case C2H_8723B_BT_INFO: |
3205 | hal_btcoex_BtInfoNotify(padapter, length: pC2hEvent->CmdLen, tmpBuf: c2hBuf); |
3206 | break; |
3207 | |
3208 | default: |
3209 | break; |
3210 | } |
3211 | } |
3212 | |
3213 | void C2HPacketHandler_8723B(struct adapter *padapter, u8 *pbuffer, u16 length) |
3214 | { |
3215 | struct c2h_evt_hdr_t C2hEvent; |
3216 | u8 *tmpBuf = NULL; |
3217 | C2hEvent.CmdID = pbuffer[0]; |
3218 | C2hEvent.CmdSeq = pbuffer[1]; |
3219 | C2hEvent.CmdLen = length-2; |
3220 | tmpBuf = pbuffer+2; |
3221 | |
3222 | process_c2h_event(padapter, pC2hEvent: &C2hEvent, c2hBuf: tmpBuf); |
3223 | /* c2h_handler_8723b(padapter,&C2hEvent); */ |
3224 | } |
3225 | |
3226 | void SetHwReg8723B(struct adapter *padapter, u8 variable, u8 *val) |
3227 | { |
3228 | struct hal_com_data *pHalData = GET_HAL_DATA(padapter); |
3229 | u8 val8; |
3230 | u32 val32; |
3231 | |
3232 | switch (variable) { |
3233 | case HW_VAR_MEDIA_STATUS: |
3234 | val8 = rtw_read8(adapter: padapter, MSR) & 0x0c; |
3235 | val8 |= *val; |
3236 | rtw_write8(adapter: padapter, MSR, val: val8); |
3237 | break; |
3238 | |
3239 | case HW_VAR_MEDIA_STATUS1: |
3240 | val8 = rtw_read8(adapter: padapter, MSR) & 0x03; |
3241 | val8 |= *val << 2; |
3242 | rtw_write8(adapter: padapter, MSR, val: val8); |
3243 | break; |
3244 | |
3245 | case HW_VAR_SET_OPMODE: |
3246 | hw_var_set_opmode(padapter, variable, val); |
3247 | break; |
3248 | |
3249 | case HW_VAR_MAC_ADDR: |
3250 | hw_var_set_macaddr(padapter, variable, val); |
3251 | break; |
3252 | |
3253 | case HW_VAR_BSSID: |
3254 | hw_var_set_bssid(padapter, variable, val); |
3255 | break; |
3256 | |
3257 | case HW_VAR_BASIC_RATE: |
3258 | { |
3259 | struct mlme_ext_info *mlmext_info = &padapter->mlmeextpriv.mlmext_info; |
3260 | u16 BrateCfg = 0; |
3261 | u16 rrsr_2g_force_mask = (RRSR_11M|RRSR_5_5M|RRSR_1M); |
3262 | u16 rrsr_2g_allow_mask = (RRSR_24M|RRSR_12M|RRSR_6M|RRSR_CCK_RATES); |
3263 | |
3264 | HalSetBrateCfg(Adapter: padapter, mBratesOS: val, pBrateCfg: &BrateCfg); |
3265 | |
3266 | /* apply force and allow mask */ |
3267 | BrateCfg |= rrsr_2g_force_mask; |
3268 | BrateCfg &= rrsr_2g_allow_mask; |
3269 | |
3270 | /* IOT consideration */ |
3271 | if (mlmext_info->assoc_AP_vendor == HT_IOT_PEER_CISCO) { |
3272 | /* if peer is cisco and didn't use ofdm rate, we enable 6M ack */ |
3273 | if ((BrateCfg & (RRSR_24M|RRSR_12M|RRSR_6M)) == 0) |
3274 | BrateCfg |= RRSR_6M; |
3275 | } |
3276 | |
3277 | pHalData->BasicRateSet = BrateCfg; |
3278 | |
3279 | /* Set RRSR rate table. */ |
3280 | rtw_write16(adapter: padapter, REG_RRSR, val: BrateCfg); |
3281 | rtw_write8(adapter: padapter, REG_RRSR+2, val: rtw_read8(adapter: padapter, REG_RRSR+2)&0xf0); |
3282 | } |
3283 | break; |
3284 | |
3285 | case HW_VAR_TXPAUSE: |
3286 | rtw_write8(adapter: padapter, REG_TXPAUSE, val: *val); |
3287 | break; |
3288 | |
3289 | case HW_VAR_BCN_FUNC: |
3290 | hw_var_set_bcn_func(padapter, variable, val); |
3291 | break; |
3292 | |
3293 | case HW_VAR_CORRECT_TSF: |
3294 | hw_var_set_correct_tsf(padapter, variable, val); |
3295 | break; |
3296 | |
3297 | case HW_VAR_CHECK_BSSID: |
3298 | { |
3299 | u32 val32; |
3300 | val32 = rtw_read32(adapter: padapter, REG_RCR); |
3301 | if (*val) |
3302 | val32 |= RCR_CBSSID_DATA|RCR_CBSSID_BCN; |
3303 | else |
3304 | val32 &= ~(RCR_CBSSID_DATA|RCR_CBSSID_BCN); |
3305 | rtw_write32(adapter: padapter, REG_RCR, val: val32); |
3306 | } |
3307 | break; |
3308 | |
3309 | case HW_VAR_MLME_DISCONNECT: |
3310 | hw_var_set_mlme_disconnect(padapter, variable, val); |
3311 | break; |
3312 | |
3313 | case HW_VAR_MLME_SITESURVEY: |
3314 | hw_var_set_mlme_sitesurvey(padapter, variable, val); |
3315 | |
3316 | hal_btcoex_ScanNotify(padapter, type: *val?true:false); |
3317 | break; |
3318 | |
3319 | case HW_VAR_MLME_JOIN: |
3320 | hw_var_set_mlme_join(padapter, variable, val); |
3321 | |
3322 | switch (*val) { |
3323 | case 0: |
3324 | /* prepare to join */ |
3325 | hal_btcoex_ConnectNotify(padapter, action: true); |
3326 | break; |
3327 | case 1: |
3328 | /* joinbss_event callback when join res < 0 */ |
3329 | hal_btcoex_ConnectNotify(padapter, action: false); |
3330 | break; |
3331 | case 2: |
3332 | /* sta add event callback */ |
3333 | /* rtw_btcoex_MediaStatusNotify(padapter, RT_MEDIA_CONNECT); */ |
3334 | break; |
3335 | } |
3336 | break; |
3337 | |
3338 | case HW_VAR_ON_RCR_AM: |
3339 | val32 = rtw_read32(adapter: padapter, REG_RCR); |
3340 | val32 |= RCR_AM; |
3341 | rtw_write32(adapter: padapter, REG_RCR, val: val32); |
3342 | break; |
3343 | |
3344 | case HW_VAR_OFF_RCR_AM: |
3345 | val32 = rtw_read32(adapter: padapter, REG_RCR); |
3346 | val32 &= ~RCR_AM; |
3347 | rtw_write32(adapter: padapter, REG_RCR, val: val32); |
3348 | break; |
3349 | |
3350 | case HW_VAR_BEACON_INTERVAL: |
3351 | rtw_write16(adapter: padapter, REG_BCN_INTERVAL, val: *((u16 *)val)); |
3352 | break; |
3353 | |
3354 | case HW_VAR_SLOT_TIME: |
3355 | rtw_write8(adapter: padapter, REG_SLOT, val: *val); |
3356 | break; |
3357 | |
3358 | case HW_VAR_RESP_SIFS: |
3359 | /* SIFS_Timer = 0x0a0a0808; */ |
3360 | /* RESP_SIFS for CCK */ |
3361 | rtw_write8(adapter: padapter, REG_RESP_SIFS_CCK, val: val[0]); /* SIFS_T2T_CCK (0x08) */ |
3362 | rtw_write8(adapter: padapter, REG_RESP_SIFS_CCK+1, val: val[1]); /* SIFS_R2T_CCK(0x08) */ |
3363 | /* RESP_SIFS for OFDM */ |
3364 | rtw_write8(adapter: padapter, REG_RESP_SIFS_OFDM, val: val[2]); /* SIFS_T2T_OFDM (0x0a) */ |
3365 | rtw_write8(adapter: padapter, REG_RESP_SIFS_OFDM+1, val: val[3]); /* SIFS_R2T_OFDM(0x0a) */ |
3366 | break; |
3367 | |
3368 | case HW_VAR_ACK_PREAMBLE: |
3369 | { |
3370 | u8 regTmp; |
3371 | u8 bShortPreamble = *val; |
3372 | |
3373 | /* Joseph marked out for Netgear 3500 TKIP channel 7 issue.(Temporarily) */ |
3374 | /* regTmp = (pHalData->nCur40MhzPrimeSC)<<5; */ |
3375 | regTmp = 0; |
3376 | if (bShortPreamble) |
3377 | regTmp |= 0x80; |
3378 | rtw_write8(adapter: padapter, REG_RRSR+2, val: regTmp); |
3379 | } |
3380 | break; |
3381 | |
3382 | case HW_VAR_CAM_EMPTY_ENTRY: |
3383 | { |
3384 | u8 ucIndex = *val; |
3385 | u8 i; |
3386 | u32 ulCommand = 0; |
3387 | u32 ulContent = 0; |
3388 | u32 ulEncAlgo = CAM_AES; |
3389 | |
3390 | for (i = 0; i < CAM_CONTENT_COUNT; i++) { |
3391 | /* filled id in CAM config 2 byte */ |
3392 | if (i == 0) { |
3393 | ulContent |= (ucIndex & 0x03) | ((u16)(ulEncAlgo)<<2); |
3394 | /* ulContent |= CAM_VALID; */ |
3395 | } else |
3396 | ulContent = 0; |
3397 | |
3398 | /* polling bit, and No Write enable, and address */ |
3399 | ulCommand = CAM_CONTENT_COUNT*ucIndex+i; |
3400 | ulCommand = ulCommand | CAM_POLLINIG | CAM_WRITE; |
3401 | /* write content 0 is equal to mark as invalid */ |
3402 | rtw_write32(adapter: padapter, WCAMI, val: ulContent); /* mdelay(40); */ |
3403 | rtw_write32(adapter: padapter, RWCAM, val: ulCommand); /* mdelay(40); */ |
3404 | } |
3405 | } |
3406 | break; |
3407 | |
3408 | case HW_VAR_CAM_INVALID_ALL: |
3409 | rtw_write32(adapter: padapter, RWCAM, BIT(31)|BIT(30)); |
3410 | break; |
3411 | |
3412 | case HW_VAR_CAM_WRITE: |
3413 | { |
3414 | u32 cmd; |
3415 | u32 *cam_val = (u32 *)val; |
3416 | |
3417 | rtw_write32(adapter: padapter, WCAMI, val: cam_val[0]); |
3418 | |
3419 | cmd = CAM_POLLINIG | CAM_WRITE | cam_val[1]; |
3420 | rtw_write32(adapter: padapter, RWCAM, val: cmd); |
3421 | } |
3422 | break; |
3423 | |
3424 | case HW_VAR_AC_PARAM_VO: |
3425 | rtw_write32(adapter: padapter, REG_EDCA_VO_PARAM, val: *((u32 *)val)); |
3426 | break; |
3427 | |
3428 | case HW_VAR_AC_PARAM_VI: |
3429 | rtw_write32(adapter: padapter, REG_EDCA_VI_PARAM, val: *((u32 *)val)); |
3430 | break; |
3431 | |
3432 | case HW_VAR_AC_PARAM_BE: |
3433 | pHalData->AcParam_BE = ((u32 *)(val))[0]; |
3434 | rtw_write32(adapter: padapter, REG_EDCA_BE_PARAM, val: *((u32 *)val)); |
3435 | break; |
3436 | |
3437 | case HW_VAR_AC_PARAM_BK: |
3438 | rtw_write32(adapter: padapter, REG_EDCA_BK_PARAM, val: *((u32 *)val)); |
3439 | break; |
3440 | |
3441 | case HW_VAR_ACM_CTRL: |
3442 | { |
3443 | u8 ctrl = *((u8 *)val); |
3444 | u8 hwctrl = 0; |
3445 | |
3446 | if (ctrl != 0) { |
3447 | hwctrl |= AcmHw_HwEn; |
3448 | |
3449 | if (ctrl & BIT(1)) /* BE */ |
3450 | hwctrl |= AcmHw_BeqEn; |
3451 | |
3452 | if (ctrl & BIT(2)) /* VI */ |
3453 | hwctrl |= AcmHw_ViqEn; |
3454 | |
3455 | if (ctrl & BIT(3)) /* VO */ |
3456 | hwctrl |= AcmHw_VoqEn; |
3457 | } |
3458 | |
3459 | rtw_write8(adapter: padapter, REG_ACMHWCTRL, val: hwctrl); |
3460 | } |
3461 | break; |
3462 | |
3463 | case HW_VAR_AMPDU_FACTOR: |
3464 | { |
3465 | u32 AMPDULen = (*((u8 *)val)); |
3466 | |
3467 | if (AMPDULen < HT_AGG_SIZE_32K) |
3468 | AMPDULen = (0x2000 << (*((u8 *)val)))-1; |
3469 | else |
3470 | AMPDULen = 0x7fff; |
3471 | |
3472 | rtw_write32(adapter: padapter, REG_AMPDU_MAX_LENGTH_8723B, val: AMPDULen); |
3473 | } |
3474 | break; |
3475 | |
3476 | case HW_VAR_H2C_FW_PWRMODE: |
3477 | { |
3478 | u8 psmode = *val; |
3479 | |
3480 | /* Forece leave RF low power mode for 1T1R to prevent conficting setting in Fw power */ |
3481 | /* saving sequence. 2010.06.07. Added by tynli. Suggested by SD3 yschang. */ |
3482 | if (psmode != PS_MODE_ACTIVE) { |
3483 | ODM_RF_Saving(pDM_VOID: &pHalData->odmpriv, bForceInNormal: true); |
3484 | } |
3485 | |
3486 | /* if (psmode != PS_MODE_ACTIVE) { */ |
3487 | /* rtl8723b_set_lowpwr_lps_cmd(padapter, true); */ |
3488 | /* else { */ |
3489 | /* rtl8723b_set_lowpwr_lps_cmd(padapter, false); */ |
3490 | /* */ |
3491 | rtl8723b_set_FwPwrMode_cmd(padapter, Mode: psmode); |
3492 | } |
3493 | break; |
3494 | case HW_VAR_H2C_PS_TUNE_PARAM: |
3495 | rtl8723b_set_FwPsTuneParam_cmd(padapter); |
3496 | break; |
3497 | |
3498 | case HW_VAR_H2C_FW_JOINBSSRPT: |
3499 | rtl8723b_set_FwJoinBssRpt_cmd(padapter, mstatus: *val); |
3500 | break; |
3501 | |
3502 | case HW_VAR_INITIAL_GAIN: |
3503 | { |
3504 | struct dig_t *pDigTable = &pHalData->odmpriv.DM_DigTable; |
3505 | u32 rx_gain = *(u32 *)val; |
3506 | |
3507 | if (rx_gain == 0xff) {/* restore rx gain */ |
3508 | ODM_Write_DIG(pDM_VOID: &pHalData->odmpriv, CurrentIGI: pDigTable->BackupIGValue); |
3509 | } else { |
3510 | pDigTable->BackupIGValue = pDigTable->CurIGValue; |
3511 | ODM_Write_DIG(pDM_VOID: &pHalData->odmpriv, CurrentIGI: rx_gain); |
3512 | } |
3513 | } |
3514 | break; |
3515 | |
3516 | case HW_VAR_EFUSE_USAGE: |
3517 | pHalData->EfuseUsedPercentage = *val; |
3518 | break; |
3519 | |
3520 | case HW_VAR_EFUSE_BYTES: |
3521 | pHalData->EfuseUsedBytes = *((u16 *)val); |
3522 | break; |
3523 | |
3524 | case HW_VAR_EFUSE_BT_USAGE: |
3525 | #ifdef HAL_EFUSE_MEMORY |
3526 | pHalData->EfuseHal.BTEfuseUsedPercentage = *val; |
3527 | #endif |
3528 | break; |
3529 | |
3530 | case HW_VAR_EFUSE_BT_BYTES: |
3531 | #ifdef HAL_EFUSE_MEMORY |
3532 | pHalData->EfuseHal.BTEfuseUsedBytes = *((u16 *)val); |
3533 | #else |
3534 | BTEfuseUsedBytes = *((u16 *)val); |
3535 | #endif |
3536 | break; |
3537 | |
3538 | case HW_VAR_FIFO_CLEARN_UP: |
3539 | { |
3540 | #define RW_RELEASE_EN BIT(18) |
3541 | #define RXDMA_IDLE BIT(17) |
3542 | |
3543 | struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); |
3544 | u8 trycnt = 100; |
3545 | |
3546 | /* pause tx */ |
3547 | rtw_write8(adapter: padapter, REG_TXPAUSE, val: 0xff); |
3548 | |
3549 | /* keep sn */ |
3550 | padapter->xmitpriv.nqos_ssn = rtw_read16(adapter: padapter, REG_NQOS_SEQ); |
3551 | |
3552 | if (!pwrpriv->bkeepfwalive) { |
3553 | /* RX DMA stop */ |
3554 | val32 = rtw_read32(adapter: padapter, REG_RXPKT_NUM); |
3555 | val32 |= RW_RELEASE_EN; |
3556 | rtw_write32(adapter: padapter, REG_RXPKT_NUM, val: val32); |
3557 | do { |
3558 | val32 = rtw_read32(adapter: padapter, REG_RXPKT_NUM); |
3559 | val32 &= RXDMA_IDLE; |
3560 | if (val32) |
3561 | break; |
3562 | } while (--trycnt); |
3563 | |
3564 | /* RQPN Load 0 */ |
3565 | rtw_write16(adapter: padapter, REG_RQPN_NPQ, val: 0); |
3566 | rtw_write32(adapter: padapter, REG_RQPN, val: 0x80000000); |
3567 | mdelay(2); |
3568 | } |
3569 | } |
3570 | break; |
3571 | |
3572 | case HW_VAR_APFM_ON_MAC: |
3573 | pHalData->bMacPwrCtrlOn = *val; |
3574 | break; |
3575 | |
3576 | case HW_VAR_NAV_UPPER: |
3577 | { |
3578 | u32 usNavUpper = *((u32 *)val); |
3579 | |
3580 | if (usNavUpper > HAL_NAV_UPPER_UNIT_8723B * 0xFF) |
3581 | break; |
3582 | |
3583 | usNavUpper = DIV_ROUND_UP(usNavUpper, |
3584 | HAL_NAV_UPPER_UNIT_8723B); |
3585 | rtw_write8(adapter: padapter, REG_NAV_UPPER, val: (u8)usNavUpper); |
3586 | } |
3587 | break; |
3588 | |
3589 | case HW_VAR_H2C_MEDIA_STATUS_RPT: |
3590 | { |
3591 | u16 mstatus_rpt = (*(u16 *)val); |
3592 | u8 mstatus, macId; |
3593 | |
3594 | mstatus = (u8) (mstatus_rpt & 0xFF); |
3595 | macId = (u8)(mstatus_rpt >> 8); |
3596 | rtl8723b_set_FwMediaStatusRpt_cmd(padapter, mstatus, macid: macId); |
3597 | } |
3598 | break; |
3599 | case HW_VAR_BCN_VALID: |
3600 | { |
3601 | /* BCN_VALID, BIT16 of REG_TDECTRL = BIT0 of REG_TDECTRL+2, write 1 to clear, Clear by sw */ |
3602 | val8 = rtw_read8(adapter: padapter, REG_TDECTRL+2); |
3603 | val8 |= BIT(0); |
3604 | rtw_write8(adapter: padapter, REG_TDECTRL+2, val: val8); |
3605 | } |
3606 | break; |
3607 | |
3608 | case HW_VAR_DL_BCN_SEL: |
3609 | { |
3610 | /* SW_BCN_SEL - Port0 */ |
3611 | val8 = rtw_read8(adapter: padapter, REG_DWBCN1_CTRL_8723B+2); |
3612 | val8 &= ~BIT(4); |
3613 | rtw_write8(adapter: padapter, REG_DWBCN1_CTRL_8723B+2, val: val8); |
3614 | } |
3615 | break; |
3616 | |
3617 | case HW_VAR_DO_IQK: |
3618 | pHalData->bNeedIQK = true; |
3619 | break; |
3620 | |
3621 | case HW_VAR_DL_RSVD_PAGE: |
3622 | if (check_fwstate(pmlmepriv: &padapter->mlmepriv, WIFI_AP_STATE) == true) |
3623 | rtl8723b_download_BTCoex_AP_mode_rsvd_page(padapter); |
3624 | else |
3625 | rtl8723b_download_rsvd_page(padapter, mstatus: RT_MEDIA_CONNECT); |
3626 | break; |
3627 | |
3628 | case HW_VAR_MACID_SLEEP: |
3629 | /* Input is MACID */ |
3630 | val32 = *(u32 *)val; |
3631 | if (val32 > 31) |
3632 | break; |
3633 | |
3634 | val8 = (u8)val32; /* macid is between 0~31 */ |
3635 | |
3636 | val32 = rtw_read32(adapter: padapter, REG_MACID_SLEEP); |
3637 | if (val32 & BIT(val8)) |
3638 | break; |
3639 | val32 |= BIT(val8); |
3640 | rtw_write32(adapter: padapter, REG_MACID_SLEEP, val: val32); |
3641 | break; |
3642 | |
3643 | case HW_VAR_MACID_WAKEUP: |
3644 | /* Input is MACID */ |
3645 | val32 = *(u32 *)val; |
3646 | if (val32 > 31) |
3647 | break; |
3648 | |
3649 | val8 = (u8)val32; /* macid is between 0~31 */ |
3650 | |
3651 | val32 = rtw_read32(adapter: padapter, REG_MACID_SLEEP); |
3652 | if (!(val32 & BIT(val8))) |
3653 | break; |
3654 | val32 &= ~BIT(val8); |
3655 | rtw_write32(adapter: padapter, REG_MACID_SLEEP, val: val32); |
3656 | break; |
3657 | |
3658 | default: |
3659 | SetHwReg(padapter, variable, val); |
3660 | break; |
3661 | } |
3662 | } |
3663 | |
3664 | void GetHwReg8723B(struct adapter *padapter, u8 variable, u8 *val) |
3665 | { |
3666 | struct hal_com_data *pHalData = GET_HAL_DATA(padapter); |
3667 | u8 val8; |
3668 | u16 val16; |
3669 | |
3670 | switch (variable) { |
3671 | case HW_VAR_TXPAUSE: |
3672 | *val = rtw_read8(adapter: padapter, REG_TXPAUSE); |
3673 | break; |
3674 | |
3675 | case HW_VAR_BCN_VALID: |
3676 | { |
3677 | /* BCN_VALID, BIT16 of REG_TDECTRL = BIT0 of REG_TDECTRL+2 */ |
3678 | val8 = rtw_read8(adapter: padapter, REG_TDECTRL+2); |
3679 | *val = (BIT(0) & val8) ? true : false; |
3680 | } |
3681 | break; |
3682 | |
3683 | case HW_VAR_FWLPS_RF_ON: |
3684 | { |
3685 | /* When we halt NIC, we should check if FW LPS is leave. */ |
3686 | u32 valRCR; |
3687 | |
3688 | if ( |
3689 | padapter->bSurpriseRemoved || |
3690 | (adapter_to_pwrctl(padapter)->rf_pwrstate == rf_off) |
3691 | ) { |
3692 | /* If it is in HW/SW Radio OFF or IPS state, we do not check Fw LPS Leave, */ |
3693 | /* because Fw is unload. */ |
3694 | *val = true; |
3695 | } else { |
3696 | valRCR = rtw_read32(adapter: padapter, REG_RCR); |
3697 | valRCR &= 0x00070000; |
3698 | if (valRCR) |
3699 | *val = false; |
3700 | else |
3701 | *val = true; |
3702 | } |
3703 | } |
3704 | break; |
3705 | |
3706 | case HW_VAR_EFUSE_USAGE: |
3707 | *val = pHalData->EfuseUsedPercentage; |
3708 | break; |
3709 | |
3710 | case HW_VAR_EFUSE_BYTES: |
3711 | *((u16 *)val) = pHalData->EfuseUsedBytes; |
3712 | break; |
3713 | |
3714 | case HW_VAR_EFUSE_BT_USAGE: |
3715 | #ifdef HAL_EFUSE_MEMORY |
3716 | *val = pHalData->EfuseHal.BTEfuseUsedPercentage; |
3717 | #endif |
3718 | break; |
3719 | |
3720 | case HW_VAR_EFUSE_BT_BYTES: |
3721 | #ifdef HAL_EFUSE_MEMORY |
3722 | *((u16 *)val) = pHalData->EfuseHal.BTEfuseUsedBytes; |
3723 | #else |
3724 | *((u16 *)val) = BTEfuseUsedBytes; |
3725 | #endif |
3726 | break; |
3727 | |
3728 | case HW_VAR_APFM_ON_MAC: |
3729 | *val = pHalData->bMacPwrCtrlOn; |
3730 | break; |
3731 | case HW_VAR_CHK_HI_QUEUE_EMPTY: |
3732 | val16 = rtw_read16(adapter: padapter, REG_TXPKT_EMPTY); |
3733 | *val = (val16 & BIT(10)) ? true:false; |
3734 | break; |
3735 | default: |
3736 | GetHwReg(padapter, variable, val); |
3737 | break; |
3738 | } |
3739 | } |
3740 | |
3741 | /* Description: |
3742 | * Change default setting of specified variable. |
3743 | */ |
3744 | u8 SetHalDefVar8723B(struct adapter *padapter, enum hal_def_variable variable, void *pval) |
3745 | { |
3746 | u8 bResult; |
3747 | |
3748 | bResult = _SUCCESS; |
3749 | |
3750 | switch (variable) { |
3751 | default: |
3752 | bResult = SetHalDefVar(adapter: padapter, variable, value: pval); |
3753 | break; |
3754 | } |
3755 | |
3756 | return bResult; |
3757 | } |
3758 | |
3759 | /* Description: |
3760 | * Query setting of specified variable. |
3761 | */ |
3762 | u8 GetHalDefVar8723B(struct adapter *padapter, enum hal_def_variable variable, void *pval) |
3763 | { |
3764 | u8 bResult; |
3765 | |
3766 | bResult = _SUCCESS; |
3767 | |
3768 | switch (variable) { |
3769 | case HAL_DEF_MAX_RECVBUF_SZ: |
3770 | *((u32 *)pval) = MAX_RECVBUF_SZ; |
3771 | break; |
3772 | |
3773 | case HAL_DEF_RX_PACKET_OFFSET: |
3774 | *((u32 *)pval) = RXDESC_SIZE + DRVINFO_SZ*8; |
3775 | break; |
3776 | |
3777 | case HW_VAR_MAX_RX_AMPDU_FACTOR: |
3778 | /* Stanley@BB.SD3 suggests 16K can get stable performance */ |
3779 | /* The experiment was done on SDIO interface */ |
3780 | /* coding by Lucas@20130730 */ |
3781 | *(u32 *)pval = IEEE80211_HT_MAX_AMPDU_16K; |
3782 | break; |
3783 | case HAL_DEF_TX_LDPC: |
3784 | case HAL_DEF_RX_LDPC: |
3785 | *((u8 *)pval) = false; |
3786 | break; |
3787 | case HAL_DEF_TX_STBC: |
3788 | *((u8 *)pval) = 0; |
3789 | break; |
3790 | case HAL_DEF_RX_STBC: |
3791 | *((u8 *)pval) = 1; |
3792 | break; |
3793 | case HAL_DEF_EXPLICIT_BEAMFORMER: |
3794 | case HAL_DEF_EXPLICIT_BEAMFORMEE: |
3795 | *((u8 *)pval) = false; |
3796 | break; |
3797 | |
3798 | case HW_DEF_RA_INFO_DUMP: |
3799 | { |
3800 | u8 mac_id = *(u8 *)pval; |
3801 | u32 cmd; |
3802 | |
3803 | cmd = 0x40000100 | mac_id; |
3804 | rtw_write32(adapter: padapter, REG_HMEBOX_DBG_2_8723B, val: cmd); |
3805 | msleep(msecs: 10); |
3806 | rtw_read32(adapter: padapter, addr: 0x2F0); // info 1 |
3807 | |
3808 | cmd = 0x40000400 | mac_id; |
3809 | rtw_write32(adapter: padapter, REG_HMEBOX_DBG_2_8723B, val: cmd); |
3810 | msleep(msecs: 10); |
3811 | rtw_read32(adapter: padapter, addr: 0x2F0); // info 1 |
3812 | rtw_read32(adapter: padapter, addr: 0x2F4); // info 2 |
3813 | rtw_read32(adapter: padapter, addr: 0x2F8); // rate mask 1 |
3814 | rtw_read32(adapter: padapter, addr: 0x2FC); // rate mask 2 |
3815 | } |
3816 | break; |
3817 | |
3818 | case HAL_DEF_TX_PAGE_BOUNDARY: |
3819 | if (!padapter->registrypriv.wifi_spec) { |
3820 | *(u8 *)pval = TX_PAGE_BOUNDARY_8723B; |
3821 | } else { |
3822 | *(u8 *)pval = WMM_NORMAL_TX_PAGE_BOUNDARY_8723B; |
3823 | } |
3824 | break; |
3825 | |
3826 | case HAL_DEF_MACID_SLEEP: |
3827 | *(u8 *)pval = true; /* support macid sleep */ |
3828 | break; |
3829 | |
3830 | default: |
3831 | bResult = GetHalDefVar(adapter: padapter, variable, value: pval); |
3832 | break; |
3833 | } |
3834 | |
3835 | return bResult; |
3836 | } |
3837 | |
3838 | void rtl8723b_start_thread(struct adapter *padapter) |
3839 | { |
3840 | struct xmit_priv *xmitpriv = &padapter->xmitpriv; |
3841 | |
3842 | xmitpriv->SdioXmitThread = kthread_run(rtl8723bs_xmit_thread, padapter, "RTWHALXT" ); |
3843 | } |
3844 | |
3845 | void rtl8723b_stop_thread(struct adapter *padapter) |
3846 | { |
3847 | struct xmit_priv *xmitpriv = &padapter->xmitpriv; |
3848 | |
3849 | /* stop xmit_buf_thread */ |
3850 | if (xmitpriv->SdioXmitThread) { |
3851 | complete(&xmitpriv->SdioXmitStart); |
3852 | wait_for_completion(&xmitpriv->SdioXmitTerminate); |
3853 | xmitpriv->SdioXmitThread = NULL; |
3854 | } |
3855 | } |
3856 | |