1365 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright(c) 2009-2012 Realtek Corporation.*/3 4#include "wifi.h"5#include "efuse.h"6#include "pci.h"7#include <linux/export.h>8 9static const u8 PGPKT_DATA_SIZE = 8;10static const int EFUSE_MAX_SIZE = 512;11 12#define START_ADDRESS 0x100013#define REG_MCUFWDL 0x008014 15static const struct rtl_efuse_ops efuse_ops = {16 .efuse_onebyte_read = efuse_one_byte_read,17 .efuse_logical_map_read = efuse_shadow_read,18};19 20static void efuse_shadow_read_1byte(struct ieee80211_hw *hw, u16 offset,21 u8 *value);22static void efuse_shadow_read_2byte(struct ieee80211_hw *hw, u16 offset,23 u16 *value);24static void efuse_shadow_read_4byte(struct ieee80211_hw *hw, u16 offset,25 u32 *value);26static void efuse_shadow_write_1byte(struct ieee80211_hw *hw, u16 offset,27 u8 value);28static void efuse_shadow_write_2byte(struct ieee80211_hw *hw, u16 offset,29 u16 value);30static void efuse_shadow_write_4byte(struct ieee80211_hw *hw, u16 offset,31 u32 value);32static int efuse_one_byte_write(struct ieee80211_hw *hw, u16 addr,33 u8 data);34static void efuse_read_all_map(struct ieee80211_hw *hw, u8 *efuse);35static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset,36 u8 *data);37static int efuse_pg_packet_write(struct ieee80211_hw *hw, u8 offset,38 u8 word_en, u8 *data);39static void efuse_word_enable_data_read(u8 word_en, u8 *sourdata,40 u8 *targetdata);41static u8 enable_efuse_data_write(struct ieee80211_hw *hw,42 u16 efuse_addr, u8 word_en, u8 *data);43static u16 efuse_get_current_size(struct ieee80211_hw *hw);44static u8 efuse_calculate_word_cnts(u8 word_en);45 46void efuse_initialize(struct ieee80211_hw *hw)47{48 struct rtl_priv *rtlpriv = rtl_priv(hw);49 u8 bytetemp;50 u8 temp;51 52 bytetemp = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[SYS_FUNC_EN] + 1);53 temp = bytetemp | 0x20;54 rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[SYS_FUNC_EN] + 1, temp);55 56 bytetemp = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[SYS_ISO_CTRL] + 1);57 temp = bytetemp & 0xFE;58 rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[SYS_ISO_CTRL] + 1, temp);59 60 bytetemp = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_TEST] + 3);61 temp = bytetemp | 0x80;62 rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_TEST] + 3, temp);63 64 rtl_write_byte(rtlpriv, 0x2F8, 0x3);65 66 rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 3, 0x72);67 68}69 70u8 efuse_read_1byte(struct ieee80211_hw *hw, u16 address)71{72 struct rtl_priv *rtlpriv = rtl_priv(hw);73 u8 data;74 u8 bytetemp;75 u8 temp;76 u32 k = 0;77 const u32 efuse_len =78 rtlpriv->cfg->maps[EFUSE_REAL_CONTENT_SIZE];79 80 if (address < efuse_len) {81 temp = address & 0xFF;82 rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 1,83 temp);84 bytetemp = rtl_read_byte(rtlpriv,85 rtlpriv->cfg->maps[EFUSE_CTRL] + 2);86 temp = ((address >> 8) & 0x03) | (bytetemp & 0xFC);87 rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 2,88 temp);89 90 bytetemp = rtl_read_byte(rtlpriv,91 rtlpriv->cfg->maps[EFUSE_CTRL] + 3);92 temp = bytetemp & 0x7F;93 rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 3,94 temp);95 96 bytetemp = rtl_read_byte(rtlpriv,97 rtlpriv->cfg->maps[EFUSE_CTRL] + 3);98 while (!(bytetemp & 0x80)) {99 bytetemp = rtl_read_byte(rtlpriv,100 rtlpriv->cfg->101 maps[EFUSE_CTRL] + 3);102 k++;103 if (k == 1000)104 break;105 }106 data = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL]);107 return data;108 } else109 return 0xFF;110 111}112EXPORT_SYMBOL(efuse_read_1byte);113 114void efuse_write_1byte(struct ieee80211_hw *hw, u16 address, u8 value)115{116 struct rtl_priv *rtlpriv = rtl_priv(hw);117 u8 bytetemp;118 u8 temp;119 u32 k = 0;120 const u32 efuse_len =121 rtlpriv->cfg->maps[EFUSE_REAL_CONTENT_SIZE];122 123 rtl_dbg(rtlpriv, COMP_EFUSE, DBG_LOUD, "Addr=%x Data =%x\n",124 address, value);125 126 if (address < efuse_len) {127 rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL], value);128 129 temp = address & 0xFF;130 rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 1,131 temp);132 bytetemp = rtl_read_byte(rtlpriv,133 rtlpriv->cfg->maps[EFUSE_CTRL] + 2);134 135 temp = ((address >> 8) & 0x03) | (bytetemp & 0xFC);136 rtl_write_byte(rtlpriv,137 rtlpriv->cfg->maps[EFUSE_CTRL] + 2, temp);138 139 bytetemp = rtl_read_byte(rtlpriv,140 rtlpriv->cfg->maps[EFUSE_CTRL] + 3);141 temp = bytetemp | 0x80;142 rtl_write_byte(rtlpriv,143 rtlpriv->cfg->maps[EFUSE_CTRL] + 3, temp);144 145 bytetemp = rtl_read_byte(rtlpriv,146 rtlpriv->cfg->maps[EFUSE_CTRL] + 3);147 148 while (bytetemp & 0x80) {149 bytetemp = rtl_read_byte(rtlpriv,150 rtlpriv->cfg->151 maps[EFUSE_CTRL] + 3);152 k++;153 if (k == 100) {154 k = 0;155 break;156 }157 }158 }159 160}161 162void read_efuse_byte(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf)163{164 struct rtl_priv *rtlpriv = rtl_priv(hw);165 u32 value32;166 u8 readbyte;167 u16 retry;168 169 rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 1,170 (_offset & 0xff));171 readbyte = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 2);172 rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 2,173 ((_offset >> 8) & 0x03) | (readbyte & 0xfc));174 175 readbyte = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 3);176 rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 3,177 (readbyte & 0x7f));178 179 retry = 0;180 value32 = rtl_read_dword(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL]);181 while (!(((value32 >> 24) & 0xff) & 0x80) && (retry < 10000)) {182 value32 = rtl_read_dword(rtlpriv,183 rtlpriv->cfg->maps[EFUSE_CTRL]);184 retry++;185 }186 187 udelay(50);188 value32 = rtl_read_dword(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL]);189 190 *pbuf = (u8) (value32 & 0xff);191}192EXPORT_SYMBOL_GPL(read_efuse_byte);193 194void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf)195{196 struct rtl_priv *rtlpriv = rtl_priv(hw);197 struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));198 u8 *efuse_tbl;199 u8 rtemp8[1];200 u16 efuse_addr = 0;201 u8 offset, wren;202 u8 u1temp = 0;203 u16 i;204 u16 j;205 const u16 efuse_max_section =206 rtlpriv->cfg->maps[EFUSE_MAX_SECTION_MAP];207 const u32 efuse_len =208 rtlpriv->cfg->maps[EFUSE_REAL_CONTENT_SIZE];209 u16 **efuse_word;210 u16 efuse_utilized = 0;211 u8 efuse_usage;212 213 if ((_offset + _size_byte) > rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]) {214 rtl_dbg(rtlpriv, COMP_EFUSE, DBG_LOUD,215 "%s: Invalid offset(%#x) with read bytes(%#x)!!\n",216 __func__, _offset, _size_byte);217 return;218 }219 220 /* allocate memory for efuse_tbl and efuse_word */221 efuse_tbl = kzalloc(rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE],222 GFP_ATOMIC);223 if (!efuse_tbl)224 return;225 efuse_word = kcalloc(EFUSE_MAX_WORD_UNIT, sizeof(u16 *), GFP_ATOMIC);226 if (!efuse_word)227 goto out;228 for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) {229 efuse_word[i] = kcalloc(efuse_max_section, sizeof(u16),230 GFP_ATOMIC);231 if (!efuse_word[i])232 goto done;233 }234 235 for (i = 0; i < efuse_max_section; i++)236 for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++)237 efuse_word[j][i] = 0xFFFF;238 239 read_efuse_byte(hw, efuse_addr, rtemp8);240 if (*rtemp8 != 0xFF) {241 efuse_utilized++;242 RTPRINT(rtlpriv, FEEPROM, EFUSE_READ_ALL,243 "Addr=%d\n", efuse_addr);244 efuse_addr++;245 }246 247 while ((*rtemp8 != 0xFF) && (efuse_addr < efuse_len)) {248 /* Check PG header for section num. */249 if ((*rtemp8 & 0x1F) == 0x0F) {/* extended header */250 u1temp = ((*rtemp8 & 0xE0) >> 5);251 read_efuse_byte(hw, efuse_addr, rtemp8);252 253 if ((*rtemp8 & 0x0F) == 0x0F) {254 efuse_addr++;255 read_efuse_byte(hw, efuse_addr, rtemp8);256 257 if (*rtemp8 != 0xFF &&258 (efuse_addr < efuse_len)) {259 efuse_addr++;260 }261 continue;262 } else {263 offset = ((*rtemp8 & 0xF0) >> 1) | u1temp;264 wren = (*rtemp8 & 0x0F);265 efuse_addr++;266 }267 } else {268 offset = ((*rtemp8 >> 4) & 0x0f);269 wren = (*rtemp8 & 0x0f);270 }271 272 if (offset < efuse_max_section) {273 RTPRINT(rtlpriv, FEEPROM, EFUSE_READ_ALL,274 "offset-%d Worden=%x\n", offset, wren);275 276 for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) {277 if (!(wren & 0x01)) {278 RTPRINT(rtlpriv, FEEPROM,279 EFUSE_READ_ALL,280 "Addr=%d\n", efuse_addr);281 282 read_efuse_byte(hw, efuse_addr, rtemp8);283 efuse_addr++;284 efuse_utilized++;285 efuse_word[i][offset] =286 (*rtemp8 & 0xff);287 288 if (efuse_addr >= efuse_len)289 break;290 291 RTPRINT(rtlpriv, FEEPROM,292 EFUSE_READ_ALL,293 "Addr=%d\n", efuse_addr);294 295 read_efuse_byte(hw, efuse_addr, rtemp8);296 efuse_addr++;297 efuse_utilized++;298 efuse_word[i][offset] |=299 (((u16)*rtemp8 << 8) & 0xff00);300 301 if (efuse_addr >= efuse_len)302 break;303 }304 305 wren >>= 1;306 }307 }308 309 RTPRINT(rtlpriv, FEEPROM, EFUSE_READ_ALL,310 "Addr=%d\n", efuse_addr);311 read_efuse_byte(hw, efuse_addr, rtemp8);312 if (*rtemp8 != 0xFF && (efuse_addr < efuse_len)) {313 efuse_utilized++;314 efuse_addr++;315 }316 }317 318 for (i = 0; i < efuse_max_section; i++) {319 for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) {320 efuse_tbl[(i * 8) + (j * 2)] =321 (efuse_word[j][i] & 0xff);322 efuse_tbl[(i * 8) + ((j * 2) + 1)] =323 ((efuse_word[j][i] >> 8) & 0xff);324 }325 }326 327 for (i = 0; i < _size_byte; i++)328 pbuf[i] = efuse_tbl[_offset + i];329 330 rtlefuse->efuse_usedbytes = efuse_utilized;331 efuse_usage = (u8) ((efuse_utilized * 100) / efuse_len);332 rtlefuse->efuse_usedpercentage = efuse_usage;333 rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_EFUSE_BYTES,334 (u8 *)&efuse_utilized);335 rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_EFUSE_USAGE,336 &efuse_usage);337done:338 for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++)339 kfree(efuse_word[i]);340 kfree(efuse_word);341out:342 kfree(efuse_tbl);343}344 345bool efuse_shadow_update_chk(struct ieee80211_hw *hw)346{347 struct rtl_priv *rtlpriv = rtl_priv(hw);348 struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));349 u8 section_idx, i, base;350 u16 words_need = 0, hdr_num = 0, totalbytes, efuse_used;351 bool wordchanged, result = true;352 353 for (section_idx = 0; section_idx < 16; section_idx++) {354 base = section_idx * 8;355 wordchanged = false;356 357 for (i = 0; i < 8; i = i + 2) {358 if (rtlefuse->efuse_map[EFUSE_INIT_MAP][base + i] !=359 rtlefuse->efuse_map[EFUSE_MODIFY_MAP][base + i] ||360 rtlefuse->efuse_map[EFUSE_INIT_MAP][base + i + 1] !=361 rtlefuse->efuse_map[EFUSE_MODIFY_MAP][base + i +362 1]) {363 words_need++;364 wordchanged = true;365 }366 }367 368 if (wordchanged)369 hdr_num++;370 }371 372 totalbytes = hdr_num + words_need * 2;373 efuse_used = rtlefuse->efuse_usedbytes;374 375 if ((totalbytes + efuse_used) >=376 (EFUSE_MAX_SIZE - rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN]))377 result = false;378 379 rtl_dbg(rtlpriv, COMP_EFUSE, DBG_LOUD,380 "%s: totalbytes(%#x), hdr_num(%#x), words_need(%#x), efuse_used(%d)\n",381 __func__, totalbytes, hdr_num, words_need, efuse_used);382 383 return result;384}385 386void efuse_shadow_read(struct ieee80211_hw *hw, u8 type,387 u16 offset, u32 *value)388{389 if (type == 1)390 efuse_shadow_read_1byte(hw, offset, (u8 *)value);391 else if (type == 2)392 efuse_shadow_read_2byte(hw, offset, (u16 *)value);393 else if (type == 4)394 efuse_shadow_read_4byte(hw, offset, value);395 396}397EXPORT_SYMBOL(efuse_shadow_read);398 399void efuse_shadow_write(struct ieee80211_hw *hw, u8 type, u16 offset,400 u32 value)401{402 if (type == 1)403 efuse_shadow_write_1byte(hw, offset, (u8) value);404 else if (type == 2)405 efuse_shadow_write_2byte(hw, offset, (u16) value);406 else if (type == 4)407 efuse_shadow_write_4byte(hw, offset, value);408 409}410 411bool efuse_shadow_update(struct ieee80211_hw *hw)412{413 struct rtl_priv *rtlpriv = rtl_priv(hw);414 struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));415 u16 i, offset, base;416 u8 word_en = 0x0F;417 u8 first_pg = false;418 419 rtl_dbg(rtlpriv, COMP_EFUSE, DBG_LOUD, "\n");420 421 if (!efuse_shadow_update_chk(hw)) {422 efuse_read_all_map(hw, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0]);423 memcpy(&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0],424 &rtlefuse->efuse_map[EFUSE_INIT_MAP][0],425 rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]);426 427 rtl_dbg(rtlpriv, COMP_EFUSE, DBG_LOUD,428 "efuse out of capacity!!\n");429 return false;430 }431 efuse_power_switch(hw, true, true);432 433 for (offset = 0; offset < 16; offset++) {434 435 word_en = 0x0F;436 base = offset * 8;437 438 for (i = 0; i < 8; i++) {439 if (first_pg) {440 word_en &= ~(BIT(i / 2));441 442 rtlefuse->efuse_map[EFUSE_INIT_MAP][base + i] =443 rtlefuse->efuse_map[EFUSE_MODIFY_MAP][base + i];444 } else {445 446 if (rtlefuse->efuse_map[EFUSE_INIT_MAP][base + i] !=447 rtlefuse->efuse_map[EFUSE_MODIFY_MAP][base + i]) {448 word_en &= ~(BIT(i / 2));449 450 rtlefuse->efuse_map[EFUSE_INIT_MAP][base + i] =451 rtlefuse->efuse_map[EFUSE_MODIFY_MAP][base + i];452 }453 }454 }455 456 if (word_en != 0x0F) {457 u8 tmpdata[8];458 459 memcpy(tmpdata,460 &rtlefuse->efuse_map[EFUSE_MODIFY_MAP][base],461 8);462 RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_LOUD,463 "U-efuse\n", tmpdata, 8);464 465 if (!efuse_pg_packet_write(hw, (u8) offset, word_en,466 tmpdata)) {467 rtl_dbg(rtlpriv, COMP_ERR, DBG_WARNING,468 "PG section(%#x) fail!!\n", offset);469 break;470 }471 }472 }473 474 efuse_power_switch(hw, true, false);475 efuse_read_all_map(hw, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0]);476 477 memcpy(&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0],478 &rtlefuse->efuse_map[EFUSE_INIT_MAP][0],479 rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]);480 481 rtl_dbg(rtlpriv, COMP_EFUSE, DBG_LOUD, "\n");482 return true;483}484 485void rtl_efuse_shadow_map_update(struct ieee80211_hw *hw)486{487 struct rtl_priv *rtlpriv = rtl_priv(hw);488 struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));489 490 if (rtlefuse->autoload_failflag)491 memset((&rtlefuse->efuse_map[EFUSE_INIT_MAP][0]),492 0xFF, rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]);493 else494 efuse_read_all_map(hw, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0]);495 496 memcpy(&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0],497 &rtlefuse->efuse_map[EFUSE_INIT_MAP][0],498 rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]);499 500}501EXPORT_SYMBOL(rtl_efuse_shadow_map_update);502 503void efuse_force_write_vendor_id(struct ieee80211_hw *hw)504{505 u8 tmpdata[8] = { 0xFF, 0xFF, 0xEC, 0x10, 0xFF, 0xFF, 0xFF, 0xFF };506 507 efuse_power_switch(hw, true, true);508 509 efuse_pg_packet_write(hw, 1, 0xD, tmpdata);510 511 efuse_power_switch(hw, true, false);512 513}514 515void efuse_re_pg_section(struct ieee80211_hw *hw, u8 section_idx)516{517}518 519static void efuse_shadow_read_1byte(struct ieee80211_hw *hw,520 u16 offset, u8 *value)521{522 struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));523 *value = rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset];524}525 526static void efuse_shadow_read_2byte(struct ieee80211_hw *hw,527 u16 offset, u16 *value)528{529 struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));530 531 *value = rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset];532 *value |= rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 1] << 8;533 534}535 536static void efuse_shadow_read_4byte(struct ieee80211_hw *hw,537 u16 offset, u32 *value)538{539 struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));540 541 *value = rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset];542 *value |= rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 1] << 8;543 *value |= rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 2] << 16;544 *value |= rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 3] << 24;545}546 547static void efuse_shadow_write_1byte(struct ieee80211_hw *hw,548 u16 offset, u8 value)549{550 struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));551 552 rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset] = value;553}554 555static void efuse_shadow_write_2byte(struct ieee80211_hw *hw,556 u16 offset, u16 value)557{558 struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));559 560 rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset] = value & 0x00FF;561 rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 1] = value >> 8;562 563}564 565static void efuse_shadow_write_4byte(struct ieee80211_hw *hw,566 u16 offset, u32 value)567{568 struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));569 570 rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset] =571 (u8) (value & 0x000000FF);572 rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 1] =573 (u8) ((value >> 8) & 0x0000FF);574 rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 2] =575 (u8) ((value >> 16) & 0x00FF);576 rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 3] =577 (u8) ((value >> 24) & 0xFF);578 579}580 581int efuse_one_byte_read(struct ieee80211_hw *hw, u16 addr, u8 *data)582{583 struct rtl_priv *rtlpriv = rtl_priv(hw);584 u8 tmpidx = 0;585 int result;586 587 rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 1,588 (u8) (addr & 0xff));589 rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 2,590 ((u8) ((addr >> 8) & 0x03)) |591 (rtl_read_byte(rtlpriv,592 rtlpriv->cfg->maps[EFUSE_CTRL] + 2) &593 0xFC));594 595 rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 3, 0x72);596 597 while (!(0x80 & rtl_read_byte(rtlpriv,598 rtlpriv->cfg->maps[EFUSE_CTRL] + 3))599 && (tmpidx < 100)) {600 tmpidx++;601 }602 603 if (tmpidx < 100) {604 *data = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL]);605 result = true;606 } else {607 *data = 0xff;608 result = false;609 }610 return result;611}612EXPORT_SYMBOL(efuse_one_byte_read);613 614static int efuse_one_byte_write(struct ieee80211_hw *hw, u16 addr, u8 data)615{616 struct rtl_priv *rtlpriv = rtl_priv(hw);617 u8 tmpidx = 0;618 619 rtl_dbg(rtlpriv, COMP_EFUSE, DBG_LOUD,620 "Addr = %x Data=%x\n", addr, data);621 622 rtl_write_byte(rtlpriv,623 rtlpriv->cfg->maps[EFUSE_CTRL] + 1, (u8) (addr & 0xff));624 rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 2,625 (rtl_read_byte(rtlpriv,626 rtlpriv->cfg->maps[EFUSE_CTRL] +627 2) & 0xFC) | (u8) ((addr >> 8) & 0x03));628 629 rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL], data);630 rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 3, 0xF2);631 632 while ((0x80 & rtl_read_byte(rtlpriv,633 rtlpriv->cfg->maps[EFUSE_CTRL] + 3))634 && (tmpidx < 100)) {635 tmpidx++;636 }637 638 if (tmpidx < 100)639 return true;640 return false;641}642 643static void efuse_read_all_map(struct ieee80211_hw *hw, u8 *efuse)644{645 struct rtl_priv *rtlpriv = rtl_priv(hw);646 647 efuse_power_switch(hw, false, true);648 read_efuse(hw, 0, rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE], efuse);649 efuse_power_switch(hw, false, false);650}651 652static void efuse_read_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr,653 u8 efuse_data, u8 offset, u8 *tmpdata,654 u8 *readstate)655{656 bool dataempty = true;657 u8 hoffset;658 u8 tmpidx;659 u8 hworden;660 u8 word_cnts;661 662 hoffset = (efuse_data >> 4) & 0x0F;663 hworden = efuse_data & 0x0F;664 word_cnts = efuse_calculate_word_cnts(hworden);665 666 if (hoffset == offset) {667 for (tmpidx = 0; tmpidx < word_cnts * 2; tmpidx++) {668 if (efuse_one_byte_read(hw, *efuse_addr + 1 + tmpidx,669 &efuse_data)) {670 tmpdata[tmpidx] = efuse_data;671 if (efuse_data != 0xff)672 dataempty = false;673 }674 }675 676 if (!dataempty) {677 *readstate = PG_STATE_DATA;678 } else {679 *efuse_addr = *efuse_addr + (word_cnts * 2) + 1;680 *readstate = PG_STATE_HEADER;681 }682 683 } else {684 *efuse_addr = *efuse_addr + (word_cnts * 2) + 1;685 *readstate = PG_STATE_HEADER;686 }687}688 689static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset, u8 *data)690{691 u8 readstate = PG_STATE_HEADER;692 693 bool continual = true;694 695 u8 efuse_data, word_cnts = 0;696 u16 efuse_addr = 0;697 u8 tmpdata[8];698 699 if (data == NULL)700 return false;701 if (offset > 15)702 return false;703 704 memset(data, 0xff, PGPKT_DATA_SIZE * sizeof(u8));705 memset(tmpdata, 0xff, PGPKT_DATA_SIZE * sizeof(u8));706 707 while (continual && (efuse_addr < EFUSE_MAX_SIZE)) {708 if (readstate & PG_STATE_HEADER) {709 if (efuse_one_byte_read(hw, efuse_addr, &efuse_data)710 && (efuse_data != 0xFF))711 efuse_read_data_case1(hw, &efuse_addr,712 efuse_data, offset,713 tmpdata, &readstate);714 else715 continual = false;716 } else if (readstate & PG_STATE_DATA) {717 efuse_word_enable_data_read(0, tmpdata, data);718 efuse_addr = efuse_addr + (word_cnts * 2) + 1;719 readstate = PG_STATE_HEADER;720 }721 722 }723 724 if ((data[0] == 0xff) && (data[1] == 0xff) &&725 (data[2] == 0xff) && (data[3] == 0xff) &&726 (data[4] == 0xff) && (data[5] == 0xff) &&727 (data[6] == 0xff) && (data[7] == 0xff))728 return false;729 else730 return true;731 732}733 734static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr,735 u8 efuse_data, u8 offset,736 int *continual, u8 *write_state,737 struct pgpkt_struct *target_pkt,738 int *repeat_times, int *result, u8 word_en)739{740 struct rtl_priv *rtlpriv = rtl_priv(hw);741 struct pgpkt_struct tmp_pkt;742 int dataempty = true;743 u8 originaldata[8 * sizeof(u8)];744 u8 badworden = 0x0F;745 u8 match_word_en, tmp_word_en;746 u8 tmpindex;747 u8 tmp_header = efuse_data;748 u8 tmp_word_cnts;749 750 tmp_pkt.offset = (tmp_header >> 4) & 0x0F;751 tmp_pkt.word_en = tmp_header & 0x0F;752 tmp_word_cnts = efuse_calculate_word_cnts(tmp_pkt.word_en);753 754 if (tmp_pkt.offset != target_pkt->offset) {755 *efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + 1;756 *write_state = PG_STATE_HEADER;757 } else {758 for (tmpindex = 0; tmpindex < (tmp_word_cnts * 2); tmpindex++) {759 if (efuse_one_byte_read(hw,760 (*efuse_addr + 1 + tmpindex),761 &efuse_data) &&762 (efuse_data != 0xFF))763 dataempty = false;764 }765 766 if (!dataempty) {767 *efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + 1;768 *write_state = PG_STATE_HEADER;769 } else {770 match_word_en = 0x0F;771 if (!((target_pkt->word_en & BIT(0)) |772 (tmp_pkt.word_en & BIT(0))))773 match_word_en &= (~BIT(0));774 775 if (!((target_pkt->word_en & BIT(1)) |776 (tmp_pkt.word_en & BIT(1))))777 match_word_en &= (~BIT(1));778 779 if (!((target_pkt->word_en & BIT(2)) |780 (tmp_pkt.word_en & BIT(2))))781 match_word_en &= (~BIT(2));782 783 if (!((target_pkt->word_en & BIT(3)) |784 (tmp_pkt.word_en & BIT(3))))785 match_word_en &= (~BIT(3));786 787 if ((match_word_en & 0x0F) != 0x0F) {788 badworden =789 enable_efuse_data_write(hw,790 *efuse_addr + 1,791 tmp_pkt.word_en,792 target_pkt->data);793 794 if (0x0F != (badworden & 0x0F)) {795 u8 reorg_offset = offset;796 u8 reorg_worden = badworden;797 798 efuse_pg_packet_write(hw, reorg_offset,799 reorg_worden,800 originaldata);801 }802 803 tmp_word_en = 0x0F;804 if ((target_pkt->word_en & BIT(0)) ^805 (match_word_en & BIT(0)))806 tmp_word_en &= (~BIT(0));807 808 if ((target_pkt->word_en & BIT(1)) ^809 (match_word_en & BIT(1)))810 tmp_word_en &= (~BIT(1));811 812 if ((target_pkt->word_en & BIT(2)) ^813 (match_word_en & BIT(2)))814 tmp_word_en &= (~BIT(2));815 816 if ((target_pkt->word_en & BIT(3)) ^817 (match_word_en & BIT(3)))818 tmp_word_en &= (~BIT(3));819 820 if ((tmp_word_en & 0x0F) != 0x0F) {821 *efuse_addr = efuse_get_current_size(hw);822 target_pkt->offset = offset;823 target_pkt->word_en = tmp_word_en;824 } else {825 *continual = false;826 }827 *write_state = PG_STATE_HEADER;828 *repeat_times += 1;829 if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) {830 *continual = false;831 *result = false;832 }833 } else {834 *efuse_addr += (2 * tmp_word_cnts) + 1;835 target_pkt->offset = offset;836 target_pkt->word_en = word_en;837 *write_state = PG_STATE_HEADER;838 }839 }840 }841 RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, "efuse PG_STATE_HEADER-1\n");842}843 844static void efuse_write_data_case2(struct ieee80211_hw *hw, u16 *efuse_addr,845 int *continual, u8 *write_state,846 struct pgpkt_struct target_pkt,847 int *repeat_times, int *result)848{849 struct rtl_priv *rtlpriv = rtl_priv(hw);850 struct pgpkt_struct tmp_pkt;851 u8 pg_header;852 u8 tmp_header;853 u8 originaldata[8 * sizeof(u8)];854 u8 tmp_word_cnts;855 u8 badworden = 0x0F;856 857 pg_header = ((target_pkt.offset << 4) & 0xf0) | target_pkt.word_en;858 efuse_one_byte_write(hw, *efuse_addr, pg_header);859 efuse_one_byte_read(hw, *efuse_addr, &tmp_header);860 861 if (tmp_header == pg_header) {862 *write_state = PG_STATE_DATA;863 } else if (tmp_header == 0xFF) {864 *write_state = PG_STATE_HEADER;865 *repeat_times += 1;866 if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) {867 *continual = false;868 *result = false;869 }870 } else {871 tmp_pkt.offset = (tmp_header >> 4) & 0x0F;872 tmp_pkt.word_en = tmp_header & 0x0F;873 874 tmp_word_cnts = efuse_calculate_word_cnts(tmp_pkt.word_en);875 876 memset(originaldata, 0xff, 8 * sizeof(u8));877 878 if (efuse_pg_packet_read(hw, tmp_pkt.offset, originaldata)) {879 badworden = enable_efuse_data_write(hw,880 *efuse_addr + 1,881 tmp_pkt.word_en,882 originaldata);883 884 if (0x0F != (badworden & 0x0F)) {885 u8 reorg_offset = tmp_pkt.offset;886 u8 reorg_worden = badworden;887 888 efuse_pg_packet_write(hw, reorg_offset,889 reorg_worden,890 originaldata);891 *efuse_addr = efuse_get_current_size(hw);892 } else {893 *efuse_addr = *efuse_addr +894 (tmp_word_cnts * 2) + 1;895 }896 } else {897 *efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + 1;898 }899 900 *write_state = PG_STATE_HEADER;901 *repeat_times += 1;902 if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) {903 *continual = false;904 *result = false;905 }906 907 RTPRINT(rtlpriv, FEEPROM, EFUSE_PG,908 "efuse PG_STATE_HEADER-2\n");909 }910}911 912static int efuse_pg_packet_write(struct ieee80211_hw *hw,913 u8 offset, u8 word_en, u8 *data)914{915 struct rtl_priv *rtlpriv = rtl_priv(hw);916 struct pgpkt_struct target_pkt;917 u8 write_state = PG_STATE_HEADER;918 int continual = true, result = true;919 u16 efuse_addr = 0;920 u8 efuse_data;921 u8 target_word_cnts = 0;922 u8 badworden = 0x0F;923 static int repeat_times;924 925 if (efuse_get_current_size(hw) >= (EFUSE_MAX_SIZE -926 rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN])) {927 RTPRINT(rtlpriv, FEEPROM, EFUSE_PG,928 "efuse_pg_packet_write error\n");929 return false;930 }931 932 target_pkt.offset = offset;933 target_pkt.word_en = word_en;934 935 memset(target_pkt.data, 0xFF, 8 * sizeof(u8));936 937 efuse_word_enable_data_read(word_en, data, target_pkt.data);938 target_word_cnts = efuse_calculate_word_cnts(target_pkt.word_en);939 940 RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, "efuse Power ON\n");941 942 while (continual && (efuse_addr < (EFUSE_MAX_SIZE -943 rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN]))) {944 if (write_state == PG_STATE_HEADER) {945 badworden = 0x0F;946 RTPRINT(rtlpriv, FEEPROM, EFUSE_PG,947 "efuse PG_STATE_HEADER\n");948 949 if (efuse_one_byte_read(hw, efuse_addr, &efuse_data) &&950 (efuse_data != 0xFF))951 efuse_write_data_case1(hw, &efuse_addr,952 efuse_data, offset,953 &continual,954 &write_state,955 &target_pkt,956 &repeat_times, &result,957 word_en);958 else959 efuse_write_data_case2(hw, &efuse_addr,960 &continual,961 &write_state,962 target_pkt,963 &repeat_times,964 &result);965 966 } else if (write_state == PG_STATE_DATA) {967 RTPRINT(rtlpriv, FEEPROM, EFUSE_PG,968 "efuse PG_STATE_DATA\n");969 badworden =970 enable_efuse_data_write(hw, efuse_addr + 1,971 target_pkt.word_en,972 target_pkt.data);973 974 if ((badworden & 0x0F) == 0x0F) {975 continual = false;976 } else {977 efuse_addr =978 efuse_addr + (2 * target_word_cnts) + 1;979 980 target_pkt.offset = offset;981 target_pkt.word_en = badworden;982 target_word_cnts =983 efuse_calculate_word_cnts(target_pkt.984 word_en);985 write_state = PG_STATE_HEADER;986 repeat_times++;987 if (repeat_times > EFUSE_REPEAT_THRESHOLD_) {988 continual = false;989 result = false;990 }991 RTPRINT(rtlpriv, FEEPROM, EFUSE_PG,992 "efuse PG_STATE_HEADER-3\n");993 }994 }995 }996 997 if (efuse_addr >= (EFUSE_MAX_SIZE -998 rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN])) {999 rtl_dbg(rtlpriv, COMP_EFUSE, DBG_LOUD,1000 "efuse_addr(%#x) Out of size!!\n", efuse_addr);1001 }1002 1003 return true;1004}1005 1006static void efuse_word_enable_data_read(u8 word_en, u8 *sourdata,1007 u8 *targetdata)1008{1009 if (!(word_en & BIT(0))) {1010 targetdata[0] = sourdata[0];1011 targetdata[1] = sourdata[1];1012 }1013 1014 if (!(word_en & BIT(1))) {1015 targetdata[2] = sourdata[2];1016 targetdata[3] = sourdata[3];1017 }1018 1019 if (!(word_en & BIT(2))) {1020 targetdata[4] = sourdata[4];1021 targetdata[5] = sourdata[5];1022 }1023 1024 if (!(word_en & BIT(3))) {1025 targetdata[6] = sourdata[6];1026 targetdata[7] = sourdata[7];1027 }1028}1029 1030static u8 enable_efuse_data_write(struct ieee80211_hw *hw,1031 u16 efuse_addr, u8 word_en, u8 *data)1032{1033 struct rtl_priv *rtlpriv = rtl_priv(hw);1034 u16 tmpaddr;1035 u16 start_addr = efuse_addr;1036 u8 badworden = 0x0F;1037 u8 tmpdata[8];1038 1039 memset(tmpdata, 0xff, PGPKT_DATA_SIZE);1040 rtl_dbg(rtlpriv, COMP_EFUSE, DBG_LOUD,1041 "word_en = %x efuse_addr=%x\n", word_en, efuse_addr);1042 1043 if (!(word_en & BIT(0))) {1044 tmpaddr = start_addr;1045 efuse_one_byte_write(hw, start_addr++, data[0]);1046 efuse_one_byte_write(hw, start_addr++, data[1]);1047 1048 efuse_one_byte_read(hw, tmpaddr, &tmpdata[0]);1049 efuse_one_byte_read(hw, tmpaddr + 1, &tmpdata[1]);1050 if ((data[0] != tmpdata[0]) || (data[1] != tmpdata[1]))1051 badworden &= (~BIT(0));1052 }1053 1054 if (!(word_en & BIT(1))) {1055 tmpaddr = start_addr;1056 efuse_one_byte_write(hw, start_addr++, data[2]);1057 efuse_one_byte_write(hw, start_addr++, data[3]);1058 1059 efuse_one_byte_read(hw, tmpaddr, &tmpdata[2]);1060 efuse_one_byte_read(hw, tmpaddr + 1, &tmpdata[3]);1061 if ((data[2] != tmpdata[2]) || (data[3] != tmpdata[3]))1062 badworden &= (~BIT(1));1063 }1064 1065 if (!(word_en & BIT(2))) {1066 tmpaddr = start_addr;1067 efuse_one_byte_write(hw, start_addr++, data[4]);1068 efuse_one_byte_write(hw, start_addr++, data[5]);1069 1070 efuse_one_byte_read(hw, tmpaddr, &tmpdata[4]);1071 efuse_one_byte_read(hw, tmpaddr + 1, &tmpdata[5]);1072 if ((data[4] != tmpdata[4]) || (data[5] != tmpdata[5]))1073 badworden &= (~BIT(2));1074 }1075 1076 if (!(word_en & BIT(3))) {1077 tmpaddr = start_addr;1078 efuse_one_byte_write(hw, start_addr++, data[6]);1079 efuse_one_byte_write(hw, start_addr++, data[7]);1080 1081 efuse_one_byte_read(hw, tmpaddr, &tmpdata[6]);1082 efuse_one_byte_read(hw, tmpaddr + 1, &tmpdata[7]);1083 if ((data[6] != tmpdata[6]) || (data[7] != tmpdata[7]))1084 badworden &= (~BIT(3));1085 }1086 1087 return badworden;1088}1089 1090void efuse_power_switch(struct ieee80211_hw *hw, u8 write, u8 pwrstate)1091{1092 struct rtl_priv *rtlpriv = rtl_priv(hw);1093 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));1094 u8 tempval;1095 u16 tmpv16;1096 1097 if (pwrstate && (rtlhal->hw_type != HARDWARE_TYPE_RTL8192SE)) {1098 if (rtlhal->hw_type != HARDWARE_TYPE_RTL8192CE &&1099 rtlhal->hw_type != HARDWARE_TYPE_RTL8192DE) {1100 rtl_write_byte(rtlpriv,1101 rtlpriv->cfg->maps[EFUSE_ACCESS], 0x69);1102 } else {1103 tmpv16 =1104 rtl_read_word(rtlpriv,1105 rtlpriv->cfg->maps[SYS_ISO_CTRL]);1106 if (!(tmpv16 & rtlpriv->cfg->maps[EFUSE_PWC_EV12V])) {1107 tmpv16 |= rtlpriv->cfg->maps[EFUSE_PWC_EV12V];1108 rtl_write_word(rtlpriv,1109 rtlpriv->cfg->maps[SYS_ISO_CTRL],1110 tmpv16);1111 }1112 }1113 tmpv16 = rtl_read_word(rtlpriv,1114 rtlpriv->cfg->maps[SYS_FUNC_EN]);1115 if (!(tmpv16 & rtlpriv->cfg->maps[EFUSE_FEN_ELDR])) {1116 tmpv16 |= rtlpriv->cfg->maps[EFUSE_FEN_ELDR];1117 rtl_write_word(rtlpriv,1118 rtlpriv->cfg->maps[SYS_FUNC_EN], tmpv16);1119 }1120 1121 tmpv16 = rtl_read_word(rtlpriv, rtlpriv->cfg->maps[SYS_CLK]);1122 if ((!(tmpv16 & rtlpriv->cfg->maps[EFUSE_LOADER_CLK_EN])) ||1123 (!(tmpv16 & rtlpriv->cfg->maps[EFUSE_ANA8M]))) {1124 tmpv16 |= (rtlpriv->cfg->maps[EFUSE_LOADER_CLK_EN] |1125 rtlpriv->cfg->maps[EFUSE_ANA8M]);1126 rtl_write_word(rtlpriv,1127 rtlpriv->cfg->maps[SYS_CLK], tmpv16);1128 }1129 }1130 1131 if (pwrstate) {1132 if (write) {1133 tempval = rtl_read_byte(rtlpriv,1134 rtlpriv->cfg->maps[EFUSE_TEST] +1135 3);1136 1137 if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) {1138 tempval &= ~(BIT(3) | BIT(4) | BIT(5) | BIT(6));1139 tempval |= (VOLTAGE_V25 << 3);1140 } else if (rtlhal->hw_type != HARDWARE_TYPE_RTL8192SE) {1141 tempval &= 0x0F;1142 tempval |= (VOLTAGE_V25 << 4);1143 }1144 1145 rtl_write_byte(rtlpriv,1146 rtlpriv->cfg->maps[EFUSE_TEST] + 3,1147 (tempval | 0x80));1148 }1149 1150 if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) {1151 rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CLK],1152 0x03);1153 }1154 } else {1155 if (rtlhal->hw_type != HARDWARE_TYPE_RTL8192CE &&1156 rtlhal->hw_type != HARDWARE_TYPE_RTL8192DE)1157 rtl_write_byte(rtlpriv,1158 rtlpriv->cfg->maps[EFUSE_ACCESS], 0);1159 1160 if (write) {1161 tempval = rtl_read_byte(rtlpriv,1162 rtlpriv->cfg->maps[EFUSE_TEST] +1163 3);1164 rtl_write_byte(rtlpriv,1165 rtlpriv->cfg->maps[EFUSE_TEST] + 3,1166 (tempval & 0x7F));1167 }1168 1169 if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) {1170 rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CLK],1171 0x02);1172 }1173 }1174}1175EXPORT_SYMBOL(efuse_power_switch);1176 1177static u16 efuse_get_current_size(struct ieee80211_hw *hw)1178{1179 int continual = true;1180 u16 efuse_addr = 0;1181 u8 hworden;1182 u8 efuse_data, word_cnts;1183 1184 while (continual && efuse_one_byte_read(hw, efuse_addr, &efuse_data) &&1185 (efuse_addr < EFUSE_MAX_SIZE)) {1186 if (efuse_data != 0xFF) {1187 hworden = efuse_data & 0x0F;1188 word_cnts = efuse_calculate_word_cnts(hworden);1189 efuse_addr = efuse_addr + (word_cnts * 2) + 1;1190 } else {1191 continual = false;1192 }1193 }1194 1195 return efuse_addr;1196}1197 1198static u8 efuse_calculate_word_cnts(u8 word_en)1199{1200 u8 word_cnts = 0;1201 1202 if (!(word_en & BIT(0)))1203 word_cnts++;1204 if (!(word_en & BIT(1)))1205 word_cnts++;1206 if (!(word_en & BIT(2)))1207 word_cnts++;1208 if (!(word_en & BIT(3)))1209 word_cnts++;1210 return word_cnts;1211}1212 1213int rtl_get_hwinfo(struct ieee80211_hw *hw, struct rtl_priv *rtlpriv,1214 int max_size, u8 *hwinfo, const int *params)1215{1216 struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));1217 struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);1218 struct device *dev = &rtlpcipriv->dev.pdev->dev;1219 u16 eeprom_id;1220 u16 i, usvalue;1221 1222 switch (rtlefuse->epromtype) {1223 case EEPROM_BOOT_EFUSE:1224 rtl_efuse_shadow_map_update(hw);1225 break;1226 1227 case EEPROM_93C46:1228 pr_err("RTL8XXX did not boot from eeprom, check it !!\n");1229 return 1;1230 1231 default:1232 dev_warn(dev, "no efuse data\n");1233 return 1;1234 }1235 1236 memcpy(hwinfo, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0], max_size);1237 1238 RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, "MAP",1239 hwinfo, max_size);1240 1241 eeprom_id = *((u16 *)&hwinfo[0]);1242 if (eeprom_id != params[0]) {1243 rtl_dbg(rtlpriv, COMP_ERR, DBG_WARNING,1244 "EEPROM ID(%#x) is invalid!!\n", eeprom_id);1245 rtlefuse->autoload_failflag = true;1246 } else {1247 rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD, "Autoload OK\n");1248 rtlefuse->autoload_failflag = false;1249 }1250 1251 if (rtlefuse->autoload_failflag)1252 return 1;1253 1254 rtlefuse->eeprom_vid = *(u16 *)&hwinfo[params[1]];1255 rtlefuse->eeprom_did = *(u16 *)&hwinfo[params[2]];1256 rtlefuse->eeprom_svid = *(u16 *)&hwinfo[params[3]];1257 rtlefuse->eeprom_smid = *(u16 *)&hwinfo[params[4]];1258 rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD,1259 "EEPROMId = 0x%4x\n", eeprom_id);1260 rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD,1261 "EEPROM VID = 0x%4x\n", rtlefuse->eeprom_vid);1262 rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD,1263 "EEPROM DID = 0x%4x\n", rtlefuse->eeprom_did);1264 rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD,1265 "EEPROM SVID = 0x%4x\n", rtlefuse->eeprom_svid);1266 rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD,1267 "EEPROM SMID = 0x%4x\n", rtlefuse->eeprom_smid);1268 1269 for (i = 0; i < 6; i += 2) {1270 usvalue = *(u16 *)&hwinfo[params[5] + i];1271 *((u16 *)(&rtlefuse->dev_addr[i])) = usvalue;1272 }1273 rtl_dbg(rtlpriv, COMP_INIT, DBG_DMESG, "%pM\n", rtlefuse->dev_addr);1274 1275 rtlefuse->eeprom_channelplan = *&hwinfo[params[6]];1276 rtlefuse->eeprom_version = *(u16 *)&hwinfo[params[7]];1277 rtlefuse->txpwr_fromeprom = true;1278 rtlefuse->eeprom_oemid = *&hwinfo[params[8]];1279 1280 rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD,1281 "EEPROM Customer ID: 0x%2x\n", rtlefuse->eeprom_oemid);1282 1283 /* set channel plan to world wide 13 */1284 rtlefuse->channel_plan = params[9];1285 1286 return 0;1287}1288EXPORT_SYMBOL_GPL(rtl_get_hwinfo);1289 1290static void _rtl_fw_block_write_usb(struct ieee80211_hw *hw, u8 *buffer, u32 size)1291{1292 struct rtl_priv *rtlpriv = rtl_priv(hw);1293 u32 start = START_ADDRESS;1294 u32 n;1295 1296 while (size > 0) {1297 if (size >= 64)1298 n = 64;1299 else if (size >= 8)1300 n = 8;1301 else1302 n = 1;1303 1304 rtl_write_chunk(rtlpriv, start, n, buffer);1305 1306 start += n;1307 buffer += n;1308 size -= n;1309 }1310}1311 1312void rtl_fw_block_write(struct ieee80211_hw *hw, u8 *buffer, u32 size)1313{1314 struct rtl_priv *rtlpriv = rtl_priv(hw);1315 u32 i;1316 1317 if (rtlpriv->rtlhal.interface == INTF_PCI) {1318 for (i = 0; i < size; i++)1319 rtl_write_byte(rtlpriv, (START_ADDRESS + i),1320 *(buffer + i));1321 } else if (rtlpriv->rtlhal.interface == INTF_USB) {1322 _rtl_fw_block_write_usb(hw, buffer, size);1323 }1324}1325EXPORT_SYMBOL_GPL(rtl_fw_block_write);1326 1327void rtl_fw_page_write(struct ieee80211_hw *hw, u32 page, u8 *buffer,1328 u32 size)1329{1330 struct rtl_priv *rtlpriv = rtl_priv(hw);1331 u8 value8;1332 u8 u8page = (u8)(page & 0x07);1333 1334 value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page;1335 1336 rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8);1337 rtl_fw_block_write(hw, buffer, size);1338}1339EXPORT_SYMBOL_GPL(rtl_fw_page_write);1340 1341void rtl_fill_dummy(u8 *pfwbuf, u32 *pfwlen)1342{1343 u32 fwlen = *pfwlen;1344 u8 remain = (u8)(fwlen % 4);1345 1346 remain = (remain == 0) ? 0 : (4 - remain);1347 1348 while (remain > 0) {1349 pfwbuf[fwlen] = 0;1350 fwlen++;1351 remain--;1352 }1353 1354 *pfwlen = fwlen;1355}1356EXPORT_SYMBOL_GPL(rtl_fill_dummy);1357 1358void rtl_efuse_ops_init(struct ieee80211_hw *hw)1359{1360 struct rtl_priv *rtlpriv = rtl_priv(hw);1361 1362 rtlpriv->efuse.efuse_ops = &efuse_ops;1363}1364EXPORT_SYMBOL_GPL(rtl_efuse_ops_init);1365