M7350/wlan/8192es/DriverSrcPkg/Driver/rtl8192cd_92es/8192cd_eeprom.c
2024-09-09 08:59:52 +00:00

580 lines
16 KiB
C
Executable File

/*
* Routines to read and write eeprom
*
* $Id: 8192cd_eeprom.c,v 1.1 2009/11/06 12:26:48 victoryman Exp $
*
* Copyright (c) 2009 Realtek Semiconductor Corp.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#define _8192CD_EEPROM_C_
#if 0
#ifdef __KERNEL__
#include <linux/config.h>
#include <linux/module.h>
#endif
#include "./8192cd_cfg.h"
#include "./8192cd.h"
#include "./8192cd_hw.h"
#include "./8192cd_util.h"
#include "./8192cd_debug.h"
#define VOID void
#define EEPROM_MAX_SIZE 256
#define CSR_EEPROM_CONTROL_REG _9346CR_
#define CLOCK_RATE 50 //100us
static VOID ShiftOutBits(struct rtl8192cd_priv *priv, USHORT data, USHORT count);
static USHORT ShiftInBits(struct rtl8192cd_priv *priv);
static VOID RaiseClock(struct rtl8192cd_priv *priv, USHORT *x);
static VOID LowerClock(struct rtl8192cd_priv *priv, USHORT *x);
static VOID EEpromCleanup(struct rtl8192cd_priv *priv);
static USHORT WaitEEPROMCmdDone(struct rtl8192cd_priv *priv);
static VOID StandBy(struct rtl8192cd_priv *priv);
//*****************************************************************************
//
// I/O based Read EEPROM Routines
//
//*****************************************************************************
//-----------------------------------------------------------------------------
// Procedure: ReadEEprom
//
// Description: This routine serially reads one word out of the EEPROM.
//
// Arguments:
// Reg - EEPROM word to read.
//
// Returns:
// Contents of EEPROM word (Reg).
//-----------------------------------------------------------------------------
static USHORT
ReadEEprom(
struct rtl8192cd_priv *priv,
UCHAR AddressSize,
USHORT Reg)
{
USHORT x;
USHORT data;
// select EEPROM, reset bits, set EECS
x = RTL_R8(CSR_EEPROM_CONTROL_REG);
x &= ~(EEDI | EEDO | EESK | CR9346_EEM0);
x |= CR9346_EEM1 | EECS;
RTL_W8(CSR_EEPROM_CONTROL_REG, (UCHAR)x);
// write the read opcode and register number in that order
// The opcode is 3bits in length, reg is 6 bits long
ShiftOutBits(priv, EEPROM_READ_OPCODE, 3);
ShiftOutBits(priv, Reg, AddressSize);
// Now read the data (16 bits) in from the selected EEPROM word
data = ShiftInBits(priv);
EEpromCleanup(priv);
return data;
}
//-----------------------------------------------------------------------------
// Procedure: ShiftOutBits
//
// Description: This routine shifts data bits out to the EEPROM.
//
// Arguments:
// data - data to send to the EEPROM.
// count - number of data bits to shift out.
//
// Returns: (none)
//-----------------------------------------------------------------------------
static VOID
ShiftOutBits(
struct rtl8192cd_priv *priv,
USHORT data,
USHORT count)
{
USHORT x,mask;
mask = 0x01 << (count - 1);
x = RTL_R8(CSR_EEPROM_CONTROL_REG);
x &= ~(EEDO | EEDI);
do
{
x &= ~EEDI;
if(data & mask)
x |= EEDI;
RTL_W8(CSR_EEPROM_CONTROL_REG, (UCHAR)x);
delay_us(CLOCK_RATE);
RaiseClock(priv, &x);
LowerClock(priv, &x);
mask = mask >> 1;
} while(mask);
x &= ~EEDI;
RTL_W8(CSR_EEPROM_CONTROL_REG, (UCHAR)x);
}
//-----------------------------------------------------------------------------
// Procedure: ShiftInBits
//
// Description: This routine shifts data bits in from the EEPROM.
//
// Arguments:
//
// Returns:
// The contents of that particular EEPROM word
//-----------------------------------------------------------------------------
static USHORT
ShiftInBits(
struct rtl8192cd_priv *priv)
{
USHORT x,d,i;
x = RTL_R8(CSR_EEPROM_CONTROL_REG);
x &= ~( EEDO | EEDI);
d = 0;
for(i=0; i<16; i++)
{
d = d << 1;
RaiseClock(priv, &x);
x = RTL_R8(CSR_EEPROM_CONTROL_REG);
x &= ~(EEDI);
if(x & EEDO)
d |= 1;
LowerClock(priv, &x);
}
return d;
}
//-----------------------------------------------------------------------------
// Procedure: RaiseClock
//
// Description: This routine raises the EEPOM's clock input (EESK)
//
// Arguments:
// x - Ptr to the EEPROM control register's current value
//
// Returns: (none)
//-----------------------------------------------------------------------------
static VOID
RaiseClock(
struct rtl8192cd_priv *priv,
USHORT *x)
{
*x = *x | EESK;
RTL_W8(CSR_EEPROM_CONTROL_REG, (UCHAR)(*x));
delay_us(CLOCK_RATE);
}
//-----------------------------------------------------------------------------
// Procedure: LowerClock
//
// Description: This routine lower's the EEPOM's clock input (EESK)
//
// Arguments:
// x - Ptr to the EEPROM control register's current value
//
// Returns: (none)
//-----------------------------------------------------------------------------
static VOID
LowerClock(
struct rtl8192cd_priv *priv,
USHORT *x)
{
*x = *x & ~EESK;
RTL_W8(CSR_EEPROM_CONTROL_REG, (UCHAR)(*x));
delay_us(CLOCK_RATE);
}
//-----------------------------------------------------------------------------
// Procedure: EEpromCleanup
//
// Description: This routine returns the EEPROM to an idle state
//
// Arguments:
//
// Returns: (none)
//-----------------------------------------------------------------------------
static VOID
EEpromCleanup(
struct rtl8192cd_priv *priv)
{
USHORT x;
x = RTL_R8(CSR_EEPROM_CONTROL_REG);
x &= ~(EECS | EEDI);
RTL_W8(CSR_EEPROM_CONTROL_REG, (UCHAR)x);
RaiseClock(priv, &x);
LowerClock(priv, &x);
}
//*****************************************************************************
//
// EEPROM Write Routines
//
//*****************************************************************************
//-----------------------------------------------------------------------------
// Procedure: D100UpdateChecksum
//
// Description: Calculates the checksum and writes it to the EEProm. This
// routine assumes that the checksum word is the last word in
// a 64 word EEPROM. It calculates the checksum accroding to
// the formula: Checksum = 0xBABA - (sum of first 63 words).
//
// Arguments:
// Adapter - Ptr to this card's adapter data structure
//
// Returns: (none)
//-----------------------------------------------------------------------------
/*static VOID
UpdateChecksum(
struct rtl8192cd_priv *priv)
{
USHORT Checksum=0;
// USHORT Iter;
// for (Iter = 0; Iter < 0x3F; Iter++)
// Checksum += ReadEEprom( CSRBaseIoAddress, Iter );
Checksum = (USHORT)0xBABA - Checksum;
// WriteEEprom( CSRBaseIoAddress, 0x3F, Checksum );
}*/
//-----------------------------------------------------------------------------
// Procedure: WriteEEprom
//
// Description: This routine writes a word to a specific EEPROM location.
//
// Arguments:
// Adapter - Ptr to this card's adapter data structure.
// reg - The EEPROM word that we are going to write to.
// data - The data (word) that we are going to write to the EEPROM.
//
// Returns: (none)
//-----------------------------------------------------------------------------
static VOID
WriteEEprom(
struct rtl8192cd_priv *priv,
UCHAR AddressSize,
USHORT reg,
USHORT data)
{
UCHAR x;
// select EEPROM, mask off ASIC and reset bits, set EECS
x = RTL_R8(CSR_EEPROM_CONTROL_REG);
x &= ~(EEDI | EEDO | EESK | CR9346_EEM0);
x |= CR9346_EEM1 | EECS;
RTL_W8(CSR_EEPROM_CONTROL_REG, x);
ShiftOutBits(priv, EEPROM_EWEN_OPCODE, 5);
/////ShiftOutBits(CSRBaseIoAddress, reg, 4);
ShiftOutBits(priv, 0, 6);
StandBy(priv);
// Erase this particular word. Write the erase opcode and register
// number in that order. The opcode is 3bits in length; reg is 6 bits long.
ShiftOutBits(priv, EEPROM_ERASE_OPCODE, 3);
ShiftOutBits(priv, reg, AddressSize);
if (WaitEEPROMCmdDone(priv) == FALSE)
{
return;
}
StandBy(priv);
// write the new word to the EEPROM
// send the write opcode the EEPORM
ShiftOutBits(priv, EEPROM_WRITE_OPCODE, 3);
// select which word in the EEPROM that we are writing to.
ShiftOutBits(priv, reg, AddressSize);
// write the data to the selected EEPROM word.
ShiftOutBits(priv, data, 16);
if (WaitEEPROMCmdDone(priv) == FALSE)
{
// DbgPrint("D100: Failed EEPROM Write");
return;
}
StandBy(priv);
ShiftOutBits(priv, EEPROM_EWDS_OPCODE, 5);
ShiftOutBits(priv, reg, 4);
EEpromCleanup(priv);
return;
}
//-----------------------------------------------------------------------------
// Procedure: WaitEEPROMCmdDone
//
// Description: This routine waits for the the EEPROM to finish its command.
// Specifically, it waits for EEDO (data out) to go high.
//
// Arguments:
// Adapter - Ptr to this card's adapter data structure.
//
// Returns:
// TRUE - If the command finished
// FALSE - If the command never finished (EEDO stayed low)
//-----------------------------------------------------------------------------
static USHORT
WaitEEPROMCmdDone(
struct rtl8192cd_priv *priv)
{
UCHAR x;
USHORT i;
StandBy(priv);
for (i=0; i<200; i++)
{
x = RTL_R8(CSR_EEPROM_CONTROL_REG);
if (x & EEDO)
return (TRUE);
delay_us(CLOCK_RATE);
}
return FALSE;
}
//-----------------------------------------------------------------------------
// Procedure: StandBy
//
// Description: This routine lowers the EEPROM chip select (EECS) for a few
// microseconds.
//
// Arguments:
// Adapter - Ptr to this card's adapter data structure.
//
// Returns: (none)
//-----------------------------------------------------------------------------
static VOID
StandBy(
struct rtl8192cd_priv *priv)
{
UCHAR x;
x = RTL_R8(CSR_EEPROM_CONTROL_REG);
x &= ~(EECS | EESK);
RTL_W8(CSR_EEPROM_CONTROL_REG, x);
delay_us(CLOCK_RATE);
x |= EECS;
RTL_W8(CSR_EEPROM_CONTROL_REG, x);
delay_us(CLOCK_RATE);
}
//*****************************************************************************
//
// Main routines to read and write EEPROM
//
//*****************************************************************************
#define NUM_11A_CHANNEL 46
const UCHAR ChannelNumberListOf11a[] = {
26, 28, 30, 32,
34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64,
66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86,
100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140,
149, 153, 157, 161
};
#define READ_EEPROM(addr) ReadEEprom(priv, EepromAddressSize, addr)
#define WRITE_EEPROM(a,d) WriteEEprom(priv, EepromAddressSize, a, d)
int ReadAdapterInfo(struct rtl8192cd_priv *priv, int entry_id, void *data)
{
USHORT Index;
USHORT usValue;
ULONG curRCR;
UCHAR EepromAddressSize;
UCHAR TxPowerLevel[64];
if (!priv->EE_Cached)
{
curRCR = RTL_R32(_RCR_);
EepromAddressSize = (curRCR & _9356SEL_)? 8 : 6;
// ID
priv->EE_ID = (unsigned int)READ_EEPROM(EEPROM_ID);
DEBUG_INFO("ID 0x%04X\n", (USHORT)priv->EE_ID);
if (priv->EE_ID != RTL8180_EEPROM_ID) {
DEBUG_INFO("ID is invalid\n");
priv->EE_AutoloadFail = TRUE;
}
else
priv->EE_AutoloadFail = FALSE;
// Version
// priv->EE_Version = (unsigned int)READ_EEPROM((USHORT)(EEPROM_VERSION >> 1));
usValue = READ_EEPROM(0x7C >> 1);
priv->EE_Version = ((usValue&0xff00)>>8);
DEBUG_INFO("Version 0x%x\n", (USHORT)priv->EE_Version);
// MAC address
for (Index = 0; Index < 6; Index += 2) {
usValue = READ_EEPROM((USHORT)((EEPROM_NODE_ADDRESS_BYTE_0 + Index)>>1));
priv->EE_Mac[Index] = usValue & 0xff;
priv->EE_Mac[Index+1] = ((usValue&0xff00) >> 8);
}
DEBUG_INFO("Mac %02X-%02X-%02X-%02X-%02X-%02X\n",
priv->EE_Mac[0], priv->EE_Mac[1], priv->EE_Mac[2], priv->EE_Mac[3],
priv->EE_Mac[4], priv->EE_Mac[5]);
// for identifying empty EEPROM
if (!priv->EE_AutoloadFail)
{
// Tx Power Level
memset(priv->EE_TxPower_CCK, 0, sizeof(priv->EE_TxPower_CCK));
for (Index = 0; Index < MAX_CCK_CHANNEL_NUM; Index += 2) {
usValue = READ_EEPROM((USHORT)((EEPROM_TX_POWER_LEVEL_0 + Index) >> 1));
*((USHORT *)(&priv->EE_TxPower_CCK[Index])) = usValue;
}
memset(priv->EE_TxPower_OFDM, 0, sizeof(priv->EE_TxPower_OFDM));
for (Index = 0; Index < NUM_11A_CHANNEL; Index += 2) {
usValue = READ_EEPROM((USHORT)((EEPROM_11A_CHANNEL_TX_POWER_LEVEL_OFFSET + Index) >> 1));
*((USHORT *)(&TxPowerLevel[Index])) = usValue;
}
for (Index = 0; Index < NUM_11A_CHANNEL; Index++)
priv->EE_TxPower_OFDM[ChannelNumberListOf11a[Index] - 1] = TxPowerLevel[Index];
for (Index = 0; Index < MAX_CCK_CHANNEL_NUM; Index += 2) {
usValue = READ_EEPROM((USHORT)((EEPROM_11G_CHANNEL_OFDM_TX_POWER_LEVEL_OFFSET + Index) >> 1));
*((USHORT *)(&TxPowerLevel[Index])) = usValue;
}
for (Index = 0; Index < MAX_CCK_CHANNEL_NUM; Index++)
priv->EE_TxPower_OFDM[Index] = TxPowerLevel[Index];
#ifdef _DEBUG_RTL8192CD_
if (rtl8192cd_debug_info & _MODULE_DEFINE) {
extern void debug_out(char *label, unsigned char *data, int data_length);
debug_out("EEProm CCK TxPower", priv->EE_TxPower_CCK, MAX_CCK_CHANNEL_NUM);
debug_out("EEProm OFDM TxPower", priv->EE_TxPower_OFDM, MAX_OFDM_CHANNEL_NUM);
}
#endif
// RF chip id
// priv->EE_RFTypeID = (unsigned int)(READ_EEPROM((USHORT)(EEPROM_RF_CHIP_ID >> 1)) & 0x00f);
priv->EE_RFTypeID = (unsigned int)(READ_EEPROM((USHORT)(0x28 >> 1)) & 0x80 ) >> 7;
DEBUG_INFO("RF ID 0x%02X\n", (UCHAR)priv->EE_RFTypeID);
// AnaParm
usValue = READ_EEPROM((USHORT)((EEPROM_ANA_PARM + 2) >> 1));
priv->EE_AnaParm = (unsigned int)(usValue << 16);
usValue = READ_EEPROM((USHORT)(EEPROM_ANA_PARM >> 1));
priv->EE_AnaParm |= usValue;
DEBUG_INFO("AnaParm 0x%08X\n", priv->EE_AnaParm);
usValue = READ_EEPROM((USHORT)((EEPROM_ANA_PARM2 + 2) >> 1));
priv->EE_AnaParm2 = (unsigned int)(usValue << 16);
usValue = READ_EEPROM((USHORT)(EEPROM_ANA_PARM2 >> 1));
priv->EE_AnaParm2 |= usValue;
DEBUG_INFO("AnaParm2 0x%08X\n", priv->EE_AnaParm2);
//add CrystalCap, joshua 20080502
priv->EE_CrystalCap = (((unsigned int) READ_EEPROM( 0x2A >> 1)) & 0xf000) >> 12;
priv->pmib->dot11RFEntry.crystalCap = priv->EE_CrystalCap;
DEBUG_INFO("CrystalCap 0x%08X\n", priv->EE_CrystalCap);
}
priv->EE_Cached = 1;
}
if ((data != NULL) && (!priv->EE_AutoloadFail))
{
switch(entry_id)
{
case EEPROM_RF_CHIP_ID:
*((UCHAR *)data) = (UCHAR)priv->EE_RFTypeID;
break;
case EEPROM_NODE_ADDRESS_BYTE_0:
memcpy(data, priv->EE_Mac, MACADDRLEN);
break;
case EEPROM_TX_POWER_LEVEL_0:
memcpy(data, priv->EE_TxPower_CCK, MAX_CCK_CHANNEL_NUM);
break;
case EEPROM_11G_CHANNEL_OFDM_TX_POWER_LEVEL_OFFSET:
memcpy(data, priv->EE_TxPower_OFDM, MAX_OFDM_CHANNEL_NUM);
break;
default:
DEBUG_INFO("not support this id yet\n");
return 0;
}
return 1;
}
else
return 0;
}
int WriteAdapterInfo(struct rtl8192cd_priv *priv, int entry_id, void *data)
{
USHORT Index;
USHORT usValue;
ULONG curRCR;
UCHAR EepromAddressSize;
priv->EE_Cached = 0;
curRCR = RTL_R32(_RCR_);
EepromAddressSize = (curRCR & _9356SEL_)? 8 : 6;
switch(entry_id)
{
case EEPROM_TX_POWER_LEVEL_0:
Index = ((USHORT)((int)data)) & 0xfffe;
usValue = *((USHORT *)(&priv->EE_TxPower_CCK[Index]));
WRITE_EEPROM((USHORT)((EEPROM_TX_POWER_LEVEL_0 + Index) >> 1), usValue);
break;
case EEPROM_11G_CHANNEL_OFDM_TX_POWER_LEVEL_OFFSET:
Index = ((USHORT)((int)data)) & 0xfffe;
usValue = *((USHORT *)(&priv->EE_TxPower_OFDM[Index]));
WRITE_EEPROM((USHORT)((EEPROM_11G_CHANNEL_OFDM_TX_POWER_LEVEL_OFFSET + Index) >> 1), usValue);
break;
default:
return 0;
}
return 1;
}
#endif