1d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar/****************************************************************************** 2d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar * 3d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar * Copyright(c) 2009-2013 Realtek Corporation. 4d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar * 5d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar * This program is free software; you can redistribute it and/or modify it 6d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar * under the terms of version 2 of the GNU General Public License as 7d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar * published by the Free Software Foundation. 8d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar * 9d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar * This program is distributed in the hope that it will be useful, but WITHOUT 10d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar * more details. 13d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar * 14d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar * You should have received a copy of the GNU General Public License along with 15d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar * this program; if not, write to the Free Software Foundation, Inc., 16d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA 17d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar * 18d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar * The full GNU General Public License is included in this distribution in the 19d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar * file called LICENSE. 20d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar * 21d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar * Contact Information: 22d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar * wlanfae <wlanfae@realtek.com> 23d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, 24d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar * Hsinchu 300, Taiwan. 25d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar * 26d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar * Larry Finger <Larry.Finger@lwfinger.net> 27d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar * 28d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar *****************************************************************************/ 29d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar 30d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar#include "fw.h" 31d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar#include "drv_types.h" 32d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar#include "usb_ops_linux.h" 33d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar#include "rtl8188e_spec.h" 34d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar#include "rtl8188e_hal.h" 35d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar 36d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar#include <linux/firmware.h> 37d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar#include <linux/kmemleak.h> 38d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar 39d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidarstatic void _rtl88e_enable_fw_download(struct adapter *adapt, bool enable) 40d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar{ 41d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar u8 tmp; 42d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar 43d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar if (enable) { 44d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar tmp = usb_read8(adapt, REG_MCUFWDL); 45d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar usb_write8(adapt, REG_MCUFWDL, tmp | 0x01); 46d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar 47d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar tmp = usb_read8(adapt, REG_MCUFWDL + 2); 48d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar usb_write8(adapt, REG_MCUFWDL + 2, tmp & 0xf7); 49d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar } else { 50d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar tmp = usb_read8(adapt, REG_MCUFWDL); 51d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar usb_write8(adapt, REG_MCUFWDL, tmp & 0xfe); 52d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar 53d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar usb_write8(adapt, REG_MCUFWDL + 1, 0x00); 54d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar } 55d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar} 56d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar 57d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidarstatic void _rtl88e_fw_block_write(struct adapter *adapt, 58d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar const u8 *buffer, u32 size) 59d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar{ 60d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar u32 blk_sz = sizeof(u32); 61d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar u8 *buf_ptr = (u8 *)buffer; 62d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar u32 *pu4BytePtr = (u32 *)buffer; 63d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar u32 i, offset, blk_cnt, remain; 64d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar 65d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar blk_cnt = size / blk_sz; 66d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar remain = size % blk_sz; 67d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar 68d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar for (i = 0; i < blk_cnt; i++) { 69d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar offset = i * blk_sz; 70d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar usb_write32(adapt, (FW_8192C_START_ADDRESS + offset), 71d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar *(pu4BytePtr + i)); 72d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar } 73d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar 74d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar if (remain) { 75d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar offset = blk_cnt * blk_sz; 76d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar buf_ptr += offset; 77d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar for (i = 0; i < remain; i++) { 78d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar usb_write8(adapt, (FW_8192C_START_ADDRESS + 79d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar offset + i), *(buf_ptr + i)); 80d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar } 81d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar } 82d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar} 83d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar 84d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidarstatic void _rtl88e_fill_dummy(u8 *pfwbuf, u32 *pfwlen) 85d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar{ 86d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar u32 fwlen = *pfwlen; 87d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar u8 remain = (u8) (fwlen % 4); 88d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar 89d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar remain = (remain == 0) ? 0 : (4 - remain); 90d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar 91d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar while (remain > 0) { 92d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar pfwbuf[fwlen] = 0; 93d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar fwlen++; 94d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar remain--; 95d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar } 96d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar 97d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar *pfwlen = fwlen; 98d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar} 99d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar 100d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidarstatic void _rtl88e_fw_page_write(struct adapter *adapt, 101d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar u32 page, const u8 *buffer, u32 size) 102d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar{ 103d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar u8 value8; 104d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar u8 u8page = (u8) (page & 0x07); 105d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar 106d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar value8 = (usb_read8(adapt, REG_MCUFWDL + 2) & 0xF8) | u8page; 107d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar 108d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar usb_write8(adapt, (REG_MCUFWDL + 2), value8); 109d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar _rtl88e_fw_block_write(adapt, buffer, size); 110d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar} 111d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar 112d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidarstatic void _rtl88e_write_fw(struct adapter *adapt, u8 *buffer, u32 size) 113d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar{ 114d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar u8 *buf_ptr = buffer; 115d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar u32 page_no, remain; 116d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar u32 page, offset; 117d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar 118d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar _rtl88e_fill_dummy(buf_ptr, &size); 119d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar 120d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar page_no = size / FW_8192C_PAGE_SIZE; 121d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar remain = size % FW_8192C_PAGE_SIZE; 122d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar 123d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar for (page = 0; page < page_no; page++) { 124d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar offset = page * FW_8192C_PAGE_SIZE; 125d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar _rtl88e_fw_page_write(adapt, page, (buf_ptr + offset), 126d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar FW_8192C_PAGE_SIZE); 127d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar } 128d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar 129d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar if (remain) { 130d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar offset = page_no * FW_8192C_PAGE_SIZE; 131d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar page = page_no; 132d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar _rtl88e_fw_page_write(adapt, page, (buf_ptr + offset), remain); 133d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar } 134d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar} 135d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar 136d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidarstatic void rtl88e_firmware_selfreset(struct adapter *adapt) 137d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar{ 138d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar u8 u1b_tmp; 139d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar 140d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar u1b_tmp = usb_read8(adapt, REG_SYS_FUNC_EN+1); 141d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar usb_write8(adapt, REG_SYS_FUNC_EN+1, (u1b_tmp & (~BIT(2)))); 142d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar usb_write8(adapt, REG_SYS_FUNC_EN+1, (u1b_tmp | BIT(2))); 143d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar} 144d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar 145d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidarstatic int _rtl88e_fw_free_to_go(struct adapter *adapt) 146d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar{ 147d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar int err = -EIO; 148d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar u32 counter = 0; 149d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar u32 value32; 150d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar 151d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar do { 152d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar value32 = usb_read32(adapt, REG_MCUFWDL); 153d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar if (value32 & FWDL_ChkSum_rpt) 154d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar break; 155d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar } while (counter++ < POLLING_READY_TIMEOUT_COUNT); 156d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar 157d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar if (counter >= POLLING_READY_TIMEOUT_COUNT) { 158d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar goto exit; 159d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar } 160d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar 161d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar value32 = usb_read32(adapt, REG_MCUFWDL); 162d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar value32 |= MCUFWDL_RDY; 163d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar value32 &= ~WINTINI_RDY; 164d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar usb_write32(adapt, REG_MCUFWDL, value32); 165d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar 166d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar rtl88e_firmware_selfreset(adapt); 167d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar counter = 0; 168d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar 169d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar do { 170d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar value32 = usb_read32(adapt, REG_MCUFWDL); 171d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar if (value32 & WINTINI_RDY) { 172d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar err = 0; 173d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar goto exit; 174d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar } 175d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar 176d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar udelay(FW_8192C_POLLING_DELAY); 177d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar 178d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar } while (counter++ < POLLING_READY_TIMEOUT_COUNT); 179d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar 180d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidarexit: 181d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar return err; 182d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar} 183d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar 18490d88de82cd83852cb5b42f9c0a82708b111a59bStephen Rothwellint rtl88eu_download_fw(struct adapter *adapt) 185d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar{ 186d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar struct hal_data_8188e *rtlhal = GET_HAL_DATA(adapt); 187d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar struct dvobj_priv *dvobj = adapter_to_dvobj(adapt); 188d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar struct device *device = dvobj_to_dev(dvobj); 189d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar const struct firmware *fw; 190d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar const char fw_name[] = "rtlwifi/rtl8188eufw.bin"; 191d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar struct rtl92c_firmware_header *pfwheader = NULL; 192d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar u8 *pfwdata; 193d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar u32 fwsize; 194d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar int err; 195d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar 196d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar if (request_firmware(&fw, fw_name, device)){ 197d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar dev_err(device, "Firmware %s not available\n", fw_name); 198d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar return -ENOENT; 199d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar } 200d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar 201d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar if (fw->size > FW_8188E_SIZE) { 202d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar dev_err(device,"Firmware size exceed 0x%X. Check it.\n", 203d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar FW_8188E_SIZE); 204d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar return -1; 205d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar } 206d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar 207d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar pfwdata = kzalloc(FW_8188E_SIZE, GFP_KERNEL); 208d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar if (!pfwdata) 209d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar return -ENOMEM; 210d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar 211d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar rtlhal->pfirmware = pfwdata; 212d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar memcpy(rtlhal->pfirmware, fw->data, fw->size); 213d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar rtlhal->fwsize = fw->size; 214d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar release_firmware(fw); 215d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar 216d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar fwsize = rtlhal->fwsize; 217d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar pfwheader = (struct rtl92c_firmware_header *)pfwdata; 218d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar 219d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar if (IS_FW_HEADER_EXIST(pfwheader)) { 220d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar pfwdata = pfwdata + 32; 221d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar fwsize = fwsize - 32; 222d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar } 223d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar 224d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar if (usb_read8(adapt, REG_MCUFWDL) & RAM_DL_SEL) { 225d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar usb_write8(adapt, REG_MCUFWDL, 0); 226d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar rtl88e_firmware_selfreset(adapt); 227d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar } 228d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar _rtl88e_enable_fw_download(adapt, true); 229d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar usb_write8(adapt, REG_MCUFWDL, usb_read8(adapt, REG_MCUFWDL) | FWDL_ChkSum_rpt); 230d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar _rtl88e_write_fw(adapt, pfwdata, fwsize); 231d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar _rtl88e_enable_fw_download(adapt, false); 232d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar 233d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar err = _rtl88e_fw_free_to_go(adapt); 234d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar 235d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar return err; 236d6c28c23f89b00a01b34670f0f1ddcdc2e0bca67navin patidar} 237