]> rtime.felk.cvut.cz Git - mcf548x/linux.git/blob - drivers/staging/rt2860/common/rtmp_mcu.c
Initial 2.6.37
[mcf548x/linux.git] / drivers / staging / rt2860 / common / rtmp_mcu.c
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
38 #include        "../rt_config.h"
39
40 #include <linux/crc-ccitt.h>
41 #include <linux/firmware.h>
42
43 #ifdef RTMP_MAC_USB
44
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);
54
55 #define FIRMWARE_3071_MIN_VERSION       17
56 #define FIRMWARE_3071_FILENAME          "rt3071.bin"    /* for RT3071/RT3072 */
57 MODULE_FIRMWARE(FIRMWARE_3071_FILENAME);
58
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
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 */
86 int RtmpAsicEraseFirmware(struct rt_rtmp_adapter *pAd)
87 {
88         unsigned long i;
89
90         for (i = 0; i < MAX_FIRMWARE_IMAGE_SIZE; i += 4)
91                 RTMP_IO_WRITE32(pAd, FIRMWARE_IMAGE_BASE + i, 0);
92
93         return 0;
94 }
95
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
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 */
185 int RtmpAsicLoadFirmware(struct rt_rtmp_adapter *pAd)
186 {
187         const struct firmware *fw;
188         int Status = NDIS_STATUS_SUCCESS;
189         unsigned long Index;
190         u32 MacReg = 0;
191
192         fw = rtmp_get_firmware(pAd);
193         if (!fw)
194                 return NDIS_STATUS_FAILURE;
195
196         RTMP_WRITE_FIRMWARE(pAd, fw->data, FIRMWAREIMAGE_LENGTH);
197
198         /* check if MCU is ready */
199         Index = 0;
200         do {
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
209         if (Index > 1000) {
210                 DBGPRINT(RT_DEBUG_ERROR,
211                          ("NICLoadFirmware: MCU is not ready\n"));
212                 Status = NDIS_STATUS_FAILURE;
213         }
214
215         DBGPRINT(RT_DEBUG_TRACE, ("<=== %s (status=%d)\n", __func__, Status));
216
217         return Status;
218 }
219
220 int RtmpAsicSendCommandToMcu(struct rt_rtmp_adapter *pAd,
221                              u8 Command,
222                              u8 Token, u8 Arg0, u8 Arg1)
223 {
224         HOST_CMD_CSR_STRUC H2MCmd;
225         H2M_MAILBOX_STRUC H2MMailbox;
226         unsigned long i = 0;
227
228 #ifdef PCIE_PS_SUPPORT
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. */
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)) {
235                 RTMP_SEM_LOCK(&pAd->McuCmdLock);
236                 if ((pAd->brt30xxBanMcuCmd == TRUE)
237                     && (Command != WAKE_MCU_CMD) && (Command != RFOFF_MCU_CMD)) {
238                         RTMP_SEM_UNLOCK(&pAd->McuCmdLock);
239                         DBGPRINT(RT_DEBUG_TRACE,
240                                  (" Ban Mcu Cmd %x in sleep mode\n", Command));
241                         return FALSE;
242                 } else if ((Command == SLEEP_MCU_CMD)
243                            || (Command == RFOFF_MCU_CMD)) {
244                         pAd->brt30xxBanMcuCmd = TRUE;
245                 } else if (Command != WAKE_MCU_CMD) {
246                         pAd->brt30xxBanMcuCmd = FALSE;
247                 }
248
249                 RTMP_SEM_UNLOCK(&pAd->McuCmdLock);
250
251         }
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);
261                         if (H2MMailbox.field.Owner == 0)
262                                 break;
263
264                         RTMPusecDelay(2);
265                         DBGPRINT(RT_DEBUG_INFO,
266                                  ("AsicSendCommanToMcu::Mail box is busy\n"));
267                 } while (i++ < 100);
268
269                 if (i > 100) {
270                         DBGPRINT_ERR(("H2M_MAILBOX still hold by MCU. command fail\n"));
271                         return FALSE;
272                 }
273
274                 H2MMailbox.field.Owner = 1;     /* pass ownership to MCU */
275                 H2MMailbox.field.CmdToken = Token;
276                 H2MMailbox.field.HighByte = Arg1;
277                 H2MMailbox.field.LowByte = Arg0;
278                 RTMP_IO_FORCE_WRITE32(pAd, H2M_MAILBOX_CSR, H2MMailbox.word);
279
280                 H2MCmd.word = 0;
281                 H2MCmd.field.HostCommand = Command;
282                 RTMP_IO_FORCE_WRITE32(pAd, HOST_CMD_CSR, H2MCmd.word);
283
284         } else
285 #endif /* PCIE_PS_SUPPORT // */
286         {
287                 do {
288                         RTMP_IO_READ32(pAd, H2M_MAILBOX_CSR, &H2MMailbox.word);
289                         if (H2MMailbox.field.Owner == 0)
290                                 break;
291
292                         RTMPusecDelay(2);
293                 } while (i++ < 100);
294
295                 if (i > 100) {
296 #ifdef RTMP_MAC_PCI
297 #endif /* RTMP_MAC_PCI // */
298                         {
299                                 DBGPRINT_ERR(("H2M_MAILBOX still hold by MCU. command fail\n"));
300                         }
301                         return FALSE;
302                 }
303 #ifdef RTMP_MAC_PCI
304 #endif /* RTMP_MAC_PCI // */
305
306                 H2MMailbox.field.Owner = 1;     /* pass ownership to MCU */
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);
311
312                 H2MCmd.word = 0;
313                 H2MCmd.field.HostCommand = Command;
314                 RTMP_IO_WRITE32(pAd, HOST_CMD_CSR, H2MCmd.word);
315
316                 if (Command != 0x80) {
317                 }
318         }
319 #ifdef PCIE_PS_SUPPORT
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. */
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)) {
327                 RTMPusecDelay(2000);
328                 /*Put this is after RF programming. */
329                 /*NdisAcquireSpinLock(&pAd->McuCmdLock); */
330                 /*pAd->brt30xxBanMcuCmd = FALSE; */
331                 /*NdisReleaseSpinLock(&pAd->McuCmdLock); */
332         }
333 #endif /* PCIE_PS_SUPPORT // */
334
335         return TRUE;
336 }