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