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