📄 smc.c
字号:
smc_wait_ms (500); /* wait 500 millisecs */
/* Configure the Receive/Phy Control register */
WriteWord( BANKSEL_REG, BANK0 );
WriteWord ( RPC_REG ,RPC_DEFAULT);
/* Copy our capabilities from PHY_STAT_REG to PHY_AD_REG */
my_phy_caps = smc_read_phy_register (PHY_STAT_REG);
my_ad_caps = PHY_AD_CSMA; /* I am CSMA capable */
if (my_phy_caps & PHY_STAT_CAP_T4) {
my_ad_caps |= PHY_AD_T4;
}
if (my_phy_caps & PHY_STAT_CAP_TXF) {
my_ad_caps |= PHY_AD_TX_FDX;
}
if (my_phy_caps & PHY_STAT_CAP_TXH) {
my_ad_caps |= PHY_AD_TX_HDX;
}
if (my_phy_caps & PHY_STAT_CAP_TF) {
my_ad_caps |= PHY_AD_10_FDX;
}
if (my_phy_caps & PHY_STAT_CAP_TH) {
my_ad_caps |= PHY_AD_10_HDX;
}
/* Update our Auto-Neg Advertisement Register */
smc_write_phy_register (PHY_AD_REG, my_ad_caps);
/* Read the register back. Without this, it appears that when */
/* auto-negotiation is restarted, sometimes it isn't ready and */
/* the link does not come up. */
smc_read_phy_register(PHY_AD_REG);
EdbgOutputDebugString ("%s:phy caps=0x%x\n", SMC_DEV_NAME, my_phy_caps); /*0x7809*/
EdbgOutputDebugString ("%s:phy advertised caps=0x%x\n", SMC_DEV_NAME, my_ad_caps); /*0x01e1*/
/* Restart auto-negotiation process in order to advertise my caps */
smc_write_phy_register (PHY_CNTL_REG, PHY_CNTL_ANEG_EN | PHY_CNTL_ANEG_RST);
/* Wait for the auto-negotiation to complete. This may take from */
/* 2 to 3 seconds. */
/* Wait for the reset to complete, or time out */
timeout = 20; /* Wait up to 10 seconds */
while (timeout--)
{
status = smc_read_phy_register (PHY_STAT_REG);
if (status & PHY_STAT_ANEG_ACK)
{
EdbgOutputDebugString ("%s:PHY auto-negotiate complete\n", SMC_DEV_NAME);
/* auto-negotiate complete */
break;
}
smc_wait_ms (500); /* wait 500 millisecs */
/* Restart auto-negotiation if remote fault */
if (status & PHY_STAT_REM_FLT)
{
EdbgOutputDebugString ("%s:PHY remote fault detected\n", SMC_DEV_NAME);
/* Restart auto-negotiation */
EdbgOutputDebugString("%s:PHY restarting auto-negotiation\n",SMC_DEV_NAME);
smc_write_phy_register (PHY_CNTL_REG,
PHY_CNTL_ANEG_EN |
PHY_CNTL_ANEG_RST |
PHY_CNTL_SPEED |
PHY_CNTL_DPLX);
}
}
EdbgOutputDebugString ("%s:PHY_STAT_REG : 0x%x\n", SMC_DEV_NAME, status);
if (timeout < 1) {
EdbgOutputDebugString("%s:PHY auto-negotiate timed out\n", SMC_DEV_NAME);
EdbgOutputDebugString("%s:PHY auto-negotiate timed out\n", SMC_DEV_NAME);
failed = 1;
}
/* Fail if we detected an auto-negotiate remote fault */
if (status & PHY_STAT_REM_FLT)
{
EdbgOutputDebugString("PHY remote fault detected\n");
failed = 1;
}
/* Re-Configure the Receive/Phy Control register */
WriteWord( RPC_REG,RPC_DEFAULT);
EdbgOutputDebugString("%s:RPC_DEFAULT : 0x%x\n", SMC_DEV_NAME, RPC_DEFAULT);
smc_phy_configure_exit:
return;
}
#endif
#if 1
/* Default is powered-up, Internal Phy, Wait States, and pin nCNTRL=low */
#define CONFIG_DEFAULT (CFG_EPH_POWER_EN | CFG_NO_WAIT)
#define SMC_inw(r) ReadWord(r)
#define SMC_inb(r) (((r)&1) ? SMC_inw((r)&~1)>>8 : SMC_inw(r)&0xFF)
#define SMC_outw(d,r) WriteWord(r,d)
void SMC_outb(BYTE d,WORD r)
{
WORD __d = (BYTE)(d);
WORD __w = SMC_inw((r)&~1);
__w &= ((r)&1) ? 0x00FF : 0xFF00;
__w |= ((r)&1) ? __d<<8 : __d;
WriteWord((r)&~1,__w);
}
void SMC_insw(r,b,l)
{
int __i ;
WORD *__b2;
__b2 = (WORD *) b;
for (__i = 0; __i < l; __i++)
{
*(__b2 + __i) = SMC_inw(r);
SMC_inw(0);
};
}
void SMC_outsw(r,b,l)
{
int __i;
WORD *__b2;
__b2 = (WORD *) b;
for (__i = 0; __i < l; __i++)
{
SMC_outw( *(__b2 + __i), r);
} \
}
#define SMC_SELECT_BANK(x) { SMC_outw( x, BANKSEL_REG ); }
static void udelay(unsigned int us)
{
volatile int i;
volatile int i2;
for(i=0 ; (unsigned int)i < us ; i++)
{
for(i2=0;i2<10;i2++)
{
}
}
}
static void smc_enable()
{
EdbgOutputDebugString("%s:smc_enable\n", SMC_DEV_NAME);
SMC_SELECT_BANK( 0 );
/* see the header file for options in TCR/RCR DEFAULT*/
SMC_outw( TCR_DEFAULT, TCR_REG );
SMC_outw( RCR_DEFAULT, RCR_REG );
}
static void smc_wait_mmu_release_complete (void)
{
int count = 0;
/* assume bank 2 selected */
while (SMC_inw (MMU_CMD_REG) & MC_BUSY) {
udelay (1); /* Wait until not busy */
if (++count > 200)
break;
}
}
static void smc_reset (void)
{
EdbgOutputDebugString ("%s:smc_reset\n", SMC_DEV_NAME);
/* This resets the registers mostly to defaults, but doesn't
affect EEPROM. That seems unnecessary */
SMC_SELECT_BANK (0);
SMC_outw (RCR_SOFTRST, RCR_REG);
/* Setup the Configuration Register */
/* This is necessary because the CONFIG_REG is not affected */
/* by a soft reset */
SMC_SELECT_BANK (1);
SMC_outw (CONFIG_DEFAULT, CONFIG_REG);
/* Release from possible power-down state */
/* Configuration register is not affected by Soft Reset */
SMC_outw (SMC_inw (CONFIG_REG) | CFG_EPH_POWER_EN, CONFIG_REG);
/* this should pause enough for the chip to be happy */
udelay (10);
SMC_SELECT_BANK (0);
/* Disable transmit and receive functionality */
SMC_outw (RCR_CLEAR, RCR_REG);
SMC_outw (TCR_CLEAR, TCR_REG);
/* set the control register */
SMC_SELECT_BANK (1);
SMC_outw (CTL_DEFAULT, CONTROL_REG);
/* Reset the MMU */
SMC_SELECT_BANK (2);
smc_wait_mmu_release_complete ();
SMC_outw (MC_RESET, MMU_CMD_REG);
while (SMC_inw (MMU_CMD_REG) & MC_BUSY)
udelay (1); /* Wait until not busy */
/* Note: It doesn't seem that waiting for the MMU busy is needed here,
but this is a place where future chipsets _COULD_ break. Be wary
of issuing another MMU command right after this */
/* Disable all interrupts */
SMC_outb (0, IM_REG);
}
int eth_init(USHORT *MacAddr)
{
int i;
BYTE *mac = (BYTE*)MacAddr;
EdbgOutputDebugString ("%s:smc_open\n", SMC_DEV_NAME);
EdbgOutputDebugString("%s:smc_open\n", SMC_DEV_NAME);
/* reset the hardware */
smc_reset ();
smc_enable ();
/* Configure the PHY */
smc_phy_configure ();
SMC_SELECT_BANK (1);
for (i = 0; i < 6; i++)
SMC_outb (*(mac+i), MACADDR0_REG + i);
return 0;
}
#endif
BOOL
SMCInit( BYTE *pbBaseAddress, DWORD dwMultiplier, USHORT MacAddr[3])
{
WORD i;
DWORD dwStartTime;
USHORT wBSR, wConfig;
if (! pbBaseAddress)
{
EdbgOutputDebugString( "BASEADDRESS error\r\n");
return FALSE;
}
pbEthernetBase = pbBaseAddress;
dwRegisterMultiplier = 0x1; //dwMultiplier;
// DANGER - May have to wait 750 usec after reset while EEPROM info loads (Pg 50 of the SMC91C94 spec).
// until this occurs, SMC registers are inaccessible.
smc_reset ();
smc_enable ();
SMC_SELECT_BANK (1);
dwStartTime = OEMEthGetSecs();
while( ReadWord( CONTROL_REG ) & 0x0003 && OEMEthGetSecs() - dwStartTime < 2);
// Verify the I/O base. The upper byte of the BSR always reads 0x33, use this.
// For Odo, the bus cycles will time out and garbage values will be returned.
wBSR = ReadWord(BANKSEL_REG);
EdbgOutputDebugString ("0xA700030e=0x%x\n",*(volatile UINT16 *)0xA700030e);
if ((wBSR & 0xFF00) != 0x3300) {
EdbgOutputDebugString("SMC card not detected, I/O base 0x%X, BSR: 0x%X\n",pbEthernetBase,wBSR);
return FALSE;
}
EdbgOutputDebugString( "SMC Ethernet card detected at I/O base 0x%X\r\n",pbEthernetBase);
// Read the MAC address from the 91C94. This should have been read in from the EEPROM during reset
// Set SQUELCH bit - this changes the threshold for a valid signal from 300mV to 180mV.
// This is to attempt to fix problems we have seen with some (usually 8 port) hubs.
wConfig = ReadWord(CONFIG_REG);
wConfig |= CFG_NO_WAIT;
wConfig |= CFG_EPH_POWER_EN;
WriteWord(CONFIG_REG, wConfig);
EdbgOutputDebugString("SMC config reg val: %X\n",wConfig);
// Initialize the control register
WriteWord( CONTROL_REG, CONTROL_REG_INIT );
for(i = 0; i < 6; i++)
SMC_outb (*((BYTE*)MacAddr+i), MACADDR0_REG + i);
// Initialize memory configuration register
SMC_SELECT_BANK (0);
WriteWord( MCR_REG, MCR_REG_INIT );
// Initialize transmit control register
WriteWord( TCR_REG, TCR_REG_INIT );
// Initialize interrupt mask register (all ints disabled to start)
SMC_SELECT_BANK (2);
WriteWord( SMC91111_INT_REG, 0);
// The receive register should be the last thing initialzed so that we don't start
// getting Frames before we're ready for them.
// Initialize the Receive Control Register (Pg 39 of the SMC91C94 spec):
SMC_SELECT_BANK (0);
WriteWord( RCR_REG, RCR_REG_INIT );
WriteWord( RCR_REG, (RCR_RXEN|RCR_STRIP_CRC) );
EdbgOutputDebugString("SMC Reset complete2\r\n");
// Even if the card is present, it likes to have a second to stabilize before the first transmission
while( OEMEthGetSecs() - dwStartTime < 2 );
#if 0
smc_write_phy_register (0x00,0x00);
EdbgOutputDebugString( "----%x\r\n",smc_read_phy_register (0x00));
EdbgOutputDebugString( "----%x\r\n",smc_read_phy_register (0x01));
EdbgOutputDebugString( "----%x\r\n",smc_read_phy_register (0x02));
EdbgOutputDebugString( "----%x\r\n",smc_read_phy_register (0x03));
EdbgOutputDebugString( "----%x\r\n",smc_read_phy_register (0x04));
#endif
smc_phy_configure ();
return TRUE;
}
// Interrupts left disabled at init, call this function to turn them on
void
SMCEnableInts()
{
// Only enable receive interrupts (we poll for Tx completion)
wIntMask = RCV_INTM;
SMC_SELECT_BANK (2);
WriteWord( SMC91111_INT_REG, wIntMask );
}
void
SMCDisableInts()
{
wIntMask = 0;
SMC_SELECT_BANK (2);
WriteWord( SMC91111_INT_REG, wIntMask );
}
DWORD
SMCGetPendingInterrupts()
{
WORD wInts;
DWORD dwRet = 0;
UINT16 wBankSave;
// I need to save/restore the affected registers in the 91C94
wBankSave = ReadWord( BANKSEL_REG );
SMC_SELECT_BANK (2);
wInts = ReadWord(SMC91111_INT_REG);
// Just check for Rx int
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -