2006-03-24 12:50:17 +03:00
/*
* Ethernet driver for the Atmel AT91RM9200 ( Thunder )
*
* Copyright ( C ) 2003 SAN People ( Pty ) Ltd
*
* Based on an earlier Atmel EMAC macrocell driver by Atmel and Lineo Inc .
* Initial version by Rick Bronson 01 / 11 / 2003
*
* Intel LXT971A PHY support by Christopher Bahns & David Knickerbocker
* ( Polaroid Corporation )
*
* Realtek RTL8201 ( B ) L PHY support by Roman Avramenko < roman @ imsystems . ru >
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version
* 2 of the License , or ( at your option ) any later version .
*/
# include <linux/module.h>
# include <linux/init.h>
# include <linux/config.h>
# include <linux/mii.h>
# include <linux/netdevice.h>
# include <linux/etherdevice.h>
# include <linux/skbuff.h>
# include <linux/dma-mapping.h>
# include <linux/ethtool.h>
# include <linux/platform_device.h>
# include <linux/clk.h>
# include <asm/io.h>
# include <asm/uaccess.h>
# include <asm/mach-types.h>
# include <asm/arch/at91rm9200_emac.h>
# include <asm/arch/gpio.h>
# include <asm/arch/board.h>
# include "at91_ether.h"
# define DRV_NAME "at91_ether"
# define DRV_VERSION "1.0"
static struct net_device * at91_dev ;
2006-06-20 13:50:23 +04:00
static struct timer_list check_timer ;
# define LINK_POLL_INTERVAL (HZ)
2006-03-24 12:50:17 +03:00
/* ..................................................................... */
/*
* Read from a EMAC register .
*/
static inline unsigned long at91_emac_read ( unsigned int reg )
{
void __iomem * emac_base = ( void __iomem * ) AT91_VA_BASE_EMAC ;
return __raw_readl ( emac_base + reg ) ;
}
/*
* Write to a EMAC register .
*/
static inline void at91_emac_write ( unsigned int reg , unsigned long value )
{
void __iomem * emac_base = ( void __iomem * ) AT91_VA_BASE_EMAC ;
__raw_writel ( value , emac_base + reg ) ;
}
/* ........................... PHY INTERFACE ........................... */
/*
* Enable the MDIO bit in MAC control register
* When not called from an interrupt - handler , access to the PHY must be
* protected by a spinlock .
*/
static void enable_mdi ( void )
{
unsigned long ctl ;
ctl = at91_emac_read ( AT91_EMAC_CTL ) ;
at91_emac_write ( AT91_EMAC_CTL , ctl | AT91_EMAC_MPE ) ; /* enable management port */
}
/*
* Disable the MDIO bit in the MAC control register
*/
static void disable_mdi ( void )
{
unsigned long ctl ;
ctl = at91_emac_read ( AT91_EMAC_CTL ) ;
at91_emac_write ( AT91_EMAC_CTL , ctl & ~ AT91_EMAC_MPE ) ; /* disable management port */
}
/*
* Wait until the PHY operation is complete .
*/
static inline void at91_phy_wait ( void ) {
unsigned long timeout = jiffies + 2 ;
while ( ! ( at91_emac_read ( AT91_EMAC_SR ) & AT91_EMAC_SR_IDLE ) ) {
if ( time_after ( jiffies , timeout ) ) {
printk ( " at91_ether: MIO timeout \n " ) ;
break ;
}
cpu_relax ( ) ;
}
}
/*
* Write value to the a PHY register
* Note : MDI interface is assumed to already have been enabled .
*/
static void write_phy ( unsigned char phy_addr , unsigned char address , unsigned int value )
{
at91_emac_write ( AT91_EMAC_MAN , AT91_EMAC_MAN_802_3 | AT91_EMAC_RW_W
| ( ( phy_addr & 0x1f ) < < 23 ) | ( address < < 18 ) | ( value & AT91_EMAC_DATA ) ) ;
/* Wait until IDLE bit in Network Status register is cleared */
at91_phy_wait ( ) ;
}
/*
* Read value stored in a PHY register .
* Note : MDI interface is assumed to already have been enabled .
*/
static void read_phy ( unsigned char phy_addr , unsigned char address , unsigned int * value )
{
at91_emac_write ( AT91_EMAC_MAN , AT91_EMAC_MAN_802_3 | AT91_EMAC_RW_R
| ( ( phy_addr & 0x1f ) < < 23 ) | ( address < < 18 ) ) ;
/* Wait until IDLE bit in Network Status register is cleared */
at91_phy_wait ( ) ;
* value = at91_emac_read ( AT91_EMAC_MAN ) & AT91_EMAC_DATA ;
}
/* ........................... PHY MANAGEMENT .......................... */
/*
* Access the PHY to determine the current link speed and mode , and update the
* MAC accordingly .
* If no link or auto - negotiation is busy , then no changes are made .
*/
2006-06-20 13:50:23 +04:00
static void update_linkspeed ( struct net_device * dev , int silent )
2006-03-24 12:50:17 +03:00
{
struct at91_private * lp = ( struct at91_private * ) dev - > priv ;
unsigned int bmsr , bmcr , lpa , mac_cfg ;
unsigned int speed , duplex ;
if ( ! mii_link_ok ( & lp - > mii ) ) { /* no link */
netif_carrier_off ( dev ) ;
2006-06-20 13:50:23 +04:00
if ( ! silent )
printk ( KERN_INFO " %s: Link down. \n " , dev - > name ) ;
2006-03-24 12:50:17 +03:00
return ;
}
/* Link up, or auto-negotiation still in progress */
read_phy ( lp - > phy_address , MII_BMSR , & bmsr ) ;
read_phy ( lp - > phy_address , MII_BMCR , & bmcr ) ;
if ( bmcr & BMCR_ANENABLE ) { /* AutoNegotiation is enabled */
if ( ! ( bmsr & BMSR_ANEGCOMPLETE ) )
return ; /* Do nothing - another interrupt generated when negotiation complete */
read_phy ( lp - > phy_address , MII_LPA , & lpa ) ;
if ( ( lpa & LPA_100FULL ) | | ( lpa & LPA_100HALF ) ) speed = SPEED_100 ;
else speed = SPEED_10 ;
if ( ( lpa & LPA_100FULL ) | | ( lpa & LPA_10FULL ) ) duplex = DUPLEX_FULL ;
else duplex = DUPLEX_HALF ;
} else {
speed = ( bmcr & BMCR_SPEED100 ) ? SPEED_100 : SPEED_10 ;
duplex = ( bmcr & BMCR_FULLDPLX ) ? DUPLEX_FULL : DUPLEX_HALF ;
}
/* Update the MAC */
mac_cfg = at91_emac_read ( AT91_EMAC_CFG ) & ~ ( AT91_EMAC_SPD | AT91_EMAC_FD ) ;
if ( speed = = SPEED_100 ) {
if ( duplex = = DUPLEX_FULL ) /* 100 Full Duplex */
mac_cfg | = AT91_EMAC_SPD | AT91_EMAC_FD ;
else /* 100 Half Duplex */
mac_cfg | = AT91_EMAC_SPD ;
} else {
if ( duplex = = DUPLEX_FULL ) /* 10 Full Duplex */
mac_cfg | = AT91_EMAC_FD ;
else { } /* 10 Half Duplex */
}
at91_emac_write ( AT91_EMAC_CFG , mac_cfg ) ;
2006-06-20 13:50:23 +04:00
if ( ! silent )
printk ( KERN_INFO " %s: Link now %i-%s \n " , dev - > name , speed , ( duplex = = DUPLEX_FULL ) ? " FullDuplex " : " HalfDuplex " ) ;
2006-03-24 12:50:17 +03:00
netif_carrier_on ( dev ) ;
}
/*
* Handle interrupts from the PHY
*/
static irqreturn_t at91ether_phy_interrupt ( int irq , void * dev_id , struct pt_regs * regs )
{
struct net_device * dev = ( struct net_device * ) dev_id ;
struct at91_private * lp = ( struct at91_private * ) dev - > priv ;
unsigned int phy ;
/*
* This hander is triggered on both edges , but the PHY chips expect
* level - triggering . We therefore have to check if the PHY actually has
* an IRQ pending .
*/
enable_mdi ( ) ;
if ( ( lp - > phy_type = = MII_DM9161_ID ) | | ( lp - > phy_type = = MII_DM9161A_ID ) ) {
read_phy ( lp - > phy_address , MII_DSINTR_REG , & phy ) ; /* ack interrupt in Davicom PHY */
if ( ! ( phy & ( 1 < < 0 ) ) )
goto done ;
}
else if ( lp - > phy_type = = MII_LXT971A_ID ) {
read_phy ( lp - > phy_address , MII_ISINTS_REG , & phy ) ; /* ack interrupt in Intel PHY */
if ( ! ( phy & ( 1 < < 2 ) ) )
goto done ;
}
else if ( lp - > phy_type = = MII_BCM5221_ID ) {
read_phy ( lp - > phy_address , MII_BCMINTR_REG , & phy ) ; /* ack interrupt in Broadcom PHY */
if ( ! ( phy & ( 1 < < 0 ) ) )
goto done ;
}
else if ( lp - > phy_type = = MII_KS8721_ID ) {
read_phy ( lp - > phy_address , MII_TPISTATUS , & phy ) ; /* ack interrupt in Micrel PHY */
if ( ! ( phy & ( ( 1 < < 2 ) | 1 ) ) )
goto done ;
}
2006-06-20 13:50:23 +04:00
update_linkspeed ( dev , 0 ) ;
2006-03-24 12:50:17 +03:00
done :
disable_mdi ( ) ;
return IRQ_HANDLED ;
}
/*
* Initialize and enable the PHY interrupt for link - state changes
*/
static void enable_phyirq ( struct net_device * dev )
{
struct at91_private * lp = ( struct at91_private * ) dev - > priv ;
unsigned int dsintr , irq_number ;
int status ;
2006-06-20 13:50:23 +04:00
irq_number = lp - > board_data . phy_irq_pin ;
if ( ! irq_number ) {
/*
* PHY doesn ' t have an IRQ pin ( RTL8201 , DP83847 , AC101L ) ,
* or board does not have it connected .
*/
check_timer . expires = jiffies + LINK_POLL_INTERVAL ;
add_timer ( & check_timer ) ;
2006-03-24 12:50:17 +03:00
return ;
2006-06-20 13:50:23 +04:00
}
2006-03-24 12:50:17 +03:00
status = request_irq ( irq_number , at91ether_phy_interrupt , 0 , dev - > name , dev ) ;
if ( status ) {
printk ( KERN_ERR " at91_ether: PHY IRQ %d request failed - status %d! \n " , irq_number , status ) ;
return ;
}
spin_lock_irq ( & lp - > lock ) ;
enable_mdi ( ) ;
if ( ( lp - > phy_type = = MII_DM9161_ID ) | | ( lp - > phy_type = = MII_DM9161A_ID ) ) { /* for Davicom PHY */
read_phy ( lp - > phy_address , MII_DSINTR_REG , & dsintr ) ;
dsintr = dsintr & ~ 0xf00 ; /* clear bits 8..11 */
write_phy ( lp - > phy_address , MII_DSINTR_REG , dsintr ) ;
}
else if ( lp - > phy_type = = MII_LXT971A_ID ) { /* for Intel PHY */
read_phy ( lp - > phy_address , MII_ISINTE_REG , & dsintr ) ;
dsintr = dsintr | 0xf2 ; /* set bits 1, 4..7 */
write_phy ( lp - > phy_address , MII_ISINTE_REG , dsintr ) ;
}
else if ( lp - > phy_type = = MII_BCM5221_ID ) { /* for Broadcom PHY */
dsintr = ( 1 < < 15 ) | ( 1 < < 14 ) ;
write_phy ( lp - > phy_address , MII_BCMINTR_REG , dsintr ) ;
}
else if ( lp - > phy_type = = MII_KS8721_ID ) { /* for Micrel PHY */
dsintr = ( 1 < < 10 ) | ( 1 < < 8 ) ;
write_phy ( lp - > phy_address , MII_TPISTATUS , dsintr ) ;
}
disable_mdi ( ) ;
spin_unlock_irq ( & lp - > lock ) ;
}
/*
* Disable the PHY interrupt
*/
static void disable_phyirq ( struct net_device * dev )
{
struct at91_private * lp = ( struct at91_private * ) dev - > priv ;
unsigned int dsintr ;
unsigned int irq_number ;
2006-06-20 13:50:23 +04:00
irq_number = lp - > board_data . phy_irq_pin ;
if ( ! irq_number ) {
del_timer_sync ( & check_timer ) ;
2006-03-24 12:50:17 +03:00
return ;
2006-06-20 13:50:23 +04:00
}
2006-03-24 12:50:17 +03:00
spin_lock_irq ( & lp - > lock ) ;
enable_mdi ( ) ;
if ( ( lp - > phy_type = = MII_DM9161_ID ) | | ( lp - > phy_type = = MII_DM9161A_ID ) ) { /* for Davicom PHY */
read_phy ( lp - > phy_address , MII_DSINTR_REG , & dsintr ) ;
dsintr = dsintr | 0xf00 ; /* set bits 8..11 */
write_phy ( lp - > phy_address , MII_DSINTR_REG , dsintr ) ;
}
else if ( lp - > phy_type = = MII_LXT971A_ID ) { /* for Intel PHY */
read_phy ( lp - > phy_address , MII_ISINTE_REG , & dsintr ) ;
dsintr = dsintr & ~ 0xf2 ; /* clear bits 1, 4..7 */
write_phy ( lp - > phy_address , MII_ISINTE_REG , dsintr ) ;
}
else if ( lp - > phy_type = = MII_BCM5221_ID ) { /* for Broadcom PHY */
read_phy ( lp - > phy_address , MII_BCMINTR_REG , & dsintr ) ;
dsintr = ~ ( 1 < < 14 ) ;
write_phy ( lp - > phy_address , MII_BCMINTR_REG , dsintr ) ;
}
else if ( lp - > phy_type = = MII_KS8721_ID ) { /* for Micrel PHY */
read_phy ( lp - > phy_address , MII_TPISTATUS , & dsintr ) ;
dsintr = ~ ( ( 1 < < 10 ) | ( 1 < < 8 ) ) ;
write_phy ( lp - > phy_address , MII_TPISTATUS , dsintr ) ;
}
disable_mdi ( ) ;
spin_unlock_irq ( & lp - > lock ) ;
free_irq ( irq_number , dev ) ; /* Free interrupt handler */
}
/*
* Perform a software reset of the PHY .
*/
#if 0
static void reset_phy ( struct net_device * dev )
{
struct at91_private * lp = ( struct at91_private * ) dev - > priv ;
unsigned int bmcr ;
spin_lock_irq ( & lp - > lock ) ;
enable_mdi ( ) ;
/* Perform PHY reset */
write_phy ( lp - > phy_address , MII_BMCR , BMCR_RESET ) ;
/* Wait until PHY reset is complete */
do {
read_phy ( lp - > phy_address , MII_BMCR , & bmcr ) ;
} while ( ! ( bmcr & & BMCR_RESET ) ) ;
disable_mdi ( ) ;
spin_unlock_irq ( & lp - > lock ) ;
}
# endif
2006-06-20 13:50:23 +04:00
static void at91ether_check_link ( unsigned long dev_id )
{
struct net_device * dev = ( struct net_device * ) dev_id ;
enable_mdi ( ) ;
update_linkspeed ( dev , 1 ) ;
disable_mdi ( ) ;
check_timer . expires = jiffies + LINK_POLL_INTERVAL ;
add_timer ( & check_timer ) ;
}
2006-03-24 12:50:17 +03:00
/* ......................... ADDRESS MANAGEMENT ........................ */
/*
* NOTE : Your bootloader must always set the MAC address correctly before
* booting into Linux .
*
* - It must always set the MAC address after reset , even if it doesn ' t
* happen to access the Ethernet while it ' s booting . Some versions of
* U - Boot on the AT91RM9200 - DK do not do this .
*
* - Likewise it must store the addresses in the correct byte order .
* MicroMonitor ( uMon ) on the CSB337 does this incorrectly ( and
* continues to do so , for bug - compatibility ) .
*/
static short __init unpack_mac_address ( struct net_device * dev , unsigned int hi , unsigned int lo )
{
char addr [ 6 ] ;
if ( machine_is_csb337 ( ) ) {
addr [ 5 ] = ( lo & 0xff ) ; /* The CSB337 bootloader stores the MAC the wrong-way around */
addr [ 4 ] = ( lo & 0xff00 ) > > 8 ;
addr [ 3 ] = ( lo & 0xff0000 ) > > 16 ;
addr [ 2 ] = ( lo & 0xff000000 ) > > 24 ;
addr [ 1 ] = ( hi & 0xff ) ;
addr [ 0 ] = ( hi & 0xff00 ) > > 8 ;
}
else {
addr [ 0 ] = ( lo & 0xff ) ;
addr [ 1 ] = ( lo & 0xff00 ) > > 8 ;
addr [ 2 ] = ( lo & 0xff0000 ) > > 16 ;
addr [ 3 ] = ( lo & 0xff000000 ) > > 24 ;
addr [ 4 ] = ( hi & 0xff ) ;
addr [ 5 ] = ( hi & 0xff00 ) > > 8 ;
}
if ( is_valid_ether_addr ( addr ) ) {
memcpy ( dev - > dev_addr , & addr , 6 ) ;
return 1 ;
}
return 0 ;
}
/*
* Set the ethernet MAC address in dev - > dev_addr
*/
static void __init get_mac_address ( struct net_device * dev )
{
/* Check Specific-Address 1 */
if ( unpack_mac_address ( dev , at91_emac_read ( AT91_EMAC_SA1H ) , at91_emac_read ( AT91_EMAC_SA1L ) ) )
return ;
/* Check Specific-Address 2 */
if ( unpack_mac_address ( dev , at91_emac_read ( AT91_EMAC_SA2H ) , at91_emac_read ( AT91_EMAC_SA2L ) ) )
return ;
/* Check Specific-Address 3 */
if ( unpack_mac_address ( dev , at91_emac_read ( AT91_EMAC_SA3H ) , at91_emac_read ( AT91_EMAC_SA3L ) ) )
return ;
/* Check Specific-Address 4 */
if ( unpack_mac_address ( dev , at91_emac_read ( AT91_EMAC_SA4H ) , at91_emac_read ( AT91_EMAC_SA4L ) ) )
return ;
printk ( KERN_ERR " at91_ether: Your bootloader did not configure a MAC address. \n " ) ;
}
/*
* Program the hardware MAC address from dev - > dev_addr .
*/
static void update_mac_address ( struct net_device * dev )
{
at91_emac_write ( AT91_EMAC_SA1L , ( dev - > dev_addr [ 3 ] < < 24 ) | ( dev - > dev_addr [ 2 ] < < 16 ) | ( dev - > dev_addr [ 1 ] < < 8 ) | ( dev - > dev_addr [ 0 ] ) ) ;
at91_emac_write ( AT91_EMAC_SA1H , ( dev - > dev_addr [ 5 ] < < 8 ) | ( dev - > dev_addr [ 4 ] ) ) ;
at91_emac_write ( AT91_EMAC_SA2L , 0 ) ;
at91_emac_write ( AT91_EMAC_SA2H , 0 ) ;
}
/*
* Store the new hardware address in dev - > dev_addr , and update the MAC .
*/
static int set_mac_address ( struct net_device * dev , void * addr )
{
struct sockaddr * address = addr ;
if ( ! is_valid_ether_addr ( address - > sa_data ) )
return - EADDRNOTAVAIL ;
memcpy ( dev - > dev_addr , address - > sa_data , dev - > addr_len ) ;
update_mac_address ( dev ) ;
printk ( " %s: Setting MAC address to %02x:%02x:%02x:%02x:%02x:%02x \n " , dev - > name ,
dev - > dev_addr [ 0 ] , dev - > dev_addr [ 1 ] , dev - > dev_addr [ 2 ] ,
dev - > dev_addr [ 3 ] , dev - > dev_addr [ 4 ] , dev - > dev_addr [ 5 ] ) ;
return 0 ;
}
static int inline hash_bit_value ( int bitnr , __u8 * addr )
{
if ( addr [ bitnr / 8 ] & ( 1 < < ( bitnr % 8 ) ) )
return 1 ;
return 0 ;
}
/*
* The hash address register is 64 bits long and takes up two locations in the memory map .
* The least significant bits are stored in EMAC_HSL and the most significant
* bits in EMAC_HSH .
*
* The unicast hash enable and the multicast hash enable bits in the network configuration
* register enable the reception of hash matched frames . The destination address is
* reduced to a 6 bit index into the 64 bit hash register using the following hash function .
* The hash function is an exclusive or of every sixth bit of the destination address .
* hash_index [ 5 ] = da [ 5 ] ^ da [ 11 ] ^ da [ 17 ] ^ da [ 23 ] ^ da [ 29 ] ^ da [ 35 ] ^ da [ 41 ] ^ da [ 47 ]
* hash_index [ 4 ] = da [ 4 ] ^ da [ 10 ] ^ da [ 16 ] ^ da [ 22 ] ^ da [ 28 ] ^ da [ 34 ] ^ da [ 40 ] ^ da [ 46 ]
* hash_index [ 3 ] = da [ 3 ] ^ da [ 09 ] ^ da [ 15 ] ^ da [ 21 ] ^ da [ 27 ] ^ da [ 33 ] ^ da [ 39 ] ^ da [ 45 ]
* hash_index [ 2 ] = da [ 2 ] ^ da [ 08 ] ^ da [ 14 ] ^ da [ 20 ] ^ da [ 26 ] ^ da [ 32 ] ^ da [ 38 ] ^ da [ 44 ]
* hash_index [ 1 ] = da [ 1 ] ^ da [ 07 ] ^ da [ 13 ] ^ da [ 19 ] ^ da [ 25 ] ^ da [ 31 ] ^ da [ 37 ] ^ da [ 43 ]
* hash_index [ 0 ] = da [ 0 ] ^ da [ 06 ] ^ da [ 12 ] ^ da [ 18 ] ^ da [ 24 ] ^ da [ 30 ] ^ da [ 36 ] ^ da [ 42 ]
* da [ 0 ] represents the least significant bit of the first byte received , that is , the multicast /
* unicast indicator , and da [ 47 ] represents the most significant bit of the last byte
* received .
* If the hash index points to a bit that is set in the hash register then the frame will be
* matched according to whether the frame is multicast or unicast .
* A multicast match will be signalled if the multicast hash enable bit is set , da [ 0 ] is 1 and
* the hash index points to a bit set in the hash register .
* A unicast match will be signalled if the unicast hash enable bit is set , da [ 0 ] is 0 and the
* hash index points to a bit set in the hash register .
* To receive all multicast frames , the hash register should be set with all ones and the
* multicast hash enable bit should be set in the network configuration register .
*/
/*
* Return the hash index value for the specified address .
*/
static int hash_get_index ( __u8 * addr )
{
int i , j , bitval ;
int hash_index = 0 ;
for ( j = 0 ; j < 6 ; j + + ) {
for ( i = 0 , bitval = 0 ; i < 8 ; i + + )
bitval ^ = hash_bit_value ( i * 6 + j , addr ) ;
hash_index | = ( bitval < < j ) ;
}
2006-06-20 14:10:57 +04:00
return hash_index ;
2006-03-24 12:50:17 +03:00
}
/*
* Add multicast addresses to the internal multicast - hash table .
*/
static void at91ether_sethashtable ( struct net_device * dev )
{
struct dev_mc_list * curr ;
unsigned long mc_filter [ 2 ] ;
unsigned int i , bitnr ;
mc_filter [ 0 ] = mc_filter [ 1 ] = 0 ;
curr = dev - > mc_list ;
for ( i = 0 ; i < dev - > mc_count ; i + + , curr = curr - > next ) {
if ( ! curr ) break ; /* unexpected end of list */
bitnr = hash_get_index ( curr - > dmi_addr ) ;
mc_filter [ bitnr > > 5 ] | = 1 < < ( bitnr & 31 ) ;
}
at91_emac_write ( AT91_EMAC_HSH , mc_filter [ 0 ] ) ;
at91_emac_write ( AT91_EMAC_HSL , mc_filter [ 1 ] ) ;
}
/*
* Enable / Disable promiscuous and multicast modes .
*/
static void at91ether_set_rx_mode ( struct net_device * dev )
{
unsigned long cfg ;
cfg = at91_emac_read ( AT91_EMAC_CFG ) ;
if ( dev - > flags & IFF_PROMISC ) /* Enable promiscuous mode */
cfg | = AT91_EMAC_CAF ;
else if ( dev - > flags & ( ~ IFF_PROMISC ) ) /* Disable promiscuous mode */
cfg & = ~ AT91_EMAC_CAF ;
if ( dev - > flags & IFF_ALLMULTI ) { /* Enable all multicast mode */
at91_emac_write ( AT91_EMAC_HSH , - 1 ) ;
at91_emac_write ( AT91_EMAC_HSL , - 1 ) ;
cfg | = AT91_EMAC_MTI ;
} else if ( dev - > mc_count > 0 ) { /* Enable specific multicasts */
at91ether_sethashtable ( dev ) ;
cfg | = AT91_EMAC_MTI ;
} else if ( dev - > flags & ( ~ IFF_ALLMULTI ) ) { /* Disable all multicast mode */
at91_emac_write ( AT91_EMAC_HSH , 0 ) ;
at91_emac_write ( AT91_EMAC_HSL , 0 ) ;
cfg & = ~ AT91_EMAC_MTI ;
}
at91_emac_write ( AT91_EMAC_CFG , cfg ) ;
}
/* ......................... ETHTOOL SUPPORT ........................... */
static int mdio_read ( struct net_device * dev , int phy_id , int location )
{
unsigned int value ;
read_phy ( phy_id , location , & value ) ;
return value ;
}
static void mdio_write ( struct net_device * dev , int phy_id , int location , int value )
{
write_phy ( phy_id , location , value ) ;
}
static int at91ether_get_settings ( struct net_device * dev , struct ethtool_cmd * cmd )
{
struct at91_private * lp = ( struct at91_private * ) dev - > priv ;
int ret ;
spin_lock_irq ( & lp - > lock ) ;
enable_mdi ( ) ;
ret = mii_ethtool_gset ( & lp - > mii , cmd ) ;
disable_mdi ( ) ;
spin_unlock_irq ( & lp - > lock ) ;
if ( lp - > phy_media = = PORT_FIBRE ) { /* override media type since mii.c doesn't know */
cmd - > supported = SUPPORTED_FIBRE ;
cmd - > port = PORT_FIBRE ;
}
return ret ;
}
static int at91ether_set_settings ( struct net_device * dev , struct ethtool_cmd * cmd )
{
struct at91_private * lp = ( struct at91_private * ) dev - > priv ;
int ret ;
spin_lock_irq ( & lp - > lock ) ;
enable_mdi ( ) ;
ret = mii_ethtool_sset ( & lp - > mii , cmd ) ;
disable_mdi ( ) ;
spin_unlock_irq ( & lp - > lock ) ;
return ret ;
}
static int at91ether_nwayreset ( struct net_device * dev )
{
struct at91_private * lp = ( struct at91_private * ) dev - > priv ;
int ret ;
spin_lock_irq ( & lp - > lock ) ;
enable_mdi ( ) ;
ret = mii_nway_restart ( & lp - > mii ) ;
disable_mdi ( ) ;
spin_unlock_irq ( & lp - > lock ) ;
return ret ;
}
static void at91ether_get_drvinfo ( struct net_device * dev , struct ethtool_drvinfo * info )
{
strlcpy ( info - > driver , DRV_NAME , sizeof ( info - > driver ) ) ;
strlcpy ( info - > version , DRV_VERSION , sizeof ( info - > version ) ) ;
strlcpy ( info - > bus_info , dev - > class_dev . dev - > bus_id , sizeof ( info - > bus_info ) ) ;
}
static struct ethtool_ops at91ether_ethtool_ops = {
. get_settings = at91ether_get_settings ,
. set_settings = at91ether_set_settings ,
. get_drvinfo = at91ether_get_drvinfo ,
. nway_reset = at91ether_nwayreset ,
. get_link = ethtool_op_get_link ,
} ;
2006-06-20 13:59:05 +04:00
static int at91ether_ioctl ( struct net_device * dev , struct ifreq * rq , int cmd )
{
struct at91_private * lp = ( struct at91_private * ) dev - > priv ;
int res ;
if ( ! netif_running ( dev ) )
return - EINVAL ;
spin_lock_irq ( & lp - > lock ) ;
enable_mdi ( ) ;
res = generic_mii_ioctl ( & lp - > mii , if_mii ( rq ) , cmd , NULL ) ;
disable_mdi ( ) ;
spin_unlock_irq ( & lp - > lock ) ;
return res ;
}
2006-03-24 12:50:17 +03:00
/* ................................ MAC ................................ */
/*
* Initialize and start the Receiver and Transmit subsystems
*/
static void at91ether_start ( struct net_device * dev )
{
struct at91_private * lp = ( struct at91_private * ) dev - > priv ;
struct recv_desc_bufs * dlist , * dlist_phys ;
int i ;
unsigned long ctl ;
dlist = lp - > dlist ;
dlist_phys = lp - > dlist_phys ;
for ( i = 0 ; i < MAX_RX_DESCR ; i + + ) {
dlist - > descriptors [ i ] . addr = ( unsigned int ) & dlist_phys - > recv_buf [ i ] [ 0 ] ;
dlist - > descriptors [ i ] . size = 0 ;
}
/* Set the Wrap bit on the last descriptor */
dlist - > descriptors [ i - 1 ] . addr | = EMAC_DESC_WRAP ;
/* Reset buffer index */
lp - > rxBuffIndex = 0 ;
/* Program address of descriptor list in Rx Buffer Queue register */
at91_emac_write ( AT91_EMAC_RBQP , ( unsigned long ) dlist_phys ) ;
/* Enable Receive and Transmit */
ctl = at91_emac_read ( AT91_EMAC_CTL ) ;
at91_emac_write ( AT91_EMAC_CTL , ctl | AT91_EMAC_RE | AT91_EMAC_TE ) ;
}
/*
* Open the ethernet interface
*/
static int at91ether_open ( struct net_device * dev )
{
struct at91_private * lp = ( struct at91_private * ) dev - > priv ;
unsigned long ctl ;
2006-06-20 14:10:57 +04:00
if ( ! is_valid_ether_addr ( dev - > dev_addr ) )
return - EADDRNOTAVAIL ;
2006-03-24 12:50:17 +03:00
2006-06-20 14:10:57 +04:00
clk_enable ( lp - > ether_clk ) ; /* Re-enable Peripheral clock */
2006-03-24 12:50:17 +03:00
/* Clear internal statistics */
ctl = at91_emac_read ( AT91_EMAC_CTL ) ;
at91_emac_write ( AT91_EMAC_CTL , ctl | AT91_EMAC_CSR ) ;
/* Update the MAC address (incase user has changed it) */
update_mac_address ( dev ) ;
/* Enable PHY interrupt */
enable_phyirq ( dev ) ;
/* Enable MAC interrupts */
at91_emac_write ( AT91_EMAC_IER , AT91_EMAC_RCOM | AT91_EMAC_RBNA
| AT91_EMAC_TUND | AT91_EMAC_RTRY | AT91_EMAC_TCOM
| AT91_EMAC_ROVR | AT91_EMAC_ABT ) ;
/* Determine current link speed */
spin_lock_irq ( & lp - > lock ) ;
enable_mdi ( ) ;
2006-06-20 13:50:23 +04:00
update_linkspeed ( dev , 0 ) ;
2006-03-24 12:50:17 +03:00
disable_mdi ( ) ;
spin_unlock_irq ( & lp - > lock ) ;
at91ether_start ( dev ) ;
netif_start_queue ( dev ) ;
return 0 ;
}
/*
* Close the interface
*/
static int at91ether_close ( struct net_device * dev )
{
2006-06-20 14:10:57 +04:00
struct at91_private * lp = ( struct at91_private * ) dev - > priv ;
2006-03-24 12:50:17 +03:00
unsigned long ctl ;
/* Disable Receiver and Transmitter */
ctl = at91_emac_read ( AT91_EMAC_CTL ) ;
at91_emac_write ( AT91_EMAC_CTL , ctl & ~ ( AT91_EMAC_TE | AT91_EMAC_RE ) ) ;
/* Disable PHY interrupt */
disable_phyirq ( dev ) ;
/* Disable MAC interrupts */
at91_emac_write ( AT91_EMAC_IDR , AT91_EMAC_RCOM | AT91_EMAC_RBNA
| AT91_EMAC_TUND | AT91_EMAC_RTRY | AT91_EMAC_TCOM
| AT91_EMAC_ROVR | AT91_EMAC_ABT ) ;
netif_stop_queue ( dev ) ;
2006-06-20 14:10:57 +04:00
clk_disable ( lp - > ether_clk ) ; /* Disable Peripheral clock */
2006-03-24 12:50:17 +03:00
return 0 ;
}
/*
* Transmit packet .
*/
static int at91ether_tx ( struct sk_buff * skb , struct net_device * dev )
{
struct at91_private * lp = ( struct at91_private * ) dev - > priv ;
if ( at91_emac_read ( AT91_EMAC_TSR ) & AT91_EMAC_TSR_BNQ ) {
netif_stop_queue ( dev ) ;
/* Store packet information (to free when Tx completed) */
lp - > skb = skb ;
lp - > skb_length = skb - > len ;
lp - > skb_physaddr = dma_map_single ( NULL , skb - > data , skb - > len , DMA_TO_DEVICE ) ;
lp - > stats . tx_bytes + = skb - > len ;
/* Set address of the data in the Transmit Address register */
at91_emac_write ( AT91_EMAC_TAR , lp - > skb_physaddr ) ;
/* Set length of the packet in the Transmit Control register */
at91_emac_write ( AT91_EMAC_TCR , skb - > len ) ;
dev - > trans_start = jiffies ;
} else {
printk ( KERN_ERR " at91_ether.c: at91ether_tx() called, but device is busy! \n " ) ;
return 1 ; /* if we return anything but zero, dev.c:1055 calls kfree_skb(skb)
on this skb , he also reports - ENETDOWN and printk ' s , so either
we free and return ( 0 ) or don ' t free and return 1 */
}
return 0 ;
}
/*
* Update the current statistics from the internal statistics registers .
*/
static struct net_device_stats * at91ether_stats ( struct net_device * dev )
{
struct at91_private * lp = ( struct at91_private * ) dev - > priv ;
int ale , lenerr , seqe , lcol , ecol ;
if ( netif_running ( dev ) ) {
lp - > stats . rx_packets + = at91_emac_read ( AT91_EMAC_OK ) ; /* Good frames received */
ale = at91_emac_read ( AT91_EMAC_ALE ) ;
lp - > stats . rx_frame_errors + = ale ; /* Alignment errors */
lenerr = at91_emac_read ( AT91_EMAC_ELR ) + at91_emac_read ( AT91_EMAC_USF ) ;
lp - > stats . rx_length_errors + = lenerr ; /* Excessive Length or Undersize Frame error */
seqe = at91_emac_read ( AT91_EMAC_SEQE ) ;
lp - > stats . rx_crc_errors + = seqe ; /* CRC error */
lp - > stats . rx_fifo_errors + = at91_emac_read ( AT91_EMAC_DRFC ) ; /* Receive buffer not available */
lp - > stats . rx_errors + = ( ale + lenerr + seqe
+ at91_emac_read ( AT91_EMAC_CDE ) + at91_emac_read ( AT91_EMAC_RJB ) ) ;
lp - > stats . tx_packets + = at91_emac_read ( AT91_EMAC_FRA ) ; /* Frames successfully transmitted */
lp - > stats . tx_fifo_errors + = at91_emac_read ( AT91_EMAC_TUE ) ; /* Transmit FIFO underruns */
lp - > stats . tx_carrier_errors + = at91_emac_read ( AT91_EMAC_CSE ) ; /* Carrier Sense errors */
lp - > stats . tx_heartbeat_errors + = at91_emac_read ( AT91_EMAC_SQEE ) ; /* Heartbeat error */
lcol = at91_emac_read ( AT91_EMAC_LCOL ) ;
ecol = at91_emac_read ( AT91_EMAC_ECOL ) ;
lp - > stats . tx_window_errors + = lcol ; /* Late collisions */
lp - > stats . tx_aborted_errors + = ecol ; /* 16 collisions */
lp - > stats . collisions + = ( at91_emac_read ( AT91_EMAC_SCOL ) + at91_emac_read ( AT91_EMAC_MCOL ) + lcol + ecol ) ;
}
return & lp - > stats ;
}
/*
* Extract received frame from buffer descriptors and sent to upper layers .
* ( Called from interrupt context )
*/
static void at91ether_rx ( struct net_device * dev )
{
struct at91_private * lp = ( struct at91_private * ) dev - > priv ;
struct recv_desc_bufs * dlist ;
unsigned char * p_recv ;
struct sk_buff * skb ;
unsigned int pktlen ;
dlist = lp - > dlist ;
while ( dlist - > descriptors [ lp - > rxBuffIndex ] . addr & EMAC_DESC_DONE ) {
p_recv = dlist - > recv_buf [ lp - > rxBuffIndex ] ;
pktlen = dlist - > descriptors [ lp - > rxBuffIndex ] . size & 0x7ff ; /* Length of frame including FCS */
skb = alloc_skb ( pktlen + 2 , GFP_ATOMIC ) ;
if ( skb ! = NULL ) {
skb_reserve ( skb , 2 ) ;
memcpy ( skb_put ( skb , pktlen ) , p_recv , pktlen ) ;
skb - > dev = dev ;
skb - > protocol = eth_type_trans ( skb , dev ) ;
skb - > len = pktlen ;
dev - > last_rx = jiffies ;
lp - > stats . rx_bytes + = pktlen ;
netif_rx ( skb ) ;
}
else {
lp - > stats . rx_dropped + = 1 ;
printk ( KERN_NOTICE " %s: Memory squeeze, dropping packet. \n " , dev - > name ) ;
}
if ( dlist - > descriptors [ lp - > rxBuffIndex ] . size & EMAC_MULTICAST )
lp - > stats . multicast + + ;
dlist - > descriptors [ lp - > rxBuffIndex ] . addr & = ~ EMAC_DESC_DONE ; /* reset ownership bit */
if ( lp - > rxBuffIndex = = MAX_RX_DESCR - 1 ) /* wrap after last buffer */
lp - > rxBuffIndex = 0 ;
else
lp - > rxBuffIndex + + ;
}
}
/*
* MAC interrupt handler
*/
static irqreturn_t at91ether_interrupt ( int irq , void * dev_id , struct pt_regs * regs )
{
struct net_device * dev = ( struct net_device * ) dev_id ;
struct at91_private * lp = ( struct at91_private * ) dev - > priv ;
unsigned long intstatus , ctl ;
/* MAC Interrupt Status register indicates what interrupts are pending.
It is automatically cleared once read . */
intstatus = at91_emac_read ( AT91_EMAC_ISR ) ;
if ( intstatus & AT91_EMAC_RCOM ) /* Receive complete */
at91ether_rx ( dev ) ;
2006-06-20 14:10:57 +04:00
if ( intstatus & AT91_EMAC_TCOM ) { /* Transmit complete */
2006-03-24 12:50:17 +03:00
/* The TCOM bit is set even if the transmission failed. */
if ( intstatus & ( AT91_EMAC_TUND | AT91_EMAC_RTRY ) )
lp - > stats . tx_errors + = 1 ;
if ( lp - > skb ) {
dev_kfree_skb_irq ( lp - > skb ) ;
lp - > skb = NULL ;
dma_unmap_single ( NULL , lp - > skb_physaddr , lp - > skb_length , DMA_TO_DEVICE ) ;
}
netif_wake_queue ( dev ) ;
}
/* Work-around for Errata #11 */
if ( intstatus & AT91_EMAC_RBNA ) {
ctl = at91_emac_read ( AT91_EMAC_CTL ) ;
at91_emac_write ( AT91_EMAC_CTL , ctl & ~ AT91_EMAC_RE ) ;
at91_emac_write ( AT91_EMAC_CTL , ctl | AT91_EMAC_RE ) ;
}
if ( intstatus & AT91_EMAC_ROVR )
printk ( " %s: ROVR error \n " , dev - > name ) ;
return IRQ_HANDLED ;
}
/*
* Initialize the ethernet interface
*/
2006-06-20 14:10:57 +04:00
static int __init at91ether_setup ( unsigned long phy_type , unsigned short phy_address ,
struct platform_device * pdev , struct clk * ether_clk )
2006-03-24 12:50:17 +03:00
{
struct at91_eth_data * board_data = pdev - > dev . platform_data ;
struct net_device * dev ;
struct at91_private * lp ;
unsigned int val ;
int res ;
if ( at91_dev ) /* already initialized */
return 0 ;
dev = alloc_etherdev ( sizeof ( struct at91_private ) ) ;
if ( ! dev )
return - ENOMEM ;
dev - > base_addr = AT91_VA_BASE_EMAC ;
dev - > irq = AT91_ID_EMAC ;
SET_MODULE_OWNER ( dev ) ;
/* Install the interrupt handler */
if ( request_irq ( dev - > irq , at91ether_interrupt , 0 , dev - > name , dev ) ) {
free_netdev ( dev ) ;
return - EBUSY ;
}
/* Allocate memory for DMA Receive descriptors */
lp = ( struct at91_private * ) dev - > priv ;
lp - > dlist = ( struct recv_desc_bufs * ) dma_alloc_coherent ( NULL , sizeof ( struct recv_desc_bufs ) , ( dma_addr_t * ) & lp - > dlist_phys , GFP_KERNEL ) ;
if ( lp - > dlist = = NULL ) {
free_irq ( dev - > irq , dev ) ;
free_netdev ( dev ) ;
return - ENOMEM ;
}
lp - > board_data = * board_data ;
2006-06-20 14:10:57 +04:00
lp - > ether_clk = ether_clk ;
2006-03-24 12:50:17 +03:00
platform_set_drvdata ( pdev , dev ) ;
spin_lock_init ( & lp - > lock ) ;
ether_setup ( dev ) ;
dev - > open = at91ether_open ;
dev - > stop = at91ether_close ;
dev - > hard_start_xmit = at91ether_tx ;
dev - > get_stats = at91ether_stats ;
dev - > set_multicast_list = at91ether_set_rx_mode ;
dev - > set_mac_address = set_mac_address ;
dev - > ethtool_ops = & at91ether_ethtool_ops ;
2006-06-20 13:59:05 +04:00
dev - > do_ioctl = at91ether_ioctl ;
2006-03-24 12:50:17 +03:00
SET_NETDEV_DEV ( dev , & pdev - > dev ) ;
get_mac_address ( dev ) ; /* Get ethernet address and store it in dev->dev_addr */
update_mac_address ( dev ) ; /* Program ethernet address into MAC */
at91_emac_write ( AT91_EMAC_CTL , 0 ) ;
if ( lp - > board_data . is_rmii )
at91_emac_write ( AT91_EMAC_CFG , AT91_EMAC_CLK_DIV32 | AT91_EMAC_BIG | AT91_EMAC_RMII ) ;
else
at91_emac_write ( AT91_EMAC_CFG , AT91_EMAC_CLK_DIV32 | AT91_EMAC_BIG ) ;
/* Perform PHY-specific initialization */
spin_lock_irq ( & lp - > lock ) ;
enable_mdi ( ) ;
if ( ( phy_type = = MII_DM9161_ID ) | | ( lp - > phy_type = = MII_DM9161A_ID ) ) {
read_phy ( phy_address , MII_DSCR_REG , & val ) ;
if ( ( val & ( 1 < < 10 ) ) = = 0 ) /* DSCR bit 10 is 0 -- fiber mode */
lp - > phy_media = PORT_FIBRE ;
} else if ( machine_is_csb337 ( ) ) {
/* mix link activity status into LED2 link state */
write_phy ( phy_address , MII_LEDCTRL_REG , 0x0d22 ) ;
}
disable_mdi ( ) ;
spin_unlock_irq ( & lp - > lock ) ;
lp - > mii . dev = dev ; /* Support for ethtool */
lp - > mii . mdio_read = mdio_read ;
lp - > mii . mdio_write = mdio_write ;
2006-06-20 13:59:05 +04:00
lp - > mii . phy_id = phy_address ;
lp - > mii . phy_id_mask = 0x1f ;
lp - > mii . reg_num_mask = 0x1f ;
2006-03-24 12:50:17 +03:00
lp - > phy_type = phy_type ; /* Type of PHY connected */
lp - > phy_address = phy_address ; /* MDI address of PHY */
/* Register the network interface */
res = register_netdev ( dev ) ;
if ( res ) {
free_irq ( dev - > irq , dev ) ;
free_netdev ( dev ) ;
dma_free_coherent ( NULL , sizeof ( struct recv_desc_bufs ) , lp - > dlist , ( dma_addr_t ) lp - > dlist_phys ) ;
return res ;
}
at91_dev = dev ;
/* Determine current link speed */
spin_lock_irq ( & lp - > lock ) ;
enable_mdi ( ) ;
2006-06-20 13:50:23 +04:00
update_linkspeed ( dev , 0 ) ;
2006-03-24 12:50:17 +03:00
disable_mdi ( ) ;
spin_unlock_irq ( & lp - > lock ) ;
netif_carrier_off ( dev ) ; /* will be enabled in open() */
2006-06-20 13:50:23 +04:00
/* If board has no PHY IRQ, use a timer to poll the PHY */
if ( ! lp - > board_data . phy_irq_pin ) {
init_timer ( & check_timer ) ;
check_timer . data = ( unsigned long ) dev ;
check_timer . function = at91ether_check_link ;
}
2006-03-24 12:50:17 +03:00
/* Display ethernet banner */
printk ( KERN_INFO " %s: AT91 ethernet at 0x%08x int=%d %s%s (%02x:%02x:%02x:%02x:%02x:%02x) \n " ,
dev - > name , ( uint ) dev - > base_addr , dev - > irq ,
at91_emac_read ( AT91_EMAC_CFG ) & AT91_EMAC_SPD ? " 100- " : " 10- " ,
at91_emac_read ( AT91_EMAC_CFG ) & AT91_EMAC_FD ? " FullDuplex " : " HalfDuplex " ,
dev - > dev_addr [ 0 ] , dev - > dev_addr [ 1 ] , dev - > dev_addr [ 2 ] ,
dev - > dev_addr [ 3 ] , dev - > dev_addr [ 4 ] , dev - > dev_addr [ 5 ] ) ;
if ( ( phy_type = = MII_DM9161_ID ) | | ( lp - > phy_type = = MII_DM9161A_ID ) )
2006-06-20 14:10:57 +04:00
printk ( KERN_INFO " %s: Davicom 9161 PHY %s \n " , dev - > name , ( lp - > phy_media = = PORT_FIBRE ) ? " (Fiber) " : " (Copper) " ) ;
2006-03-24 12:50:17 +03:00
else if ( phy_type = = MII_LXT971A_ID )
printk ( KERN_INFO " %s: Intel LXT971A PHY \n " , dev - > name ) ;
else if ( phy_type = = MII_RTL8201_ID )
printk ( KERN_INFO " %s: Realtek RTL8201(B)L PHY \n " , dev - > name ) ;
else if ( phy_type = = MII_BCM5221_ID )
printk ( KERN_INFO " %s: Broadcom BCM5221 PHY \n " , dev - > name ) ;
else if ( phy_type = = MII_DP83847_ID )
printk ( KERN_INFO " %s: National Semiconductor DP83847 PHY \n " , dev - > name ) ;
else if ( phy_type = = MII_AC101L_ID )
printk ( KERN_INFO " %s: Altima AC101L PHY \n " , dev - > name ) ;
else if ( phy_type = = MII_KS8721_ID )
printk ( KERN_INFO " %s: Micrel KS8721 PHY \n " , dev - > name ) ;
return 0 ;
}
/*
* Detect MAC and PHY and perform initialization
*/
static int __init at91ether_probe ( struct platform_device * pdev )
{
unsigned int phyid1 , phyid2 ;
int detected = - 1 ;
unsigned long phy_id ;
unsigned short phy_address = 0 ;
2006-06-20 14:10:57 +04:00
struct clk * ether_clk ;
2006-03-24 12:50:17 +03:00
ether_clk = clk_get ( & pdev - > dev , " ether_clk " ) ;
2006-06-20 14:10:57 +04:00
if ( IS_ERR ( ether_clk ) ) {
2006-03-24 12:50:17 +03:00
printk ( KERN_ERR " at91_ether: no clock defined \n " ) ;
return - ENODEV ;
}
clk_enable ( ether_clk ) ; /* Enable Peripheral clock */
while ( ( detected ! = 0 ) & & ( phy_address < 32 ) ) {
/* Read the PHY ID registers */
enable_mdi ( ) ;
read_phy ( phy_address , MII_PHYSID1 , & phyid1 ) ;
read_phy ( phy_address , MII_PHYSID2 , & phyid2 ) ;
disable_mdi ( ) ;
phy_id = ( phyid1 < < 16 ) | ( phyid2 & 0xfff0 ) ;
switch ( phy_id ) {
case MII_DM9161_ID : /* Davicom 9161: PHY_ID1 = 0x181, PHY_ID2 = B881 */
case MII_DM9161A_ID : /* Davicom 9161A: PHY_ID1 = 0x181, PHY_ID2 = B8A0 */
case MII_LXT971A_ID : /* Intel LXT971A: PHY_ID1 = 0x13, PHY_ID2 = 78E0 */
case MII_RTL8201_ID : /* Realtek RTL8201: PHY_ID1 = 0, PHY_ID2 = 0x8201 */
case MII_BCM5221_ID : /* Broadcom BCM5221: PHY_ID1 = 0x40, PHY_ID2 = 0x61e0 */
case MII_DP83847_ID : /* National Semiconductor DP83847: */
case MII_AC101L_ID : /* Altima AC101L: PHY_ID1 = 0x22, PHY_ID2 = 0x5520 */
case MII_KS8721_ID : /* Micrel KS8721: PHY_ID1 = 0x22, PHY_ID2 = 0x1610 */
2006-06-20 14:10:57 +04:00
detected = at91ether_setup ( phy_id , phy_address , pdev , ether_clk ) ;
2006-03-24 12:50:17 +03:00
break ;
}
phy_address + + ;
}
clk_disable ( ether_clk ) ; /* Disable Peripheral clock */
return detected ;
}
static int __devexit at91ether_remove ( struct platform_device * pdev )
{
struct at91_private * lp = ( struct at91_private * ) at91_dev - > priv ;
unregister_netdev ( at91_dev ) ;
free_irq ( at91_dev - > irq , at91_dev ) ;
dma_free_coherent ( NULL , sizeof ( struct recv_desc_bufs ) , lp - > dlist , ( dma_addr_t ) lp - > dlist_phys ) ;
2006-06-20 14:10:57 +04:00
clk_put ( lp - > ether_clk ) ;
2006-03-24 12:50:17 +03:00
free_netdev ( at91_dev ) ;
at91_dev = NULL ;
return 0 ;
}
static struct platform_driver at91ether_driver = {
. probe = at91ether_probe ,
. remove = __devexit_p ( at91ether_remove ) ,
/* FIXME: support suspend and resume */
. driver = {
. name = DRV_NAME ,
. owner = THIS_MODULE ,
} ,
} ;
static int __init at91ether_init ( void )
{
return platform_driver_register ( & at91ether_driver ) ;
}
static void __exit at91ether_exit ( void )
{
platform_driver_unregister ( & at91ether_driver ) ;
}
module_init ( at91ether_init )
module_exit ( at91ether_exit )
MODULE_LICENSE ( " GPL " ) ;
MODULE_DESCRIPTION ( " AT91RM9200 EMAC Ethernet driver " ) ;
MODULE_AUTHOR ( " Andrew Victor " ) ;