Commit 615a4d12 authored by Larry Finger's avatar Larry Finger Committed by Greg Kroah-Hartman

staging: r8188eu: Add files for new driver - part 14

This commit adds files hal/rtl8188e_hal_init.c, hal/rtl8188e_mp.c,
hal/rtl8188e_phycfg.c, and hal/rtl8188e_rf6052.c.
Signed-off-by: default avatarLarry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 7ef8ded0
/******************************************************************************
*
* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
*
* 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.
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*
*
******************************************************************************/
#define _HAL_INIT_C_
#include <drv_types.h>
#include <rtw_efuse.h>
#include <rtl8188e_hal.h>
#include <rtw_iol.h>
#include <usb_ops.h>
static void iol_mode_enable(struct adapter *padapter, u8 enable)
{
u8 reg_0xf0 = 0;
if (enable) {
/* Enable initial offload */
reg_0xf0 = rtw_read8(padapter, REG_SYS_CFG);
rtw_write8(padapter, REG_SYS_CFG, reg_0xf0|SW_OFFLOAD_EN);
if (!padapter->bFWReady) {
DBG_88E("bFWReady == false call reset 8051...\n");
_8051Reset88E(padapter);
}
} else {
/* disable initial offload */
reg_0xf0 = rtw_read8(padapter, REG_SYS_CFG);
rtw_write8(padapter, REG_SYS_CFG, reg_0xf0 & ~SW_OFFLOAD_EN);
}
}
static s32 iol_execute(struct adapter *padapter, u8 control)
{
s32 status = _FAIL;
u8 reg_0x88 = 0;
u32 start = 0, passing_time = 0;
control = control&0x0f;
reg_0x88 = rtw_read8(padapter, REG_HMEBOX_E0);
rtw_write8(padapter, REG_HMEBOX_E0, reg_0x88|control);
start = rtw_get_current_time();
while ((reg_0x88 = rtw_read8(padapter, REG_HMEBOX_E0)) & control &&
(passing_time = rtw_get_passing_time_ms(start)) < 1000) {
;
}
reg_0x88 = rtw_read8(padapter, REG_HMEBOX_E0);
status = (reg_0x88 & control) ? _FAIL : _SUCCESS;
if (reg_0x88 & control<<4)
status = _FAIL;
return status;
}
static s32 iol_InitLLTTable(struct adapter *padapter, u8 txpktbuf_bndy)
{
s32 rst = _SUCCESS;
iol_mode_enable(padapter, 1);
rtw_write8(padapter, REG_TDECTRL+1, txpktbuf_bndy);
rst = iol_execute(padapter, CMD_INIT_LLT);
iol_mode_enable(padapter, 0);
return rst;
}
static void
efuse_phymap_to_logical(u8 *phymap, u16 _offset, u16 _size_byte, u8 *pbuf)
{
u8 *efuseTbl = NULL;
u8 rtemp8;
u16 eFuse_Addr = 0;
u8 offset, wren;
u16 i, j;
u16 **eFuseWord = NULL;
u16 efuse_utilized = 0;
u8 u1temp = 0;
efuseTbl = (u8 *)rtw_zmalloc(EFUSE_MAP_LEN_88E);
if (efuseTbl == NULL) {
DBG_88E("%s: alloc efuseTbl fail!\n", __func__);
goto exit;
}
eFuseWord = (u16 **)rtw_malloc2d(EFUSE_MAX_SECTION_88E, EFUSE_MAX_WORD_UNIT, sizeof(u16));
if (eFuseWord == NULL) {
DBG_88E("%s: alloc eFuseWord fail!\n", __func__);
goto exit;
}
/* 0. Refresh efuse init map as all oxFF. */
for (i = 0; i < EFUSE_MAX_SECTION_88E; i++)
for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++)
eFuseWord[i][j] = 0xFFFF;
/* */
/* 1. Read the first byte to check if efuse is empty!!! */
/* */
/* */
rtemp8 = *(phymap+eFuse_Addr);
if (rtemp8 != 0xFF) {
efuse_utilized++;
eFuse_Addr++;
} else {
DBG_88E("EFUSE is empty efuse_Addr-%d efuse_data =%x\n", eFuse_Addr, rtemp8);
goto exit;
}
/* */
/* 2. Read real efuse content. Filter PG header and every section data. */
/* */
while ((rtemp8 != 0xFF) && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E)) {
/* Check PG header for section num. */
if ((rtemp8 & 0x1F) == 0x0F) { /* extended header */
u1temp = ((rtemp8 & 0xE0) >> 5);
rtemp8 = *(phymap+eFuse_Addr);
if ((rtemp8 & 0x0F) == 0x0F) {
eFuse_Addr++;
rtemp8 = *(phymap+eFuse_Addr);
if (rtemp8 != 0xFF && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E))
eFuse_Addr++;
continue;
} else {
offset = ((rtemp8 & 0xF0) >> 1) | u1temp;
wren = (rtemp8 & 0x0F);
eFuse_Addr++;
}
} else {
offset = ((rtemp8 >> 4) & 0x0f);
wren = (rtemp8 & 0x0f);
}
if (offset < EFUSE_MAX_SECTION_88E) {
/* Get word enable value from PG header */
for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) {
/* Check word enable condition in the section */
if (!(wren & 0x01)) {
rtemp8 = *(phymap+eFuse_Addr);
eFuse_Addr++;
efuse_utilized++;
eFuseWord[offset][i] = (rtemp8 & 0xff);
if (eFuse_Addr >= EFUSE_REAL_CONTENT_LEN_88E)
break;
rtemp8 = *(phymap+eFuse_Addr);
eFuse_Addr++;
efuse_utilized++;
eFuseWord[offset][i] |= (((u16)rtemp8 << 8) & 0xff00);
if (eFuse_Addr >= EFUSE_REAL_CONTENT_LEN_88E)
break;
}
wren >>= 1;
}
}
/* Read next PG header */
rtemp8 = *(phymap+eFuse_Addr);
if (rtemp8 != 0xFF && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E)) {
efuse_utilized++;
eFuse_Addr++;
}
}
/* */
/* 3. Collect 16 sections and 4 word unit into Efuse map. */
/* */
for (i = 0; i < EFUSE_MAX_SECTION_88E; i++) {
for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) {
efuseTbl[(i*8)+(j*2)] = (eFuseWord[i][j] & 0xff);
efuseTbl[(i*8)+((j*2)+1)] = ((eFuseWord[i][j] >> 8) & 0xff);
}
}
/* */
/* 4. Copy from Efuse map to output pointer memory!!! */
/* */
for (i = 0; i < _size_byte; i++)
pbuf[i] = efuseTbl[_offset+i];
/* */
/* 5. Calculate Efuse utilization. */
/* */
exit:
kfree(efuseTbl);
if (eFuseWord)
rtw_mfree2d((void *)eFuseWord, EFUSE_MAX_SECTION_88E, EFUSE_MAX_WORD_UNIT, sizeof(u16));
}
static void efuse_read_phymap_from_txpktbuf(
struct adapter *adapter,
int bcnhead, /* beacon head, where FW store len(2-byte) and efuse physical map. */
u8 *content, /* buffer to store efuse physical map */
u16 *size /* for efuse content: the max byte to read. will update to byte read */
)
{
u16 dbg_addr = 0;
u32 start = 0, passing_time = 0;
u8 reg_0x143 = 0;
u32 lo32 = 0, hi32 = 0;
u16 len = 0, count = 0;
int i = 0;
u16 limit = *size;
u8 *pos = content;
if (bcnhead < 0) /* if not valid */
bcnhead = rtw_read8(adapter, REG_TDECTRL+1);
DBG_88E("%s bcnhead:%d\n", __func__, bcnhead);
rtw_write8(adapter, REG_PKT_BUFF_ACCESS_CTRL, TXPKT_BUF_SELECT);
dbg_addr = bcnhead*128/8; /* 8-bytes addressing */
while (1) {
rtw_write16(adapter, REG_PKTBUF_DBG_ADDR, dbg_addr+i);
rtw_write8(adapter, REG_TXPKTBUF_DBG, 0);
start = rtw_get_current_time();
while (!(reg_0x143 = rtw_read8(adapter, REG_TXPKTBUF_DBG)) &&
(passing_time = rtw_get_passing_time_ms(start)) < 1000) {
DBG_88E("%s polling reg_0x143:0x%02x, reg_0x106:0x%02x\n", __func__, reg_0x143, rtw_read8(adapter, 0x106));
rtw_usleep_os(100);
}
lo32 = rtw_read32(adapter, REG_PKTBUF_DBG_DATA_L);
hi32 = rtw_read32(adapter, REG_PKTBUF_DBG_DATA_H);
if (i == 0) {
u8 lenc[2];
u16 lenbak, aaabak;
u16 aaa;
lenc[0] = rtw_read8(adapter, REG_PKTBUF_DBG_DATA_L);
lenc[1] = rtw_read8(adapter, REG_PKTBUF_DBG_DATA_L+1);
aaabak = le16_to_cpup((__le16 *)lenc);
lenbak = le16_to_cpu(*((__le16 *)lenc));
aaa = le16_to_cpup((__le16 *)&lo32);
len = le16_to_cpu(*((__le16 *)&lo32));
limit = (len-2 < limit) ? len-2 : limit;
DBG_88E("%s len:%u, lenbak:%u, aaa:%u, aaabak:%u\n", __func__, len, lenbak, aaa, aaabak);
memcpy(pos, ((u8 *)&lo32)+2, (limit >= count+2) ? 2 : limit-count);
count += (limit >= count+2) ? 2 : limit-count;
pos = content+count;
} else {
memcpy(pos, ((u8 *)&lo32), (limit >= count+4) ? 4 : limit-count);
count += (limit >= count+4) ? 4 : limit-count;
pos = content+count;
}
if (limit > count && len-2 > count) {
memcpy(pos, (u8 *)&hi32, (limit >= count+4) ? 4 : limit-count);
count += (limit >= count+4) ? 4 : limit-count;
pos = content+count;
}
if (limit <= count || len-2 <= count)
break;
i++;
}
rtw_write8(adapter, REG_PKT_BUFF_ACCESS_CTRL, DISABLE_TRXPKT_BUF_ACCESS);
DBG_88E("%s read count:%u\n", __func__, count);
*size = count;
}
static s32 iol_read_efuse(struct adapter *padapter, u8 txpktbuf_bndy, u16 offset, u16 size_byte, u8 *logical_map)
{
s32 status = _FAIL;
u8 physical_map[512];
u16 size = 512;
rtw_write8(padapter, REG_TDECTRL+1, txpktbuf_bndy);
_rtw_memset(physical_map, 0xFF, 512);
rtw_write8(padapter, REG_PKT_BUFF_ACCESS_CTRL, TXPKT_BUF_SELECT);
status = iol_execute(padapter, CMD_READ_EFUSE_MAP);
if (status == _SUCCESS)
efuse_read_phymap_from_txpktbuf(padapter, txpktbuf_bndy, physical_map, &size);
efuse_phymap_to_logical(physical_map, offset, size_byte, logical_map);
return status;
}
s32 rtl8188e_iol_efuse_patch(struct adapter *padapter)
{
s32 result = _SUCCESS;
DBG_88E("==> %s\n", __func__);
if (rtw_IOL_applied(padapter)) {
iol_mode_enable(padapter, 1);
result = iol_execute(padapter, CMD_READ_EFUSE_MAP);
if (result == _SUCCESS)
result = iol_execute(padapter, CMD_EFUSE_PATCH);
iol_mode_enable(padapter, 0);
}
return result;
}
static s32 iol_ioconfig(struct adapter *padapter, u8 iocfg_bndy)
{
s32 rst = _SUCCESS;
rtw_write8(padapter, REG_TDECTRL+1, iocfg_bndy);
rst = iol_execute(padapter, CMD_IOCONFIG);
return rst;
}
static int rtl8188e_IOL_exec_cmds_sync(struct adapter *adapter, struct xmit_frame *xmit_frame, u32 max_wating_ms, u32 bndy_cnt)
{
struct pkt_attrib *pattrib = &xmit_frame->attrib;
u8 i;
int ret = _FAIL;
if (rtw_IOL_append_END_cmd(xmit_frame) != _SUCCESS)
goto exit;
if (rtw_usb_bulk_size_boundary(adapter, TXDESC_SIZE+pattrib->last_txcmdsz)) {
if (rtw_IOL_append_END_cmd(xmit_frame) != _SUCCESS)
goto exit;
}
dump_mgntframe_and_wait(adapter, xmit_frame, max_wating_ms);
iol_mode_enable(adapter, 1);
for (i = 0; i < bndy_cnt; i++) {
u8 page_no = 0;
page_no = i*2;
ret = iol_ioconfig(adapter, page_no);
if (ret != _SUCCESS)
break;
}
iol_mode_enable(adapter, 0);
exit:
/* restore BCN_HEAD */
rtw_write8(adapter, REG_TDECTRL+1, 0);
return ret;
}
void rtw_IOL_cmd_tx_pkt_buf_dump(struct adapter *Adapter, int data_len)
{
u32 fifo_data, reg_140;
u32 addr, rstatus, loop = 0;
u16 data_cnts = (data_len/8)+1;
u8 *pbuf = rtw_zvmalloc(data_len+10);
DBG_88E("###### %s ######\n", __func__);
rtw_write8(Adapter, REG_PKT_BUFF_ACCESS_CTRL, TXPKT_BUF_SELECT);
if (pbuf) {
for (addr = 0; addr < data_cnts; addr++) {
rtw_write32(Adapter, 0x140, addr);
rtw_usleep_os(2);
loop = 0;
do {
rstatus = (reg_140 = rtw_read32(Adapter, REG_PKTBUF_DBG_CTRL)&BIT24);
if (rstatus) {
fifo_data = rtw_read32(Adapter, REG_PKTBUF_DBG_DATA_L);
memcpy(pbuf+(addr*8), &fifo_data, 4);
fifo_data = rtw_read32(Adapter, REG_PKTBUF_DBG_DATA_H);
memcpy(pbuf+(addr*8+4), &fifo_data, 4);
}
rtw_usleep_os(2);
} while (!rstatus && (loop++ < 10));
}
rtw_IOL_cmd_buf_dump(Adapter, data_len, pbuf);
rtw_vmfree(pbuf, data_len+10);
}
DBG_88E("###### %s ######\n", __func__);
}
static void _FWDownloadEnable(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 _BlockWrite(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;
if (blockCount_p1) {
RT_TRACE(_module_hal_init_c_, _drv_notice_,
("_BlockWrite: [P1] buffSize(%d) blockSize_p1(%d) blockCount_p1(%d) remainSize_p1(%d)\n",
buffSize, blockSize_p1, blockCount_p1, remainSize_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;
if (blockCount_p2) {
RT_TRACE(_module_hal_init_c_, _drv_notice_,
("_BlockWrite: [P2] buffSize_p2(%d) blockSize_p2(%d) blockCount_p2(%d) remainSize_p2(%d)\n",
(buffSize-offset), blockSize_p2 , blockCount_p2, remainSize_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;
RT_TRACE(_module_hal_init_c_, _drv_notice_,
("_BlockWrite: [P3] buffSize_p3(%d) blockSize_p3(%d) blockCount_p3(%d)\n",
(buffSize-offset), blockSize_p3, blockCount_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 _PageWrite(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 _BlockWrite(padapter, buffer, size);
}
static int _WriteFW(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 = _PageWrite(padapter, page, bufferPtr+offset, MAX_PAGE_SIZE);
if (ret == _FAIL)
goto exit;
}
if (remainSize) {
offset = pageNums * MAX_PAGE_SIZE;
page = pageNums;
ret = _PageWrite(padapter, page, bufferPtr+offset, remainSize);
if (ret == _FAIL)
goto exit;
}
RT_TRACE(_module_hal_init_c_, _drv_info_, ("_WriteFW Done- for Normal chip.\n"));
exit:
return ret;
}
void _8051Reset88E(struct adapter *padapter)
{
u8 u1bTmp;
u1bTmp = rtw_read8(padapter, REG_SYS_FUNC_EN+1);
rtw_write8(padapter, REG_SYS_FUNC_EN+1, u1bTmp&(~BIT2));
rtw_write8(padapter, REG_SYS_FUNC_EN+1, u1bTmp|(BIT2));
DBG_88E("=====> _8051Reset88E(): 8051 reset success .\n");
}
static s32 _FWFreeToGo(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);
_8051Reset88E(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;
}
rtw_udelay_os(5);
} while (counter++ < POLLING_READY_TIMEOUT_COUNT);
DBG_88E("%s: Polling FW ready fail!! REG_MCUFWDL:0x%08x\n", __func__, value32);
return _FAIL;
}
#define IS_FW_81xxC(padapter) (((GET_HAL_DATA(padapter))->FirmwareSignature & 0xFFF0) == 0x88C0)
s32 rtl8188e_FirmwareDownload(struct adapter *padapter)
{
s32 rtStatus = _SUCCESS;
u8 writeFW_retry = 0;
u32 fwdl_start_time;
struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter);
u8 *FwImage;
u32 FwImageLen;
struct rt_firmware *pFirmware = NULL;
struct rt_firmware_hdr *pFwHdr = NULL;
u8 *pFirmwareBuf;
u32 FirmwareLen;
RT_TRACE(_module_hal_init_c_, _drv_info_, ("+%s\n", __func__));
pFirmware = (struct rt_firmware *)rtw_zmalloc(sizeof(struct rt_firmware));
if (!pFirmware) {
rtStatus = _FAIL;
goto Exit;
}
FwImage = (u8 *)Rtl8188E_FwImageArray;
FwImageLen = Rtl8188E_FWImgArrayLength;
pFirmware->eFWSource = FW_SOURCE_HEADER_FILE;
switch (pFirmware->eFWSource) {
case FW_SOURCE_IMG_FILE:
break;
case FW_SOURCE_HEADER_FILE:
if (FwImageLen > FW_8188E_SIZE) {
rtStatus = _FAIL;
RT_TRACE(_module_hal_init_c_, _drv_err_, ("Firmware size exceed 0x%X. Check it.\n", FW_8188E_SIZE));
goto Exit;
}
pFirmware->szFwBuffer = FwImage;
pFirmware->ulFwLength = FwImageLen;
break;
}
pFirmwareBuf = pFirmware->szFwBuffer;
FirmwareLen = pFirmware->ulFwLength;
DBG_88E_LEVEL(_drv_info_, "+%s: !bUsedWoWLANFw, FmrmwareLen:%d+\n", __func__, FirmwareLen);
/* To Check Fw header. Added by tynli. 2009.12.04. */
pFwHdr = (struct rt_firmware_hdr *)pFirmware->szFwBuffer;
pHalData->FirmwareVersion = le16_to_cpu(pFwHdr->Version);
pHalData->FirmwareSubVersion = pFwHdr->Subversion;
pHalData->FirmwareSignature = le16_to_cpu(pFwHdr->Signature);
DBG_88E("%s: fw_ver =%d fw_subver =%d sig = 0x%x\n",
__func__, pHalData->FirmwareVersion, pHalData->FirmwareSubVersion, pHalData->FirmwareSignature);
if (IS_FW_HEADER_EXIST(pFwHdr)) {
/* Shift 32 bytes for FW header */
pFirmwareBuf = pFirmwareBuf + 32;
FirmwareLen = FirmwareLen - 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);
_8051Reset88E(padapter);
}
_FWDownloadEnable(padapter, true);
fwdl_start_time = rtw_get_current_time();
while (1) {
/* reset the FWDL chksum */
rtw_write8(padapter, REG_MCUFWDL, rtw_read8(padapter, REG_MCUFWDL) | FWDL_ChkSum_rpt);
rtStatus = _WriteFW(padapter, pFirmwareBuf, FirmwareLen);
if (rtStatus == _SUCCESS ||
(rtw_get_passing_time_ms(fwdl_start_time) > 500 && writeFW_retry++ >= 3))
break;
DBG_88E("%s writeFW_retry:%u, time after fwdl_start_time:%ums\n",
__func__, writeFW_retry, rtw_get_passing_time_ms(fwdl_start_time)
);
}
_FWDownloadEnable(padapter, false);
if (_SUCCESS != rtStatus) {
DBG_88E("DL Firmware failed!\n");
goto Exit;
}
rtStatus = _FWFreeToGo(padapter);
if (_SUCCESS != rtStatus) {
DBG_88E("DL Firmware failed!\n");
goto Exit;
}
RT_TRACE(_module_hal_init_c_, _drv_info_, ("Firmware is ready to run!\n"));
Exit:
kfree(pFirmware);
return rtStatus;
}
void rtl8188e_InitializeFirmwareVars(struct adapter *padapter)
{
struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter);
/* Init Fw LPS related. */
padapter->pwrctrlpriv.bFwCurrentInPSMode = false;
/* Init H2C counter. by tynli. 2009.12.09. */
pHalData->LastHMEBoxNum = 0;
}
static void rtl8188e_free_hal_data(struct adapter *padapter)
{
_func_enter_;
kfree(padapter->HalData);
padapter->HalData = NULL;
_func_exit_;
}
/* */
/* Efuse related code */
/* */
enum{
VOLTAGE_V25 = 0x03,
LDOE25_SHIFT = 28 ,
};
static bool
hal_EfusePgPacketWrite2ByteHeader(
struct adapter *pAdapter,
u8 efuseType,
u16 *pAddr,
struct pgpkt *pTargetPkt,
bool bPseudoTest);
static bool
hal_EfusePgPacketWrite1ByteHeader(
struct adapter *pAdapter,
u8 efuseType,
u16 *pAddr,
struct pgpkt *pTargetPkt,
bool bPseudoTest);
static bool
hal_EfusePgPacketWriteData(
struct adapter *pAdapter,
u8 efuseType,
u16 *pAddr,
struct pgpkt *pTargetPkt,
bool bPseudoTest);
static void
hal_EfusePowerSwitch_RTL8188E(
struct adapter *pAdapter,
u8 bWrite,
u8 PwrState)
{
u8 tempval;
u16 tmpV16;
if (PwrState) {
rtw_write8(pAdapter, REG_EFUSE_ACCESS, EFUSE_ACCESS_ON);
/* 1.2V Power: From VDDON with Power Cut(0x0000h[15]), defualt valid */
tmpV16 = rtw_read16(pAdapter, REG_SYS_ISO_CTRL);
if (!(tmpV16 & PWC_EV12V)) {
tmpV16 |= PWC_EV12V;
rtw_write16(pAdapter, REG_SYS_ISO_CTRL, tmpV16);
}
/* Reset: 0x0000h[28], default valid */
tmpV16 = rtw_read16(pAdapter, REG_SYS_FUNC_EN);
if (!(tmpV16 & FEN_ELDR)) {
tmpV16 |= FEN_ELDR;
rtw_write16(pAdapter, REG_SYS_FUNC_EN, tmpV16);
}
/* Clock: Gated(0x0008h[5]) 8M(0x0008h[1]) clock from ANA, default valid */
tmpV16 = rtw_read16(pAdapter, REG_SYS_CLKR);
if ((!(tmpV16 & LOADER_CLK_EN)) || (!(tmpV16 & ANA8M))) {
tmpV16 |= (LOADER_CLK_EN | ANA8M);
rtw_write16(pAdapter, REG_SYS_CLKR, tmpV16);
}
if (bWrite) {
/* Enable LDO 2.5V before read/write action */
tempval = rtw_read8(pAdapter, EFUSE_TEST+3);
tempval &= 0x0F;
tempval |= (VOLTAGE_V25 << 4);
rtw_write8(pAdapter, EFUSE_TEST+3, (tempval | 0x80));
}
} else {
rtw_write8(pAdapter, REG_EFUSE_ACCESS, EFUSE_ACCESS_OFF);
if (bWrite) {
/* Disable LDO 2.5V after read/write action */
tempval = rtw_read8(pAdapter, EFUSE_TEST+3);
rtw_write8(pAdapter, EFUSE_TEST+3, (tempval & 0x7F));
}
}
}
static void
rtl8188e_EfusePowerSwitch(
struct adapter *pAdapter,
u8 bWrite,
u8 PwrState)
{
hal_EfusePowerSwitch_RTL8188E(pAdapter, bWrite, PwrState);
}
static void Hal_EfuseReadEFuse88E(struct adapter *Adapter,
u16 _offset,
u16 _size_byte,
u8 *pbuf,
bool bPseudoTest
)
{
u8 *efuseTbl = NULL;
u8 rtemp8[1];
u16 eFuse_Addr = 0;
u8 offset, wren;
u16 i, j;
u16 **eFuseWord = NULL;
u16 efuse_utilized = 0;
u8 u1temp = 0;
/* */
/* Do NOT excess total size of EFuse table. Added by Roger, 2008.11.10. */
/* */
if ((_offset + _size_byte) > EFUSE_MAP_LEN_88E) {/* total E-Fuse table is 512bytes */
DBG_88E("Hal_EfuseReadEFuse88E(): Invalid offset(%#x) with read bytes(%#x)!!\n", _offset, _size_byte);
goto exit;
}
efuseTbl = (u8 *)rtw_zmalloc(EFUSE_MAP_LEN_88E);
if (efuseTbl == NULL) {
DBG_88E("%s: alloc efuseTbl fail!\n", __func__);
goto exit;
}
eFuseWord = (u16 **)rtw_malloc2d(EFUSE_MAX_SECTION_88E, EFUSE_MAX_WORD_UNIT, sizeof(u16));
if (eFuseWord == NULL) {
DBG_88E("%s: alloc eFuseWord fail!\n", __func__);
goto exit;
}
/* 0. Refresh efuse init map as all oxFF. */
for (i = 0; i < EFUSE_MAX_SECTION_88E; i++)
for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++)
eFuseWord[i][j] = 0xFFFF;
/* */
/* 1. Read the first byte to check if efuse is empty!!! */
/* */
/* */
ReadEFuseByte(Adapter, eFuse_Addr, rtemp8, bPseudoTest);
if (*rtemp8 != 0xFF) {
efuse_utilized++;
eFuse_Addr++;
} else {
DBG_88E("EFUSE is empty efuse_Addr-%d efuse_data =%x\n", eFuse_Addr, *rtemp8);
goto exit;
}
/* */
/* 2. Read real efuse content. Filter PG header and every section data. */
/* */
while ((*rtemp8 != 0xFF) && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E)) {
/* Check PG header for section num. */
if ((*rtemp8 & 0x1F) == 0x0F) { /* extended header */
u1temp = ((*rtemp8 & 0xE0) >> 5);
ReadEFuseByte(Adapter, eFuse_Addr, rtemp8, bPseudoTest);
if ((*rtemp8 & 0x0F) == 0x0F) {
eFuse_Addr++;
ReadEFuseByte(Adapter, eFuse_Addr, rtemp8, bPseudoTest);
if (*rtemp8 != 0xFF && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E))
eFuse_Addr++;
continue;
} else {
offset = ((*rtemp8 & 0xF0) >> 1) | u1temp;
wren = (*rtemp8 & 0x0F);
eFuse_Addr++;
}
} else {
offset = ((*rtemp8 >> 4) & 0x0f);
wren = (*rtemp8 & 0x0f);
}
if (offset < EFUSE_MAX_SECTION_88E) {
/* Get word enable value from PG header */
for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) {
/* Check word enable condition in the section */
if (!(wren & 0x01)) {
ReadEFuseByte(Adapter, eFuse_Addr, rtemp8, bPseudoTest);
eFuse_Addr++;
efuse_utilized++;
eFuseWord[offset][i] = (*rtemp8 & 0xff);
if (eFuse_Addr >= EFUSE_REAL_CONTENT_LEN_88E)
break;
ReadEFuseByte(Adapter, eFuse_Addr, rtemp8, bPseudoTest);
eFuse_Addr++;
efuse_utilized++;
eFuseWord[offset][i] |= (((u16)*rtemp8 << 8) & 0xff00);
if (eFuse_Addr >= EFUSE_REAL_CONTENT_LEN_88E)
break;
}
wren >>= 1;
}
}
/* Read next PG header */
ReadEFuseByte(Adapter, eFuse_Addr, rtemp8, bPseudoTest);
if (*rtemp8 != 0xFF && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E)) {
efuse_utilized++;
eFuse_Addr++;
}
}
/* 3. Collect 16 sections and 4 word unit into Efuse map. */
for (i = 0; i < EFUSE_MAX_SECTION_88E; i++) {
for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) {
efuseTbl[(i*8)+(j*2)] = (eFuseWord[i][j] & 0xff);
efuseTbl[(i*8)+((j*2)+1)] = ((eFuseWord[i][j] >> 8) & 0xff);
}
}
/* 4. Copy from Efuse map to output pointer memory!!! */
for (i = 0; i < _size_byte; i++)
pbuf[i] = efuseTbl[_offset+i];
/* 5. Calculate Efuse utilization. */
rtw_hal_set_hwreg(Adapter, HW_VAR_EFUSE_BYTES, (u8 *)&eFuse_Addr);
exit:
kfree(efuseTbl);
if (eFuseWord)
rtw_mfree2d((void *)eFuseWord, EFUSE_MAX_SECTION_88E, EFUSE_MAX_WORD_UNIT, sizeof(u16));
}
static void ReadEFuseByIC(struct adapter *Adapter, u8 efuseType, u16 _offset, u16 _size_byte, u8 *pbuf, bool bPseudoTest)
{
if (!bPseudoTest) {
int ret = _FAIL;
if (rtw_IOL_applied(Adapter)) {
rtw_hal_power_on(Adapter);
iol_mode_enable(Adapter, 1);
ret = iol_read_efuse(Adapter, 0, _offset, _size_byte, pbuf);
iol_mode_enable(Adapter, 0);
if (_SUCCESS == ret)
goto exit;
}
}
Hal_EfuseReadEFuse88E(Adapter, _offset, _size_byte, pbuf, bPseudoTest);
exit:
return;
}
static void ReadEFuse_Pseudo(struct adapter *Adapter, u8 efuseType, u16 _offset, u16 _size_byte, u8 *pbuf, bool bPseudoTest)
{
Hal_EfuseReadEFuse88E(Adapter, _offset, _size_byte, pbuf, bPseudoTest);
}
static void rtl8188e_ReadEFuse(struct adapter *Adapter, u8 efuseType,
u16 _offset, u16 _size_byte, u8 *pbuf,
bool bPseudoTest)
{
if (bPseudoTest)
ReadEFuse_Pseudo (Adapter, efuseType, _offset, _size_byte, pbuf, bPseudoTest);
else
ReadEFuseByIC(Adapter, efuseType, _offset, _size_byte, pbuf, bPseudoTest);
}
/* Do not support BT */
static void Hal_EFUSEGetEfuseDefinition88E(struct adapter *pAdapter, u8 efuseType, u8 type, void *pOut)
{
switch (type) {
case TYPE_EFUSE_MAX_SECTION:
{
u8 *pMax_section;
pMax_section = (u8 *)pOut;
*pMax_section = EFUSE_MAX_SECTION_88E;
}
break;
case TYPE_EFUSE_REAL_CONTENT_LEN:
{
u16 *pu2Tmp;
pu2Tmp = (u16 *)pOut;
*pu2Tmp = EFUSE_REAL_CONTENT_LEN_88E;
}
break;
case TYPE_EFUSE_CONTENT_LEN_BANK:
{
u16 *pu2Tmp;
pu2Tmp = (u16 *)pOut;
*pu2Tmp = EFUSE_REAL_CONTENT_LEN_88E;
}
break;
case TYPE_AVAILABLE_EFUSE_BYTES_BANK:
{
u16 *pu2Tmp;
pu2Tmp = (u16 *)pOut;
*pu2Tmp = (u16)(EFUSE_REAL_CONTENT_LEN_88E-EFUSE_OOB_PROTECT_BYTES_88E);
}
break;
case TYPE_AVAILABLE_EFUSE_BYTES_TOTAL:
{
u16 *pu2Tmp;
pu2Tmp = (u16 *)pOut;
*pu2Tmp = (u16)(EFUSE_REAL_CONTENT_LEN_88E-EFUSE_OOB_PROTECT_BYTES_88E);
}
break;
case TYPE_EFUSE_MAP_LEN:
{
u16 *pu2Tmp;
pu2Tmp = (u16 *)pOut;
*pu2Tmp = (u16)EFUSE_MAP_LEN_88E;
}
break;
case TYPE_EFUSE_PROTECT_BYTES_BANK:
{
u8 *pu1Tmp;
pu1Tmp = (u8 *)pOut;
*pu1Tmp = (u8)(EFUSE_OOB_PROTECT_BYTES_88E);
}
break;
default:
{
u8 *pu1Tmp;
pu1Tmp = (u8 *)pOut;
*pu1Tmp = 0;
}
break;
}
}
static void Hal_EFUSEGetEfuseDefinition_Pseudo88E(struct adapter *pAdapter, u8 efuseType, u8 type, void *pOut)
{
switch (type) {
case TYPE_EFUSE_MAX_SECTION:
{
u8 *pMax_section;
pMax_section = (u8 *)pOut;
*pMax_section = EFUSE_MAX_SECTION_88E;
}
break;
case TYPE_EFUSE_REAL_CONTENT_LEN:
{
u16 *pu2Tmp;
pu2Tmp = (u16 *)pOut;
*pu2Tmp = EFUSE_REAL_CONTENT_LEN_88E;
}
break;
case TYPE_EFUSE_CONTENT_LEN_BANK:
{
u16 *pu2Tmp;
pu2Tmp = (u16 *)pOut;
*pu2Tmp = EFUSE_REAL_CONTENT_LEN_88E;
}
break;
case TYPE_AVAILABLE_EFUSE_BYTES_BANK:
{
u16 *pu2Tmp;
pu2Tmp = (u16 *)pOut;
*pu2Tmp = (u16)(EFUSE_REAL_CONTENT_LEN_88E-EFUSE_OOB_PROTECT_BYTES_88E);
}
break;
case TYPE_AVAILABLE_EFUSE_BYTES_TOTAL:
{
u16 *pu2Tmp;
pu2Tmp = (u16 *)pOut;
*pu2Tmp = (u16)(EFUSE_REAL_CONTENT_LEN_88E-EFUSE_OOB_PROTECT_BYTES_88E);
}
break;
case TYPE_EFUSE_MAP_LEN:
{
u16 *pu2Tmp;
pu2Tmp = (u16 *)pOut;
*pu2Tmp = (u16)EFUSE_MAP_LEN_88E;
}
break;
case TYPE_EFUSE_PROTECT_BYTES_BANK:
{
u8 *pu1Tmp;
pu1Tmp = (u8 *)pOut;
*pu1Tmp = (u8)(EFUSE_OOB_PROTECT_BYTES_88E);
}
break;
default:
{
u8 *pu1Tmp;
pu1Tmp = (u8 *)pOut;
*pu1Tmp = 0;
}
break;
}
}
static void rtl8188e_EFUSE_GetEfuseDefinition(struct adapter *pAdapter, u8 efuseType, u8 type, void *pOut, bool bPseudoTest)
{
if (bPseudoTest)
Hal_EFUSEGetEfuseDefinition_Pseudo88E(pAdapter, efuseType, type, pOut);
else
Hal_EFUSEGetEfuseDefinition88E(pAdapter, efuseType, type, pOut);
}
static u8 Hal_EfuseWordEnableDataWrite(struct adapter *pAdapter, u16 efuse_addr, u8 word_en, u8 *data, bool bPseudoTest)
{
u16 tmpaddr = 0;
u16 start_addr = efuse_addr;
u8 badworden = 0x0F;
u8 tmpdata[8];
_rtw_memset((void *)tmpdata, 0xff, PGPKT_DATA_SIZE);
if (!(word_en&BIT0)) {
tmpaddr = start_addr;
efuse_OneByteWrite(pAdapter, start_addr++, data[0], bPseudoTest);
efuse_OneByteWrite(pAdapter, start_addr++, data[1], bPseudoTest);
efuse_OneByteRead(pAdapter, tmpaddr, &tmpdata[0], bPseudoTest);
efuse_OneByteRead(pAdapter, tmpaddr+1, &tmpdata[1], bPseudoTest);
if ((data[0] != tmpdata[0]) || (data[1] != tmpdata[1]))
badworden &= (~BIT0);
}
if (!(word_en&BIT1)) {
tmpaddr = start_addr;
efuse_OneByteWrite(pAdapter, start_addr++, data[2], bPseudoTest);
efuse_OneByteWrite(pAdapter, start_addr++, data[3], bPseudoTest);
efuse_OneByteRead(pAdapter, tmpaddr , &tmpdata[2], bPseudoTest);
efuse_OneByteRead(pAdapter, tmpaddr+1, &tmpdata[3], bPseudoTest);
if ((data[2] != tmpdata[2]) || (data[3] != tmpdata[3]))
badworden &= (~BIT1);
}
if (!(word_en&BIT2)) {
tmpaddr = start_addr;
efuse_OneByteWrite(pAdapter, start_addr++, data[4], bPseudoTest);
efuse_OneByteWrite(pAdapter, start_addr++, data[5], bPseudoTest);
efuse_OneByteRead(pAdapter, tmpaddr, &tmpdata[4], bPseudoTest);
efuse_OneByteRead(pAdapter, tmpaddr+1, &tmpdata[5], bPseudoTest);
if ((data[4] != tmpdata[4]) || (data[5] != tmpdata[5]))
badworden &= (~BIT2);
}
if (!(word_en&BIT3)) {
tmpaddr = start_addr;
efuse_OneByteWrite(pAdapter, start_addr++, data[6], bPseudoTest);
efuse_OneByteWrite(pAdapter, start_addr++, data[7], bPseudoTest);
efuse_OneByteRead(pAdapter, tmpaddr, &tmpdata[6], bPseudoTest);
efuse_OneByteRead(pAdapter, tmpaddr+1, &tmpdata[7], bPseudoTest);
if ((data[6] != tmpdata[6]) || (data[7] != tmpdata[7]))
badworden &= (~BIT3);
}
return badworden;
}
static u8 Hal_EfuseWordEnableDataWrite_Pseudo(struct adapter *pAdapter, u16 efuse_addr, u8 word_en, u8 *data, bool bPseudoTest)
{
u8 ret;
ret = Hal_EfuseWordEnableDataWrite(pAdapter, efuse_addr, word_en, data, bPseudoTest);
return ret;
}
static u8 rtl8188e_Efuse_WordEnableDataWrite(struct adapter *pAdapter, u16 efuse_addr, u8 word_en, u8 *data, bool bPseudoTest)
{
u8 ret = 0;
if (bPseudoTest)
ret = Hal_EfuseWordEnableDataWrite_Pseudo (pAdapter, efuse_addr, word_en, data, bPseudoTest);
else
ret = Hal_EfuseWordEnableDataWrite(pAdapter, efuse_addr, word_en, data, bPseudoTest);
return ret;
}
static u16 hal_EfuseGetCurrentSize_8188e(struct adapter *pAdapter, bool bPseudoTest)
{
int bContinual = true;
u16 efuse_addr = 0;
u8 hoffset = 0, hworden = 0;
u8 efuse_data, word_cnts = 0;
if (bPseudoTest)
efuse_addr = (u16)(fakeEfuseUsedBytes);
else
rtw_hal_get_hwreg(pAdapter, HW_VAR_EFUSE_BYTES, (u8 *)&efuse_addr);
while (bContinual &&
efuse_OneByteRead(pAdapter, efuse_addr, &efuse_data, bPseudoTest) &&
AVAILABLE_EFUSE_ADDR(efuse_addr)) {
if (efuse_data != 0xFF) {
if ((efuse_data&0x1F) == 0x0F) { /* extended header */
hoffset = efuse_data;
efuse_addr++;
efuse_OneByteRead(pAdapter, efuse_addr, &efuse_data, bPseudoTest);
if ((efuse_data & 0x0F) == 0x0F) {
efuse_addr++;
continue;
} else {
hoffset = ((hoffset & 0xE0) >> 5) | ((efuse_data & 0xF0) >> 1);
hworden = efuse_data & 0x0F;
}
} else {
hoffset = (efuse_data>>4) & 0x0F;
hworden = efuse_data & 0x0F;
}
word_cnts = Efuse_CalculateWordCnts(hworden);
/* read next header */
efuse_addr = efuse_addr + (word_cnts*2)+1;
} else {
bContinual = false;
}
}
if (bPseudoTest)
fakeEfuseUsedBytes = efuse_addr;
else
rtw_hal_set_hwreg(pAdapter, HW_VAR_EFUSE_BYTES, (u8 *)&efuse_addr);
return efuse_addr;
}
static u16 Hal_EfuseGetCurrentSize_Pseudo(struct adapter *pAdapter, bool bPseudoTest)
{
u16 ret = 0;
ret = hal_EfuseGetCurrentSize_8188e(pAdapter, bPseudoTest);
return ret;
}
static u16 rtl8188e_EfuseGetCurrentSize(struct adapter *pAdapter, u8 efuseType, bool bPseudoTest)
{
u16 ret = 0;
if (bPseudoTest)
ret = Hal_EfuseGetCurrentSize_Pseudo(pAdapter, bPseudoTest);
else
ret = hal_EfuseGetCurrentSize_8188e(pAdapter, bPseudoTest);
return ret;
}
static int hal_EfusePgPacketRead_8188e(struct adapter *pAdapter, u8 offset, u8 *data, bool bPseudoTest)
{
u8 ReadState = PG_STATE_HEADER;
int bContinual = true;
int bDataEmpty = true;
u8 efuse_data, word_cnts = 0;
u16 efuse_addr = 0;
u8 hoffset = 0, hworden = 0;
u8 tmpidx = 0;
u8 tmpdata[8];
u8 max_section = 0;
u8 tmp_header = 0;
EFUSE_GetEfuseDefinition(pAdapter, EFUSE_WIFI, TYPE_EFUSE_MAX_SECTION, (void *)&max_section, bPseudoTest);
if (data == NULL)
return false;
if (offset > max_section)
return false;
_rtw_memset((void *)data, 0xff, sizeof(u8)*PGPKT_DATA_SIZE);
_rtw_memset((void *)tmpdata, 0xff, sizeof(u8)*PGPKT_DATA_SIZE);
/* <Roger_TODO> Efuse has been pre-programmed dummy 5Bytes at the end of Efuse by CP. */
/* Skip dummy parts to prevent unexpected data read from Efuse. */
/* By pass right now. 2009.02.19. */
while (bContinual && AVAILABLE_EFUSE_ADDR(efuse_addr)) {
/* Header Read ------------- */
if (ReadState & PG_STATE_HEADER) {
if (efuse_OneByteRead(pAdapter, efuse_addr, &efuse_data, bPseudoTest) && (efuse_data != 0xFF)) {
if (EXT_HEADER(efuse_data)) {
tmp_header = efuse_data;
efuse_addr++;
efuse_OneByteRead(pAdapter, efuse_addr, &efuse_data, bPseudoTest);
if (!ALL_WORDS_DISABLED(efuse_data)) {
hoffset = ((tmp_header & 0xE0) >> 5) | ((efuse_data & 0xF0) >> 1);
hworden = efuse_data & 0x0F;
} else {
DBG_88E("Error, All words disabled\n");
efuse_addr++;
continue;
}
} else {
hoffset = (efuse_data>>4) & 0x0F;
hworden = efuse_data & 0x0F;
}
word_cnts = Efuse_CalculateWordCnts(hworden);
bDataEmpty = true;
if (hoffset == offset) {
for (tmpidx = 0; tmpidx < word_cnts*2; tmpidx++) {
if (efuse_OneByteRead(pAdapter, efuse_addr+1+tmpidx, &efuse_data, bPseudoTest)) {
tmpdata[tmpidx] = efuse_data;
if (efuse_data != 0xff)
bDataEmpty = false;
}
}
if (bDataEmpty == false) {
ReadState = PG_STATE_DATA;
} else {/* read next header */
efuse_addr = efuse_addr + (word_cnts*2)+1;
ReadState = PG_STATE_HEADER;
}
} else {/* read next header */
efuse_addr = efuse_addr + (word_cnts*2)+1;
ReadState = PG_STATE_HEADER;
}
} else {
bContinual = false;
}
} else if (ReadState & PG_STATE_DATA) {
/* Data section Read ------------- */
efuse_WordEnableDataRead(hworden, tmpdata, data);
efuse_addr = efuse_addr + (word_cnts*2)+1;
ReadState = PG_STATE_HEADER;
}
}
if ((data[0] == 0xff) && (data[1] == 0xff) && (data[2] == 0xff) && (data[3] == 0xff) &&
(data[4] == 0xff) && (data[5] == 0xff) && (data[6] == 0xff) && (data[7] == 0xff))
return false;
else
return true;
}
static int Hal_EfusePgPacketRead(struct adapter *pAdapter, u8 offset, u8 *data, bool bPseudoTest)
{
int ret;
ret = hal_EfusePgPacketRead_8188e(pAdapter, offset, data, bPseudoTest);
return ret;
}
static int Hal_EfusePgPacketRead_Pseudo(struct adapter *pAdapter, u8 offset, u8 *data, bool bPseudoTest)
{
int ret;
ret = hal_EfusePgPacketRead_8188e(pAdapter, offset, data, bPseudoTest);
return ret;
}
static int rtl8188e_Efuse_PgPacketRead(struct adapter *pAdapter, u8 offset, u8 *data, bool bPseudoTest)
{
int ret;
if (bPseudoTest)
ret = Hal_EfusePgPacketRead_Pseudo (pAdapter, offset, data, bPseudoTest);
else
ret = Hal_EfusePgPacketRead(pAdapter, offset, data, bPseudoTest);
return ret;
}
static bool hal_EfuseFixHeaderProcess(struct adapter *pAdapter, u8 efuseType, struct pgpkt *pFixPkt, u16 *pAddr, bool bPseudoTest)
{
u8 originaldata[8], badworden = 0;
u16 efuse_addr = *pAddr;
u32 PgWriteSuccess = 0;
_rtw_memset((void *)originaldata, 0xff, 8);
if (Efuse_PgPacketRead(pAdapter, pFixPkt->offset, originaldata, bPseudoTest)) {
/* check if data exist */
badworden = Efuse_WordEnableDataWrite(pAdapter, efuse_addr+1, pFixPkt->word_en, originaldata, bPseudoTest);
if (badworden != 0xf) { /* write fail */
PgWriteSuccess = Efuse_PgPacketWrite(pAdapter, pFixPkt->offset, badworden, originaldata, bPseudoTest);
if (!PgWriteSuccess)
return false;
else
efuse_addr = Efuse_GetCurrentSize(pAdapter, efuseType, bPseudoTest);
} else {
efuse_addr = efuse_addr + (pFixPkt->word_cnts*2) + 1;
}
} else {
efuse_addr = efuse_addr + (pFixPkt->word_cnts*2) + 1;
}
*pAddr = efuse_addr;
return true;
}
static bool hal_EfusePgPacketWrite2ByteHeader(struct adapter *pAdapter, u8 efuseType, u16 *pAddr, struct pgpkt *pTargetPkt, bool bPseudoTest)
{
bool bRet = false;
u16 efuse_addr = *pAddr, efuse_max_available_len = 0;
u8 pg_header = 0, tmp_header = 0, pg_header_temp = 0;
u8 repeatcnt = 0;
EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_AVAILABLE_EFUSE_BYTES_BANK, (void *)&efuse_max_available_len, bPseudoTest);
while (efuse_addr < efuse_max_available_len) {
pg_header = ((pTargetPkt->offset & 0x07) << 5) | 0x0F;
efuse_OneByteWrite(pAdapter, efuse_addr, pg_header, bPseudoTest);
efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header, bPseudoTest);
while (tmp_header == 0xFF) {
if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_)
return false;
efuse_OneByteWrite(pAdapter, efuse_addr, pg_header, bPseudoTest);
efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header, bPseudoTest);
}
/* to write ext_header */
if (tmp_header == pg_header) {
efuse_addr++;
pg_header_temp = pg_header;
pg_header = ((pTargetPkt->offset & 0x78) << 1) | pTargetPkt->word_en;
efuse_OneByteWrite(pAdapter, efuse_addr, pg_header, bPseudoTest);
efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header, bPseudoTest);
while (tmp_header == 0xFF) {
if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_)
return false;
efuse_OneByteWrite(pAdapter, efuse_addr, pg_header, bPseudoTest);
efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header, bPseudoTest);
}
if ((tmp_header & 0x0F) == 0x0F) { /* word_en PG fail */
if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) {
return false;
} else {
efuse_addr++;
continue;
}
} else if (pg_header != tmp_header) { /* offset PG fail */
struct pgpkt fixPkt;
fixPkt.offset = ((pg_header_temp & 0xE0) >> 5) | ((tmp_header & 0xF0) >> 1);
fixPkt.word_en = tmp_header & 0x0F;
fixPkt.word_cnts = Efuse_CalculateWordCnts(fixPkt.word_en);
if (!hal_EfuseFixHeaderProcess(pAdapter, efuseType, &fixPkt, &efuse_addr, bPseudoTest))
return false;
} else {
bRet = true;
break;
}
} else if ((tmp_header & 0x1F) == 0x0F) { /* wrong extended header */
efuse_addr += 2;
continue;
}
}
*pAddr = efuse_addr;
return bRet;
}
static bool hal_EfusePgPacketWrite1ByteHeader(struct adapter *pAdapter, u8 efuseType, u16 *pAddr, struct pgpkt *pTargetPkt, bool bPseudoTest)
{
bool bRet = false;
u8 pg_header = 0, tmp_header = 0;
u16 efuse_addr = *pAddr;
u8 repeatcnt = 0;
pg_header = ((pTargetPkt->offset << 4) & 0xf0) | pTargetPkt->word_en;
efuse_OneByteWrite(pAdapter, efuse_addr, pg_header, bPseudoTest);
efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header, bPseudoTest);
while (tmp_header == 0xFF) {
if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_)
return false;
efuse_OneByteWrite(pAdapter, efuse_addr, pg_header, bPseudoTest);
efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header, bPseudoTest);
}
if (pg_header == tmp_header) {
bRet = true;
} else {
struct pgpkt fixPkt;
fixPkt.offset = (tmp_header>>4) & 0x0F;
fixPkt.word_en = tmp_header & 0x0F;
fixPkt.word_cnts = Efuse_CalculateWordCnts(fixPkt.word_en);
if (!hal_EfuseFixHeaderProcess(pAdapter, efuseType, &fixPkt, &efuse_addr, bPseudoTest))
return false;
}
*pAddr = efuse_addr;
return bRet;
}
static bool hal_EfusePgPacketWriteData(struct adapter *pAdapter, u8 efuseType, u16 *pAddr, struct pgpkt *pTargetPkt, bool bPseudoTest)
{
bool bRet = false;
u16 efuse_addr = *pAddr;
u8 badworden = 0;
u32 PgWriteSuccess = 0;
badworden = 0x0f;
badworden = Efuse_WordEnableDataWrite(pAdapter, efuse_addr+1, pTargetPkt->word_en, pTargetPkt->data, bPseudoTest);
if (badworden == 0x0F) {
/* write ok */
return true;
} else {
/* reorganize other pg packet */
PgWriteSuccess = Efuse_PgPacketWrite(pAdapter, pTargetPkt->offset, badworden, pTargetPkt->data, bPseudoTest);
if (!PgWriteSuccess)
return false;
else
return true;
}
return bRet;
}
static bool
hal_EfusePgPacketWriteHeader(
struct adapter *pAdapter,
u8 efuseType,
u16 *pAddr,
struct pgpkt *pTargetPkt,
bool bPseudoTest)
{
bool bRet = false;
if (pTargetPkt->offset >= EFUSE_MAX_SECTION_BASE)
bRet = hal_EfusePgPacketWrite2ByteHeader(pAdapter, efuseType, pAddr, pTargetPkt, bPseudoTest);
else
bRet = hal_EfusePgPacketWrite1ByteHeader(pAdapter, efuseType, pAddr, pTargetPkt, bPseudoTest);
return bRet;
}
static bool wordEnMatched(struct pgpkt *pTargetPkt, struct pgpkt *pCurPkt,
u8 *pWden)
{
u8 match_word_en = 0x0F; /* default all words are disabled */
/* check if the same words are enabled both target and current PG packet */
if (((pTargetPkt->word_en & BIT0) == 0) &&
((pCurPkt->word_en & BIT0) == 0))
match_word_en &= ~BIT0; /* enable word 0 */
if (((pTargetPkt->word_en & BIT1) == 0) &&
((pCurPkt->word_en & BIT1) == 0))
match_word_en &= ~BIT1; /* enable word 1 */
if (((pTargetPkt->word_en & BIT2) == 0) &&
((pCurPkt->word_en & BIT2) == 0))
match_word_en &= ~BIT2; /* enable word 2 */
if (((pTargetPkt->word_en & BIT3) == 0) &&
((pCurPkt->word_en & BIT3) == 0))
match_word_en &= ~BIT3; /* enable word 3 */
*pWden = match_word_en;
if (match_word_en != 0xf)
return true;
else
return false;
}
static bool hal_EfuseCheckIfDatafollowed(struct adapter *pAdapter, u8 word_cnts, u16 startAddr, bool bPseudoTest)
{
bool bRet = false;
u8 i, efuse_data;
for (i = 0; i < (word_cnts*2); i++) {
if (efuse_OneByteRead(pAdapter, (startAddr+i), &efuse_data, bPseudoTest) && (efuse_data != 0xFF))
bRet = true;
}
return bRet;
}
static bool hal_EfusePartialWriteCheck(struct adapter *pAdapter, u8 efuseType, u16 *pAddr, struct pgpkt *pTargetPkt, bool bPseudoTest)
{
bool bRet = false;
u8 i, efuse_data = 0, cur_header = 0;
u8 matched_wden = 0, badworden = 0;
u16 startAddr = 0, efuse_max_available_len = 0, efuse_max = 0;
struct pgpkt curPkt;
EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_AVAILABLE_EFUSE_BYTES_BANK, (void *)&efuse_max_available_len, bPseudoTest);
EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_EFUSE_REAL_CONTENT_LEN, (void *)&efuse_max, bPseudoTest);
if (efuseType == EFUSE_WIFI) {
if (bPseudoTest) {
startAddr = (u16)(fakeEfuseUsedBytes%EFUSE_REAL_CONTENT_LEN);
} else {
rtw_hal_get_hwreg(pAdapter, HW_VAR_EFUSE_BYTES, (u8 *)&startAddr);
startAddr %= EFUSE_REAL_CONTENT_LEN;
}
} else {
if (bPseudoTest)
startAddr = (u16)(fakeBTEfuseUsedBytes%EFUSE_REAL_CONTENT_LEN);
else
startAddr = (u16)(BTEfuseUsedBytes%EFUSE_REAL_CONTENT_LEN);
}
while (1) {
if (startAddr >= efuse_max_available_len) {
bRet = false;
break;
}
if (efuse_OneByteRead(pAdapter, startAddr, &efuse_data, bPseudoTest) && (efuse_data != 0xFF)) {
if (EXT_HEADER(efuse_data)) {
cur_header = efuse_data;
startAddr++;
efuse_OneByteRead(pAdapter, startAddr, &efuse_data, bPseudoTest);
if (ALL_WORDS_DISABLED(efuse_data)) {
bRet = false;
break;
} else {
curPkt.offset = ((cur_header & 0xE0) >> 5) | ((efuse_data & 0xF0) >> 1);
curPkt.word_en = efuse_data & 0x0F;
}
} else {
cur_header = efuse_data;
curPkt.offset = (cur_header>>4) & 0x0F;
curPkt.word_en = cur_header & 0x0F;
}
curPkt.word_cnts = Efuse_CalculateWordCnts(curPkt.word_en);
/* if same header is found but no data followed */
/* write some part of data followed by the header. */
if ((curPkt.offset == pTargetPkt->offset) &&
(!hal_EfuseCheckIfDatafollowed(pAdapter, curPkt.word_cnts, startAddr+1, bPseudoTest)) &&
wordEnMatched(pTargetPkt, &curPkt, &matched_wden)) {
/* Here to write partial data */
badworden = Efuse_WordEnableDataWrite(pAdapter, startAddr+1, matched_wden, pTargetPkt->data, bPseudoTest);
if (badworden != 0x0F) {
u32 PgWriteSuccess = 0;
/* if write fail on some words, write these bad words again */
PgWriteSuccess = Efuse_PgPacketWrite(pAdapter, pTargetPkt->offset, badworden, pTargetPkt->data, bPseudoTest);
if (!PgWriteSuccess) {
bRet = false; /* write fail, return */
break;
}
}
/* partial write ok, update the target packet for later use */
for (i = 0; i < 4; i++) {
if ((matched_wden & (0x1<<i)) == 0) /* this word has been written */
pTargetPkt->word_en |= (0x1<<i); /* disable the word */
}
pTargetPkt->word_cnts = Efuse_CalculateWordCnts(pTargetPkt->word_en);
}
/* read from next header */
startAddr = startAddr + (curPkt.word_cnts*2) + 1;
} else {
/* not used header, 0xff */
*pAddr = startAddr;
bRet = true;
break;
}
}
return bRet;
}
static bool
hal_EfusePgCheckAvailableAddr(
struct adapter *pAdapter,
u8 efuseType,
bool bPseudoTest
)
{
u16 efuse_max_available_len = 0;
/* Change to check TYPE_EFUSE_MAP_LEN , beacuse 8188E raw 256, logic map over 256. */
EFUSE_GetEfuseDefinition(pAdapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (void *)&efuse_max_available_len, false);
if (Efuse_GetCurrentSize(pAdapter, efuseType, bPseudoTest) >= efuse_max_available_len)
return false;
return true;
}
static void hal_EfuseConstructPGPkt(u8 offset, u8 word_en, u8 *pData, struct pgpkt *pTargetPkt)
{
_rtw_memset((void *)pTargetPkt->data, 0xFF, sizeof(u8)*8);
pTargetPkt->offset = offset;
pTargetPkt->word_en = word_en;
efuse_WordEnableDataRead(word_en, pData, pTargetPkt->data);
pTargetPkt->word_cnts = Efuse_CalculateWordCnts(pTargetPkt->word_en);
}
static bool hal_EfusePgPacketWrite_8188e(struct adapter *pAdapter, u8 offset, u8 word_en, u8 *pData, bool bPseudoTest)
{
struct pgpkt targetPkt;
u16 startAddr = 0;
u8 efuseType = EFUSE_WIFI;
if (!hal_EfusePgCheckAvailableAddr(pAdapter, efuseType, bPseudoTest))
return false;
hal_EfuseConstructPGPkt(offset, word_en, pData, &targetPkt);
if (!hal_EfusePartialWriteCheck(pAdapter, efuseType, &startAddr, &targetPkt, bPseudoTest))
return false;
if (!hal_EfusePgPacketWriteHeader(pAdapter, efuseType, &startAddr, &targetPkt, bPseudoTest))
return false;
if (!hal_EfusePgPacketWriteData(pAdapter, efuseType, &startAddr, &targetPkt, bPseudoTest))
return false;
return true;
}
static int Hal_EfusePgPacketWrite_Pseudo(struct adapter *pAdapter, u8 offset, u8 word_en, u8 *data, bool bPseudoTest)
{
int ret;
ret = hal_EfusePgPacketWrite_8188e(pAdapter, offset, word_en, data, bPseudoTest);
return ret;
}
static int Hal_EfusePgPacketWrite(struct adapter *pAdapter, u8 offset, u8 word_en, u8 *data, bool bPseudoTest)
{
int ret = 0;
ret = hal_EfusePgPacketWrite_8188e(pAdapter, offset, word_en, data, bPseudoTest);
return ret;
}
static int rtl8188e_Efuse_PgPacketWrite(struct adapter *pAdapter, u8 offset, u8 word_en, u8 *data, bool bPseudoTest)
{
int ret;
if (bPseudoTest)
ret = Hal_EfusePgPacketWrite_Pseudo (pAdapter, offset, word_en, data, bPseudoTest);
else
ret = Hal_EfusePgPacketWrite(pAdapter, offset, word_en, data, bPseudoTest);
return ret;
}
static struct HAL_VERSION ReadChipVersion8188E(struct adapter *padapter)
{
u32 value32;
struct HAL_VERSION ChipVersion;
struct hal_data_8188e *pHalData;
pHalData = GET_HAL_DATA(padapter);
value32 = rtw_read32(padapter, REG_SYS_CFG);
ChipVersion.ICType = CHIP_8188E;
ChipVersion.ChipType = ((value32 & RTL_ID) ? TEST_CHIP : NORMAL_CHIP);
ChipVersion.RFType = RF_TYPE_1T1R;
ChipVersion.VendorType = ((value32 & VENDOR_ID) ? CHIP_VENDOR_UMC : CHIP_VENDOR_TSMC);
ChipVersion.CUTVersion = (value32 & CHIP_VER_RTL_MASK)>>CHIP_VER_RTL_SHIFT; /* IC version (CUT) */
/* For regulator mode. by tynli. 2011.01.14 */
pHalData->RegulatorMode = ((value32 & TRP_BT_EN) ? RT_LDO_REGULATOR : RT_SWITCHING_REGULATOR);
ChipVersion.ROMVer = 0; /* ROM code version. */
pHalData->MultiFunc = RT_MULTI_FUNC_NONE;
dump_chip_info(ChipVersion);
pHalData->VersionID = ChipVersion;
if (IS_1T2R(ChipVersion)) {
pHalData->rf_type = RF_1T2R;
pHalData->NumTotalRFPath = 2;
} else if (IS_2T2R(ChipVersion)) {
pHalData->rf_type = RF_2T2R;
pHalData->NumTotalRFPath = 2;
} else{
pHalData->rf_type = RF_1T1R;
pHalData->NumTotalRFPath = 1;
}
MSG_88E("RF_Type is %x!!\n", pHalData->rf_type);
return ChipVersion;
}
static void rtl8188e_read_chip_version(struct adapter *padapter)
{
ReadChipVersion8188E(padapter);
}
static void rtl8188e_GetHalODMVar(struct adapter *Adapter, enum hal_odm_variable eVariable, void *pValue1, bool bSet)
{
}
static void rtl8188e_SetHalODMVar(struct adapter *Adapter, enum hal_odm_variable eVariable, void *pValue1, bool bSet)
{
struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
struct odm_dm_struct *podmpriv = &pHalData->odmpriv;
switch (eVariable) {
case HAL_ODM_STA_INFO:
{
struct sta_info *psta = (struct sta_info *)pValue1;
if (bSet) {
DBG_88E("### Set STA_(%d) info\n", psta->mac_id);
ODM_CmnInfoPtrArrayHook(podmpriv, ODM_CMNINFO_STA_STATUS, psta->mac_id, psta);
ODM_RAInfo_Init(podmpriv, psta->mac_id);
} else {
DBG_88E("### Clean STA_(%d) info\n", psta->mac_id);
ODM_CmnInfoPtrArrayHook(podmpriv, ODM_CMNINFO_STA_STATUS, psta->mac_id, NULL);
}
}
break;
case HAL_ODM_P2P_STATE:
ODM_CmnInfoUpdate(podmpriv, ODM_CMNINFO_WIFI_DIRECT, bSet);
break;
case HAL_ODM_WIFI_DISPLAY_STATE:
ODM_CmnInfoUpdate(podmpriv, ODM_CMNINFO_WIFI_DISPLAY, bSet);
break;
default:
break;
}
}
void rtl8188e_clone_haldata(struct adapter *dst_adapter, struct adapter *src_adapter)
{
memcpy(dst_adapter->HalData, src_adapter->HalData, dst_adapter->hal_data_sz);
}
void rtl8188e_start_thread(struct adapter *padapter)
{
}
void rtl8188e_stop_thread(struct adapter *padapter)
{
}
static void hal_notch_filter_8188e(struct adapter *adapter, bool enable)
{
if (enable) {
DBG_88E("Enable notch filter\n");
rtw_write8(adapter, rOFDM0_RxDSP+1, rtw_read8(adapter, rOFDM0_RxDSP+1) | BIT1);
} else {
DBG_88E("Disable notch filter\n");
rtw_write8(adapter, rOFDM0_RxDSP+1, rtw_read8(adapter, rOFDM0_RxDSP+1) & ~BIT1);
}
}
void rtl8188e_set_hal_ops(struct hal_ops *pHalFunc)
{
pHalFunc->free_hal_data = &rtl8188e_free_hal_data;
pHalFunc->dm_init = &rtl8188e_init_dm_priv;
pHalFunc->dm_deinit = &rtl8188e_deinit_dm_priv;
pHalFunc->read_chip_version = &rtl8188e_read_chip_version;
pHalFunc->set_bwmode_handler = &PHY_SetBWMode8188E;
pHalFunc->set_channel_handler = &PHY_SwChnl8188E;
pHalFunc->hal_dm_watchdog = &rtl8188e_HalDmWatchDog;
pHalFunc->Add_RateATid = &rtl8188e_Add_RateATid;
pHalFunc->run_thread = &rtl8188e_start_thread;
pHalFunc->cancel_thread = &rtl8188e_stop_thread;
pHalFunc->AntDivBeforeLinkHandler = &AntDivBeforeLink8188E;
pHalFunc->AntDivCompareHandler = &AntDivCompare8188E;
pHalFunc->read_bbreg = &rtl8188e_PHY_QueryBBReg;
pHalFunc->write_bbreg = &rtl8188e_PHY_SetBBReg;
pHalFunc->read_rfreg = &rtl8188e_PHY_QueryRFReg;
pHalFunc->write_rfreg = &rtl8188e_PHY_SetRFReg;
/* Efuse related function */
pHalFunc->EfusePowerSwitch = &rtl8188e_EfusePowerSwitch;
pHalFunc->ReadEFuse = &rtl8188e_ReadEFuse;
pHalFunc->EFUSEGetEfuseDefinition = &rtl8188e_EFUSE_GetEfuseDefinition;
pHalFunc->EfuseGetCurrentSize = &rtl8188e_EfuseGetCurrentSize;
pHalFunc->Efuse_PgPacketRead = &rtl8188e_Efuse_PgPacketRead;
pHalFunc->Efuse_PgPacketWrite = &rtl8188e_Efuse_PgPacketWrite;
pHalFunc->Efuse_WordEnableDataWrite = &rtl8188e_Efuse_WordEnableDataWrite;
pHalFunc->sreset_init_value = &sreset_init_value;
pHalFunc->sreset_reset_value = &sreset_reset_value;
pHalFunc->silentreset = &rtl8188e_silentreset_for_specific_platform;
pHalFunc->sreset_xmit_status_check = &rtl8188e_sreset_xmit_status_check;
pHalFunc->sreset_linked_status_check = &rtl8188e_sreset_linked_status_check;
pHalFunc->sreset_get_wifi_status = &sreset_get_wifi_status;
pHalFunc->GetHalODMVarHandler = &rtl8188e_GetHalODMVar;
pHalFunc->SetHalODMVarHandler = &rtl8188e_SetHalODMVar;
pHalFunc->IOL_exec_cmds_sync = &rtl8188e_IOL_exec_cmds_sync;
pHalFunc->hal_notch_filter = &hal_notch_filter_8188e;
}
u8 GetEEPROMSize8188E(struct adapter *padapter)
{
u8 size = 0;
u32 cr;
cr = rtw_read16(padapter, REG_9346CR);
/* 6: EEPROM used is 93C46, 4: boot from E-Fuse. */
size = (cr & BOOT_FROM_EEPROM) ? 6 : 4;
MSG_88E("EEPROM type is %s\n", size == 4 ? "E-FUSE" : "93C46");
return size;
}
/* */
/* */
/* LLT R/W/Init function */
/* */
/* */
static s32 _LLTWrite(struct adapter *padapter, u32 address, u32 data)
{
s32 status = _SUCCESS;
s32 count = 0;
u32 value = _LLT_INIT_ADDR(address) | _LLT_INIT_DATA(data) | _LLT_OP(_LLT_WRITE_ACCESS);
u16 LLTReg = REG_LLT_INIT;
rtw_write32(padapter, LLTReg, value);
/* polling */
do {
value = rtw_read32(padapter, LLTReg);
if (_LLT_NO_ACTIVE == _LLT_OP_VALUE(value))
break;
if (count > POLLING_LLT_THRESHOLD) {
RT_TRACE(_module_hal_init_c_, _drv_err_, ("Failed to polling write LLT done at address %d!\n", address));
status = _FAIL;
break;
}
} while (count++);
return status;
}
s32 InitLLTTable(struct adapter *padapter, u8 txpktbuf_bndy)
{
s32 status = _FAIL;
u32 i;
u32 Last_Entry_Of_TxPktBuf = LAST_ENTRY_OF_TX_PKT_BUFFER;/* 176, 22k */
if (rtw_IOL_applied(padapter)) {
status = iol_InitLLTTable(padapter, txpktbuf_bndy);
} else {
for (i = 0; i < (txpktbuf_bndy - 1); i++) {
status = _LLTWrite(padapter, i, i + 1);
if (_SUCCESS != status)
return status;
}
/* end of list */
status = _LLTWrite(padapter, (txpktbuf_bndy - 1), 0xFF);
if (_SUCCESS != status)
return status;
/* Make the other pages as ring buffer */
/* This ring buffer is used as beacon buffer if we config this MAC as two MAC transfer. */
/* Otherwise used as local loopback buffer. */
for (i = txpktbuf_bndy; i < Last_Entry_Of_TxPktBuf; i++) {
status = _LLTWrite(padapter, i, (i + 1));
if (_SUCCESS != status)
return status;
}
/* Let last entry point to the start entry of ring buffer */
status = _LLTWrite(padapter, Last_Entry_Of_TxPktBuf, txpktbuf_bndy);
if (_SUCCESS != status) {
return status;
}
}
return status;
}
void
Hal_InitPGData88E(struct adapter *padapter)
{
struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter);
if (!pEEPROM->bautoload_fail_flag) { /* autoload OK. */
if (!is_boot_from_eeprom(padapter)) {
/* Read EFUSE real map to shadow. */
EFUSE_ShadowMapUpdate(padapter, EFUSE_WIFI, false);
}
} else {/* autoload fail */
RT_TRACE(_module_hci_hal_init_c_, _drv_notice_, ("AutoLoad Fail reported from CR9346!!\n"));
/* update to default value 0xFF */
if (!is_boot_from_eeprom(padapter))
EFUSE_ShadowMapUpdate(padapter, EFUSE_WIFI, false);
}
}
void
Hal_EfuseParseIDCode88E(
struct adapter *padapter,
u8 *hwinfo
)
{
struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter);
u16 EEPROMId;
/* Checl 0x8129 again for making sure autoload status!! */
EEPROMId = le16_to_cpu(*((__le16 *)hwinfo));
if (EEPROMId != RTL_EEPROM_ID) {
DBG_88E("EEPROM ID(%#x) is invalid!!\n", EEPROMId);
pEEPROM->bautoload_fail_flag = true;
} else {
pEEPROM->bautoload_fail_flag = false;
}
DBG_88E("EEPROM ID = 0x%04x\n", EEPROMId);
}
static void Hal_ReadPowerValueFromPROM_8188E(struct txpowerinfo24g *pwrInfo24G, u8 *PROMContent, bool AutoLoadFail)
{
u32 rfPath, eeAddr = EEPROM_TX_PWR_INX_88E, group, TxCount = 0;
_rtw_memset(pwrInfo24G, 0, sizeof(struct txpowerinfo24g));
if (AutoLoadFail) {
for (rfPath = 0; rfPath < MAX_RF_PATH; rfPath++) {
/* 2.4G default value */
for (group = 0; group < MAX_CHNL_GROUP_24G; group++) {
pwrInfo24G->IndexCCK_Base[rfPath][group] = EEPROM_DEFAULT_24G_INDEX;
pwrInfo24G->IndexBW40_Base[rfPath][group] = EEPROM_DEFAULT_24G_INDEX;
}
for (TxCount = 0; TxCount < MAX_TX_COUNT; TxCount++) {
if (TxCount == 0) {
pwrInfo24G->BW20_Diff[rfPath][0] = EEPROM_DEFAULT_24G_HT20_DIFF;
pwrInfo24G->OFDM_Diff[rfPath][0] = EEPROM_DEFAULT_24G_OFDM_DIFF;
} else {
pwrInfo24G->BW20_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF;
pwrInfo24G->BW40_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF;
pwrInfo24G->CCK_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF;
pwrInfo24G->OFDM_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF;
}
}
}
return;
}
for (rfPath = 0; rfPath < MAX_RF_PATH; rfPath++) {
/* 2.4G default value */
for (group = 0; group < MAX_CHNL_GROUP_24G; group++) {
pwrInfo24G->IndexCCK_Base[rfPath][group] = PROMContent[eeAddr++];
if (pwrInfo24G->IndexCCK_Base[rfPath][group] == 0xFF)
pwrInfo24G->IndexCCK_Base[rfPath][group] = EEPROM_DEFAULT_24G_INDEX;
}
for (group = 0; group < MAX_CHNL_GROUP_24G-1; group++) {
pwrInfo24G->IndexBW40_Base[rfPath][group] = PROMContent[eeAddr++];
if (pwrInfo24G->IndexBW40_Base[rfPath][group] == 0xFF)
pwrInfo24G->IndexBW40_Base[rfPath][group] = EEPROM_DEFAULT_24G_INDEX;
}
for (TxCount = 0; TxCount < MAX_TX_COUNT; TxCount++) {
if (TxCount == 0) {
pwrInfo24G->BW40_Diff[rfPath][TxCount] = 0;
if (PROMContent[eeAddr] == 0xFF) {
pwrInfo24G->BW20_Diff[rfPath][TxCount] = EEPROM_DEFAULT_24G_HT20_DIFF;
} else {
pwrInfo24G->BW20_Diff[rfPath][TxCount] = (PROMContent[eeAddr]&0xf0)>>4;
if (pwrInfo24G->BW20_Diff[rfPath][TxCount] & BIT3) /* 4bit sign number to 8 bit sign number */
pwrInfo24G->BW20_Diff[rfPath][TxCount] |= 0xF0;
}
if (PROMContent[eeAddr] == 0xFF) {
pwrInfo24G->OFDM_Diff[rfPath][TxCount] = EEPROM_DEFAULT_24G_OFDM_DIFF;
} else {
pwrInfo24G->OFDM_Diff[rfPath][TxCount] = (PROMContent[eeAddr]&0x0f);
if (pwrInfo24G->OFDM_Diff[rfPath][TxCount] & BIT3) /* 4bit sign number to 8 bit sign number */
pwrInfo24G->OFDM_Diff[rfPath][TxCount] |= 0xF0;
}
pwrInfo24G->CCK_Diff[rfPath][TxCount] = 0;
eeAddr++;
} else {
if (PROMContent[eeAddr] == 0xFF) {
pwrInfo24G->BW40_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF;
} else {
pwrInfo24G->BW40_Diff[rfPath][TxCount] = (PROMContent[eeAddr]&0xf0)>>4;
if (pwrInfo24G->BW40_Diff[rfPath][TxCount] & BIT3) /* 4bit sign number to 8 bit sign number */
pwrInfo24G->BW40_Diff[rfPath][TxCount] |= 0xF0;
}
if (PROMContent[eeAddr] == 0xFF) {
pwrInfo24G->BW20_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF;
} else {
pwrInfo24G->BW20_Diff[rfPath][TxCount] = (PROMContent[eeAddr]&0x0f);
if (pwrInfo24G->BW20_Diff[rfPath][TxCount] & BIT3) /* 4bit sign number to 8 bit sign number */
pwrInfo24G->BW20_Diff[rfPath][TxCount] |= 0xF0;
}
eeAddr++;
if (PROMContent[eeAddr] == 0xFF) {
pwrInfo24G->OFDM_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF;
} else {
pwrInfo24G->OFDM_Diff[rfPath][TxCount] = (PROMContent[eeAddr]&0xf0)>>4;
if (pwrInfo24G->OFDM_Diff[rfPath][TxCount] & BIT3) /* 4bit sign number to 8 bit sign number */
pwrInfo24G->OFDM_Diff[rfPath][TxCount] |= 0xF0;
}
if (PROMContent[eeAddr] == 0xFF) {
pwrInfo24G->CCK_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF;
} else {
pwrInfo24G->CCK_Diff[rfPath][TxCount] = (PROMContent[eeAddr]&0x0f);
if (pwrInfo24G->CCK_Diff[rfPath][TxCount] & BIT3) /* 4bit sign number to 8 bit sign number */
pwrInfo24G->CCK_Diff[rfPath][TxCount] |= 0xF0;
}
eeAddr++;
}
}
}
}
static u8 Hal_GetChnlGroup88E(u8 chnl, u8 *pGroup)
{
u8 bIn24G = true;
if (chnl <= 14) {
bIn24G = true;
if (chnl < 3) /* Chanel 1-2 */
*pGroup = 0;
else if (chnl < 6) /* Channel 3-5 */
*pGroup = 1;
else if (chnl < 9) /* Channel 6-8 */
*pGroup = 2;
else if (chnl < 12) /* Channel 9-11 */
*pGroup = 3;
else if (chnl < 14) /* Channel 12-13 */
*pGroup = 4;
else if (chnl == 14) /* Channel 14 */
*pGroup = 5;
} else {
bIn24G = false;
if (chnl <= 40)
*pGroup = 0;
else if (chnl <= 48)
*pGroup = 1;
else if (chnl <= 56)
*pGroup = 2;
else if (chnl <= 64)
*pGroup = 3;
else if (chnl <= 104)
*pGroup = 4;
else if (chnl <= 112)
*pGroup = 5;
else if (chnl <= 120)
*pGroup = 5;
else if (chnl <= 128)
*pGroup = 6;
else if (chnl <= 136)
*pGroup = 7;
else if (chnl <= 144)
*pGroup = 8;
else if (chnl <= 153)
*pGroup = 9;
else if (chnl <= 161)
*pGroup = 10;
else if (chnl <= 177)
*pGroup = 11;
}
return bIn24G;
}
void Hal_ReadPowerSavingMode88E(struct adapter *padapter, u8 *hwinfo, bool AutoLoadFail)
{
if (AutoLoadFail) {
padapter->pwrctrlpriv.bHWPowerdown = false;
padapter->pwrctrlpriv.bSupportRemoteWakeup = false;
} else {
/* hw power down mode selection , 0:rf-off / 1:power down */
if (padapter->registrypriv.hwpdn_mode == 2)
padapter->pwrctrlpriv.bHWPowerdown = (hwinfo[EEPROM_RF_FEATURE_OPTION_88E] & BIT4);
else
padapter->pwrctrlpriv.bHWPowerdown = padapter->registrypriv.hwpdn_mode;
/* decide hw if support remote wakeup function */
/* if hw supported, 8051 (SIE) will generate WeakUP signal(D+/D- toggle) when autoresume */
padapter->pwrctrlpriv.bSupportRemoteWakeup = (hwinfo[EEPROM_USB_OPTIONAL_FUNCTION0] & BIT1) ? true : false;
DBG_88E("%s...bHWPwrPindetect(%x)-bHWPowerdown(%x) , bSupportRemoteWakeup(%x)\n", __func__,
padapter->pwrctrlpriv.bHWPwrPindetect, padapter->pwrctrlpriv.bHWPowerdown , padapter->pwrctrlpriv.bSupportRemoteWakeup);
DBG_88E("### PS params => power_mgnt(%x), usbss_enable(%x) ###\n", padapter->registrypriv.power_mgnt, padapter->registrypriv.usbss_enable);
}
}
void Hal_ReadTxPowerInfo88E(struct adapter *padapter, u8 *PROMContent, bool AutoLoadFail)
{
struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter);
struct txpowerinfo24g pwrInfo24G;
u8 rfPath, ch, group;
u8 bIn24G, TxCount;
Hal_ReadPowerValueFromPROM_8188E(&pwrInfo24G, PROMContent, AutoLoadFail);
if (!AutoLoadFail)
pHalData->bTXPowerDataReadFromEEPORM = true;
for (rfPath = 0; rfPath < pHalData->NumTotalRFPath; rfPath++) {
for (ch = 0; ch <= CHANNEL_MAX_NUMBER; ch++) {
bIn24G = Hal_GetChnlGroup88E(ch, &group);
if (bIn24G) {
pHalData->Index24G_CCK_Base[rfPath][ch] = pwrInfo24G.IndexCCK_Base[rfPath][group];
if (ch == 14)
pHalData->Index24G_BW40_Base[rfPath][ch] = pwrInfo24G.IndexBW40_Base[rfPath][4];
else
pHalData->Index24G_BW40_Base[rfPath][ch] = pwrInfo24G.IndexBW40_Base[rfPath][group];
}
if (bIn24G) {
DBG_88E("======= Path %d, Channel %d =======\n", rfPath, ch);
DBG_88E("Index24G_CCK_Base[%d][%d] = 0x%x\n", rfPath, ch , pHalData->Index24G_CCK_Base[rfPath][ch]);
DBG_88E("Index24G_BW40_Base[%d][%d] = 0x%x\n", rfPath, ch , pHalData->Index24G_BW40_Base[rfPath][ch]);
}
}
for (TxCount = 0; TxCount < MAX_TX_COUNT; TxCount++) {
pHalData->CCK_24G_Diff[rfPath][TxCount] = pwrInfo24G.CCK_Diff[rfPath][TxCount];
pHalData->OFDM_24G_Diff[rfPath][TxCount] = pwrInfo24G.OFDM_Diff[rfPath][TxCount];
pHalData->BW20_24G_Diff[rfPath][TxCount] = pwrInfo24G.BW20_Diff[rfPath][TxCount];
pHalData->BW40_24G_Diff[rfPath][TxCount] = pwrInfo24G.BW40_Diff[rfPath][TxCount];
DBG_88E("======= TxCount %d =======\n", TxCount);
DBG_88E("CCK_24G_Diff[%d][%d] = %d\n", rfPath, TxCount, pHalData->CCK_24G_Diff[rfPath][TxCount]);
DBG_88E("OFDM_24G_Diff[%d][%d] = %d\n", rfPath, TxCount, pHalData->OFDM_24G_Diff[rfPath][TxCount]);
DBG_88E("BW20_24G_Diff[%d][%d] = %d\n", rfPath, TxCount, pHalData->BW20_24G_Diff[rfPath][TxCount]);
DBG_88E("BW40_24G_Diff[%d][%d] = %d\n", rfPath, TxCount, pHalData->BW40_24G_Diff[rfPath][TxCount]);
}
}
/* 2010/10/19 MH Add Regulator recognize for CU. */
if (!AutoLoadFail) {
pHalData->EEPROMRegulatory = (PROMContent[EEPROM_RF_BOARD_OPTION_88E]&0x7); /* bit0~2 */
if (PROMContent[EEPROM_RF_BOARD_OPTION_88E] == 0xFF)
pHalData->EEPROMRegulatory = (EEPROM_DEFAULT_BOARD_OPTION&0x7); /* bit0~2 */
} else {
pHalData->EEPROMRegulatory = 0;
}
DBG_88E("EEPROMRegulatory = 0x%x\n", pHalData->EEPROMRegulatory);
}
void Hal_EfuseParseXtal_8188E(struct adapter *pAdapter, u8 *hwinfo, bool AutoLoadFail)
{
struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter);
if (!AutoLoadFail) {
pHalData->CrystalCap = hwinfo[EEPROM_XTAL_88E];
if (pHalData->CrystalCap == 0xFF)
pHalData->CrystalCap = EEPROM_Default_CrystalCap_88E;
} else {
pHalData->CrystalCap = EEPROM_Default_CrystalCap_88E;
}
DBG_88E("CrystalCap: 0x%2x\n", pHalData->CrystalCap);
}
void Hal_EfuseParseBoardType88E(struct adapter *pAdapter, u8 *hwinfo, bool AutoLoadFail)
{
struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter);
if (!AutoLoadFail)
pHalData->BoardType = ((hwinfo[EEPROM_RF_BOARD_OPTION_88E]&0xE0)>>5);
else
pHalData->BoardType = 0;
DBG_88E("Board Type: 0x%2x\n", pHalData->BoardType);
}
void Hal_EfuseParseEEPROMVer88E(struct adapter *padapter, u8 *hwinfo, bool AutoLoadFail)
{
struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter);
if (!AutoLoadFail) {
pHalData->EEPROMVersion = hwinfo[EEPROM_VERSION_88E];
if (pHalData->EEPROMVersion == 0xFF)
pHalData->EEPROMVersion = EEPROM_Default_Version;
} else {
pHalData->EEPROMVersion = 1;
}
RT_TRACE(_module_hci_hal_init_c_, _drv_info_,
("Hal_EfuseParseEEPROMVer(), EEVer = %d\n",
pHalData->EEPROMVersion));
}
void rtl8188e_EfuseParseChnlPlan(struct adapter *padapter, u8 *hwinfo, bool AutoLoadFail)
{
padapter->mlmepriv.ChannelPlan =
hal_com_get_channel_plan(padapter,
hwinfo ? hwinfo[EEPROM_ChannelPlan_88E] : 0xFF,
padapter->registrypriv.channel_plan,
RT_CHANNEL_DOMAIN_WORLD_WIDE_13, AutoLoadFail);
DBG_88E("mlmepriv.ChannelPlan = 0x%02x\n", padapter->mlmepriv.ChannelPlan);
}
void Hal_EfuseParseCustomerID88E(struct adapter *padapter, u8 *hwinfo, bool AutoLoadFail)
{
struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter);
if (!AutoLoadFail) {
pHalData->EEPROMCustomerID = hwinfo[EEPROM_CUSTOMERID_88E];
} else {
pHalData->EEPROMCustomerID = 0;
pHalData->EEPROMSubCustomerID = 0;
}
DBG_88E("EEPROM Customer ID: 0x%2x\n", pHalData->EEPROMCustomerID);
}
void Hal_ReadAntennaDiversity88E(struct adapter *pAdapter, u8 *PROMContent, bool AutoLoadFail)
{
struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter);
struct registry_priv *registry_par = &pAdapter->registrypriv;
if (!AutoLoadFail) {
/* Antenna Diversity setting. */
if (registry_par->antdiv_cfg == 2) { /* 2:By EFUSE */
pHalData->AntDivCfg = (PROMContent[EEPROM_RF_BOARD_OPTION_88E]&0x18)>>3;
if (PROMContent[EEPROM_RF_BOARD_OPTION_88E] == 0xFF)
pHalData->AntDivCfg = (EEPROM_DEFAULT_BOARD_OPTION&0x18)>>3;;
} else {
pHalData->AntDivCfg = registry_par->antdiv_cfg; /* 0:OFF , 1:ON, 2:By EFUSE */
}
if (registry_par->antdiv_type == 0) {
/* If TRxAntDivType is AUTO in advanced setting, use EFUSE value instead. */
pHalData->TRxAntDivType = PROMContent[EEPROM_RF_ANTENNA_OPT_88E];
if (pHalData->TRxAntDivType == 0xFF)
pHalData->TRxAntDivType = CG_TRX_HW_ANTDIV; /* For 88EE, 1Tx and 1RxCG are fixed.(1Ant, Tx and RxCG are both on aux port) */
} else {
pHalData->TRxAntDivType = registry_par->antdiv_type;
}
if (pHalData->TRxAntDivType == CG_TRX_HW_ANTDIV || pHalData->TRxAntDivType == CGCS_RX_HW_ANTDIV)
pHalData->AntDivCfg = 1; /* 0xC1[3] is ignored. */
} else {
pHalData->AntDivCfg = 0;
pHalData->TRxAntDivType = pHalData->TRxAntDivType; /* The value in the driver setting of device manager. */
}
DBG_88E("EEPROM : AntDivCfg = %x, TRxAntDivType = %x\n", pHalData->AntDivCfg, pHalData->TRxAntDivType);
}
void Hal_ReadThermalMeter_88E(struct adapter *Adapter, u8 *PROMContent, bool AutoloadFail)
{
struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
/* ThermalMeter from EEPROM */
if (!AutoloadFail)
pHalData->EEPROMThermalMeter = PROMContent[EEPROM_THERMAL_METER_88E];
else
pHalData->EEPROMThermalMeter = EEPROM_Default_ThermalMeter_88E;
if (pHalData->EEPROMThermalMeter == 0xff || AutoloadFail) {
pHalData->bAPKThermalMeterIgnore = true;
pHalData->EEPROMThermalMeter = EEPROM_Default_ThermalMeter_88E;
}
DBG_88E("ThermalMeter = 0x%x\n", pHalData->EEPROMThermalMeter);
}
void Hal_InitChannelPlan(struct adapter *padapter)
{
}
bool HalDetectPwrDownMode88E(struct adapter *Adapter)
{
u8 tmpvalue = 0;
struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
struct pwrctrl_priv *pwrctrlpriv = &Adapter->pwrctrlpriv;
EFUSE_ShadowRead(Adapter, 1, EEPROM_RF_FEATURE_OPTION_88E, (u32 *)&tmpvalue);
/* 2010/08/25 MH INF priority > PDN Efuse value. */
if (tmpvalue & BIT(4) && pwrctrlpriv->reg_pdnmode)
pHalData->pwrdown = true;
else
pHalData->pwrdown = false;
DBG_88E("HalDetectPwrDownMode(): PDN =%d\n", pHalData->pwrdown);
return pHalData->pwrdown;
} /* HalDetectPwrDownMode */
/* This function is used only for 92C to set REG_BCN_CTRL(0x550) register. */
/* We just reserve the value of the register in variable pHalData->RegBcnCtrlVal and then operate */
/* the value of the register via atomic operation. */
/* This prevents from race condition when setting this register. */
/* The value of pHalData->RegBcnCtrlVal is initialized in HwConfigureRTL8192CE() function. */
void SetBcnCtrlReg(struct adapter *padapter, u8 SetBits, u8 ClearBits)
{
struct hal_data_8188e *pHalData;
pHalData = GET_HAL_DATA(padapter);
pHalData->RegBcnCtrlVal |= SetBits;
pHalData->RegBcnCtrlVal &= ~ClearBits;
rtw_write8(padapter, REG_BCN_CTRL, (u8)pHalData->RegBcnCtrlVal);
}
/******************************************************************************
*
* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
*
* 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.
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*
*
******************************************************************************/
#define _RTL8188E_MP_C_
#include <drv_types.h>
#include <rtw_mp.h>
#include <rtl8188e_hal.h>
#include <rtl8188e_dm.h>
s32 Hal_SetPowerTracking(struct adapter *padapter, u8 enable)
{
struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter);
struct odm_dm_struct *pDM_Odm = &(pHalData->odmpriv);
if (!netif_running(padapter->pnetdev)) {
RT_TRACE(_module_mp_, _drv_warning_,
("SetPowerTracking! Fail: interface not opened!\n"));
return _FAIL;
}
if (!check_fwstate(&padapter->mlmepriv, WIFI_MP_STATE)) {
RT_TRACE(_module_mp_, _drv_warning_,
("SetPowerTracking! Fail: not in MP mode!\n"));
return _FAIL;
}
if (enable)
pDM_Odm->RFCalibrateInfo.bTXPowerTracking = true;
else
pDM_Odm->RFCalibrateInfo.bTXPowerTrackingInit = false;
return _SUCCESS;
}
void Hal_GetPowerTracking(struct adapter *padapter, u8 *enable)
{
struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter);
struct odm_dm_struct *pDM_Odm = &(pHalData->odmpriv);
*enable = pDM_Odm->RFCalibrateInfo.TxPowerTrackControl;
}
/*-----------------------------------------------------------------------------
* Function: mpt_SwitchRfSetting
*
* Overview: Change RF Setting when we siwthc channel/rate/BW for MP.
*
* Input: struct adapter * pAdapter
*
* Output: NONE
*
* Return: NONE
*
* Revised History:
* When Who Remark
* 01/08/2009 MHC Suggestion from SD3 Willis for 92S series.
* 01/09/2009 MHC Add CCK modification for 40MHZ. Suggestion from SD3.
*
*---------------------------------------------------------------------------*/
void Hal_mpt_SwitchRfSetting(struct adapter *pAdapter)
{
struct mp_priv *pmp = &pAdapter->mppriv;
/* <20120525, Kordan> Dynamic mechanism for APK, asked by Dennis. */
pmp->MptCtx.backup0x52_RF_A = (u8)PHY_QueryRFReg(pAdapter, RF_PATH_A, RF_0x52, 0x000F0);
pmp->MptCtx.backup0x52_RF_B = (u8)PHY_QueryRFReg(pAdapter, RF_PATH_B, RF_0x52, 0x000F0);
PHY_SetRFReg(pAdapter, RF_PATH_A, RF_0x52, 0x000F0, 0xD);
PHY_SetRFReg(pAdapter, RF_PATH_B, RF_0x52, 0x000F0, 0xD);
return;
}
/*---------------------------hal\rtl8192c\MPT_Phy.c---------------------------*/
/*---------------------------hal\rtl8192c\MPT_HelperFunc.c---------------------------*/
void Hal_MPT_CCKTxPowerAdjust(struct adapter *Adapter, bool bInCH14)
{
u32 TempVal = 0, TempVal2 = 0, TempVal3 = 0;
u32 CurrCCKSwingVal = 0, CCKSwingIndex = 12;
u8 i;
/* get current cck swing value and check 0xa22 & 0xa23 later to match the table. */
CurrCCKSwingVal = read_bbreg(Adapter, rCCK0_TxFilter1, bMaskHWord);
if (!bInCH14) {
/* Readback the current bb cck swing value and compare with the table to */
/* get the current swing index */
for (i = 0; i < CCK_TABLE_SIZE; i++) {
if (((CurrCCKSwingVal&0xff) == (u32)CCKSwingTable_Ch1_Ch13[i][0]) &&
(((CurrCCKSwingVal&0xff00)>>8) == (u32)CCKSwingTable_Ch1_Ch13[i][1])) {
CCKSwingIndex = i;
break;
}
}
/* Write 0xa22 0xa23 */
TempVal = CCKSwingTable_Ch1_Ch13[CCKSwingIndex][0] +
(CCKSwingTable_Ch1_Ch13[CCKSwingIndex][1]<<8);
/* Write 0xa24 ~ 0xa27 */
TempVal2 = 0;
TempVal2 = CCKSwingTable_Ch1_Ch13[CCKSwingIndex][2] +
(CCKSwingTable_Ch1_Ch13[CCKSwingIndex][3]<<8) +
(CCKSwingTable_Ch1_Ch13[CCKSwingIndex][4]<<16)+
(CCKSwingTable_Ch1_Ch13[CCKSwingIndex][5]<<24);
/* Write 0xa28 0xa29 */
TempVal3 = 0;
TempVal3 = CCKSwingTable_Ch1_Ch13[CCKSwingIndex][6] +
(CCKSwingTable_Ch1_Ch13[CCKSwingIndex][7]<<8);
} else {
for (i = 0; i < CCK_TABLE_SIZE; i++) {
if (((CurrCCKSwingVal&0xff) == (u32)CCKSwingTable_Ch14[i][0]) &&
(((CurrCCKSwingVal&0xff00)>>8) == (u32)CCKSwingTable_Ch14[i][1])) {
CCKSwingIndex = i;
break;
}
}
/* Write 0xa22 0xa23 */
TempVal = CCKSwingTable_Ch14[CCKSwingIndex][0] +
(CCKSwingTable_Ch14[CCKSwingIndex][1]<<8);
/* Write 0xa24 ~ 0xa27 */
TempVal2 = 0;
TempVal2 = CCKSwingTable_Ch14[CCKSwingIndex][2] +
(CCKSwingTable_Ch14[CCKSwingIndex][3]<<8) +
(CCKSwingTable_Ch14[CCKSwingIndex][4]<<16)+
(CCKSwingTable_Ch14[CCKSwingIndex][5]<<24);
/* Write 0xa28 0xa29 */
TempVal3 = 0;
TempVal3 = CCKSwingTable_Ch14[CCKSwingIndex][6] +
(CCKSwingTable_Ch14[CCKSwingIndex][7]<<8);
}
write_bbreg(Adapter, rCCK0_TxFilter1, bMaskHWord, TempVal);
write_bbreg(Adapter, rCCK0_TxFilter2, bMaskDWord, TempVal2);
write_bbreg(Adapter, rCCK0_DebugPort, bMaskLWord, TempVal3);
}
void Hal_MPT_CCKTxPowerAdjustbyIndex(struct adapter *pAdapter, bool beven)
{
struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter);
struct mpt_context *pMptCtx = &pAdapter->mppriv.MptCtx;
struct odm_dm_struct *pDM_Odm = &(pHalData->odmpriv);
s32 TempCCk;
u8 CCK_index, CCK_index_old = 0;
u8 Action = 0; /* 0: no action, 1: even->odd, 2:odd->even */
s32 i = 0;
if (!IS_92C_SERIAL(pHalData->VersionID))
return;
if (beven && !pMptCtx->bMptIndexEven) {
/* odd->even */
Action = 2;
pMptCtx->bMptIndexEven = true;
} else if (!beven && pMptCtx->bMptIndexEven) {
/* even->odd */
Action = 1;
pMptCtx->bMptIndexEven = false;
}
if (Action != 0) {
/* Query CCK default setting From 0xa24 */
TempCCk = read_bbreg(pAdapter, rCCK0_TxFilter2, bMaskDWord) & bMaskCCK;
for (i = 0; i < CCK_TABLE_SIZE; i++) {
if (pDM_Odm->RFCalibrateInfo.bCCKinCH14) {
if (_rtw_memcmp((void *)&TempCCk, (void *)&CCKSwingTable_Ch14[i][2], 4)) {
CCK_index_old = (u8)i;
break;
}
} else {
if (_rtw_memcmp((void *)&TempCCk, (void *)&CCKSwingTable_Ch1_Ch13[i][2], 4)) {
CCK_index_old = (u8)i;
break;
}
}
}
if (Action == 1)
CCK_index = CCK_index_old - 1;
else
CCK_index = CCK_index_old + 1;
/* Adjust CCK according to gain index */
if (!pDM_Odm->RFCalibrateInfo.bCCKinCH14) {
rtw_write8(pAdapter, 0xa22, CCKSwingTable_Ch1_Ch13[CCK_index][0]);
rtw_write8(pAdapter, 0xa23, CCKSwingTable_Ch1_Ch13[CCK_index][1]);
rtw_write8(pAdapter, 0xa24, CCKSwingTable_Ch1_Ch13[CCK_index][2]);
rtw_write8(pAdapter, 0xa25, CCKSwingTable_Ch1_Ch13[CCK_index][3]);
rtw_write8(pAdapter, 0xa26, CCKSwingTable_Ch1_Ch13[CCK_index][4]);
rtw_write8(pAdapter, 0xa27, CCKSwingTable_Ch1_Ch13[CCK_index][5]);
rtw_write8(pAdapter, 0xa28, CCKSwingTable_Ch1_Ch13[CCK_index][6]);
rtw_write8(pAdapter, 0xa29, CCKSwingTable_Ch1_Ch13[CCK_index][7]);
} else {
rtw_write8(pAdapter, 0xa22, CCKSwingTable_Ch14[CCK_index][0]);
rtw_write8(pAdapter, 0xa23, CCKSwingTable_Ch14[CCK_index][1]);
rtw_write8(pAdapter, 0xa24, CCKSwingTable_Ch14[CCK_index][2]);
rtw_write8(pAdapter, 0xa25, CCKSwingTable_Ch14[CCK_index][3]);
rtw_write8(pAdapter, 0xa26, CCKSwingTable_Ch14[CCK_index][4]);
rtw_write8(pAdapter, 0xa27, CCKSwingTable_Ch14[CCK_index][5]);
rtw_write8(pAdapter, 0xa28, CCKSwingTable_Ch14[CCK_index][6]);
rtw_write8(pAdapter, 0xa29, CCKSwingTable_Ch14[CCK_index][7]);
}
}
}
/*---------------------------hal\rtl8192c\MPT_HelperFunc.c---------------------------*/
/*
* SetChannel
* Description
* Use H2C command to change channel,
* not only modify rf register, but also other setting need to be done.
*/
void Hal_SetChannel(struct adapter *pAdapter)
{
struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter);
struct mp_priv *pmp = &pAdapter->mppriv;
struct odm_dm_struct *pDM_Odm = &(pHalData->odmpriv);
u8 eRFPath;
u8 channel = pmp->channel;
/* set RF channel register */
for (eRFPath = 0; eRFPath < pHalData->NumTotalRFPath; eRFPath++)
_write_rfreg(pAdapter, eRFPath, ODM_CHANNEL, 0x3FF, channel);
Hal_mpt_SwitchRfSetting(pAdapter);
SelectChannel(pAdapter, channel);
if (pHalData->CurrentChannel == 14 && !pDM_Odm->RFCalibrateInfo.bCCKinCH14) {
pDM_Odm->RFCalibrateInfo.bCCKinCH14 = true;
Hal_MPT_CCKTxPowerAdjust(pAdapter, pDM_Odm->RFCalibrateInfo.bCCKinCH14);
} else if (pHalData->CurrentChannel != 14 && pDM_Odm->RFCalibrateInfo.bCCKinCH14) {
pDM_Odm->RFCalibrateInfo.bCCKinCH14 = false;
Hal_MPT_CCKTxPowerAdjust(pAdapter, pDM_Odm->RFCalibrateInfo.bCCKinCH14);
}
}
/*
* Notice
* Switch bandwitdth may change center frequency(channel)
*/
void Hal_SetBandwidth(struct adapter *pAdapter)
{
struct mp_priv *pmp = &pAdapter->mppriv;
SetBWMode(pAdapter, pmp->bandwidth, pmp->prime_channel_offset);
Hal_mpt_SwitchRfSetting(pAdapter);
}
void Hal_SetCCKTxPower(struct adapter *pAdapter, u8 *TxPower)
{
u32 tmpval = 0;
/* rf-A cck tx power */
write_bbreg(pAdapter, rTxAGC_A_CCK1_Mcs32, bMaskByte1, TxPower[RF_PATH_A]);
tmpval = (TxPower[RF_PATH_A]<<16) | (TxPower[RF_PATH_A]<<8) | TxPower[RF_PATH_A];
write_bbreg(pAdapter, rTxAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval);
/* rf-B cck tx power */
write_bbreg(pAdapter, rTxAGC_B_CCK11_A_CCK2_11, bMaskByte0, TxPower[RF_PATH_B]);
tmpval = (TxPower[RF_PATH_B]<<16) | (TxPower[RF_PATH_B]<<8) | TxPower[RF_PATH_B];
write_bbreg(pAdapter, rTxAGC_B_CCK1_55_Mcs32, 0xffffff00, tmpval);
RT_TRACE(_module_mp_, _drv_notice_,
("-SetCCKTxPower: A[0x%02x] B[0x%02x]\n",
TxPower[RF_PATH_A], TxPower[RF_PATH_B]));
}
void Hal_SetOFDMTxPower(struct adapter *pAdapter, u8 *TxPower)
{
u32 TxAGC = 0;
u8 tmpval = 0;
/* HT Tx-rf(A) */
tmpval = TxPower[RF_PATH_A];
TxAGC = (tmpval<<24) | (tmpval<<16) | (tmpval<<8) | tmpval;
write_bbreg(pAdapter, rTxAGC_A_Rate18_06, bMaskDWord, TxAGC);
write_bbreg(pAdapter, rTxAGC_A_Rate54_24, bMaskDWord, TxAGC);
write_bbreg(pAdapter, rTxAGC_A_Mcs03_Mcs00, bMaskDWord, TxAGC);
write_bbreg(pAdapter, rTxAGC_A_Mcs07_Mcs04, bMaskDWord, TxAGC);
write_bbreg(pAdapter, rTxAGC_A_Mcs11_Mcs08, bMaskDWord, TxAGC);
write_bbreg(pAdapter, rTxAGC_A_Mcs15_Mcs12, bMaskDWord, TxAGC);
/* HT Tx-rf(B) */
tmpval = TxPower[RF_PATH_B];
TxAGC = (tmpval<<24) | (tmpval<<16) | (tmpval<<8) | tmpval;
write_bbreg(pAdapter, rTxAGC_B_Rate18_06, bMaskDWord, TxAGC);
write_bbreg(pAdapter, rTxAGC_B_Rate54_24, bMaskDWord, TxAGC);
write_bbreg(pAdapter, rTxAGC_B_Mcs03_Mcs00, bMaskDWord, TxAGC);
write_bbreg(pAdapter, rTxAGC_B_Mcs07_Mcs04, bMaskDWord, TxAGC);
write_bbreg(pAdapter, rTxAGC_B_Mcs11_Mcs08, bMaskDWord, TxAGC);
write_bbreg(pAdapter, rTxAGC_B_Mcs15_Mcs12, bMaskDWord, TxAGC);
}
void Hal_SetAntennaPathPower(struct adapter *pAdapter)
{
struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter);
u8 TxPowerLevel[MAX_RF_PATH_NUMS];
u8 rfPath;
TxPowerLevel[RF_PATH_A] = pAdapter->mppriv.txpoweridx;
TxPowerLevel[RF_PATH_B] = pAdapter->mppriv.txpoweridx_b;
switch (pAdapter->mppriv.antenna_tx) {
case ANTENNA_A:
default:
rfPath = RF_PATH_A;
break;
case ANTENNA_B:
rfPath = RF_PATH_B;
break;
case ANTENNA_C:
rfPath = RF_PATH_C;
break;
}
switch (pHalData->rf_chip) {
case RF_8225:
case RF_8256:
case RF_6052:
Hal_SetCCKTxPower(pAdapter, TxPowerLevel);
if (pAdapter->mppriv.rateidx < MPT_RATE_6M) /* CCK rate */
Hal_MPT_CCKTxPowerAdjustbyIndex(pAdapter, TxPowerLevel[rfPath]%2 == 0);
Hal_SetOFDMTxPower(pAdapter, TxPowerLevel);
break;
default:
break;
}
}
void Hal_SetTxPower(struct adapter *pAdapter)
{
struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter);
u8 TxPower = pAdapter->mppriv.txpoweridx;
u8 TxPowerLevel[MAX_RF_PATH_NUMS];
u8 rf, rfPath;
for (rf = 0; rf < MAX_RF_PATH_NUMS; rf++)
TxPowerLevel[rf] = TxPower;
switch (pAdapter->mppriv.antenna_tx) {
case ANTENNA_A:
default:
rfPath = RF_PATH_A;
break;
case ANTENNA_B:
rfPath = RF_PATH_B;
break;
case ANTENNA_C:
rfPath = RF_PATH_C;
break;
}
switch (pHalData->rf_chip) {
/* 2008/09/12 MH Test only !! We enable the TX power tracking for MP!!!!! */
/* We should call normal driver API later!! */
case RF_8225:
case RF_8256:
case RF_6052:
Hal_SetCCKTxPower(pAdapter, TxPowerLevel);
if (pAdapter->mppriv.rateidx < MPT_RATE_6M) /* CCK rate */
Hal_MPT_CCKTxPowerAdjustbyIndex(pAdapter, TxPowerLevel[rfPath]%2 == 0);
Hal_SetOFDMTxPower(pAdapter, TxPowerLevel);
break;
default:
break;
}
}
void Hal_SetDataRate(struct adapter *pAdapter)
{
Hal_mpt_SwitchRfSetting(pAdapter);
}
void Hal_SetAntenna(struct adapter *pAdapter)
{
struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter);
struct ant_sel_ofdm *p_ofdm_tx; /* OFDM Tx register */
struct ant_sel_cck *p_cck_txrx;
u8 r_rx_antenna_ofdm = 0, r_ant_select_cck_val = 0;
u8 chgTx = 0, chgRx = 0;
u32 r_ant_select_ofdm_val = 0, r_ofdm_tx_en_val = 0;
p_ofdm_tx = (struct ant_sel_ofdm *)&r_ant_select_ofdm_val;
p_cck_txrx = (struct ant_sel_cck *)&r_ant_select_cck_val;
p_ofdm_tx->r_ant_ht1 = 0x1;
p_ofdm_tx->r_ant_ht2 = 0x2; /* Second TX RF path is A */
p_ofdm_tx->r_ant_non_ht = 0x3; /* 0x1+0x2=0x3 */
switch (pAdapter->mppriv.antenna_tx) {
case ANTENNA_A:
p_ofdm_tx->r_tx_antenna = 0x1;
r_ofdm_tx_en_val = 0x1;
p_ofdm_tx->r_ant_l = 0x1;
p_ofdm_tx->r_ant_ht_s1 = 0x1;
p_ofdm_tx->r_ant_non_ht_s1 = 0x1;
p_cck_txrx->r_ccktx_enable = 0x8;
chgTx = 1;
/* From SD3 Willis suggestion !!! Set RF A=TX and B as standby */
write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter2, 0xe, 2);
write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter2, 0xe, 1);
r_ofdm_tx_en_val = 0x3;
/* Power save */
/* We need to close RFB by SW control */
if (pHalData->rf_type == RF_2T2R) {
PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT10, 0);
PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT26, 1);
PHY_SetBBReg(pAdapter, rFPGA0_XB_RFInterfaceOE, BIT10, 0);
PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFParameter, BIT1, 1);
PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFParameter, BIT17, 0);
}
break;
case ANTENNA_B:
p_ofdm_tx->r_tx_antenna = 0x2;
r_ofdm_tx_en_val = 0x2;
p_ofdm_tx->r_ant_l = 0x2;
p_ofdm_tx->r_ant_ht_s1 = 0x2;
p_ofdm_tx->r_ant_non_ht_s1 = 0x2;
p_cck_txrx->r_ccktx_enable = 0x4;
chgTx = 1;
/* From SD3 Willis suggestion !!! Set RF A as standby */
PHY_SetBBReg(pAdapter, rFPGA0_XA_HSSIParameter2, 0xe, 1);
PHY_SetBBReg(pAdapter, rFPGA0_XB_HSSIParameter2, 0xe, 2);
/* Power save */
/* cosa r_ant_select_ofdm_val = 0x22222222; */
/* 2008/10/31 MH From SD3 Willi's suggestion. We must read RF 1T table. */
/* 2009/01/08 MH From Sd3 Willis. We need to close RFA by SW control */
if (pHalData->rf_type == RF_2T2R || pHalData->rf_type == RF_1T2R) {
PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT10, 1);
PHY_SetBBReg(pAdapter, rFPGA0_XA_RFInterfaceOE, BIT10, 0);
PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT26, 0);
PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFParameter, BIT1, 0);
PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFParameter, BIT17, 1);
}
break;
case ANTENNA_AB: /* For 8192S */
p_ofdm_tx->r_tx_antenna = 0x3;
r_ofdm_tx_en_val = 0x3;
p_ofdm_tx->r_ant_l = 0x3;
p_ofdm_tx->r_ant_ht_s1 = 0x3;
p_ofdm_tx->r_ant_non_ht_s1 = 0x3;
p_cck_txrx->r_ccktx_enable = 0xC;
chgTx = 1;
/* From SD3 Willis suggestion !!! Set RF B as standby */
PHY_SetBBReg(pAdapter, rFPGA0_XA_HSSIParameter2, 0xe, 2);
PHY_SetBBReg(pAdapter, rFPGA0_XB_HSSIParameter2, 0xe, 2);
/* Disable Power save */
/* cosa r_ant_select_ofdm_val = 0x3321333; */
/* 2009/01/08 MH From Sd3 Willis. We need to enable RFA/B by SW control */
if (pHalData->rf_type == RF_2T2R) {
PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT10, 0);
PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT26, 0);
PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFParameter, BIT1, 1);
PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFParameter, BIT17, 1);
}
break;
default:
break;
}
/* r_rx_antenna_ofdm, bit0=A, bit1=B, bit2=C, bit3=D */
/* r_cckrx_enable : CCK default, 0=A, 1=B, 2=C, 3=D */
/* r_cckrx_enable_2 : CCK option, 0=A, 1=B, 2=C, 3=D */
switch (pAdapter->mppriv.antenna_rx) {
case ANTENNA_A:
r_rx_antenna_ofdm = 0x1; /* A */
p_cck_txrx->r_cckrx_enable = 0x0; /* default: A */
p_cck_txrx->r_cckrx_enable_2 = 0x0; /* option: A */
chgRx = 1;
break;
case ANTENNA_B:
r_rx_antenna_ofdm = 0x2; /* B */
p_cck_txrx->r_cckrx_enable = 0x1; /* default: B */
p_cck_txrx->r_cckrx_enable_2 = 0x1; /* option: B */
chgRx = 1;
break;
case ANTENNA_AB:
r_rx_antenna_ofdm = 0x3; /* AB */
p_cck_txrx->r_cckrx_enable = 0x0; /* default:A */
p_cck_txrx->r_cckrx_enable_2 = 0x1; /* option:B */
chgRx = 1;
break;
default:
break;
}
if (chgTx && chgRx) {
switch (pHalData->rf_chip) {
case RF_8225:
case RF_8256:
case RF_6052:
/* r_ant_sel_cck_val = r_ant_select_cck_val; */
PHY_SetBBReg(pAdapter, rFPGA1_TxInfo, 0x7fffffff, r_ant_select_ofdm_val); /* OFDM Tx */
PHY_SetBBReg(pAdapter, rFPGA0_TxInfo, 0x0000000f, r_ofdm_tx_en_val); /* OFDM Tx */
PHY_SetBBReg(pAdapter, rOFDM0_TRxPathEnable, 0x0000000f, r_rx_antenna_ofdm); /* OFDM Rx */
PHY_SetBBReg(pAdapter, rOFDM1_TRxPathEnable, 0x0000000f, r_rx_antenna_ofdm); /* OFDM Rx */
PHY_SetBBReg(pAdapter, rCCK0_AFESetting, bMaskByte3, r_ant_select_cck_val); /* CCK TxRx */
break;
default:
break;
}
}
RT_TRACE(_module_mp_, _drv_notice_, ("-SwitchAntenna: finished\n"));
}
s32 Hal_SetThermalMeter(struct adapter *pAdapter, u8 target_ther)
{
struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter);
if (!netif_running(pAdapter->pnetdev)) {
RT_TRACE(_module_mp_, _drv_warning_, ("SetThermalMeter! Fail: interface not opened!\n"));
return _FAIL;
}
if (check_fwstate(&pAdapter->mlmepriv, WIFI_MP_STATE) == false) {
RT_TRACE(_module_mp_, _drv_warning_, ("SetThermalMeter: Fail! not in MP mode!\n"));
return _FAIL;
}
target_ther &= 0xff;
if (target_ther < 0x07)
target_ther = 0x07;
else if (target_ther > 0x1d)
target_ther = 0x1d;
pHalData->EEPROMThermalMeter = target_ther;
return _SUCCESS;
}
void Hal_TriggerRFThermalMeter(struct adapter *pAdapter)
{
_write_rfreg(pAdapter, RF_PATH_A , RF_T_METER_88E , BIT17 | BIT16 , 0x03);
}
u8 Hal_ReadRFThermalMeter(struct adapter *pAdapter)
{
u32 ThermalValue = 0;
ThermalValue = _read_rfreg(pAdapter, RF_PATH_A, RF_T_METER_88E, 0xfc00);
return (u8)ThermalValue;
}
void Hal_GetThermalMeter(struct adapter *pAdapter, u8 *value)
{
Hal_TriggerRFThermalMeter(pAdapter);
rtw_msleep_os(1000);
*value = Hal_ReadRFThermalMeter(pAdapter);
}
void Hal_SetSingleCarrierTx(struct adapter *pAdapter, u8 bStart)
{
pAdapter->mppriv.MptCtx.bSingleCarrier = bStart;
if (bStart) {
/* Start Single Carrier. */
RT_TRACE(_module_mp_, _drv_alert_, ("SetSingleCarrierTx: test start\n"));
/* 1. if OFDM block on? */
if (!read_bbreg(pAdapter, rFPGA0_RFMOD, bOFDMEn))
write_bbreg(pAdapter, rFPGA0_RFMOD, bOFDMEn, bEnable);/* set OFDM block on */
/* 2. set CCK test mode off, set to CCK normal mode */
write_bbreg(pAdapter, rCCK0_System, bCCKBBMode, bDisable);
/* 3. turn on scramble setting */
write_bbreg(pAdapter, rCCK0_System, bCCKScramble, bEnable);
/* 4. Turn On Single Carrier Tx and turn off the other test modes. */
write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, bDisable);
write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, bEnable);
write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, bDisable);
/* for dynamic set Power index. */
write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000500);
write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000500);
} else {
/* Stop Single Carrier. */
RT_TRACE(_module_mp_, _drv_alert_, ("SetSingleCarrierTx: test stop\n"));
/* Turn off all test modes. */
write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, bDisable);
write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, bDisable);
write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, bDisable);
rtw_msleep_os(10);
/* BB Reset */
write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x0);
write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x1);
/* Stop for dynamic set Power index. */
write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000100);
write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000100);
}
}
void Hal_SetSingleToneTx(struct adapter *pAdapter, u8 bStart)
{
struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter);
bool is92C = IS_92C_SERIAL(pHalData->VersionID);
u8 rfPath;
u32 reg58 = 0x0;
switch (pAdapter->mppriv.antenna_tx) {
case ANTENNA_A:
default:
rfPath = RF_PATH_A;
break;
case ANTENNA_B:
rfPath = RF_PATH_B;
break;
case ANTENNA_C:
rfPath = RF_PATH_C;
break;
}
pAdapter->mppriv.MptCtx.bSingleTone = bStart;
if (bStart) {
/* Start Single Tone. */
RT_TRACE(_module_mp_, _drv_alert_, ("SetSingleToneTx: test start\n"));
/* <20120326, Kordan> To amplify the power of tone for Xtal calibration. (asked by Edlu) */
if (IS_HARDWARE_TYPE_8188E(pAdapter)) {
reg58 = PHY_QueryRFReg(pAdapter, RF_PATH_A, LNA_Low_Gain_3, bRFRegOffsetMask);
reg58 &= 0xFFFFFFF0;
reg58 += 2;
PHY_SetRFReg(pAdapter, RF_PATH_A, LNA_Low_Gain_3, bRFRegOffsetMask, reg58);
}
PHY_SetBBReg(pAdapter, rFPGA0_RFMOD, bCCKEn, 0x0);
PHY_SetBBReg(pAdapter, rFPGA0_RFMOD, bOFDMEn, 0x0);
if (is92C) {
_write_rfreg(pAdapter, RF_PATH_A, 0x21, BIT19, 0x01);
rtw_usleep_os(100);
if (rfPath == RF_PATH_A)
write_rfreg(pAdapter, RF_PATH_B, 0x00, 0x10000); /* PAD all on. */
else if (rfPath == RF_PATH_B)
write_rfreg(pAdapter, RF_PATH_A, 0x00, 0x10000); /* PAD all on. */
write_rfreg(pAdapter, rfPath, 0x00, 0x2001f); /* PAD all on. */
rtw_usleep_os(100);
} else {
write_rfreg(pAdapter, rfPath, 0x21, 0xd4000);
rtw_usleep_os(100);
write_rfreg(pAdapter, rfPath, 0x00, 0x2001f); /* PAD all on. */
rtw_usleep_os(100);
}
/* for dynamic set Power index. */
write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000500);
write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000500);
} else {
/* Stop Single Tone. */
RT_TRACE(_module_mp_, _drv_alert_, ("SetSingleToneTx: test stop\n"));
/* <20120326, Kordan> To amplify the power of tone for Xtal calibration. (asked by Edlu) */
/* <20120326, Kordan> Only in single tone mode. (asked by Edlu) */
if (IS_HARDWARE_TYPE_8188E(pAdapter)) {
reg58 = PHY_QueryRFReg(pAdapter, RF_PATH_A, LNA_Low_Gain_3, bRFRegOffsetMask);
reg58 &= 0xFFFFFFF0;
PHY_SetRFReg(pAdapter, RF_PATH_A, LNA_Low_Gain_3, bRFRegOffsetMask, reg58);
}
write_bbreg(pAdapter, rFPGA0_RFMOD, bCCKEn, 0x1);
write_bbreg(pAdapter, rFPGA0_RFMOD, bOFDMEn, 0x1);
if (is92C) {
_write_rfreg(pAdapter, RF_PATH_A, 0x21, BIT19, 0x00);
rtw_usleep_os(100);
write_rfreg(pAdapter, RF_PATH_A, 0x00, 0x32d75); /* PAD all on. */
write_rfreg(pAdapter, RF_PATH_B, 0x00, 0x32d75); /* PAD all on. */
rtw_usleep_os(100);
} else {
write_rfreg(pAdapter, rfPath, 0x21, 0x54000);
rtw_usleep_os(100);
write_rfreg(pAdapter, rfPath, 0x00, 0x30000); /* PAD all on. */
rtw_usleep_os(100);
}
/* Stop for dynamic set Power index. */
write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000100);
write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000100);
}
}
void Hal_SetCarrierSuppressionTx(struct adapter *pAdapter, u8 bStart)
{
pAdapter->mppriv.MptCtx.bCarrierSuppression = bStart;
if (bStart) {
/* Start Carrier Suppression. */
RT_TRACE(_module_mp_, _drv_alert_, ("SetCarrierSuppressionTx: test start\n"));
if (pAdapter->mppriv.rateidx <= MPT_RATE_11M) {
/* 1. if CCK block on? */
if (!read_bbreg(pAdapter, rFPGA0_RFMOD, bCCKEn))
write_bbreg(pAdapter, rFPGA0_RFMOD, bCCKEn, bEnable);/* set CCK block on */
/* Turn Off All Test Mode */
write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, bDisable);
write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, bDisable);
write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, bDisable);
write_bbreg(pAdapter, rCCK0_System, bCCKBBMode, 0x2); /* transmit mode */
write_bbreg(pAdapter, rCCK0_System, bCCKScramble, 0x0); /* turn off scramble setting */
/* Set CCK Tx Test Rate */
write_bbreg(pAdapter, rCCK0_System, bCCKTxRate, 0x0); /* Set FTxRate to 1Mbps */
}
/* for dynamic set Power index. */
write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000500);
write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000500);
} else {
/* Stop Carrier Suppression. */
RT_TRACE(_module_mp_, _drv_alert_, ("SetCarrierSuppressionTx: test stop\n"));
if (pAdapter->mppriv.rateidx <= MPT_RATE_11M) {
write_bbreg(pAdapter, rCCK0_System, bCCKBBMode, 0x0); /* normal mode */
write_bbreg(pAdapter, rCCK0_System, bCCKScramble, 0x1); /* turn on scramble setting */
/* BB Reset */
write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x0);
write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x1);
}
/* Stop for dynamic set Power index. */
write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000100);
write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000100);
}
}
void Hal_SetCCKContinuousTx(struct adapter *pAdapter, u8 bStart)
{
u32 cckrate;
if (bStart) {
RT_TRACE(_module_mp_, _drv_alert_,
("SetCCKContinuousTx: test start\n"));
/* 1. if CCK block on? */
if (!read_bbreg(pAdapter, rFPGA0_RFMOD, bCCKEn))
write_bbreg(pAdapter, rFPGA0_RFMOD, bCCKEn, bEnable);/* set CCK block on */
/* Turn Off All Test Mode */
write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, bDisable);
write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, bDisable);
write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, bDisable);
/* Set CCK Tx Test Rate */
cckrate = pAdapter->mppriv.rateidx;
write_bbreg(pAdapter, rCCK0_System, bCCKTxRate, cckrate);
write_bbreg(pAdapter, rCCK0_System, bCCKBBMode, 0x2); /* transmit mode */
write_bbreg(pAdapter, rCCK0_System, bCCKScramble, bEnable); /* turn on scramble setting */
/* for dynamic set Power index. */
write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000500);
write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000500);
} else {
RT_TRACE(_module_mp_, _drv_info_,
("SetCCKContinuousTx: test stop\n"));
write_bbreg(pAdapter, rCCK0_System, bCCKBBMode, 0x0); /* normal mode */
write_bbreg(pAdapter, rCCK0_System, bCCKScramble, bEnable); /* turn on scramble setting */
/* BB Reset */
write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x0);
write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x1);
/* Stop for dynamic set Power index. */
write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000100);
write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000100);
}
pAdapter->mppriv.MptCtx.bCckContTx = bStart;
pAdapter->mppriv.MptCtx.bOfdmContTx = false;
} /* mpt_StartCckContTx */
void Hal_SetOFDMContinuousTx(struct adapter *pAdapter, u8 bStart)
{
if (bStart) {
RT_TRACE(_module_mp_, _drv_info_, ("SetOFDMContinuousTx: test start\n"));
/* 1. if OFDM block on? */
if (!read_bbreg(pAdapter, rFPGA0_RFMOD, bOFDMEn))
write_bbreg(pAdapter, rFPGA0_RFMOD, bOFDMEn, bEnable);/* set OFDM block on */
/* 2. set CCK test mode off, set to CCK normal mode */
write_bbreg(pAdapter, rCCK0_System, bCCKBBMode, bDisable);
/* 3. turn on scramble setting */
write_bbreg(pAdapter, rCCK0_System, bCCKScramble, bEnable);
/* 4. Turn On Continue Tx and turn off the other test modes. */
write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, bEnable);
write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, bDisable);
write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, bDisable);
/* for dynamic set Power index. */
write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000500);
write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000500);
} else {
RT_TRACE(_module_mp_, _drv_info_, ("SetOFDMContinuousTx: test stop\n"));
write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, bDisable);
write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, bDisable);
write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, bDisable);
/* Delay 10 ms */
rtw_msleep_os(10);
/* BB Reset */
write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x0);
write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x1);
/* Stop for dynamic set Power index. */
write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000100);
write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000100);
}
pAdapter->mppriv.MptCtx.bCckContTx = false;
pAdapter->mppriv.MptCtx.bOfdmContTx = bStart;
} /* mpt_StartOfdmContTx */
void Hal_SetContinuousTx(struct adapter *pAdapter, u8 bStart)
{
RT_TRACE(_module_mp_, _drv_info_,
("SetContinuousTx: rate:%d\n", pAdapter->mppriv.rateidx));
pAdapter->mppriv.MptCtx.bStartContTx = bStart;
if (pAdapter->mppriv.rateidx <= MPT_RATE_11M)
Hal_SetCCKContinuousTx(pAdapter, bStart);
else if ((pAdapter->mppriv.rateidx >= MPT_RATE_6M) &&
(pAdapter->mppriv.rateidx <= MPT_RATE_MCS15))
Hal_SetOFDMContinuousTx(pAdapter, bStart);
}
/******************************************************************************
*
* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
*
* 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.
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*
*
******************************************************************************/
#define _RTL8188E_PHYCFG_C_
#include <osdep_service.h>
#include <drv_types.h>
#include <rtw_iol.h>
#include <rtl8188e_hal.h>
/*---------------------------Define Local Constant---------------------------*/
/* Channel switch:The size of command tables for switch channel*/
#define MAX_PRECMD_CNT 16
#define MAX_RFDEPENDCMD_CNT 16
#define MAX_POSTCMD_CNT 16
#define MAX_DOZE_WAITING_TIMES_9x 64
/*---------------------------Define Local Constant---------------------------*/
/*------------------------Define global variable-----------------------------*/
/*------------------------Define local variable------------------------------*/
/*--------------------Define export function prototype-----------------------*/
/* Please refer to header file */
/*--------------------Define export function prototype-----------------------*/
/*----------------------------Function Body----------------------------------*/
/* */
/* 1. BB register R/W API */
/* */
/**
* Function: phy_CalculateBitShift
*
* OverView: Get shifted position of the BitMask
*
* Input:
* u32 BitMask,
*
* Output: none
* Return: u32 Return the shift bit bit position of the mask
*/
static u32 phy_CalculateBitShift(u32 BitMask)
{
u32 i;
for (i = 0; i <= 31; i++) {
if (((BitMask>>i) & 0x1) == 1)
break;
}
return i;
}
/**
* Function: PHY_QueryBBReg
*
* OverView: Read "sepcific bits" from BB register
*
* Input:
* struct adapter *Adapter,
* u32 RegAddr, The target address to be readback
* u32 BitMask The target bit position in the target address
* to be readback
* Output: None
* Return: u32 Data The readback register value
* Note: This function is equal to "GetRegSetting" in PHY programming guide
*/
u32
rtl8188e_PHY_QueryBBReg(
struct adapter *Adapter,
u32 RegAddr,
u32 BitMask
)
{
u32 ReturnValue = 0, OriginalValue, BitShift;
OriginalValue = rtw_read32(Adapter, RegAddr);
BitShift = phy_CalculateBitShift(BitMask);
ReturnValue = (OriginalValue & BitMask) >> BitShift;
return ReturnValue;
}
/**
* Function: PHY_SetBBReg
*
* OverView: Write "Specific bits" to BB register (page 8~)
*
* Input:
* struct adapter *Adapter,
* u32 RegAddr, The target address to be modified
* u32 BitMask The target bit position in the target address
* to be modified
* u32 Data The new register value in the target bit position
* of the target address
*
* Output: None
* Return: None
* Note: This function is equal to "PutRegSetting" in PHY programming guide
*/
void rtl8188e_PHY_SetBBReg(struct adapter *Adapter, u32 RegAddr, u32 BitMask, u32 Data)
{
u32 OriginalValue, BitShift;
if (BitMask != bMaskDWord) { /* if not "double word" write */
OriginalValue = rtw_read32(Adapter, RegAddr);
BitShift = phy_CalculateBitShift(BitMask);
Data = ((OriginalValue & (~BitMask)) | (Data << BitShift));
}
rtw_write32(Adapter, RegAddr, Data);
}
/* */
/* 2. RF register R/W API */
/* */
/**
* Function: phy_RFSerialRead
*
* OverView: Read regster from RF chips
*
* Input:
* struct adapter *Adapter,
* enum rf_radio_path eRFPath, Radio path of A/B/C/D
* u32 Offset, The target address to be read
*
* Output: None
* Return: u32 reback value
* Note: Threre are three types of serial operations:
* 1. Software serial write
* 2. Hardware LSSI-Low Speed Serial Interface
* 3. Hardware HSSI-High speed
* serial write. Driver need to implement (1) and (2).
* This function is equal to the combination of RF_ReadReg() and RFLSSIRead()
*/
static u32
phy_RFSerialRead(
struct adapter *Adapter,
enum rf_radio_path eRFPath,
u32 Offset
)
{
u32 retValue = 0;
struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
struct bb_reg_def *pPhyReg = &pHalData->PHYRegDef[eRFPath];
u32 NewOffset;
u32 tmplong, tmplong2;
u8 RfPiEnable = 0;
/* */
/* Make sure RF register offset is correct */
/* */
Offset &= 0xff;
/* */
/* Switch page for 8256 RF IC */
/* */
NewOffset = Offset;
/* For 92S LSSI Read RFLSSIRead */
/* For RF A/B write 0x824/82c(does not work in the future) */
/* We must use 0x824 for RF A and B to execute read trigger */
tmplong = PHY_QueryBBReg(Adapter, rFPGA0_XA_HSSIParameter2, bMaskDWord);
if (eRFPath == RF_PATH_A)
tmplong2 = tmplong;
else
tmplong2 = PHY_QueryBBReg(Adapter, pPhyReg->rfHSSIPara2, bMaskDWord);
tmplong2 = (tmplong2 & (~bLSSIReadAddress)) | (NewOffset<<23) | bLSSIReadEdge; /* T65 RF */
PHY_SetBBReg(Adapter, rFPGA0_XA_HSSIParameter2, bMaskDWord, tmplong&(~bLSSIReadEdge));
rtw_udelay_os(10);/* PlatformStallExecution(10); */
PHY_SetBBReg(Adapter, pPhyReg->rfHSSIPara2, bMaskDWord, tmplong2);
rtw_udelay_os(100);/* PlatformStallExecution(100); */
rtw_udelay_os(10);/* PlatformStallExecution(10); */
if (eRFPath == RF_PATH_A)
RfPiEnable = (u8)PHY_QueryBBReg(Adapter, rFPGA0_XA_HSSIParameter1, BIT8);
else if (eRFPath == RF_PATH_B)
RfPiEnable = (u8)PHY_QueryBBReg(Adapter, rFPGA0_XB_HSSIParameter1, BIT8);
if (RfPiEnable) { /* Read from BBreg8b8, 12 bits for 8190, 20bits for T65 RF */
retValue = PHY_QueryBBReg(Adapter, pPhyReg->rfLSSIReadBackPi, bLSSIReadBackData);
} else { /* Read from BBreg8a0, 12 bits for 8190, 20 bits for T65 RF */
retValue = PHY_QueryBBReg(Adapter, pPhyReg->rfLSSIReadBack, bLSSIReadBackData);
}
return retValue;
}
/**
* Function: phy_RFSerialWrite
*
* OverView: Write data to RF register (page 8~)
*
* Input:
* struct adapter *Adapter,
* enum rf_radio_path eRFPath, Radio path of A/B/C/D
* u32 Offset, The target address to be read
* u32 Data The new register Data in the target bit position
* of the target to be read
*
* Output: None
* Return: None
* Note: Threre are three types of serial operations:
* 1. Software serial write
* 2. Hardware LSSI-Low Speed Serial Interface
* 3. Hardware HSSI-High speed
* serial write. Driver need to implement (1) and (2).
* This function is equal to the combination of RF_ReadReg() and RFLSSIRead()
*
* Note: For RF8256 only
* The total count of RTL8256(Zebra4) register is around 36 bit it only employs
* 4-bit RF address. RTL8256 uses "register mode control bit" (Reg00[12], Reg00[10])
* to access register address bigger than 0xf. See "Appendix-4 in PHY Configuration
* programming guide" for more details.
* Thus, we define a sub-finction for RTL8526 register address conversion
* ===========================================================
* Register Mode RegCTL[1] RegCTL[0] Note
* (Reg00[12]) (Reg00[10])
* ===========================================================
* Reg_Mode0 0 x Reg 0 ~15(0x0 ~ 0xf)
* ------------------------------------------------------------------
* Reg_Mode1 1 0 Reg 16 ~30(0x1 ~ 0xf)
* ------------------------------------------------------------------
* Reg_Mode2 1 1 Reg 31 ~ 45(0x1 ~ 0xf)
* ------------------------------------------------------------------
*
* 2008/09/02 MH Add 92S RF definition
*
*
*
*/
static void
phy_RFSerialWrite(
struct adapter *Adapter,
enum rf_radio_path eRFPath,
u32 Offset,
u32 Data
)
{
u32 DataAndAddr = 0;
struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
struct bb_reg_def *pPhyReg = &pHalData->PHYRegDef[eRFPath];
u32 NewOffset;
/* 2009/06/17 MH We can not execute IO for power save or other accident mode. */
Offset &= 0xff;
/* */
/* Switch page for 8256 RF IC */
/* */
NewOffset = Offset;
/* */
/* Put write addr in [5:0] and write data in [31:16] */
/* */
DataAndAddr = ((NewOffset<<20) | (Data&0x000fffff)) & 0x0fffffff; /* T65 RF */
/* */
/* Write Operation */
/* */
PHY_SetBBReg(Adapter, pPhyReg->rf3wireOffset, bMaskDWord, DataAndAddr);
}
/**
* Function: PHY_QueryRFReg
*
* OverView: Query "Specific bits" to RF register (page 8~)
*
* Input:
* struct adapter *Adapter,
* enum rf_radio_path eRFPath, Radio path of A/B/C/D
* u32 RegAddr, The target address to be read
* u32 BitMask The target bit position in the target address
* to be read
*
* Output: None
* Return: u32 Readback value
* Note: This function is equal to "GetRFRegSetting" in PHY programming guide
*/
u32 rtl8188e_PHY_QueryRFReg(struct adapter *Adapter, enum rf_radio_path eRFPath,
u32 RegAddr, u32 BitMask)
{
u32 Original_Value, Readback_Value, BitShift;
Original_Value = phy_RFSerialRead(Adapter, eRFPath, RegAddr);
BitShift = phy_CalculateBitShift(BitMask);
Readback_Value = (Original_Value & BitMask) >> BitShift;
return Readback_Value;
}
/**
* Function: PHY_SetRFReg
*
* OverView: Write "Specific bits" to RF register (page 8~)
*
* Input:
* struct adapter *Adapter,
* enum rf_radio_path eRFPath, Radio path of A/B/C/D
* u32 RegAddr, The target address to be modified
* u32 BitMask The target bit position in the target address
* to be modified
* u32 Data The new register Data in the target bit position
* of the target address
*
* Output: None
* Return: None
* Note: This function is equal to "PutRFRegSetting" in PHY programming guide
*/
void
rtl8188e_PHY_SetRFReg(
struct adapter *Adapter,
enum rf_radio_path eRFPath,
u32 RegAddr,
u32 BitMask,
u32 Data
)
{
u32 Original_Value, BitShift;
/* RF data is 12 bits only */
if (BitMask != bRFRegOffsetMask) {
Original_Value = phy_RFSerialRead(Adapter, eRFPath, RegAddr);
BitShift = phy_CalculateBitShift(BitMask);
Data = ((Original_Value & (~BitMask)) | (Data << BitShift));
}
phy_RFSerialWrite(Adapter, eRFPath, RegAddr, Data);
}
/* */
/* 3. Initial MAC/BB/RF config by reading MAC/BB/RF txt. */
/* */
/*-----------------------------------------------------------------------------
* Function: PHY_MACConfig8192C
*
* Overview: Condig MAC by header file or parameter file.
*
* Input: NONE
*
* Output: NONE
*
* Return: NONE
*
* Revised History:
* When Who Remark
* 08/12/2008 MHC Create Version 0.
*
*---------------------------------------------------------------------------*/
s32 PHY_MACConfig8188E(struct adapter *Adapter)
{
struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
int rtStatus = _SUCCESS;
/* */
/* Config MAC */
/* */
if (HAL_STATUS_FAILURE == ODM_ConfigMACWithHeaderFile(&pHalData->odmpriv))
rtStatus = _FAIL;
/* 2010.07.13 AMPDU aggregation number B */
rtw_write16(Adapter, REG_MAX_AGGR_NUM, MAX_AGGR_NUM);
return rtStatus;
}
/**
* Function: phy_InitBBRFRegisterDefinition
*
* OverView: Initialize Register definition offset for Radio Path A/B/C/D
*
* Input:
* struct adapter *Adapter,
*
* Output: None
* Return: None
* Note: The initialization value is constant and it should never be changes
*/
static void
phy_InitBBRFRegisterDefinition(
struct adapter *Adapter
)
{
struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
/* RF Interface Sowrtware Control */
pHalData->PHYRegDef[RF_PATH_A].rfintfs = rFPGA0_XAB_RFInterfaceSW; /* 16 LSBs if read 32-bit from 0x870 */
pHalData->PHYRegDef[RF_PATH_B].rfintfs = rFPGA0_XAB_RFInterfaceSW; /* 16 MSBs if read 32-bit from 0x870 (16-bit for 0x872) */
pHalData->PHYRegDef[RF_PATH_C].rfintfs = rFPGA0_XCD_RFInterfaceSW;/* 16 LSBs if read 32-bit from 0x874 */
pHalData->PHYRegDef[RF_PATH_D].rfintfs = rFPGA0_XCD_RFInterfaceSW;/* 16 MSBs if read 32-bit from 0x874 (16-bit for 0x876) */
/* RF Interface Readback Value */
pHalData->PHYRegDef[RF_PATH_A].rfintfi = rFPGA0_XAB_RFInterfaceRB; /* 16 LSBs if read 32-bit from 0x8E0 */
pHalData->PHYRegDef[RF_PATH_B].rfintfi = rFPGA0_XAB_RFInterfaceRB;/* 16 MSBs if read 32-bit from 0x8E0 (16-bit for 0x8E2) */
pHalData->PHYRegDef[RF_PATH_C].rfintfi = rFPGA0_XCD_RFInterfaceRB;/* 16 LSBs if read 32-bit from 0x8E4 */
pHalData->PHYRegDef[RF_PATH_D].rfintfi = rFPGA0_XCD_RFInterfaceRB;/* 16 MSBs if read 32-bit from 0x8E4 (16-bit for 0x8E6) */
/* RF Interface Output (and Enable) */
pHalData->PHYRegDef[RF_PATH_A].rfintfo = rFPGA0_XA_RFInterfaceOE; /* 16 LSBs if read 32-bit from 0x860 */
pHalData->PHYRegDef[RF_PATH_B].rfintfo = rFPGA0_XB_RFInterfaceOE; /* 16 LSBs if read 32-bit from 0x864 */
/* RF Interface (Output and) Enable */
pHalData->PHYRegDef[RF_PATH_A].rfintfe = rFPGA0_XA_RFInterfaceOE; /* 16 MSBs if read 32-bit from 0x860 (16-bit for 0x862) */
pHalData->PHYRegDef[RF_PATH_B].rfintfe = rFPGA0_XB_RFInterfaceOE; /* 16 MSBs if read 32-bit from 0x864 (16-bit for 0x866) */
/* Addr of LSSI. Wirte RF register by driver */
pHalData->PHYRegDef[RF_PATH_A].rf3wireOffset = rFPGA0_XA_LSSIParameter; /* LSSI Parameter */
pHalData->PHYRegDef[RF_PATH_B].rf3wireOffset = rFPGA0_XB_LSSIParameter;
/* RF parameter */
pHalData->PHYRegDef[RF_PATH_A].rfLSSI_Select = rFPGA0_XAB_RFParameter; /* BB Band Select */
pHalData->PHYRegDef[RF_PATH_B].rfLSSI_Select = rFPGA0_XAB_RFParameter;
pHalData->PHYRegDef[RF_PATH_C].rfLSSI_Select = rFPGA0_XCD_RFParameter;
pHalData->PHYRegDef[RF_PATH_D].rfLSSI_Select = rFPGA0_XCD_RFParameter;
/* Tx AGC Gain Stage (same for all path. Should we remove this?) */
pHalData->PHYRegDef[RF_PATH_A].rfTxGainStage = rFPGA0_TxGainStage; /* Tx gain stage */
pHalData->PHYRegDef[RF_PATH_B].rfTxGainStage = rFPGA0_TxGainStage; /* Tx gain stage */
pHalData->PHYRegDef[RF_PATH_C].rfTxGainStage = rFPGA0_TxGainStage; /* Tx gain stage */
pHalData->PHYRegDef[RF_PATH_D].rfTxGainStage = rFPGA0_TxGainStage; /* Tx gain stage */
/* Tranceiver A~D HSSI Parameter-1 */
pHalData->PHYRegDef[RF_PATH_A].rfHSSIPara1 = rFPGA0_XA_HSSIParameter1; /* wire control parameter1 */
pHalData->PHYRegDef[RF_PATH_B].rfHSSIPara1 = rFPGA0_XB_HSSIParameter1; /* wire control parameter1 */
/* Tranceiver A~D HSSI Parameter-2 */
pHalData->PHYRegDef[RF_PATH_A].rfHSSIPara2 = rFPGA0_XA_HSSIParameter2; /* wire control parameter2 */
pHalData->PHYRegDef[RF_PATH_B].rfHSSIPara2 = rFPGA0_XB_HSSIParameter2; /* wire control parameter2 */
/* RF switch Control */
pHalData->PHYRegDef[RF_PATH_A].rfSwitchControl = rFPGA0_XAB_SwitchControl; /* TR/Ant switch control */
pHalData->PHYRegDef[RF_PATH_B].rfSwitchControl = rFPGA0_XAB_SwitchControl;
pHalData->PHYRegDef[RF_PATH_C].rfSwitchControl = rFPGA0_XCD_SwitchControl;
pHalData->PHYRegDef[RF_PATH_D].rfSwitchControl = rFPGA0_XCD_SwitchControl;
/* AGC control 1 */
pHalData->PHYRegDef[RF_PATH_A].rfAGCControl1 = rOFDM0_XAAGCCore1;
pHalData->PHYRegDef[RF_PATH_B].rfAGCControl1 = rOFDM0_XBAGCCore1;
pHalData->PHYRegDef[RF_PATH_C].rfAGCControl1 = rOFDM0_XCAGCCore1;
pHalData->PHYRegDef[RF_PATH_D].rfAGCControl1 = rOFDM0_XDAGCCore1;
/* AGC control 2 */
pHalData->PHYRegDef[RF_PATH_A].rfAGCControl2 = rOFDM0_XAAGCCore2;
pHalData->PHYRegDef[RF_PATH_B].rfAGCControl2 = rOFDM0_XBAGCCore2;
pHalData->PHYRegDef[RF_PATH_C].rfAGCControl2 = rOFDM0_XCAGCCore2;
pHalData->PHYRegDef[RF_PATH_D].rfAGCControl2 = rOFDM0_XDAGCCore2;
/* RX AFE control 1 */
pHalData->PHYRegDef[RF_PATH_A].rfRxIQImbalance = rOFDM0_XARxIQImbalance;
pHalData->PHYRegDef[RF_PATH_B].rfRxIQImbalance = rOFDM0_XBRxIQImbalance;
pHalData->PHYRegDef[RF_PATH_C].rfRxIQImbalance = rOFDM0_XCRxIQImbalance;
pHalData->PHYRegDef[RF_PATH_D].rfRxIQImbalance = rOFDM0_XDRxIQImbalance;
/* RX AFE control 1 */
pHalData->PHYRegDef[RF_PATH_A].rfRxAFE = rOFDM0_XARxAFE;
pHalData->PHYRegDef[RF_PATH_B].rfRxAFE = rOFDM0_XBRxAFE;
pHalData->PHYRegDef[RF_PATH_C].rfRxAFE = rOFDM0_XCRxAFE;
pHalData->PHYRegDef[RF_PATH_D].rfRxAFE = rOFDM0_XDRxAFE;
/* Tx AFE control 1 */
pHalData->PHYRegDef[RF_PATH_A].rfTxIQImbalance = rOFDM0_XATxIQImbalance;
pHalData->PHYRegDef[RF_PATH_B].rfTxIQImbalance = rOFDM0_XBTxIQImbalance;
pHalData->PHYRegDef[RF_PATH_C].rfTxIQImbalance = rOFDM0_XCTxIQImbalance;
pHalData->PHYRegDef[RF_PATH_D].rfTxIQImbalance = rOFDM0_XDTxIQImbalance;
/* Tx AFE control 2 */
pHalData->PHYRegDef[RF_PATH_A].rfTxAFE = rOFDM0_XATxAFE;
pHalData->PHYRegDef[RF_PATH_B].rfTxAFE = rOFDM0_XBTxAFE;
pHalData->PHYRegDef[RF_PATH_C].rfTxAFE = rOFDM0_XCTxAFE;
pHalData->PHYRegDef[RF_PATH_D].rfTxAFE = rOFDM0_XDTxAFE;
/* Tranceiver LSSI Readback SI mode */
pHalData->PHYRegDef[RF_PATH_A].rfLSSIReadBack = rFPGA0_XA_LSSIReadBack;
pHalData->PHYRegDef[RF_PATH_B].rfLSSIReadBack = rFPGA0_XB_LSSIReadBack;
pHalData->PHYRegDef[RF_PATH_C].rfLSSIReadBack = rFPGA0_XC_LSSIReadBack;
pHalData->PHYRegDef[RF_PATH_D].rfLSSIReadBack = rFPGA0_XD_LSSIReadBack;
/* Tranceiver LSSI Readback PI mode */
pHalData->PHYRegDef[RF_PATH_A].rfLSSIReadBackPi = TransceiverA_HSPI_Readback;
pHalData->PHYRegDef[RF_PATH_B].rfLSSIReadBackPi = TransceiverB_HSPI_Readback;
}
void storePwrIndexDiffRateOffset(struct adapter *Adapter, u32 RegAddr, u32 BitMask, u32 Data)
{
struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
if (RegAddr == rTxAGC_A_Rate18_06)
pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][0] = Data;
if (RegAddr == rTxAGC_A_Rate54_24)
pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][1] = Data;
if (RegAddr == rTxAGC_A_CCK1_Mcs32)
pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][6] = Data;
if (RegAddr == rTxAGC_B_CCK11_A_CCK2_11 && BitMask == 0xffffff00)
pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][7] = Data;
if (RegAddr == rTxAGC_A_Mcs03_Mcs00)
pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][2] = Data;
if (RegAddr == rTxAGC_A_Mcs07_Mcs04)
pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][3] = Data;
if (RegAddr == rTxAGC_A_Mcs11_Mcs08)
pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][4] = Data;
if (RegAddr == rTxAGC_A_Mcs15_Mcs12) {
pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][5] = Data;
if (pHalData->rf_type == RF_1T1R)
pHalData->pwrGroupCnt++;
}
if (RegAddr == rTxAGC_B_Rate18_06)
pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][8] = Data;
if (RegAddr == rTxAGC_B_Rate54_24)
pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][9] = Data;
if (RegAddr == rTxAGC_B_CCK1_55_Mcs32)
pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][14] = Data;
if (RegAddr == rTxAGC_B_CCK11_A_CCK2_11 && BitMask == 0x000000ff)
pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][15] = Data;
if (RegAddr == rTxAGC_B_Mcs03_Mcs00)
pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][10] = Data;
if (RegAddr == rTxAGC_B_Mcs07_Mcs04)
pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][11] = Data;
if (RegAddr == rTxAGC_B_Mcs11_Mcs08)
pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][12] = Data;
if (RegAddr == rTxAGC_B_Mcs15_Mcs12) {
pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][13] = Data;
if (pHalData->rf_type != RF_1T1R)
pHalData->pwrGroupCnt++;
}
}
static int phy_BB8188E_Config_ParaFile(struct adapter *Adapter)
{
struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(Adapter);
struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
int rtStatus = _SUCCESS;
/* */
/* 1. Read PHY_REG.TXT BB INIT!! */
/* We will seperate as 88C / 92C according to chip version */
/* */
if (HAL_STATUS_FAILURE == ODM_ConfigBBWithHeaderFile(&pHalData->odmpriv, CONFIG_BB_PHY_REG))
rtStatus = _FAIL;
if (rtStatus != _SUCCESS)
goto phy_BB8190_Config_ParaFile_Fail;
/* 2. If EEPROM or EFUSE autoload OK, We must config by PHY_REG_PG.txt */
if (!pEEPROM->bautoload_fail_flag) {
pHalData->pwrGroupCnt = 0;
if (HAL_STATUS_FAILURE == ODM_ConfigBBWithHeaderFile(&pHalData->odmpriv, CONFIG_BB_PHY_REG_PG))
rtStatus = _FAIL;
}
if (rtStatus != _SUCCESS)
goto phy_BB8190_Config_ParaFile_Fail;
/* 3. BB AGC table Initialization */
if (HAL_STATUS_FAILURE == ODM_ConfigBBWithHeaderFile(&pHalData->odmpriv, CONFIG_BB_AGC_TAB))
rtStatus = _FAIL;
if (rtStatus != _SUCCESS)
goto phy_BB8190_Config_ParaFile_Fail;
phy_BB8190_Config_ParaFile_Fail:
return rtStatus;
}
int
PHY_BBConfig8188E(
struct adapter *Adapter
)
{
int rtStatus = _SUCCESS;
struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
u32 RegVal;
u8 CrystalCap;
phy_InitBBRFRegisterDefinition(Adapter);
/* Enable BB and RF */
RegVal = rtw_read16(Adapter, REG_SYS_FUNC_EN);
rtw_write16(Adapter, REG_SYS_FUNC_EN, (u16)(RegVal|BIT13|BIT0|BIT1));
/* 20090923 Joseph: Advised by Steven and Jenyu. Power sequence before init RF. */
rtw_write8(Adapter, REG_RF_CTRL, RF_EN|RF_RSTB|RF_SDMRSTB);
rtw_write8(Adapter, REG_SYS_FUNC_EN, FEN_USBA | FEN_USBD | FEN_BB_GLB_RSTn | FEN_BBRSTB);
/* Config BB and AGC */
rtStatus = phy_BB8188E_Config_ParaFile(Adapter);
/* write 0x24[16:11] = 0x24[22:17] = CrystalCap */
CrystalCap = pHalData->CrystalCap & 0x3F;
PHY_SetBBReg(Adapter, REG_AFE_XTAL_CTRL, 0x7ff800, (CrystalCap | (CrystalCap << 6)));
return rtStatus;
}
int PHY_RFConfig8188E(struct adapter *Adapter)
{
int rtStatus = _SUCCESS;
/* RF config */
rtStatus = PHY_RF6052_Config8188E(Adapter);
return rtStatus;
}
/*-----------------------------------------------------------------------------
* Function: PHY_ConfigRFWithParaFile()
*
* Overview: This function read RF parameters from general file format, and do RF 3-wire
*
* Input: struct adapter *Adapter
* ps8 pFileName
* enum rf_radio_path eRFPath
*
* Output: NONE
*
* Return: RT_STATUS_SUCCESS: configuration file exist
*
* Note: Delay may be required for RF configuration
*---------------------------------------------------------------------------*/
int rtl8188e_PHY_ConfigRFWithParaFile(struct adapter *Adapter, u8 *pFileName, enum rf_radio_path eRFPath)
{
return _SUCCESS;
}
void
rtl8192c_PHY_GetHWRegOriginalValue(
struct adapter *Adapter
)
{
struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
/* read rx initial gain */
pHalData->DefaultInitialGain[0] = (u8)PHY_QueryBBReg(Adapter, rOFDM0_XAAGCCore1, bMaskByte0);
pHalData->DefaultInitialGain[1] = (u8)PHY_QueryBBReg(Adapter, rOFDM0_XBAGCCore1, bMaskByte0);
pHalData->DefaultInitialGain[2] = (u8)PHY_QueryBBReg(Adapter, rOFDM0_XCAGCCore1, bMaskByte0);
pHalData->DefaultInitialGain[3] = (u8)PHY_QueryBBReg(Adapter, rOFDM0_XDAGCCore1, bMaskByte0);
/* read framesync */
pHalData->framesync = (u8)PHY_QueryBBReg(Adapter, rOFDM0_RxDetector3, bMaskByte0);
pHalData->framesyncC34 = PHY_QueryBBReg(Adapter, rOFDM0_RxDetector2, bMaskDWord);
}
/* */
/* Description: */
/* Map dBm into Tx power index according to */
/* current HW model, for example, RF and PA, and */
/* current wireless mode. */
/* By Bruce, 2008-01-29. */
/* */
static u8 phy_DbmToTxPwrIdx(struct adapter *Adapter, enum wireless_mode WirelessMode, int PowerInDbm)
{
u8 TxPwrIdx = 0;
int Offset = 0;
/* */
/* Tested by MP, we found that CCK Index 0 equals to 8dbm, OFDM legacy equals to */
/* 3dbm, and OFDM HT equals to 0dbm repectively. */
/* Note: */
/* The mapping may be different by different NICs. Do not use this formula for what needs accurate result. */
/* By Bruce, 2008-01-29. */
/* */
switch (WirelessMode) {
case WIRELESS_MODE_B:
Offset = -7;
break;
case WIRELESS_MODE_G:
case WIRELESS_MODE_N_24G:
default:
Offset = -8;
break;
}
if ((PowerInDbm - Offset) > 0)
TxPwrIdx = (u8)((PowerInDbm - Offset) * 2);
else
TxPwrIdx = 0;
/* Tx Power Index is too large. */
if (TxPwrIdx > MAX_TXPWR_IDX_NMODE_92S)
TxPwrIdx = MAX_TXPWR_IDX_NMODE_92S;
return TxPwrIdx;
}
/* */
/* Description: */
/* Map Tx power index into dBm according to */
/* current HW model, for example, RF and PA, and */
/* current wireless mode. */
/* By Bruce, 2008-01-29. */
/* */
static int phy_TxPwrIdxToDbm(struct adapter *Adapter, enum wireless_mode WirelessMode, u8 TxPwrIdx)
{
int Offset = 0;
int PwrOutDbm = 0;
/* */
/* Tested by MP, we found that CCK Index 0 equals to -7dbm, OFDM legacy equals to -8dbm. */
/* Note: */
/* The mapping may be different by different NICs. Do not use this formula for what needs accurate result. */
/* By Bruce, 2008-01-29. */
/* */
switch (WirelessMode) {
case WIRELESS_MODE_B:
Offset = -7;
break;
case WIRELESS_MODE_G:
case WIRELESS_MODE_N_24G:
default:
Offset = -8;
break;
}
PwrOutDbm = TxPwrIdx / 2 + Offset; /* Discard the decimal part. */
return PwrOutDbm;
}
/*-----------------------------------------------------------------------------
* Function: GetTxPowerLevel8190()
*
* Overview: This function is export to "common" moudule
*
* Input: struct adapter *Adapter
* psByte Power Level
*
* Output: NONE
*
* Return: NONE
*
*---------------------------------------------------------------------------*/
void PHY_GetTxPowerLevel8188E(struct adapter *Adapter, u32 *powerlevel)
{
struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
u8 TxPwrLevel = 0;
int TxPwrDbm;
/* */
/* Because the Tx power indexes are different, we report the maximum of them to */
/* meet the CCX TPC request. By Bruce, 2008-01-31. */
/* */
/* CCK */
TxPwrLevel = pHalData->CurrentCckTxPwrIdx;
TxPwrDbm = phy_TxPwrIdxToDbm(Adapter, WIRELESS_MODE_B, TxPwrLevel);
/* Legacy OFDM */
TxPwrLevel = pHalData->CurrentOfdm24GTxPwrIdx + pHalData->LegacyHTTxPowerDiff;
/* Compare with Legacy OFDM Tx power. */
if (phy_TxPwrIdxToDbm(Adapter, WIRELESS_MODE_G, TxPwrLevel) > TxPwrDbm)
TxPwrDbm = phy_TxPwrIdxToDbm(Adapter, WIRELESS_MODE_G, TxPwrLevel);
/* HT OFDM */
TxPwrLevel = pHalData->CurrentOfdm24GTxPwrIdx;
/* Compare with HT OFDM Tx power. */
if (phy_TxPwrIdxToDbm(Adapter, WIRELESS_MODE_N_24G, TxPwrLevel) > TxPwrDbm)
TxPwrDbm = phy_TxPwrIdxToDbm(Adapter, WIRELESS_MODE_N_24G, TxPwrLevel);
*powerlevel = TxPwrDbm;
}
static void getTxPowerIndex88E(struct adapter *Adapter, u8 channel, u8 *cckPowerLevel,
u8 *ofdmPowerLevel, u8 *BW20PowerLevel,
u8 *BW40PowerLevel)
{
struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
u8 index = (channel - 1);
u8 TxCount = 0, path_nums;
if ((RF_1T2R == pHalData->rf_type) || (RF_1T1R == pHalData->rf_type))
path_nums = 1;
else
path_nums = 2;
for (TxCount = 0; TxCount < path_nums; TxCount++) {
if (TxCount == RF_PATH_A) {
/* 1. CCK */
cckPowerLevel[TxCount] = pHalData->Index24G_CCK_Base[TxCount][index];
/* 2. OFDM */
ofdmPowerLevel[TxCount] = pHalData->Index24G_BW40_Base[RF_PATH_A][index]+
pHalData->OFDM_24G_Diff[TxCount][RF_PATH_A];
/* 1. BW20 */
BW20PowerLevel[TxCount] = pHalData->Index24G_BW40_Base[RF_PATH_A][index]+
pHalData->BW20_24G_Diff[TxCount][RF_PATH_A];
/* 2. BW40 */
BW40PowerLevel[TxCount] = pHalData->Index24G_BW40_Base[TxCount][index];
} else if (TxCount == RF_PATH_B) {
/* 1. CCK */
cckPowerLevel[TxCount] = pHalData->Index24G_CCK_Base[TxCount][index];
/* 2. OFDM */
ofdmPowerLevel[TxCount] = pHalData->Index24G_BW40_Base[RF_PATH_A][index]+
pHalData->BW20_24G_Diff[RF_PATH_A][index]+
pHalData->BW20_24G_Diff[TxCount][index];
/* 1. BW20 */
BW20PowerLevel[TxCount] = pHalData->Index24G_BW40_Base[RF_PATH_A][index]+
pHalData->BW20_24G_Diff[TxCount][RF_PATH_A]+
pHalData->BW20_24G_Diff[TxCount][index];
/* 2. BW40 */
BW40PowerLevel[TxCount] = pHalData->Index24G_BW40_Base[TxCount][index];
} else if (TxCount == RF_PATH_C) {
/* 1. CCK */
cckPowerLevel[TxCount] = pHalData->Index24G_CCK_Base[TxCount][index];
/* 2. OFDM */
ofdmPowerLevel[TxCount] = pHalData->Index24G_BW40_Base[RF_PATH_A][index]+
pHalData->BW20_24G_Diff[RF_PATH_A][index]+
pHalData->BW20_24G_Diff[RF_PATH_B][index]+
pHalData->BW20_24G_Diff[TxCount][index];
/* 1. BW20 */
BW20PowerLevel[TxCount] = pHalData->Index24G_BW40_Base[RF_PATH_A][index]+
pHalData->BW20_24G_Diff[RF_PATH_A][index]+
pHalData->BW20_24G_Diff[RF_PATH_B][index]+
pHalData->BW20_24G_Diff[TxCount][index];
/* 2. BW40 */
BW40PowerLevel[TxCount] = pHalData->Index24G_BW40_Base[TxCount][index];
} else if (TxCount == RF_PATH_D) {
/* 1. CCK */
cckPowerLevel[TxCount] = pHalData->Index24G_CCK_Base[TxCount][index];
/* 2. OFDM */
ofdmPowerLevel[TxCount] = pHalData->Index24G_BW40_Base[RF_PATH_A][index]+
pHalData->BW20_24G_Diff[RF_PATH_A][index]+
pHalData->BW20_24G_Diff[RF_PATH_B][index]+
pHalData->BW20_24G_Diff[RF_PATH_C][index]+
pHalData->BW20_24G_Diff[TxCount][index];
/* 1. BW20 */
BW20PowerLevel[TxCount] = pHalData->Index24G_BW40_Base[RF_PATH_A][index]+
pHalData->BW20_24G_Diff[RF_PATH_A][index]+
pHalData->BW20_24G_Diff[RF_PATH_B][index]+
pHalData->BW20_24G_Diff[RF_PATH_C][index]+
pHalData->BW20_24G_Diff[TxCount][index];
/* 2. BW40 */
BW40PowerLevel[TxCount] = pHalData->Index24G_BW40_Base[TxCount][index];
}
}
}
static void phy_PowerIndexCheck88E(struct adapter *Adapter, u8 channel, u8 *cckPowerLevel,
u8 *ofdmPowerLevel, u8 *BW20PowerLevel, u8 *BW40PowerLevel)
{
struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
pHalData->CurrentCckTxPwrIdx = cckPowerLevel[0];
pHalData->CurrentOfdm24GTxPwrIdx = ofdmPowerLevel[0];
pHalData->CurrentBW2024GTxPwrIdx = BW20PowerLevel[0];
pHalData->CurrentBW4024GTxPwrIdx = BW40PowerLevel[0];
}
/*-----------------------------------------------------------------------------
* Function: SetTxPowerLevel8190()
*
* Overview: This function is export to "HalCommon" moudule
* We must consider RF path later!!!!!!!
*
* Input: struct adapter *Adapter
* u8 channel
*
* Output: NONE
*
* Return: NONE
* 2008/11/04 MHC We remove EEPROM_93C56.
* We need to move CCX relative code to independet file.
* 2009/01/21 MHC Support new EEPROM format from SD3 requirement.
*
*---------------------------------------------------------------------------*/
void
PHY_SetTxPowerLevel8188E(
struct adapter *Adapter,
u8 channel
)
{
u8 cckPowerLevel[MAX_TX_COUNT] = {0};
u8 ofdmPowerLevel[MAX_TX_COUNT] = {0};/* [0]:RF-A, [1]:RF-B */
u8 BW20PowerLevel[MAX_TX_COUNT] = {0};
u8 BW40PowerLevel[MAX_TX_COUNT] = {0};
getTxPowerIndex88E(Adapter, channel, &cckPowerLevel[0], &ofdmPowerLevel[0], &BW20PowerLevel[0], &BW40PowerLevel[0]);
phy_PowerIndexCheck88E(Adapter, channel, &cckPowerLevel[0], &ofdmPowerLevel[0], &BW20PowerLevel[0], &BW40PowerLevel[0]);
rtl8188e_PHY_RF6052SetCckTxPower(Adapter, &cckPowerLevel[0]);
rtl8188e_PHY_RF6052SetOFDMTxPower(Adapter, &ofdmPowerLevel[0], &BW20PowerLevel[0], &BW40PowerLevel[0], channel);
}
/* */
/* Description: */
/* Update transmit power level of all channel supported. */
/* */
/* TODO: */
/* A mode. */
/* By Bruce, 2008-02-04. */
/* */
bool
PHY_UpdateTxPowerDbm8188E(
struct adapter *Adapter,
int powerInDbm
)
{
struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
u8 idx;
u8 rf_path;
/* TODO: A mode Tx power. */
u8 CckTxPwrIdx = phy_DbmToTxPwrIdx(Adapter, WIRELESS_MODE_B, powerInDbm);
u8 OfdmTxPwrIdx = phy_DbmToTxPwrIdx(Adapter, WIRELESS_MODE_N_24G, powerInDbm);
if (OfdmTxPwrIdx - pHalData->LegacyHTTxPowerDiff > 0)
OfdmTxPwrIdx -= pHalData->LegacyHTTxPowerDiff;
else
OfdmTxPwrIdx = 0;
for (idx = 0; idx < 14; idx++) {
for (rf_path = 0; rf_path < 2; rf_path++) {
pHalData->TxPwrLevelCck[rf_path][idx] = CckTxPwrIdx;
pHalData->TxPwrLevelHT40_1S[rf_path][idx] =
pHalData->TxPwrLevelHT40_2S[rf_path][idx] = OfdmTxPwrIdx;
}
}
return true;
}
void
PHY_ScanOperationBackup8188E(
struct adapter *Adapter,
u8 Operation
)
{
}
/*-----------------------------------------------------------------------------
* Function: PHY_SetBWModeCallback8192C()
*
* Overview: Timer callback function for SetSetBWMode
*
* Input: PRT_TIMER pTimer
*
* Output: NONE
*
* Return: NONE
*
* Note: (1) We do not take j mode into consideration now
* (2) Will two workitem of "switch channel" and "switch channel bandwidth" run
* concurrently?
*---------------------------------------------------------------------------*/
static void
_PHY_SetBWMode92C(
struct adapter *Adapter
)
{
struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
u8 regBwOpMode;
u8 regRRSR_RSC;
if (pHalData->rf_chip == RF_PSEUDO_11N)
return;
/* There is no 40MHz mode in RF_8225. */
if (pHalData->rf_chip == RF_8225)
return;
if (Adapter->bDriverStopped)
return;
/* 3 */
/* 3<1>Set MAC register */
/* 3 */
regBwOpMode = rtw_read8(Adapter, REG_BWOPMODE);
regRRSR_RSC = rtw_read8(Adapter, REG_RRSR+2);
switch (pHalData->CurrentChannelBW) {
case HT_CHANNEL_WIDTH_20:
regBwOpMode |= BW_OPMODE_20MHZ;
/* 2007/02/07 Mark by Emily becasue we have not verify whether this register works */
rtw_write8(Adapter, REG_BWOPMODE, regBwOpMode);
break;
case HT_CHANNEL_WIDTH_40:
regBwOpMode &= ~BW_OPMODE_20MHZ;
/* 2007/02/07 Mark by Emily becasue we have not verify whether this register works */
rtw_write8(Adapter, REG_BWOPMODE, regBwOpMode);
regRRSR_RSC = (regRRSR_RSC&0x90) | (pHalData->nCur40MhzPrimeSC<<5);
rtw_write8(Adapter, REG_RRSR+2, regRRSR_RSC);
break;
default:
break;
}
/* 3 */
/* 3 <2>Set PHY related register */
/* 3 */
switch (pHalData->CurrentChannelBW) {
/* 20 MHz channel*/
case HT_CHANNEL_WIDTH_20:
PHY_SetBBReg(Adapter, rFPGA0_RFMOD, bRFMOD, 0x0);
PHY_SetBBReg(Adapter, rFPGA1_RFMOD, bRFMOD, 0x0);
break;
/* 40 MHz channel*/
case HT_CHANNEL_WIDTH_40:
PHY_SetBBReg(Adapter, rFPGA0_RFMOD, bRFMOD, 0x1);
PHY_SetBBReg(Adapter, rFPGA1_RFMOD, bRFMOD, 0x1);
/* Set Control channel to upper or lower. These settings are required only for 40MHz */
PHY_SetBBReg(Adapter, rCCK0_System, bCCKSideBand, (pHalData->nCur40MhzPrimeSC>>1));
PHY_SetBBReg(Adapter, rOFDM1_LSTF, 0xC00, pHalData->nCur40MhzPrimeSC);
PHY_SetBBReg(Adapter, 0x818, (BIT26 | BIT27),
(pHalData->nCur40MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_LOWER) ? 2 : 1);
break;
default:
break;
}
/* Skip over setting of J-mode in BB register here. Default value is "None J mode". Emily 20070315 */
/* 3<3>Set RF related register */
switch (pHalData->rf_chip) {
case RF_8225:
break;
case RF_8256:
/* Please implement this function in Hal8190PciPhy8256.c */
break;
case RF_8258:
/* Please implement this function in Hal8190PciPhy8258.c */
break;
case RF_PSEUDO_11N:
break;
case RF_6052:
rtl8188e_PHY_RF6052SetBandwidth(Adapter, pHalData->CurrentChannelBW);
break;
default:
break;
}
}
/*-----------------------------------------------------------------------------
* Function: SetBWMode8190Pci()
*
* Overview: This function is export to "HalCommon" moudule
*
* Input: struct adapter *Adapter
* enum ht_channel_width Bandwidth 20M or 40M
*
* Output: NONE
*
* Return: NONE
*
* Note: We do not take j mode into consideration now
*---------------------------------------------------------------------------*/
void PHY_SetBWMode8188E(struct adapter *Adapter, enum ht_channel_width Bandwidth, /* 20M or 40M */
unsigned char Offset) /* Upper, Lower, or Don't care */
{
struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
enum ht_channel_width tmpBW = pHalData->CurrentChannelBW;
pHalData->CurrentChannelBW = Bandwidth;
pHalData->nCur40MhzPrimeSC = Offset;
if ((!Adapter->bDriverStopped) && (!Adapter->bSurpriseRemoved))
_PHY_SetBWMode92C(Adapter);
else
pHalData->CurrentChannelBW = tmpBW;
}
static void _PHY_SwChnl8192C(struct adapter *Adapter, u8 channel)
{
u8 eRFPath;
u32 param1, param2;
struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
if (Adapter->bNotifyChannelChange)
DBG_88E("[%s] ch = %d\n", __func__, channel);
/* s1. pre common command - CmdID_SetTxPowerLevel */
PHY_SetTxPowerLevel8188E(Adapter, channel);
/* s2. RF dependent command - CmdID_RF_WriteReg, param1=RF_CHNLBW, param2=channel */
param1 = RF_CHNLBW;
param2 = channel;
for (eRFPath = 0; eRFPath < pHalData->NumTotalRFPath; eRFPath++) {
pHalData->RfRegChnlVal[eRFPath] = ((pHalData->RfRegChnlVal[eRFPath] & 0xfffffc00) | param2);
PHY_SetRFReg(Adapter, (enum rf_radio_path)eRFPath, param1, bRFRegOffsetMask, pHalData->RfRegChnlVal[eRFPath]);
}
}
void PHY_SwChnl8188E(struct adapter *Adapter, u8 channel)
{
/* Call after initialization */
struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
u8 tmpchannel = pHalData->CurrentChannel;
bool bResult = true;
if (pHalData->rf_chip == RF_PSEUDO_11N)
return; /* return immediately if it is peudo-phy */
if (channel == 0)
channel = 1;
pHalData->CurrentChannel = channel;
if ((!Adapter->bDriverStopped) && (!Adapter->bSurpriseRemoved)) {
_PHY_SwChnl8192C(Adapter, channel);
if (bResult)
;
else
pHalData->CurrentChannel = tmpchannel;
} else {
pHalData->CurrentChannel = tmpchannel;
}
}
/******************************************************************************
*
* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
*
* 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.
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*
*
******************************************************************************/
/******************************************************************************
*
*
* Module: rtl8192c_rf6052.c ( Source C File)
*
* Note: Provide RF 6052 series relative API.
*
* Function:
*
* Export:
*
* Abbrev:
*
* History:
* Data Who Remark
*
* 09/25/2008 MHC Create initial version.
* 11/05/2008 MHC Add API for tw power setting.
*
*
******************************************************************************/
#define _RTL8188E_RF6052_C_
#include <osdep_service.h>
#include <drv_types.h>
#include <rtl8188e_hal.h>
/*---------------------------Define Local Constant---------------------------*/
/* Define local structure for debug!!!!! */
struct rf_shadow {
/* Shadow register value */
u32 Value;
/* Compare or not flag */
u8 Compare;
/* Record If it had ever modified unpredicted */
u8 ErrorOrNot;
/* Recorver Flag */
u8 Recorver;
/* */
u8 Driver_Write;
};
/*---------------------------Define Local Constant---------------------------*/
/*------------------------Define global variable-----------------------------*/
/*------------------------Define local variable------------------------------*/
/*-----------------------------------------------------------------------------
* Function: RF_ChangeTxPath
*
* Overview: For RL6052, we must change some RF settign for 1T or 2T.
*
* Input: u16 DataRate 0x80-8f, 0x90-9f
*
* Output: NONE
*
* Return: NONE
*
* Revised History:
* When Who Remark
* 09/25/2008 MHC Create Version 0.
* Firmwaer support the utility later.
*
*---------------------------------------------------------------------------*/
void rtl8188e_RF_ChangeTxPath(struct adapter *Adapter, u16 DataRate)
{
/* We do not support gain table change inACUT now !!!! Delete later !!! */
} /* RF_ChangeTxPath */
/*-----------------------------------------------------------------------------
* Function: PHY_RF6052SetBandwidth()
*
* Overview: This function is called by SetBWModeCallback8190Pci() only
*
* Input: struct adapter *Adapter
* WIRELESS_BANDWIDTH_E Bandwidth 20M or 40M
*
* Output: NONE
*
* Return: NONE
*
* Note: For RF type 0222D
*---------------------------------------------------------------------------*/
void rtl8188e_PHY_RF6052SetBandwidth(struct adapter *Adapter,
enum ht_channel_width Bandwidth)
{
struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
switch (Bandwidth) {
case HT_CHANNEL_WIDTH_20:
pHalData->RfRegChnlVal[0] = ((pHalData->RfRegChnlVal[0] & 0xfffff3ff) | BIT(10) | BIT(11));
PHY_SetRFReg(Adapter, RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask, pHalData->RfRegChnlVal[0]);
break;
case HT_CHANNEL_WIDTH_40:
pHalData->RfRegChnlVal[0] = ((pHalData->RfRegChnlVal[0] & 0xfffff3ff) | BIT(10));
PHY_SetRFReg(Adapter, RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask, pHalData->RfRegChnlVal[0]);
break;
default:
break;
}
}
/*-----------------------------------------------------------------------------
* Function: PHY_RF6052SetCckTxPower
*
* Overview:
*
* Input: NONE
*
* Output: NONE
*
* Return: NONE
*
* Revised History:
* When Who Remark
* 11/05/2008 MHC Simulate 8192series..
*
*---------------------------------------------------------------------------*/
void
rtl8188e_PHY_RF6052SetCckTxPower(
struct adapter *Adapter,
u8 *pPowerlevel)
{
struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
struct dm_priv *pdmpriv = &pHalData->dmpriv;
struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv;
u32 TxAGC[2] = {0, 0}, tmpval = 0, pwrtrac_value;
bool TurboScanOff = false;
u8 idx1, idx2;
u8 *ptr;
u8 direction;
/* FOR CE ,must disable turbo scan */
TurboScanOff = true;
if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) {
TxAGC[RF_PATH_A] = 0x3f3f3f3f;
TxAGC[RF_PATH_B] = 0x3f3f3f3f;
TurboScanOff = true;/* disable turbo scan */
if (TurboScanOff) {
for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) {
TxAGC[idx1] =
pPowerlevel[idx1] | (pPowerlevel[idx1]<<8) |
(pPowerlevel[idx1]<<16) | (pPowerlevel[idx1]<<24);
/* 2010/10/18 MH For external PA module. We need to limit power index to be less than 0x20. */
if (TxAGC[idx1] > 0x20 && pHalData->ExternalPA)
TxAGC[idx1] = 0x20;
}
}
} else {
/* Driver dynamic Tx power shall not affect Tx power.
* It shall be determined by power training mechanism.
i * Currently, we cannot fully disable driver dynamic
* tx power mechanism because it is referenced by BT
* coexist mechanism.
* In the future, two mechanism shall be separated from
* each other and maintained independantly. */
if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level1) {
TxAGC[RF_PATH_A] = 0x10101010;
TxAGC[RF_PATH_B] = 0x10101010;
} else if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level2) {
TxAGC[RF_PATH_A] = 0x00000000;
TxAGC[RF_PATH_B] = 0x00000000;
} else {
for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) {
TxAGC[idx1] =
pPowerlevel[idx1] | (pPowerlevel[idx1]<<8) |
(pPowerlevel[idx1]<<16) | (pPowerlevel[idx1]<<24);
}
if (pHalData->EEPROMRegulatory == 0) {
tmpval = (pHalData->MCSTxPowerLevelOriginalOffset[0][6]) +
(pHalData->MCSTxPowerLevelOriginalOffset[0][7]<<8);
TxAGC[RF_PATH_A] += tmpval;
tmpval = (pHalData->MCSTxPowerLevelOriginalOffset[0][14]) +
(pHalData->MCSTxPowerLevelOriginalOffset[0][15]<<24);
TxAGC[RF_PATH_B] += tmpval;
}
}
}
for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) {
ptr = (u8 *)(&(TxAGC[idx1]));
for (idx2 = 0; idx2 < 4; idx2++) {
if (*ptr > RF6052_MAX_TX_PWR)
*ptr = RF6052_MAX_TX_PWR;
ptr++;
}
}
ODM_TxPwrTrackAdjust88E(&pHalData->odmpriv, 1, &direction, &pwrtrac_value);
if (direction == 1) {
/* Increase TX pwoer */
TxAGC[0] += pwrtrac_value;
TxAGC[1] += pwrtrac_value;
} else if (direction == 2) {
/* Decrease TX pwoer */
TxAGC[0] -= pwrtrac_value;
TxAGC[1] -= pwrtrac_value;
}
/* rf-A cck tx power */
tmpval = TxAGC[RF_PATH_A]&0xff;
PHY_SetBBReg(Adapter, rTxAGC_A_CCK1_Mcs32, bMaskByte1, tmpval);
tmpval = TxAGC[RF_PATH_A]>>8;
PHY_SetBBReg(Adapter, rTxAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval);
/* rf-B cck tx power */
tmpval = TxAGC[RF_PATH_B]>>24;
PHY_SetBBReg(Adapter, rTxAGC_B_CCK11_A_CCK2_11, bMaskByte0, tmpval);
tmpval = TxAGC[RF_PATH_B]&0x00ffffff;
PHY_SetBBReg(Adapter, rTxAGC_B_CCK1_55_Mcs32, 0xffffff00, tmpval);
} /* PHY_RF6052SetCckTxPower */
/* */
/* powerbase0 for OFDM rates */
/* powerbase1 for HT MCS rates */
/* */
static void getpowerbase88e(struct adapter *Adapter, u8 *pPowerLevelOFDM,
u8 *pPowerLevelBW20, u8 *pPowerLevelBW40, u8 Channel, u32 *OfdmBase, u32 *MCSBase)
{
struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
u32 powerBase0, powerBase1;
u8 i, powerlevel[2];
for (i = 0; i < 2; i++) {
powerBase0 = pPowerLevelOFDM[i];
powerBase0 = (powerBase0<<24) | (powerBase0<<16) | (powerBase0<<8) | powerBase0;
*(OfdmBase+i) = powerBase0;
}
for (i = 0; i < pHalData->NumTotalRFPath; i++) {
/* Check HT20 to HT40 diff */
if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_20)
powerlevel[i] = pPowerLevelBW20[i];
else
powerlevel[i] = pPowerLevelBW40[i];
powerBase1 = powerlevel[i];
powerBase1 = (powerBase1<<24) | (powerBase1<<16) | (powerBase1<<8) | powerBase1;
*(MCSBase+i) = powerBase1;
}
}
static void get_rx_power_val_by_reg(struct adapter *Adapter, u8 Channel,
u8 index, u32 *powerBase0, u32 *powerBase1,
u32 *pOutWriteVal)
{
struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
struct dm_priv *pdmpriv = &pHalData->dmpriv;
u8 i, chnlGroup = 0, pwr_diff_limit[4], customer_pwr_limit;
s8 pwr_diff = 0;
u32 writeVal, customer_limit, rf;
u8 Regulatory = pHalData->EEPROMRegulatory;
/* Index 0 & 1= legacy OFDM, 2-5=HT_MCS rate */
for (rf = 0; rf < 2; rf++) {
switch (Regulatory) {
case 0: /* Realtek better performance */
/* increase power diff defined by Realtek for large power */
chnlGroup = 0;
writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf ? 8 : 0)] +
((index < 2) ? powerBase0[rf] : powerBase1[rf]);
break;
case 1: /* Realtek regulatory */
/* increase power diff defined by Realtek for regulatory */
if (pHalData->pwrGroupCnt == 1)
chnlGroup = 0;
if (pHalData->pwrGroupCnt >= pHalData->PGMaxGroup) {
if (Channel < 3) /* Chanel 1-2 */
chnlGroup = 0;
else if (Channel < 6) /* Channel 3-5 */
chnlGroup = 1;
else if (Channel < 9) /* Channel 6-8 */
chnlGroup = 2;
else if (Channel < 12) /* Channel 9-11 */
chnlGroup = 3;
else if (Channel < 14) /* Channel 12-13 */
chnlGroup = 4;
else if (Channel == 14) /* Channel 14 */
chnlGroup = 5;
}
writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf ? 8 : 0)] +
((index < 2) ? powerBase0[rf] : powerBase1[rf]);
break;
case 2: /* Better regulatory */
/* don't increase any power diff */
writeVal = ((index < 2) ? powerBase0[rf] : powerBase1[rf]);
break;
case 3: /* Customer defined power diff. */
/* increase power diff defined by customer. */
chnlGroup = 0;
if (index < 2)
pwr_diff = pHalData->TxPwrLegacyHtDiff[rf][Channel-1];
else if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_20)
pwr_diff = pHalData->TxPwrHt20Diff[rf][Channel-1];
if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_40)
customer_pwr_limit = pHalData->PwrGroupHT40[rf][Channel-1];
else
customer_pwr_limit = pHalData->PwrGroupHT20[rf][Channel-1];
if (pwr_diff >= customer_pwr_limit)
pwr_diff = 0;
else
pwr_diff = customer_pwr_limit - pwr_diff;
for (i = 0; i < 4; i++) {
pwr_diff_limit[i] = (u8)((pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf ? 8 : 0)]&(0x7f<<(i*8)))>>(i*8));
if (pwr_diff_limit[i] > pwr_diff)
pwr_diff_limit[i] = pwr_diff;
}
customer_limit = (pwr_diff_limit[3]<<24) | (pwr_diff_limit[2]<<16) |
(pwr_diff_limit[1]<<8) | (pwr_diff_limit[0]);
writeVal = customer_limit + ((index < 2) ? powerBase0[rf] : powerBase1[rf]);
break;
default:
chnlGroup = 0;
writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf ? 8 : 0)] +
((index < 2) ? powerBase0[rf] : powerBase1[rf]);
break;
}
/* 20100427 Joseph: Driver dynamic Tx power shall not affect Tx power. It shall be determined by power training mechanism. */
/* Currently, we cannot fully disable driver dynamic tx power mechanism because it is referenced by BT coexist mechanism. */
/* In the future, two mechanism shall be separated from each other and maintained independantly. Thanks for Lanhsin's reminder. */
/* 92d do not need this */
if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level1)
writeVal = 0x14141414;
else if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level2)
writeVal = 0x00000000;
/* 20100628 Joseph: High power mode for BT-Coexist mechanism. */
/* This mechanism is only applied when Driver-Highpower-Mechanism is OFF. */
if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_BT1)
writeVal = writeVal - 0x06060606;
else if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_BT2)
writeVal = writeVal;
*(pOutWriteVal+rf) = writeVal;
}
}
static void writeOFDMPowerReg88E(struct adapter *Adapter, u8 index, u32 *pValue)
{
struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
u16 regoffset_a[6] = {
rTxAGC_A_Rate18_06, rTxAGC_A_Rate54_24,
rTxAGC_A_Mcs03_Mcs00, rTxAGC_A_Mcs07_Mcs04,
rTxAGC_A_Mcs11_Mcs08, rTxAGC_A_Mcs15_Mcs12};
u16 regoffset_b[6] = {
rTxAGC_B_Rate18_06, rTxAGC_B_Rate54_24,
rTxAGC_B_Mcs03_Mcs00, rTxAGC_B_Mcs07_Mcs04,
rTxAGC_B_Mcs11_Mcs08, rTxAGC_B_Mcs15_Mcs12};
u8 i, rf, pwr_val[4];
u32 writeVal;
u16 regoffset;
for (rf = 0; rf < 2; rf++) {
writeVal = pValue[rf];
for (i = 0; i < 4; i++) {
pwr_val[i] = (u8)((writeVal & (0x7f<<(i*8)))>>(i*8));
if (pwr_val[i] > RF6052_MAX_TX_PWR)
pwr_val[i] = RF6052_MAX_TX_PWR;
}
writeVal = (pwr_val[3]<<24) | (pwr_val[2]<<16) | (pwr_val[1]<<8) | pwr_val[0];
if (rf == 0)
regoffset = regoffset_a[index];
else
regoffset = regoffset_b[index];
PHY_SetBBReg(Adapter, regoffset, bMaskDWord, writeVal);
/* 201005115 Joseph: Set Tx Power diff for Tx power training mechanism. */
if (((pHalData->rf_type == RF_2T2R) &&
(regoffset == rTxAGC_A_Mcs15_Mcs12 || regoffset == rTxAGC_B_Mcs15_Mcs12)) ||
((pHalData->rf_type != RF_2T2R) &&
(regoffset == rTxAGC_A_Mcs07_Mcs04 || regoffset == rTxAGC_B_Mcs07_Mcs04))) {
writeVal = pwr_val[3];
if (regoffset == rTxAGC_A_Mcs15_Mcs12 || regoffset == rTxAGC_A_Mcs07_Mcs04)
regoffset = 0xc90;
if (regoffset == rTxAGC_B_Mcs15_Mcs12 || regoffset == rTxAGC_B_Mcs07_Mcs04)
regoffset = 0xc98;
for (i = 0; i < 3; i++) {
if (i != 2)
writeVal = (writeVal > 8) ? (writeVal-8) : 0;
else
writeVal = (writeVal > 6) ? (writeVal-6) : 0;
rtw_write8(Adapter, (u32)(regoffset+i), (u8)writeVal);
}
}
}
}
/*-----------------------------------------------------------------------------
* Function: PHY_RF6052SetOFDMTxPower
*
* Overview: For legacy and HY OFDM, we must read EEPROM TX power index for
* different channel and read original value in TX power register area from
* 0xe00. We increase offset and original value to be correct tx pwr.
*
* Input: NONE
*
* Output: NONE
*
* Return: NONE
*
* Revised History:
* When Who Remark
* 11/05/2008 MHC Simulate 8192 series method.
* 01/06/2009 MHC 1. Prevent Path B tx power overflow or underflow dure to
* A/B pwr difference or legacy/HT pwr diff.
* 2. We concern with path B legacy/HT OFDM difference.
* 01/22/2009 MHC Support new EPRO format from SD3.
*
*---------------------------------------------------------------------------*/
void
rtl8188e_PHY_RF6052SetOFDMTxPower(
struct adapter *Adapter,
u8 *pPowerLevelOFDM,
u8 *pPowerLevelBW20,
u8 *pPowerLevelBW40,
u8 Channel)
{
struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
u32 writeVal[2], powerBase0[2], powerBase1[2], pwrtrac_value;
u8 direction;
u8 index = 0;
getpowerbase88e(Adapter, pPowerLevelOFDM, pPowerLevelBW20, pPowerLevelBW40, Channel, &powerBase0[0], &powerBase1[0]);
/* 2012/04/23 MH According to power tracking value, we need to revise OFDM tx power. */
/* This is ued to fix unstable power tracking mode. */
ODM_TxPwrTrackAdjust88E(&pHalData->odmpriv, 0, &direction, &pwrtrac_value);
for (index = 0; index < 6; index++) {
get_rx_power_val_by_reg(Adapter, Channel, index,
&powerBase0[0], &powerBase1[0],
&writeVal[0]);
if (direction == 1) {
writeVal[0] += pwrtrac_value;
writeVal[1] += pwrtrac_value;
} else if (direction == 2) {
writeVal[0] -= pwrtrac_value;
writeVal[1] -= pwrtrac_value;
}
writeOFDMPowerReg88E(Adapter, index, &writeVal[0]);
}
}
static int phy_RF6052_Config_ParaFile(struct adapter *Adapter)
{
struct bb_reg_def *pPhyReg;
struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
u32 u4RegValue = 0;
u8 eRFPath;
int rtStatus = _SUCCESS;
/* 3----------------------------------------------------------------- */
/* 3 <2> Initialize RF */
/* 3----------------------------------------------------------------- */
for (eRFPath = 0; eRFPath < pHalData->NumTotalRFPath; eRFPath++) {
pPhyReg = &pHalData->PHYRegDef[eRFPath];
/*----Store original RFENV control type----*/
switch (eRFPath) {
case RF_PATH_A:
case RF_PATH_C:
u4RegValue = PHY_QueryBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV);
break;
case RF_PATH_B:
case RF_PATH_D:
u4RegValue = PHY_QueryBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV<<16);
break;
}
/*----Set RF_ENV enable----*/
PHY_SetBBReg(Adapter, pPhyReg->rfintfe, bRFSI_RFENV<<16, 0x1);
rtw_udelay_os(1);/* PlatformStallExecution(1); */
/*----Set RF_ENV output high----*/
PHY_SetBBReg(Adapter, pPhyReg->rfintfo, bRFSI_RFENV, 0x1);
rtw_udelay_os(1);/* PlatformStallExecution(1); */
/* Set bit number of Address and Data for RF register */
PHY_SetBBReg(Adapter, pPhyReg->rfHSSIPara2, b3WireAddressLength, 0x0); /* Set 1 to 4 bits for 8255 */
rtw_udelay_os(1);/* PlatformStallExecution(1); */
PHY_SetBBReg(Adapter, pPhyReg->rfHSSIPara2, b3WireDataLength, 0x0); /* Set 0 to 12 bits for 8255 */
rtw_udelay_os(1);/* PlatformStallExecution(1); */
/*----Initialize RF fom connfiguration file----*/
switch (eRFPath) {
case RF_PATH_A:
if (HAL_STATUS_FAILURE == ODM_ConfigRFWithHeaderFile(&pHalData->odmpriv, (enum ODM_RF_RADIO_PATH)eRFPath, (enum ODM_RF_RADIO_PATH)eRFPath))
rtStatus = _FAIL;
break;
case RF_PATH_B:
if (HAL_STATUS_FAILURE == ODM_ConfigRFWithHeaderFile(&pHalData->odmpriv, (enum ODM_RF_RADIO_PATH)eRFPath, (enum ODM_RF_RADIO_PATH)eRFPath))
rtStatus = _FAIL;
break;
case RF_PATH_C:
break;
case RF_PATH_D:
break;
}
/*----Restore RFENV control type----*/;
switch (eRFPath) {
case RF_PATH_A:
case RF_PATH_C:
PHY_SetBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV, u4RegValue);
break;
case RF_PATH_B:
case RF_PATH_D:
PHY_SetBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV<<16, u4RegValue);
break;
}
if (rtStatus != _SUCCESS)
goto phy_RF6052_Config_ParaFile_Fail;
}
return rtStatus;
phy_RF6052_Config_ParaFile_Fail:
return rtStatus;
}
int PHY_RF6052_Config8188E(struct adapter *Adapter)
{
struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
int rtStatus = _SUCCESS;
/* */
/* Initialize general global value */
/* */
/* TODO: Extend RF_PATH_C and RF_PATH_D in the future */
if (pHalData->rf_type == RF_1T1R)
pHalData->NumTotalRFPath = 1;
else
pHalData->NumTotalRFPath = 2;
/* */
/* Config BB and RF */
/* */
rtStatus = phy_RF6052_Config_ParaFile(Adapter);
return rtStatus;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment