📄 lan91c111.c
字号:
for(index=0 ; index < pNbuf->length; index +=2)
{
*(uint16*)ðframe->data[index] = LAN91C111_DATA;
}
/* Get control byte and odd byte if there is one */
lastword = LAN91C111_DATA;
if(lastword & 0x0020)
{
/* write last byte */
ethframe->data[index] = (uint8)((lastword & 0xFF00)>>8);
/* increase length by 1*/
pNbuf->length++;
}
/* Issue "Remove and Release" command */
while (LAN91C111_MMCR & LAN91C111_MMCR_BUSY);
LAN91C111_MMCR = LAN91C111_MMCR_RELEASE;
/* Call the appropriate handler */
nif_protocol_handler(nif,ethframe->type,pNbuf);
/* free the buffer */
nif->rx_free(pNbuf);
/* Return to ISR */
return;
}
/********************************************************************/
int
lan91c111_handler (void * applefritter, NIF *nif)
{
uint16 intstatus, oldIMR, oldBank, oldPTR;
vuint32 intdone;
intdone = FALSE;
/* Save off Bank Select register */
oldBank = LAN91C111_BSR;
/* switch to Bank 2 */
SMC_SELECT_BANK(2);
/* Save off Address Pointer register */
oldPTR = LAN91C111_PTR;
/* read the interrupt mask register */
oldIMR = LAN91C111_IMR;
/* disable all interrupts */
LAN91C111_IMR = 0;
while(!intdone)
{
/* switch to Bank 2 */
SMC_SELECT_BANK(2);
/* read in interrupt status register */
intstatus = (LAN91C111_ISR&0xFF00);
if(LAN91C111_ISR_RCV_INT &intstatus)
{
lan91c111_receive(applefritter, nif);
++nif->f_rx;
}
else if(LAN91C111_ISR_TX_INT &intstatus)
{
/* Acknowledge TXINTR */
LAN91C111_ISR = LAN91C111_ISR_TX_INT;
++nif->f_tx;
}
else if(LAN91C111_ISR_RX_OVRN_INT &intstatus)
{
/* Acknowledge interrupt */
LAN91C111_ISR = LAN91C111_ISR_RX_OVRN_INT;
}
else
intdone = TRUE;
} /* while(!intdone) */
/* Make sure I am in Bank 2 */
SMC_SELECT_BANK(2);
/* Check to see if FIFO is emtpy */
if(LAN91C111_PTR & LAN91C111_PTR_NOT_EMPTY)
{
return FALSE;
}
/* Restore Address Pointer register */
LAN91C111_PTR = oldPTR;
/* Restore the interrupt mask register */
LAN91C111_IMR = oldIMR;
/* Restore Bank Select register */
LAN91C111_BSR = oldBank;
return TRUE;
}
/********************************************************************
* Shutdown phy
********************************************************************/
static void lan91c111_phy_shutdown(void)
{
unsigned int timeout;
unsigned int j;
// Reset the PHY, setting all other bits to zero
lan91c111_write_phy_reg(PHYADDR, PHY_CNTL_REG, PHY_CNTL_RST);
// Wait for the reset to complete, or time out
timeout = 6; // Wait up to 3 seconds
while (timeout--)
{
if (!(lan91c111_read_phy_reg(PHYADDR, PHY_CNTL_REG) & PHY_CNTL_RST))
{
// reset complete
break;
}
/* delay some time */
for( j=0 ; j<100 ; j++);
}
if (timeout < 1)
{
printf("PHY reset timed out\n");
return;
}
}
/********************************************************************
* Configures the specified PHY using Autonegotiation. Calls
* smc_phy_fixed() if the user has requested a certain config.
********************************************************************/
static void lan91c111_phy_configure(void)
{
unsigned int timeout;
unsigned int j;
uint16 status;
// Reset the PHY, setting all other bits to zero
lan91c111_write_phy_reg(PHYADDR, PHY_CNTL_REG, PHY_CNTL_RST);
// Wait for the reset to complete, or time out
timeout = 6; // Wait up to 3 seconds
while (timeout--)
{
if (!(lan91c111_read_phy_reg(PHYADDR, PHY_CNTL_REG) & PHY_CNTL_RST))
{
// reset complete
break;
}
/* delay some time */
for( j=0 ; j<100 ; j++);
}
if (timeout < 1)
{
printf("PHY reset timed out\n");
return;
}
// Enable PHY Interrupts (for register 18)
// Interrupts listed here are disabled
lan91c111_write_phy_reg(PHYADDR, PHY_MASK_REG, PHY_INT_LNKFAIL
|PHY_INT_INT
|PHY_INT_LOSSSYNC
|PHY_INT_CWRD
|PHY_INT_SSD
|PHY_INT_ESD
|PHY_INT_RPOL
|PHY_INT_JAB
|PHY_INT_SPDDET
|PHY_INT_DPLXDET);
/* Configure the Receive/Phy Control register */
SMC_SELECT_BANK(0);
LAN91C111_RPC = LAN91C111_RPC_DEFAULT;
// Update our Auto-Neg Advertisement Register
lan91c111_write_phy_reg(PHYADDR, PHY_AD_REG, (PHY_AD_TX_FDX|PHY_AD_TX_HDX|PHY_AD_10_FDX|PHY_AD_10_HDX|PHY_AD_CSMA));
// Restart auto-negotiation process in order to advertise my caps
lan91c111_write_phy_reg(PHYADDR, 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 = lan91c111_read_phy_reg(PHYADDR, PHY_STAT_REG);
if (status & PHY_STAT_ANEG_ACK)
{
// auto-negotiate complete
break;
}
/* delay some time */
for( j=0 ; j<10000 ; j++);
// Restart auto-negotiation if remote fault
if (status & PHY_STAT_REM_FLT)
{
// Restart auto-negotiation
lan91c111_write_phy_reg(PHYADDR, PHY_CNTL_REG,
PHY_CNTL_ANEG_EN | PHY_CNTL_ANEG_RST |
PHY_CNTL_SPEED | PHY_CNTL_DPLX);
}
}
}
/********************************************************************
* Writes a register to the MII Management serial interface
********************************************************************/
static void lan91c111_write_phy_reg(uint8 phyaddr, uint8 phyreg, uint16 phydata)
{
uint16 oldBank;
uint32 i,j;
uint16 mask;
uint16 mii_reg;
uint16 bits[65];
uint32 clk_idx = 0;
// 32 consecutive ones on MDO to establish sync
for (i = 0; i < 32; ++i)
bits[clk_idx++] = LAN91C111_MII_MDOE | LAN91C111_MII_MDO;
// Start code <01>
bits[clk_idx++] = LAN91C111_MII_MDOE;
bits[clk_idx++] = LAN91C111_MII_MDOE | LAN91C111_MII_MDO;
// Write command <01>
bits[clk_idx++] = LAN91C111_MII_MDOE;
bits[clk_idx++] = LAN91C111_MII_MDOE | LAN91C111_MII_MDO;
// Output the PHY address, msb first
mask = (uint8)0x10;
for (i = 0; i < 5; ++i)
{
if (phyaddr & mask)
bits[clk_idx++] = LAN91C111_MII_MDOE | LAN91C111_MII_MDO;
else
bits[clk_idx++] = LAN91C111_MII_MDOE;
// Shift to next lowest bit
mask >>= 1;
}
// Output the phy register number, msb first
mask = (uint8)0x10;
for (i = 0; i < 5; ++i)
{
if (phyreg & mask)
bits[clk_idx++] = LAN91C111_MII_MDOE | LAN91C111_MII_MDO;
else
bits[clk_idx++] = LAN91C111_MII_MDOE;
// Shift to next lowest bit
mask >>= 1;
}
// Tristate and turnaround (2 bit times)
bits[clk_idx++] = 0;
bits[clk_idx++] = 0;
// Write out 16 bits of data, msb first
mask = 0x8000;
for (i = 0; i < 16; ++i)
{
if (phydata & mask)
bits[clk_idx++] = LAN91C111_MII_MDOE | LAN91C111_MII_MDO;
else
bits[clk_idx++] = LAN91C111_MII_MDOE;
// Shift to next lowest bit
mask >>= 1;
}
// Save the current bank
oldBank = LAN91C111_BSR;
// Select bank 3
SMC_SELECT_BANK(3);
// Get the current MII register value
mii_reg = LAN91C111_MII;
// Turn off all MII Interface bits
mii_reg &= ~(LAN91C111_MII_MDOE|LAN91C111_MII_MCLK|LAN91C111_MII_MDI|LAN91C111_MII_MDO);
// Clock all cycles
for (i = 0; i < sizeof bits; ++i)
{
// Clock Low - output data
LAN91C111_MII = (mii_reg | bits[i]);
for(j=0 ; j<4000 ;j++);
// Clock Hi - input data
LAN91C111_MII = (mii_reg | bits[i] | LAN91C111_MII_MCLK);
for(j=0 ; j<4000 ;j++);
bits[i] |= (LAN91C111_MII & LAN91C111_MII_MDI);
}
// Return to idle state
// Set clock to low, data to low, and output tristated
LAN91C111_MII = mii_reg;
for(j=0 ; j<1000 ;j++);
// Restore original bank select
// SMC_SELECT_BANK(oldBank);
LAN91C111_BSR = oldBank;
}
/********************************************************************
* Reads a register from the MII Management serial interface
********************************************************************/
static uint16
lan91c111_read_phy_reg(uint8 phyaddr, uint8 phyreg)
{
uint16 oldBank;
uint32 i,j;
uint8 mask;
uint16 mii_reg;
uint16 bits[64];
uint32 clk_idx = 0;
uint32 input_idx;
uint16 phydata;
// 32 consecutive ones on MDO to establish sync
for (i = 0; i < 32; ++i)
bits[clk_idx++] = LAN91C111_MII_MDOE | LAN91C111_MII_MDO;
// Start code <01>
bits[clk_idx++] = LAN91C111_MII_MDOE;
bits[clk_idx++] = LAN91C111_MII_MDOE | LAN91C111_MII_MDO;
// Read command <10>
bits[clk_idx++] = LAN91C111_MII_MDOE | LAN91C111_MII_MDO;
bits[clk_idx++] = LAN91C111_MII_MDOE;
// Output the PHY address, msb first
mask = (uint8)0x10;
for (i = 0; i < 5; ++i)
{
if (phyaddr & mask)
bits[clk_idx++] = LAN91C111_MII_MDOE | LAN91C111_MII_MDO;
else
bits[clk_idx++] = LAN91C111_MII_MDOE;
// Shift to next lowest bit
mask >>= 1;
}
// Output the phy register number, msb first
mask = (uint8)0x10;
for (i = 0; i < 5; ++i)
{
if (phyreg & mask)
bits[clk_idx++] = LAN91C111_MII_MDOE | LAN91C111_MII_MDO;
else
bits[clk_idx++] = LAN91C111_MII_MDOE;
// Shift to next lowest bit
mask >>= 1;
}
// Tristate and turnaround (2 bit times)
bits[clk_idx++] = 0;
//bits[clk_idx++] = 0;
// Input starts at this bit time
input_idx = clk_idx;
// Will input 16 bits
for (i = 0; i < 16; ++i)
bits[clk_idx++] = 0;
// Final clock bit
bits[clk_idx] = 0;
// Save the current bank
oldBank = LAN91C111_BSR;
// Select bank 3
SMC_SELECT_BANK(3);
// Get the current MII register value
mii_reg = LAN91C111_MII;
// Turn off all MII Interface bits
mii_reg &= ~(LAN91C111_MII_MDOE|LAN91C111_MII_MCLK|LAN91C111_MII_MDI|LAN91C111_MII_MDO);
// Clock all 64 cycles
for (i = 0; i < sizeof bits; ++i)
{
// Clock Low - output data
LAN91C111_MII = ( mii_reg | bits[i] );
for(j=0 ; j<4000 ;j++);
// Clock Hi - input data
LAN91C111_MII = ( mii_reg | bits[i] | LAN91C111_MII_MCLK );
for(j=0 ; j<4000 ;j++)
{}
bits[i] |= (LAN91C111_MII & LAN91C111_MII_MDI);
}
// Return to idle state
// Set clock to low, data to low, and output tristated
LAN91C111_MII = mii_reg;
for(j=0 ; j<1000 ;j++);
// Restore original bank select
// SMC_SELECT_BANK( oldBank );
LAN91C111_BSR = oldBank;
// Recover input data
phydata = 0;
for (i = 0; i < 16; ++i)
{
phydata <<= 1;
if (bits[input_idx++] & LAN91C111_MII_MDI)
phydata |= 0x0001;
}
return(phydata);
}
/********************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -