1 /******************************************************************************
3 * Copyright(c) 2009-2013 Realtek Corporation.
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.
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
14 * The full GNU General Public License is included in this distribution in the
15 * file called LICENSE.
17 * Contact Information:
18 * wlanfae <wlanfae@realtek.com>
19 * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
20 * Hsinchu 300, Taiwan.
22 * Larry Finger <Larry.Finger@lwfinger.net>
24 *****************************************************************************/
27 #include "drv_types.h"
28 #include "usb_ops_linux.h"
29 #include "rtl8188e_spec.h"
30 #include "rtl8188e_hal.h"
32 #include <linux/firmware.h>
33 #include <linux/kmemleak.h>
35 static void _rtl88e_enable_fw_download(struct adapter *adapt, bool enable)
40 tmp = usb_read8(adapt, REG_MCUFWDL);
41 usb_write8(adapt, REG_MCUFWDL, tmp | 0x01);
43 tmp = usb_read8(adapt, REG_MCUFWDL + 2);
44 usb_write8(adapt, REG_MCUFWDL + 2, tmp & 0xf7);
46 tmp = usb_read8(adapt, REG_MCUFWDL);
47 usb_write8(adapt, REG_MCUFWDL, tmp & 0xfe);
49 usb_write8(adapt, REG_MCUFWDL + 1, 0x00);
53 static void _rtl88e_fw_block_write(struct adapter *adapt,
54 const u8 *buffer, u32 size)
56 u32 blk_sz = sizeof(u32);
57 const u8 *byte_buffer;
58 const u32 *dword_buffer = (u32 *)buffer;
59 u32 i, write_address, blk_cnt, remain;
61 blk_cnt = size / blk_sz;
62 remain = size % blk_sz;
64 write_address = FW_8192C_START_ADDRESS;
66 for (i = 0; i < blk_cnt; i++, write_address += blk_sz)
67 usb_write32(adapt, write_address, dword_buffer[i]);
69 byte_buffer = buffer + blk_cnt * blk_sz;
70 for (i = 0; i < remain; i++, write_address++)
71 usb_write8(adapt, write_address, byte_buffer[i]);
74 static void _rtl88e_fw_page_write(struct adapter *adapt,
75 u32 page, const u8 *buffer, u32 size)
78 u8 u8page = (u8)(page & 0x07);
80 value8 = (usb_read8(adapt, REG_MCUFWDL + 2) & 0xF8) | u8page;
82 usb_write8(adapt, (REG_MCUFWDL + 2), value8);
83 _rtl88e_fw_block_write(adapt, buffer, size);
86 static void _rtl88e_write_fw(struct adapter *adapt, u8 *buffer, u32 size)
92 page_no = size / FW_8192C_PAGE_SIZE;
93 remain = size % FW_8192C_PAGE_SIZE;
95 for (page = 0; page < page_no; page++) {
96 offset = page * FW_8192C_PAGE_SIZE;
97 _rtl88e_fw_page_write(adapt, page, (buf_ptr + offset),
102 offset = page_no * FW_8192C_PAGE_SIZE;
104 _rtl88e_fw_page_write(adapt, page, (buf_ptr + offset), remain);
108 static void rtl88e_firmware_selfreset(struct adapter *adapt)
112 u1b_tmp = usb_read8(adapt, REG_SYS_FUNC_EN+1);
113 usb_write8(adapt, REG_SYS_FUNC_EN+1, (u1b_tmp & (~BIT(2))));
114 usb_write8(adapt, REG_SYS_FUNC_EN+1, (u1b_tmp | BIT(2)));
117 static int _rtl88e_fw_free_to_go(struct adapter *adapt)
124 value32 = usb_read32(adapt, REG_MCUFWDL);
125 if (value32 & FWDL_ChkSum_rpt)
127 } while (counter++ < POLLING_READY_TIMEOUT_COUNT);
129 if (counter >= POLLING_READY_TIMEOUT_COUNT)
132 value32 = usb_read32(adapt, REG_MCUFWDL);
133 value32 |= MCUFWDL_RDY;
134 value32 &= ~WINTINI_RDY;
135 usb_write32(adapt, REG_MCUFWDL, value32);
137 rtl88e_firmware_selfreset(adapt);
141 value32 = usb_read32(adapt, REG_MCUFWDL);
142 if (value32 & WINTINI_RDY) {
147 udelay(FW_8192C_POLLING_DELAY);
149 } while (counter++ < POLLING_READY_TIMEOUT_COUNT);
155 int rtl88eu_download_fw(struct adapter *adapt)
157 struct dvobj_priv *dvobj = adapter_to_dvobj(adapt);
158 struct device *device = dvobj_to_dev(dvobj);
159 const struct firmware *fw;
160 const char fw_name[] = "/*(DEBLOBBED)*/";
161 struct rtl92c_firmware_header *pfwheader = NULL;
162 u8 *download_data, *fw_data;
163 size_t download_size;
164 unsigned int trailing_zeros_length;
166 if (reject_firmware(&fw, fw_name, device)) {
167 dev_err(device, "Firmware %s not available\n", fw_name);
171 if (fw->size > FW_8188E_SIZE) {
172 dev_err(device, "Firmware size exceed 0x%X. Check it.\n",
174 release_firmware(fw);
178 trailing_zeros_length = (4 - fw->size % 4) % 4;
180 fw_data = kmalloc(fw->size + trailing_zeros_length, GFP_KERNEL);
182 release_firmware(fw);
186 memcpy(fw_data, fw->data, fw->size);
187 memset(fw_data + fw->size, 0, trailing_zeros_length);
189 pfwheader = (struct rtl92c_firmware_header *)fw_data;
191 if (IS_FW_HEADER_EXIST(pfwheader)) {
192 download_data = fw_data + 32;
193 download_size = fw->size + trailing_zeros_length - 32;
195 download_data = fw_data;
196 download_size = fw->size + trailing_zeros_length;
199 release_firmware(fw);
201 if (usb_read8(adapt, REG_MCUFWDL) & RAM_DL_SEL) {
202 usb_write8(adapt, REG_MCUFWDL, 0);
203 rtl88e_firmware_selfreset(adapt);
205 _rtl88e_enable_fw_download(adapt, true);
206 usb_write8(adapt, REG_MCUFWDL, usb_read8(adapt, REG_MCUFWDL) | FWDL_ChkSum_rpt);
207 _rtl88e_write_fw(adapt, download_data, download_size);
208 _rtl88e_enable_fw_download(adapt, false);
211 return _rtl88e_fw_free_to_go(adapt);