PageRenderTime 229ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 1ms

/drivers/staging/rtl8712/rtl8712_efuse.c

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