rtw_eeprom.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. /******************************************************************************
  2. *
  3. * Copyright(c) 2007 - 2017 Realtek Corporation.
  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_EEPROM_C_
  16. #include <drv_conf.h>
  17. #include <osdep_service.h>
  18. #include <drv_types.h>
  19. void up_clk(_adapter *padapter, u16 *x)
  20. {
  21. *x = *x | _EESK;
  22. rtw_write8(padapter, EE_9346CR, (u8)*x);
  23. rtw_udelay_os(CLOCK_RATE);
  24. }
  25. void down_clk(_adapter *padapter, u16 *x)
  26. {
  27. *x = *x & ~_EESK;
  28. rtw_write8(padapter, EE_9346CR, (u8)*x);
  29. rtw_udelay_os(CLOCK_RATE);
  30. }
  31. void shift_out_bits(_adapter *padapter, u16 data, u16 count)
  32. {
  33. u16 x, mask;
  34. if (rtw_is_surprise_removed(padapter)) {
  35. goto out;
  36. }
  37. mask = 0x01 << (count - 1);
  38. x = rtw_read8(padapter, EE_9346CR);
  39. x &= ~(_EEDO | _EEDI);
  40. do {
  41. x &= ~_EEDI;
  42. if (data & mask)
  43. x |= _EEDI;
  44. if (rtw_is_surprise_removed(padapter)) {
  45. goto out;
  46. }
  47. rtw_write8(padapter, EE_9346CR, (u8)x);
  48. rtw_udelay_os(CLOCK_RATE);
  49. up_clk(padapter, &x);
  50. down_clk(padapter, &x);
  51. mask = mask >> 1;
  52. } while (mask);
  53. if (rtw_is_surprise_removed(padapter)) {
  54. goto out;
  55. }
  56. x &= ~_EEDI;
  57. rtw_write8(padapter, EE_9346CR, (u8)x);
  58. out:
  59. return;
  60. }
  61. u16 shift_in_bits(_adapter *padapter)
  62. {
  63. u16 x, d = 0, i;
  64. if (rtw_is_surprise_removed(padapter)) {
  65. goto out;
  66. }
  67. x = rtw_read8(padapter, EE_9346CR);
  68. x &= ~(_EEDO | _EEDI);
  69. d = 0;
  70. for (i = 0; i < 16; i++) {
  71. d = d << 1;
  72. up_clk(padapter, &x);
  73. if (rtw_is_surprise_removed(padapter)) {
  74. goto out;
  75. }
  76. x = rtw_read8(padapter, EE_9346CR);
  77. x &= ~(_EEDI);
  78. if (x & _EEDO)
  79. d |= 1;
  80. down_clk(padapter, &x);
  81. }
  82. out:
  83. return d;
  84. }
  85. void standby(_adapter *padapter)
  86. {
  87. u8 x;
  88. x = rtw_read8(padapter, EE_9346CR);
  89. x &= ~(_EECS | _EESK);
  90. rtw_write8(padapter, EE_9346CR, x);
  91. rtw_udelay_os(CLOCK_RATE);
  92. x |= _EECS;
  93. rtw_write8(padapter, EE_9346CR, x);
  94. rtw_udelay_os(CLOCK_RATE);
  95. }
  96. u16 wait_eeprom_cmd_done(_adapter *padapter)
  97. {
  98. u8 x;
  99. u16 i, res = _FALSE;
  100. standby(padapter);
  101. for (i = 0; i < 200; i++) {
  102. x = rtw_read8(padapter, EE_9346CR);
  103. if (x & _EEDO) {
  104. res = _TRUE;
  105. goto exit;
  106. }
  107. rtw_udelay_os(CLOCK_RATE);
  108. }
  109. exit:
  110. return res;
  111. }
  112. void eeprom_clean(_adapter *padapter)
  113. {
  114. u16 x;
  115. if (rtw_is_surprise_removed(padapter)) {
  116. goto out;
  117. }
  118. x = rtw_read8(padapter, EE_9346CR);
  119. if (rtw_is_surprise_removed(padapter)) {
  120. goto out;
  121. }
  122. x &= ~(_EECS | _EEDI);
  123. rtw_write8(padapter, EE_9346CR, (u8)x);
  124. if (rtw_is_surprise_removed(padapter)) {
  125. goto out;
  126. }
  127. up_clk(padapter, &x);
  128. if (rtw_is_surprise_removed(padapter)) {
  129. goto out;
  130. }
  131. down_clk(padapter, &x);
  132. out:
  133. return;
  134. }
  135. void eeprom_write16(_adapter *padapter, u16 reg, u16 data)
  136. {
  137. u8 x;
  138. #ifdef CONFIG_RTL8712
  139. u8 tmp8_ori, tmp8_new, tmp8_clk_ori, tmp8_clk_new;
  140. tmp8_ori = rtw_read8(padapter, 0x102502f1);
  141. tmp8_new = tmp8_ori & 0xf7;
  142. if (tmp8_ori != tmp8_new) {
  143. rtw_write8(padapter, 0x102502f1, tmp8_new);
  144. }
  145. tmp8_clk_ori = rtw_read8(padapter, 0x10250003);
  146. tmp8_clk_new = tmp8_clk_ori | 0x20;
  147. if (tmp8_clk_new != tmp8_clk_ori) {
  148. rtw_write8(padapter, 0x10250003, tmp8_clk_new);
  149. }
  150. #endif
  151. x = rtw_read8(padapter, EE_9346CR);
  152. x &= ~(_EEDI | _EEDO | _EESK | _EEM0);
  153. x |= _EEM1 | _EECS;
  154. rtw_write8(padapter, EE_9346CR, x);
  155. shift_out_bits(padapter, EEPROM_EWEN_OPCODE, 5);
  156. if (padapter->EepromAddressSize == 8) /* CF+ and SDIO */
  157. shift_out_bits(padapter, 0, 6);
  158. else /* USB */
  159. shift_out_bits(padapter, 0, 4);
  160. standby(padapter);
  161. /* Commented out by rcnjko, 2004.0
  162. * Erase this particular word. Write the erase opcode and register
  163. * number in that order. The opcode is 3bits in length; reg is 6 bits long. */
  164. /* shift_out_bits(Adapter, EEPROM_ERASE_OPCODE, 3);
  165. * shift_out_bits(Adapter, reg, Adapter->EepromAddressSize);
  166. *
  167. * if (wait_eeprom_cmd_done(Adapter ) == FALSE)
  168. * {
  169. * return;
  170. * } */
  171. standby(padapter);
  172. /* write the new word to the EEPROM */
  173. /* send the write opcode the EEPORM */
  174. shift_out_bits(padapter, EEPROM_WRITE_OPCODE, 3);
  175. /* select which word in the EEPROM that we are writing to. */
  176. shift_out_bits(padapter, reg, padapter->EepromAddressSize);
  177. /* write the data to the selected EEPROM word. */
  178. shift_out_bits(padapter, data, 16);
  179. if (wait_eeprom_cmd_done(padapter) == _FALSE)
  180. goto exit;
  181. standby(padapter);
  182. shift_out_bits(padapter, EEPROM_EWDS_OPCODE, 5);
  183. shift_out_bits(padapter, reg, 4);
  184. eeprom_clean(padapter);
  185. exit:
  186. #ifdef CONFIG_RTL8712
  187. if (tmp8_clk_new != tmp8_clk_ori)
  188. rtw_write8(padapter, 0x10250003, tmp8_clk_ori);
  189. if (tmp8_new != tmp8_ori)
  190. rtw_write8(padapter, 0x102502f1, tmp8_ori);
  191. #endif
  192. return;
  193. }
  194. u16 eeprom_read16(_adapter *padapter, u16 reg) /* ReadEEprom */
  195. {
  196. u16 x;
  197. u16 data = 0;
  198. #ifdef CONFIG_RTL8712
  199. u8 tmp8_ori, tmp8_new, tmp8_clk_ori, tmp8_clk_new;
  200. tmp8_ori = rtw_read8(padapter, 0x102502f1);
  201. tmp8_new = tmp8_ori & 0xf7;
  202. if (tmp8_ori != tmp8_new) {
  203. rtw_write8(padapter, 0x102502f1, tmp8_new);
  204. }
  205. tmp8_clk_ori = rtw_read8(padapter, 0x10250003);
  206. tmp8_clk_new = tmp8_clk_ori | 0x20;
  207. if (tmp8_clk_new != tmp8_clk_ori) {
  208. rtw_write8(padapter, 0x10250003, tmp8_clk_new);
  209. }
  210. #endif
  211. if (rtw_is_surprise_removed(padapter)) {
  212. goto out;
  213. }
  214. /* select EEPROM, reset bits, set _EECS */
  215. x = rtw_read8(padapter, EE_9346CR);
  216. if (rtw_is_surprise_removed(padapter)) {
  217. goto out;
  218. }
  219. x &= ~(_EEDI | _EEDO | _EESK | _EEM0);
  220. x |= _EEM1 | _EECS;
  221. rtw_write8(padapter, EE_9346CR, (unsigned char)x);
  222. /* write the read opcode and register number in that order */
  223. /* The opcode is 3bits in length, reg is 6 bits long */
  224. shift_out_bits(padapter, EEPROM_READ_OPCODE, 3);
  225. shift_out_bits(padapter, reg, padapter->EepromAddressSize);
  226. /* Now read the data (16 bits) in from the selected EEPROM word */
  227. data = shift_in_bits(padapter);
  228. eeprom_clean(padapter);
  229. out:
  230. #ifdef CONFIG_RTL8712
  231. if (tmp8_clk_new != tmp8_clk_ori)
  232. rtw_write8(padapter, 0x10250003, tmp8_clk_ori);
  233. if (tmp8_new != tmp8_ori)
  234. rtw_write8(padapter, 0x102502f1, tmp8_ori);
  235. #endif
  236. return data;
  237. }
  238. /* From even offset */
  239. void eeprom_read_sz(_adapter *padapter, u16 reg, u8 *data, u32 sz)
  240. {
  241. u16 x, data16;
  242. u32 i;
  243. if (rtw_is_surprise_removed(padapter)) {
  244. goto out;
  245. }
  246. /* select EEPROM, reset bits, set _EECS */
  247. x = rtw_read8(padapter, EE_9346CR);
  248. if (rtw_is_surprise_removed(padapter)) {
  249. goto out;
  250. }
  251. x &= ~(_EEDI | _EEDO | _EESK | _EEM0);
  252. x |= _EEM1 | _EECS;
  253. rtw_write8(padapter, EE_9346CR, (unsigned char)x);
  254. /* write the read opcode and register number in that order */
  255. /* The opcode is 3bits in length, reg is 6 bits long */
  256. shift_out_bits(padapter, EEPROM_READ_OPCODE, 3);
  257. shift_out_bits(padapter, reg, padapter->EepromAddressSize);
  258. for (i = 0; i < sz; i += 2) {
  259. data16 = shift_in_bits(padapter);
  260. data[i] = data16 & 0xff;
  261. data[i + 1] = data16 >> 8;
  262. }
  263. eeprom_clean(padapter);
  264. out:
  265. return;
  266. }
  267. /* addr_off : address offset of the entry in eeprom (not the tuple number of eeprom (reg); that is addr_off !=reg) */
  268. u8 eeprom_read(_adapter *padapter, u32 addr_off, u8 sz, u8 *rbuf)
  269. {
  270. u8 quotient, remainder, addr_2align_odd;
  271. u16 reg, stmp , i = 0, idx = 0;
  272. reg = (u16)(addr_off >> 1);
  273. addr_2align_odd = (u8)(addr_off & 0x1);
  274. if (addr_2align_odd) { /* read that start at high part: e.g 1,3,5,7,9,... */
  275. stmp = eeprom_read16(padapter, reg);
  276. rbuf[idx++] = (u8)((stmp >> 8) & 0xff); /* return hogh-part of the short */
  277. reg++;
  278. sz--;
  279. }
  280. quotient = sz >> 1;
  281. remainder = sz & 0x1;
  282. for (i = 0 ; i < quotient; i++) {
  283. stmp = eeprom_read16(padapter, reg + i);
  284. rbuf[idx++] = (u8)(stmp & 0xff);
  285. rbuf[idx++] = (u8)((stmp >> 8) & 0xff);
  286. }
  287. reg = reg + i;
  288. if (remainder) { /* end of read at lower part of short : 0,2,4,6,... */
  289. stmp = eeprom_read16(padapter, reg);
  290. rbuf[idx] = (u8)(stmp & 0xff);
  291. }
  292. return _TRUE;
  293. }
  294. VOID read_eeprom_content(_adapter *padapter)
  295. {
  296. }