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