1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /****************************************************************************** |
3 | * |
4 | * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. |
5 | * |
6 | ******************************************************************************/ |
7 | #include <drv_types.h> |
8 | #include <rtw_debug.h> |
9 | #include <hal_data.h> |
10 | #include <linux/jiffies.h> |
11 | |
12 | |
13 | /* Define global variables */ |
14 | u8 fakeEfuseBank; |
15 | u32 fakeEfuseUsedBytes; |
16 | u8 fakeEfuseContent[EFUSE_MAX_HW_SIZE] = {0}; |
17 | u8 fakeEfuseInitMap[EFUSE_MAX_MAP_LEN] = {0}; |
18 | u8 fakeEfuseModifiedMap[EFUSE_MAX_MAP_LEN] = {0}; |
19 | |
20 | u32 BTEfuseUsedBytes; |
21 | u8 BTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE]; |
22 | u8 BTEfuseInitMap[EFUSE_BT_MAX_MAP_LEN] = {0}; |
23 | u8 BTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN] = {0}; |
24 | |
25 | u32 fakeBTEfuseUsedBytes; |
26 | u8 fakeBTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE]; |
27 | u8 fakeBTEfuseInitMap[EFUSE_BT_MAX_MAP_LEN] = {0}; |
28 | u8 fakeBTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN] = {0}; |
29 | |
30 | #define REG_EFUSE_CTRL 0x0030 |
31 | #define EFUSE_CTRL REG_EFUSE_CTRL /* E-Fuse Control. */ |
32 | |
33 | static bool |
34 | Efuse_Read1ByteFromFakeContent(u16 Offset, u8 *Value) |
35 | { |
36 | if (Offset >= EFUSE_MAX_HW_SIZE) |
37 | return false; |
38 | if (fakeEfuseBank == 0) |
39 | *Value = fakeEfuseContent[Offset]; |
40 | else |
41 | *Value = fakeBTEfuseContent[fakeEfuseBank-1][Offset]; |
42 | return true; |
43 | } |
44 | |
45 | static bool |
46 | Efuse_Write1ByteToFakeContent(u16 Offset, u8 Value) |
47 | { |
48 | if (Offset >= EFUSE_MAX_HW_SIZE) |
49 | return false; |
50 | if (fakeEfuseBank == 0) |
51 | fakeEfuseContent[Offset] = Value; |
52 | else |
53 | fakeBTEfuseContent[fakeEfuseBank-1][Offset] = Value; |
54 | return true; |
55 | } |
56 | |
57 | /*----------------------------------------------------------------------------- |
58 | * Function: Efuse_PowerSwitch |
59 | * |
60 | * Overview: When we want to enable write operation, we should change to |
61 | * pwr on state. When we stop write, we should switch to 500k mode |
62 | * and disable LDO 2.5V. |
63 | * |
64 | * Input: NONE |
65 | * |
66 | * Output: NONE |
67 | * |
68 | * Return: NONE |
69 | * |
70 | * Revised History: |
71 | * When Who Remark |
72 | * 11/17/2008 MHC Create Version 0. |
73 | * |
74 | *---------------------------------------------------------------------------*/ |
75 | void |
76 | Efuse_PowerSwitch( |
77 | struct adapter *padapter, |
78 | u8 bWrite, |
79 | u8 PwrState) |
80 | { |
81 | padapter->HalFunc.EfusePowerSwitch(padapter, bWrite, PwrState); |
82 | } |
83 | |
84 | /*----------------------------------------------------------------------------- |
85 | * Function: Efuse_GetCurrentSize |
86 | * |
87 | * Overview: Get current efuse size!!! |
88 | * |
89 | * Input: NONE |
90 | * |
91 | * Output: NONE |
92 | * |
93 | * Return: NONE |
94 | * |
95 | * Revised History: |
96 | * When Who Remark |
97 | * 11/16/2008 MHC Create Version 0. |
98 | * |
99 | *---------------------------------------------------------------------------*/ |
100 | u16 |
101 | Efuse_GetCurrentSize( |
102 | struct adapter *padapter, |
103 | u8 efuseType, |
104 | bool bPseudoTest) |
105 | { |
106 | return padapter->HalFunc.EfuseGetCurrentSize(padapter, efuseType, |
107 | bPseudoTest); |
108 | } |
109 | |
110 | /* 11/16/2008 MH Add description. Get current efuse area enabled word!!. */ |
111 | u8 |
112 | Efuse_CalculateWordCnts(u8 word_en) |
113 | { |
114 | u8 word_cnts = 0; |
115 | if (!(word_en & BIT(0))) |
116 | word_cnts++; /* 0 : write enable */ |
117 | if (!(word_en & BIT(1))) |
118 | word_cnts++; |
119 | if (!(word_en & BIT(2))) |
120 | word_cnts++; |
121 | if (!(word_en & BIT(3))) |
122 | word_cnts++; |
123 | return word_cnts; |
124 | } |
125 | |
126 | /* */ |
127 | /* Description: */ |
128 | /* 1. Execute E-Fuse read byte operation according as map offset and */ |
129 | /* save to E-Fuse table. */ |
130 | /* 2. Referred from SD1 Richard. */ |
131 | /* */ |
132 | /* Assumption: */ |
133 | /* 1. Boot from E-Fuse and successfully auto-load. */ |
134 | /* 2. PASSIVE_LEVEL (USB interface) */ |
135 | /* */ |
136 | /* Created by Roger, 2008.10.21. */ |
137 | /* */ |
138 | /* 2008/12/12 MH 1. Reorganize code flow and reserve bytes. and add description. */ |
139 | /* 2. Add efuse utilization collect. */ |
140 | /* 2008/12/22 MH Read Efuse must check if we write section 1 data again!!! Sec1 */ |
141 | /* write addr must be after sec5. */ |
142 | /* */ |
143 | |
144 | void |
145 | efuse_ReadEFuse( |
146 | struct adapter *Adapter, |
147 | u8 efuseType, |
148 | u16 _offset, |
149 | u16 _size_byte, |
150 | u8 *pbuf, |
151 | bool bPseudoTest |
152 | ); |
153 | void |
154 | efuse_ReadEFuse( |
155 | struct adapter *Adapter, |
156 | u8 efuseType, |
157 | u16 _offset, |
158 | u16 _size_byte, |
159 | u8 *pbuf, |
160 | bool bPseudoTest |
161 | ) |
162 | { |
163 | Adapter->HalFunc.ReadEFuse(Adapter, efuseType, _offset, _size_byte, pbuf, bPseudoTest); |
164 | } |
165 | |
166 | void |
167 | EFUSE_GetEfuseDefinition( |
168 | struct adapter *padapter, |
169 | u8 efuseType, |
170 | u8 type, |
171 | void *pOut, |
172 | bool bPseudoTest |
173 | ) |
174 | { |
175 | padapter->HalFunc.EFUSEGetEfuseDefinition(padapter, efuseType, type, pOut, bPseudoTest); |
176 | } |
177 | |
178 | /*----------------------------------------------------------------------------- |
179 | * Function: EFUSE_Read1Byte |
180 | * |
181 | * Overview: Copy from WMAC fot EFUSE read 1 byte. |
182 | * |
183 | * Input: NONE |
184 | * |
185 | * Output: NONE |
186 | * |
187 | * Return: NONE |
188 | * |
189 | * Revised History: |
190 | * When Who Remark |
191 | * 09/23/2008 MHC Copy from WMAC. |
192 | * |
193 | *---------------------------------------------------------------------------*/ |
194 | u8 |
195 | EFUSE_Read1Byte( |
196 | struct adapter *Adapter, |
197 | u16 Address) |
198 | { |
199 | u8 Bytetemp = {0x00}; |
200 | u8 temp = {0x00}; |
201 | u32 k = 0; |
202 | u16 contentLen = 0; |
203 | |
204 | EFUSE_GetEfuseDefinition(padapter: Adapter, EFUSE_WIFI, type: TYPE_EFUSE_REAL_CONTENT_LEN, pOut: (void *)&contentLen, bPseudoTest: false); |
205 | |
206 | if (Address < contentLen) {/* E-fuse 512Byte */ |
207 | /* Write E-fuse Register address bit0~7 */ |
208 | temp = Address & 0xFF; |
209 | rtw_write8(adapter: Adapter, EFUSE_CTRL+1, val: temp); |
210 | Bytetemp = rtw_read8(adapter: Adapter, EFUSE_CTRL+2); |
211 | /* Write E-fuse Register address bit8~9 */ |
212 | temp = ((Address >> 8) & 0x03) | (Bytetemp & 0xFC); |
213 | rtw_write8(adapter: Adapter, EFUSE_CTRL+2, val: temp); |
214 | |
215 | /* Write 0x30[31]= 0 */ |
216 | Bytetemp = rtw_read8(adapter: Adapter, EFUSE_CTRL+3); |
217 | temp = Bytetemp & 0x7F; |
218 | rtw_write8(adapter: Adapter, EFUSE_CTRL+3, val: temp); |
219 | |
220 | /* Wait Write-ready (0x30[31]= 1) */ |
221 | Bytetemp = rtw_read8(adapter: Adapter, EFUSE_CTRL+3); |
222 | while (!(Bytetemp & 0x80)) { |
223 | Bytetemp = rtw_read8(adapter: Adapter, EFUSE_CTRL+3); |
224 | k++; |
225 | if (k == 1000) |
226 | break; |
227 | } |
228 | return rtw_read8(adapter: Adapter, EFUSE_CTRL); |
229 | } else |
230 | return 0xFF; |
231 | |
232 | } /* EFUSE_Read1Byte */ |
233 | |
234 | /* 11/16/2008 MH Read one byte from real Efuse. */ |
235 | u8 |
236 | efuse_OneByteRead( |
237 | struct adapter *padapter, |
238 | u16 addr, |
239 | u8 *data, |
240 | bool bPseudoTest) |
241 | { |
242 | u32 tmpidx = 0; |
243 | u8 bResult; |
244 | u8 readbyte; |
245 | |
246 | if (bPseudoTest) |
247 | return Efuse_Read1ByteFromFakeContent(Offset: addr, Value: data); |
248 | |
249 | /* <20130121, Kordan> For SMIC EFUSE specificatoin. */ |
250 | /* 0x34[11]: SW force PGMEN input of efuse to high. (for the bank selected by 0x34[9:8]) */ |
251 | /* PHY_SetMacReg(padapter, 0x34, BIT11, 0); */ |
252 | rtw_write16(adapter: padapter, addr: 0x34, val: rtw_read16(adapter: padapter, addr: 0x34) & (~BIT11)); |
253 | |
254 | /* -----------------e-fuse reg ctrl --------------------------------- */ |
255 | /* address */ |
256 | rtw_write8(adapter: padapter, EFUSE_CTRL+1, val: (u8)(addr&0xff)); |
257 | rtw_write8(adapter: padapter, EFUSE_CTRL+2, val: ((u8)((addr>>8) & 0x03)) | |
258 | (rtw_read8(adapter: padapter, EFUSE_CTRL+2)&0xFC)); |
259 | |
260 | /* rtw_write8(padapter, EFUSE_CTRL+3, 0x72); read cmd */ |
261 | /* Write bit 32 0 */ |
262 | readbyte = rtw_read8(adapter: padapter, EFUSE_CTRL+3); |
263 | rtw_write8(adapter: padapter, EFUSE_CTRL+3, val: (readbyte & 0x7f)); |
264 | |
265 | while (!(0x80 & rtw_read8(adapter: padapter, EFUSE_CTRL+3)) && (tmpidx < 1000)) { |
266 | mdelay(1); |
267 | tmpidx++; |
268 | } |
269 | if (tmpidx < 100) { |
270 | *data = rtw_read8(adapter: padapter, EFUSE_CTRL); |
271 | bResult = true; |
272 | } else { |
273 | *data = 0xff; |
274 | bResult = false; |
275 | } |
276 | |
277 | return bResult; |
278 | } |
279 | |
280 | /* 11/16/2008 MH Write one byte to reald Efuse. */ |
281 | u8 efuse_OneByteWrite(struct adapter *padapter, u16 addr, u8 data, bool bPseudoTest) |
282 | { |
283 | u8 tmpidx = 0; |
284 | u8 bResult = false; |
285 | u32 efuseValue; |
286 | |
287 | if (bPseudoTest) |
288 | return Efuse_Write1ByteToFakeContent(Offset: addr, Value: data); |
289 | |
290 | |
291 | /* -----------------e-fuse reg ctrl --------------------------------- */ |
292 | /* address */ |
293 | |
294 | |
295 | efuseValue = rtw_read32(adapter: padapter, EFUSE_CTRL); |
296 | efuseValue |= (BIT21|BIT31); |
297 | efuseValue &= ~(0x3FFFF); |
298 | efuseValue |= ((addr<<8 | data) & 0x3FFFF); |
299 | |
300 | |
301 | /* <20130227, Kordan> 8192E MP chip A-cut had better not set 0x34[11] until B-Cut. */ |
302 | |
303 | /* <20130121, Kordan> For SMIC EFUSE specificatoin. */ |
304 | /* 0x34[11]: SW force PGMEN input of efuse to high. (for the bank selected by 0x34[9:8]) */ |
305 | /* PHY_SetMacReg(padapter, 0x34, BIT11, 1); */ |
306 | rtw_write16(adapter: padapter, addr: 0x34, val: rtw_read16(adapter: padapter, addr: 0x34) | (BIT11)); |
307 | rtw_write32(adapter: padapter, EFUSE_CTRL, val: 0x90600000|((addr<<8 | data))); |
308 | |
309 | while ((0x80 & rtw_read8(adapter: padapter, EFUSE_CTRL+3)) && (tmpidx < 100)) { |
310 | mdelay(1); |
311 | tmpidx++; |
312 | } |
313 | |
314 | if (tmpidx < 100) |
315 | bResult = true; |
316 | else |
317 | bResult = false; |
318 | |
319 | /* disable Efuse program enable */ |
320 | PHY_SetMacReg(padapter, EFUSE_TEST, BIT(11), 0); |
321 | |
322 | return bResult; |
323 | } |
324 | |
325 | int |
326 | Efuse_PgPacketRead(struct adapter *padapter, |
327 | u8 offset, |
328 | u8 *data, |
329 | bool bPseudoTest) |
330 | { |
331 | return padapter->HalFunc.Efuse_PgPacketRead(padapter, offset, data, |
332 | bPseudoTest); |
333 | } |
334 | |
335 | int |
336 | Efuse_PgPacketWrite(struct adapter *padapter, |
337 | u8 offset, |
338 | u8 word_en, |
339 | u8 *data, |
340 | bool bPseudoTest) |
341 | { |
342 | return padapter->HalFunc.Efuse_PgPacketWrite(padapter, offset, word_en, |
343 | data, bPseudoTest); |
344 | } |
345 | |
346 | /*----------------------------------------------------------------------------- |
347 | * Function: efuse_WordEnableDataRead |
348 | * |
349 | * Overview: Read allowed word in current efuse section data. |
350 | * |
351 | * Input: NONE |
352 | * |
353 | * Output: NONE |
354 | * |
355 | * Return: NONE |
356 | * |
357 | * Revised History: |
358 | * When Who Remark |
359 | * 11/16/2008 MHC Create Version 0. |
360 | * 11/21/2008 MHC Fix Write bug when we only enable late word. |
361 | * |
362 | *---------------------------------------------------------------------------*/ |
363 | void |
364 | efuse_WordEnableDataRead(u8 word_en, |
365 | u8 *sourdata, |
366 | u8 *targetdata) |
367 | { |
368 | if (!(word_en&BIT(0))) { |
369 | targetdata[0] = sourdata[0]; |
370 | targetdata[1] = sourdata[1]; |
371 | } |
372 | if (!(word_en&BIT(1))) { |
373 | targetdata[2] = sourdata[2]; |
374 | targetdata[3] = sourdata[3]; |
375 | } |
376 | if (!(word_en&BIT(2))) { |
377 | targetdata[4] = sourdata[4]; |
378 | targetdata[5] = sourdata[5]; |
379 | } |
380 | if (!(word_en&BIT(3))) { |
381 | targetdata[6] = sourdata[6]; |
382 | targetdata[7] = sourdata[7]; |
383 | } |
384 | } |
385 | |
386 | |
387 | u8 |
388 | Efuse_WordEnableDataWrite(struct adapter *padapter, |
389 | u16 efuse_addr, |
390 | u8 word_en, |
391 | u8 *data, |
392 | bool bPseudoTest) |
393 | { |
394 | return padapter->HalFunc.Efuse_WordEnableDataWrite(padapter, efuse_addr, |
395 | word_en, data, |
396 | bPseudoTest); |
397 | } |
398 | |
399 | /*----------------------------------------------------------------------------- |
400 | * Function: Efuse_ReadAllMap |
401 | * |
402 | * Overview: Read All Efuse content |
403 | * |
404 | * Input: NONE |
405 | * |
406 | * Output: NONE |
407 | * |
408 | * Return: NONE |
409 | * |
410 | * Revised History: |
411 | * When Who Remark |
412 | * 11/11/2008 MHC Create Version 0. |
413 | * |
414 | *---------------------------------------------------------------------------*/ |
415 | void |
416 | Efuse_ReadAllMap( |
417 | struct adapter *padapter, |
418 | u8 efuseType, |
419 | u8 *Efuse, |
420 | bool bPseudoTest); |
421 | void Efuse_ReadAllMap(struct adapter *padapter, u8 efuseType, u8 *Efuse, bool bPseudoTest) |
422 | { |
423 | u16 mapLen = 0; |
424 | |
425 | Efuse_PowerSwitch(padapter, bWrite: false, PwrState: true); |
426 | |
427 | EFUSE_GetEfuseDefinition(padapter, efuseType, type: TYPE_EFUSE_MAP_LEN, pOut: (void *)&mapLen, bPseudoTest); |
428 | |
429 | efuse_ReadEFuse(Adapter: padapter, efuseType, offset: 0, size_byte: mapLen, pbuf: Efuse, bPseudoTest); |
430 | |
431 | Efuse_PowerSwitch(padapter, bWrite: false, PwrState: false); |
432 | } |
433 | |
434 | /*----------------------------------------------------------------------------- |
435 | * Function: efuse_ShadowRead1Byte |
436 | * efuse_ShadowRead2Byte |
437 | * efuse_ShadowRead4Byte |
438 | * |
439 | * Overview: Read from efuse init map by one/two/four bytes !!!!! |
440 | * |
441 | * Input: NONE |
442 | * |
443 | * Output: NONE |
444 | * |
445 | * Return: NONE |
446 | * |
447 | * Revised History: |
448 | * When Who Remark |
449 | * 11/12/2008 MHC Create Version 0. |
450 | * |
451 | *---------------------------------------------------------------------------*/ |
452 | static void efuse_ShadowRead1Byte(struct adapter *padapter, u16 Offset, u8 *Value) |
453 | { |
454 | struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); |
455 | |
456 | *Value = pEEPROM->efuse_eeprom_data[Offset]; |
457 | |
458 | } /* EFUSE_ShadowRead1Byte */ |
459 | |
460 | /* Read Two Bytes */ |
461 | static void efuse_ShadowRead2Byte(struct adapter *padapter, u16 Offset, u16 *Value) |
462 | { |
463 | struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); |
464 | |
465 | *Value = pEEPROM->efuse_eeprom_data[Offset]; |
466 | *Value |= pEEPROM->efuse_eeprom_data[Offset+1]<<8; |
467 | |
468 | } /* EFUSE_ShadowRead2Byte */ |
469 | |
470 | /* Read Four Bytes */ |
471 | static void efuse_ShadowRead4Byte(struct adapter *padapter, u16 Offset, u32 *Value) |
472 | { |
473 | struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); |
474 | |
475 | *Value = pEEPROM->efuse_eeprom_data[Offset]; |
476 | *Value |= pEEPROM->efuse_eeprom_data[Offset+1]<<8; |
477 | *Value |= pEEPROM->efuse_eeprom_data[Offset+2]<<16; |
478 | *Value |= pEEPROM->efuse_eeprom_data[Offset+3]<<24; |
479 | |
480 | } /* efuse_ShadowRead4Byte */ |
481 | |
482 | /*----------------------------------------------------------------------------- |
483 | * Function: EFUSE_ShadowMapUpdate |
484 | * |
485 | * Overview: Transfer current EFUSE content to shadow init and modify map. |
486 | * |
487 | * Input: NONE |
488 | * |
489 | * Output: NONE |
490 | * |
491 | * Return: NONE |
492 | * |
493 | * Revised History: |
494 | * When Who Remark |
495 | * 11/13/2008 MHC Create Version 0. |
496 | * |
497 | *---------------------------------------------------------------------------*/ |
498 | void EFUSE_ShadowMapUpdate(struct adapter *padapter, u8 efuseType, bool bPseudoTest) |
499 | { |
500 | struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); |
501 | u16 mapLen = 0; |
502 | |
503 | EFUSE_GetEfuseDefinition(padapter, efuseType, type: TYPE_EFUSE_MAP_LEN, pOut: (void *)&mapLen, bPseudoTest); |
504 | |
505 | if (pEEPROM->bautoload_fail_flag) |
506 | memset(pEEPROM->efuse_eeprom_data, 0xFF, mapLen); |
507 | else |
508 | Efuse_ReadAllMap(padapter, efuseType, Efuse: pEEPROM->efuse_eeprom_data, bPseudoTest); |
509 | |
510 | /* PlatformMoveMemory((void *)&pHalData->EfuseMap[EFUSE_MODIFY_MAP][0], */ |
511 | /* void *)&pHalData->EfuseMap[EFUSE_INIT_MAP][0], mapLen); */ |
512 | } /* EFUSE_ShadowMapUpdate */ |
513 | |
514 | |
515 | /*----------------------------------------------------------------------------- |
516 | * Function: EFUSE_ShadowRead |
517 | * |
518 | * Overview: Read from efuse init map !!!!! |
519 | * |
520 | * Input: NONE |
521 | * |
522 | * Output: NONE |
523 | * |
524 | * Return: NONE |
525 | * |
526 | * Revised History: |
527 | * When Who Remark |
528 | * 11/12/2008 MHC Create Version 0. |
529 | * |
530 | *---------------------------------------------------------------------------*/ |
531 | void EFUSE_ShadowRead(struct adapter *padapter, u8 Type, u16 Offset, u32 *Value) |
532 | { |
533 | if (Type == 1) |
534 | efuse_ShadowRead1Byte(padapter, Offset, Value: (u8 *)Value); |
535 | else if (Type == 2) |
536 | efuse_ShadowRead2Byte(padapter, Offset, Value: (u16 *)Value); |
537 | else if (Type == 4) |
538 | efuse_ShadowRead4Byte(padapter, Offset, Value: (u32 *)Value); |
539 | |
540 | } /* EFUSE_ShadowRead*/ |
541 | |