Commit | Line | Data |
---|---|---|
94a79942 LF |
1 | /****************************************************************************** |
2 | * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. | |
3 | * | |
4 | * This program is distributed in the hope that it will be useful, but WITHOUT | |
5 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
6 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
7 | * more details. | |
8 | * | |
9 | * You should have received a copy of the GNU General Public License along with | |
10 | * this program; if not, write to the Free Software Foundation, Inc., | |
11 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA | |
12 | * | |
13 | * The full GNU General Public License is included in this distribution in the | |
14 | * file called LICENSE. | |
15 | * | |
16 | * Contact Information: | |
17 | * wlanfae <wlanfae@realtek.com> | |
18 | ******************************************************************************/ | |
19 | ||
94a79942 LF |
20 | #include "rtl_core.h" |
21 | #include "r8192E_hw.h" | |
94a79942 | 22 | #include "r8192E_hwimg.h" |
94a79942 | 23 | #include "r8192E_firmware.h" |
94a79942 | 24 | #include <linux/firmware.h> |
94a79942 | 25 | |
16362f45 | 26 | void rtl92e_init_fw_param(struct net_device *dev) |
94a79942 | 27 | { |
e3e37629 | 28 | struct r8192_priv *priv = rtllib_priv(dev); |
5aca114d | 29 | struct rt_firmware *pfirmware = priv->pFirmware; |
94a79942 | 30 | |
11632a0e LF |
31 | pfirmware->cmdpacket_frag_thresold = GET_COMMAND_PACKET_FRAG_THRESHOLD( |
32 | MAX_TRANSMIT_BUFFER_SIZE); | |
94a79942 LF |
33 | } |
34 | ||
49aab5fd LF |
35 | static bool fw_download_code(struct net_device *dev, u8 *code_virtual_address, |
36 | u32 buffer_len) | |
94a79942 | 37 | { |
e3e37629 | 38 | struct r8192_priv *priv = rtllib_priv(dev); |
94a79942 LF |
39 | u16 frag_threshold; |
40 | u16 frag_length, frag_offset = 0; | |
41 | int i; | |
42 | ||
5aca114d | 43 | struct rt_firmware *pfirmware = priv->pFirmware; |
94a79942 LF |
44 | struct sk_buff *skb; |
45 | unsigned char *seg_ptr; | |
3b83db43 | 46 | struct cb_desc *tcb_desc; |
94a79942 LF |
47 | u8 bLastIniPkt; |
48 | ||
16362f45 | 49 | rtl92e_init_fw_param(dev); |
94a79942 LF |
50 | frag_threshold = pfirmware->cmdpacket_frag_thresold; |
51 | do { | |
52 | if ((buffer_len - frag_offset) > frag_threshold) { | |
dc986e3e | 53 | frag_length = frag_threshold; |
94a79942 LF |
54 | bLastIniPkt = 0; |
55 | ||
56 | } else { | |
57 | frag_length = buffer_len - frag_offset; | |
58 | bLastIniPkt = 1; | |
59 | ||
60 | } | |
61 | ||
62 | skb = dev_alloc_skb(frag_length + 4); | |
11632a0e | 63 | memcpy((unsigned char *)(skb->cb), &dev, sizeof(dev)); |
3b83db43 | 64 | tcb_desc = (struct cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); |
94a79942 LF |
65 | tcb_desc->queue_index = TXCMD_QUEUE; |
66 | tcb_desc->bCmdOrInit = DESC_PACKET_TYPE_INIT; | |
67 | tcb_desc->bLastIniPkt = bLastIniPkt; | |
68 | ||
69 | seg_ptr = skb->data; | |
11632a0e LF |
70 | for (i = 0; i < frag_length; i += 4) { |
71 | *seg_ptr++ = ((i+0) < frag_length) ? | |
72 | code_virtual_address[i+3] : 0; | |
73 | *seg_ptr++ = ((i+1) < frag_length) ? | |
74 | code_virtual_address[i+2] : 0; | |
75 | *seg_ptr++ = ((i+2) < frag_length) ? | |
76 | code_virtual_address[i+1] : 0; | |
77 | *seg_ptr++ = ((i+3) < frag_length) ? | |
78 | code_virtual_address[i+0] : 0; | |
94a79942 | 79 | } |
11632a0e | 80 | tcb_desc->txbuf_size = (u16)i; |
94a79942 LF |
81 | skb_put(skb, i); |
82 | ||
11632a0e LF |
83 | if (!priv->rtllib->check_nic_enough_desc(dev, tcb_desc->queue_index) || |
84 | (!skb_queue_empty(&priv->rtllib->skb_waitQ[tcb_desc->queue_index])) || | |
85 | (priv->rtllib->queue_stop)) { | |
0822339b MK |
86 | RT_TRACE(COMP_FIRMWARE, |
87 | "===================> tx full!\n"); | |
11632a0e LF |
88 | skb_queue_tail(&priv->rtllib->skb_waitQ |
89 | [tcb_desc->queue_index], skb); | |
94a79942 | 90 | } else { |
11632a0e | 91 | priv->rtllib->softmac_hard_start_xmit(skb, dev); |
94a79942 LF |
92 | } |
93 | ||
94 | code_virtual_address += frag_length; | |
95 | frag_offset += frag_length; | |
96 | ||
11632a0e | 97 | } while (frag_offset < buffer_len); |
94a79942 | 98 | |
d8ae1967 | 99 | rtl92e_writeb(dev, TPPoll, TPPoll_CQ); |
94a79942 | 100 | |
e623d0f3 | 101 | return true; |
94a79942 LF |
102 | } |
103 | ||
49aab5fd | 104 | static bool CPUcheck_maincodeok_turnonCPU(struct net_device *dev) |
94a79942 LF |
105 | { |
106 | bool rt_status = true; | |
107 | u32 CPU_status = 0; | |
108 | unsigned long timeout; | |
109 | ||
8b9733c1 | 110 | timeout = jiffies + msecs_to_jiffies(200); |
94a79942 | 111 | while (time_before(jiffies, timeout)) { |
99aa47e0 | 112 | CPU_status = rtl92e_readl(dev, CPU_GEN); |
94a79942 LF |
113 | if (CPU_status & CPU_GEN_PUT_CODE_OK) |
114 | break; | |
11632a0e | 115 | mdelay(2); |
94a79942 LF |
116 | } |
117 | ||
118 | if (!(CPU_status&CPU_GEN_PUT_CODE_OK)) { | |
3b4140af | 119 | netdev_err(dev, "Firmware download failed.\n"); |
94a79942 LF |
120 | goto CPUCheckMainCodeOKAndTurnOnCPU_Fail; |
121 | } else { | |
122 | RT_TRACE(COMP_FIRMWARE, "Download Firmware: Put code ok!\n"); | |
123 | } | |
124 | ||
99aa47e0 | 125 | CPU_status = rtl92e_readl(dev, CPU_GEN); |
d8ae1967 MK |
126 | rtl92e_writeb(dev, CPU_GEN, |
127 | (u8)((CPU_status|CPU_GEN_PWR_STB_CPU)&0xff)); | |
94a79942 LF |
128 | mdelay(1); |
129 | ||
8b9733c1 | 130 | timeout = jiffies + msecs_to_jiffies(200); |
94a79942 | 131 | while (time_before(jiffies, timeout)) { |
99aa47e0 | 132 | CPU_status = rtl92e_readl(dev, CPU_GEN); |
94a79942 LF |
133 | if (CPU_status&CPU_GEN_BOOT_RDY) |
134 | break; | |
11632a0e | 135 | mdelay(2); |
94a79942 LF |
136 | } |
137 | ||
3b4140af MK |
138 | if (!(CPU_status&CPU_GEN_BOOT_RDY)) { |
139 | netdev_err(dev, "Firmware boot failed.\n"); | |
94a79942 | 140 | goto CPUCheckMainCodeOKAndTurnOnCPU_Fail; |
3b4140af MK |
141 | } |
142 | ||
143 | RT_TRACE(COMP_FIRMWARE, "Download Firmware: Boot ready!\n"); | |
94a79942 LF |
144 | |
145 | return rt_status; | |
146 | ||
147 | CPUCheckMainCodeOKAndTurnOnCPU_Fail: | |
94a79942 LF |
148 | rt_status = false; |
149 | return rt_status; | |
150 | } | |
151 | ||
49aab5fd | 152 | static bool CPUcheck_firmware_ready(struct net_device *dev) |
94a79942 LF |
153 | { |
154 | ||
155 | bool rt_status = true; | |
156 | u32 CPU_status = 0; | |
157 | unsigned long timeout; | |
158 | ||
8b9733c1 | 159 | timeout = jiffies + msecs_to_jiffies(20); |
94a79942 | 160 | while (time_before(jiffies, timeout)) { |
99aa47e0 | 161 | CPU_status = rtl92e_readl(dev, CPU_GEN); |
94a79942 LF |
162 | if (CPU_status&CPU_GEN_FIRM_RDY) |
163 | break; | |
11632a0e | 164 | mdelay(2); |
94a79942 LF |
165 | } |
166 | ||
167 | if (!(CPU_status&CPU_GEN_FIRM_RDY)) | |
168 | goto CPUCheckFirmwareReady_Fail; | |
169 | else | |
170 | RT_TRACE(COMP_FIRMWARE, "Download Firmware: Firmware ready!\n"); | |
171 | ||
172 | return rt_status; | |
173 | ||
174 | CPUCheckFirmwareReady_Fail: | |
94a79942 LF |
175 | rt_status = false; |
176 | return rt_status; | |
177 | ||
178 | } | |
179 | ||
11632a0e LF |
180 | static bool firmware_check_ready(struct net_device *dev, |
181 | u8 load_fw_status) | |
94a79942 | 182 | { |
e3e37629 | 183 | struct r8192_priv *priv = rtllib_priv(dev); |
5aca114d | 184 | struct rt_firmware *pfirmware = priv->pFirmware; |
94a79942 LF |
185 | bool rt_status = true; |
186 | ||
187 | switch (load_fw_status) { | |
188 | case FW_INIT_STEP0_BOOT: | |
189 | pfirmware->firmware_status = FW_STATUS_1_MOVE_BOOT_CODE; | |
94a79942 LF |
190 | break; |
191 | ||
192 | case FW_INIT_STEP1_MAIN: | |
193 | pfirmware->firmware_status = FW_STATUS_2_MOVE_MAIN_CODE; | |
194 | ||
195 | rt_status = CPUcheck_maincodeok_turnonCPU(dev); | |
11632a0e | 196 | if (rt_status) |
94a79942 | 197 | pfirmware->firmware_status = FW_STATUS_3_TURNON_CPU; |
11632a0e | 198 | else |
0822339b MK |
199 | RT_TRACE(COMP_FIRMWARE, |
200 | "CPUcheck_maincodeok_turnonCPU fail!\n"); | |
94a79942 LF |
201 | |
202 | break; | |
203 | ||
204 | case FW_INIT_STEP2_DATA: | |
205 | pfirmware->firmware_status = FW_STATUS_4_MOVE_DATA_CODE; | |
206 | mdelay(1); | |
207 | ||
208 | rt_status = CPUcheck_firmware_ready(dev); | |
11632a0e | 209 | if (rt_status) |
94a79942 | 210 | pfirmware->firmware_status = FW_STATUS_5_READY; |
11632a0e | 211 | else |
0822339b MK |
212 | RT_TRACE(COMP_FIRMWARE, |
213 | "CPUcheck_firmware_ready fail(%d)!\n", | |
214 | rt_status); | |
94a79942 LF |
215 | |
216 | break; | |
217 | default: | |
218 | rt_status = false; | |
73e29189 | 219 | RT_TRACE(COMP_FIRMWARE, "Unknown firmware status"); |
94a79942 LF |
220 | break; |
221 | } | |
222 | ||
223 | return rt_status; | |
224 | } | |
225 | ||
b8216b69 | 226 | bool rtl92e_init_fw(struct net_device *dev) |
94a79942 | 227 | { |
e3e37629 | 228 | struct r8192_priv *priv = rtllib_priv(dev); |
94a79942 LF |
229 | bool rt_status = true; |
230 | ||
94a79942 LF |
231 | u32 file_length = 0; |
232 | u8 *mapped_file = NULL; | |
35e33b04 | 233 | u8 i = 0; |
6bf04003 | 234 | enum opt_rst_type rst_opt = OPT_SYSTEM_RESET; |
cec07695 | 235 | enum firmware_init_step starting_state = FW_INIT_STEP0_BOOT; |
94a79942 | 236 | |
5aca114d | 237 | struct rt_firmware *pfirmware = priv->pFirmware; |
94a79942 LF |
238 | |
239 | RT_TRACE(COMP_FIRMWARE, " PlatformInitFirmware()==>\n"); | |
240 | ||
11632a0e | 241 | if (pfirmware->firmware_status == FW_STATUS_0_INIT) { |
94a79942 LF |
242 | rst_opt = OPT_SYSTEM_RESET; |
243 | starting_state = FW_INIT_STEP0_BOOT; | |
244 | ||
11632a0e | 245 | } else if (pfirmware->firmware_status == FW_STATUS_5_READY) { |
94a79942 LF |
246 | rst_opt = OPT_FIRMWARE_RESET; |
247 | starting_state = FW_INIT_STEP2_DATA; | |
11632a0e | 248 | } else { |
0822339b MK |
249 | RT_TRACE(COMP_FIRMWARE, |
250 | "PlatformInitFirmware: undefined firmware state\n"); | |
94a79942 LF |
251 | } |
252 | ||
35e33b04 | 253 | for (i = starting_state; i <= FW_INIT_STEP2_DATA; i++) { |
94a79942 | 254 | if (rst_opt == OPT_SYSTEM_RESET) { |
35e33b04 | 255 | if (pfirmware->firmware_buf_size[i] == 0) { |
84fcb4b3 BH |
256 | const char *fw_name[3] = { |
257 | RTL8192E_BOOT_IMG_FW, | |
258 | RTL8192E_MAIN_IMG_FW, | |
259 | RTL8192E_DATA_IMG_FW | |
260 | }; | |
261 | const struct firmware *fw_entry; | |
262 | int rc; | |
3a6b70c3 | 263 | |
84fcb4b3 | 264 | rc = request_firmware(&fw_entry, |
35e33b04 | 265 | fw_name[i], |
84fcb4b3 BH |
266 | &priv->pdev->dev); |
267 | if (rc < 0) { | |
0822339b MK |
268 | RT_TRACE(COMP_FIRMWARE, |
269 | "request firmware fail!\n"); | |
84fcb4b3 BH |
270 | goto download_firmware_fail; |
271 | } | |
272 | if (fw_entry->size > | |
35e33b04 | 273 | sizeof(pfirmware->firmware_buf[i])) { |
0822339b MK |
274 | RT_TRACE(COMP_FIRMWARE, |
275 | "img file size exceed the container struct buffer fail!\n"); | |
84fcb4b3 BH |
276 | goto download_firmware_fail; |
277 | } | |
94a79942 | 278 | |
35e33b04 MK |
279 | if (i != FW_INIT_STEP1_MAIN) { |
280 | memcpy(pfirmware->firmware_buf[i], | |
11632a0e | 281 | fw_entry->data, fw_entry->size); |
35e33b04 | 282 | pfirmware->firmware_buf_size[i] = |
84fcb4b3 | 283 | fw_entry->size; |
94a79942 | 284 | |
84fcb4b3 | 285 | } else { |
35e33b04 | 286 | memset(pfirmware->firmware_buf[i], |
11632a0e | 287 | 0, 128); |
35e33b04 | 288 | memcpy(&pfirmware->firmware_buf[i][128], |
11632a0e | 289 | fw_entry->data, fw_entry->size); |
35e33b04 | 290 | pfirmware->firmware_buf_size[i] = |
84fcb4b3 | 291 | fw_entry->size + 128; |
94a79942 | 292 | } |
94a79942 | 293 | |
84fcb4b3 BH |
294 | if (rst_opt == OPT_SYSTEM_RESET) |
295 | release_firmware(fw_entry); | |
94a79942 | 296 | } |
94a79942 LF |
297 | } |
298 | ||
35e33b04 MK |
299 | mapped_file = pfirmware->firmware_buf[i]; |
300 | file_length = pfirmware->firmware_buf_size[i]; | |
84fcb4b3 | 301 | |
11632a0e | 302 | rt_status = fw_download_code(dev, mapped_file, file_length); |
bec027ea | 303 | if (!rt_status) |
94a79942 | 304 | goto download_firmware_fail; |
94a79942 | 305 | |
35e33b04 | 306 | if (!firmware_check_ready(dev, i)) |
94a79942 | 307 | goto download_firmware_fail; |
94a79942 LF |
308 | } |
309 | ||
310 | RT_TRACE(COMP_FIRMWARE, "Firmware Download Success\n"); | |
311 | return rt_status; | |
312 | ||
313 | download_firmware_fail: | |
3b4140af | 314 | netdev_err(dev, "%s: Failed to initialize firmware.\n", __func__); |
94a79942 LF |
315 | rt_status = false; |
316 | return rt_status; | |
317 | ||
318 | } |