]>
Commit | Line | Data |
---|---|---|
06a05884 LF |
1 | /****************************************************************************** |
2 | * | |
3 | * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify it | |
6 | * under the terms of version 2 of the GNU General Public License as | |
7 | * published by the Free Software Foundation. | |
8 | * | |
9 | * This program is distributed in the hope that it will be useful, but WITHOUT | |
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
12 | * more details. | |
13 | * | |
14 | * You should have received a copy of the GNU General Public License along with | |
15 | * this program; if not, write to the Free Software Foundation, Inc., | |
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA | |
17 | * | |
18 | * | |
19 | ******************************************************************************/ | |
20 | #define _RTW_EFUSE_C_ | |
21 | ||
22 | #include <osdep_service.h> | |
23 | #include <drv_types.h> | |
24 | #include <rtw_efuse.h> | |
e73fd15e | 25 | #include <usb_ops_linux.h> |
ee5f8a43 | 26 | #include <rtl8188e_hal.h> |
27 | #include <rtw_iol.h> | |
06a05884 | 28 | |
06a05884 LF |
29 | #define REG_EFUSE_CTRL 0x0030 |
30 | #define EFUSE_CTRL REG_EFUSE_CTRL /* E-Fuse Control. */ | |
06a05884 | 31 | |
ee5f8a43 | 32 | enum{ |
33 | VOLTAGE_V25 = 0x03, | |
34 | LDOE25_SHIFT = 28 , | |
35 | }; | |
36 | ||
37 | /* | |
38 | * Function: Efuse_PowerSwitch | |
39 | * | |
40 | * Overview: When we want to enable write operation, we should change to | |
41 | * pwr on state. When we stop write, we should switch to 500k mode | |
42 | * and disable LDO 2.5V. | |
43 | */ | |
44 | ||
45 | void Efuse_PowerSwitch( | |
46 | struct adapter *pAdapter, | |
47 | u8 bWrite, | |
48 | u8 PwrState) | |
49 | { | |
50 | u8 tempval; | |
51 | u16 tmpV16; | |
52 | ||
53 | if (PwrState) { | |
54 | usb_write8(pAdapter, REG_EFUSE_ACCESS, EFUSE_ACCESS_ON); | |
55 | ||
56 | /* 1.2V Power: From VDDON with Power Cut(0x0000h[15]), defualt valid */ | |
57 | tmpV16 = usb_read16(pAdapter, REG_SYS_ISO_CTRL); | |
58 | if (!(tmpV16 & PWC_EV12V)) { | |
59 | tmpV16 |= PWC_EV12V; | |
60 | usb_write16(pAdapter, REG_SYS_ISO_CTRL, tmpV16); | |
61 | } | |
62 | /* Reset: 0x0000h[28], default valid */ | |
63 | tmpV16 = usb_read16(pAdapter, REG_SYS_FUNC_EN); | |
64 | if (!(tmpV16 & FEN_ELDR)) { | |
65 | tmpV16 |= FEN_ELDR; | |
66 | usb_write16(pAdapter, REG_SYS_FUNC_EN, tmpV16); | |
67 | } | |
68 | ||
69 | /* Clock: Gated(0x0008h[5]) 8M(0x0008h[1]) clock from ANA, default valid */ | |
70 | tmpV16 = usb_read16(pAdapter, REG_SYS_CLKR); | |
71 | if ((!(tmpV16 & LOADER_CLK_EN)) || (!(tmpV16 & ANA8M))) { | |
72 | tmpV16 |= (LOADER_CLK_EN | ANA8M); | |
73 | usb_write16(pAdapter, REG_SYS_CLKR, tmpV16); | |
74 | } | |
75 | ||
76 | if (bWrite) { | |
77 | /* Enable LDO 2.5V before read/write action */ | |
78 | tempval = usb_read8(pAdapter, EFUSE_TEST+3); | |
79 | tempval &= 0x0F; | |
80 | tempval |= (VOLTAGE_V25 << 4); | |
81 | usb_write8(pAdapter, EFUSE_TEST+3, (tempval | 0x80)); | |
82 | } | |
83 | } else { | |
84 | usb_write8(pAdapter, REG_EFUSE_ACCESS, EFUSE_ACCESS_OFF); | |
85 | ||
86 | if (bWrite) { | |
87 | /* Disable LDO 2.5V after read/write action */ | |
88 | tempval = usb_read8(pAdapter, EFUSE_TEST+3); | |
89 | usb_write8(pAdapter, EFUSE_TEST+3, (tempval & 0x7F)); | |
90 | } | |
91 | } | |
92 | } | |
93 | ||
94 | static void | |
95 | efuse_phymap_to_logical(u8 *phymap, u16 _offset, u16 _size_byte, u8 *pbuf) | |
96 | { | |
97 | u8 *efuseTbl = NULL; | |
98 | u8 rtemp8; | |
99 | u16 eFuse_Addr = 0; | |
100 | u8 offset, wren; | |
101 | u16 i, j; | |
102 | u16 **eFuseWord = NULL; | |
103 | u16 efuse_utilized = 0; | |
104 | u8 u1temp = 0; | |
105 | ||
fadbe0cd | 106 | efuseTbl = kzalloc(EFUSE_MAP_LEN_88E, GFP_KERNEL); |
ee5f8a43 | 107 | if (efuseTbl == NULL) { |
108 | DBG_88E("%s: alloc efuseTbl fail!\n", __func__); | |
3cfab18c | 109 | return; |
ee5f8a43 | 110 | } |
111 | ||
112 | eFuseWord = (u16 **)rtw_malloc2d(EFUSE_MAX_SECTION_88E, EFUSE_MAX_WORD_UNIT, sizeof(u16)); | |
113 | if (eFuseWord == NULL) { | |
114 | DBG_88E("%s: alloc eFuseWord fail!\n", __func__); | |
3cfab18c | 115 | goto eFuseWord_failed; |
ee5f8a43 | 116 | } |
117 | ||
118 | /* 0. Refresh efuse init map as all oxFF. */ | |
119 | for (i = 0; i < EFUSE_MAX_SECTION_88E; i++) | |
120 | for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) | |
121 | eFuseWord[i][j] = 0xFFFF; | |
122 | ||
123 | /* */ | |
124 | /* 1. Read the first byte to check if efuse is empty!!! */ | |
125 | /* */ | |
126 | /* */ | |
127 | rtemp8 = *(phymap+eFuse_Addr); | |
128 | if (rtemp8 != 0xFF) { | |
129 | efuse_utilized++; | |
130 | eFuse_Addr++; | |
131 | } else { | |
132 | DBG_88E("EFUSE is empty efuse_Addr-%d efuse_data =%x\n", eFuse_Addr, rtemp8); | |
133 | goto exit; | |
134 | } | |
135 | ||
136 | /* */ | |
137 | /* 2. Read real efuse content. Filter PG header and every section data. */ | |
138 | /* */ | |
139 | while ((rtemp8 != 0xFF) && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E)) { | |
140 | /* Check PG header for section num. */ | |
141 | if ((rtemp8 & 0x1F) == 0x0F) { /* extended header */ | |
07add2d3 | 142 | u1temp = (rtemp8 & 0xE0) >> 5; |
ee5f8a43 | 143 | rtemp8 = *(phymap+eFuse_Addr); |
144 | if ((rtemp8 & 0x0F) == 0x0F) { | |
145 | eFuse_Addr++; | |
146 | rtemp8 = *(phymap+eFuse_Addr); | |
147 | ||
148 | if (rtemp8 != 0xFF && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E)) | |
149 | eFuse_Addr++; | |
150 | continue; | |
151 | } else { | |
152 | offset = ((rtemp8 & 0xF0) >> 1) | u1temp; | |
adb3d770 | 153 | wren = rtemp8 & 0x0F; |
ee5f8a43 | 154 | eFuse_Addr++; |
155 | } | |
156 | } else { | |
adb3d770 HM |
157 | offset = (rtemp8 >> 4) & 0x0f; |
158 | wren = rtemp8 & 0x0f; | |
ee5f8a43 | 159 | } |
160 | ||
161 | if (offset < EFUSE_MAX_SECTION_88E) { | |
162 | /* Get word enable value from PG header */ | |
163 | for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) { | |
164 | /* Check word enable condition in the section */ | |
165 | if (!(wren & 0x01)) { | |
166 | rtemp8 = *(phymap+eFuse_Addr); | |
167 | eFuse_Addr++; | |
168 | efuse_utilized++; | |
169 | eFuseWord[offset][i] = (rtemp8 & 0xff); | |
170 | if (eFuse_Addr >= EFUSE_REAL_CONTENT_LEN_88E) | |
171 | break; | |
172 | rtemp8 = *(phymap+eFuse_Addr); | |
173 | eFuse_Addr++; | |
174 | efuse_utilized++; | |
175 | eFuseWord[offset][i] |= (((u16)rtemp8 << 8) & 0xff00); | |
176 | ||
177 | if (eFuse_Addr >= EFUSE_REAL_CONTENT_LEN_88E) | |
178 | break; | |
179 | } | |
180 | wren >>= 1; | |
181 | } | |
182 | } | |
183 | /* Read next PG header */ | |
184 | rtemp8 = *(phymap+eFuse_Addr); | |
185 | ||
186 | if (rtemp8 != 0xFF && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E)) { | |
187 | efuse_utilized++; | |
188 | eFuse_Addr++; | |
189 | } | |
190 | } | |
191 | ||
192 | /* */ | |
193 | /* 3. Collect 16 sections and 4 word unit into Efuse map. */ | |
194 | /* */ | |
195 | for (i = 0; i < EFUSE_MAX_SECTION_88E; i++) { | |
196 | for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) { | |
197 | efuseTbl[(i*8)+(j*2)] = (eFuseWord[i][j] & 0xff); | |
198 | efuseTbl[(i*8)+((j*2)+1)] = ((eFuseWord[i][j] >> 8) & 0xff); | |
199 | } | |
200 | } | |
201 | ||
202 | /* */ | |
203 | /* 4. Copy from Efuse map to output pointer memory!!! */ | |
204 | /* */ | |
205 | for (i = 0; i < _size_byte; i++) | |
206 | pbuf[i] = efuseTbl[_offset+i]; | |
207 | ||
208 | /* */ | |
209 | /* 5. Calculate Efuse utilization. */ | |
210 | /* */ | |
211 | ||
212 | exit: | |
3cfab18c | 213 | kfree(eFuseWord); |
ee5f8a43 | 214 | |
3cfab18c TP |
215 | eFuseWord_failed: |
216 | kfree(efuseTbl); | |
ee5f8a43 | 217 | } |
218 | ||
219 | static void efuse_read_phymap_from_txpktbuf( | |
220 | struct adapter *adapter, | |
221 | int bcnhead, /* beacon head, where FW store len(2-byte) and efuse physical map. */ | |
222 | u8 *content, /* buffer to store efuse physical map */ | |
223 | u16 *size /* for efuse content: the max byte to read. will update to byte read */ | |
224 | ) | |
225 | { | |
226 | u16 dbg_addr = 0; | |
227 | u32 start = 0, passing_time = 0; | |
228 | u8 reg_0x143 = 0; | |
229 | u32 lo32 = 0, hi32 = 0; | |
230 | u16 len = 0, count = 0; | |
231 | int i = 0; | |
232 | u16 limit = *size; | |
233 | ||
234 | u8 *pos = content; | |
235 | ||
236 | if (bcnhead < 0) /* if not valid */ | |
237 | bcnhead = usb_read8(adapter, REG_TDECTRL+1); | |
238 | ||
239 | DBG_88E("%s bcnhead:%d\n", __func__, bcnhead); | |
240 | ||
241 | usb_write8(adapter, REG_PKT_BUFF_ACCESS_CTRL, TXPKT_BUF_SELECT); | |
242 | ||
243 | dbg_addr = bcnhead*128/8; /* 8-bytes addressing */ | |
244 | ||
245 | while (1) { | |
246 | usb_write16(adapter, REG_PKTBUF_DBG_ADDR, dbg_addr+i); | |
247 | ||
248 | usb_write8(adapter, REG_TXPKTBUF_DBG, 0); | |
249 | start = jiffies; | |
250 | while (!(reg_0x143 = usb_read8(adapter, REG_TXPKTBUF_DBG)) && | |
251 | (passing_time = rtw_get_passing_time_ms(start)) < 1000) { | |
252 | DBG_88E("%s polling reg_0x143:0x%02x, reg_0x106:0x%02x\n", __func__, reg_0x143, usb_read8(adapter, 0x106)); | |
c8cb5f2c | 253 | usleep_range(1000, 2000); |
ee5f8a43 | 254 | } |
255 | ||
256 | lo32 = usb_read32(adapter, REG_PKTBUF_DBG_DATA_L); | |
257 | hi32 = usb_read32(adapter, REG_PKTBUF_DBG_DATA_H); | |
258 | ||
259 | if (i == 0) { | |
260 | u8 lenc[2]; | |
261 | u16 lenbak, aaabak; | |
262 | u16 aaa; | |
263 | lenc[0] = usb_read8(adapter, REG_PKTBUF_DBG_DATA_L); | |
264 | lenc[1] = usb_read8(adapter, REG_PKTBUF_DBG_DATA_L+1); | |
265 | ||
266 | aaabak = le16_to_cpup((__le16 *)lenc); | |
267 | lenbak = le16_to_cpu(*((__le16 *)lenc)); | |
268 | aaa = le16_to_cpup((__le16 *)&lo32); | |
269 | len = le16_to_cpu(*((__le16 *)&lo32)); | |
270 | ||
271 | limit = (len-2 < limit) ? len-2 : limit; | |
272 | ||
273 | DBG_88E("%s len:%u, lenbak:%u, aaa:%u, aaabak:%u\n", __func__, len, lenbak, aaa, aaabak); | |
274 | ||
275 | memcpy(pos, ((u8 *)&lo32)+2, (limit >= count+2) ? 2 : limit-count); | |
276 | count += (limit >= count+2) ? 2 : limit-count; | |
277 | pos = content+count; | |
278 | ||
279 | } else { | |
280 | memcpy(pos, ((u8 *)&lo32), (limit >= count+4) ? 4 : limit-count); | |
281 | count += (limit >= count+4) ? 4 : limit-count; | |
282 | pos = content+count; | |
283 | } | |
284 | ||
285 | if (limit > count && len-2 > count) { | |
286 | memcpy(pos, (u8 *)&hi32, (limit >= count+4) ? 4 : limit-count); | |
287 | count += (limit >= count+4) ? 4 : limit-count; | |
288 | pos = content+count; | |
289 | } | |
290 | ||
291 | if (limit <= count || len-2 <= count) | |
292 | break; | |
293 | i++; | |
294 | } | |
295 | usb_write8(adapter, REG_PKT_BUFF_ACCESS_CTRL, DISABLE_TRXPKT_BUF_ACCESS); | |
296 | DBG_88E("%s read count:%u\n", __func__, count); | |
297 | *size = count; | |
298 | } | |
299 | ||
300 | static s32 iol_read_efuse(struct adapter *padapter, u8 txpktbuf_bndy, u16 offset, u16 size_byte, u8 *logical_map) | |
301 | { | |
302 | s32 status = _FAIL; | |
303 | u8 physical_map[512]; | |
304 | u16 size = 512; | |
305 | ||
306 | usb_write8(padapter, REG_TDECTRL+1, txpktbuf_bndy); | |
1ce39848 | 307 | memset(physical_map, 0xFF, 512); |
ee5f8a43 | 308 | usb_write8(padapter, REG_PKT_BUFF_ACCESS_CTRL, TXPKT_BUF_SELECT); |
309 | status = iol_execute(padapter, CMD_READ_EFUSE_MAP); | |
310 | if (status == _SUCCESS) | |
311 | efuse_read_phymap_from_txpktbuf(padapter, txpktbuf_bndy, physical_map, &size); | |
312 | efuse_phymap_to_logical(physical_map, offset, size_byte, logical_map); | |
313 | return status; | |
314 | } | |
315 | ||
316 | void efuse_ReadEFuse(struct adapter *Adapter, u8 efuseType, u16 _offset, u16 _size_byte, u8 *pbuf) | |
317 | { | |
318 | ||
319 | if (rtw_IOL_applied(Adapter)) { | |
320 | rtw_hal_power_on(Adapter); | |
321 | iol_mode_enable(Adapter, 1); | |
322 | iol_read_efuse(Adapter, 0, _offset, _size_byte, pbuf); | |
323 | iol_mode_enable(Adapter, 0); | |
324 | } | |
ee5f8a43 | 325 | } |
326 | ||
327 | /* Do not support BT */ | |
328 | void EFUSE_GetEfuseDefinition(struct adapter *pAdapter, u8 efuseType, u8 type, void *pOut) | |
329 | { | |
330 | switch (type) { | |
331 | case TYPE_EFUSE_MAX_SECTION: | |
332 | { | |
333 | u8 *pMax_section; | |
60c89911 | 334 | pMax_section = pOut; |
ee5f8a43 | 335 | *pMax_section = EFUSE_MAX_SECTION_88E; |
336 | } | |
337 | break; | |
338 | case TYPE_EFUSE_REAL_CONTENT_LEN: | |
339 | { | |
340 | u16 *pu2Tmp; | |
60c89911 | 341 | pu2Tmp = pOut; |
ee5f8a43 | 342 | *pu2Tmp = EFUSE_REAL_CONTENT_LEN_88E; |
343 | } | |
344 | break; | |
345 | case TYPE_EFUSE_CONTENT_LEN_BANK: | |
346 | { | |
347 | u16 *pu2Tmp; | |
60c89911 | 348 | pu2Tmp = pOut; |
ee5f8a43 | 349 | *pu2Tmp = EFUSE_REAL_CONTENT_LEN_88E; |
350 | } | |
351 | break; | |
352 | case TYPE_AVAILABLE_EFUSE_BYTES_BANK: | |
353 | { | |
354 | u16 *pu2Tmp; | |
60c89911 | 355 | pu2Tmp = pOut; |
ee5f8a43 | 356 | *pu2Tmp = (u16)(EFUSE_REAL_CONTENT_LEN_88E-EFUSE_OOB_PROTECT_BYTES_88E); |
357 | } | |
358 | break; | |
359 | case TYPE_AVAILABLE_EFUSE_BYTES_TOTAL: | |
360 | { | |
361 | u16 *pu2Tmp; | |
60c89911 | 362 | pu2Tmp = pOut; |
ee5f8a43 | 363 | *pu2Tmp = (u16)(EFUSE_REAL_CONTENT_LEN_88E-EFUSE_OOB_PROTECT_BYTES_88E); |
364 | } | |
365 | break; | |
366 | case TYPE_EFUSE_MAP_LEN: | |
367 | { | |
368 | u16 *pu2Tmp; | |
60c89911 | 369 | pu2Tmp = pOut; |
ee5f8a43 | 370 | *pu2Tmp = (u16)EFUSE_MAP_LEN_88E; |
371 | } | |
372 | break; | |
373 | case TYPE_EFUSE_PROTECT_BYTES_BANK: | |
374 | { | |
375 | u8 *pu1Tmp; | |
60c89911 | 376 | pu1Tmp = pOut; |
ee5f8a43 | 377 | *pu1Tmp = (u8)(EFUSE_OOB_PROTECT_BYTES_88E); |
378 | } | |
379 | break; | |
380 | default: | |
381 | { | |
382 | u8 *pu1Tmp; | |
60c89911 | 383 | pu1Tmp = pOut; |
ee5f8a43 | 384 | *pu1Tmp = 0; |
385 | } | |
386 | break; | |
387 | } | |
388 | } | |
389 | ||
390 | u8 Efuse_WordEnableDataWrite(struct adapter *pAdapter, u16 efuse_addr, u8 word_en, u8 *data) | |
391 | { | |
392 | u16 tmpaddr = 0; | |
393 | u16 start_addr = efuse_addr; | |
394 | u8 badworden = 0x0F; | |
395 | u8 tmpdata[8]; | |
396 | ||
1ce39848 | 397 | memset((void *)tmpdata, 0xff, PGPKT_DATA_SIZE); |
ee5f8a43 | 398 | |
399 | if (!(word_en&BIT0)) { | |
400 | tmpaddr = start_addr; | |
401 | efuse_OneByteWrite(pAdapter, start_addr++, data[0]); | |
402 | efuse_OneByteWrite(pAdapter, start_addr++, data[1]); | |
403 | ||
404 | efuse_OneByteRead(pAdapter, tmpaddr, &tmpdata[0]); | |
405 | efuse_OneByteRead(pAdapter, tmpaddr+1, &tmpdata[1]); | |
406 | if ((data[0] != tmpdata[0]) || (data[1] != tmpdata[1])) | |
407 | badworden &= (~BIT0); | |
408 | } | |
409 | if (!(word_en&BIT1)) { | |
410 | tmpaddr = start_addr; | |
411 | efuse_OneByteWrite(pAdapter, start_addr++, data[2]); | |
412 | efuse_OneByteWrite(pAdapter, start_addr++, data[3]); | |
413 | ||
414 | efuse_OneByteRead(pAdapter, tmpaddr, &tmpdata[2]); | |
415 | efuse_OneByteRead(pAdapter, tmpaddr+1, &tmpdata[3]); | |
416 | if ((data[2] != tmpdata[2]) || (data[3] != tmpdata[3])) | |
417 | badworden &= (~BIT1); | |
418 | } | |
419 | if (!(word_en&BIT2)) { | |
420 | tmpaddr = start_addr; | |
421 | efuse_OneByteWrite(pAdapter, start_addr++, data[4]); | |
422 | efuse_OneByteWrite(pAdapter, start_addr++, data[5]); | |
423 | ||
424 | efuse_OneByteRead(pAdapter, tmpaddr, &tmpdata[4]); | |
425 | efuse_OneByteRead(pAdapter, tmpaddr+1, &tmpdata[5]); | |
426 | if ((data[4] != tmpdata[4]) || (data[5] != tmpdata[5])) | |
427 | badworden &= (~BIT2); | |
428 | } | |
429 | if (!(word_en&BIT3)) { | |
430 | tmpaddr = start_addr; | |
431 | efuse_OneByteWrite(pAdapter, start_addr++, data[6]); | |
432 | efuse_OneByteWrite(pAdapter, start_addr++, data[7]); | |
433 | ||
434 | efuse_OneByteRead(pAdapter, tmpaddr, &tmpdata[6]); | |
435 | efuse_OneByteRead(pAdapter, tmpaddr+1, &tmpdata[7]); | |
436 | if ((data[6] != tmpdata[6]) || (data[7] != tmpdata[7])) | |
437 | badworden &= (~BIT3); | |
438 | } | |
439 | return badworden; | |
440 | } | |
441 | ||
e7e7068f | 442 | static u16 Efuse_GetCurrentSize(struct adapter *pAdapter) |
ee5f8a43 | 443 | { |
444 | int bContinual = true; | |
445 | u16 efuse_addr = 0; | |
446 | u8 hoffset = 0, hworden = 0; | |
447 | u8 efuse_data, word_cnts = 0; | |
448 | ||
449 | rtw_hal_get_hwreg(pAdapter, HW_VAR_EFUSE_BYTES, (u8 *)&efuse_addr); | |
450 | ||
451 | while (bContinual && | |
452 | efuse_OneByteRead(pAdapter, efuse_addr, &efuse_data) && | |
453 | AVAILABLE_EFUSE_ADDR(efuse_addr)) { | |
454 | if (efuse_data != 0xFF) { | |
455 | if ((efuse_data&0x1F) == 0x0F) { /* extended header */ | |
456 | hoffset = efuse_data; | |
457 | efuse_addr++; | |
458 | efuse_OneByteRead(pAdapter, efuse_addr, &efuse_data); | |
459 | if ((efuse_data & 0x0F) == 0x0F) { | |
460 | efuse_addr++; | |
461 | continue; | |
462 | } else { | |
463 | hoffset = ((hoffset & 0xE0) >> 5) | ((efuse_data & 0xF0) >> 1); | |
464 | hworden = efuse_data & 0x0F; | |
465 | } | |
466 | } else { | |
467 | hoffset = (efuse_data>>4) & 0x0F; | |
468 | hworden = efuse_data & 0x0F; | |
469 | } | |
470 | word_cnts = Efuse_CalculateWordCnts(hworden); | |
471 | /* read next header */ | |
472 | efuse_addr = efuse_addr + (word_cnts*2)+1; | |
473 | } else { | |
474 | bContinual = false; | |
475 | } | |
476 | } | |
477 | ||
478 | rtw_hal_set_hwreg(pAdapter, HW_VAR_EFUSE_BYTES, (u8 *)&efuse_addr); | |
479 | ||
480 | return efuse_addr; | |
481 | } | |
482 | ||
483 | int Efuse_PgPacketRead(struct adapter *pAdapter, u8 offset, u8 *data) | |
484 | { | |
485 | u8 ReadState = PG_STATE_HEADER; | |
486 | int bContinual = true; | |
487 | int bDataEmpty = true; | |
488 | u8 efuse_data, word_cnts = 0; | |
489 | u16 efuse_addr = 0; | |
490 | u8 hoffset = 0, hworden = 0; | |
491 | u8 tmpidx = 0; | |
492 | u8 tmpdata[8]; | |
493 | u8 max_section = 0; | |
494 | u8 tmp_header = 0; | |
495 | ||
496 | EFUSE_GetEfuseDefinition(pAdapter, EFUSE_WIFI, TYPE_EFUSE_MAX_SECTION, (void *)&max_section); | |
497 | ||
498 | if (data == NULL) | |
499 | return false; | |
500 | if (offset > max_section) | |
501 | return false; | |
502 | ||
1ce39848 | 503 | memset((void *)data, 0xff, sizeof(u8)*PGPKT_DATA_SIZE); |
504 | memset((void *)tmpdata, 0xff, sizeof(u8)*PGPKT_DATA_SIZE); | |
ee5f8a43 | 505 | |
506 | /* <Roger_TODO> Efuse has been pre-programmed dummy 5Bytes at the end of Efuse by CP. */ | |
507 | /* Skip dummy parts to prevent unexpected data read from Efuse. */ | |
508 | /* By pass right now. 2009.02.19. */ | |
509 | while (bContinual && AVAILABLE_EFUSE_ADDR(efuse_addr)) { | |
510 | /* Header Read ------------- */ | |
511 | if (ReadState & PG_STATE_HEADER) { | |
512 | if (efuse_OneByteRead(pAdapter, efuse_addr, &efuse_data) && (efuse_data != 0xFF)) { | |
513 | if (EXT_HEADER(efuse_data)) { | |
514 | tmp_header = efuse_data; | |
515 | efuse_addr++; | |
516 | efuse_OneByteRead(pAdapter, efuse_addr, &efuse_data); | |
517 | if (!ALL_WORDS_DISABLED(efuse_data)) { | |
518 | hoffset = ((tmp_header & 0xE0) >> 5) | ((efuse_data & 0xF0) >> 1); | |
519 | hworden = efuse_data & 0x0F; | |
520 | } else { | |
521 | DBG_88E("Error, All words disabled\n"); | |
522 | efuse_addr++; | |
523 | continue; | |
524 | } | |
525 | } else { | |
526 | hoffset = (efuse_data>>4) & 0x0F; | |
527 | hworden = efuse_data & 0x0F; | |
528 | } | |
529 | word_cnts = Efuse_CalculateWordCnts(hworden); | |
530 | bDataEmpty = true; | |
531 | ||
532 | if (hoffset == offset) { | |
533 | for (tmpidx = 0; tmpidx < word_cnts*2; tmpidx++) { | |
534 | if (efuse_OneByteRead(pAdapter, efuse_addr+1+tmpidx, &efuse_data)) { | |
535 | tmpdata[tmpidx] = efuse_data; | |
536 | if (efuse_data != 0xff) | |
537 | bDataEmpty = false; | |
538 | } | |
539 | } | |
540 | if (bDataEmpty == false) { | |
541 | ReadState = PG_STATE_DATA; | |
542 | } else {/* read next header */ | |
543 | efuse_addr = efuse_addr + (word_cnts*2)+1; | |
544 | ReadState = PG_STATE_HEADER; | |
545 | } | |
546 | } else {/* read next header */ | |
547 | efuse_addr = efuse_addr + (word_cnts*2)+1; | |
548 | ReadState = PG_STATE_HEADER; | |
549 | } | |
550 | } else { | |
551 | bContinual = false; | |
552 | } | |
553 | } else if (ReadState & PG_STATE_DATA) { | |
554 | /* Data section Read ------------- */ | |
555 | efuse_WordEnableDataRead(hworden, tmpdata, data); | |
556 | efuse_addr = efuse_addr + (word_cnts*2)+1; | |
557 | ReadState = PG_STATE_HEADER; | |
558 | } | |
559 | ||
560 | } | |
561 | ||
562 | if ((data[0] == 0xff) && (data[1] == 0xff) && (data[2] == 0xff) && (data[3] == 0xff) && | |
563 | (data[4] == 0xff) && (data[5] == 0xff) && (data[6] == 0xff) && (data[7] == 0xff)) | |
564 | return false; | |
565 | else | |
566 | return true; | |
567 | } | |
568 | ||
569 | static bool hal_EfuseFixHeaderProcess(struct adapter *pAdapter, u8 efuseType, struct pgpkt *pFixPkt, u16 *pAddr) | |
570 | { | |
571 | u8 originaldata[8], badworden = 0; | |
572 | u16 efuse_addr = *pAddr; | |
573 | u32 PgWriteSuccess = 0; | |
574 | ||
1ce39848 | 575 | memset((void *)originaldata, 0xff, 8); |
ee5f8a43 | 576 | |
577 | if (Efuse_PgPacketRead(pAdapter, pFixPkt->offset, originaldata)) { | |
578 | /* check if data exist */ | |
579 | badworden = Efuse_WordEnableDataWrite(pAdapter, efuse_addr+1, pFixPkt->word_en, originaldata); | |
580 | ||
581 | if (badworden != 0xf) { /* write fail */ | |
582 | PgWriteSuccess = Efuse_PgPacketWrite(pAdapter, pFixPkt->offset, badworden, originaldata); | |
583 | ||
584 | if (!PgWriteSuccess) | |
585 | return false; | |
586 | else | |
587 | efuse_addr = Efuse_GetCurrentSize(pAdapter); | |
588 | } else { | |
589 | efuse_addr = efuse_addr + (pFixPkt->word_cnts*2) + 1; | |
590 | } | |
591 | } else { | |
592 | efuse_addr = efuse_addr + (pFixPkt->word_cnts*2) + 1; | |
593 | } | |
594 | *pAddr = efuse_addr; | |
595 | return true; | |
596 | } | |
597 | ||
598 | static bool hal_EfusePgPacketWrite2ByteHeader(struct adapter *pAdapter, u8 efuseType, u16 *pAddr, struct pgpkt *pTargetPkt) | |
599 | { | |
600 | bool bRet = false; | |
601 | u16 efuse_addr = *pAddr, efuse_max_available_len = 0; | |
602 | u8 pg_header = 0, tmp_header = 0, pg_header_temp = 0; | |
603 | u8 repeatcnt = 0; | |
604 | ||
605 | EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_AVAILABLE_EFUSE_BYTES_BANK, (void *)&efuse_max_available_len); | |
606 | ||
607 | while (efuse_addr < efuse_max_available_len) { | |
608 | pg_header = ((pTargetPkt->offset & 0x07) << 5) | 0x0F; | |
609 | efuse_OneByteWrite(pAdapter, efuse_addr, pg_header); | |
610 | efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header); | |
611 | ||
612 | while (tmp_header == 0xFF) { | |
613 | if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) | |
614 | return false; | |
615 | ||
616 | efuse_OneByteWrite(pAdapter, efuse_addr, pg_header); | |
617 | efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header); | |
618 | } | |
619 | ||
620 | /* to write ext_header */ | |
621 | if (tmp_header == pg_header) { | |
622 | efuse_addr++; | |
623 | pg_header_temp = pg_header; | |
624 | pg_header = ((pTargetPkt->offset & 0x78) << 1) | pTargetPkt->word_en; | |
625 | ||
626 | efuse_OneByteWrite(pAdapter, efuse_addr, pg_header); | |
627 | efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header); | |
628 | ||
629 | while (tmp_header == 0xFF) { | |
630 | if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) | |
631 | return false; | |
632 | ||
633 | efuse_OneByteWrite(pAdapter, efuse_addr, pg_header); | |
634 | efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header); | |
635 | } | |
636 | ||
637 | if ((tmp_header & 0x0F) == 0x0F) { /* word_en PG fail */ | |
638 | if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) { | |
639 | return false; | |
ee5f8a43 | 640 | } |
b7c12ca4 DU |
641 | efuse_addr++; |
642 | continue; | |
ee5f8a43 | 643 | } else if (pg_header != tmp_header) { /* offset PG fail */ |
644 | struct pgpkt fixPkt; | |
645 | fixPkt.offset = ((pg_header_temp & 0xE0) >> 5) | ((tmp_header & 0xF0) >> 1); | |
646 | fixPkt.word_en = tmp_header & 0x0F; | |
647 | fixPkt.word_cnts = Efuse_CalculateWordCnts(fixPkt.word_en); | |
648 | if (!hal_EfuseFixHeaderProcess(pAdapter, efuseType, &fixPkt, &efuse_addr)) | |
649 | return false; | |
650 | } else { | |
651 | bRet = true; | |
652 | break; | |
653 | } | |
654 | } else if ((tmp_header & 0x1F) == 0x0F) { /* wrong extended header */ | |
655 | efuse_addr += 2; | |
656 | continue; | |
657 | } | |
658 | } | |
659 | ||
660 | *pAddr = efuse_addr; | |
661 | return bRet; | |
662 | } | |
663 | ||
664 | static bool hal_EfusePgPacketWrite1ByteHeader(struct adapter *pAdapter, u8 efuseType, u16 *pAddr, struct pgpkt *pTargetPkt) | |
665 | { | |
666 | bool bRet = false; | |
667 | u8 pg_header = 0, tmp_header = 0; | |
668 | u16 efuse_addr = *pAddr; | |
669 | u8 repeatcnt = 0; | |
670 | ||
671 | pg_header = ((pTargetPkt->offset << 4) & 0xf0) | pTargetPkt->word_en; | |
672 | ||
673 | efuse_OneByteWrite(pAdapter, efuse_addr, pg_header); | |
674 | efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header); | |
675 | ||
676 | while (tmp_header == 0xFF) { | |
677 | if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) | |
678 | return false; | |
679 | efuse_OneByteWrite(pAdapter, efuse_addr, pg_header); | |
680 | efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header); | |
681 | } | |
682 | ||
683 | if (pg_header == tmp_header) { | |
684 | bRet = true; | |
685 | } else { | |
686 | struct pgpkt fixPkt; | |
687 | fixPkt.offset = (tmp_header>>4) & 0x0F; | |
688 | fixPkt.word_en = tmp_header & 0x0F; | |
689 | fixPkt.word_cnts = Efuse_CalculateWordCnts(fixPkt.word_en); | |
690 | if (!hal_EfuseFixHeaderProcess(pAdapter, efuseType, &fixPkt, &efuse_addr)) | |
691 | return false; | |
692 | } | |
693 | ||
694 | *pAddr = efuse_addr; | |
695 | return bRet; | |
696 | } | |
697 | ||
698 | static bool hal_EfusePgPacketWriteData(struct adapter *pAdapter, u8 efuseType, u16 *pAddr, struct pgpkt *pTargetPkt) | |
699 | { | |
700 | u16 efuse_addr = *pAddr; | |
701 | u8 badworden = 0; | |
702 | u32 PgWriteSuccess = 0; | |
703 | ||
704 | badworden = 0x0f; | |
705 | badworden = Efuse_WordEnableDataWrite(pAdapter, efuse_addr+1, pTargetPkt->word_en, pTargetPkt->data); | |
706 | if (badworden == 0x0F) { | |
707 | /* write ok */ | |
708 | return true; | |
ee5f8a43 | 709 | } |
b7c12ca4 DU |
710 | /* reorganize other pg packet */ |
711 | PgWriteSuccess = Efuse_PgPacketWrite(pAdapter, pTargetPkt->offset, badworden, pTargetPkt->data); | |
712 | if (!PgWriteSuccess) | |
713 | return false; | |
714 | else | |
715 | return true; | |
ee5f8a43 | 716 | } |
717 | ||
718 | static bool | |
719 | hal_EfusePgPacketWriteHeader( | |
720 | struct adapter *pAdapter, | |
721 | u8 efuseType, | |
722 | u16 *pAddr, | |
723 | struct pgpkt *pTargetPkt) | |
724 | { | |
725 | bool bRet = false; | |
726 | ||
727 | if (pTargetPkt->offset >= EFUSE_MAX_SECTION_BASE) | |
728 | bRet = hal_EfusePgPacketWrite2ByteHeader(pAdapter, efuseType, pAddr, pTargetPkt); | |
729 | else | |
730 | bRet = hal_EfusePgPacketWrite1ByteHeader(pAdapter, efuseType, pAddr, pTargetPkt); | |
731 | ||
732 | return bRet; | |
733 | } | |
734 | ||
735 | static bool wordEnMatched(struct pgpkt *pTargetPkt, struct pgpkt *pCurPkt, | |
736 | u8 *pWden) | |
737 | { | |
738 | u8 match_word_en = 0x0F; /* default all words are disabled */ | |
739 | ||
740 | /* check if the same words are enabled both target and current PG packet */ | |
741 | if (((pTargetPkt->word_en & BIT0) == 0) && | |
742 | ((pCurPkt->word_en & BIT0) == 0)) | |
743 | match_word_en &= ~BIT0; /* enable word 0 */ | |
744 | if (((pTargetPkt->word_en & BIT1) == 0) && | |
745 | ((pCurPkt->word_en & BIT1) == 0)) | |
746 | match_word_en &= ~BIT1; /* enable word 1 */ | |
747 | if (((pTargetPkt->word_en & BIT2) == 0) && | |
748 | ((pCurPkt->word_en & BIT2) == 0)) | |
749 | match_word_en &= ~BIT2; /* enable word 2 */ | |
750 | if (((pTargetPkt->word_en & BIT3) == 0) && | |
751 | ((pCurPkt->word_en & BIT3) == 0)) | |
752 | match_word_en &= ~BIT3; /* enable word 3 */ | |
753 | ||
754 | *pWden = match_word_en; | |
755 | ||
756 | if (match_word_en != 0xf) | |
757 | return true; | |
758 | else | |
759 | return false; | |
760 | } | |
761 | ||
762 | static bool hal_EfuseCheckIfDatafollowed(struct adapter *pAdapter, u8 word_cnts, u16 startAddr) | |
763 | { | |
764 | bool bRet = false; | |
765 | u8 i, efuse_data; | |
766 | ||
767 | for (i = 0; i < (word_cnts*2); i++) { | |
768 | if (efuse_OneByteRead(pAdapter, (startAddr+i), &efuse_data) && (efuse_data != 0xFF)) | |
769 | bRet = true; | |
770 | } | |
771 | return bRet; | |
772 | } | |
773 | ||
774 | static bool hal_EfusePartialWriteCheck(struct adapter *pAdapter, u8 efuseType, u16 *pAddr, struct pgpkt *pTargetPkt) | |
775 | { | |
776 | bool bRet = false; | |
777 | u8 i, efuse_data = 0, cur_header = 0; | |
778 | u8 matched_wden = 0, badworden = 0; | |
779 | u16 startAddr = 0, efuse_max_available_len = 0, efuse_max = 0; | |
780 | struct pgpkt curPkt; | |
781 | ||
782 | EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_AVAILABLE_EFUSE_BYTES_BANK, (void *)&efuse_max_available_len); | |
783 | EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_EFUSE_REAL_CONTENT_LEN, (void *)&efuse_max); | |
784 | ||
785 | rtw_hal_get_hwreg(pAdapter, HW_VAR_EFUSE_BYTES, (u8 *)&startAddr); | |
786 | startAddr %= EFUSE_REAL_CONTENT_LEN; | |
787 | ||
788 | while (1) { | |
789 | if (startAddr >= efuse_max_available_len) { | |
790 | bRet = false; | |
791 | break; | |
792 | } | |
793 | ||
794 | if (efuse_OneByteRead(pAdapter, startAddr, &efuse_data) && (efuse_data != 0xFF)) { | |
795 | if (EXT_HEADER(efuse_data)) { | |
796 | cur_header = efuse_data; | |
797 | startAddr++; | |
798 | efuse_OneByteRead(pAdapter, startAddr, &efuse_data); | |
799 | if (ALL_WORDS_DISABLED(efuse_data)) { | |
800 | bRet = false; | |
801 | break; | |
802 | } else { | |
803 | curPkt.offset = ((cur_header & 0xE0) >> 5) | ((efuse_data & 0xF0) >> 1); | |
804 | curPkt.word_en = efuse_data & 0x0F; | |
805 | } | |
806 | } else { | |
807 | cur_header = efuse_data; | |
808 | curPkt.offset = (cur_header>>4) & 0x0F; | |
809 | curPkt.word_en = cur_header & 0x0F; | |
810 | } | |
811 | ||
812 | curPkt.word_cnts = Efuse_CalculateWordCnts(curPkt.word_en); | |
813 | /* if same header is found but no data followed */ | |
814 | /* write some part of data followed by the header. */ | |
815 | if ((curPkt.offset == pTargetPkt->offset) && | |
816 | (!hal_EfuseCheckIfDatafollowed(pAdapter, curPkt.word_cnts, startAddr+1)) && | |
817 | wordEnMatched(pTargetPkt, &curPkt, &matched_wden)) { | |
818 | /* Here to write partial data */ | |
819 | badworden = Efuse_WordEnableDataWrite(pAdapter, startAddr+1, matched_wden, pTargetPkt->data); | |
820 | if (badworden != 0x0F) { | |
821 | u32 PgWriteSuccess = 0; | |
822 | /* if write fail on some words, write these bad words again */ | |
823 | ||
824 | PgWriteSuccess = Efuse_PgPacketWrite(pAdapter, pTargetPkt->offset, badworden, pTargetPkt->data); | |
825 | ||
826 | if (!PgWriteSuccess) { | |
827 | bRet = false; /* write fail, return */ | |
828 | break; | |
829 | } | |
830 | } | |
831 | /* partial write ok, update the target packet for later use */ | |
832 | for (i = 0; i < 4; i++) { | |
833 | if ((matched_wden & (0x1<<i)) == 0) /* this word has been written */ | |
834 | pTargetPkt->word_en |= (0x1<<i); /* disable the word */ | |
835 | } | |
836 | pTargetPkt->word_cnts = Efuse_CalculateWordCnts(pTargetPkt->word_en); | |
837 | } | |
838 | /* read from next header */ | |
839 | startAddr = startAddr + (curPkt.word_cnts*2) + 1; | |
840 | } else { | |
841 | /* not used header, 0xff */ | |
842 | *pAddr = startAddr; | |
843 | bRet = true; | |
844 | break; | |
845 | } | |
846 | } | |
847 | return bRet; | |
848 | } | |
849 | ||
850 | static bool | |
851 | hal_EfusePgCheckAvailableAddr( | |
852 | struct adapter *pAdapter, | |
853 | u8 efuseType | |
854 | ) | |
855 | { | |
856 | u16 efuse_max_available_len = 0; | |
857 | ||
858 | /* Change to check TYPE_EFUSE_MAP_LEN , because 8188E raw 256, logic map over 256. */ | |
859 | EFUSE_GetEfuseDefinition(pAdapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (void *)&efuse_max_available_len); | |
860 | ||
861 | if (Efuse_GetCurrentSize(pAdapter) >= efuse_max_available_len) | |
862 | return false; | |
863 | return true; | |
864 | } | |
865 | ||
866 | static void hal_EfuseConstructPGPkt(u8 offset, u8 word_en, u8 *pData, struct pgpkt *pTargetPkt) | |
867 | { | |
1ce39848 | 868 | memset((void *)pTargetPkt->data, 0xFF, sizeof(u8)*8); |
ee5f8a43 | 869 | pTargetPkt->offset = offset; |
870 | pTargetPkt->word_en = word_en; | |
871 | efuse_WordEnableDataRead(word_en, pData, pTargetPkt->data); | |
872 | pTargetPkt->word_cnts = Efuse_CalculateWordCnts(pTargetPkt->word_en); | |
873 | } | |
874 | ||
875 | bool Efuse_PgPacketWrite(struct adapter *pAdapter, u8 offset, u8 word_en, u8 *pData) | |
876 | { | |
877 | struct pgpkt targetPkt; | |
878 | u16 startAddr = 0; | |
879 | u8 efuseType = EFUSE_WIFI; | |
880 | ||
881 | if (!hal_EfusePgCheckAvailableAddr(pAdapter, efuseType)) | |
882 | return false; | |
883 | ||
884 | hal_EfuseConstructPGPkt(offset, word_en, pData, &targetPkt); | |
885 | ||
886 | if (!hal_EfusePartialWriteCheck(pAdapter, efuseType, &startAddr, &targetPkt)) | |
887 | return false; | |
888 | ||
889 | if (!hal_EfusePgPacketWriteHeader(pAdapter, efuseType, &startAddr, &targetPkt)) | |
890 | return false; | |
891 | ||
892 | if (!hal_EfusePgPacketWriteData(pAdapter, efuseType, &startAddr, &targetPkt)) | |
893 | return false; | |
894 | ||
895 | return true; | |
896 | } | |
897 | ||
756850c6 | 898 | u8 Efuse_CalculateWordCnts(u8 word_en) |
06a05884 LF |
899 | { |
900 | u8 word_cnts = 0; | |
901 | if (!(word_en & BIT(0))) | |
902 | word_cnts++; /* 0 : write enable */ | |
903 | if (!(word_en & BIT(1))) | |
904 | word_cnts++; | |
905 | if (!(word_en & BIT(2))) | |
906 | word_cnts++; | |
907 | if (!(word_en & BIT(3))) | |
908 | word_cnts++; | |
909 | return word_cnts; | |
910 | } | |
911 | ||
78810556 | 912 | u8 efuse_OneByteRead(struct adapter *pAdapter, u16 addr, u8 *data) |
06a05884 LF |
913 | { |
914 | u8 tmpidx = 0; | |
915 | u8 result; | |
916 | ||
e76484d0 | 917 | usb_write8(pAdapter, EFUSE_CTRL+1, (u8)(addr & 0xff)); |
918 | usb_write8(pAdapter, EFUSE_CTRL+2, ((u8)((addr>>8) & 0x03)) | | |
c7b2e995 | 919 | (usb_read8(pAdapter, EFUSE_CTRL+2) & 0xFC)); |
06a05884 | 920 | |
e76484d0 | 921 | usb_write8(pAdapter, EFUSE_CTRL+3, 0x72);/* read cmd */ |
06a05884 | 922 | |
c7b2e995 | 923 | while (!(0x80 & usb_read8(pAdapter, EFUSE_CTRL+3)) && (tmpidx < 100)) |
06a05884 LF |
924 | tmpidx++; |
925 | if (tmpidx < 100) { | |
c7b2e995 | 926 | *data = usb_read8(pAdapter, EFUSE_CTRL); |
06a05884 LF |
927 | result = true; |
928 | } else { | |
929 | *data = 0xff; | |
930 | result = false; | |
931 | } | |
932 | return result; | |
933 | } | |
934 | ||
20f3b6c8 | 935 | u8 efuse_OneByteWrite(struct adapter *pAdapter, u16 addr, u8 data) |
06a05884 LF |
936 | { |
937 | u8 tmpidx = 0; | |
938 | u8 result; | |
939 | ||
e76484d0 | 940 | usb_write8(pAdapter, EFUSE_CTRL+1, (u8)(addr&0xff)); |
941 | usb_write8(pAdapter, EFUSE_CTRL+2, | |
c7b2e995 | 942 | (usb_read8(pAdapter, EFUSE_CTRL+2) & 0xFC) | |
06a05884 | 943 | (u8)((addr>>8) & 0x03)); |
e76484d0 | 944 | usb_write8(pAdapter, EFUSE_CTRL, data);/* data */ |
06a05884 | 945 | |
e76484d0 | 946 | usb_write8(pAdapter, EFUSE_CTRL+3, 0xF2);/* write cmd */ |
06a05884 | 947 | |
c7b2e995 | 948 | while ((0x80 & usb_read8(pAdapter, EFUSE_CTRL+3)) && (tmpidx < 100)) |
06a05884 LF |
949 | tmpidx++; |
950 | ||
951 | if (tmpidx < 100) | |
952 | result = true; | |
953 | else | |
954 | result = false; | |
955 | ||
956 | return result; | |
957 | } | |
958 | ||
756850c6 | 959 | /* |
960 | * Overview: Read allowed word in current efuse section data. | |
961 | */ | |
06a05884 LF |
962 | void efuse_WordEnableDataRead(u8 word_en, u8 *sourdata, u8 *targetdata) |
963 | { | |
964 | if (!(word_en&BIT(0))) { | |
965 | targetdata[0] = sourdata[0]; | |
966 | targetdata[1] = sourdata[1]; | |
967 | } | |
968 | if (!(word_en&BIT(1))) { | |
969 | targetdata[2] = sourdata[2]; | |
970 | targetdata[3] = sourdata[3]; | |
971 | } | |
972 | if (!(word_en&BIT(2))) { | |
973 | targetdata[4] = sourdata[4]; | |
974 | targetdata[5] = sourdata[5]; | |
975 | } | |
976 | if (!(word_en&BIT(3))) { | |
977 | targetdata[6] = sourdata[6]; | |
978 | targetdata[7] = sourdata[7]; | |
979 | } | |
980 | } | |
981 | ||
756850c6 | 982 | /* |
06a05884 | 983 | * Overview: Read All Efuse content |
756850c6 | 984 | */ |
0d1c84d6 | 985 | static void Efuse_ReadAllMap(struct adapter *pAdapter, u8 efuseType, u8 *Efuse) |
06a05884 LF |
986 | { |
987 | u16 mapLen = 0; | |
988 | ||
989 | Efuse_PowerSwitch(pAdapter, false, true); | |
990 | ||
9dec254a | 991 | EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_EFUSE_MAP_LEN, (void *)&mapLen); |
06a05884 | 992 | |
142547b3 | 993 | efuse_ReadEFuse(pAdapter, efuseType, 0, mapLen, Efuse); |
06a05884 LF |
994 | |
995 | Efuse_PowerSwitch(pAdapter, false, false); | |
996 | } | |
997 | ||
756850c6 | 998 | /* |
06a05884 | 999 | * Overview: Transfer current EFUSE content to shadow init and modify map. |
756850c6 | 1000 | */ |
06a05884 LF |
1001 | void EFUSE_ShadowMapUpdate( |
1002 | struct adapter *pAdapter, | |
b0d255c7 | 1003 | u8 efuseType) |
06a05884 LF |
1004 | { |
1005 | struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(pAdapter); | |
1006 | u16 mapLen = 0; | |
1007 | ||
9dec254a | 1008 | EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_EFUSE_MAP_LEN, (void *)&mapLen); |
06a05884 LF |
1009 | |
1010 | if (pEEPROM->bautoload_fail_flag) | |
1ce39848 | 1011 | memset(pEEPROM->efuse_eeprom_data, 0xFF, mapLen); |
06a05884 | 1012 | else |
0d1c84d6 | 1013 | Efuse_ReadAllMap(pAdapter, efuseType, pEEPROM->efuse_eeprom_data); |
756850c6 | 1014 | } |