@ -1,6 +1,9 @@
/*
* Cirrus Logic CS8900A Ethernet
*
* ( C ) 2009 Ben Warren , biggerbadderben @ gmail . com
* Converted to use CONFIG_NET_MULTI API
*
* ( C ) 2003 Wolfgang Denk , wd @ denx . de
* Extension to synchronize ethaddr environment variable
* against value in EEPROM
@ -38,220 +41,229 @@
# include <common.h>
# include <command.h>
# include "cs8900.h"
# include <asm/io.h>
# include <net.h>
# include <malloc.h>
# include "cs8900.h"
# undef DEBUG
/* packet page register access functions */
# ifdef CS8900_BUS32
# ifdef CONFIG_CS8900_BUS32
# define REG_WRITE(v, a) writel((v),(a))
# define REG_READ(a) readl((a))
/* we don't need 16 bit initialisation on 32 bit bus */
# define get_reg_init_bus(x) get_reg((x))
# else
static unsigned short get_reg_init_bus ( int regno )
{
/* force 16 bit busmode */
volatile unsigned char c ;
c = CS8900_BUS16_0 ;
c = CS8900_BUS16_1 ;
c = CS8900_BUS16_0 ;
c = CS8900_BUS16_1 ;
c = CS8900_BUS16_0 ;
# define REG_WRITE(v, a) writew((v),(a))
# define REG_READ(a) readw((a))
CS8900_PPTR = regno ;
return CS8900_PDATA ;
static u16 get_reg_init_bus ( struct eth_device * dev , int regno )
{
/* force 16 bit busmode */
volatile u8 c ;
struct cs8900_priv * priv = ( struct cs8900_priv * ) ( dev - > priv ) ;
uint8_t volatile * const iob = ( uint8_t volatile * const ) dev - > iobase ;
c = readb ( iob ) ;
c = readb ( iob + 1 ) ;
c = readb ( iob ) ;
c = readb ( iob + 1 ) ;
c = readb ( iob ) ;
REG_WRITE ( regno , & priv - > regs - > pptr ) ;
return REG_READ ( & priv - > regs - > pdata ) ;
}
# endif
static unsigned short get_reg ( int regno )
static u16 get_reg ( struct eth_device * dev , int regno )
{
CS8900_PPTR = regno ;
return CS8900_PDATA ;
struct cs8900_priv * priv = ( struct cs8900_priv * ) ( dev - > priv ) ;
REG_WRITE ( regno , & priv - > regs - > pptr ) ;
return REG_READ ( & priv - > regs - > pdata ) ;
}
static void put_reg ( int regno , unsigned short val )
static void put_reg ( struct eth_device * dev , int regno , u16 val )
{
CS8900_PPTR = regno ;
CS8900_PDATA = val ;
struct cs8900_priv * priv = ( struct cs8900_priv * ) ( dev - > priv ) ;
REG_WRITE ( regno , & priv - > regs - > pptr ) ;
REG_WRITE ( val , & priv - > regs - > pdata ) ;
}
static void eth_reset ( void )
static void cs8900_reset ( struct eth_device * dev )
{
int tmo ;
unsigned short us ;
u16 us ;
/* reset NIC */
put_reg ( PP_SelfCTL , get_reg ( PP_SelfCTL ) | PP_SelfCTL_Reset ) ;
put_reg ( dev , PP_SelfCTL , get_reg ( dev , PP_SelfCTL ) | PP_SelfCTL_Reset ) ;
/* wait for 200ms */
udelay ( 200000 ) ;
udelay ( 200000 ) ;
/* Wait until the chip is reset */
tmo = get_timer ( 0 ) + 1 * CONFIG_SYS_HZ ;
while ( ( ( ( us = get_reg_init_bus ( PP_SelfSTAT ) ) & PP_SelfSTAT_InitD ) = = 0 )
& & tmo < get_timer ( 0 ) )
tmo = get_timer ( 0 ) + 1 * CONFIG_SYS_HZ ;
while ( ( ( ( us = get_reg_init_bus ( dev , PP_SelfSTAT ) ) &
PP_SelfSTAT_InitD ) = = 0 ) & & tmo < get_timer ( 0 ) )
/*NOP*/ ;
}
static void eth_reginit ( void )
static void cs8900_reginit ( struct eth_device * dev )
{
/* receive only error free packets addressed to this card */
put_reg ( PP_RxCTL , PP_RxCTL_IA | PP_RxCTL_Broadcast | PP_RxCTL_RxOK ) ;
put_reg ( dev , PP_RxCTL ,
PP_RxCTL_IA | PP_RxCTL_Broadcast | PP_RxCTL_RxOK ) ;
/* do not generate any interrupts on receive operations */
put_reg ( PP_RxCFG , 0 ) ;
put_reg ( dev , PP_RxCFG , 0 ) ;
/* do not generate any interrupts on transmit operations */
put_reg ( PP_TxCFG , 0 ) ;
put_reg ( dev , PP_TxCFG , 0 ) ;
/* do not generate any interrupts on buffer operations */
put_reg ( PP_BufCFG , 0 ) ;
put_reg ( dev , PP_BufCFG , 0 ) ;
/* enable transmitter/receiver mode */
put_reg ( PP_LineCTL , PP_LineCTL_Rx | PP_LineCTL_Tx ) ;
put_reg ( dev , PP_LineCTL , PP_LineCTL_Rx | PP_LineCTL_Tx ) ;
}
void cs8900_get_enetaddr ( void )
void cs8900_get_enetaddr ( struct eth_device * dev )
{
int i ;
uchar enetaddr [ 6 ] ;
/* if the env is setup, then bail */
if ( eth_getenv_enetaddr ( " ethaddr " , enetaddr ) )
return ;
/* verify chip id */
if ( get_reg_init_bus ( PP_ChipID ) ! = 0x630e )
if ( get_reg_init_bus ( dev , PP_ChipID ) ! = 0x630e )
return ;
eth_reset ( ) ;
if ( ( get_reg ( PP_SelfSTAT ) & ( PP_SelfSTAT_EEPROM | PP_SelfSTAT_EEPROM_OK ) ) = =
( PP_SelfSTAT_EEPROM | PP_SelfSTAT_EEPROM_OK ) ) {
cs8900_reset ( dev ) ;
if ( ( get_reg ( dev , PP_SelfSTAT ) &
( PP_SelfSTAT_EEPROM | PP_SelfSTAT_EEPROM_OK ) ) = =
( PP_SelfSTAT_EEPROM | PP_SelfSTAT_EEPROM_OK ) ) {
/* Load the MAC from EEPROM */
for ( i = 0 ; i < 6 / 2 ; i + + ) {
unsigned int Addr ;
for ( i = 0 ; i < 3 ; i + + ) {
u32 Addr ;
Addr = get_reg ( PP_IA + i * 2 ) ;
enetaddr [ i * 2 ] = Addr & 0xFF ;
enetaddr [ i * 2 + 1 ] = Addr > > 8 ;
Addr = get_reg ( dev , PP_IA + i * 2 ) ;
dev - > enetaddr [ i * 2 ] = Addr & 0xFF ;
dev - > enetaddr [ i * 2 + 1 ] = Addr > > 8 ;
}
eth_setenv_enetaddr ( " ethaddr " , enetaddr ) ;
debug ( " ### Set environment from HW MAC addr = \" %pM \" \n " , enetaddr ) ;
}
}
void eth_halt ( void )
void cs8900_halt ( struct eth_device * dev )
{
/* disable transmitter/receiver mode */
put_reg ( PP_LineCTL , 0 ) ;
put_reg ( dev , PP_LineCTL , 0 ) ;
/* "shutdown" to show ChipID or kernel wouldn't find he cs8900 ... */
get_reg_init_bus ( PP_ChipID ) ;
get_reg_init_bus ( dev , PP_ChipID ) ;
}
int eth_init ( bd_t * bd )
static int cs8900_init ( struct eth_device * dev , bd_t * bd )
{
uchar enetaddr [ 6 ] ;
uchar * enetaddr = dev - > enetaddr ;
u16 id ;
/* verify chip id */
if ( get_reg_init_bus ( PP_ChipID ) ! = 0x630e ) {
printf ( " CS8900 Ethernet chip not found?! \n " ) ;
return 0 ;
id = get_reg_init_bus ( dev , PP_ChipID ) ;
if ( id ! = 0x630e ) {
printf ( " CS8900 Ethernet chip not found: "
" ID=0x%04x instead 0x%04x \n " , id , 0x630e ) ;
return 1 ;
}
eth_reset ( ) ;
cs8900_reset ( dev ) ;
/* set the ethernet address */
eth_getenv_enetaddr ( " ethaddr " , enetaddr ) ;
put_reg ( PP_IA + 0 , enetaddr [ 0 ] | ( enetaddr [ 1 ] < < 8 ) ) ;
put_reg ( PP_IA + 2 , enetaddr [ 2 ] | ( enetaddr [ 3 ] < < 8 ) ) ;
put_reg ( PP_IA + 4 , enetaddr [ 4 ] | ( enetaddr [ 5 ] < < 8 ) ) ;
put_reg ( dev , PP_IA + 0 , enetaddr [ 0 ] | ( enetaddr [ 1 ] < < 8 ) ) ;
put_reg ( dev , PP_IA + 2 , enetaddr [ 2 ] | ( enetaddr [ 3 ] < < 8 ) ) ;
put_reg ( dev , PP_IA + 4 , enetaddr [ 4 ] | ( enetaddr [ 5 ] < < 8 ) ) ;
eth_reginit ( ) ;
cs8900_reginit ( dev ) ;
return 0 ;
}
/* Get a data block via Ethernet */
int eth_rx ( void )
static int cs8900_recv ( struct eth_device * dev )
{
int i ;
unsigned short rxlen ;
unsigned short * addr ;
unsigned short status ;
u16 rxlen ;
u16 * addr ;
u16 status ;
status = get_reg ( PP_RER ) ;
struct cs8900_priv * priv = ( struct cs8900_priv * ) ( dev - > priv ) ;
status = get_reg ( dev , PP_RER ) ;
if ( ( status & PP_RER_RxOK ) = = 0 )
return 0 ;
status = CS8900_RTDATA ; /* stat */
rxlen = CS8900_RTDATA ; /* len */
status = REG_READ ( & priv - > regs - > rtdata ) ;
rxlen = REG_READ ( & priv - > regs - > rtdata ) ;
# ifdef DEBUG
if ( rxlen > PKTSIZE_ALIGN + PKTALIGN )
printf ( " packet too big! \n " ) ;
# endif
for ( addr = ( unsigned short * ) NetRxPackets [ 0 ] , i = rxlen > > 1 ; i > 0 ;
debug ( " packet too big! \n " ) ;
for ( addr = ( u16 * ) NetRxPackets [ 0 ] , i = rxlen > > 1 ; i > 0 ;
i - - )
* addr + + = CS8900_RTDATA ;
* addr + + = REG_READ ( & priv - > regs - > rtdata ) ;
if ( rxlen & 1 )
* addr + + = CS8900_RTDATA ;
* addr + + = REG_READ ( & priv - > regs - > rtdata ) ;
/* Pass the packet up to the protocol layers. */
NetReceive ( NetRxPackets [ 0 ] , rxlen ) ;
return rxlen ;
}
/* Send a data block via Ethernet. */
int eth_send ( volatile void * packet , int length )
static int cs8900_send ( struct eth_device * dev ,
volatile void * packet , int length )
{
volatile unsigned short * addr ;
volatile u16 * addr ;
int tmo ;
unsigned short s ;
u16 s ;
struct cs8900_priv * priv = ( struct cs8900_priv * ) ( dev - > priv ) ;
retry :
/* initiate a transmit sequence */
CS8900_TxCMD = PP_TxCmd_TxStart_Full ;
CS8900_TxLEN = length ;
REG_WRITE ( PP_TxCmd_TxStart_Full , & priv - > regs - > txcmd ) ;
REG_WRITE ( length , & priv - > regs - > txlen ) ;
/* Test to see if the chip has allocated memory for the packet */
if ( ( get_reg ( PP_BusSTAT ) & PP_BusSTAT_TxRDY ) = = 0 ) {
if ( ( get_reg ( dev , PP_BusSTAT ) & PP_BusSTAT_TxRDY ) = = 0 ) {
/* Oops... this should not happen! */
# ifdef DEBUG
printf ( " cs: unable to send packet; retrying... \n " ) ;
# endif
for ( tmo = get_timer ( 0 ) + 5 * CONFIG_SYS_HZ ; get_timer ( 0 ) < tmo ; )
debug ( " cs: unable to send packet; retrying... \n " ) ;
for ( tmo = get_timer ( 0 ) + 5 * CONFIG_SYS_HZ ;
get_timer ( 0 ) < tmo ; )
/*NOP*/ ;
eth_reset ( ) ;
eth_reginit ( ) ;
cs8900_reset ( dev ) ;
cs8900_reginit ( dev ) ;
goto retry ;
}
/* Write the contents of the packet */
/* assume even number of bytes */
for ( addr = packet ; length > 0 ; length - = 2 )
CS8900_RTDATA = * addr + + ;
REG_WRITE ( * addr + + , & priv - > regs - > rtdata ) ;
/* wait for transfer to succeed */
tmo = get_timer ( 0 ) + 5 * CONFIG_SYS_HZ ;
while ( ( s = get_reg ( PP_TER ) & ~ 0x1F ) = = 0 ) {
if ( get_timer ( 0 ) > = tmo )
tmo = get_timer ( 0 ) + 5 * CONFIG_SYS_HZ ;
while ( ( s = get_reg ( dev , PP_TER ) & ~ 0x1F ) = = 0 ) {
if ( get_timer ( 0 ) > = tmo )
break ;
}
/* nothing */ ;
if ( ( s & ( PP_TER_CRS | PP_TER_TxOK ) ) ! = PP_TER_TxOK ) {
# ifdef DEBUG
printf ( " \n transmission error %#x \n " , s ) ;
# endif
if ( ( s & ( PP_TER_CRS | PP_TER_TxOK ) ) ! = PP_TER_TxOK ) {
debug ( " \n transmission error %#x \n " , s ) ;
}
return 0 ;
}
static void cs8900_e2prom_ready ( vo id )
static void cs8900_e2prom_ready ( struct eth_de vice * dev )
{
while ( get_reg ( PP_SelfSTAT ) & SI_BUSY )
while ( get_reg ( dev , PP_SelfSTAT ) & SI_BUSY )
;
}
@ -259,12 +271,13 @@ static void cs8900_e2prom_ready(void)
/* read a 16-bit word out of the EEPROM */
/***********************************************************/
int cs8900_e2prom_read ( unsigned char addr , unsigned short * value )
int cs8900_e2prom_read ( struct eth_device * dev ,
u8 addr , u16 * value )
{
cs8900_e2prom_ready ( ) ;
put_reg ( PP_EECMD , EEPROM_READ_CMD | addr ) ;
cs8900_e2prom_ready ( ) ;
* value = get_reg ( PP_EEData ) ;
cs8900_e2prom_ready ( dev ) ;
put_reg ( dev , PP_EECMD , EEPROM_READ_CMD | addr ) ;
cs8900_e2prom_ready ( dev ) ;
* value = get_reg ( dev , PP_EEData ) ;
return 0 ;
}
@ -274,16 +287,51 @@ int cs8900_e2prom_read(unsigned char addr, unsigned short *value)
/* write a 16-bit word into the EEPROM */
/***********************************************************/
int cs8900_e2prom_write ( unsigned char addr , unsigned short value )
int cs8900_e2prom_write ( struct eth_device * dev , u8 addr , u16 value )
{
cs8900_e2prom_ready ( dev ) ;
put_reg ( dev , PP_EECMD , EEPROM_WRITE_EN ) ;
cs8900_e2prom_ready ( dev ) ;
put_reg ( dev , PP_EEData , value ) ;
put_reg ( dev , PP_EECMD , EEPROM_WRITE_CMD | addr ) ;
cs8900_e2prom_ready ( dev ) ;
put_reg ( dev , PP_EECMD , EEPROM_WRITE_DIS ) ;
cs8900_e2prom_ready ( dev ) ;
return 0 ;
}
int cs8900_initialize ( u8 dev_num , int base_addr )
{
cs8900_e2prom_ready ( ) ;
put_reg ( PP_EECMD , EEPROM_WRITE_EN ) ;
cs8900_e2prom_ready ( ) ;
put_reg ( PP_EEData , value ) ;
put_reg ( PP_EECMD , EEPROM_WRITE_CMD | addr ) ;
cs8900_e2prom_ready ( ) ;
put_reg ( PP_EECMD , EEPROM_WRITE_DIS ) ;
cs8900_e2prom_ready ( ) ;
struct eth_device * dev ;
struct cs8900_priv * priv ;
dev = malloc ( sizeof ( * dev ) ) ;
if ( ! dev ) {
free ( dev ) ;
return 0 ;
}
memset ( dev , 0 , sizeof ( * dev ) ) ;
priv = malloc ( sizeof ( * priv ) ) ;
if ( ! priv ) {
free ( priv ) ;
return 0 ;
}
memset ( priv , 0 , sizeof ( * priv ) ) ;
priv - > regs = ( struct cs8900_regs * ) base_addr ;
/* Load MAC address from EEPROM */
cs8900_get_enetaddr ( dev ) ;
dev - > iobase = base_addr ;
dev - > priv = priv ;
dev - > init = cs8900_init ;
dev - > halt = cs8900_halt ;
dev - > send = cs8900_send ;
dev - > recv = cs8900_recv ;
sprintf ( dev - > name , " %s-%hu " , CS8900_DRIVERNAME , dev_num ) ;
eth_register ( dev ) ;
return 0 ;
}