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