Merge tag 'sound-5.13-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai...
[linux-2.6-microblaze.git] / drivers / staging / rtl8712 / rtl8712_efuse.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * rtl8712_efuse.c
4  *
5  * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
6  * Linux device driver for RTL8192SU
7  *
8  * Modifications for inclusion into the Linux staging tree are
9  * Copyright(c) 2010 Larry Finger. All rights reserved.
10  *
11  * Contact information:
12  * WLAN FAE <wlanfae@realtek.com>.
13  * Larry Finger <Larry.Finger@lwfinger.net>
14  *
15  ******************************************************************************/
16
17 #define _RTL8712_EFUSE_C_
18
19 #include "osdep_service.h"
20 #include "drv_types.h"
21 #include "rtl8712_efuse.h"
22
23 /* reserve 3 bytes for HW stop read */
24 static int efuse_available_max_size = EFUSE_MAX_SIZE - 3 /*0x1FD*/;
25
26 static void efuse_reg_ctrl(struct _adapter *adapter, u8 bPowerOn)
27 {
28         u8 tmpu8 = 0;
29
30         if (bPowerOn) {
31                 /* -----------------e-fuse pwr & clk reg ctrl ---------------
32                  * Enable LDOE25 Macro Block
33                  */
34                 tmpu8 = r8712_read8(adapter, EFUSE_TEST + 3);
35                 tmpu8 |= 0x80;
36                 r8712_write8(adapter, EFUSE_TEST + 3, tmpu8);
37                 msleep(20); /* for some platform , need some delay time */
38                 /* Change Efuse Clock for write action to 40MHZ */
39                 r8712_write8(adapter, EFUSE_CLK_CTRL, 0x03);
40                 msleep(20); /* for some platform , need some delay time */
41         } else {
42                 /* -----------------e-fuse pwr & clk reg ctrl -----------------
43                  * Disable LDOE25 Macro Block
44                  */
45                 tmpu8 = r8712_read8(adapter, EFUSE_TEST + 3);
46                 tmpu8 &= 0x7F;
47                 r8712_write8(adapter, EFUSE_TEST + 3, tmpu8);
48                 /* Change Efuse Clock for write action to 500K */
49                 r8712_write8(adapter, EFUSE_CLK_CTRL, 0x02);
50         }
51 }
52
53 /*
54  * Before write E-Fuse, this function must be called.
55  */
56 u8 r8712_efuse_reg_init(struct _adapter *adapter)
57 {
58         return true;
59 }
60
61 void r8712_efuse_reg_uninit(struct _adapter *adapter)
62 {
63         efuse_reg_ctrl(adapter, false);
64 }
65
66 static u8 efuse_one_byte_read(struct _adapter *adapter, u16 addr, u8 *data)
67 {
68         u8 tmpidx = 0, bResult;
69
70         /* -----------------e-fuse reg ctrl --------------------------------- */
71         r8712_write8(adapter, EFUSE_CTRL + 1, (u8)(addr & 0xFF)); /* address */
72         r8712_write8(adapter, EFUSE_CTRL + 2, ((u8)((addr >> 8) & 0x03)) |
73                (r8712_read8(adapter, EFUSE_CTRL + 2) & 0xFC));
74         r8712_write8(adapter, EFUSE_CTRL + 3, 0x72); /* read cmd */
75         /* wait for complete */
76         while (!(0x80 & r8712_read8(adapter, EFUSE_CTRL + 3)) &&
77                (tmpidx < 100))
78                 tmpidx++;
79         if (tmpidx < 100) {
80                 *data = r8712_read8(adapter, EFUSE_CTRL);
81                 bResult = true;
82         } else {
83                 *data = 0xff;
84                 bResult = false;
85         }
86         return bResult;
87 }
88
89 static u8 efuse_one_byte_write(struct _adapter *adapter, u16 addr, u8 data)
90 {
91         u8 tmpidx = 0, bResult;
92
93         /* -----------------e-fuse reg ctrl -------------------------------- */
94         r8712_write8(adapter, EFUSE_CTRL + 1, (u8)(addr & 0xFF)); /* address */
95         r8712_write8(adapter, EFUSE_CTRL + 2, ((u8)((addr >> 8) & 0x03)) |
96                (r8712_read8(adapter, EFUSE_CTRL + 2) & 0xFC));
97         r8712_write8(adapter, EFUSE_CTRL, data); /* data */
98         r8712_write8(adapter, EFUSE_CTRL + 3, 0xF2); /* write cmd */
99         /* wait for complete */
100         while ((0x80 &  r8712_read8(adapter, EFUSE_CTRL + 3)) &&
101                (tmpidx < 100))
102                 tmpidx++;
103         if (tmpidx < 100)
104                 bResult = true;
105         else
106                 bResult = false;
107         return bResult;
108 }
109
110 static u8 efuse_one_byte_rw(struct _adapter *adapter, u8 bRead, u16 addr,
111                             u8 *data)
112 {
113         u8 tmpidx = 0, tmpv8 = 0, bResult;
114
115         /* -----------------e-fuse reg ctrl --------------------------------- */
116         r8712_write8(adapter, EFUSE_CTRL + 1, (u8)(addr & 0xFF)); /* address */
117         tmpv8 = ((u8)((addr >> 8) & 0x03)) |
118                  (r8712_read8(adapter, EFUSE_CTRL + 2) & 0xFC);
119         r8712_write8(adapter, EFUSE_CTRL + 2, tmpv8);
120         if (bRead) {
121                 r8712_write8(adapter, EFUSE_CTRL + 3,  0x72); /* read cmd */
122                 while (!(0x80 & r8712_read8(adapter, EFUSE_CTRL + 3)) &&
123                        (tmpidx < 100))
124                         tmpidx++;
125                 if (tmpidx < 100) {
126                         *data = r8712_read8(adapter, EFUSE_CTRL);
127                         bResult = true;
128                 } else {
129                         *data = 0;
130                         bResult = false;
131                 }
132         } else {
133                 r8712_write8(adapter, EFUSE_CTRL, *data); /* data */
134                 r8712_write8(adapter, EFUSE_CTRL + 3, 0xF2); /* write cmd */
135                 while ((0x80 & r8712_read8(adapter, EFUSE_CTRL + 3)) &&
136                        (tmpidx < 100))
137                         tmpidx++;
138                 if (tmpidx < 100)
139                         bResult = true;
140                 else
141                         bResult = false;
142         }
143         return bResult;
144 }
145
146 static u8 efuse_is_empty(struct _adapter *adapter, u8 *empty)
147 {
148         u8 value, ret = true;
149
150         /* read one byte to check if E-Fuse is empty */
151         if (efuse_one_byte_rw(adapter, true, 0, &value)) {
152                 if (value == 0xFF)
153                         *empty = true;
154                 else
155                         *empty = false;
156         } else {
157                 ret = false;
158         }
159         return ret;
160 }
161
162 void r8712_efuse_change_max_size(struct _adapter *adapter)
163 {
164         u16 pre_pg_data_saddr = 0x1FB;
165         u16 i;
166         u16 pre_pg_data_size = 5;
167         u8 pre_pg_data[5];
168
169         for (i = 0; i < pre_pg_data_size; i++)
170                 efuse_one_byte_read(adapter, pre_pg_data_saddr + i,
171                                     &pre_pg_data[i]);
172         if ((pre_pg_data[0] == 0x03) && (pre_pg_data[1] == 0x00) &&
173             (pre_pg_data[2] == 0x00) && (pre_pg_data[3] == 0x00) &&
174             (pre_pg_data[4] == 0x0C))
175                 efuse_available_max_size -= pre_pg_data_size;
176 }
177
178 int r8712_efuse_get_max_size(struct _adapter *adapter)
179 {
180         return  efuse_available_max_size;
181 }
182
183 static u8 calculate_word_cnts(const u8 word_en)
184 {
185         u8 word_cnts = 0;
186         u8 word_idx;
187
188         for (word_idx = 0; word_idx < PGPKG_MAX_WORDS; word_idx++)
189                 if (!(word_en & BIT(word_idx)))
190                         word_cnts++; /* 0 : write enable */
191         return word_cnts;
192 }
193
194 static void pgpacket_copy_data(const u8 word_en, const u8 *sourdata,
195                                u8 *targetdata)
196 {
197         u8 tmpindex = 0;
198         u8 word_idx, byte_idx;
199
200         for (word_idx = 0; word_idx < PGPKG_MAX_WORDS; word_idx++) {
201                 if (!(word_en & BIT(word_idx))) {
202                         byte_idx = word_idx * 2;
203                         targetdata[byte_idx] = sourdata[tmpindex++];
204                         targetdata[byte_idx + 1] = sourdata[tmpindex++];
205                 }
206         }
207 }
208
209 u16 r8712_efuse_get_current_size(struct _adapter *adapter)
210 {
211         int bContinual = true;
212         u16 efuse_addr = 0;
213         u8 hworden = 0;
214         u8 efuse_data, word_cnts = 0;
215
216         while (bContinual && efuse_one_byte_read(adapter, efuse_addr,
217                &efuse_data) && (efuse_addr < efuse_available_max_size)) {
218                 if (efuse_data != 0xFF) {
219                         hworden =  efuse_data & 0x0F;
220                         word_cnts = calculate_word_cnts(hworden);
221                         /* read next header */
222                         efuse_addr = efuse_addr + (word_cnts * 2) + 1;
223                 } else {
224                         bContinual = false;
225                 }
226         }
227         return efuse_addr;
228 }
229
230 u8 r8712_efuse_pg_packet_read(struct _adapter *adapter, u8 offset, u8 *data)
231 {
232         u8 hoffset = 0, hworden = 0, word_cnts = 0;
233         u16 efuse_addr = 0;
234         u8 efuse_data;
235         u8 tmpidx = 0;
236         u8 tmpdata[PGPKT_DATA_SIZE];
237         u8 ret = true;
238
239         if (!data)
240                 return false;
241         if (offset > 0x0f)
242                 return false;
243         memset(data, 0xFF, sizeof(u8) * PGPKT_DATA_SIZE);
244         while (efuse_addr < efuse_available_max_size) {
245                 if (efuse_one_byte_read(adapter, efuse_addr, &efuse_data)) {
246                         if (efuse_data == 0xFF)
247                                 break;
248                         hoffset = (efuse_data >> 4) & 0x0F;
249                         hworden =  efuse_data & 0x0F;
250                         word_cnts = calculate_word_cnts(hworden);
251                         if (hoffset == offset) {
252                                 memset(tmpdata, 0xFF, PGPKT_DATA_SIZE);
253                                 for (tmpidx = 0; tmpidx < word_cnts * 2;
254                                      tmpidx++) {
255                                         if (efuse_one_byte_read(adapter,
256                                             efuse_addr + 1 + tmpidx,
257                                             &efuse_data)) {
258                                                 tmpdata[tmpidx] = efuse_data;
259                                         } else {
260                                                 ret = false;
261                                         }
262                                 }
263                                 pgpacket_copy_data(hworden, tmpdata, data);
264                         }
265                         efuse_addr += 1 + (word_cnts * 2);
266                 } else {
267                         ret = false;
268                         break;
269                 }
270         }
271         return ret;
272 }
273
274 static u8 fix_header(struct _adapter *adapter, u8 header, u16 header_addr)
275 {
276         struct PGPKT_STRUCT pkt;
277         u8 offset, word_en, value;
278         u16 addr;
279         int i;
280         u8 ret = true;
281
282         pkt.offset = GET_EFUSE_OFFSET(header);
283         pkt.word_en = GET_EFUSE_WORD_EN(header);
284         addr = header_addr + 1 + calculate_word_cnts(pkt.word_en) * 2;
285         if (addr > efuse_available_max_size)
286                 return false;
287         /* retrieve original data */
288         addr = 0;
289         while (addr < header_addr) {
290                 if (!efuse_one_byte_read(adapter, addr++, &value)) {
291                         ret = false;
292                         break;
293                 }
294                 offset = GET_EFUSE_OFFSET(value);
295                 word_en = GET_EFUSE_WORD_EN(value);
296                 if (pkt.offset != offset) {
297                         addr += calculate_word_cnts(word_en) * 2;
298                         continue;
299                 }
300                 for (i = 0; i < PGPKG_MAX_WORDS; i++) {
301                         if (BIT(i) & word_en) {
302                                 if (BIT(i) & pkt.word_en) {
303                                         if (efuse_one_byte_read(
304                                                         adapter, addr,
305                                                         &value))
306                                                 pkt.data[i * 2] = value;
307                                         else
308                                                 return false;
309                                         if (efuse_one_byte_read(
310                                                         adapter,
311                                                         addr + 1,
312                                                         &value))
313                                                 pkt.data[i * 2 + 1] =
314                                                         value;
315                                         else
316                                                 return false;
317                                 }
318                                 addr += 2;
319                         }
320                 }
321         }
322         if (addr != header_addr)
323                 return false;
324         addr++;
325         /* fill original data */
326         for (i = 0; i < PGPKG_MAX_WORDS; i++) {
327                 if (BIT(i) & pkt.word_en) {
328                         efuse_one_byte_write(adapter, addr, pkt.data[i * 2]);
329                         efuse_one_byte_write(adapter, addr + 1,
330                                              pkt.data[i * 2 + 1]);
331                         /* additional check */
332                         if (!efuse_one_byte_read(adapter, addr, &value)) {
333                                 ret = false;
334                         } else if (pkt.data[i * 2] != value) {
335                                 ret = false;
336                                 if (value == 0xFF) /* write again */
337                                         efuse_one_byte_write(adapter, addr,
338                                                              pkt.data[i * 2]);
339                         }
340                         if (!efuse_one_byte_read(adapter, addr + 1, &value)) {
341                                 ret = false;
342                         } else if (pkt.data[i * 2 + 1] != value) {
343                                 ret = false;
344                                 if (value == 0xFF) /* write again */
345                                         efuse_one_byte_write(adapter, addr + 1,
346                                                              pkt.data[i * 2 +
347                                                                       1]);
348                         }
349                 }
350                 addr += 2;
351         }
352         return ret;
353 }
354
355 u8 r8712_efuse_pg_packet_write(struct _adapter *adapter, const u8 offset,
356                                const u8 word_en, const u8 *data)
357 {
358         u8 pg_header = 0;
359         u16 efuse_addr = 0, curr_size = 0;
360         u8 efuse_data, target_word_cnts = 0;
361         int repeat_times;
362         int sub_repeat;
363         u8 bResult = true;
364
365         /* check if E-Fuse Clock Enable and E-Fuse Clock is 40M */
366         efuse_data = r8712_read8(adapter, EFUSE_CLK_CTRL);
367         if (efuse_data != 0x03)
368                 return false;
369         pg_header = MAKE_EFUSE_HEADER(offset, word_en);
370         target_word_cnts = calculate_word_cnts(word_en);
371         repeat_times = 0;
372         efuse_addr = 0;
373         while (efuse_addr < efuse_available_max_size) {
374                 curr_size = r8712_efuse_get_current_size(adapter);
375                 if ((curr_size + 1 + target_word_cnts * 2) >
376                      efuse_available_max_size)
377                         return false; /*target_word_cnts + pg header(1 byte)*/
378                 efuse_addr = curr_size; /* current size is also the last addr*/
379                 efuse_one_byte_write(adapter, efuse_addr, pg_header); /*hdr*/
380                 sub_repeat = 0;
381                 /* check if what we read is what we write */
382                 while (!efuse_one_byte_read(adapter, efuse_addr,
383                                             &efuse_data)) {
384                         if (++sub_repeat > _REPEAT_THRESHOLD_) {
385                                 bResult = false; /* continue to blind write */
386                                 break; /* continue to blind write */
387                         }
388                 }
389                 if ((sub_repeat > _REPEAT_THRESHOLD_) ||
390                     (pg_header == efuse_data)) {
391                         /* write header ok OR can't check header(creep) */
392                         u8 i;
393
394                         /* go to next address */
395                         efuse_addr++;
396                         for (i = 0; i < target_word_cnts * 2; i++) {
397                                 efuse_one_byte_write(adapter,
398                                                      efuse_addr + i,
399                                                      *(data + i));
400                                 if (!efuse_one_byte_read(adapter,
401                                                          efuse_addr + i,
402                                                          &efuse_data))
403                                         bResult = false;
404                                 else if (*(data + i) != efuse_data) /* fail */
405                                         bResult = false;
406                         }
407                         break;
408                 }
409                 /* write header fail */
410                 bResult = false;
411                 if (efuse_data == 0xFF)
412                         return bResult; /* nothing damaged. */
413                 /* call rescue procedure */
414                 if (!fix_header(adapter, efuse_data, efuse_addr))
415                         return false; /* rescue fail */
416
417                 if (++repeat_times > _REPEAT_THRESHOLD_) /* fail */
418                         break;
419                 /* otherwise, take another risk... */
420         }
421         return bResult;
422 }
423
424 u8 r8712_efuse_access(struct _adapter *adapter, u8 bRead, u16 start_addr,
425                       u16 cnts, u8 *data)
426 {
427         int i;
428         u8 res = true;
429
430         if (start_addr > EFUSE_MAX_SIZE)
431                 return false;
432         if (!bRead && ((start_addr + cnts) >
433            efuse_available_max_size))
434                 return false;
435         if (!bRead && !r8712_efuse_reg_init(adapter))
436                 return false;
437         /* -----------------e-fuse one byte read / write ---------------------*/
438         for (i = 0; i < cnts; i++) {
439                 if ((start_addr + i) > EFUSE_MAX_SIZE) {
440                         res = false;
441                         break;
442                 }
443                 res = efuse_one_byte_rw(adapter, bRead, start_addr + i,
444                                         data + i);
445                 if (!bRead && !res)
446                         break;
447         }
448         if (!bRead)
449                 r8712_efuse_reg_uninit(adapter);
450         return res;
451 }
452
453 u8 r8712_efuse_map_read(struct _adapter *adapter, u16 addr, u16 cnts, u8 *data)
454 {
455         u8 offset, ret = true;
456         u8 pktdata[PGPKT_DATA_SIZE];
457         int i, idx;
458
459         if ((addr + cnts) > EFUSE_MAP_MAX_SIZE)
460                 return false;
461         if (efuse_is_empty(adapter, &offset) && offset) {
462                 for (i = 0; i < cnts; i++)
463                         data[i] = 0xFF;
464                 return ret;
465         }
466         offset = (addr >> 3) & 0xF;
467         ret = r8712_efuse_pg_packet_read(adapter, offset, pktdata);
468         i = addr & 0x7; /* pktdata index */
469         idx = 0;        /* data index */
470
471         do {
472                 for (; i < PGPKT_DATA_SIZE; i++) {
473                         data[idx++] = pktdata[i];
474                         if (idx == cnts)
475                                 return ret;
476                 }
477                 offset++;
478                 if (!r8712_efuse_pg_packet_read(adapter, offset, pktdata))
479                         ret = false;
480                 i = 0;
481         } while (1);
482         return ret;
483 }
484
485 u8 r8712_efuse_map_write(struct _adapter *adapter, u16 addr, u16 cnts,
486                          u8 *data)
487 {
488         u8 offset, word_en, empty;
489         u8 pktdata[PGPKT_DATA_SIZE], newdata[PGPKT_DATA_SIZE];
490         int i, j, idx;
491
492         if ((addr + cnts) > EFUSE_MAP_MAX_SIZE)
493                 return false;
494         /* check if E-Fuse Clock Enable and E-Fuse Clock is 40M */
495         empty = r8712_read8(adapter, EFUSE_CLK_CTRL);
496         if (empty != 0x03)
497                 return false;
498         if (efuse_is_empty(adapter, &empty)) {
499                 if (empty)
500                         memset(pktdata, 0xFF, PGPKT_DATA_SIZE);
501         } else {
502                 return false;
503         }
504         offset = (addr >> 3) & 0xF;
505         if (!empty)
506                 if (!r8712_efuse_pg_packet_read(adapter, offset, pktdata))
507                         return false;
508         word_en = 0xF;
509         memset(newdata, 0xFF, PGPKT_DATA_SIZE);
510         i = addr & 0x7; /* pktdata index */
511         j = 0;          /* newdata index */
512         idx = 0;        /* data index */
513
514         if (i & 0x1) {
515                 /*  odd start */
516                 if (data[idx] != pktdata[i]) {
517                         word_en &= ~BIT(i >> 1);
518                         newdata[j++] = pktdata[i - 1];
519                         newdata[j++] = data[idx];
520                 }
521                 i++;
522                 idx++;
523         }
524         do {
525                 for (; i < PGPKT_DATA_SIZE; i += 2) {
526                         if ((cnts - idx) == 1) {
527                                 if (data[idx] != pktdata[i]) {
528                                         word_en &= ~BIT(i >> 1);
529                                         newdata[j++] = data[idx];
530                                         newdata[j++] = pktdata[1 + 1];
531                                 }
532                                 idx++;
533                                 break;
534                         }
535
536                         if ((data[idx] != pktdata[i]) || (data[idx + 1] !=
537                              pktdata[i + 1])) {
538                                 word_en &= ~BIT(i >> 1);
539                                 newdata[j++] = data[idx];
540                                 newdata[j++] = data[idx + 1];
541                         }
542                         idx += 2;
543
544                         if (idx == cnts)
545                                 break;
546                 }
547
548                 if (word_en != 0xF)
549                         if (!r8712_efuse_pg_packet_write(adapter, offset,
550                                                          word_en, newdata))
551                                 return false;
552                 if (idx == cnts)
553                         break;
554                 offset++;
555                 if (!empty)
556                         if (!r8712_efuse_pg_packet_read(adapter, offset,
557                                                         pktdata))
558                                 return false;
559                 i = 0;
560                 j = 0;
561                 word_en = 0xF;
562                 memset(newdata, 0xFF, PGPKT_DATA_SIZE);
563         } while (1);
564
565         return true;
566 }