| /* |
| ************************************************************************* |
| * Ralink Tech Inc. |
| * 5F., No.36, Taiyuan St., Jhubei City, |
| * Hsinchu County 302, |
| * Taiwan, R.O.C. |
| * |
| * (c) Copyright 2002-2007, Ralink Technology, Inc. |
| * |
| * This program is free software; you can redistribute it and/or modify * |
| * it under the terms of the GNU General Public License as published by * |
| * the Free Software Foundation; either version 2 of the License, or * |
| * (at your option) any later version. * |
| * * |
| * This program is distributed in the hope that it will be useful, * |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of * |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * |
| * GNU General Public License for more details. * |
| * * |
| * You should have received a copy of the GNU General Public License * |
| * along with this program; if not, write to the * |
| * Free Software Foundation, Inc., * |
| * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * |
| * * |
| ************************************************************************* |
| |
| Module Name: |
| rtmp_mcu.c |
| |
| Abstract: |
| Miniport generic portion header file |
| |
| Revision History: |
| Who When What |
| -------- ---------- ---------------------------------------------- |
| */ |
| |
| #include "../rt_config.h" |
| |
| #include <linux/crc-ccitt.h> |
| #include <linux/firmware.h> |
| |
| #ifdef RTMP_MAC_USB |
| |
| #define FIRMWAREIMAGE_LENGTH 0x1000 |
| |
| #define FIRMWARE_2870_MIN_VERSION 12 |
| #define FIRMWARE_2870_FILENAME "rt2870.bin" |
| MODULE_FIRMWARE(FIRMWARE_2870_FILENAME); |
| |
| #define FIRMWARE_3070_MIN_VERSION 17 |
| #define FIRMWARE_3070_FILENAME "rt3070.bin" |
| MODULE_FIRMWARE(FIRMWARE_3070_FILENAME); |
| |
| #define FIRMWARE_3071_MIN_VERSION 17 |
| #define FIRMWARE_3071_FILENAME "rt3071.bin" /* for RT3071/RT3072 */ |
| MODULE_FIRMWARE(FIRMWARE_3071_FILENAME); |
| |
| #else /* RTMP_MAC_PCI */ |
| |
| #define FIRMWAREIMAGE_LENGTH 0x2000 |
| |
| #define FIRMWARE_2860_MIN_VERSION 11 |
| #define FIRMWARE_2860_FILENAME "rt2860.bin" |
| MODULE_FIRMWARE(FIRMWARE_2860_FILENAME); |
| |
| #define FIRMWARE_3090_MIN_VERSION 19 |
| #define FIRMWARE_3090_FILENAME "rt3090.bin" /* for RT3090/RT3390 */ |
| MODULE_FIRMWARE(FIRMWARE_3090_FILENAME); |
| |
| #endif |
| |
| /* |
| ======================================================================== |
| |
| Routine Description: |
| erase 8051 firmware image in MAC ASIC |
| |
| Arguments: |
| Adapter Pointer to our adapter |
| |
| IRQL = PASSIVE_LEVEL |
| |
| ======================================================================== |
| */ |
| int RtmpAsicEraseFirmware(struct rt_rtmp_adapter *pAd) |
| { |
| unsigned long i; |
| |
| for (i = 0; i < MAX_FIRMWARE_IMAGE_SIZE; i += 4) |
| RTMP_IO_WRITE32(pAd, FIRMWARE_IMAGE_BASE + i, 0); |
| |
| return 0; |
| } |
| |
| static const struct firmware *rtmp_get_firmware(struct rt_rtmp_adapter *adapter) |
| { |
| const char *name; |
| const struct firmware *fw = NULL; |
| u8 min_version; |
| struct device *dev; |
| int err; |
| |
| if (adapter->firmware) |
| return adapter->firmware; |
| |
| #ifdef RTMP_MAC_USB |
| if (IS_RT3071(adapter)) { |
| name = FIRMWARE_3071_FILENAME; |
| min_version = FIRMWARE_3071_MIN_VERSION; |
| } else if (IS_RT3070(adapter)) { |
| name = FIRMWARE_3070_FILENAME; |
| min_version = FIRMWARE_3070_MIN_VERSION; |
| } else { |
| name = FIRMWARE_2870_FILENAME; |
| min_version = FIRMWARE_2870_MIN_VERSION; |
| } |
| dev = &((struct os_cookie *)adapter->OS_Cookie)->pUsb_Dev->dev; |
| #else /* RTMP_MAC_PCI */ |
| if (IS_RT3090(adapter) || IS_RT3390(adapter)) { |
| name = FIRMWARE_3090_FILENAME; |
| min_version = FIRMWARE_3090_MIN_VERSION; |
| } else { |
| name = FIRMWARE_2860_FILENAME; |
| min_version = FIRMWARE_2860_MIN_VERSION; |
| } |
| dev = &((struct os_cookie *)adapter->OS_Cookie)->pci_dev->dev; |
| #endif |
| |
| err = request_firmware(&fw, name, dev); |
| if (err) { |
| dev_err(dev, "firmware file %s request failed (%d)\n", |
| name, err); |
| return NULL; |
| } |
| |
| if (fw->size < FIRMWAREIMAGE_LENGTH) { |
| dev_err(dev, "firmware file %s size is invalid\n", name); |
| goto invalid; |
| } |
| |
| /* is it new enough? */ |
| adapter->FirmwareVersion = fw->data[FIRMWAREIMAGE_LENGTH - 3]; |
| if (adapter->FirmwareVersion < min_version) { |
| dev_err(dev, |
| "firmware file %s is too old;" |
| " driver requires v%d or later\n", |
| name, min_version); |
| goto invalid; |
| } |
| |
| /* is the internal CRC correct? */ |
| if (crc_ccitt(0xffff, fw->data, FIRMWAREIMAGE_LENGTH - 2) != |
| (fw->data[FIRMWAREIMAGE_LENGTH - 2] | |
| (fw->data[FIRMWAREIMAGE_LENGTH - 1] << 8))) { |
| dev_err(dev, "firmware file %s failed internal CRC\n", name); |
| goto invalid; |
| } |
| |
| adapter->firmware = fw; |
| return fw; |
| |
| invalid: |
| release_firmware(fw); |
| return NULL; |
| } |
| |
| /* |
| ======================================================================== |
| |
| Routine Description: |
| Load 8051 firmware file into MAC ASIC |
| |
| Arguments: |
| Adapter Pointer to our adapter |
| |
| Return Value: |
| NDIS_STATUS_SUCCESS firmware image load ok |
| NDIS_STATUS_FAILURE image not found |
| |
| IRQL = PASSIVE_LEVEL |
| |
| ======================================================================== |
| */ |
| int RtmpAsicLoadFirmware(struct rt_rtmp_adapter *pAd) |
| { |
| const struct firmware *fw; |
| int Status = NDIS_STATUS_SUCCESS; |
| unsigned long Index; |
| u32 MacReg = 0; |
| |
| fw = rtmp_get_firmware(pAd); |
| if (!fw) |
| return NDIS_STATUS_FAILURE; |
| |
| RTMP_WRITE_FIRMWARE(pAd, fw->data, FIRMWAREIMAGE_LENGTH); |
| |
| /* check if MCU is ready */ |
| Index = 0; |
| do { |
| RTMP_IO_READ32(pAd, PBF_SYS_CTRL, &MacReg); |
| |
| if (MacReg & 0x80) |
| break; |
| |
| RTMPusecDelay(1000); |
| } while (Index++ < 1000); |
| |
| if (Index > 1000) { |
| DBGPRINT(RT_DEBUG_ERROR, |
| ("NICLoadFirmware: MCU is not ready\n")); |
| Status = NDIS_STATUS_FAILURE; |
| } |
| |
| DBGPRINT(RT_DEBUG_TRACE, ("<=== %s (status=%d)\n", __func__, Status)); |
| |
| return Status; |
| } |
| |
| int RtmpAsicSendCommandToMcu(struct rt_rtmp_adapter *pAd, |
| u8 Command, |
| u8 Token, u8 Arg0, u8 Arg1) |
| { |
| HOST_CMD_CSR_STRUC H2MCmd; |
| H2M_MAILBOX_STRUC H2MMailbox; |
| unsigned long i = 0; |
| |
| #ifdef PCIE_PS_SUPPORT |
| /* 3090F power solution 3 has hw limitation that needs to ban all mcu command */ |
| /* when firmware is in radio state. For other chip doesn't have this limitation. */ |
| if (((IS_RT3090(pAd) || IS_RT3572(pAd) || IS_RT3390(pAd)) |
| && IS_VERSION_AFTER_F(pAd)) && IS_VERSION_AFTER_F(pAd) |
| && (pAd->StaCfg.PSControl.field.rt30xxPowerMode == 3) |
| && (pAd->StaCfg.PSControl.field.EnableNewPS == TRUE)) { |
| RTMP_SEM_LOCK(&pAd->McuCmdLock); |
| if ((pAd->brt30xxBanMcuCmd == TRUE) |
| && (Command != WAKE_MCU_CMD) && (Command != RFOFF_MCU_CMD)) { |
| RTMP_SEM_UNLOCK(&pAd->McuCmdLock); |
| DBGPRINT(RT_DEBUG_TRACE, |
| (" Ban Mcu Cmd %x in sleep mode\n", Command)); |
| return FALSE; |
| } else if ((Command == SLEEP_MCU_CMD) |
| || (Command == RFOFF_MCU_CMD)) { |
| pAd->brt30xxBanMcuCmd = TRUE; |
| } else if (Command != WAKE_MCU_CMD) { |
| pAd->brt30xxBanMcuCmd = FALSE; |
| } |
| |
| RTMP_SEM_UNLOCK(&pAd->McuCmdLock); |
| |
| } |
| if (((IS_RT3090(pAd) || IS_RT3572(pAd) || IS_RT3390(pAd)) |
| && IS_VERSION_AFTER_F(pAd)) && IS_VERSION_AFTER_F(pAd) |
| && (pAd->StaCfg.PSControl.field.rt30xxPowerMode == 3) |
| && (pAd->StaCfg.PSControl.field.EnableNewPS == TRUE) |
| && (Command == WAKE_MCU_CMD)) { |
| |
| do { |
| RTMP_IO_FORCE_READ32(pAd, H2M_MAILBOX_CSR, |
| &H2MMailbox.word); |
| if (H2MMailbox.field.Owner == 0) |
| break; |
| |
| RTMPusecDelay(2); |
| DBGPRINT(RT_DEBUG_INFO, |
| ("AsicSendCommanToMcu::Mail box is busy\n")); |
| } while (i++ < 100); |
| |
| if (i > 100) { |
| DBGPRINT_ERR(("H2M_MAILBOX still hold by MCU. command fail\n")); |
| return FALSE; |
| } |
| |
| H2MMailbox.field.Owner = 1; /* pass ownership to MCU */ |
| H2MMailbox.field.CmdToken = Token; |
| H2MMailbox.field.HighByte = Arg1; |
| H2MMailbox.field.LowByte = Arg0; |
| RTMP_IO_FORCE_WRITE32(pAd, H2M_MAILBOX_CSR, H2MMailbox.word); |
| |
| H2MCmd.word = 0; |
| H2MCmd.field.HostCommand = Command; |
| RTMP_IO_FORCE_WRITE32(pAd, HOST_CMD_CSR, H2MCmd.word); |
| |
| } else |
| #endif /* PCIE_PS_SUPPORT // */ |
| { |
| do { |
| RTMP_IO_READ32(pAd, H2M_MAILBOX_CSR, &H2MMailbox.word); |
| if (H2MMailbox.field.Owner == 0) |
| break; |
| |
| RTMPusecDelay(2); |
| } while (i++ < 100); |
| |
| if (i > 100) { |
| #ifdef RTMP_MAC_PCI |
| #endif /* RTMP_MAC_PCI // */ |
| { |
| DBGPRINT_ERR(("H2M_MAILBOX still hold by MCU. command fail\n")); |
| } |
| return FALSE; |
| } |
| #ifdef RTMP_MAC_PCI |
| #endif /* RTMP_MAC_PCI // */ |
| |
| H2MMailbox.field.Owner = 1; /* pass ownership to MCU */ |
| H2MMailbox.field.CmdToken = Token; |
| H2MMailbox.field.HighByte = Arg1; |
| H2MMailbox.field.LowByte = Arg0; |
| RTMP_IO_WRITE32(pAd, H2M_MAILBOX_CSR, H2MMailbox.word); |
| |
| H2MCmd.word = 0; |
| H2MCmd.field.HostCommand = Command; |
| RTMP_IO_WRITE32(pAd, HOST_CMD_CSR, H2MCmd.word); |
| |
| if (Command != 0x80) { |
| } |
| } |
| #ifdef PCIE_PS_SUPPORT |
| /* 3090 MCU Wakeup command needs more time to be stable. */ |
| /* Before stable, don't issue other MCU command to prevent from firmware error. */ |
| if (((IS_RT3090(pAd) || IS_RT3572(pAd) || IS_RT3390(pAd)) |
| && IS_VERSION_AFTER_F(pAd)) && IS_VERSION_AFTER_F(pAd) |
| && (pAd->StaCfg.PSControl.field.rt30xxPowerMode == 3) |
| && (pAd->StaCfg.PSControl.field.EnableNewPS == TRUE) |
| && (Command == WAKE_MCU_CMD)) { |
| RTMPusecDelay(2000); |
| /*Put this is after RF programming. */ |
| /*NdisAcquireSpinLock(&pAd->McuCmdLock); */ |
| /*pAd->brt30xxBanMcuCmd = FALSE; */ |
| /*NdisReleaseSpinLock(&pAd->McuCmdLock); */ |
| } |
| #endif /* PCIE_PS_SUPPORT // */ |
| |
| return TRUE; |
| } |