[go: nahoru, domu]

1/******************************************************************************
2 *
3 * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
17 *
18 *
19 ******************************************************************************/
20#define _RTW_EFUSE_C_
21
22#include <osdep_service.h>
23#include <drv_types.h>
24#include <rtw_efuse.h>
25#include <usb_ops_linux.h>
26#include <rtl8188e_hal.h>
27#include <rtw_iol.h>
28
29#define REG_EFUSE_CTRL		0x0030
30#define EFUSE_CTRL			REG_EFUSE_CTRL		/*  E-Fuse Control. */
31
32enum{
33		VOLTAGE_V25						= 0x03,
34		LDOE25_SHIFT						= 28 ,
35	};
36
37/*
38 * Function:	Efuse_PowerSwitch
39 *
40 * Overview:	When we want to enable write operation, we should change to
41 *				pwr on state. When we stop write, we should switch to 500k mode
42 *				and disable LDO 2.5V.
43 */
44
45void Efuse_PowerSwitch(
46		struct adapter *pAdapter,
47		u8 bWrite,
48		u8 PwrState)
49{
50	u8 tempval;
51	u16	tmpV16;
52
53	if (PwrState) {
54		usb_write8(pAdapter, REG_EFUSE_ACCESS, EFUSE_ACCESS_ON);
55
56		/*  1.2V Power: From VDDON with Power Cut(0x0000h[15]), defualt valid */
57		tmpV16 = usb_read16(pAdapter, REG_SYS_ISO_CTRL);
58		if (!(tmpV16 & PWC_EV12V)) {
59			tmpV16 |= PWC_EV12V;
60			 usb_write16(pAdapter, REG_SYS_ISO_CTRL, tmpV16);
61		}
62		/*  Reset: 0x0000h[28], default valid */
63		tmpV16 =  usb_read16(pAdapter, REG_SYS_FUNC_EN);
64		if (!(tmpV16 & FEN_ELDR)) {
65			tmpV16 |= FEN_ELDR;
66			usb_write16(pAdapter, REG_SYS_FUNC_EN, tmpV16);
67		}
68
69		/*  Clock: Gated(0x0008h[5]) 8M(0x0008h[1]) clock from ANA, default valid */
70		tmpV16 = usb_read16(pAdapter, REG_SYS_CLKR);
71		if ((!(tmpV16 & LOADER_CLK_EN))  || (!(tmpV16 & ANA8M))) {
72			tmpV16 |= (LOADER_CLK_EN | ANA8M);
73			usb_write16(pAdapter, REG_SYS_CLKR, tmpV16);
74		}
75
76		if (bWrite) {
77			/*  Enable LDO 2.5V before read/write action */
78			tempval = usb_read8(pAdapter, EFUSE_TEST+3);
79			tempval &= 0x0F;
80			tempval |= (VOLTAGE_V25 << 4);
81			usb_write8(pAdapter, EFUSE_TEST+3, (tempval | 0x80));
82		}
83	} else {
84		usb_write8(pAdapter, REG_EFUSE_ACCESS, EFUSE_ACCESS_OFF);
85
86		if (bWrite) {
87			/*  Disable LDO 2.5V after read/write action */
88			tempval = usb_read8(pAdapter, EFUSE_TEST+3);
89			usb_write8(pAdapter, EFUSE_TEST+3, (tempval & 0x7F));
90		}
91	}
92}
93
94static void
95efuse_phymap_to_logical(u8 *phymap, u16 _offset, u16 _size_byte, u8  *pbuf)
96{
97	u8 *efuseTbl = NULL;
98	u8 rtemp8;
99	u16	eFuse_Addr = 0;
100	u8 offset, wren;
101	u16	i, j;
102	u16	**eFuseWord = NULL;
103	u16	efuse_utilized = 0;
104	u8 u1temp = 0;
105
106	efuseTbl = kzalloc(EFUSE_MAP_LEN_88E, GFP_KERNEL);
107	if (efuseTbl == NULL) {
108		DBG_88E("%s: alloc efuseTbl fail!\n", __func__);
109		goto exit;
110	}
111
112	eFuseWord = (u16 **)rtw_malloc2d(EFUSE_MAX_SECTION_88E, EFUSE_MAX_WORD_UNIT, sizeof(u16));
113	if (eFuseWord == NULL) {
114		DBG_88E("%s: alloc eFuseWord fail!\n", __func__);
115		goto exit;
116	}
117
118	/*  0. Refresh efuse init map as all oxFF. */
119	for (i = 0; i < EFUSE_MAX_SECTION_88E; i++)
120		for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++)
121			eFuseWord[i][j] = 0xFFFF;
122
123	/*  */
124	/*  1. Read the first byte to check if efuse is empty!!! */
125	/*  */
126	/*  */
127	rtemp8 = *(phymap+eFuse_Addr);
128	if (rtemp8 != 0xFF) {
129		efuse_utilized++;
130		eFuse_Addr++;
131	} else {
132		DBG_88E("EFUSE is empty efuse_Addr-%d efuse_data =%x\n", eFuse_Addr, rtemp8);
133		goto exit;
134	}
135
136	/*  */
137	/*  2. Read real efuse content. Filter PG header and every section data. */
138	/*  */
139	while ((rtemp8 != 0xFF) && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E)) {
140		/*  Check PG header for section num. */
141		if ((rtemp8 & 0x1F) == 0x0F) {		/* extended header */
142			u1temp = ((rtemp8 & 0xE0) >> 5);
143			rtemp8 = *(phymap+eFuse_Addr);
144			if ((rtemp8 & 0x0F) == 0x0F) {
145				eFuse_Addr++;
146				rtemp8 = *(phymap+eFuse_Addr);
147
148				if (rtemp8 != 0xFF && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E))
149					eFuse_Addr++;
150				continue;
151			} else {
152				offset = ((rtemp8 & 0xF0) >> 1) | u1temp;
153				wren = (rtemp8 & 0x0F);
154				eFuse_Addr++;
155			}
156		} else {
157			offset = ((rtemp8 >> 4) & 0x0f);
158			wren = (rtemp8 & 0x0f);
159		}
160
161		if (offset < EFUSE_MAX_SECTION_88E) {
162			/*  Get word enable value from PG header */
163			for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) {
164				/*  Check word enable condition in the section */
165				if (!(wren & 0x01)) {
166					rtemp8 = *(phymap+eFuse_Addr);
167					eFuse_Addr++;
168					efuse_utilized++;
169					eFuseWord[offset][i] = (rtemp8 & 0xff);
170					if (eFuse_Addr >= EFUSE_REAL_CONTENT_LEN_88E)
171						break;
172					rtemp8 = *(phymap+eFuse_Addr);
173					eFuse_Addr++;
174					efuse_utilized++;
175					eFuseWord[offset][i] |= (((u16)rtemp8 << 8) & 0xff00);
176
177					if (eFuse_Addr >= EFUSE_REAL_CONTENT_LEN_88E)
178						break;
179				}
180				wren >>= 1;
181			}
182		}
183		/*  Read next PG header */
184		rtemp8 = *(phymap+eFuse_Addr);
185
186		if (rtemp8 != 0xFF && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E)) {
187			efuse_utilized++;
188			eFuse_Addr++;
189		}
190	}
191
192	/*  */
193	/*  3. Collect 16 sections and 4 word unit into Efuse map. */
194	/*  */
195	for (i = 0; i < EFUSE_MAX_SECTION_88E; i++) {
196		for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) {
197			efuseTbl[(i*8)+(j*2)] = (eFuseWord[i][j] & 0xff);
198			efuseTbl[(i*8)+((j*2)+1)] = ((eFuseWord[i][j] >> 8) & 0xff);
199		}
200	}
201
202	/*  */
203	/*  4. Copy from Efuse map to output pointer memory!!! */
204	/*  */
205	for (i = 0; i < _size_byte; i++)
206		pbuf[i] = efuseTbl[_offset+i];
207
208	/*  */
209	/*  5. Calculate Efuse utilization. */
210	/*  */
211
212exit:
213	kfree(efuseTbl);
214
215	if (eFuseWord)
216		kfree(eFuseWord);
217}
218
219static void efuse_read_phymap_from_txpktbuf(
220	struct adapter  *adapter,
221	int bcnhead,	/* beacon head, where FW store len(2-byte) and efuse physical map. */
222	u8 *content,	/* buffer to store efuse physical map */
223	u16 *size	/* for efuse content: the max byte to read. will update to byte read */
224	)
225{
226	u16 dbg_addr = 0;
227	u32 start  = 0, passing_time = 0;
228	u8 reg_0x143 = 0;
229	u32 lo32 = 0, hi32 = 0;
230	u16 len = 0, count = 0;
231	int i = 0;
232	u16 limit = *size;
233
234	u8 *pos = content;
235
236	if (bcnhead < 0) /* if not valid */
237		bcnhead = usb_read8(adapter, REG_TDECTRL+1);
238
239	DBG_88E("%s bcnhead:%d\n", __func__, bcnhead);
240
241	usb_write8(adapter, REG_PKT_BUFF_ACCESS_CTRL, TXPKT_BUF_SELECT);
242
243	dbg_addr = bcnhead*128/8; /* 8-bytes addressing */
244
245	while (1) {
246		usb_write16(adapter, REG_PKTBUF_DBG_ADDR, dbg_addr+i);
247
248		usb_write8(adapter, REG_TXPKTBUF_DBG, 0);
249		start = jiffies;
250		while (!(reg_0x143 = usb_read8(adapter, REG_TXPKTBUF_DBG)) &&
251		       (passing_time = rtw_get_passing_time_ms(start)) < 1000) {
252			DBG_88E("%s polling reg_0x143:0x%02x, reg_0x106:0x%02x\n", __func__, reg_0x143, usb_read8(adapter, 0x106));
253			msleep(1);
254		}
255
256		lo32 = usb_read32(adapter, REG_PKTBUF_DBG_DATA_L);
257		hi32 = usb_read32(adapter, REG_PKTBUF_DBG_DATA_H);
258
259		if (i == 0) {
260			u8 lenc[2];
261			u16 lenbak, aaabak;
262			u16 aaa;
263			lenc[0] = usb_read8(adapter, REG_PKTBUF_DBG_DATA_L);
264			lenc[1] = usb_read8(adapter, REG_PKTBUF_DBG_DATA_L+1);
265
266			aaabak = le16_to_cpup((__le16 *)lenc);
267			lenbak = le16_to_cpu(*((__le16 *)lenc));
268			aaa = le16_to_cpup((__le16 *)&lo32);
269			len = le16_to_cpu(*((__le16 *)&lo32));
270
271			limit = (len-2 < limit) ? len-2 : limit;
272
273			DBG_88E("%s len:%u, lenbak:%u, aaa:%u, aaabak:%u\n", __func__, len, lenbak, aaa, aaabak);
274
275			memcpy(pos, ((u8 *)&lo32)+2, (limit >= count+2) ? 2 : limit-count);
276			count += (limit >= count+2) ? 2 : limit-count;
277			pos = content+count;
278
279		} else {
280			memcpy(pos, ((u8 *)&lo32), (limit >= count+4) ? 4 : limit-count);
281			count += (limit >= count+4) ? 4 : limit-count;
282			pos = content+count;
283		}
284
285		if (limit > count && len-2 > count) {
286			memcpy(pos, (u8 *)&hi32, (limit >= count+4) ? 4 : limit-count);
287			count += (limit >= count+4) ? 4 : limit-count;
288			pos = content+count;
289		}
290
291		if (limit <= count || len-2 <= count)
292			break;
293		i++;
294	}
295	usb_write8(adapter, REG_PKT_BUFF_ACCESS_CTRL, DISABLE_TRXPKT_BUF_ACCESS);
296	DBG_88E("%s read count:%u\n", __func__, count);
297	*size = count;
298}
299
300static s32 iol_read_efuse(struct adapter *padapter, u8 txpktbuf_bndy, u16 offset, u16 size_byte, u8 *logical_map)
301{
302	s32 status = _FAIL;
303	u8 physical_map[512];
304	u16 size = 512;
305
306	usb_write8(padapter, REG_TDECTRL+1, txpktbuf_bndy);
307	memset(physical_map, 0xFF, 512);
308	usb_write8(padapter, REG_PKT_BUFF_ACCESS_CTRL, TXPKT_BUF_SELECT);
309	status = iol_execute(padapter, CMD_READ_EFUSE_MAP);
310	if (status == _SUCCESS)
311		efuse_read_phymap_from_txpktbuf(padapter, txpktbuf_bndy, physical_map, &size);
312	efuse_phymap_to_logical(physical_map, offset, size_byte, logical_map);
313	return status;
314}
315
316void efuse_ReadEFuse(struct adapter *Adapter, u8 efuseType, u16 _offset, u16 _size_byte, u8 *pbuf)
317{
318
319	if (rtw_IOL_applied(Adapter)) {
320		rtw_hal_power_on(Adapter);
321		iol_mode_enable(Adapter, 1);
322		iol_read_efuse(Adapter, 0, _offset, _size_byte, pbuf);
323		iol_mode_enable(Adapter, 0);
324	}
325	return;
326}
327
328/* Do not support BT */
329void EFUSE_GetEfuseDefinition(struct adapter *pAdapter, u8 efuseType, u8 type, void *pOut)
330{
331	switch (type) {
332	case TYPE_EFUSE_MAX_SECTION:
333		{
334			u8 *pMax_section;
335			pMax_section = (u8 *)pOut;
336			*pMax_section = EFUSE_MAX_SECTION_88E;
337		}
338		break;
339	case TYPE_EFUSE_REAL_CONTENT_LEN:
340		{
341			u16 *pu2Tmp;
342			pu2Tmp = (u16 *)pOut;
343			*pu2Tmp = EFUSE_REAL_CONTENT_LEN_88E;
344		}
345		break;
346	case TYPE_EFUSE_CONTENT_LEN_BANK:
347		{
348			u16 *pu2Tmp;
349			pu2Tmp = (u16 *)pOut;
350			*pu2Tmp = EFUSE_REAL_CONTENT_LEN_88E;
351		}
352		break;
353	case TYPE_AVAILABLE_EFUSE_BYTES_BANK:
354		{
355			u16 *pu2Tmp;
356			pu2Tmp = (u16 *)pOut;
357			*pu2Tmp = (u16)(EFUSE_REAL_CONTENT_LEN_88E-EFUSE_OOB_PROTECT_BYTES_88E);
358		}
359		break;
360	case TYPE_AVAILABLE_EFUSE_BYTES_TOTAL:
361		{
362			u16 *pu2Tmp;
363			pu2Tmp = (u16 *)pOut;
364			*pu2Tmp = (u16)(EFUSE_REAL_CONTENT_LEN_88E-EFUSE_OOB_PROTECT_BYTES_88E);
365		}
366		break;
367	case TYPE_EFUSE_MAP_LEN:
368		{
369			u16 *pu2Tmp;
370			pu2Tmp = (u16 *)pOut;
371			*pu2Tmp = (u16)EFUSE_MAP_LEN_88E;
372		}
373		break;
374	case TYPE_EFUSE_PROTECT_BYTES_BANK:
375		{
376			u8 *pu1Tmp;
377			pu1Tmp = (u8 *)pOut;
378			*pu1Tmp = (u8)(EFUSE_OOB_PROTECT_BYTES_88E);
379		}
380		break;
381	default:
382		{
383			u8 *pu1Tmp;
384			pu1Tmp = (u8 *)pOut;
385			*pu1Tmp = 0;
386		}
387		break;
388	}
389}
390
391u8 Efuse_WordEnableDataWrite(struct adapter *pAdapter, u16 efuse_addr, u8 word_en, u8 *data)
392{
393	u16	tmpaddr = 0;
394	u16	start_addr = efuse_addr;
395	u8 badworden = 0x0F;
396	u8 tmpdata[8];
397
398	memset((void *)tmpdata, 0xff, PGPKT_DATA_SIZE);
399
400	if (!(word_en&BIT0)) {
401		tmpaddr = start_addr;
402		efuse_OneByteWrite(pAdapter, start_addr++, data[0]);
403		efuse_OneByteWrite(pAdapter, start_addr++, data[1]);
404
405		efuse_OneByteRead(pAdapter, tmpaddr, &tmpdata[0]);
406		efuse_OneByteRead(pAdapter, tmpaddr+1, &tmpdata[1]);
407		if ((data[0] != tmpdata[0]) || (data[1] != tmpdata[1]))
408			badworden &= (~BIT0);
409	}
410	if (!(word_en&BIT1)) {
411		tmpaddr = start_addr;
412		efuse_OneByteWrite(pAdapter, start_addr++, data[2]);
413		efuse_OneByteWrite(pAdapter, start_addr++, data[3]);
414
415		efuse_OneByteRead(pAdapter, tmpaddr, &tmpdata[2]);
416		efuse_OneByteRead(pAdapter, tmpaddr+1, &tmpdata[3]);
417		if ((data[2] != tmpdata[2]) || (data[3] != tmpdata[3]))
418			badworden &= (~BIT1);
419	}
420	if (!(word_en&BIT2)) {
421		tmpaddr = start_addr;
422		efuse_OneByteWrite(pAdapter, start_addr++, data[4]);
423		efuse_OneByteWrite(pAdapter, start_addr++, data[5]);
424
425		efuse_OneByteRead(pAdapter, tmpaddr, &tmpdata[4]);
426		efuse_OneByteRead(pAdapter, tmpaddr+1, &tmpdata[5]);
427		if ((data[4] != tmpdata[4]) || (data[5] != tmpdata[5]))
428			badworden &= (~BIT2);
429	}
430	if (!(word_en&BIT3)) {
431		tmpaddr = start_addr;
432		efuse_OneByteWrite(pAdapter, start_addr++, data[6]);
433		efuse_OneByteWrite(pAdapter, start_addr++, data[7]);
434
435		efuse_OneByteRead(pAdapter, tmpaddr, &tmpdata[6]);
436		efuse_OneByteRead(pAdapter, tmpaddr+1, &tmpdata[7]);
437		if ((data[6] != tmpdata[6]) || (data[7] != tmpdata[7]))
438			badworden &= (~BIT3);
439	}
440	return badworden;
441}
442
443static u16 Efuse_GetCurrentSize(struct adapter *pAdapter)
444{
445	int	bContinual = true;
446	u16	efuse_addr = 0;
447	u8 hoffset = 0, hworden = 0;
448	u8 efuse_data, word_cnts = 0;
449
450	rtw_hal_get_hwreg(pAdapter, HW_VAR_EFUSE_BYTES, (u8 *)&efuse_addr);
451
452	while (bContinual &&
453	       efuse_OneByteRead(pAdapter, efuse_addr, &efuse_data) &&
454	       AVAILABLE_EFUSE_ADDR(efuse_addr)) {
455		if (efuse_data != 0xFF) {
456			if ((efuse_data&0x1F) == 0x0F) {		/* extended header */
457				hoffset = efuse_data;
458				efuse_addr++;
459				efuse_OneByteRead(pAdapter, efuse_addr, &efuse_data);
460				if ((efuse_data & 0x0F) == 0x0F) {
461					efuse_addr++;
462					continue;
463				} else {
464					hoffset = ((hoffset & 0xE0) >> 5) | ((efuse_data & 0xF0) >> 1);
465					hworden = efuse_data & 0x0F;
466				}
467			} else {
468				hoffset = (efuse_data>>4) & 0x0F;
469				hworden =  efuse_data & 0x0F;
470			}
471			word_cnts = Efuse_CalculateWordCnts(hworden);
472			/* read next header */
473			efuse_addr = efuse_addr + (word_cnts*2)+1;
474		} else {
475			bContinual = false;
476		}
477	}
478
479	rtw_hal_set_hwreg(pAdapter, HW_VAR_EFUSE_BYTES, (u8 *)&efuse_addr);
480
481	return efuse_addr;
482}
483
484int Efuse_PgPacketRead(struct adapter *pAdapter, u8 offset, u8 *data)
485{
486	u8 ReadState = PG_STATE_HEADER;
487	int	bContinual = true;
488	int	bDataEmpty = true;
489	u8 efuse_data, word_cnts = 0;
490	u16	efuse_addr = 0;
491	u8 hoffset = 0, hworden = 0;
492	u8 tmpidx = 0;
493	u8 tmpdata[8];
494	u8 max_section = 0;
495	u8 tmp_header = 0;
496
497	EFUSE_GetEfuseDefinition(pAdapter, EFUSE_WIFI, TYPE_EFUSE_MAX_SECTION, (void *)&max_section);
498
499	if (data == NULL)
500		return false;
501	if (offset > max_section)
502		return false;
503
504	memset((void *)data, 0xff, sizeof(u8)*PGPKT_DATA_SIZE);
505	memset((void *)tmpdata, 0xff, sizeof(u8)*PGPKT_DATA_SIZE);
506
507	/*  <Roger_TODO> Efuse has been pre-programmed dummy 5Bytes at the end of Efuse by CP. */
508	/*  Skip dummy parts to prevent unexpected data read from Efuse. */
509	/*  By pass right now. 2009.02.19. */
510	while (bContinual && AVAILABLE_EFUSE_ADDR(efuse_addr)) {
511		/*   Header Read ------------- */
512		if (ReadState & PG_STATE_HEADER) {
513			if (efuse_OneByteRead(pAdapter, efuse_addr, &efuse_data) && (efuse_data != 0xFF)) {
514				if (EXT_HEADER(efuse_data)) {
515					tmp_header = efuse_data;
516					efuse_addr++;
517					efuse_OneByteRead(pAdapter, efuse_addr, &efuse_data);
518					if (!ALL_WORDS_DISABLED(efuse_data)) {
519						hoffset = ((tmp_header & 0xE0) >> 5) | ((efuse_data & 0xF0) >> 1);
520						hworden = efuse_data & 0x0F;
521					} else {
522						DBG_88E("Error, All words disabled\n");
523						efuse_addr++;
524						continue;
525					}
526				} else {
527					hoffset = (efuse_data>>4) & 0x0F;
528					hworden =  efuse_data & 0x0F;
529				}
530				word_cnts = Efuse_CalculateWordCnts(hworden);
531				bDataEmpty = true;
532
533				if (hoffset == offset) {
534					for (tmpidx = 0; tmpidx < word_cnts*2; tmpidx++) {
535						if (efuse_OneByteRead(pAdapter, efuse_addr+1+tmpidx, &efuse_data)) {
536							tmpdata[tmpidx] = efuse_data;
537							if (efuse_data != 0xff)
538								bDataEmpty = false;
539						}
540					}
541					if (bDataEmpty == false) {
542						ReadState = PG_STATE_DATA;
543					} else {/* read next header */
544						efuse_addr = efuse_addr + (word_cnts*2)+1;
545						ReadState = PG_STATE_HEADER;
546					}
547				} else {/* read next header */
548					efuse_addr = efuse_addr + (word_cnts*2)+1;
549					ReadState = PG_STATE_HEADER;
550				}
551			} else {
552				bContinual = false;
553			}
554		} else if (ReadState & PG_STATE_DATA) {
555		/*   Data section Read ------------- */
556			efuse_WordEnableDataRead(hworden, tmpdata, data);
557			efuse_addr = efuse_addr + (word_cnts*2)+1;
558			ReadState = PG_STATE_HEADER;
559		}
560
561	}
562
563	if ((data[0] == 0xff) && (data[1] == 0xff) && (data[2] == 0xff)  && (data[3] == 0xff) &&
564	    (data[4] == 0xff) && (data[5] == 0xff) && (data[6] == 0xff)  && (data[7] == 0xff))
565		return false;
566	else
567		return true;
568}
569
570static bool hal_EfuseFixHeaderProcess(struct adapter *pAdapter, u8 efuseType, struct pgpkt *pFixPkt, u16 *pAddr)
571{
572	u8 originaldata[8], badworden = 0;
573	u16	efuse_addr = *pAddr;
574	u32	PgWriteSuccess = 0;
575
576	memset((void *)originaldata, 0xff, 8);
577
578	if (Efuse_PgPacketRead(pAdapter, pFixPkt->offset, originaldata)) {
579		/* check if data exist */
580		badworden = Efuse_WordEnableDataWrite(pAdapter, efuse_addr+1, pFixPkt->word_en, originaldata);
581
582		if (badworden != 0xf) {	/*  write fail */
583			PgWriteSuccess = Efuse_PgPacketWrite(pAdapter, pFixPkt->offset, badworden, originaldata);
584
585			if (!PgWriteSuccess)
586				return false;
587			else
588				efuse_addr = Efuse_GetCurrentSize(pAdapter);
589		} else {
590			efuse_addr = efuse_addr + (pFixPkt->word_cnts*2) + 1;
591		}
592	} else {
593		efuse_addr = efuse_addr + (pFixPkt->word_cnts*2) + 1;
594	}
595	*pAddr = efuse_addr;
596	return true;
597}
598
599static bool hal_EfusePgPacketWrite2ByteHeader(struct adapter *pAdapter, u8 efuseType, u16 *pAddr, struct pgpkt *pTargetPkt)
600{
601	bool bRet = false;
602	u16	efuse_addr = *pAddr, efuse_max_available_len = 0;
603	u8 pg_header = 0, tmp_header = 0, pg_header_temp = 0;
604	u8 repeatcnt = 0;
605
606	EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_AVAILABLE_EFUSE_BYTES_BANK, (void *)&efuse_max_available_len);
607
608	while (efuse_addr < efuse_max_available_len) {
609		pg_header = ((pTargetPkt->offset & 0x07) << 5) | 0x0F;
610		efuse_OneByteWrite(pAdapter, efuse_addr, pg_header);
611		efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header);
612
613		while (tmp_header == 0xFF) {
614			if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_)
615				return false;
616
617			efuse_OneByteWrite(pAdapter, efuse_addr, pg_header);
618			efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header);
619		}
620
621		/* to write ext_header */
622		if (tmp_header == pg_header) {
623			efuse_addr++;
624			pg_header_temp = pg_header;
625			pg_header = ((pTargetPkt->offset & 0x78) << 1) | pTargetPkt->word_en;
626
627			efuse_OneByteWrite(pAdapter, efuse_addr, pg_header);
628			efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header);
629
630			while (tmp_header == 0xFF) {
631				if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_)
632					return false;
633
634				efuse_OneByteWrite(pAdapter, efuse_addr, pg_header);
635				efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header);
636			}
637
638			if ((tmp_header & 0x0F) == 0x0F) {	/* word_en PG fail */
639				if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) {
640					return false;
641				} else {
642					efuse_addr++;
643					continue;
644				}
645			} else if (pg_header != tmp_header) {	/* offset PG fail */
646				struct pgpkt	fixPkt;
647				fixPkt.offset = ((pg_header_temp & 0xE0) >> 5) | ((tmp_header & 0xF0) >> 1);
648				fixPkt.word_en = tmp_header & 0x0F;
649				fixPkt.word_cnts = Efuse_CalculateWordCnts(fixPkt.word_en);
650				if (!hal_EfuseFixHeaderProcess(pAdapter, efuseType, &fixPkt, &efuse_addr))
651					return false;
652			} else {
653				bRet = true;
654				break;
655			}
656		} else if ((tmp_header & 0x1F) == 0x0F) {		/* wrong extended header */
657			efuse_addr += 2;
658			continue;
659		}
660	}
661
662	*pAddr = efuse_addr;
663	return bRet;
664}
665
666static bool hal_EfusePgPacketWrite1ByteHeader(struct adapter *pAdapter, u8 efuseType, u16 *pAddr, struct pgpkt *pTargetPkt)
667{
668	bool bRet = false;
669	u8 pg_header = 0, tmp_header = 0;
670	u16	efuse_addr = *pAddr;
671	u8 repeatcnt = 0;
672
673	pg_header = ((pTargetPkt->offset << 4) & 0xf0) | pTargetPkt->word_en;
674
675	efuse_OneByteWrite(pAdapter, efuse_addr, pg_header);
676	efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header);
677
678	while (tmp_header == 0xFF) {
679		if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_)
680			return false;
681		efuse_OneByteWrite(pAdapter, efuse_addr, pg_header);
682		efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header);
683	}
684
685	if (pg_header == tmp_header) {
686		bRet = true;
687	} else {
688		struct pgpkt	fixPkt;
689		fixPkt.offset = (tmp_header>>4) & 0x0F;
690		fixPkt.word_en = tmp_header & 0x0F;
691		fixPkt.word_cnts = Efuse_CalculateWordCnts(fixPkt.word_en);
692		if (!hal_EfuseFixHeaderProcess(pAdapter, efuseType, &fixPkt, &efuse_addr))
693			return false;
694	}
695
696	*pAddr = efuse_addr;
697	return bRet;
698}
699
700static bool hal_EfusePgPacketWriteData(struct adapter *pAdapter, u8 efuseType, u16 *pAddr, struct pgpkt *pTargetPkt)
701{
702	u16	efuse_addr = *pAddr;
703	u8 badworden = 0;
704	u32	PgWriteSuccess = 0;
705
706	badworden = 0x0f;
707	badworden = Efuse_WordEnableDataWrite(pAdapter, efuse_addr+1, pTargetPkt->word_en, pTargetPkt->data);
708	if (badworden == 0x0F) {
709		/*  write ok */
710		return true;
711	} else {
712		/* reorganize other pg packet */
713		PgWriteSuccess = Efuse_PgPacketWrite(pAdapter, pTargetPkt->offset, badworden, pTargetPkt->data);
714		if (!PgWriteSuccess)
715			return false;
716		else
717			return true;
718	}
719}
720
721static bool
722hal_EfusePgPacketWriteHeader(
723				struct adapter *pAdapter,
724				u8 efuseType,
725				u16				*pAddr,
726				struct pgpkt *pTargetPkt)
727{
728	bool bRet = false;
729
730	if (pTargetPkt->offset >= EFUSE_MAX_SECTION_BASE)
731		bRet = hal_EfusePgPacketWrite2ByteHeader(pAdapter, efuseType, pAddr, pTargetPkt);
732	else
733		bRet = hal_EfusePgPacketWrite1ByteHeader(pAdapter, efuseType, pAddr, pTargetPkt);
734
735	return bRet;
736}
737
738static bool wordEnMatched(struct pgpkt *pTargetPkt, struct pgpkt *pCurPkt,
739			  u8 *pWden)
740{
741	u8 match_word_en = 0x0F;	/*  default all words are disabled */
742
743	/*  check if the same words are enabled both target and current PG packet */
744	if (((pTargetPkt->word_en & BIT0) == 0) &&
745	    ((pCurPkt->word_en & BIT0) == 0))
746		match_word_en &= ~BIT0;				/*  enable word 0 */
747	if (((pTargetPkt->word_en & BIT1) == 0) &&
748	    ((pCurPkt->word_en & BIT1) == 0))
749		match_word_en &= ~BIT1;				/*  enable word 1 */
750	if (((pTargetPkt->word_en & BIT2) == 0) &&
751	    ((pCurPkt->word_en & BIT2) == 0))
752		match_word_en &= ~BIT2;				/*  enable word 2 */
753	if (((pTargetPkt->word_en & BIT3) == 0) &&
754	    ((pCurPkt->word_en & BIT3) == 0))
755		match_word_en &= ~BIT3;				/*  enable word 3 */
756
757	*pWden = match_word_en;
758
759	if (match_word_en != 0xf)
760		return true;
761	else
762		return false;
763}
764
765static bool hal_EfuseCheckIfDatafollowed(struct adapter *pAdapter, u8 word_cnts, u16 startAddr)
766{
767	bool bRet = false;
768	u8 i, efuse_data;
769
770	for (i = 0; i < (word_cnts*2); i++) {
771		if (efuse_OneByteRead(pAdapter, (startAddr+i), &efuse_data) && (efuse_data != 0xFF))
772			bRet = true;
773	}
774	return bRet;
775}
776
777static bool hal_EfusePartialWriteCheck(struct adapter *pAdapter, u8 efuseType, u16 *pAddr, struct pgpkt *pTargetPkt)
778{
779	bool bRet = false;
780	u8 i, efuse_data = 0, cur_header = 0;
781	u8 matched_wden = 0, badworden = 0;
782	u16	startAddr = 0, efuse_max_available_len = 0, efuse_max = 0;
783	struct pgpkt curPkt;
784
785	EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_AVAILABLE_EFUSE_BYTES_BANK, (void *)&efuse_max_available_len);
786	EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_EFUSE_REAL_CONTENT_LEN, (void *)&efuse_max);
787
788	rtw_hal_get_hwreg(pAdapter, HW_VAR_EFUSE_BYTES, (u8 *)&startAddr);
789	startAddr %= EFUSE_REAL_CONTENT_LEN;
790
791	while (1) {
792		if (startAddr >= efuse_max_available_len) {
793			bRet = false;
794			break;
795		}
796
797		if (efuse_OneByteRead(pAdapter, startAddr, &efuse_data) && (efuse_data != 0xFF)) {
798			if (EXT_HEADER(efuse_data)) {
799				cur_header = efuse_data;
800				startAddr++;
801				efuse_OneByteRead(pAdapter, startAddr, &efuse_data);
802				if (ALL_WORDS_DISABLED(efuse_data)) {
803					bRet = false;
804					break;
805				} else {
806					curPkt.offset = ((cur_header & 0xE0) >> 5) | ((efuse_data & 0xF0) >> 1);
807					curPkt.word_en = efuse_data & 0x0F;
808				}
809			} else {
810				cur_header  =  efuse_data;
811				curPkt.offset = (cur_header>>4) & 0x0F;
812				curPkt.word_en = cur_header & 0x0F;
813			}
814
815			curPkt.word_cnts = Efuse_CalculateWordCnts(curPkt.word_en);
816			/*  if same header is found but no data followed */
817			/*  write some part of data followed by the header. */
818			if ((curPkt.offset == pTargetPkt->offset) &&
819			    (!hal_EfuseCheckIfDatafollowed(pAdapter, curPkt.word_cnts, startAddr+1)) &&
820			    wordEnMatched(pTargetPkt, &curPkt, &matched_wden)) {
821				/*  Here to write partial data */
822				badworden = Efuse_WordEnableDataWrite(pAdapter, startAddr+1, matched_wden, pTargetPkt->data);
823				if (badworden != 0x0F) {
824					u32	PgWriteSuccess = 0;
825					/*  if write fail on some words, write these bad words again */
826
827					PgWriteSuccess = Efuse_PgPacketWrite(pAdapter, pTargetPkt->offset, badworden, pTargetPkt->data);
828
829					if (!PgWriteSuccess) {
830						bRet = false;	/*  write fail, return */
831						break;
832					}
833				}
834				/*  partial write ok, update the target packet for later use */
835				for (i = 0; i < 4; i++) {
836					if ((matched_wden & (0x1<<i)) == 0)	/*  this word has been written */
837						pTargetPkt->word_en |= (0x1<<i);	/*  disable the word */
838				}
839				pTargetPkt->word_cnts = Efuse_CalculateWordCnts(pTargetPkt->word_en);
840			}
841			/*  read from next header */
842			startAddr = startAddr + (curPkt.word_cnts*2) + 1;
843		} else {
844			/*  not used header, 0xff */
845			*pAddr = startAddr;
846			bRet = true;
847			break;
848		}
849	}
850	return bRet;
851}
852
853static bool
854hal_EfusePgCheckAvailableAddr(
855		struct adapter *pAdapter,
856		u8 efuseType
857	)
858{
859	u16	efuse_max_available_len = 0;
860
861	/* Change to check TYPE_EFUSE_MAP_LEN , because 8188E raw 256, logic map over 256. */
862	EFUSE_GetEfuseDefinition(pAdapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (void *)&efuse_max_available_len);
863
864	if (Efuse_GetCurrentSize(pAdapter) >= efuse_max_available_len)
865		return false;
866	return true;
867}
868
869static void hal_EfuseConstructPGPkt(u8 offset, u8 word_en, u8 *pData, struct pgpkt *pTargetPkt)
870{
871	memset((void *)pTargetPkt->data, 0xFF, sizeof(u8)*8);
872	pTargetPkt->offset = offset;
873	pTargetPkt->word_en = word_en;
874	efuse_WordEnableDataRead(word_en, pData, pTargetPkt->data);
875	pTargetPkt->word_cnts = Efuse_CalculateWordCnts(pTargetPkt->word_en);
876}
877
878bool Efuse_PgPacketWrite(struct adapter *pAdapter, u8 offset, u8 word_en, u8 *pData)
879{
880	struct pgpkt	targetPkt;
881	u16			startAddr = 0;
882	u8 efuseType = EFUSE_WIFI;
883
884	if (!hal_EfusePgCheckAvailableAddr(pAdapter, efuseType))
885		return false;
886
887	hal_EfuseConstructPGPkt(offset, word_en, pData, &targetPkt);
888
889	if (!hal_EfusePartialWriteCheck(pAdapter, efuseType, &startAddr, &targetPkt))
890		return false;
891
892	if (!hal_EfusePgPacketWriteHeader(pAdapter, efuseType, &startAddr, &targetPkt))
893		return false;
894
895	if (!hal_EfusePgPacketWriteData(pAdapter, efuseType, &startAddr, &targetPkt))
896		return false;
897
898	return true;
899}
900
901u8 Efuse_CalculateWordCnts(u8 word_en)
902{
903	u8 word_cnts = 0;
904	if (!(word_en & BIT(0)))
905		word_cnts++; /*  0 : write enable */
906	if (!(word_en & BIT(1)))
907		word_cnts++;
908	if (!(word_en & BIT(2)))
909		word_cnts++;
910	if (!(word_en & BIT(3)))
911		word_cnts++;
912	return word_cnts;
913}
914
915u8 efuse_OneByteRead(struct adapter *pAdapter, u16 addr, u8 *data)
916{
917	u8 tmpidx = 0;
918	u8 result;
919
920	usb_write8(pAdapter, EFUSE_CTRL+1, (u8)(addr & 0xff));
921	usb_write8(pAdapter, EFUSE_CTRL+2, ((u8)((addr>>8) & 0x03)) |
922		   (usb_read8(pAdapter, EFUSE_CTRL+2) & 0xFC));
923
924	usb_write8(pAdapter, EFUSE_CTRL+3,  0x72);/* read cmd */
925
926	while (!(0x80 & usb_read8(pAdapter, EFUSE_CTRL+3)) && (tmpidx < 100))
927		tmpidx++;
928	if (tmpidx < 100) {
929		*data = usb_read8(pAdapter, EFUSE_CTRL);
930		result = true;
931	} else {
932		*data = 0xff;
933		result = false;
934	}
935	return result;
936}
937
938u8 efuse_OneByteWrite(struct adapter *pAdapter, u16 addr, u8 data)
939{
940	u8 tmpidx = 0;
941	u8 result;
942
943	usb_write8(pAdapter, EFUSE_CTRL+1, (u8)(addr&0xff));
944	usb_write8(pAdapter, EFUSE_CTRL+2,
945		   (usb_read8(pAdapter, EFUSE_CTRL+2) & 0xFC) |
946		   (u8)((addr>>8) & 0x03));
947	usb_write8(pAdapter, EFUSE_CTRL, data);/* data */
948
949	usb_write8(pAdapter, EFUSE_CTRL+3, 0xF2);/* write cmd */
950
951	while ((0x80 &  usb_read8(pAdapter, EFUSE_CTRL+3)) && (tmpidx < 100))
952		tmpidx++;
953
954	if (tmpidx < 100)
955		result = true;
956	else
957		result = false;
958
959	return result;
960}
961
962/*
963 * Overview:   Read allowed word in current efuse section data.
964 */
965void efuse_WordEnableDataRead(u8 word_en, u8 *sourdata, u8 *targetdata)
966{
967	if (!(word_en&BIT(0))) {
968		targetdata[0] = sourdata[0];
969		targetdata[1] = sourdata[1];
970	}
971	if (!(word_en&BIT(1))) {
972		targetdata[2] = sourdata[2];
973		targetdata[3] = sourdata[3];
974	}
975	if (!(word_en&BIT(2))) {
976		targetdata[4] = sourdata[4];
977		targetdata[5] = sourdata[5];
978	}
979	if (!(word_en&BIT(3))) {
980		targetdata[6] = sourdata[6];
981		targetdata[7] = sourdata[7];
982	}
983}
984
985/*
986 * Overview:	Read All Efuse content
987 */
988static void Efuse_ReadAllMap(struct adapter *pAdapter, u8 efuseType, u8 *Efuse)
989{
990	u16 mapLen = 0;
991
992	Efuse_PowerSwitch(pAdapter, false, true);
993
994	EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_EFUSE_MAP_LEN, (void *)&mapLen);
995
996	efuse_ReadEFuse(pAdapter, efuseType, 0, mapLen, Efuse);
997
998	Efuse_PowerSwitch(pAdapter, false, false);
999}
1000
1001/*
1002 * Overview:	Transfer current EFUSE content to shadow init and modify map.
1003 */
1004void EFUSE_ShadowMapUpdate(
1005	struct adapter *pAdapter,
1006	u8 efuseType)
1007{
1008	struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(pAdapter);
1009	u16 mapLen = 0;
1010
1011	EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_EFUSE_MAP_LEN, (void *)&mapLen);
1012
1013	if (pEEPROM->bautoload_fail_flag)
1014		memset(pEEPROM->efuse_eeprom_data, 0xFF, mapLen);
1015	else
1016		Efuse_ReadAllMap(pAdapter, efuseType, pEEPROM->efuse_eeprom_data);
1017}
1018