fw_common.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. /******************************************************************************
  2. *
  3. * Copyright(c) 2009-2014 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. * The full GNU General Public License is included in this distribution in the
  15. * file called LICENSE.
  16. *
  17. * Contact Information:
  18. * wlanfae <wlanfae@realtek.com>
  19. * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
  20. * Hsinchu 300, Taiwan.
  21. *
  22. * Larry Finger <Larry.Finger@lwfinger.net>
  23. *
  24. *****************************************************************************/
  25. #include "../wifi.h"
  26. #include "../pci.h"
  27. #include "../base.h"
  28. #include "fw_common.h"
  29. #include <linux/module.h>
  30. void rtl8723_enable_fw_download(struct ieee80211_hw *hw, bool enable)
  31. {
  32. struct rtl_priv *rtlpriv = rtl_priv(hw);
  33. u8 tmp;
  34. if (enable) {
  35. tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
  36. rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1,
  37. tmp | 0x04);
  38. tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
  39. rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01);
  40. tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);
  41. rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);
  42. } else {
  43. tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
  44. rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);
  45. rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00);
  46. }
  47. }
  48. EXPORT_SYMBOL_GPL(rtl8723_enable_fw_download);
  49. void rtl8723_fw_block_write(struct ieee80211_hw *hw,
  50. const u8 *buffer, u32 size)
  51. {
  52. struct rtl_priv *rtlpriv = rtl_priv(hw);
  53. u32 blocksize = sizeof(u32);
  54. u8 *bufferptr = (u8 *)buffer;
  55. u32 *pu4byteptr = (u32 *)buffer;
  56. u32 i, offset, blockcount, remainsize;
  57. blockcount = size / blocksize;
  58. remainsize = size % blocksize;
  59. for (i = 0; i < blockcount; i++) {
  60. offset = i * blocksize;
  61. rtl_write_dword(rtlpriv, (FW_8192C_START_ADDRESS + offset),
  62. *(pu4byteptr + i));
  63. }
  64. if (remainsize) {
  65. offset = blockcount * blocksize;
  66. bufferptr += offset;
  67. for (i = 0; i < remainsize; i++) {
  68. rtl_write_byte(rtlpriv,
  69. (FW_8192C_START_ADDRESS + offset + i),
  70. *(bufferptr + i));
  71. }
  72. }
  73. }
  74. EXPORT_SYMBOL_GPL(rtl8723_fw_block_write);
  75. void rtl8723_fw_page_write(struct ieee80211_hw *hw,
  76. u32 page, const u8 *buffer, u32 size)
  77. {
  78. struct rtl_priv *rtlpriv = rtl_priv(hw);
  79. u8 value8;
  80. u8 u8page = (u8) (page & 0x07);
  81. value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page;
  82. rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8);
  83. rtl8723_fw_block_write(hw, buffer, size);
  84. }
  85. EXPORT_SYMBOL_GPL(rtl8723_fw_page_write);
  86. void rtl8723_fill_dummy(u8 *pfwbuf, u32 *pfwlen)
  87. {
  88. u32 fwlen = *pfwlen;
  89. u8 remain = (u8) (fwlen % 4);
  90. remain = (remain == 0) ? 0 : (4 - remain);
  91. while (remain > 0) {
  92. pfwbuf[fwlen] = 0;
  93. fwlen++;
  94. remain--;
  95. }
  96. *pfwlen = fwlen;
  97. }
  98. EXPORT_SYMBOL(rtl8723_fill_dummy);
  99. void rtl8723_write_fw(struct ieee80211_hw *hw,
  100. enum version_8723e version,
  101. u8 *buffer, u32 size, u8 max_page)
  102. {
  103. struct rtl_priv *rtlpriv = rtl_priv(hw);
  104. u8 *bufferptr = buffer;
  105. u32 page_nums, remain_size;
  106. u32 page, offset;
  107. RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "FW size is %d bytes,\n", size);
  108. rtl8723_fill_dummy(bufferptr, &size);
  109. page_nums = size / FW_8192C_PAGE_SIZE;
  110. remain_size = size % FW_8192C_PAGE_SIZE;
  111. if (page_nums > max_page) {
  112. RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
  113. "Page numbers should not greater than %d\n", max_page);
  114. }
  115. for (page = 0; page < page_nums; page++) {
  116. offset = page * FW_8192C_PAGE_SIZE;
  117. rtl8723_fw_page_write(hw, page, (bufferptr + offset),
  118. FW_8192C_PAGE_SIZE);
  119. }
  120. if (remain_size) {
  121. offset = page_nums * FW_8192C_PAGE_SIZE;
  122. page = page_nums;
  123. rtl8723_fw_page_write(hw, page, (bufferptr + offset),
  124. remain_size);
  125. }
  126. RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "FW write done.\n");
  127. }
  128. EXPORT_SYMBOL_GPL(rtl8723_write_fw);
  129. void rtl8723ae_firmware_selfreset(struct ieee80211_hw *hw)
  130. {
  131. u8 u1b_tmp;
  132. u8 delay = 100;
  133. struct rtl_priv *rtlpriv = rtl_priv(hw);
  134. rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20);
  135. u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
  136. while (u1b_tmp & BIT(2)) {
  137. delay--;
  138. if (delay == 0)
  139. break;
  140. udelay(50);
  141. u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
  142. }
  143. if (delay == 0) {
  144. u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
  145. rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1,
  146. u1b_tmp&(~BIT(2)));
  147. }
  148. }
  149. EXPORT_SYMBOL_GPL(rtl8723ae_firmware_selfreset);
  150. void rtl8723be_firmware_selfreset(struct ieee80211_hw *hw)
  151. {
  152. u8 u1b_tmp;
  153. struct rtl_priv *rtlpriv = rtl_priv(hw);
  154. u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1);
  155. rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, (u1b_tmp & (~BIT(0))));
  156. u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
  157. rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, (u1b_tmp & (~BIT(2))));
  158. udelay(50);
  159. u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1);
  160. rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, (u1b_tmp | BIT(0)));
  161. u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
  162. rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, (u1b_tmp | BIT(2)));
  163. RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
  164. " _8051Reset8723be(): 8051 reset success .\n");
  165. }
  166. EXPORT_SYMBOL_GPL(rtl8723be_firmware_selfreset);
  167. int rtl8723_fw_free_to_go(struct ieee80211_hw *hw, bool is_8723be,
  168. int max_count)
  169. {
  170. struct rtl_priv *rtlpriv = rtl_priv(hw);
  171. int err = -EIO;
  172. u32 counter = 0;
  173. u32 value32;
  174. do {
  175. value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
  176. } while ((counter++ < max_count) &&
  177. (!(value32 & FWDL_CHKSUM_RPT)));
  178. if (counter >= max_count) {
  179. RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
  180. "chksum report fail ! REG_MCUFWDL:0x%08x .\n",
  181. value32);
  182. goto exit;
  183. }
  184. RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
  185. "Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32);
  186. value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL) | MCUFWDL_RDY;
  187. value32 &= ~WINTINI_RDY;
  188. rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
  189. if (is_8723be)
  190. rtl8723be_firmware_selfreset(hw);
  191. counter = 0;
  192. do {
  193. value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
  194. if (value32 & WINTINI_RDY) {
  195. RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
  196. "Polling FW ready success!! REG_MCUFWDL:0x%08x .\n",
  197. value32);
  198. err = 0;
  199. goto exit;
  200. }
  201. mdelay(FW_8192C_POLLING_DELAY);
  202. } while (counter++ < max_count);
  203. RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
  204. "Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n",
  205. value32);
  206. exit:
  207. return err;
  208. }
  209. EXPORT_SYMBOL_GPL(rtl8723_fw_free_to_go);
  210. int rtl8723_download_fw(struct ieee80211_hw *hw,
  211. bool is_8723be, int max_count)
  212. {
  213. struct rtl_priv *rtlpriv = rtl_priv(hw);
  214. struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
  215. struct rtl8723e_firmware_header *pfwheader;
  216. u8 *pfwdata;
  217. u32 fwsize;
  218. int err;
  219. enum version_8723e version = rtlhal->version;
  220. int max_page;
  221. if (!rtlhal->pfirmware)
  222. return 1;
  223. pfwheader = (struct rtl8723e_firmware_header *)rtlhal->pfirmware;
  224. pfwdata = rtlhal->pfirmware;
  225. fwsize = rtlhal->fwsize;
  226. if (!is_8723be)
  227. max_page = 6;
  228. else
  229. max_page = 8;
  230. if (rtlpriv->cfg->ops->is_fw_header(pfwheader)) {
  231. RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
  232. "Firmware Version(%d), Signature(%#x), Size(%d)\n",
  233. pfwheader->version, pfwheader->signature,
  234. (int)sizeof(struct rtl8723e_firmware_header));
  235. pfwdata = pfwdata + sizeof(struct rtl8723e_firmware_header);
  236. fwsize = fwsize - sizeof(struct rtl8723e_firmware_header);
  237. }
  238. if (rtl_read_byte(rtlpriv, REG_MCUFWDL)&BIT(7)) {
  239. if (is_8723be)
  240. rtl8723be_firmware_selfreset(hw);
  241. else
  242. rtl8723ae_firmware_selfreset(hw);
  243. rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00);
  244. }
  245. rtl8723_enable_fw_download(hw, true);
  246. rtl8723_write_fw(hw, version, pfwdata, fwsize, max_page);
  247. rtl8723_enable_fw_download(hw, false);
  248. err = rtl8723_fw_free_to_go(hw, is_8723be, max_count);
  249. if (err) {
  250. RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
  251. "Firmware is not ready to run!\n");
  252. } else {
  253. RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
  254. "Firmware is ready to run!\n");
  255. }
  256. return 0;
  257. }
  258. EXPORT_SYMBOL_GPL(rtl8723_download_fw);
  259. bool rtl8723_cmd_send_packet(struct ieee80211_hw *hw,
  260. struct sk_buff *skb)
  261. {
  262. struct rtl_priv *rtlpriv = rtl_priv(hw);
  263. struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
  264. struct rtl8192_tx_ring *ring;
  265. struct rtl_tx_desc *pdesc;
  266. struct sk_buff *pskb = NULL;
  267. u8 own;
  268. unsigned long flags;
  269. ring = &rtlpci->tx_ring[BEACON_QUEUE];
  270. pskb = __skb_dequeue(&ring->queue);
  271. if (pskb)
  272. kfree_skb(pskb);
  273. spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
  274. pdesc = &ring->desc[0];
  275. own = (u8) rtlpriv->cfg->ops->get_desc((u8 *)pdesc, true, HW_DESC_OWN);
  276. rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *)pdesc, 1, 1, skb);
  277. __skb_queue_tail(&ring->queue, skb);
  278. spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
  279. rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE);
  280. return true;
  281. }
  282. EXPORT_SYMBOL_GPL(rtl8723_cmd_send_packet);