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