/******************************************************************************
*
* Copyright(c) 2009-2014 Realtek Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* 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.
*
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
* Contact Information:
* wlanfae <wlanfae@realtek.com>
* Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
* Hsinchu 300, Taiwan.
*
* Larry Finger <Larry.Finger@lwfinger.net>
*
*****************************************************************************/
#include "../wifi.h"
#include "../pci.h"
#include "../base.h"
#include "../core.h"
#include "reg.h"
#include "def.h"
#include "fw.h"
#include "dm.h"
static void _rtl92ee_enable_fw_download(struct ieee80211_hw *hw, bool enable)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
u8 tmp;
if (enable) {
rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x05);
tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);
rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);
} else {
tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);
}
}
static void _rtl92ee_fw_block_write(struct ieee80211_hw *hw,
const u8 *buffer, u32 size)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
u32 blocksize = sizeof(u32);
u8 *bufferptr = (u8 *)buffer;
u32 *pu4byteptr = (u32 *)buffer;
u32 i, offset, blockcount, remainsize;
blockcount = size / blocksize;
remainsize = size % blocksize;
for (i = 0; i < blockcount; i++) {
offset = i * blocksize;
rtl_write_dword(rtlpriv, (FW_8192C_START_ADDRESS + offset),
*(pu4byteptr + i));
}
if (remainsize) {
offset = blockcount * blocksize;
bufferptr += offset;
for (i = 0; i < remainsize; i++) {
rtl_write_byte(rtlpriv,
(FW_8192C_START_ADDRESS + offset + i),
*(bufferptr + i));
}
}
}
static void _rtl92ee_fw_page_write(struct ieee80211_hw *hw, u32 page,
const u8 *buffer, u32 size)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
u8 value8;
u8 u8page = (u8)(page & 0x07);
value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page;
rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8);
_rtl92ee_fw_block_write(hw, buffer, size);
}
static void _rtl92ee_fill_dummy(u8 *pfwbuf, u32 *pfwlen)
{
u32 fwlen = *pfwlen;
u8 remain = (u8)(fwlen % 4);
remain = (remain == 0) ? 0 : (4 - remain);
while (remain > 0) {
pfwbuf[fwlen] = 0;
fwlen++;
remain--;
}
*pfwlen = fwlen;
}
static void _rtl92ee_write_fw(struct ieee80211_hw *hw,
enum version_8192e version,
u8 *buffer, u32 size)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
u8 *bufferptr = (u8 *)buffer;
u32 pagenums, remainsize;
u32 page, offset;
RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD , "FW size is %d bytes,\n", size);
_rtl92ee_fill_dummy(bufferptr, &size);
pagenums = size / FW_8192C_PAGE_SIZE;
remainsize = size % FW_8192C_PAGE_SIZE;
if (pagenums > 8) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
"Page numbers should not greater then 8\n");
}
for (page = 0; page < pagenums; page++) {
offset = page * FW_8192C_PAGE_SIZE;
_rtl92ee_fw_page_write(hw, page, (bufferptr + offset),
FW_8192C_PAGE_SIZE);
udelay(2);
}
if (remainsize) {
offset = pagenums * FW_8192C_PAGE_SIZE;
page = pagenums;
_rtl92ee_fw_page_write(hw, page, (bufferptr + offset),
remainsize);
}
}
static int _rtl92ee_fw_free_to_go(struct