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