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 */
14u8 fakeEfuseBank;
15u32 fakeEfuseUsedBytes;
16u8 fakeEfuseContent[EFUSE_MAX_HW_SIZE] = {0};
17u8 fakeEfuseInitMap[EFUSE_MAX_MAP_LEN] = {0};
18u8 fakeEfuseModifiedMap[EFUSE_MAX_MAP_LEN] = {0};
19
20u32 BTEfuseUsedBytes;
21u8 BTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE];
22u8 BTEfuseInitMap[EFUSE_BT_MAX_MAP_LEN] = {0};
23u8 BTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN] = {0};
24
25u32 fakeBTEfuseUsedBytes;
26u8 fakeBTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE];
27u8 fakeBTEfuseInitMap[EFUSE_BT_MAX_MAP_LEN] = {0};
28u8 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
33static bool
34Efuse_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
45static bool
46Efuse_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 *---------------------------------------------------------------------------*/
75void
76Efuse_PowerSwitch(
77struct adapter *padapter,
78u8 bWrite,
79u8 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 *---------------------------------------------------------------------------*/
100u16
101Efuse_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!!. */
111u8
112Efuse_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
144void
145efuse_ReadEFuse(
146 struct adapter *Adapter,
147 u8 efuseType,
148 u16 _offset,
149 u16 _size_byte,
150 u8 *pbuf,
151bool bPseudoTest
152 );
153void
154efuse_ReadEFuse(
155 struct adapter *Adapter,
156 u8 efuseType,
157 u16 _offset,
158 u16 _size_byte,
159 u8 *pbuf,
160bool bPseudoTest
161 )
162{
163 Adapter->HalFunc.ReadEFuse(Adapter, efuseType, _offset, _size_byte, pbuf, bPseudoTest);
164}
165
166void
167EFUSE_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 *---------------------------------------------------------------------------*/
194u8
195EFUSE_Read1Byte(
196struct adapter *Adapter,
197u16 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. */
235u8
236efuse_OneByteRead(
237struct adapter *padapter,
238u16 addr,
239u8 *data,
240bool 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. */
281u8 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
325int
326Efuse_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
335int
336Efuse_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 *---------------------------------------------------------------------------*/
363void
364efuse_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
387u8
388Efuse_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 *---------------------------------------------------------------------------*/
415void
416Efuse_ReadAllMap(
417 struct adapter *padapter,
418 u8 efuseType,
419 u8 *Efuse,
420 bool bPseudoTest);
421void 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 *---------------------------------------------------------------------------*/
452static 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 */
461static 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 */
471static 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 *---------------------------------------------------------------------------*/
498void 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 *---------------------------------------------------------------------------*/
531void 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

source code of linux/drivers/staging/rtl8723bs/core/rtw_efuse.c