mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-14 09:09:56 +00:00
staging: r8188eu: move firmware loading code out of the hal layer
Move the firmware loading functions from rtl8188e_hal_init.c into the new file core/rtw_fw.c. Signed-off-by: Michael Straube <straube.linux@gmail.com> Link: https://lore.kernel.org/r/20220107103620.15648-20-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
dbf1c5e37e
commit
7235d165d3
@ -37,6 +37,7 @@ r8188eu-y = \
|
|||||||
core/rtw_br_ext.o \
|
core/rtw_br_ext.o \
|
||||||
core/rtw_cmd.o \
|
core/rtw_cmd.o \
|
||||||
core/rtw_efuse.o \
|
core/rtw_efuse.o \
|
||||||
|
core/rtw_fw.o \
|
||||||
core/rtw_ieee80211.o \
|
core/rtw_ieee80211.o \
|
||||||
core/rtw_ioctl_set.o \
|
core/rtw_ioctl_set.o \
|
||||||
core/rtw_iol.o \
|
core/rtw_iol.o \
|
||||||
|
284
drivers/staging/r8188eu/core/rtw_fw.c
Normal file
284
drivers/staging/r8188eu/core/rtw_fw.c
Normal file
@ -0,0 +1,284 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/* Copyright(c) 2007 - 2011 Realtek Corporation. */
|
||||||
|
|
||||||
|
#include <linux/firmware.h>
|
||||||
|
#include "../include/rtw_fw.h"
|
||||||
|
|
||||||
|
static void fw_download_enable(struct adapter *padapter, bool enable)
|
||||||
|
{
|
||||||
|
u8 tmp;
|
||||||
|
|
||||||
|
if (enable) {
|
||||||
|
/* MCU firmware download enable. */
|
||||||
|
tmp = rtw_read8(padapter, REG_MCUFWDL);
|
||||||
|
rtw_write8(padapter, REG_MCUFWDL, tmp | 0x01);
|
||||||
|
|
||||||
|
/* 8051 reset */
|
||||||
|
tmp = rtw_read8(padapter, REG_MCUFWDL + 2);
|
||||||
|
rtw_write8(padapter, REG_MCUFWDL + 2, tmp & 0xf7);
|
||||||
|
} else {
|
||||||
|
/* MCU firmware download disable. */
|
||||||
|
tmp = rtw_read8(padapter, REG_MCUFWDL);
|
||||||
|
rtw_write8(padapter, REG_MCUFWDL, tmp & 0xfe);
|
||||||
|
|
||||||
|
/* Reserved for fw extension. */
|
||||||
|
rtw_write8(padapter, REG_MCUFWDL + 1, 0x00);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int block_write(struct adapter *padapter, void *buffer, u32 buffSize)
|
||||||
|
{
|
||||||
|
int ret = _SUCCESS;
|
||||||
|
u32 blockSize_p1 = 4; /* (Default) Phase #1 : PCI muse use 4-byte write to download FW */
|
||||||
|
u32 blockSize_p2 = 8; /* Phase #2 : Use 8-byte, if Phase#1 use big size to write FW. */
|
||||||
|
u32 blockSize_p3 = 1; /* Phase #3 : Use 1-byte, the remnant of FW image. */
|
||||||
|
u32 blockCount_p1 = 0, blockCount_p2 = 0, blockCount_p3 = 0;
|
||||||
|
u32 remainSize_p1 = 0, remainSize_p2 = 0;
|
||||||
|
u8 *bufferPtr = (u8 *)buffer;
|
||||||
|
u32 i = 0, offset = 0;
|
||||||
|
|
||||||
|
blockSize_p1 = MAX_REG_BOLCK_SIZE;
|
||||||
|
|
||||||
|
/* 3 Phase #1 */
|
||||||
|
blockCount_p1 = buffSize / blockSize_p1;
|
||||||
|
remainSize_p1 = buffSize % blockSize_p1;
|
||||||
|
|
||||||
|
for (i = 0; i < blockCount_p1; i++) {
|
||||||
|
ret = rtw_writeN(padapter, (FW_8188E_START_ADDRESS + i * blockSize_p1), blockSize_p1, (bufferPtr + i * blockSize_p1));
|
||||||
|
if (ret == _FAIL)
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 3 Phase #2 */
|
||||||
|
if (remainSize_p1) {
|
||||||
|
offset = blockCount_p1 * blockSize_p1;
|
||||||
|
|
||||||
|
blockCount_p2 = remainSize_p1 / blockSize_p2;
|
||||||
|
remainSize_p2 = remainSize_p1 % blockSize_p2;
|
||||||
|
|
||||||
|
for (i = 0; i < blockCount_p2; i++) {
|
||||||
|
ret = rtw_writeN(padapter, (FW_8188E_START_ADDRESS + offset + i * blockSize_p2), blockSize_p2, (bufferPtr + offset + i * blockSize_p2));
|
||||||
|
|
||||||
|
if (ret == _FAIL)
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 3 Phase #3 */
|
||||||
|
if (remainSize_p2) {
|
||||||
|
offset = (blockCount_p1 * blockSize_p1) + (blockCount_p2 * blockSize_p2);
|
||||||
|
|
||||||
|
blockCount_p3 = remainSize_p2 / blockSize_p3;
|
||||||
|
|
||||||
|
for (i = 0; i < blockCount_p3; i++) {
|
||||||
|
ret = rtw_write8(padapter, (FW_8188E_START_ADDRESS + offset + i), *(bufferPtr + offset + i));
|
||||||
|
|
||||||
|
if (ret == _FAIL)
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int page_write(struct adapter *padapter, u32 page, void *buffer, u32 size)
|
||||||
|
{
|
||||||
|
u8 value8;
|
||||||
|
u8 u8Page = (u8)(page & 0x07);
|
||||||
|
|
||||||
|
value8 = (rtw_read8(padapter, REG_MCUFWDL + 2) & 0xF8) | u8Page;
|
||||||
|
rtw_write8(padapter, REG_MCUFWDL + 2, value8);
|
||||||
|
|
||||||
|
return block_write(padapter, buffer, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int write_fw(struct adapter *padapter, void *buffer, u32 size)
|
||||||
|
{
|
||||||
|
/* Since we need dynamic decide method of dwonload fw, so we call this function to get chip version. */
|
||||||
|
/* We can remove _ReadChipVersion from ReadpadapterInfo8192C later. */
|
||||||
|
int ret = _SUCCESS;
|
||||||
|
u32 pageNums, remainSize;
|
||||||
|
u32 page, offset;
|
||||||
|
u8 *bufferPtr = (u8 *)buffer;
|
||||||
|
|
||||||
|
pageNums = size / MAX_PAGE_SIZE;
|
||||||
|
remainSize = size % MAX_PAGE_SIZE;
|
||||||
|
|
||||||
|
for (page = 0; page < pageNums; page++) {
|
||||||
|
offset = page * MAX_PAGE_SIZE;
|
||||||
|
ret = page_write(padapter, page, bufferPtr + offset, MAX_PAGE_SIZE);
|
||||||
|
|
||||||
|
if (ret == _FAIL)
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
if (remainSize) {
|
||||||
|
offset = pageNums * MAX_PAGE_SIZE;
|
||||||
|
page = pageNums;
|
||||||
|
ret = page_write(padapter, page, bufferPtr + offset, remainSize);
|
||||||
|
|
||||||
|
if (ret == _FAIL)
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
exit:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rtw_reset_8051(struct adapter *padapter)
|
||||||
|
{
|
||||||
|
u8 val8;
|
||||||
|
|
||||||
|
val8 = rtw_read8(padapter, REG_SYS_FUNC_EN + 1);
|
||||||
|
rtw_write8(padapter, REG_SYS_FUNC_EN + 1, val8 & (~BIT(2)));
|
||||||
|
rtw_write8(padapter, REG_SYS_FUNC_EN + 1, val8 | (BIT(2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fw_free_to_go(struct adapter *padapter)
|
||||||
|
{
|
||||||
|
u32 counter = 0;
|
||||||
|
u32 value32;
|
||||||
|
|
||||||
|
/* polling CheckSum report */
|
||||||
|
do {
|
||||||
|
value32 = rtw_read32(padapter, REG_MCUFWDL);
|
||||||
|
if (value32 & FWDL_CHKSUM_RPT)
|
||||||
|
break;
|
||||||
|
} while (counter++ < POLLING_READY_TIMEOUT_COUNT);
|
||||||
|
|
||||||
|
if (counter >= POLLING_READY_TIMEOUT_COUNT) {
|
||||||
|
DBG_88E("%s: chksum report fail! REG_MCUFWDL:0x%08x\n", __func__, value32);
|
||||||
|
return _FAIL;
|
||||||
|
}
|
||||||
|
DBG_88E("%s: Checksum report OK! REG_MCUFWDL:0x%08x\n", __func__, value32);
|
||||||
|
|
||||||
|
value32 = rtw_read32(padapter, REG_MCUFWDL);
|
||||||
|
value32 |= MCUFWDL_RDY;
|
||||||
|
value32 &= ~WINTINI_RDY;
|
||||||
|
rtw_write32(padapter, REG_MCUFWDL, value32);
|
||||||
|
|
||||||
|
rtw_reset_8051(padapter);
|
||||||
|
|
||||||
|
/* polling for FW ready */
|
||||||
|
counter = 0;
|
||||||
|
do {
|
||||||
|
value32 = rtw_read32(padapter, REG_MCUFWDL);
|
||||||
|
if (value32 & WINTINI_RDY) {
|
||||||
|
DBG_88E("%s: Polling FW ready success!! REG_MCUFWDL:0x%08x\n", __func__, value32);
|
||||||
|
return _SUCCESS;
|
||||||
|
}
|
||||||
|
udelay(5);
|
||||||
|
} while (counter++ < POLLING_READY_TIMEOUT_COUNT);
|
||||||
|
|
||||||
|
DBG_88E("%s: Polling FW ready fail!! REG_MCUFWDL:0x%08x\n", __func__, value32);
|
||||||
|
return _FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int load_firmware(struct rt_firmware *rtfw, struct device *device)
|
||||||
|
{
|
||||||
|
int ret = _SUCCESS;
|
||||||
|
const struct firmware *fw;
|
||||||
|
const char *fw_name = "rtlwifi/rtl8188eufw.bin";
|
||||||
|
int err = request_firmware(&fw, fw_name, device);
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
pr_err("Request firmware failed with error 0x%x\n", err);
|
||||||
|
ret = _FAIL;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
if (!fw) {
|
||||||
|
pr_err("Firmware %s not available\n", fw_name);
|
||||||
|
ret = _FAIL;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
rtfw->data = kmemdup(fw->data, fw->size, GFP_KERNEL);
|
||||||
|
if (!rtfw->data) {
|
||||||
|
pr_err("Failed to allocate rtfw->data\n");
|
||||||
|
ret = _FAIL;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
rtfw->size = fw->size;
|
||||||
|
dev_dbg(device, "!bUsedWoWLANFw, FmrmwareLen:%d+\n", rtfw->size);
|
||||||
|
|
||||||
|
exit:
|
||||||
|
release_firmware(fw);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtl8188e_firmware_download(struct adapter *padapter)
|
||||||
|
{
|
||||||
|
int ret = _SUCCESS;
|
||||||
|
u8 write_fw_retry = 0;
|
||||||
|
u32 fwdl_start_time;
|
||||||
|
struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
|
||||||
|
struct device *device = dvobj_to_dev(dvobj);
|
||||||
|
struct rt_firmware_hdr *fwhdr = NULL;
|
||||||
|
u16 fw_version, fw_subversion, fw_signature;
|
||||||
|
u8 *fw_data;
|
||||||
|
u32 fw_size;
|
||||||
|
static int log_version;
|
||||||
|
|
||||||
|
if (!dvobj->firmware.data)
|
||||||
|
ret = load_firmware(&dvobj->firmware, device);
|
||||||
|
if (ret == _FAIL) {
|
||||||
|
dvobj->firmware.data = NULL;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
fw_data = dvobj->firmware.data;
|
||||||
|
fw_size = dvobj->firmware.size;
|
||||||
|
|
||||||
|
/* To Check Fw header. Added by tynli. 2009.12.04. */
|
||||||
|
fwhdr = (struct rt_firmware_hdr *)dvobj->firmware.data;
|
||||||
|
|
||||||
|
fw_version = le16_to_cpu(fwhdr->Version);
|
||||||
|
fw_subversion = fwhdr->Subversion;
|
||||||
|
fw_signature = le16_to_cpu(fwhdr->Signature);
|
||||||
|
|
||||||
|
if (!log_version++)
|
||||||
|
pr_info("%sFirmware Version %d, SubVersion %d, Signature 0x%x\n",
|
||||||
|
DRIVER_PREFIX, fw_version, fw_subversion, fw_signature);
|
||||||
|
|
||||||
|
if (IS_FW_HEADER_EXIST(fwhdr)) {
|
||||||
|
/* Shift 32 bytes for FW header */
|
||||||
|
fw_data = fw_data + 32;
|
||||||
|
fw_size = fw_size - 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Suggested by Filen. If 8051 is running in RAM code, driver should inform Fw to reset by itself, */
|
||||||
|
/* or it will cause download Fw fail. 2010.02.01. by tynli. */
|
||||||
|
if (rtw_read8(padapter, REG_MCUFWDL) & RAM_DL_SEL) { /* 8051 RAM code */
|
||||||
|
rtw_write8(padapter, REG_MCUFWDL, 0x00);
|
||||||
|
rtw_reset_8051(padapter);
|
||||||
|
}
|
||||||
|
|
||||||
|
fw_download_enable(padapter, true);
|
||||||
|
fwdl_start_time = jiffies;
|
||||||
|
while (1) {
|
||||||
|
/* reset the FWDL chksum */
|
||||||
|
rtw_write8(padapter, REG_MCUFWDL, rtw_read8(padapter, REG_MCUFWDL) | FWDL_CHKSUM_RPT);
|
||||||
|
|
||||||
|
ret = write_fw(padapter, fw_data, fw_size);
|
||||||
|
|
||||||
|
if (ret == _SUCCESS ||
|
||||||
|
(rtw_get_passing_time_ms(fwdl_start_time) > 500 && write_fw_retry++ >= 3))
|
||||||
|
break;
|
||||||
|
|
||||||
|
DBG_88E("%s write_fw_retry:%u, time after fwdl_start_time:%ums\n",
|
||||||
|
__func__, write_fw_retry, rtw_get_passing_time_ms(fwdl_start_time)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
fw_download_enable(padapter, false);
|
||||||
|
if (ret != _SUCCESS) {
|
||||||
|
DBG_88E("DL Firmware failed!\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = fw_free_to_go(padapter);
|
||||||
|
if (ret != _SUCCESS) {
|
||||||
|
DBG_88E("DL Firmware failed!\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
return ret;
|
||||||
|
}
|
@ -3,12 +3,12 @@
|
|||||||
|
|
||||||
#define _HAL_INIT_C_
|
#define _HAL_INIT_C_
|
||||||
|
|
||||||
#include "../include/linux/firmware.h"
|
|
||||||
#include "../include/drv_types.h"
|
#include "../include/drv_types.h"
|
||||||
#include "../include/rtw_efuse.h"
|
#include "../include/rtw_efuse.h"
|
||||||
#include "../include/rtl8188e_hal.h"
|
#include "../include/rtl8188e_hal.h"
|
||||||
#include "../include/rtw_iol.h"
|
#include "../include/rtw_iol.h"
|
||||||
#include "../include/usb_ops.h"
|
#include "../include/usb_ops.h"
|
||||||
|
#include "../include/rtw_fw.h"
|
||||||
|
|
||||||
static void iol_mode_enable(struct adapter *padapter, u8 enable)
|
static void iol_mode_enable(struct adapter *padapter, u8 enable)
|
||||||
{
|
{
|
||||||
@ -336,287 +336,6 @@ exit:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fw_download_enable(struct adapter *padapter, bool enable)
|
|
||||||
{
|
|
||||||
u8 tmp;
|
|
||||||
|
|
||||||
if (enable) {
|
|
||||||
/* MCU firmware download enable. */
|
|
||||||
tmp = rtw_read8(padapter, REG_MCUFWDL);
|
|
||||||
rtw_write8(padapter, REG_MCUFWDL, tmp | 0x01);
|
|
||||||
|
|
||||||
/* 8051 reset */
|
|
||||||
tmp = rtw_read8(padapter, REG_MCUFWDL + 2);
|
|
||||||
rtw_write8(padapter, REG_MCUFWDL + 2, tmp & 0xf7);
|
|
||||||
} else {
|
|
||||||
/* MCU firmware download disable. */
|
|
||||||
tmp = rtw_read8(padapter, REG_MCUFWDL);
|
|
||||||
rtw_write8(padapter, REG_MCUFWDL, tmp & 0xfe);
|
|
||||||
|
|
||||||
/* Reserved for fw extension. */
|
|
||||||
rtw_write8(padapter, REG_MCUFWDL + 1, 0x00);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#define MAX_REG_BOLCK_SIZE 196
|
|
||||||
|
|
||||||
static int block_write(struct adapter *padapter, void *buffer, u32 buffSize)
|
|
||||||
{
|
|
||||||
int ret = _SUCCESS;
|
|
||||||
u32 blockSize_p1 = 4; /* (Default) Phase #1 : PCI muse use 4-byte write to download FW */
|
|
||||||
u32 blockSize_p2 = 8; /* Phase #2 : Use 8-byte, if Phase#1 use big size to write FW. */
|
|
||||||
u32 blockSize_p3 = 1; /* Phase #3 : Use 1-byte, the remnant of FW image. */
|
|
||||||
u32 blockCount_p1 = 0, blockCount_p2 = 0, blockCount_p3 = 0;
|
|
||||||
u32 remainSize_p1 = 0, remainSize_p2 = 0;
|
|
||||||
u8 *bufferPtr = (u8 *)buffer;
|
|
||||||
u32 i = 0, offset = 0;
|
|
||||||
|
|
||||||
blockSize_p1 = MAX_REG_BOLCK_SIZE;
|
|
||||||
|
|
||||||
/* 3 Phase #1 */
|
|
||||||
blockCount_p1 = buffSize / blockSize_p1;
|
|
||||||
remainSize_p1 = buffSize % blockSize_p1;
|
|
||||||
|
|
||||||
for (i = 0; i < blockCount_p1; i++) {
|
|
||||||
ret = rtw_writeN(padapter, (FW_8188E_START_ADDRESS + i * blockSize_p1), blockSize_p1, (bufferPtr + i * blockSize_p1));
|
|
||||||
if (ret == _FAIL)
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 3 Phase #2 */
|
|
||||||
if (remainSize_p1) {
|
|
||||||
offset = blockCount_p1 * blockSize_p1;
|
|
||||||
|
|
||||||
blockCount_p2 = remainSize_p1 / blockSize_p2;
|
|
||||||
remainSize_p2 = remainSize_p1 % blockSize_p2;
|
|
||||||
|
|
||||||
for (i = 0; i < blockCount_p2; i++) {
|
|
||||||
ret = rtw_writeN(padapter, (FW_8188E_START_ADDRESS + offset + i * blockSize_p2), blockSize_p2, (bufferPtr + offset + i * blockSize_p2));
|
|
||||||
|
|
||||||
if (ret == _FAIL)
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 3 Phase #3 */
|
|
||||||
if (remainSize_p2) {
|
|
||||||
offset = (blockCount_p1 * blockSize_p1) + (blockCount_p2 * blockSize_p2);
|
|
||||||
|
|
||||||
blockCount_p3 = remainSize_p2 / blockSize_p3;
|
|
||||||
|
|
||||||
for (i = 0; i < blockCount_p3; i++) {
|
|
||||||
ret = rtw_write8(padapter, (FW_8188E_START_ADDRESS + offset + i), *(bufferPtr + offset + i));
|
|
||||||
|
|
||||||
if (ret == _FAIL)
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
exit:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int page_write(struct adapter *padapter, u32 page, void *buffer, u32 size)
|
|
||||||
{
|
|
||||||
u8 value8;
|
|
||||||
u8 u8Page = (u8)(page & 0x07);
|
|
||||||
|
|
||||||
value8 = (rtw_read8(padapter, REG_MCUFWDL + 2) & 0xF8) | u8Page;
|
|
||||||
rtw_write8(padapter, REG_MCUFWDL + 2, value8);
|
|
||||||
|
|
||||||
return block_write(padapter, buffer, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int write_fw(struct adapter *padapter, void *buffer, u32 size)
|
|
||||||
{
|
|
||||||
/* Since we need dynamic decide method of dwonload fw, so we call this function to get chip version. */
|
|
||||||
/* We can remove _ReadChipVersion from ReadpadapterInfo8192C later. */
|
|
||||||
int ret = _SUCCESS;
|
|
||||||
u32 pageNums, remainSize;
|
|
||||||
u32 page, offset;
|
|
||||||
u8 *bufferPtr = (u8 *)buffer;
|
|
||||||
|
|
||||||
pageNums = size / MAX_PAGE_SIZE;
|
|
||||||
remainSize = size % MAX_PAGE_SIZE;
|
|
||||||
|
|
||||||
for (page = 0; page < pageNums; page++) {
|
|
||||||
offset = page * MAX_PAGE_SIZE;
|
|
||||||
ret = page_write(padapter, page, bufferPtr + offset, MAX_PAGE_SIZE);
|
|
||||||
|
|
||||||
if (ret == _FAIL)
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
if (remainSize) {
|
|
||||||
offset = pageNums * MAX_PAGE_SIZE;
|
|
||||||
page = pageNums;
|
|
||||||
ret = page_write(padapter, page, bufferPtr + offset, remainSize);
|
|
||||||
|
|
||||||
if (ret == _FAIL)
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
exit:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void rtw_reset_8051(struct adapter *padapter)
|
|
||||||
{
|
|
||||||
u8 val8;
|
|
||||||
|
|
||||||
val8 = rtw_read8(padapter, REG_SYS_FUNC_EN + 1);
|
|
||||||
rtw_write8(padapter, REG_SYS_FUNC_EN + 1, val8 & (~BIT(2)));
|
|
||||||
rtw_write8(padapter, REG_SYS_FUNC_EN + 1, val8 | (BIT(2)));
|
|
||||||
}
|
|
||||||
|
|
||||||
static int fw_free_to_go(struct adapter *padapter)
|
|
||||||
{
|
|
||||||
u32 counter = 0;
|
|
||||||
u32 value32;
|
|
||||||
|
|
||||||
/* polling CheckSum report */
|
|
||||||
do {
|
|
||||||
value32 = rtw_read32(padapter, REG_MCUFWDL);
|
|
||||||
if (value32 & FWDL_CHKSUM_RPT)
|
|
||||||
break;
|
|
||||||
} while (counter++ < POLLING_READY_TIMEOUT_COUNT);
|
|
||||||
|
|
||||||
if (counter >= POLLING_READY_TIMEOUT_COUNT) {
|
|
||||||
DBG_88E("%s: chksum report fail! REG_MCUFWDL:0x%08x\n", __func__, value32);
|
|
||||||
return _FAIL;
|
|
||||||
}
|
|
||||||
DBG_88E("%s: Checksum report OK! REG_MCUFWDL:0x%08x\n", __func__, value32);
|
|
||||||
|
|
||||||
value32 = rtw_read32(padapter, REG_MCUFWDL);
|
|
||||||
value32 |= MCUFWDL_RDY;
|
|
||||||
value32 &= ~WINTINI_RDY;
|
|
||||||
rtw_write32(padapter, REG_MCUFWDL, value32);
|
|
||||||
|
|
||||||
rtw_reset_8051(padapter);
|
|
||||||
|
|
||||||
/* polling for FW ready */
|
|
||||||
counter = 0;
|
|
||||||
do {
|
|
||||||
value32 = rtw_read32(padapter, REG_MCUFWDL);
|
|
||||||
if (value32 & WINTINI_RDY) {
|
|
||||||
DBG_88E("%s: Polling FW ready success!! REG_MCUFWDL:0x%08x\n", __func__, value32);
|
|
||||||
return _SUCCESS;
|
|
||||||
}
|
|
||||||
udelay(5);
|
|
||||||
} while (counter++ < POLLING_READY_TIMEOUT_COUNT);
|
|
||||||
|
|
||||||
DBG_88E("%s: Polling FW ready fail!! REG_MCUFWDL:0x%08x\n", __func__, value32);
|
|
||||||
return _FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int load_firmware(struct rt_firmware *rtfw, struct device *device)
|
|
||||||
{
|
|
||||||
int ret = _SUCCESS;
|
|
||||||
const struct firmware *fw;
|
|
||||||
const char *fw_name = "rtlwifi/rtl8188eufw.bin";
|
|
||||||
int err = request_firmware(&fw, fw_name, device);
|
|
||||||
|
|
||||||
if (err) {
|
|
||||||
pr_err("Request firmware failed with error 0x%x\n", err);
|
|
||||||
ret = _FAIL;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
if (!fw) {
|
|
||||||
pr_err("Firmware %s not available\n", fw_name);
|
|
||||||
ret = _FAIL;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
rtfw->data = kmemdup(fw->data, fw->size, GFP_KERNEL);
|
|
||||||
if (!rtfw->data) {
|
|
||||||
pr_err("Failed to allocate rtfw->data\n");
|
|
||||||
ret = _FAIL;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
rtfw->size = fw->size;
|
|
||||||
dev_dbg(device, "!bUsedWoWLANFw, FmrmwareLen:%d+\n", rtfw->size);
|
|
||||||
|
|
||||||
exit:
|
|
||||||
release_firmware(fw);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int rtl8188e_firmware_download(struct adapter *padapter)
|
|
||||||
{
|
|
||||||
int ret = _SUCCESS;
|
|
||||||
u8 write_fw_retry = 0;
|
|
||||||
u32 fwdl_start_time;
|
|
||||||
struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
|
|
||||||
struct device *device = dvobj_to_dev(dvobj);
|
|
||||||
struct rt_firmware_hdr *fwhdr = NULL;
|
|
||||||
u16 fw_version, fw_subversion, fw_signature;
|
|
||||||
u8 *fw_data;
|
|
||||||
u32 fw_size;
|
|
||||||
static int log_version;
|
|
||||||
|
|
||||||
if (!dvobj->firmware.data)
|
|
||||||
ret = load_firmware(&dvobj->firmware, device);
|
|
||||||
if (ret == _FAIL) {
|
|
||||||
dvobj->firmware.data = NULL;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
fw_data = dvobj->firmware.data;
|
|
||||||
fw_size = dvobj->firmware.size;
|
|
||||||
|
|
||||||
/* To Check Fw header. Added by tynli. 2009.12.04. */
|
|
||||||
fwhdr = (struct rt_firmware_hdr *)dvobj->firmware.data;
|
|
||||||
|
|
||||||
fw_version = le16_to_cpu(fwhdr->Version);
|
|
||||||
fw_subversion = fwhdr->Subversion;
|
|
||||||
fw_signature = le16_to_cpu(fwhdr->Signature);
|
|
||||||
|
|
||||||
if (!log_version++)
|
|
||||||
pr_info("%sFirmware Version %d, SubVersion %d, Signature 0x%x\n",
|
|
||||||
DRIVER_PREFIX, fw_version, fw_subversion, fw_signature);
|
|
||||||
|
|
||||||
if (IS_FW_HEADER_EXIST(fwhdr)) {
|
|
||||||
/* Shift 32 bytes for FW header */
|
|
||||||
fw_data = fw_data + 32;
|
|
||||||
fw_size = fw_size - 32;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Suggested by Filen. If 8051 is running in RAM code, driver should inform Fw to reset by itself, */
|
|
||||||
/* or it will cause download Fw fail. 2010.02.01. by tynli. */
|
|
||||||
if (rtw_read8(padapter, REG_MCUFWDL) & RAM_DL_SEL) { /* 8051 RAM code */
|
|
||||||
rtw_write8(padapter, REG_MCUFWDL, 0x00);
|
|
||||||
rtw_reset_8051(padapter);
|
|
||||||
}
|
|
||||||
|
|
||||||
fw_download_enable(padapter, true);
|
|
||||||
fwdl_start_time = jiffies;
|
|
||||||
while (1) {
|
|
||||||
/* reset the FWDL chksum */
|
|
||||||
rtw_write8(padapter, REG_MCUFWDL, rtw_read8(padapter, REG_MCUFWDL) | FWDL_CHKSUM_RPT);
|
|
||||||
|
|
||||||
ret = write_fw(padapter, fw_data, fw_size);
|
|
||||||
|
|
||||||
if (ret == _SUCCESS ||
|
|
||||||
(rtw_get_passing_time_ms(fwdl_start_time) > 500 && write_fw_retry++ >= 3))
|
|
||||||
break;
|
|
||||||
|
|
||||||
DBG_88E("%s write_fw_retry:%u, time after fwdl_start_time:%ums\n",
|
|
||||||
__func__, write_fw_retry, rtw_get_passing_time_ms(fwdl_start_time)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
fw_download_enable(padapter, false);
|
|
||||||
if (ret != _SUCCESS) {
|
|
||||||
DBG_88E("DL Firmware failed!\n");
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = fw_free_to_go(padapter);
|
|
||||||
if (ret != _SUCCESS) {
|
|
||||||
DBG_88E("DL Firmware failed!\n");
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
exit:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* */
|
/* */
|
||||||
/* Efuse related code */
|
/* Efuse related code */
|
||||||
/* */
|
/* */
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
#include "../include/osdep_service.h"
|
#include "../include/osdep_service.h"
|
||||||
#include "../include/drv_types.h"
|
#include "../include/drv_types.h"
|
||||||
#include "../include/rtw_efuse.h"
|
#include "../include/rtw_efuse.h"
|
||||||
|
#include "../include/rtw_fw.h"
|
||||||
#include "../include/rtl8188e_hal.h"
|
#include "../include/rtl8188e_hal.h"
|
||||||
#include "../include/rtw_iol.h"
|
#include "../include/rtw_iol.h"
|
||||||
#include "../include/usb_ops.h"
|
#include "../include/usb_ops.h"
|
||||||
|
@ -249,10 +249,6 @@ struct hal_data_8188e {
|
|||||||
u8 UsbRxAggPageTimeout;
|
u8 UsbRxAggPageTimeout;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* rtl8188e_hal_init.c */
|
|
||||||
int rtl8188e_firmware_download(struct adapter *padapter);
|
|
||||||
void rtw_reset_8051(struct adapter *padapter);
|
|
||||||
|
|
||||||
s32 InitLLTTable(struct adapter *padapter, u8 txpktbuf_bndy);
|
s32 InitLLTTable(struct adapter *padapter, u8 txpktbuf_bndy);
|
||||||
|
|
||||||
/* EFuse */
|
/* EFuse */
|
||||||
|
14
drivers/staging/r8188eu/include/rtw_fw.h
Normal file
14
drivers/staging/r8188eu/include/rtw_fw.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
|
||||||
|
/* Copyright(c) 2007 - 2011 Realtek Corporation. */
|
||||||
|
|
||||||
|
#ifndef __RTW_FW_H__
|
||||||
|
#define __RTW_FW_H__
|
||||||
|
|
||||||
|
#include "drv_types.h"
|
||||||
|
|
||||||
|
#define MAX_REG_BOLCK_SIZE 196
|
||||||
|
|
||||||
|
int rtl8188e_firmware_download(struct adapter *padapter);
|
||||||
|
void rtw_reset_8051(struct adapter *padapter);
|
||||||
|
|
||||||
|
#endif
|
Loading…
x
Reference in New Issue
Block a user