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