]>
Commit | Line | Data |
---|---|---|
ca97b838 BZ |
1 | /* |
2 | ************************************************************************* | |
3 | * Ralink Tech Inc. | |
4 | * 5F., No.36, Taiyuan St., Jhubei City, | |
5 | * Hsinchu County 302, | |
6 | * Taiwan, R.O.C. | |
7 | * | |
8 | * (c) Copyright 2002-2007, Ralink Technology, Inc. | |
9 | * | |
10 | * This program is free software; you can redistribute it and/or modify * | |
11 | * it under the terms of the GNU General Public License as published by * | |
12 | * the Free Software Foundation; either version 2 of the License, or * | |
13 | * (at your option) any later version. * | |
14 | * * | |
15 | * This program is distributed in the hope that it will be useful, * | |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | |
18 | * GNU General Public License for more details. * | |
19 | * * | |
20 | * You should have received a copy of the GNU General Public License * | |
21 | * along with this program; if not, write to the * | |
22 | * Free Software Foundation, Inc., * | |
23 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * | |
24 | * * | |
25 | ************************************************************************* | |
26 | ||
27 | Module Name: | |
28 | rtmp_mcu.c | |
29 | ||
30 | Abstract: | |
31 | Miniport generic portion header file | |
32 | ||
33 | Revision History: | |
34 | Who When What | |
35 | -------- ---------- ---------------------------------------------- | |
36 | */ | |
37 | ||
ca97b838 BZ |
38 | #include "../rt_config.h" |
39 | ||
c22202fa BH |
40 | #include <linux/crc-ccitt.h> |
41 | #include <linux/firmware.h> | |
ca97b838 | 42 | |
ca97b838 | 43 | #ifdef RTMP_MAC_USB |
ca97b838 | 44 | |
c22202fa BH |
45 | #define FIRMWAREIMAGE_LENGTH 0x1000 |
46 | ||
47 | #define FIRMWARE_2870_MIN_VERSION 12 | |
48 | #define FIRMWARE_2870_FILENAME "rt2870.bin" | |
49 | MODULE_FIRMWARE(FIRMWARE_2870_FILENAME); | |
50 | ||
51 | #define FIRMWARE_3070_MIN_VERSION 17 | |
52 | #define FIRMWARE_3070_FILENAME "rt3070.bin" | |
53 | MODULE_FIRMWARE(FIRMWARE_3070_FILENAME); | |
ca97b838 | 54 | |
c22202fa BH |
55 | #define FIRMWARE_3071_MIN_VERSION 17 |
56 | #define FIRMWARE_3071_FILENAME "rt3071.bin" /* for RT3071/RT3072 */ | |
57 | MODULE_FIRMWARE(FIRMWARE_3071_FILENAME); | |
ca97b838 | 58 | |
c22202fa BH |
59 | #else /* RTMP_MAC_PCI */ |
60 | ||
61 | #define FIRMWAREIMAGE_LENGTH 0x2000 | |
62 | ||
63 | #define FIRMWARE_2860_MIN_VERSION 11 | |
64 | #define FIRMWARE_2860_FILENAME "rt2860.bin" | |
65 | MODULE_FIRMWARE(FIRMWARE_2860_FILENAME); | |
66 | ||
67 | #define FIRMWARE_3090_MIN_VERSION 19 | |
68 | #define FIRMWARE_3090_FILENAME "rt3090.bin" /* for RT3090/RT3390 */ | |
69 | MODULE_FIRMWARE(FIRMWARE_3090_FILENAME); | |
70 | ||
71 | #endif | |
ca97b838 BZ |
72 | |
73 | /* | |
74 | ======================================================================== | |
75 | ||
76 | Routine Description: | |
77 | erase 8051 firmware image in MAC ASIC | |
78 | ||
79 | Arguments: | |
80 | Adapter Pointer to our adapter | |
81 | ||
82 | IRQL = PASSIVE_LEVEL | |
83 | ||
84 | ======================================================================== | |
85 | */ | |
62eb734b | 86 | int RtmpAsicEraseFirmware(struct rt_rtmp_adapter *pAd) |
ca97b838 | 87 | { |
51126deb | 88 | unsigned long i; |
ca97b838 | 89 | |
96b3c83d | 90 | for (i = 0; i < MAX_FIRMWARE_IMAGE_SIZE; i += 4) |
ca97b838 BZ |
91 | RTMP_IO_WRITE32(pAd, FIRMWARE_IMAGE_BASE + i, 0); |
92 | ||
93 | return 0; | |
94 | } | |
95 | ||
c22202fa BH |
96 | static const struct firmware *rtmp_get_firmware(struct rt_rtmp_adapter *adapter) |
97 | { | |
98 | const char *name; | |
99 | const struct firmware *fw = NULL; | |
100 | u8 min_version; | |
101 | struct device *dev; | |
102 | int err; | |
103 | ||
104 | if (adapter->firmware) | |
105 | return adapter->firmware; | |
106 | ||
107 | #ifdef RTMP_MAC_USB | |
108 | if (IS_RT3071(adapter)) { | |
109 | name = FIRMWARE_3071_FILENAME; | |
110 | min_version = FIRMWARE_3071_MIN_VERSION; | |
111 | } else if (IS_RT3070(adapter)) { | |
112 | name = FIRMWARE_3070_FILENAME; | |
113 | min_version = FIRMWARE_3070_MIN_VERSION; | |
114 | } else { | |
115 | name = FIRMWARE_2870_FILENAME; | |
116 | min_version = FIRMWARE_2870_MIN_VERSION; | |
117 | } | |
118 | dev = &((struct os_cookie *)adapter->OS_Cookie)->pUsb_Dev->dev; | |
119 | #else /* RTMP_MAC_PCI */ | |
120 | if (IS_RT3090(adapter) || IS_RT3390(adapter)) { | |
121 | name = FIRMWARE_3090_FILENAME; | |
122 | min_version = FIRMWARE_3090_MIN_VERSION; | |
123 | } else { | |
124 | name = FIRMWARE_2860_FILENAME; | |
125 | min_version = FIRMWARE_2860_MIN_VERSION; | |
126 | } | |
127 | dev = &((struct os_cookie *)adapter->OS_Cookie)->pci_dev->dev; | |
128 | #endif | |
129 | ||
130 | err = request_firmware(&fw, name, dev); | |
131 | if (err) { | |
132 | dev_err(dev, "firmware file %s request failed (%d)\n", | |
133 | name, err); | |
134 | return NULL; | |
135 | } | |
136 | ||
137 | if (fw->size < FIRMWAREIMAGE_LENGTH) { | |
138 | dev_err(dev, "firmware file %s size is invalid\n", name); | |
139 | goto invalid; | |
140 | } | |
141 | ||
142 | /* is it new enough? */ | |
143 | adapter->FirmwareVersion = fw->data[FIRMWAREIMAGE_LENGTH - 3]; | |
144 | if (adapter->FirmwareVersion < min_version) { | |
145 | dev_err(dev, | |
146 | "firmware file %s is too old;" | |
147 | " driver requires v%d or later\n", | |
148 | name, min_version); | |
149 | goto invalid; | |
150 | } | |
151 | ||
152 | /* is the internal CRC correct? */ | |
153 | if (crc_ccitt(0xffff, fw->data, FIRMWAREIMAGE_LENGTH - 2) != | |
154 | (fw->data[FIRMWAREIMAGE_LENGTH - 2] | | |
155 | (fw->data[FIRMWAREIMAGE_LENGTH - 1] << 8))) { | |
156 | dev_err(dev, "firmware file %s failed internal CRC\n", name); | |
157 | goto invalid; | |
158 | } | |
159 | ||
160 | adapter->firmware = fw; | |
161 | return fw; | |
162 | ||
163 | invalid: | |
164 | release_firmware(fw); | |
165 | return NULL; | |
166 | } | |
167 | ||
ca97b838 BZ |
168 | /* |
169 | ======================================================================== | |
170 | ||
171 | Routine Description: | |
172 | Load 8051 firmware file into MAC ASIC | |
173 | ||
174 | Arguments: | |
175 | Adapter Pointer to our adapter | |
176 | ||
177 | Return Value: | |
178 | NDIS_STATUS_SUCCESS firmware image load ok | |
179 | NDIS_STATUS_FAILURE image not found | |
180 | ||
181 | IRQL = PASSIVE_LEVEL | |
182 | ||
183 | ======================================================================== | |
184 | */ | |
62eb734b | 185 | int RtmpAsicLoadFirmware(struct rt_rtmp_adapter *pAd) |
ca97b838 | 186 | { |
c22202fa | 187 | const struct firmware *fw; |
51126deb | 188 | int Status = NDIS_STATUS_SUCCESS; |
c22202fa | 189 | unsigned long Index; |
51126deb | 190 | u32 MacReg = 0; |
ca97b838 | 191 | |
c22202fa BH |
192 | fw = rtmp_get_firmware(pAd); |
193 | if (!fw) | |
194 | return NDIS_STATUS_FAILURE; | |
ca97b838 | 195 | |
c22202fa | 196 | RTMP_WRITE_FIRMWARE(pAd, fw->data, FIRMWAREIMAGE_LENGTH); |
ca97b838 | 197 | |
ca97b838 BZ |
198 | /* check if MCU is ready */ |
199 | Index = 0; | |
96b3c83d | 200 | do { |
ca97b838 BZ |
201 | RTMP_IO_READ32(pAd, PBF_SYS_CTRL, &MacReg); |
202 | ||
203 | if (MacReg & 0x80) | |
204 | break; | |
205 | ||
206 | RTMPusecDelay(1000); | |
207 | } while (Index++ < 1000); | |
208 | ||
96b3c83d BZ |
209 | if (Index > 1000) { |
210 | DBGPRINT(RT_DEBUG_ERROR, | |
d6dbc012 | 211 | ("NICLoadFirmware: MCU is not ready\n")); |
ca97b838 BZ |
212 | Status = NDIS_STATUS_FAILURE; |
213 | } | |
214 | ||
96b3c83d | 215 | DBGPRINT(RT_DEBUG_TRACE, ("<=== %s (status=%d)\n", __func__, Status)); |
ca97b838 | 216 | |
96b3c83d | 217 | return Status; |
ca97b838 BZ |
218 | } |
219 | ||
62eb734b | 220 | int RtmpAsicSendCommandToMcu(struct rt_rtmp_adapter *pAd, |
51126deb BZ |
221 | u8 Command, |
222 | u8 Token, u8 Arg0, u8 Arg1) | |
ca97b838 | 223 | { |
96b3c83d BZ |
224 | HOST_CMD_CSR_STRUC H2MCmd; |
225 | H2M_MAILBOX_STRUC H2MMailbox; | |
51126deb | 226 | unsigned long i = 0; |
ca97b838 | 227 | |
e44fd1cf | 228 | #ifdef PCIE_PS_SUPPORT |
ec278fa2 BZ |
229 | /* 3090F power solution 3 has hw limitation that needs to ban all mcu command */ |
230 | /* when firmware is in radio state. For other chip doesn't have this limitation. */ | |
96b3c83d BZ |
231 | if (((IS_RT3090(pAd) || IS_RT3572(pAd) || IS_RT3390(pAd)) |
232 | && IS_VERSION_AFTER_F(pAd)) && IS_VERSION_AFTER_F(pAd) | |
233 | && (pAd->StaCfg.PSControl.field.rt30xxPowerMode == 3) | |
234 | && (pAd->StaCfg.PSControl.field.EnableNewPS == TRUE)) { | |
e44fd1cf BZ |
235 | RTMP_SEM_LOCK(&pAd->McuCmdLock); |
236 | if ((pAd->brt30xxBanMcuCmd == TRUE) | |
96b3c83d | 237 | && (Command != WAKE_MCU_CMD) && (Command != RFOFF_MCU_CMD)) { |
e44fd1cf | 238 | RTMP_SEM_UNLOCK(&pAd->McuCmdLock); |
96b3c83d BZ |
239 | DBGPRINT(RT_DEBUG_TRACE, |
240 | (" Ban Mcu Cmd %x in sleep mode\n", Command)); | |
e44fd1cf | 241 | return FALSE; |
96b3c83d BZ |
242 | } else if ((Command == SLEEP_MCU_CMD) |
243 | || (Command == RFOFF_MCU_CMD)) { | |
e44fd1cf | 244 | pAd->brt30xxBanMcuCmd = TRUE; |
96b3c83d | 245 | } else if (Command != WAKE_MCU_CMD) { |
e44fd1cf BZ |
246 | pAd->brt30xxBanMcuCmd = FALSE; |
247 | } | |
248 | ||
249 | RTMP_SEM_UNLOCK(&pAd->McuCmdLock); | |
250 | ||
251 | } | |
96b3c83d BZ |
252 | if (((IS_RT3090(pAd) || IS_RT3572(pAd) || IS_RT3390(pAd)) |
253 | && IS_VERSION_AFTER_F(pAd)) && IS_VERSION_AFTER_F(pAd) | |
254 | && (pAd->StaCfg.PSControl.field.rt30xxPowerMode == 3) | |
255 | && (pAd->StaCfg.PSControl.field.EnableNewPS == TRUE) | |
256 | && (Command == WAKE_MCU_CMD)) { | |
257 | ||
258 | do { | |
259 | RTMP_IO_FORCE_READ32(pAd, H2M_MAILBOX_CSR, | |
260 | &H2MMailbox.word); | |
e44fd1cf BZ |
261 | if (H2MMailbox.field.Owner == 0) |
262 | break; | |
263 | ||
264 | RTMPusecDelay(2); | |
96b3c83d BZ |
265 | DBGPRINT(RT_DEBUG_INFO, |
266 | ("AsicSendCommanToMcu::Mail box is busy\n")); | |
267 | } while (i++ < 100); | |
e44fd1cf | 268 | |
23a51a80 | 269 | if (i > 100) { |
e44fd1cf BZ |
270 | DBGPRINT_ERR(("H2M_MAILBOX still hold by MCU. command fail\n")); |
271 | return FALSE; | |
272 | } | |
273 | ||
ec278fa2 | 274 | H2MMailbox.field.Owner = 1; /* pass ownership to MCU */ |
e44fd1cf BZ |
275 | H2MMailbox.field.CmdToken = Token; |
276 | H2MMailbox.field.HighByte = Arg1; | |
96b3c83d | 277 | H2MMailbox.field.LowByte = Arg0; |
e44fd1cf BZ |
278 | RTMP_IO_FORCE_WRITE32(pAd, H2M_MAILBOX_CSR, H2MMailbox.word); |
279 | ||
96b3c83d BZ |
280 | H2MCmd.word = 0; |
281 | H2MCmd.field.HostCommand = Command; | |
e44fd1cf BZ |
282 | RTMP_IO_FORCE_WRITE32(pAd, HOST_CMD_CSR, H2MCmd.word); |
283 | ||
96b3c83d | 284 | } else |
ec278fa2 | 285 | #endif /* PCIE_PS_SUPPORT // */ |
e44fd1cf | 286 | { |
96b3c83d BZ |
287 | do { |
288 | RTMP_IO_READ32(pAd, H2M_MAILBOX_CSR, &H2MMailbox.word); | |
289 | if (H2MMailbox.field.Owner == 0) | |
290 | break; | |
ca97b838 | 291 | |
96b3c83d BZ |
292 | RTMPusecDelay(2); |
293 | } while (i++ < 100); | |
ca97b838 | 294 | |
96b3c83d | 295 | if (i > 100) { |
ca97b838 | 296 | #ifdef RTMP_MAC_PCI |
ec278fa2 | 297 | #endif /* RTMP_MAC_PCI // */ |
96b3c83d BZ |
298 | { |
299 | DBGPRINT_ERR(("H2M_MAILBOX still hold by MCU. command fail\n")); | |
300 | } | |
301 | return FALSE; | |
ca97b838 | 302 | } |
ca97b838 | 303 | #ifdef RTMP_MAC_PCI |
ec278fa2 | 304 | #endif /* RTMP_MAC_PCI // */ |
ca97b838 | 305 | |
ec278fa2 | 306 | H2MMailbox.field.Owner = 1; /* pass ownership to MCU */ |
96b3c83d BZ |
307 | H2MMailbox.field.CmdToken = Token; |
308 | H2MMailbox.field.HighByte = Arg1; | |
309 | H2MMailbox.field.LowByte = Arg0; | |
310 | RTMP_IO_WRITE32(pAd, H2M_MAILBOX_CSR, H2MMailbox.word); | |
ca97b838 | 311 | |
96b3c83d BZ |
312 | H2MCmd.word = 0; |
313 | H2MCmd.field.HostCommand = Command; | |
314 | RTMP_IO_WRITE32(pAd, HOST_CMD_CSR, H2MCmd.word); | |
ca97b838 | 315 | |
96b3c83d BZ |
316 | if (Command != 0x80) { |
317 | } | |
ca97b838 | 318 | } |
e44fd1cf | 319 | #ifdef PCIE_PS_SUPPORT |
ec278fa2 BZ |
320 | /* 3090 MCU Wakeup command needs more time to be stable. */ |
321 | /* Before stable, don't issue other MCU command to prevent from firmware error. */ | |
96b3c83d BZ |
322 | if (((IS_RT3090(pAd) || IS_RT3572(pAd) || IS_RT3390(pAd)) |
323 | && IS_VERSION_AFTER_F(pAd)) && IS_VERSION_AFTER_F(pAd) | |
324 | && (pAd->StaCfg.PSControl.field.rt30xxPowerMode == 3) | |
325 | && (pAd->StaCfg.PSControl.field.EnableNewPS == TRUE) | |
326 | && (Command == WAKE_MCU_CMD)) { | |
e44fd1cf | 327 | RTMPusecDelay(2000); |
ec278fa2 BZ |
328 | /*Put this is after RF programming. */ |
329 | /*NdisAcquireSpinLock(&pAd->McuCmdLock); */ | |
330 | /*pAd->brt30xxBanMcuCmd = FALSE; */ | |
331 | /*NdisReleaseSpinLock(&pAd->McuCmdLock); */ | |
e44fd1cf | 332 | } |
ec278fa2 | 333 | #endif /* PCIE_PS_SUPPORT // */ |
ca97b838 BZ |
334 | |
335 | return TRUE; | |
336 | } |