blob: 76f60ba5ee9b2bf297f0dcffadccb753810dd11b [file] [log] [blame]
Larry Finger2865d422010-08-20 10:15:30 -05001/*
2 * rtl8712_efuse.c
3 *
4 * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
5 * Linux device driver for RTL8192SU
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of version 2 of the GNU General Public License as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
19 *
20 * Modifications for inclusion into the Linux staging tree are
21 * Copyright(c) 2010 Larry Finger. All rights reserved.
22 *
23 * Contact information:
24 * WLAN FAE <wlanfae@realtek.com>.
25 * Larry Finger <Larry.Finger@lwfinger.net>
26 *
27 ******************************************************************************/
28
29#define _RTL8712_EFUSE_C_
30
31#include "osdep_service.h"
32#include "drv_types.h"
33#include "rtl8712_efuse.h"
34
35/* reserve 3 bytes for HW stop read */
36static int efuse_available_max_size = EFUSE_MAX_SIZE - 3 /*0x1FD*/;
37
38static void efuse_reg_ctrl(struct _adapter *padapter, u8 bPowerOn)
39{
40 u8 tmpu8 = 0;
41
Luis de Bethencourt1ca96882015-10-19 18:14:29 +010042 if (bPowerOn) {
Larry Finger2865d422010-08-20 10:15:30 -050043 /* -----------------e-fuse pwr & clk reg ctrl ---------------
44 * Enable LDOE25 Macro Block
45 */
46 tmpu8 = r8712_read8(padapter, EFUSE_TEST + 3);
47 tmpu8 |= 0x80;
48 r8712_write8(padapter, EFUSE_TEST + 3, tmpu8);
49 msleep(20); /* for some platform , need some delay time */
50 /* Change Efuse Clock for write action to 40MHZ */
51 r8712_write8(padapter, EFUSE_CLK_CTRL, 0x03);
52 msleep(20); /* for some platform , need some delay time */
53 } else {
54 /* -----------------e-fuse pwr & clk reg ctrl -----------------
55 * Disable LDOE25 Macro Block
56 */
57 tmpu8 = r8712_read8(padapter, EFUSE_TEST + 3);
58 tmpu8 &= 0x7F;
59 r8712_write8(padapter, EFUSE_TEST + 3, tmpu8);
60 /* Change Efuse Clock for write action to 500K */
61 r8712_write8(padapter, EFUSE_CLK_CTRL, 0x02);
62 }
63}
64
65/*
66 * Before write E-Fuse, this function must be called.
67 */
68u8 r8712_efuse_reg_init(struct _adapter *padapter)
69{
70 return true;
71}
72
73void r8712_efuse_reg_uninit(struct _adapter *padapter)
74{
75 efuse_reg_ctrl(padapter, false);
76}
77
78static u8 efuse_one_byte_read(struct _adapter *padapter, u16 addr, u8 *data)
79{
80 u8 tmpidx = 0, bResult;
81
82 /* -----------------e-fuse reg ctrl --------------------------------- */
Luis de Bethencourt4ef2de52015-10-19 18:16:01 +010083 r8712_write8(padapter, EFUSE_CTRL + 1, (u8)(addr & 0xFF)); /* address */
84 r8712_write8(padapter, EFUSE_CTRL + 2, ((u8)((addr >> 8) & 0x03)) |
85 (r8712_read8(padapter, EFUSE_CTRL + 2) & 0xFC));
86 r8712_write8(padapter, EFUSE_CTRL + 3, 0x72); /* read cmd */
Larry Finger2865d422010-08-20 10:15:30 -050087 /* wait for complete */
Luis de Bethencourt4ef2de52015-10-19 18:16:01 +010088 while (!(0x80 & r8712_read8(padapter, EFUSE_CTRL + 3)) &&
89 (tmpidx < 100))
Larry Finger2865d422010-08-20 10:15:30 -050090 tmpidx++;
91 if (tmpidx < 100) {
92 *data = r8712_read8(padapter, EFUSE_CTRL);
93 bResult = true;
94 } else {
95 *data = 0xff;
96 bResult = false;
97 }
98 return bResult;
99}
100
101static u8 efuse_one_byte_write(struct _adapter *padapter, u16 addr, u8 data)
102{
103 u8 tmpidx = 0, bResult;
104
105 /* -----------------e-fuse reg ctrl -------------------------------- */
Luis de Bethencourt4ef2de52015-10-19 18:16:01 +0100106 r8712_write8(padapter, EFUSE_CTRL + 1, (u8)(addr & 0xFF)); /* address */
107 r8712_write8(padapter, EFUSE_CTRL + 2, ((u8)((addr >> 8) & 0x03)) |
108 (r8712_read8(padapter, EFUSE_CTRL + 2) & 0xFC));
Larry Finger2865d422010-08-20 10:15:30 -0500109 r8712_write8(padapter, EFUSE_CTRL, data); /* data */
Luis de Bethencourt4ef2de52015-10-19 18:16:01 +0100110 r8712_write8(padapter, EFUSE_CTRL + 3, 0xF2); /* write cmd */
Larry Finger2865d422010-08-20 10:15:30 -0500111 /* wait for complete */
Luis de Bethencourt4ef2de52015-10-19 18:16:01 +0100112 while ((0x80 & r8712_read8(padapter, EFUSE_CTRL + 3)) &&
113 (tmpidx < 100))
Larry Finger2865d422010-08-20 10:15:30 -0500114 tmpidx++;
115 if (tmpidx < 100)
116 bResult = true;
117 else
118 bResult = false;
119 return bResult;
120}
121
122static u8 efuse_one_byte_rw(struct _adapter *padapter, u8 bRead, u16 addr,
123 u8 *data)
124{
125 u8 tmpidx = 0, tmpv8 = 0, bResult;
126
127 /* -----------------e-fuse reg ctrl --------------------------------- */
Luis de Bethencourt4ef2de52015-10-19 18:16:01 +0100128 r8712_write8(padapter, EFUSE_CTRL + 1, (u8)(addr & 0xFF)); /* address */
Larry Finger2865d422010-08-20 10:15:30 -0500129 tmpv8 = ((u8)((addr >> 8) & 0x03)) |
130 (r8712_read8(padapter, EFUSE_CTRL + 2) & 0xFC);
Luis de Bethencourt4ef2de52015-10-19 18:16:01 +0100131 r8712_write8(padapter, EFUSE_CTRL + 2, tmpv8);
Luis de Bethencourt1ca96882015-10-19 18:14:29 +0100132 if (bRead) {
Luis de Bethencourt4ef2de52015-10-19 18:16:01 +0100133 r8712_write8(padapter, EFUSE_CTRL + 3, 0x72); /* read cmd */
134 while (!(0x80 & r8712_read8(padapter, EFUSE_CTRL + 3)) &&
Larry Finger2865d422010-08-20 10:15:30 -0500135 (tmpidx < 100))
136 tmpidx++;
137 if (tmpidx < 100) {
138 *data = r8712_read8(padapter, EFUSE_CTRL);
139 bResult = true;
140 } else {
141 *data = 0;
142 bResult = false;
143 }
144 } else {
145 r8712_write8(padapter, EFUSE_CTRL, *data); /* data */
Luis de Bethencourt4ef2de52015-10-19 18:16:01 +0100146 r8712_write8(padapter, EFUSE_CTRL + 3, 0xF2); /* write cmd */
147 while ((0x80 & r8712_read8(padapter, EFUSE_CTRL + 3)) &&
Larry Finger2865d422010-08-20 10:15:30 -0500148 (tmpidx < 100))
149 tmpidx++;
150 if (tmpidx < 100)
151 bResult = true;
152 else
153 bResult = false;
154 }
155 return bResult;
156}
157
158static u8 efuse_is_empty(struct _adapter *padapter, u8 *empty)
159{
160 u8 value, ret = true;
161
162 /* read one byte to check if E-Fuse is empty */
Luis de Bethencourt1ca96882015-10-19 18:14:29 +0100163 if (efuse_one_byte_rw(padapter, true, 0, &value)) {
Rakhi Sharmaf7099ad72016-02-13 10:54:20 +0530164 if (value == 0xFF)
Larry Finger2865d422010-08-20 10:15:30 -0500165 *empty = true;
166 else
167 *empty = false;
Luis de Bethencourt168a2c12015-10-19 18:15:29 +0100168 } else {
Larry Finger2865d422010-08-20 10:15:30 -0500169 ret = false;
Luis de Bethencourt168a2c12015-10-19 18:15:29 +0100170 }
Larry Finger2865d422010-08-20 10:15:30 -0500171 return ret;
172}
173
174void r8712_efuse_change_max_size(struct _adapter *padapter)
175{
176 u16 pre_pg_data_saddr = 0x1FB;
177 u16 i;
178 u16 pre_pg_data_size = 5;
179 u8 pre_pg_data[5];
180
181 for (i = 0; i < pre_pg_data_size; i++)
182 efuse_one_byte_read(padapter, pre_pg_data_saddr + i,
183 &pre_pg_data[i]);
184 if ((pre_pg_data[0] == 0x03) && (pre_pg_data[1] == 0x00) &&
185 (pre_pg_data[2] == 0x00) && (pre_pg_data[3] == 0x00) &&
186 (pre_pg_data[4] == 0x0C))
187 efuse_available_max_size -= pre_pg_data_size;
188}
189
190int r8712_efuse_get_max_size(struct _adapter *padapter)
191{
192 return efuse_available_max_size;
193}
194
195static u8 calculate_word_cnts(const u8 word_en)
196{
197 u8 word_cnts = 0;
198 u8 word_idx;
199
200 for (word_idx = 0; word_idx < PGPKG_MAX_WORDS; word_idx++)
201 if (!(word_en & BIT(word_idx)))
202 word_cnts++; /* 0 : write enable */
203 return word_cnts;
204}
205
206static void pgpacket_copy_data(const u8 word_en, const u8 *sourdata,
207 u8 *targetdata)
208{
209 u8 tmpindex = 0;
210 u8 word_idx, byte_idx;
211
212 for (word_idx = 0; word_idx < PGPKG_MAX_WORDS; word_idx++) {
Luis de Bethencourt4ef2de52015-10-19 18:16:01 +0100213 if (!(word_en & BIT(word_idx))) {
Larry Finger2865d422010-08-20 10:15:30 -0500214 byte_idx = word_idx * 2;
215 targetdata[byte_idx] = sourdata[tmpindex++];
216 targetdata[byte_idx + 1] = sourdata[tmpindex++];
217 }
218 }
219}
220
221u16 r8712_efuse_get_current_size(struct _adapter *padapter)
222{
223 int bContinual = true;
224 u16 efuse_addr = 0;
Sudip Mukherjeee29d3eb2014-10-27 17:42:25 +0530225 u8 hworden = 0;
Larry Finger2865d422010-08-20 10:15:30 -0500226 u8 efuse_data, word_cnts = 0;
227
228 while (bContinual && efuse_one_byte_read(padapter, efuse_addr,
229 &efuse_data) && (efuse_addr < efuse_available_max_size)) {
230 if (efuse_data != 0xFF) {
Larry Finger2865d422010-08-20 10:15:30 -0500231 hworden = efuse_data & 0x0F;
232 word_cnts = calculate_word_cnts(hworden);
233 /* read next header */
234 efuse_addr = efuse_addr + (word_cnts * 2) + 1;
Luis de Bethencourt168a2c12015-10-19 18:15:29 +0100235 } else {
Thomas Cort77e73e82013-10-01 11:26:55 -0400236 bContinual = false;
Luis de Bethencourt168a2c12015-10-19 18:15:29 +0100237 }
Larry Finger2865d422010-08-20 10:15:30 -0500238 }
239 return efuse_addr;
240}
241
242u8 r8712_efuse_pg_packet_read(struct _adapter *padapter, u8 offset, u8 *data)
243{
244 u8 hoffset = 0, hworden = 0, word_cnts = 0;
245 u16 efuse_addr = 0;
246 u8 efuse_data;
247 u8 tmpidx = 0;
248 u8 tmpdata[PGPKT_DATA_SIZE];
249 u8 ret = true;
250
251 if (data == NULL)
252 return false;
253 if (offset > 0x0f)
254 return false;
Luis de Bethencourt4ef2de52015-10-19 18:16:01 +0100255 memset(data, 0xFF, sizeof(u8) * PGPKT_DATA_SIZE);
Larry Finger2865d422010-08-20 10:15:30 -0500256 while (efuse_addr < efuse_available_max_size) {
Luis de Bethencourt1ca96882015-10-19 18:14:29 +0100257 if (efuse_one_byte_read(padapter, efuse_addr, &efuse_data)) {
Larry Finger2865d422010-08-20 10:15:30 -0500258 if (efuse_data == 0xFF)
259 break;
260 hoffset = (efuse_data >> 4) & 0x0F;
261 hworden = efuse_data & 0x0F;
262 word_cnts = calculate_word_cnts(hworden);
263 if (hoffset == offset) {
264 memset(tmpdata, 0xFF, PGPKT_DATA_SIZE);
265 for (tmpidx = 0; tmpidx < word_cnts * 2;
266 tmpidx++) {
267 if (efuse_one_byte_read(padapter,
Luis de Bethencourt4ef2de52015-10-19 18:16:01 +0100268 efuse_addr + 1 + tmpidx,
269 &efuse_data)) {
Larry Finger2865d422010-08-20 10:15:30 -0500270 tmpdata[tmpidx] = efuse_data;
Luis de Bethencourt168a2c12015-10-19 18:15:29 +0100271 } else {
Larry Finger2865d422010-08-20 10:15:30 -0500272 ret = false;
Luis de Bethencourt168a2c12015-10-19 18:15:29 +0100273 }
Larry Finger2865d422010-08-20 10:15:30 -0500274 }
275 pgpacket_copy_data(hworden, tmpdata, data);
276 }
Luis de Bethencourt4ef2de52015-10-19 18:16:01 +0100277 efuse_addr += 1 + (word_cnts * 2);
Larry Finger2865d422010-08-20 10:15:30 -0500278 } else {
279 ret = false;
280 break;
281 }
282 }
283 return ret;
284}
285
286static u8 fix_header(struct _adapter *padapter, u8 header, u16 header_addr)
287{
288 struct PGPKT_STRUCT pkt;
289 u8 offset, word_en, value;
290 u16 addr;
291 int i;
292 u8 ret = true;
293
294 pkt.offset = GET_EFUSE_OFFSET(header);
295 pkt.word_en = GET_EFUSE_WORD_EN(header);
296 addr = header_addr + 1 + calculate_word_cnts(pkt.word_en) * 2;
297 if (addr > efuse_available_max_size)
298 return false;
299 /* retrieve original data */
300 addr = 0;
301 while (addr < header_addr) {
Luis de Bethencourt1ca96882015-10-19 18:14:29 +0100302 if (!efuse_one_byte_read(padapter, addr++, &value)) {
Larry Finger2865d422010-08-20 10:15:30 -0500303 ret = false;
304 break;
305 }
306 offset = GET_EFUSE_OFFSET(value);
307 word_en = GET_EFUSE_WORD_EN(value);
308 if (pkt.offset != offset) {
Luis de Bethencourt4ef2de52015-10-19 18:16:01 +0100309 addr += calculate_word_cnts(word_en) * 2;
Larry Finger2865d422010-08-20 10:15:30 -0500310 continue;
311 }
312 for (i = 0; i < PGPKG_MAX_WORDS; i++) {
Ali Bahar0aeb6232011-09-04 03:14:17 +0800313 if (BIT(i) & word_en) {
314 if (BIT(i) & pkt.word_en) {
315 if (efuse_one_byte_read(
316 padapter, addr,
Luis de Bethencourt1ca96882015-10-19 18:14:29 +0100317 &value))
Luis de Bethencourt4ef2de52015-10-19 18:16:01 +0100318 pkt.data[i * 2] = value;
Ali Bahar0aeb6232011-09-04 03:14:17 +0800319 else
320 return false;
321 if (efuse_one_byte_read(
322 padapter,
323 addr + 1,
Luis de Bethencourt1ca96882015-10-19 18:14:29 +0100324 &value))
Luis de Bethencourt4ef2de52015-10-19 18:16:01 +0100325 pkt.data[i * 2 + 1] =
Ali Bahar0aeb6232011-09-04 03:14:17 +0800326 value;
327 else
328 return false;
329 }
330 addr += 2;
Larry Finger2865d422010-08-20 10:15:30 -0500331 }
Larry Finger2865d422010-08-20 10:15:30 -0500332 }
333 }
334 if (addr != header_addr)
335 return false;
336 addr++;
337 /* fill original data */
338 for (i = 0; i < PGPKG_MAX_WORDS; i++) {
Ali Bahar0aeb6232011-09-04 03:14:17 +0800339 if (BIT(i) & pkt.word_en) {
Luis de Bethencourt4ef2de52015-10-19 18:16:01 +0100340 efuse_one_byte_write(padapter, addr, pkt.data[i * 2]);
341 efuse_one_byte_write(padapter, addr + 1,
342 pkt.data[i * 2 + 1]);
Ali Bahar0aeb6232011-09-04 03:14:17 +0800343 /* additional check */
Luis de Bethencourt168a2c12015-10-19 18:15:29 +0100344 if (!efuse_one_byte_read(padapter, addr, &value)) {
Ali Bahar0aeb6232011-09-04 03:14:17 +0800345 ret = false;
Luis de Bethencourt4ef2de52015-10-19 18:16:01 +0100346 } else if (pkt.data[i * 2] != value) {
Ali Bahar0aeb6232011-09-04 03:14:17 +0800347 ret = false;
Rakhi Sharmaf7099ad72016-02-13 10:54:20 +0530348 if (value == 0xFF) /* write again */
Ali Bahar0aeb6232011-09-04 03:14:17 +0800349 efuse_one_byte_write(padapter, addr,
350 pkt.data[i * 2]);
351 }
Luis de Bethencourt4ef2de52015-10-19 18:16:01 +0100352 if (!efuse_one_byte_read(padapter, addr + 1, &value)) {
Ali Bahar0aeb6232011-09-04 03:14:17 +0800353 ret = false;
Luis de Bethencourt4ef2de52015-10-19 18:16:01 +0100354 } else if (pkt.data[i * 2 + 1] != value) {
Ali Bahar0aeb6232011-09-04 03:14:17 +0800355 ret = false;
Rakhi Sharmaf7099ad72016-02-13 10:54:20 +0530356 if (value == 0xFF) /* write again */
Luis de Bethencourt4ef2de52015-10-19 18:16:01 +0100357 efuse_one_byte_write(padapter, addr + 1,
358 pkt.data[i * 2 +
359 1]);
Ali Bahar0aeb6232011-09-04 03:14:17 +0800360 }
Larry Finger2865d422010-08-20 10:15:30 -0500361 }
362 addr += 2;
363 }
364 return ret;
365}
366
367u8 r8712_efuse_pg_packet_write(struct _adapter *padapter, const u8 offset,
368 const u8 word_en, const u8 *data)
369{
370 u8 pg_header = 0;
371 u16 efuse_addr = 0, curr_size = 0;
372 u8 efuse_data, target_word_cnts = 0;
373 static int repeat_times;
374 int sub_repeat;
375 u8 bResult = true;
376
377 /* check if E-Fuse Clock Enable and E-Fuse Clock is 40M */
378 efuse_data = r8712_read8(padapter, EFUSE_CLK_CTRL);
379 if (efuse_data != 0x03)
380 return false;
381 pg_header = MAKE_EFUSE_HEADER(offset, word_en);
382 target_word_cnts = calculate_word_cnts(word_en);
383 repeat_times = 0;
384 efuse_addr = 0;
385 while (efuse_addr < efuse_available_max_size) {
386 curr_size = r8712_efuse_get_current_size(padapter);
387 if ((curr_size + 1 + target_word_cnts * 2) >
388 efuse_available_max_size)
389 return false; /*target_word_cnts + pg header(1 byte)*/
390 efuse_addr = curr_size; /* current size is also the last addr*/
391 efuse_one_byte_write(padapter, efuse_addr, pg_header); /*hdr*/
392 sub_repeat = 0;
393 /* check if what we read is what we write */
Luis de Bethencourt1ca96882015-10-19 18:14:29 +0100394 while (!efuse_one_byte_read(padapter, efuse_addr,
395 &efuse_data)) {
Larry Finger2865d422010-08-20 10:15:30 -0500396 if (++sub_repeat > _REPEAT_THRESHOLD_) {
397 bResult = false; /* continue to blind write */
398 break; /* continue to blind write */
399 }
400 }
401 if ((sub_repeat > _REPEAT_THRESHOLD_) ||
402 (pg_header == efuse_data)) {
403 /* write header ok OR can't check header(creep) */
404 u8 i;
405
406 /* go to next address */
407 efuse_addr++;
Luis de Bethencourt4ef2de52015-10-19 18:16:01 +0100408 for (i = 0; i < target_word_cnts * 2; i++) {
Larry Finger2865d422010-08-20 10:15:30 -0500409 efuse_one_byte_write(padapter,
410 efuse_addr + i,
411 *(data + i));
Luis de Bethencourt1ca96882015-10-19 18:14:29 +0100412 if (!efuse_one_byte_read(padapter,
413 efuse_addr + i,
414 &efuse_data))
Larry Finger2865d422010-08-20 10:15:30 -0500415 bResult = false;
Luis de Bethencourt4ef2de52015-10-19 18:16:01 +0100416 else if (*(data + i) != efuse_data) /* fail */
Larry Finger2865d422010-08-20 10:15:30 -0500417 bResult = false;
418 }
419 break;
Larry Finger2865d422010-08-20 10:15:30 -0500420 }
Serguey Parkhomovskya15522c2014-10-07 20:42:45 -0700421 /* write header fail */
422 bResult = false;
Rakhi Sharmaf7099ad72016-02-13 10:54:20 +0530423 if (efuse_data == 0xFF)
Serguey Parkhomovskya15522c2014-10-07 20:42:45 -0700424 return bResult; /* nothing damaged. */
425 /* call rescue procedure */
426 if (!fix_header(padapter, efuse_data, efuse_addr))
427 return false; /* rescue fail */
428
429 if (++repeat_times > _REPEAT_THRESHOLD_) /* fail */
430 break;
431 /* otherwise, take another risk... */
Larry Finger2865d422010-08-20 10:15:30 -0500432 }
433 return bResult;
434}
435
436u8 r8712_efuse_access(struct _adapter *padapter, u8 bRead, u16 start_addr,
437 u16 cnts, u8 *data)
438{
439 int i;
Joe Perches859171c2010-11-14 19:04:48 -0800440 u8 res = true;
Larry Finger2865d422010-08-20 10:15:30 -0500441
442 if (start_addr > EFUSE_MAX_SIZE)
443 return false;
Luis de Bethencourt1ca96882015-10-19 18:14:29 +0100444 if (!bRead && ((start_addr + cnts) >
Larry Finger2865d422010-08-20 10:15:30 -0500445 efuse_available_max_size))
446 return false;
Luis de Bethencourt1ca96882015-10-19 18:14:29 +0100447 if (!bRead && !r8712_efuse_reg_init(padapter))
Larry Finger2865d422010-08-20 10:15:30 -0500448 return false;
449 /* -----------------e-fuse one byte read / write ---------------------*/
450 for (i = 0; i < cnts; i++) {
451 if ((start_addr + i) > EFUSE_MAX_SIZE) {
452 res = false;
453 break;
454 }
455 res = efuse_one_byte_rw(padapter, bRead, start_addr + i,
456 data + i);
Luis de Bethencourt1ca96882015-10-19 18:14:29 +0100457 if (!bRead && !res)
Larry Finger2865d422010-08-20 10:15:30 -0500458 break;
459 }
Luis de Bethencourt1ca96882015-10-19 18:14:29 +0100460 if (!bRead)
Larry Finger2865d422010-08-20 10:15:30 -0500461 r8712_efuse_reg_uninit(padapter);
462 return res;
463}
464
465u8 r8712_efuse_map_read(struct _adapter *padapter, u16 addr, u16 cnts, u8 *data)
466{
467 u8 offset, ret = true;
468 u8 pktdata[PGPKT_DATA_SIZE];
469 int i, idx;
470
471 if ((addr + cnts) > EFUSE_MAP_MAX_SIZE)
472 return false;
Luis de Bethencourt1ca96882015-10-19 18:14:29 +0100473 if (efuse_is_empty(padapter, &offset) && offset) {
Larry Finger2865d422010-08-20 10:15:30 -0500474 for (i = 0; i < cnts; i++)
475 data[i] = 0xFF;
476 return ret;
477 }
478 offset = (addr >> 3) & 0xF;
479 ret = r8712_efuse_pg_packet_read(padapter, offset, pktdata);
480 i = addr & 0x7; /* pktdata index */
481 idx = 0; /* data index */
482
483 do {
484 for (; i < PGPKT_DATA_SIZE; i++) {
485 data[idx++] = pktdata[i];
486 if (idx == cnts)
487 return ret;
488 }
489 offset++;
490 if (!r8712_efuse_pg_packet_read(padapter, offset, pktdata))
491 ret = false;
492 i = 0;
493 } while (1);
494 return ret;
495}
496
497u8 r8712_efuse_map_write(struct _adapter *padapter, u16 addr, u16 cnts,
498 u8 *data)
499{
500 u8 offset, word_en, empty;
501 u8 pktdata[PGPKT_DATA_SIZE], newdata[PGPKT_DATA_SIZE];
502 int i, j, idx;
503
504 if ((addr + cnts) > EFUSE_MAP_MAX_SIZE)
505 return false;
506 /* check if E-Fuse Clock Enable and E-Fuse Clock is 40M */
507 empty = r8712_read8(padapter, EFUSE_CLK_CTRL);
508 if (empty != 0x03)
509 return false;
Luis de Bethencourt1ca96882015-10-19 18:14:29 +0100510 if (efuse_is_empty(padapter, &empty)) {
511 if (empty)
Larry Finger2865d422010-08-20 10:15:30 -0500512 memset(pktdata, 0xFF, PGPKT_DATA_SIZE);
Luis de Bethencourt168a2c12015-10-19 18:15:29 +0100513 } else {
Larry Finger2865d422010-08-20 10:15:30 -0500514 return false;
Luis de Bethencourt168a2c12015-10-19 18:15:29 +0100515 }
Larry Finger2865d422010-08-20 10:15:30 -0500516 offset = (addr >> 3) & 0xF;
Luis de Bethencourt1ca96882015-10-19 18:14:29 +0100517 if (!empty)
Larry Finger2865d422010-08-20 10:15:30 -0500518 if (!r8712_efuse_pg_packet_read(padapter, offset, pktdata))
519 return false;
520 word_en = 0xF;
521 memset(newdata, 0xFF, PGPKT_DATA_SIZE);
522 i = addr & 0x7; /* pktdata index */
523 j = 0; /* newdata index */
524 idx = 0; /* data index */
525
526 if (i & 0x1) {
527 /* odd start */
528 if (data[idx] != pktdata[i]) {
529 word_en &= ~BIT(i >> 1);
530 newdata[j++] = pktdata[i - 1];
531 newdata[j++] = data[idx];
532 }
533 i++;
534 idx++;
535 }
536 do {
537 for (; i < PGPKT_DATA_SIZE; i += 2) {
538 if ((cnts - idx) == 1) {
539 if (data[idx] != pktdata[i]) {
540 word_en &= ~BIT(i >> 1);
541 newdata[j++] = data[idx];
542 newdata[j++] = pktdata[1 + 1];
543 }
544 idx++;
545 break;
Larry Finger2865d422010-08-20 10:15:30 -0500546 }
Serguey Parkhomovskya15522c2014-10-07 20:42:45 -0700547
Luis de Bethencourt4ef2de52015-10-19 18:16:01 +0100548 if ((data[idx] != pktdata[i]) || (data[idx + 1] !=
549 pktdata[i + 1])) {
Serguey Parkhomovskya15522c2014-10-07 20:42:45 -0700550 word_en &= ~BIT(i >> 1);
551 newdata[j++] = data[idx];
552 newdata[j++] = data[idx + 1];
553 }
554 idx += 2;
555
Larry Finger2865d422010-08-20 10:15:30 -0500556 if (idx == cnts)
557 break;
558 }
559
560 if (word_en != 0xF)
Luis de Bethencourt1ca96882015-10-19 18:14:29 +0100561 if (!r8712_efuse_pg_packet_write(padapter, offset,
562 word_en, newdata))
Larry Finger2865d422010-08-20 10:15:30 -0500563 return false;
564 if (idx == cnts)
565 break;
566 offset++;
Luis de Bethencourt1ca96882015-10-19 18:14:29 +0100567 if (!empty)
Larry Finger2865d422010-08-20 10:15:30 -0500568 if (!r8712_efuse_pg_packet_read(padapter, offset,
569 pktdata))
570 return false;
571 i = 0;
572 j = 0;
573 word_en = 0xF;
574 memset(newdata, 0xFF, PGPKT_DATA_SIZE);
575 } while (1);
576
577 return true;
578}