diff mbox

[1/1] AT91: Remove fixed mapping for AT91RM9200 ethernet

Message ID 1329150023-19503-1-git-send-email-plagnioj@jcrosoft.com
State Not Applicable, archived
Delegated to: David Miller
Headers show

Commit Message

Jean-Christophe PLAGNIOL-VILLARD Feb. 13, 2012, 4:20 p.m. UTC
From: Andrew Victor <avictor.za@gmail.com>

The AT91RM9200 Ethernet controller still has a fixed IO mapping.
So:
* Remove the fixed IO mapping and AT91_VA_BASE_EMAC definition.
* Pass the physical base-address via platform-resources to the driver.
* Convert at91_ether.c driver to perform an ioremap().
* Ethernet PHY detection needs to be performed during the driver
initialization process, it can no longer be done first.

Signed-off-by: Andrew Victor <linux@maxim.org.za>
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Cc: netdev@vger.kernel.org
---
Hi David,

	If you don't mind I'll apply it via AT91 tree as it's part of a patch
	series to clean the at91

Best Regards,
J.
 arch/arm/mach-at91/at91rm9200.c            |   10 -
 arch/arm/mach-at91/at91rm9200_devices.c    |    4 +-
 arch/arm/mach-at91/include/mach/hardware.h |    1 -
 drivers/net/ethernet/cadence/at91_ether.c  |  527 +++++++++++++++-------------
 drivers/net/ethernet/cadence/at91_ether.h  |    1 +
 5 files changed, 287 insertions(+), 256 deletions(-)

Comments

Nicolas Ferre April 24, 2012, 8:37 a.m. UTC | #1
On 02/13/2012 05:20 PM, Jean-Christophe PLAGNIOL-VILLARD :
> From: Andrew Victor <avictor.za@gmail.com>
> 
> The AT91RM9200 Ethernet controller still has a fixed IO mapping.
> So:
> * Remove the fixed IO mapping and AT91_VA_BASE_EMAC definition.
> * Pass the physical base-address via platform-resources to the driver.
> * Convert at91_ether.c driver to perform an ioremap().
> * Ethernet PHY detection needs to be performed during the driver
> initialization process, it can no longer be done first.
> 
> Signed-off-by: Andrew Victor <linux@maxim.org.za>
> Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
> Cc: netdev@vger.kernel.org
> ---
> Hi David,
> 
> 	If you don't mind I'll apply it via AT91 tree as it's part of a patch
> 	series to clean the at91

David,

It seems that this patch has not been noticed (which is understandable
as you were not in copy...).

As I have a bug fix for this driver, my question is: will it still be
possible for you to take this one in the net tree for 3.4-rc or will it
have to wait for 3.5?

Depending on your answer, I will send you my bug fix on top of this one
or as an independent patch.

Best regards,

>  arch/arm/mach-at91/at91rm9200.c            |   10 -
>  arch/arm/mach-at91/at91rm9200_devices.c    |    4 +-
>  arch/arm/mach-at91/include/mach/hardware.h |    1 -
>  drivers/net/ethernet/cadence/at91_ether.c  |  527 +++++++++++++++-------------
>  drivers/net/ethernet/cadence/at91_ether.h  |    1 +
>  5 files changed, 287 insertions(+), 256 deletions(-)
> 
> diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c
> index c7efa17..92e0227 100644
> --- a/arch/arm/mach-at91/at91rm9200.c
> +++ b/arch/arm/mach-at91/at91rm9200.c
> @@ -25,15 +25,6 @@
>  #include "clock.h"
>  #include "sam9_smc.h"
>  
> -static struct map_desc at91rm9200_io_desc[] __initdata = {
> -	{
> -		.virtual	= AT91_VA_BASE_EMAC,
> -		.pfn		= __phys_to_pfn(AT91RM9200_BASE_EMAC),
> -		.length		= SZ_16K,
> -		.type		= MT_DEVICE,
> -	},
> -};
> -
>  /* --------------------------------------------------------------------
>   *  Clocks
>   * -------------------------------------------------------------------- */
> @@ -314,7 +305,6 @@ static void __init at91rm9200_map_io(void)
>  {
>  	/* Map peripherals */
>  	at91_init_sram(0, AT91RM9200_SRAM_BASE, AT91RM9200_SRAM_SIZE);
> -	iotable_init(at91rm9200_io_desc, ARRAY_SIZE(at91rm9200_io_desc));
>  }
>  
>  static void __init at91rm9200_ioremap_registers(void)
> diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c
> index aca272b..04d6b16 100644
> --- a/arch/arm/mach-at91/at91rm9200_devices.c
> +++ b/arch/arm/mach-at91/at91rm9200_devices.c
> @@ -140,8 +140,8 @@ static struct macb_platform_data eth_data;
>  
>  static struct resource eth_resources[] = {
>  	[0] = {
> -		.start	= AT91_VA_BASE_EMAC,
> -		.end	= AT91_VA_BASE_EMAC + SZ_16K - 1,
> +		.start	= AT91RM9200_BASE_EMAC,
> +		.end	= AT91RM9200_BASE_EMAC + SZ_16K - 1,
>  		.flags	= IORESOURCE_MEM,
>  	},
>  	[1] = {
> diff --git a/arch/arm/mach-at91/include/mach/hardware.h b/arch/arm/mach-at91/include/mach/hardware.h
> index e9e29a6..01db372 100644
> --- a/arch/arm/mach-at91/include/mach/hardware.h
> +++ b/arch/arm/mach-at91/include/mach/hardware.h
> @@ -94,7 +94,6 @@
>   * Virtual to Physical Address mapping for IO devices.
>   */
>  #define AT91_VA_BASE_SYS	AT91_IO_P2V(AT91_BASE_SYS)
> -#define AT91_VA_BASE_EMAC	AT91_IO_P2V(AT91RM9200_BASE_EMAC)
>  
>   /* Internal SRAM is mapped below the IO devices */
>  #define AT91_SRAM_MAX		SZ_1M
> diff --git a/drivers/net/ethernet/cadence/at91_ether.c b/drivers/net/ethernet/cadence/at91_ether.c
> index 1a5b6ef..2b7d278 100644
> --- a/drivers/net/ethernet/cadence/at91_ether.c
> +++ b/drivers/net/ethernet/cadence/at91_ether.c
> @@ -30,6 +30,7 @@
>  #include <linux/platform_device.h>
>  #include <linux/clk.h>
>  #include <linux/gfp.h>
> +#include <linux/phy.h>
>  
>  #include <asm/io.h>
>  #include <asm/uaccess.h>
> @@ -51,21 +52,17 @@
>  /*
>   * Read from a EMAC register.
>   */
> -static inline unsigned long at91_emac_read(unsigned int reg)
> +static inline unsigned long at91_emac_read(struct at91_private *lp, unsigned int reg)
>  {
> -	void __iomem *emac_base = (void __iomem *)AT91_VA_BASE_EMAC;
> -
> -	return __raw_readl(emac_base + reg);
> +	return __raw_readl(lp->emac_base + reg);
>  }
>  
>  /*
>   * Write to a EMAC register.
>   */
> -static inline void at91_emac_write(unsigned int reg, unsigned long value)
> +static inline void at91_emac_write(struct at91_private *lp, unsigned int reg, unsigned long value)
>  {
> -	void __iomem *emac_base = (void __iomem *)AT91_VA_BASE_EMAC;
> -
> -	__raw_writel(value, emac_base + reg);
> +	__raw_writel(value, lp->emac_base + reg);
>  }
>  
>  /* ........................... PHY INTERFACE ........................... */
> @@ -75,32 +72,33 @@ static inline void at91_emac_write(unsigned int reg, unsigned long value)
>   * When not called from an interrupt-handler, access to the PHY must be
>   *  protected by a spinlock.
>   */
> -static void enable_mdi(void)
> +static void enable_mdi(struct at91_private *lp)
>  {
>  	unsigned long ctl;
>  
> -	ctl = at91_emac_read(AT91_EMAC_CTL);
> -	at91_emac_write(AT91_EMAC_CTL, ctl | AT91_EMAC_MPE);	/* enable management port */
> +	ctl = at91_emac_read(lp, AT91_EMAC_CTL);
> +	at91_emac_write(lp, AT91_EMAC_CTL, ctl | AT91_EMAC_MPE);	/* enable management port */
>  }
>  
>  /*
>   * Disable the MDIO bit in the MAC control register
>   */
> -static void disable_mdi(void)
> +static void disable_mdi(struct at91_private *lp)
>  {
>  	unsigned long ctl;
>  
> -	ctl = at91_emac_read(AT91_EMAC_CTL);
> -	at91_emac_write(AT91_EMAC_CTL, ctl & ~AT91_EMAC_MPE);	/* disable management port */
> +	ctl = at91_emac_read(lp, AT91_EMAC_CTL);
> +	at91_emac_write(lp, AT91_EMAC_CTL, ctl & ~AT91_EMAC_MPE);	/* disable management port */
>  }
>  
>  /*
>   * Wait until the PHY operation is complete.
>   */
> -static inline void at91_phy_wait(void) {
> +static inline void at91_phy_wait(struct at91_private *lp)
> +{
>  	unsigned long timeout = jiffies + 2;
>  
> -	while (!(at91_emac_read(AT91_EMAC_SR) & AT91_EMAC_SR_IDLE)) {
> +	while (!(at91_emac_read(lp, AT91_EMAC_SR) & AT91_EMAC_SR_IDLE)) {
>  		if (time_after(jiffies, timeout)) {
>  			printk("at91_ether: MIO timeout\n");
>  			break;
> @@ -113,28 +111,28 @@ static inline void at91_phy_wait(void) {
>   * 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)
> +static void write_phy(struct at91_private *lp, 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
> +	at91_emac_write(lp, 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();
> +	at91_phy_wait(lp);
>  }
>  
>  /*
>   * 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)
> +static void read_phy(struct at91_private *lp, 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
> +	at91_emac_write(lp, 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();
> +	at91_phy_wait(lp);
>  
> -	*value = at91_emac_read(AT91_EMAC_MAN) & AT91_EMAC_DATA;
> +	*value = at91_emac_read(lp, AT91_EMAC_MAN) & AT91_EMAC_DATA;
>  }
>  
>  /* ........................... PHY MANAGEMENT .......................... */
> @@ -158,13 +156,13 @@ static void update_linkspeed(struct net_device *dev, int silent)
>  	}
>  
>  	/* Link up, or auto-negotiation still in progress */
> -	read_phy(lp->phy_address, MII_BMSR, &bmsr);
> -	read_phy(lp->phy_address, MII_BMCR, &bmcr);
> +	read_phy(lp, lp->phy_address, MII_BMSR, &bmsr);
> +	read_phy(lp, 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);
> +		read_phy(lp, 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;
> @@ -175,7 +173,7 @@ static void update_linkspeed(struct net_device *dev, int silent)
>  	}
>  
>  	/* Update the MAC */
> -	mac_cfg = at91_emac_read(AT91_EMAC_CFG) & ~(AT91_EMAC_SPD | AT91_EMAC_FD);
> +	mac_cfg = at91_emac_read(lp, 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;
> @@ -186,7 +184,7 @@ static void update_linkspeed(struct net_device *dev, int silent)
>  			mac_cfg |= AT91_EMAC_FD;
>  		else {}					/* 10 Half Duplex */
>  	}
> -	at91_emac_write(AT91_EMAC_CFG, mac_cfg);
> +	at91_emac_write(lp, AT91_EMAC_CFG, mac_cfg);
>  
>  	if (!silent)
>  		printk(KERN_INFO "%s: Link now %i-%s\n", dev->name, speed, (duplex == DUPLEX_FULL) ? "FullDuplex" : "HalfDuplex");
> @@ -207,34 +205,34 @@ static irqreturn_t at91ether_phy_interrupt(int irq, void *dev_id)
>  	 * level-triggering.  We therefore have to check if the PHY actually has
>  	 * an IRQ pending.
>  	 */
> -	enable_mdi();
> +	enable_mdi(lp);
>  	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 */
> +		read_phy(lp, 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 */
> +		read_phy(lp, 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 */
> +		read_phy(lp, 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 */
> +		read_phy(lp, lp->phy_address, MII_TPISTATUS, &phy);		/* ack interrupt in Micrel PHY */
>  		if (!(phy & ((1 << 2) | 1)))
>  			goto done;
>  	}
> -	else if (lp->phy_type == MII_T78Q21x3_ID) {			/* ack interrupt in Teridian PHY */
> -		read_phy(lp->phy_address, MII_T78Q21INT_REG, &phy);
> +	else if (lp->phy_type == MII_T78Q21x3_ID) {					/* ack interrupt in Teridian PHY */
> +		read_phy(lp, lp->phy_address, MII_T78Q21INT_REG, &phy);
>  		if (!(phy & ((1 << 2) | 1)))
>  			goto done;
>  	}
>  	else if (lp->phy_type == MII_DP83848_ID) {
> -		read_phy(lp->phy_address, MII_DPPHYSTS_REG, &phy);	/* ack interrupt in DP83848 PHY */
> +		read_phy(lp, lp->phy_address, MII_DPPHYSTS_REG, &phy);	/* ack interrupt in DP83848 PHY */
>  		if (!(phy & (1 << 7)))
>  			goto done;
>  	}
> @@ -242,7 +240,7 @@ static irqreturn_t at91ether_phy_interrupt(int irq, void *dev_id)
>  	update_linkspeed(dev, 0);
>  
>  done:
> -	disable_mdi();
> +	disable_mdi(lp);
>  
>  	return IRQ_HANDLED;
>  }
> @@ -273,41 +271,41 @@ static void enable_phyirq(struct net_device *dev)
>  	}
>  
>  	spin_lock_irq(&lp->lock);
> -	enable_mdi();
> +	enable_mdi(lp);
>  
>  	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);
> +		read_phy(lp, lp->phy_address, MII_DSINTR_REG, &dsintr);
>  		dsintr = dsintr & ~0xf00;		/* clear bits 8..11 */
> -		write_phy(lp->phy_address, MII_DSINTR_REG, dsintr);
> +		write_phy(lp, 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);
> +		read_phy(lp, lp->phy_address, MII_ISINTE_REG, &dsintr);
>  		dsintr = dsintr | 0xf2;			/* set bits 1, 4..7 */
> -		write_phy(lp->phy_address, MII_ISINTE_REG, dsintr);
> +		write_phy(lp, 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);
> +		write_phy(lp, 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);
> +		write_phy(lp, lp->phy_address, MII_TPISTATUS, dsintr);
>  	}
>  	else if (lp->phy_type == MII_T78Q21x3_ID) {	/* for Teridian PHY */
> -		read_phy(lp->phy_address, MII_T78Q21INT_REG, &dsintr);
> +		read_phy(lp, lp->phy_address, MII_T78Q21INT_REG, &dsintr);
>  		dsintr = dsintr | 0x500;		/* set bits 8, 10 */
> -		write_phy(lp->phy_address, MII_T78Q21INT_REG, dsintr);
> +		write_phy(lp, lp->phy_address, MII_T78Q21INT_REG, dsintr);
>  	}
>  	else if (lp->phy_type == MII_DP83848_ID) {	/* National Semiconductor DP83848 PHY */
> -		read_phy(lp->phy_address, MII_DPMISR_REG, &dsintr);
> +		read_phy(lp, lp->phy_address, MII_DPMISR_REG, &dsintr);
>  		dsintr = dsintr | 0x3c;			/* set bits 2..5 */
> -		write_phy(lp->phy_address, MII_DPMISR_REG, dsintr);
> -		read_phy(lp->phy_address, MII_DPMICR_REG, &dsintr);
> +		write_phy(lp, lp->phy_address, MII_DPMISR_REG, dsintr);
> +		read_phy(lp, lp->phy_address, MII_DPMICR_REG, &dsintr);
>  		dsintr = dsintr | 0x3;			/* set bits 0,1 */
> -		write_phy(lp->phy_address, MII_DPMICR_REG, dsintr);
> +		write_phy(lp, lp->phy_address, MII_DPMICR_REG, dsintr);
>  	}
>  
> -	disable_mdi();
> +	disable_mdi(lp);
>  	spin_unlock_irq(&lp->lock);
>  }
>  
> @@ -326,43 +324,43 @@ static void disable_phyirq(struct net_device *dev)
>  	}
>  
>  	spin_lock_irq(&lp->lock);
> -	enable_mdi();
> +	enable_mdi(lp);
>  
>  	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);
> +		read_phy(lp, lp->phy_address, MII_DSINTR_REG, &dsintr);
>  		dsintr = dsintr | 0xf00;			/* set bits 8..11 */
> -		write_phy(lp->phy_address, MII_DSINTR_REG, dsintr);
> +		write_phy(lp, 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);
> +		read_phy(lp, lp->phy_address, MII_ISINTE_REG, &dsintr);
>  		dsintr = dsintr & ~0xf2;			/* clear bits 1, 4..7 */
> -		write_phy(lp->phy_address, MII_ISINTE_REG, dsintr);
> +		write_phy(lp, 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);
> +		read_phy(lp, lp->phy_address, MII_BCMINTR_REG, &dsintr);
>  		dsintr = ~(1 << 14);
> -		write_phy(lp->phy_address, MII_BCMINTR_REG, dsintr);
> +		write_phy(lp, 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);
> +		read_phy(lp, lp->phy_address, MII_TPISTATUS, &dsintr);
>  		dsintr = ~((1 << 10) | (1 << 8));
> -		write_phy(lp->phy_address, MII_TPISTATUS, dsintr);
> +		write_phy(lp, lp->phy_address, MII_TPISTATUS, dsintr);
>  	}
>  	else if (lp->phy_type == MII_T78Q21x3_ID) {	/* for Teridian PHY */
> -		read_phy(lp->phy_address, MII_T78Q21INT_REG, &dsintr);
> +		read_phy(lp, lp->phy_address, MII_T78Q21INT_REG, &dsintr);
>  		dsintr = dsintr & ~0x500;			/* clear bits 8, 10 */
> -		write_phy(lp->phy_address, MII_T78Q21INT_REG, dsintr);
> +		write_phy(lp, lp->phy_address, MII_T78Q21INT_REG, dsintr);
>  	}
>  	else if (lp->phy_type == MII_DP83848_ID) {	/* National Semiconductor DP83848 PHY */
> -		read_phy(lp->phy_address, MII_DPMICR_REG, &dsintr);
> +		read_phy(lp, lp->phy_address, MII_DPMICR_REG, &dsintr);
>  		dsintr = dsintr & ~0x3;				/* clear bits 0, 1 */
> -		write_phy(lp->phy_address, MII_DPMICR_REG, dsintr);
> -		read_phy(lp->phy_address, MII_DPMISR_REG, &dsintr);
> +		write_phy(lp, lp->phy_address, MII_DPMICR_REG, dsintr);
> +		read_phy(lp, lp->phy_address, MII_DPMISR_REG, &dsintr);
>  		dsintr = dsintr & ~0x3c;			/* clear bits 2..5 */
> -		write_phy(lp->phy_address, MII_DPMISR_REG, dsintr);
> +		write_phy(lp, lp->phy_address, MII_DPMISR_REG, dsintr);
>  	}
>  
> -	disable_mdi();
> +	disable_mdi(lp);
>  	spin_unlock_irq(&lp->lock);
>  
>  	irq_number = lp->board_data.phy_irq_pin;
> @@ -379,17 +377,17 @@ static void reset_phy(struct net_device *dev)
>  	unsigned int bmcr;
>  
>  	spin_lock_irq(&lp->lock);
> -	enable_mdi();
> +	enable_mdi(lp);
>  
>  	/* Perform PHY reset */
> -	write_phy(lp->phy_address, MII_BMCR, BMCR_RESET);
> +	write_phy(lp, lp->phy_address, MII_BMCR, BMCR_RESET);
>  
>  	/* Wait until PHY reset is complete */
>  	do {
> -		read_phy(lp->phy_address, MII_BMCR, &bmcr);
> +		read_phy(lp, lp->phy_address, MII_BMCR, &bmcr);
>  	} while (!(bmcr & BMCR_RESET));
>  
> -	disable_mdi();
> +	disable_mdi(lp);
>  	spin_unlock_irq(&lp->lock);
>  }
>  #endif
> @@ -399,13 +397,37 @@ static void at91ether_check_link(unsigned long dev_id)
>  	struct net_device *dev = (struct net_device *) dev_id;
>  	struct at91_private *lp = netdev_priv(dev);
>  
> -	enable_mdi();
> +	enable_mdi(lp);
>  	update_linkspeed(dev, 1);
> -	disable_mdi();
> +	disable_mdi(lp);
>  
>  	mod_timer(&lp->check_timer, jiffies + LINK_POLL_INTERVAL);
>  }
>  
> +/*
> + * Perform any PHY-specific initialization.
> + */
> +static void __init initialize_phy(struct at91_private *lp)
> +{
> +	unsigned int val;
> +
> +	spin_lock_irq(&lp->lock);
> +	enable_mdi(lp);
> +
> +	if ((lp->phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) {
> +		read_phy(lp, lp->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(lp, lp->phy_address, MII_LEDCTRL_REG, 0x0d22);
> +	} else if (machine_is_ecbat91())
> +		write_phy(lp, lp->phy_address, MII_LEDCTRL_REG, 0x156A);
> +
> +	disable_mdi(lp);
> +	spin_unlock_irq(&lp->lock);
> +}
> +
>  /* ......................... ADDRESS MANAGEMENT ........................ */
>  
>  /*
> @@ -454,17 +476,19 @@ static short __init unpack_mac_address(struct net_device *dev, unsigned int hi,
>   */
>  static void __init get_mac_address(struct net_device *dev)
>  {
> +	struct at91_private *lp = netdev_priv(dev);
> +
>  	/* Check Specific-Address 1 */
> -	if (unpack_mac_address(dev, at91_emac_read(AT91_EMAC_SA1H), at91_emac_read(AT91_EMAC_SA1L)))
> +	if (unpack_mac_address(dev, at91_emac_read(lp, AT91_EMAC_SA1H), at91_emac_read(lp, 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)))
> +	if (unpack_mac_address(dev, at91_emac_read(lp, AT91_EMAC_SA2H), at91_emac_read(lp, 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)))
> +	if (unpack_mac_address(dev, at91_emac_read(lp, AT91_EMAC_SA3H), at91_emac_read(lp, 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)))
> +	if (unpack_mac_address(dev, at91_emac_read(lp, AT91_EMAC_SA4H), at91_emac_read(lp, AT91_EMAC_SA4L)))
>  		return;
>  
>  	printk(KERN_ERR "at91_ether: Your bootloader did not configure a MAC address.\n");
> @@ -475,11 +499,13 @@ static void __init get_mac_address(struct net_device *dev)
>   */
>  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]));
> +	struct at91_private *lp = netdev_priv(dev);
>  
> -	at91_emac_write(AT91_EMAC_SA2L, 0);
> -	at91_emac_write(AT91_EMAC_SA2H, 0);
> +	at91_emac_write(lp, 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(lp, AT91_EMAC_SA1H, (dev->dev_addr[5] << 8) | (dev->dev_addr[4]));
> +
> +	at91_emac_write(lp, AT91_EMAC_SA2L, 0);
> +	at91_emac_write(lp, AT91_EMAC_SA2H, 0);
>  }
>  
>  /*
> @@ -559,6 +585,7 @@ static int hash_get_index(__u8 *addr)
>   */
>  static void at91ether_sethashtable(struct net_device *dev)
>  {
> +	struct at91_private *lp = netdev_priv(dev);
>  	struct netdev_hw_addr *ha;
>  	unsigned long mc_filter[2];
>  	unsigned int bitnr;
> @@ -570,8 +597,8 @@ static void at91ether_sethashtable(struct net_device *dev)
>  		mc_filter[bitnr >> 5] |= 1 << (bitnr & 31);
>  	}
>  
> -	at91_emac_write(AT91_EMAC_HSL, mc_filter[0]);
> -	at91_emac_write(AT91_EMAC_HSH, mc_filter[1]);
> +	at91_emac_write(lp, AT91_EMAC_HSL, mc_filter[0]);
> +	at91_emac_write(lp, AT91_EMAC_HSH, mc_filter[1]);
>  }
>  
>  /*
> @@ -579,9 +606,10 @@ static void at91ether_sethashtable(struct net_device *dev)
>   */
>  static void at91ether_set_multicast_list(struct net_device *dev)
>  {
> +	struct at91_private *lp = netdev_priv(dev);
>  	unsigned long cfg;
>  
> -	cfg = at91_emac_read(AT91_EMAC_CFG);
> +	cfg = at91_emac_read(lp, AT91_EMAC_CFG);
>  
>  	if (dev->flags & IFF_PROMISC)			/* Enable promiscuous mode */
>  		cfg |= AT91_EMAC_CAF;
> @@ -589,34 +617,37 @@ static void at91ether_set_multicast_list(struct net_device *dev)
>  		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);
> +		at91_emac_write(lp, AT91_EMAC_HSH, -1);
> +		at91_emac_write(lp, AT91_EMAC_HSL, -1);
>  		cfg |= AT91_EMAC_MTI;
>  	} else if (!netdev_mc_empty(dev)) { /* 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);
> +		at91_emac_write(lp, AT91_EMAC_HSH, 0);
> +		at91_emac_write(lp, AT91_EMAC_HSL, 0);
>  		cfg &= ~AT91_EMAC_MTI;
>  	}
>  
> -	at91_emac_write(AT91_EMAC_CFG, cfg);
> +	at91_emac_write(lp, AT91_EMAC_CFG, cfg);
>  }
>  
>  /* ......................... ETHTOOL SUPPORT ........................... */
>  
>  static int mdio_read(struct net_device *dev, int phy_id, int location)
>  {
> +	struct at91_private *lp = netdev_priv(dev);
>  	unsigned int value;
>  
> -	read_phy(phy_id, location, &value);
> +	read_phy(lp, 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);
> +	struct at91_private *lp = netdev_priv(dev);
> +
> +	write_phy(lp, phy_id, location, value);
>  }
>  
>  static int at91ether_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
> @@ -625,11 +656,11 @@ static int at91ether_get_settings(struct net_device *dev, struct ethtool_cmd *cm
>  	int ret;
>  
>  	spin_lock_irq(&lp->lock);
> -	enable_mdi();
> +	enable_mdi(lp);
>  
>  	ret = mii_ethtool_gset(&lp->mii, cmd);
>  
> -	disable_mdi();
> +	disable_mdi(lp);
>  	spin_unlock_irq(&lp->lock);
>  
>  	if (lp->phy_media == PORT_FIBRE) {		/* override media type since mii.c doesn't know */
> @@ -646,11 +677,11 @@ static int at91ether_set_settings(struct net_device *dev, struct ethtool_cmd *cm
>  	int ret;
>  
>  	spin_lock_irq(&lp->lock);
> -	enable_mdi();
> +	enable_mdi(lp);
>  
>  	ret = mii_ethtool_sset(&lp->mii, cmd);
>  
> -	disable_mdi();
> +	disable_mdi(lp);
>  	spin_unlock_irq(&lp->lock);
>  
>  	return ret;
> @@ -662,11 +693,11 @@ static int at91ether_nwayreset(struct net_device *dev)
>  	int ret;
>  
>  	spin_lock_irq(&lp->lock);
> -	enable_mdi();
> +	enable_mdi(lp);
>  
>  	ret = mii_nway_restart(&lp->mii);
>  
> -	disable_mdi();
> +	disable_mdi(lp);
>  	spin_unlock_irq(&lp->lock);
>  
>  	return ret;
> @@ -696,9 +727,9 @@ static int at91ether_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
>  		return -EINVAL;
>  
>  	spin_lock_irq(&lp->lock);
> -	enable_mdi();
> +	enable_mdi(lp);
>  	res = generic_mii_ioctl(&lp->mii, if_mii(rq), cmd, NULL);
> -	disable_mdi();
> +	disable_mdi(lp);
>  	spin_unlock_irq(&lp->lock);
>  
>  	return res;
> @@ -731,11 +762,11 @@ static void at91ether_start(struct net_device *dev)
>  	lp->rxBuffIndex = 0;
>  
>  	/* Program address of descriptor list in Rx Buffer Queue register */
> -	at91_emac_write(AT91_EMAC_RBQP, (unsigned long) dlist_phys);
> +	at91_emac_write(lp, 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);
> +	ctl = at91_emac_read(lp, AT91_EMAC_CTL);
> +	at91_emac_write(lp, AT91_EMAC_CTL, ctl | AT91_EMAC_RE | AT91_EMAC_TE);
>  }
>  
>  /*
> @@ -752,8 +783,8 @@ static int at91ether_open(struct net_device *dev)
>  	clk_enable(lp->ether_clk);		/* Re-enable Peripheral clock */
>  
>  	/* Clear internal statistics */
> -	ctl = at91_emac_read(AT91_EMAC_CTL);
> -	at91_emac_write(AT91_EMAC_CTL, ctl | AT91_EMAC_CSR);
> +	ctl = at91_emac_read(lp, AT91_EMAC_CTL);
> +	at91_emac_write(lp, AT91_EMAC_CTL, ctl | AT91_EMAC_CSR);
>  
>  	/* Update the MAC address (incase user has changed it) */
>  	update_mac_address(dev);
> @@ -762,15 +793,15 @@ static int at91ether_open(struct net_device *dev)
>  	enable_phyirq(dev);
>  
>  	/* Enable MAC interrupts */
> -	at91_emac_write(AT91_EMAC_IER, AT91_EMAC_RCOM | AT91_EMAC_RBNA
> +	at91_emac_write(lp, 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();
> +	enable_mdi(lp);
>  	update_linkspeed(dev, 0);
> -	disable_mdi();
> +	disable_mdi(lp);
>  	spin_unlock_irq(&lp->lock);
>  
>  	at91ether_start(dev);
> @@ -787,14 +818,14 @@ static int at91ether_close(struct net_device *dev)
>  	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));
> +	ctl = at91_emac_read(lp, AT91_EMAC_CTL);
> +	at91_emac_write(lp, 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_write(lp, AT91_EMAC_IDR, AT91_EMAC_RCOM | AT91_EMAC_RBNA
>  				| AT91_EMAC_TUND | AT91_EMAC_RTRY | AT91_EMAC_TCOM
>  				| AT91_EMAC_ROVR | AT91_EMAC_ABT);
>  
> @@ -812,7 +843,7 @@ static int at91ether_start_xmit(struct sk_buff *skb, struct net_device *dev)
>  {
>  	struct at91_private *lp = netdev_priv(dev);
>  
> -	if (at91_emac_read(AT91_EMAC_TSR) & AT91_EMAC_TSR_BNQ) {
> +	if (at91_emac_read(lp, AT91_EMAC_TSR) & AT91_EMAC_TSR_BNQ) {
>  		netif_stop_queue(dev);
>  
>  		/* Store packet information (to free when Tx completed) */
> @@ -822,9 +853,9 @@ static int at91ether_start_xmit(struct sk_buff *skb, struct net_device *dev)
>  		dev->stats.tx_bytes += skb->len;
>  
>  		/* Set address of the data in the Transmit Address register */
> -		at91_emac_write(AT91_EMAC_TAR, lp->skb_physaddr);
> +		at91_emac_write(lp, AT91_EMAC_TAR, lp->skb_physaddr);
>  		/* Set length of the packet in the Transmit Control register */
> -		at91_emac_write(AT91_EMAC_TCR, skb->len);
> +		at91_emac_write(lp, AT91_EMAC_TCR, skb->len);
>  
>  	} else {
>  		printk(KERN_ERR "at91_ether.c: at91ether_start_xmit() called, but device is busy!\n");
> @@ -841,31 +872,32 @@ static int at91ether_start_xmit(struct sk_buff *skb, struct net_device *dev)
>   */
>  static struct net_device_stats *at91ether_stats(struct net_device *dev)
>  {
> +	struct at91_private *lp = netdev_priv(dev);
>  	int ale, lenerr, seqe, lcol, ecol;
>  
>  	if (netif_running(dev)) {
> -		dev->stats.rx_packets += at91_emac_read(AT91_EMAC_OK);		/* Good frames received */
> -		ale = at91_emac_read(AT91_EMAC_ALE);
> +		dev->stats.rx_packets += at91_emac_read(lp, AT91_EMAC_OK);	/* Good frames received */
> +		ale = at91_emac_read(lp, AT91_EMAC_ALE);
>  		dev->stats.rx_frame_errors += ale;				/* Alignment errors */
> -		lenerr = at91_emac_read(AT91_EMAC_ELR) + at91_emac_read(AT91_EMAC_USF);
> +		lenerr = at91_emac_read(lp, AT91_EMAC_ELR) + at91_emac_read(lp, AT91_EMAC_USF);
>  		dev->stats.rx_length_errors += lenerr;				/* Excessive Length or Undersize Frame error */
> -		seqe = at91_emac_read(AT91_EMAC_SEQE);
> +		seqe = at91_emac_read(lp, AT91_EMAC_SEQE);
>  		dev->stats.rx_crc_errors += seqe;				/* CRC error */
> -		dev->stats.rx_fifo_errors += at91_emac_read(AT91_EMAC_DRFC);	/* Receive buffer not available */
> +		dev->stats.rx_fifo_errors += at91_emac_read(lp, AT91_EMAC_DRFC);/* Receive buffer not available */
>  		dev->stats.rx_errors += (ale + lenerr + seqe
> -			+ at91_emac_read(AT91_EMAC_CDE) + at91_emac_read(AT91_EMAC_RJB));
> +			+ at91_emac_read(lp, AT91_EMAC_CDE) + at91_emac_read(lp, AT91_EMAC_RJB));
>  
> -		dev->stats.tx_packets += at91_emac_read(AT91_EMAC_FRA);		/* Frames successfully transmitted */
> -		dev->stats.tx_fifo_errors += at91_emac_read(AT91_EMAC_TUE);	/* Transmit FIFO underruns */
> -		dev->stats.tx_carrier_errors += at91_emac_read(AT91_EMAC_CSE);	/* Carrier Sense errors */
> -		dev->stats.tx_heartbeat_errors += at91_emac_read(AT91_EMAC_SQEE);/* Heartbeat error */
> +		dev->stats.tx_packets += at91_emac_read(lp, AT91_EMAC_FRA);	/* Frames successfully transmitted */
> +		dev->stats.tx_fifo_errors += at91_emac_read(lp, AT91_EMAC_TUE);	/* Transmit FIFO underruns */
> +		dev->stats.tx_carrier_errors += at91_emac_read(lp, AT91_EMAC_CSE);	/* Carrier Sense errors */
> +		dev->stats.tx_heartbeat_errors += at91_emac_read(lp, AT91_EMAC_SQEE);/* Heartbeat error */
>  
> -		lcol = at91_emac_read(AT91_EMAC_LCOL);
> -		ecol = at91_emac_read(AT91_EMAC_ECOL);
> +		lcol = at91_emac_read(lp, AT91_EMAC_LCOL);
> +		ecol = at91_emac_read(lp, AT91_EMAC_ECOL);
>  		dev->stats.tx_window_errors += lcol;			/* Late collisions */
>  		dev->stats.tx_aborted_errors += ecol;			/* 16 collisions */
>  
> -		dev->stats.collisions += (at91_emac_read(AT91_EMAC_SCOL) + at91_emac_read(AT91_EMAC_MCOL) + lcol + ecol);
> +		dev->stats.collisions += (at91_emac_read(lp, AT91_EMAC_SCOL) + at91_emac_read(lp, AT91_EMAC_MCOL) + lcol + ecol);
>  	}
>  	return &dev->stats;
>  }
> @@ -922,7 +954,7 @@ static irqreturn_t at91ether_interrupt(int irq, void *dev_id)
>  
>  	/* MAC Interrupt Status register indicates what interrupts are pending.
>  	   It is automatically cleared once read. */
> -	intstatus = at91_emac_read(AT91_EMAC_ISR);
> +	intstatus = at91_emac_read(lp, AT91_EMAC_ISR);
>  
>  	if (intstatus & AT91_EMAC_RCOM)		/* Receive complete */
>  		at91ether_rx(dev);
> @@ -942,9 +974,9 @@ static irqreturn_t at91ether_interrupt(int irq, void *dev_id)
>  
>  	/* 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);
> +		ctl = at91_emac_read(lp, AT91_EMAC_CTL);
> +		at91_emac_write(lp, AT91_EMAC_CTL, ctl & ~AT91_EMAC_RE);
> +		at91_emac_write(lp, AT91_EMAC_CTL, ctl | AT91_EMAC_RE);
>  	}
>  
>  	if (intstatus & AT91_EMAC_ROVR)
> @@ -980,189 +1012,199 @@ static const struct net_device_ops at91ether_netdev_ops = {
>  };
>  
>  /*
> - * Initialize the ethernet interface
> + * Detect the PHY type, and its address.
>   */
> -static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_address,
> -			struct platform_device *pdev, struct clk *ether_clk)
> +static int __init at91ether_phy_detect(struct at91_private *lp)
> +{
> +	unsigned int phyid1, phyid2;
> +	unsigned long phy_id;
> +	unsigned short phy_address = 0;
> +
> +	while (phy_address < PHY_MAX_ADDR) {
> +		/* Read the PHY ID registers */
> +		enable_mdi(lp);
> +		read_phy(lp, phy_address, MII_PHYSID1, &phyid1);
> +		read_phy(lp, phy_address, MII_PHYSID2, &phyid2);
> +		disable_mdi(lp);
> +
> +		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_DP83848_ID:		/* National Semiconductor DP83848:  */
> +			case MII_AC101L_ID:		/* Altima AC101L: PHY_ID1 = 0x22, PHY_ID2 = 0x5520 */
> +			case MII_KS8721_ID:		/* Micrel KS8721: PHY_ID1 = 0x22, PHY_ID2 = 0x1610 */
> +			case MII_T78Q21x3_ID:		/* Teridian 78Q21x3: PHY_ID1 = 0x0E, PHY_ID2 = 7237 */
> +			case MII_LAN83C185_ID:		/* SMSC LAN83C185: PHY_ID1 = 0x0007, PHY_ID2 = 0xC0A1 */
> +				/* store detected values */
> +				lp->phy_type = phy_id;		/* Type of PHY connected */
> +				lp->phy_address = phy_address;	/* MDI address of PHY */
> +				return 1;
> +		}
> +
> +		phy_address++;
> +	}
> +
> +	return 0;		/* not detected */
> +}
> +
> +
> +/*
> + * Detect MAC & PHY and perform ethernet interface initialization
> + */
> +static int __init at91ether_probe(struct platform_device *pdev)
>  {
>  	struct macb_platform_data *board_data = pdev->dev.platform_data;
> +	struct resource *regs;
>  	struct net_device *dev;
>  	struct at91_private *lp;
> -	unsigned int val;
>  	int res;
>  
> +	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!regs)
> +		return -ENOENT;
> +
>  	dev = alloc_etherdev(sizeof(struct at91_private));
>  	if (!dev)
>  		return -ENOMEM;
>  
> -	dev->base_addr = AT91_VA_BASE_EMAC;
> -	dev->irq = AT91RM9200_ID_EMAC;
> +	lp = netdev_priv(dev);
> +	lp->board_data = *board_data;
> +	spin_lock_init(&lp->lock);
> +
> +	dev->base_addr = regs->start;		/* physical base address */
> +	lp->emac_base = ioremap(regs->start, regs->end - regs->start + 1);
> +	if (!lp->emac_base) {
> +		res = -ENOMEM;
> +		goto err_free_dev;
> +	}
> +
> +	/* Clock */
> +	lp->ether_clk = clk_get(&pdev->dev, "ether_clk");
> +	if (IS_ERR(lp->ether_clk)) {
> +		res = -ENODEV;
> +		goto err_ioumap;
> +	}
> +	clk_enable(lp->ether_clk);
>  
>  	/* Install the interrupt handler */
> +	dev->irq = platform_get_irq(pdev, 0);
>  	if (request_irq(dev->irq, at91ether_interrupt, 0, dev->name, dev)) {
> -		free_netdev(dev);
> -		return -EBUSY;
> +		res = -EBUSY;
> +		goto err_disable_clock;
>  	}
>  
>  	/* Allocate memory for DMA Receive descriptors */
> -	lp = netdev_priv(dev);
>  	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;
> +		res = -ENOMEM;
> +		goto err_free_irq;
>  	}
> -	lp->board_data = *board_data;
> -	lp->ether_clk = ether_clk;
> -	platform_set_drvdata(pdev, dev);
> -
> -	spin_lock_init(&lp->lock);
>  
>  	ether_setup(dev);
>  	dev->netdev_ops = &at91ether_netdev_ops;
>  	dev->ethtool_ops = &at91ether_ethtool_ops;
> -
> +	platform_set_drvdata(pdev, dev);
>  	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);
> +	at91_emac_write(lp, 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);
> +	if (board_data->is_rmii)
> +		at91_emac_write(lp, 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);
> +		at91_emac_write(lp, 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);
> -	} else if (machine_is_ecbat91())
> -		write_phy(phy_address, MII_LEDCTRL_REG, 0x156A);
> +	/* Detect PHY */
> +	if (!at91ether_phy_detect(lp)) {
> +		printk(KERN_ERR "at91_ether: Could not detect ethernet PHY\n");
> +		res = -ENODEV;
> +		goto err_free_dmamem;
> +	}
>  
> -	disable_mdi();
> -	spin_unlock_irq(&lp->lock);
> +	initialize_phy(lp);
>  
>  	lp->mii.dev = dev;		/* Support for ethtool */
>  	lp->mii.mdio_read = mdio_read;
>  	lp->mii.mdio_write = mdio_write;
> -	lp->mii.phy_id = phy_address;
> +	lp->mii.phy_id = lp->phy_address;
>  	lp->mii.phy_id_mask = 0x1f;
>  	lp->mii.reg_num_mask = 0x1f;
>  
> -	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;
> -	}
> +	if (res)
> +		goto err_free_dmamem;
>  
>  	/* Determine current link speed */
>  	spin_lock_irq(&lp->lock);
> -	enable_mdi();
> +	enable_mdi(lp);
>  	update_linkspeed(dev, 0);
> -	disable_mdi();
> +	disable_mdi(lp);
>  	spin_unlock_irq(&lp->lock);
>  	netif_carrier_off(dev);		/* will be enabled in open() */
>  
>  	/* If board has no PHY IRQ, use a timer to poll the PHY */
> -	if (!gpio_is_valid(lp->board_data.phy_irq_pin)) {
> +	if (gpio_is_valid(lp->board_data.phy_irq_pin)) {
> +		gpio_request(board_data->phy_irq_pin, "ethernet_phy");
> +	} else {
> +		/* If board has no PHY IRQ, use a timer to poll the PHY */
>  		init_timer(&lp->check_timer);
>  		lp->check_timer.data = (unsigned long)dev;
>  		lp->check_timer.function = at91ether_check_link;
> -	} else if (lp->board_data.phy_irq_pin >= 32)
> -		gpio_request(lp->board_data.phy_irq_pin, "ethernet_phy");
> +	}
>  
>  	/* Display ethernet banner */
>  	printk(KERN_INFO "%s: AT91 ethernet at 0x%08x int=%d %s%s (%pM)\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",
> +	       at91_emac_read(lp, AT91_EMAC_CFG) & AT91_EMAC_SPD ? "100-" : "10-",
> +	       at91_emac_read(lp, AT91_EMAC_CFG) & AT91_EMAC_FD ? "FullDuplex" : "HalfDuplex",
>  	       dev->dev_addr);
> -	if ((phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID))
> +	if ((lp->phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID))
>  		printk(KERN_INFO "%s: Davicom 9161 PHY %s\n", dev->name, (lp->phy_media == PORT_FIBRE) ? "(Fiber)" : "(Copper)");
> -	else if (phy_type == MII_LXT971A_ID)
> +	else if (lp->phy_type == MII_LXT971A_ID)
>  		printk(KERN_INFO "%s: Intel LXT971A PHY\n", dev->name);
> -	else if (phy_type == MII_RTL8201_ID)
> +	else if (lp->phy_type == MII_RTL8201_ID)
>  		printk(KERN_INFO "%s: Realtek RTL8201(B)L PHY\n", dev->name);
> -	else if (phy_type == MII_BCM5221_ID)
> +	else if (lp->phy_type == MII_BCM5221_ID)
>  		printk(KERN_INFO "%s: Broadcom BCM5221 PHY\n", dev->name);
> -	else if (phy_type == MII_DP83847_ID)
> +	else if (lp->phy_type == MII_DP83847_ID)
>  		printk(KERN_INFO "%s: National Semiconductor DP83847 PHY\n", dev->name);
> -	else if (phy_type == MII_DP83848_ID)
> +	else if (lp->phy_type == MII_DP83848_ID)
>  		printk(KERN_INFO "%s: National Semiconductor DP83848 PHY\n", dev->name);
> -	else if (phy_type == MII_AC101L_ID)
> +	else if (lp->phy_type == MII_AC101L_ID)
>  		printk(KERN_INFO "%s: Altima AC101L PHY\n", dev->name);
> -	else if (phy_type == MII_KS8721_ID)
> +	else if (lp->phy_type == MII_KS8721_ID)
>  		printk(KERN_INFO "%s: Micrel KS8721 PHY\n", dev->name);
> -	else if (phy_type == MII_T78Q21x3_ID)
> +	else if (lp->phy_type == MII_T78Q21x3_ID)
>  		printk(KERN_INFO "%s: Teridian 78Q21x3 PHY\n", dev->name);
> -	else if (phy_type == MII_LAN83C185_ID)
> +	else if (lp->phy_type == MII_LAN83C185_ID)
>  		printk(KERN_INFO "%s: SMSC LAN83C185 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;
> -	struct clk *ether_clk;
> -
> -	ether_clk = clk_get(&pdev->dev, "ether_clk");
> -	if (IS_ERR(ether_clk)) {
> -		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_DP83848_ID:		/* National Semiconductor DP83848:  */
> -			case MII_AC101L_ID:		/* Altima AC101L: PHY_ID1 = 0x22, PHY_ID2 = 0x5520 */
> -			case MII_KS8721_ID:		/* Micrel KS8721: PHY_ID1 = 0x22, PHY_ID2 = 0x1610 */
> -			case MII_T78Q21x3_ID:		/* Teridian 78Q21x3: PHY_ID1 = 0x0E, PHY_ID2 = 7237 */
> -			case MII_LAN83C185_ID:		/* SMSC LAN83C185: PHY_ID1 = 0x0007, PHY_ID2 = 0xC0A1 */
> -				detected = at91ether_setup(phy_id, phy_address, pdev, ether_clk);
> -				break;
> -		}
> +	clk_disable(lp->ether_clk);					/* Disable Peripheral clock */
>  
> -		phy_address++;
> -	}
> +	return 0;
>  
> -	clk_disable(ether_clk);					/* Disable Peripheral clock */
>  
> -	return detected;
> +err_free_dmamem:
> +	platform_set_drvdata(pdev, NULL);
> +	dma_free_coherent(NULL, sizeof(struct recv_desc_bufs), lp->dlist, (dma_addr_t)lp->dlist_phys);
> +err_free_irq:
> +	free_irq(dev->irq, dev);
> +err_disable_clock:
> +	clk_disable(lp->ether_clk);
> +	clk_put(lp->ether_clk);
> +err_ioumap:
> +	iounmap(lp->emac_base);
> +err_free_dev:
> +	free_netdev(dev);
> +	return res;
>  }
>  
>  static int __devexit at91ether_remove(struct platform_device *pdev)
> @@ -1170,8 +1212,7 @@ static int __devexit at91ether_remove(struct platform_device *pdev)
>  	struct net_device *dev = platform_get_drvdata(pdev);
>  	struct at91_private *lp = netdev_priv(dev);
>  
> -	if (gpio_is_valid(lp->board_data.phy_irq_pin) &&
> -	    lp->board_data.phy_irq_pin >= 32)
> +	if (gpio_is_valid(lp->board_data.phy_irq_pin))
>  		gpio_free(lp->board_data.phy_irq_pin);
>  
>  	unregister_netdev(dev);
> diff --git a/drivers/net/ethernet/cadence/at91_ether.h b/drivers/net/ethernet/cadence/at91_ether.h
> index 3725fbb0..0ef6328 100644
> --- a/drivers/net/ethernet/cadence/at91_ether.h
> +++ b/drivers/net/ethernet/cadence/at91_ether.h
> @@ -88,6 +88,7 @@ struct at91_private
>  	struct macb_platform_data board_data;	/* board-specific
>  						 * configuration (shared with
>  						 * macb for common data */
> +	void __iomem *emac_base;		/* base register address */
>  	struct clk *ether_clk;			/* clock */
>  
>  	/* PHY */
diff mbox

Patch

diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c
index c7efa17..92e0227 100644
--- a/arch/arm/mach-at91/at91rm9200.c
+++ b/arch/arm/mach-at91/at91rm9200.c
@@ -25,15 +25,6 @@ 
 #include "clock.h"
 #include "sam9_smc.h"
 
-static struct map_desc at91rm9200_io_desc[] __initdata = {
-	{
-		.virtual	= AT91_VA_BASE_EMAC,
-		.pfn		= __phys_to_pfn(AT91RM9200_BASE_EMAC),
-		.length		= SZ_16K,
-		.type		= MT_DEVICE,
-	},
-};
-
 /* --------------------------------------------------------------------
  *  Clocks
  * -------------------------------------------------------------------- */
@@ -314,7 +305,6 @@  static void __init at91rm9200_map_io(void)
 {
 	/* Map peripherals */
 	at91_init_sram(0, AT91RM9200_SRAM_BASE, AT91RM9200_SRAM_SIZE);
-	iotable_init(at91rm9200_io_desc, ARRAY_SIZE(at91rm9200_io_desc));
 }
 
 static void __init at91rm9200_ioremap_registers(void)
diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c
index aca272b..04d6b16 100644
--- a/arch/arm/mach-at91/at91rm9200_devices.c
+++ b/arch/arm/mach-at91/at91rm9200_devices.c
@@ -140,8 +140,8 @@  static struct macb_platform_data eth_data;
 
 static struct resource eth_resources[] = {
 	[0] = {
-		.start	= AT91_VA_BASE_EMAC,
-		.end	= AT91_VA_BASE_EMAC + SZ_16K - 1,
+		.start	= AT91RM9200_BASE_EMAC,
+		.end	= AT91RM9200_BASE_EMAC + SZ_16K - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
diff --git a/arch/arm/mach-at91/include/mach/hardware.h b/arch/arm/mach-at91/include/mach/hardware.h
index e9e29a6..01db372 100644
--- a/arch/arm/mach-at91/include/mach/hardware.h
+++ b/arch/arm/mach-at91/include/mach/hardware.h
@@ -94,7 +94,6 @@ 
  * Virtual to Physical Address mapping for IO devices.
  */
 #define AT91_VA_BASE_SYS	AT91_IO_P2V(AT91_BASE_SYS)
-#define AT91_VA_BASE_EMAC	AT91_IO_P2V(AT91RM9200_BASE_EMAC)
 
  /* Internal SRAM is mapped below the IO devices */
 #define AT91_SRAM_MAX		SZ_1M
diff --git a/drivers/net/ethernet/cadence/at91_ether.c b/drivers/net/ethernet/cadence/at91_ether.c
index 1a5b6ef..2b7d278 100644
--- a/drivers/net/ethernet/cadence/at91_ether.c
+++ b/drivers/net/ethernet/cadence/at91_ether.c
@@ -30,6 +30,7 @@ 
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/gfp.h>
+#include <linux/phy.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -51,21 +52,17 @@ 
 /*
  * Read from a EMAC register.
  */
-static inline unsigned long at91_emac_read(unsigned int reg)
+static inline unsigned long at91_emac_read(struct at91_private *lp, unsigned int reg)
 {
-	void __iomem *emac_base = (void __iomem *)AT91_VA_BASE_EMAC;
-
-	return __raw_readl(emac_base + reg);
+	return __raw_readl(lp->emac_base + reg);
 }
 
 /*
  * Write to a EMAC register.
  */
-static inline void at91_emac_write(unsigned int reg, unsigned long value)
+static inline void at91_emac_write(struct at91_private *lp, unsigned int reg, unsigned long value)
 {
-	void __iomem *emac_base = (void __iomem *)AT91_VA_BASE_EMAC;
-
-	__raw_writel(value, emac_base + reg);
+	__raw_writel(value, lp->emac_base + reg);
 }
 
 /* ........................... PHY INTERFACE ........................... */
@@ -75,32 +72,33 @@  static inline void at91_emac_write(unsigned int reg, unsigned long value)
  * When not called from an interrupt-handler, access to the PHY must be
  *  protected by a spinlock.
  */
-static void enable_mdi(void)
+static void enable_mdi(struct at91_private *lp)
 {
 	unsigned long ctl;
 
-	ctl = at91_emac_read(AT91_EMAC_CTL);
-	at91_emac_write(AT91_EMAC_CTL, ctl | AT91_EMAC_MPE);	/* enable management port */
+	ctl = at91_emac_read(lp, AT91_EMAC_CTL);
+	at91_emac_write(lp, AT91_EMAC_CTL, ctl | AT91_EMAC_MPE);	/* enable management port */
 }
 
 /*
  * Disable the MDIO bit in the MAC control register
  */
-static void disable_mdi(void)
+static void disable_mdi(struct at91_private *lp)
 {
 	unsigned long ctl;
 
-	ctl = at91_emac_read(AT91_EMAC_CTL);
-	at91_emac_write(AT91_EMAC_CTL, ctl & ~AT91_EMAC_MPE);	/* disable management port */
+	ctl = at91_emac_read(lp, AT91_EMAC_CTL);
+	at91_emac_write(lp, AT91_EMAC_CTL, ctl & ~AT91_EMAC_MPE);	/* disable management port */
 }
 
 /*
  * Wait until the PHY operation is complete.
  */
-static inline void at91_phy_wait(void) {
+static inline void at91_phy_wait(struct at91_private *lp)
+{
 	unsigned long timeout = jiffies + 2;
 
-	while (!(at91_emac_read(AT91_EMAC_SR) & AT91_EMAC_SR_IDLE)) {
+	while (!(at91_emac_read(lp, AT91_EMAC_SR) & AT91_EMAC_SR_IDLE)) {
 		if (time_after(jiffies, timeout)) {
 			printk("at91_ether: MIO timeout\n");
 			break;
@@ -113,28 +111,28 @@  static inline void at91_phy_wait(void) {
  * 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)
+static void write_phy(struct at91_private *lp, 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
+	at91_emac_write(lp, 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();
+	at91_phy_wait(lp);
 }
 
 /*
  * 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)
+static void read_phy(struct at91_private *lp, 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
+	at91_emac_write(lp, 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();
+	at91_phy_wait(lp);
 
-	*value = at91_emac_read(AT91_EMAC_MAN) & AT91_EMAC_DATA;
+	*value = at91_emac_read(lp, AT91_EMAC_MAN) & AT91_EMAC_DATA;
 }
 
 /* ........................... PHY MANAGEMENT .......................... */
@@ -158,13 +156,13 @@  static void update_linkspeed(struct net_device *dev, int silent)
 	}
 
 	/* Link up, or auto-negotiation still in progress */
-	read_phy(lp->phy_address, MII_BMSR, &bmsr);
-	read_phy(lp->phy_address, MII_BMCR, &bmcr);
+	read_phy(lp, lp->phy_address, MII_BMSR, &bmsr);
+	read_phy(lp, 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);
+		read_phy(lp, 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;
@@ -175,7 +173,7 @@  static void update_linkspeed(struct net_device *dev, int silent)
 	}
 
 	/* Update the MAC */
-	mac_cfg = at91_emac_read(AT91_EMAC_CFG) & ~(AT91_EMAC_SPD | AT91_EMAC_FD);
+	mac_cfg = at91_emac_read(lp, 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;
@@ -186,7 +184,7 @@  static void update_linkspeed(struct net_device *dev, int silent)
 			mac_cfg |= AT91_EMAC_FD;
 		else {}					/* 10 Half Duplex */
 	}
-	at91_emac_write(AT91_EMAC_CFG, mac_cfg);
+	at91_emac_write(lp, AT91_EMAC_CFG, mac_cfg);
 
 	if (!silent)
 		printk(KERN_INFO "%s: Link now %i-%s\n", dev->name, speed, (duplex == DUPLEX_FULL) ? "FullDuplex" : "HalfDuplex");
@@ -207,34 +205,34 @@  static irqreturn_t at91ether_phy_interrupt(int irq, void *dev_id)
 	 * level-triggering.  We therefore have to check if the PHY actually has
 	 * an IRQ pending.
 	 */
-	enable_mdi();
+	enable_mdi(lp);
 	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 */
+		read_phy(lp, 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 */
+		read_phy(lp, 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 */
+		read_phy(lp, 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 */
+		read_phy(lp, lp->phy_address, MII_TPISTATUS, &phy);		/* ack interrupt in Micrel PHY */
 		if (!(phy & ((1 << 2) | 1)))
 			goto done;
 	}
-	else if (lp->phy_type == MII_T78Q21x3_ID) {			/* ack interrupt in Teridian PHY */
-		read_phy(lp->phy_address, MII_T78Q21INT_REG, &phy);
+	else if (lp->phy_type == MII_T78Q21x3_ID) {					/* ack interrupt in Teridian PHY */
+		read_phy(lp, lp->phy_address, MII_T78Q21INT_REG, &phy);
 		if (!(phy & ((1 << 2) | 1)))
 			goto done;
 	}
 	else if (lp->phy_type == MII_DP83848_ID) {
-		read_phy(lp->phy_address, MII_DPPHYSTS_REG, &phy);	/* ack interrupt in DP83848 PHY */
+		read_phy(lp, lp->phy_address, MII_DPPHYSTS_REG, &phy);	/* ack interrupt in DP83848 PHY */
 		if (!(phy & (1 << 7)))
 			goto done;
 	}
@@ -242,7 +240,7 @@  static irqreturn_t at91ether_phy_interrupt(int irq, void *dev_id)
 	update_linkspeed(dev, 0);
 
 done:
-	disable_mdi();
+	disable_mdi(lp);
 
 	return IRQ_HANDLED;
 }
@@ -273,41 +271,41 @@  static void enable_phyirq(struct net_device *dev)
 	}
 
 	spin_lock_irq(&lp->lock);
-	enable_mdi();
+	enable_mdi(lp);
 
 	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);
+		read_phy(lp, lp->phy_address, MII_DSINTR_REG, &dsintr);
 		dsintr = dsintr & ~0xf00;		/* clear bits 8..11 */
-		write_phy(lp->phy_address, MII_DSINTR_REG, dsintr);
+		write_phy(lp, 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);
+		read_phy(lp, lp->phy_address, MII_ISINTE_REG, &dsintr);
 		dsintr = dsintr | 0xf2;			/* set bits 1, 4..7 */
-		write_phy(lp->phy_address, MII_ISINTE_REG, dsintr);
+		write_phy(lp, 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);
+		write_phy(lp, 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);
+		write_phy(lp, lp->phy_address, MII_TPISTATUS, dsintr);
 	}
 	else if (lp->phy_type == MII_T78Q21x3_ID) {	/* for Teridian PHY */
-		read_phy(lp->phy_address, MII_T78Q21INT_REG, &dsintr);
+		read_phy(lp, lp->phy_address, MII_T78Q21INT_REG, &dsintr);
 		dsintr = dsintr | 0x500;		/* set bits 8, 10 */
-		write_phy(lp->phy_address, MII_T78Q21INT_REG, dsintr);
+		write_phy(lp, lp->phy_address, MII_T78Q21INT_REG, dsintr);
 	}
 	else if (lp->phy_type == MII_DP83848_ID) {	/* National Semiconductor DP83848 PHY */
-		read_phy(lp->phy_address, MII_DPMISR_REG, &dsintr);
+		read_phy(lp, lp->phy_address, MII_DPMISR_REG, &dsintr);
 		dsintr = dsintr | 0x3c;			/* set bits 2..5 */
-		write_phy(lp->phy_address, MII_DPMISR_REG, dsintr);
-		read_phy(lp->phy_address, MII_DPMICR_REG, &dsintr);
+		write_phy(lp, lp->phy_address, MII_DPMISR_REG, dsintr);
+		read_phy(lp, lp->phy_address, MII_DPMICR_REG, &dsintr);
 		dsintr = dsintr | 0x3;			/* set bits 0,1 */
-		write_phy(lp->phy_address, MII_DPMICR_REG, dsintr);
+		write_phy(lp, lp->phy_address, MII_DPMICR_REG, dsintr);
 	}
 
-	disable_mdi();
+	disable_mdi(lp);
 	spin_unlock_irq(&lp->lock);
 }
 
@@ -326,43 +324,43 @@  static void disable_phyirq(struct net_device *dev)
 	}
 
 	spin_lock_irq(&lp->lock);
-	enable_mdi();
+	enable_mdi(lp);
 
 	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);
+		read_phy(lp, lp->phy_address, MII_DSINTR_REG, &dsintr);
 		dsintr = dsintr | 0xf00;			/* set bits 8..11 */
-		write_phy(lp->phy_address, MII_DSINTR_REG, dsintr);
+		write_phy(lp, 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);
+		read_phy(lp, lp->phy_address, MII_ISINTE_REG, &dsintr);
 		dsintr = dsintr & ~0xf2;			/* clear bits 1, 4..7 */
-		write_phy(lp->phy_address, MII_ISINTE_REG, dsintr);
+		write_phy(lp, 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);
+		read_phy(lp, lp->phy_address, MII_BCMINTR_REG, &dsintr);
 		dsintr = ~(1 << 14);
-		write_phy(lp->phy_address, MII_BCMINTR_REG, dsintr);
+		write_phy(lp, 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);
+		read_phy(lp, lp->phy_address, MII_TPISTATUS, &dsintr);
 		dsintr = ~((1 << 10) | (1 << 8));
-		write_phy(lp->phy_address, MII_TPISTATUS, dsintr);
+		write_phy(lp, lp->phy_address, MII_TPISTATUS, dsintr);
 	}
 	else if (lp->phy_type == MII_T78Q21x3_ID) {	/* for Teridian PHY */
-		read_phy(lp->phy_address, MII_T78Q21INT_REG, &dsintr);
+		read_phy(lp, lp->phy_address, MII_T78Q21INT_REG, &dsintr);
 		dsintr = dsintr & ~0x500;			/* clear bits 8, 10 */
-		write_phy(lp->phy_address, MII_T78Q21INT_REG, dsintr);
+		write_phy(lp, lp->phy_address, MII_T78Q21INT_REG, dsintr);
 	}
 	else if (lp->phy_type == MII_DP83848_ID) {	/* National Semiconductor DP83848 PHY */
-		read_phy(lp->phy_address, MII_DPMICR_REG, &dsintr);
+		read_phy(lp, lp->phy_address, MII_DPMICR_REG, &dsintr);
 		dsintr = dsintr & ~0x3;				/* clear bits 0, 1 */
-		write_phy(lp->phy_address, MII_DPMICR_REG, dsintr);
-		read_phy(lp->phy_address, MII_DPMISR_REG, &dsintr);
+		write_phy(lp, lp->phy_address, MII_DPMICR_REG, dsintr);
+		read_phy(lp, lp->phy_address, MII_DPMISR_REG, &dsintr);
 		dsintr = dsintr & ~0x3c;			/* clear bits 2..5 */
-		write_phy(lp->phy_address, MII_DPMISR_REG, dsintr);
+		write_phy(lp, lp->phy_address, MII_DPMISR_REG, dsintr);
 	}
 
-	disable_mdi();
+	disable_mdi(lp);
 	spin_unlock_irq(&lp->lock);
 
 	irq_number = lp->board_data.phy_irq_pin;
@@ -379,17 +377,17 @@  static void reset_phy(struct net_device *dev)
 	unsigned int bmcr;
 
 	spin_lock_irq(&lp->lock);
-	enable_mdi();
+	enable_mdi(lp);
 
 	/* Perform PHY reset */
-	write_phy(lp->phy_address, MII_BMCR, BMCR_RESET);
+	write_phy(lp, lp->phy_address, MII_BMCR, BMCR_RESET);
 
 	/* Wait until PHY reset is complete */
 	do {
-		read_phy(lp->phy_address, MII_BMCR, &bmcr);
+		read_phy(lp, lp->phy_address, MII_BMCR, &bmcr);
 	} while (!(bmcr & BMCR_RESET));
 
-	disable_mdi();
+	disable_mdi(lp);
 	spin_unlock_irq(&lp->lock);
 }
 #endif
@@ -399,13 +397,37 @@  static void at91ether_check_link(unsigned long dev_id)
 	struct net_device *dev = (struct net_device *) dev_id;
 	struct at91_private *lp = netdev_priv(dev);
 
-	enable_mdi();
+	enable_mdi(lp);
 	update_linkspeed(dev, 1);
-	disable_mdi();
+	disable_mdi(lp);
 
 	mod_timer(&lp->check_timer, jiffies + LINK_POLL_INTERVAL);
 }
 
+/*
+ * Perform any PHY-specific initialization.
+ */
+static void __init initialize_phy(struct at91_private *lp)
+{
+	unsigned int val;
+
+	spin_lock_irq(&lp->lock);
+	enable_mdi(lp);
+
+	if ((lp->phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) {
+		read_phy(lp, lp->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(lp, lp->phy_address, MII_LEDCTRL_REG, 0x0d22);
+	} else if (machine_is_ecbat91())
+		write_phy(lp, lp->phy_address, MII_LEDCTRL_REG, 0x156A);
+
+	disable_mdi(lp);
+	spin_unlock_irq(&lp->lock);
+}
+
 /* ......................... ADDRESS MANAGEMENT ........................ */
 
 /*
@@ -454,17 +476,19 @@  static short __init unpack_mac_address(struct net_device *dev, unsigned int hi,
  */
 static void __init get_mac_address(struct net_device *dev)
 {
+	struct at91_private *lp = netdev_priv(dev);
+
 	/* Check Specific-Address 1 */
-	if (unpack_mac_address(dev, at91_emac_read(AT91_EMAC_SA1H), at91_emac_read(AT91_EMAC_SA1L)))
+	if (unpack_mac_address(dev, at91_emac_read(lp, AT91_EMAC_SA1H), at91_emac_read(lp, 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)))
+	if (unpack_mac_address(dev, at91_emac_read(lp, AT91_EMAC_SA2H), at91_emac_read(lp, 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)))
+	if (unpack_mac_address(dev, at91_emac_read(lp, AT91_EMAC_SA3H), at91_emac_read(lp, 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)))
+	if (unpack_mac_address(dev, at91_emac_read(lp, AT91_EMAC_SA4H), at91_emac_read(lp, AT91_EMAC_SA4L)))
 		return;
 
 	printk(KERN_ERR "at91_ether: Your bootloader did not configure a MAC address.\n");
@@ -475,11 +499,13 @@  static void __init get_mac_address(struct net_device *dev)
  */
 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]));
+	struct at91_private *lp = netdev_priv(dev);
 
-	at91_emac_write(AT91_EMAC_SA2L, 0);
-	at91_emac_write(AT91_EMAC_SA2H, 0);
+	at91_emac_write(lp, 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(lp, AT91_EMAC_SA1H, (dev->dev_addr[5] << 8) | (dev->dev_addr[4]));
+
+	at91_emac_write(lp, AT91_EMAC_SA2L, 0);
+	at91_emac_write(lp, AT91_EMAC_SA2H, 0);
 }
 
 /*
@@ -559,6 +585,7 @@  static int hash_get_index(__u8 *addr)
  */
 static void at91ether_sethashtable(struct net_device *dev)
 {
+	struct at91_private *lp = netdev_priv(dev);
 	struct netdev_hw_addr *ha;
 	unsigned long mc_filter[2];
 	unsigned int bitnr;
@@ -570,8 +597,8 @@  static void at91ether_sethashtable(struct net_device *dev)
 		mc_filter[bitnr >> 5] |= 1 << (bitnr & 31);
 	}
 
-	at91_emac_write(AT91_EMAC_HSL, mc_filter[0]);
-	at91_emac_write(AT91_EMAC_HSH, mc_filter[1]);
+	at91_emac_write(lp, AT91_EMAC_HSL, mc_filter[0]);
+	at91_emac_write(lp, AT91_EMAC_HSH, mc_filter[1]);
 }
 
 /*
@@ -579,9 +606,10 @@  static void at91ether_sethashtable(struct net_device *dev)
  */
 static void at91ether_set_multicast_list(struct net_device *dev)
 {
+	struct at91_private *lp = netdev_priv(dev);
 	unsigned long cfg;
 
-	cfg = at91_emac_read(AT91_EMAC_CFG);
+	cfg = at91_emac_read(lp, AT91_EMAC_CFG);
 
 	if (dev->flags & IFF_PROMISC)			/* Enable promiscuous mode */
 		cfg |= AT91_EMAC_CAF;
@@ -589,34 +617,37 @@  static void at91ether_set_multicast_list(struct net_device *dev)
 		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);
+		at91_emac_write(lp, AT91_EMAC_HSH, -1);
+		at91_emac_write(lp, AT91_EMAC_HSL, -1);
 		cfg |= AT91_EMAC_MTI;
 	} else if (!netdev_mc_empty(dev)) { /* 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);
+		at91_emac_write(lp, AT91_EMAC_HSH, 0);
+		at91_emac_write(lp, AT91_EMAC_HSL, 0);
 		cfg &= ~AT91_EMAC_MTI;
 	}
 
-	at91_emac_write(AT91_EMAC_CFG, cfg);
+	at91_emac_write(lp, AT91_EMAC_CFG, cfg);
 }
 
 /* ......................... ETHTOOL SUPPORT ........................... */
 
 static int mdio_read(struct net_device *dev, int phy_id, int location)
 {
+	struct at91_private *lp = netdev_priv(dev);
 	unsigned int value;
 
-	read_phy(phy_id, location, &value);
+	read_phy(lp, 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);
+	struct at91_private *lp = netdev_priv(dev);
+
+	write_phy(lp, phy_id, location, value);
 }
 
 static int at91ether_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
@@ -625,11 +656,11 @@  static int at91ether_get_settings(struct net_device *dev, struct ethtool_cmd *cm
 	int ret;
 
 	spin_lock_irq(&lp->lock);
-	enable_mdi();
+	enable_mdi(lp);
 
 	ret = mii_ethtool_gset(&lp->mii, cmd);
 
-	disable_mdi();
+	disable_mdi(lp);
 	spin_unlock_irq(&lp->lock);
 
 	if (lp->phy_media == PORT_FIBRE) {		/* override media type since mii.c doesn't know */
@@ -646,11 +677,11 @@  static int at91ether_set_settings(struct net_device *dev, struct ethtool_cmd *cm
 	int ret;
 
 	spin_lock_irq(&lp->lock);
-	enable_mdi();
+	enable_mdi(lp);
 
 	ret = mii_ethtool_sset(&lp->mii, cmd);
 
-	disable_mdi();
+	disable_mdi(lp);
 	spin_unlock_irq(&lp->lock);
 
 	return ret;
@@ -662,11 +693,11 @@  static int at91ether_nwayreset(struct net_device *dev)
 	int ret;
 
 	spin_lock_irq(&lp->lock);
-	enable_mdi();
+	enable_mdi(lp);
 
 	ret = mii_nway_restart(&lp->mii);
 
-	disable_mdi();
+	disable_mdi(lp);
 	spin_unlock_irq(&lp->lock);
 
 	return ret;
@@ -696,9 +727,9 @@  static int at91ether_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 		return -EINVAL;
 
 	spin_lock_irq(&lp->lock);
-	enable_mdi();
+	enable_mdi(lp);
 	res = generic_mii_ioctl(&lp->mii, if_mii(rq), cmd, NULL);
-	disable_mdi();
+	disable_mdi(lp);
 	spin_unlock_irq(&lp->lock);
 
 	return res;
@@ -731,11 +762,11 @@  static void at91ether_start(struct net_device *dev)
 	lp->rxBuffIndex = 0;
 
 	/* Program address of descriptor list in Rx Buffer Queue register */
-	at91_emac_write(AT91_EMAC_RBQP, (unsigned long) dlist_phys);
+	at91_emac_write(lp, 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);
+	ctl = at91_emac_read(lp, AT91_EMAC_CTL);
+	at91_emac_write(lp, AT91_EMAC_CTL, ctl | AT91_EMAC_RE | AT91_EMAC_TE);
 }
 
 /*
@@ -752,8 +783,8 @@  static int at91ether_open(struct net_device *dev)
 	clk_enable(lp->ether_clk);		/* Re-enable Peripheral clock */
 
 	/* Clear internal statistics */
-	ctl = at91_emac_read(AT91_EMAC_CTL);
-	at91_emac_write(AT91_EMAC_CTL, ctl | AT91_EMAC_CSR);
+	ctl = at91_emac_read(lp, AT91_EMAC_CTL);
+	at91_emac_write(lp, AT91_EMAC_CTL, ctl | AT91_EMAC_CSR);
 
 	/* Update the MAC address (incase user has changed it) */
 	update_mac_address(dev);
@@ -762,15 +793,15 @@  static int at91ether_open(struct net_device *dev)
 	enable_phyirq(dev);
 
 	/* Enable MAC interrupts */
-	at91_emac_write(AT91_EMAC_IER, AT91_EMAC_RCOM | AT91_EMAC_RBNA
+	at91_emac_write(lp, 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();
+	enable_mdi(lp);
 	update_linkspeed(dev, 0);
-	disable_mdi();
+	disable_mdi(lp);
 	spin_unlock_irq(&lp->lock);
 
 	at91ether_start(dev);
@@ -787,14 +818,14 @@  static int at91ether_close(struct net_device *dev)
 	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));
+	ctl = at91_emac_read(lp, AT91_EMAC_CTL);
+	at91_emac_write(lp, 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_write(lp, AT91_EMAC_IDR, AT91_EMAC_RCOM | AT91_EMAC_RBNA
 				| AT91_EMAC_TUND | AT91_EMAC_RTRY | AT91_EMAC_TCOM
 				| AT91_EMAC_ROVR | AT91_EMAC_ABT);
 
@@ -812,7 +843,7 @@  static int at91ether_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct at91_private *lp = netdev_priv(dev);
 
-	if (at91_emac_read(AT91_EMAC_TSR) & AT91_EMAC_TSR_BNQ) {
+	if (at91_emac_read(lp, AT91_EMAC_TSR) & AT91_EMAC_TSR_BNQ) {
 		netif_stop_queue(dev);
 
 		/* Store packet information (to free when Tx completed) */
@@ -822,9 +853,9 @@  static int at91ether_start_xmit(struct sk_buff *skb, struct net_device *dev)
 		dev->stats.tx_bytes += skb->len;
 
 		/* Set address of the data in the Transmit Address register */
-		at91_emac_write(AT91_EMAC_TAR, lp->skb_physaddr);
+		at91_emac_write(lp, AT91_EMAC_TAR, lp->skb_physaddr);
 		/* Set length of the packet in the Transmit Control register */
-		at91_emac_write(AT91_EMAC_TCR, skb->len);
+		at91_emac_write(lp, AT91_EMAC_TCR, skb->len);
 
 	} else {
 		printk(KERN_ERR "at91_ether.c: at91ether_start_xmit() called, but device is busy!\n");
@@ -841,31 +872,32 @@  static int at91ether_start_xmit(struct sk_buff *skb, struct net_device *dev)
  */
 static struct net_device_stats *at91ether_stats(struct net_device *dev)
 {
+	struct at91_private *lp = netdev_priv(dev);
 	int ale, lenerr, seqe, lcol, ecol;
 
 	if (netif_running(dev)) {
-		dev->stats.rx_packets += at91_emac_read(AT91_EMAC_OK);		/* Good frames received */
-		ale = at91_emac_read(AT91_EMAC_ALE);
+		dev->stats.rx_packets += at91_emac_read(lp, AT91_EMAC_OK);	/* Good frames received */
+		ale = at91_emac_read(lp, AT91_EMAC_ALE);
 		dev->stats.rx_frame_errors += ale;				/* Alignment errors */
-		lenerr = at91_emac_read(AT91_EMAC_ELR) + at91_emac_read(AT91_EMAC_USF);
+		lenerr = at91_emac_read(lp, AT91_EMAC_ELR) + at91_emac_read(lp, AT91_EMAC_USF);
 		dev->stats.rx_length_errors += lenerr;				/* Excessive Length or Undersize Frame error */
-		seqe = at91_emac_read(AT91_EMAC_SEQE);
+		seqe = at91_emac_read(lp, AT91_EMAC_SEQE);
 		dev->stats.rx_crc_errors += seqe;				/* CRC error */
-		dev->stats.rx_fifo_errors += at91_emac_read(AT91_EMAC_DRFC);	/* Receive buffer not available */
+		dev->stats.rx_fifo_errors += at91_emac_read(lp, AT91_EMAC_DRFC);/* Receive buffer not available */
 		dev->stats.rx_errors += (ale + lenerr + seqe
-			+ at91_emac_read(AT91_EMAC_CDE) + at91_emac_read(AT91_EMAC_RJB));
+			+ at91_emac_read(lp, AT91_EMAC_CDE) + at91_emac_read(lp, AT91_EMAC_RJB));
 
-		dev->stats.tx_packets += at91_emac_read(AT91_EMAC_FRA);		/* Frames successfully transmitted */
-		dev->stats.tx_fifo_errors += at91_emac_read(AT91_EMAC_TUE);	/* Transmit FIFO underruns */
-		dev->stats.tx_carrier_errors += at91_emac_read(AT91_EMAC_CSE);	/* Carrier Sense errors */
-		dev->stats.tx_heartbeat_errors += at91_emac_read(AT91_EMAC_SQEE);/* Heartbeat error */
+		dev->stats.tx_packets += at91_emac_read(lp, AT91_EMAC_FRA);	/* Frames successfully transmitted */
+		dev->stats.tx_fifo_errors += at91_emac_read(lp, AT91_EMAC_TUE);	/* Transmit FIFO underruns */
+		dev->stats.tx_carrier_errors += at91_emac_read(lp, AT91_EMAC_CSE);	/* Carrier Sense errors */
+		dev->stats.tx_heartbeat_errors += at91_emac_read(lp, AT91_EMAC_SQEE);/* Heartbeat error */
 
-		lcol = at91_emac_read(AT91_EMAC_LCOL);
-		ecol = at91_emac_read(AT91_EMAC_ECOL);
+		lcol = at91_emac_read(lp, AT91_EMAC_LCOL);
+		ecol = at91_emac_read(lp, AT91_EMAC_ECOL);
 		dev->stats.tx_window_errors += lcol;			/* Late collisions */
 		dev->stats.tx_aborted_errors += ecol;			/* 16 collisions */
 
-		dev->stats.collisions += (at91_emac_read(AT91_EMAC_SCOL) + at91_emac_read(AT91_EMAC_MCOL) + lcol + ecol);
+		dev->stats.collisions += (at91_emac_read(lp, AT91_EMAC_SCOL) + at91_emac_read(lp, AT91_EMAC_MCOL) + lcol + ecol);
 	}
 	return &dev->stats;
 }
@@ -922,7 +954,7 @@  static irqreturn_t at91ether_interrupt(int irq, void *dev_id)
 
 	/* MAC Interrupt Status register indicates what interrupts are pending.
 	   It is automatically cleared once read. */
-	intstatus = at91_emac_read(AT91_EMAC_ISR);
+	intstatus = at91_emac_read(lp, AT91_EMAC_ISR);
 
 	if (intstatus & AT91_EMAC_RCOM)		/* Receive complete */
 		at91ether_rx(dev);
@@ -942,9 +974,9 @@  static irqreturn_t at91ether_interrupt(int irq, void *dev_id)
 
 	/* 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);
+		ctl = at91_emac_read(lp, AT91_EMAC_CTL);
+		at91_emac_write(lp, AT91_EMAC_CTL, ctl & ~AT91_EMAC_RE);
+		at91_emac_write(lp, AT91_EMAC_CTL, ctl | AT91_EMAC_RE);
 	}
 
 	if (intstatus & AT91_EMAC_ROVR)
@@ -980,189 +1012,199 @@  static const struct net_device_ops at91ether_netdev_ops = {
 };
 
 /*
- * Initialize the ethernet interface
+ * Detect the PHY type, and its address.
  */
-static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_address,
-			struct platform_device *pdev, struct clk *ether_clk)
+static int __init at91ether_phy_detect(struct at91_private *lp)
+{
+	unsigned int phyid1, phyid2;
+	unsigned long phy_id;
+	unsigned short phy_address = 0;
+
+	while (phy_address < PHY_MAX_ADDR) {
+		/* Read the PHY ID registers */
+		enable_mdi(lp);
+		read_phy(lp, phy_address, MII_PHYSID1, &phyid1);
+		read_phy(lp, phy_address, MII_PHYSID2, &phyid2);
+		disable_mdi(lp);
+
+		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_DP83848_ID:		/* National Semiconductor DP83848:  */
+			case MII_AC101L_ID:		/* Altima AC101L: PHY_ID1 = 0x22, PHY_ID2 = 0x5520 */
+			case MII_KS8721_ID:		/* Micrel KS8721: PHY_ID1 = 0x22, PHY_ID2 = 0x1610 */
+			case MII_T78Q21x3_ID:		/* Teridian 78Q21x3: PHY_ID1 = 0x0E, PHY_ID2 = 7237 */
+			case MII_LAN83C185_ID:		/* SMSC LAN83C185: PHY_ID1 = 0x0007, PHY_ID2 = 0xC0A1 */
+				/* store detected values */
+				lp->phy_type = phy_id;		/* Type of PHY connected */
+				lp->phy_address = phy_address;	/* MDI address of PHY */
+				return 1;
+		}
+
+		phy_address++;
+	}
+
+	return 0;		/* not detected */
+}
+
+
+/*
+ * Detect MAC & PHY and perform ethernet interface initialization
+ */
+static int __init at91ether_probe(struct platform_device *pdev)
 {
 	struct macb_platform_data *board_data = pdev->dev.platform_data;
+	struct resource *regs;
 	struct net_device *dev;
 	struct at91_private *lp;
-	unsigned int val;
 	int res;
 
+	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!regs)
+		return -ENOENT;
+
 	dev = alloc_etherdev(sizeof(struct at91_private));
 	if (!dev)
 		return -ENOMEM;
 
-	dev->base_addr = AT91_VA_BASE_EMAC;
-	dev->irq = AT91RM9200_ID_EMAC;
+	lp = netdev_priv(dev);
+	lp->board_data = *board_data;
+	spin_lock_init(&lp->lock);
+
+	dev->base_addr = regs->start;		/* physical base address */
+	lp->emac_base = ioremap(regs->start, regs->end - regs->start + 1);
+	if (!lp->emac_base) {
+		res = -ENOMEM;
+		goto err_free_dev;
+	}
+
+	/* Clock */
+	lp->ether_clk = clk_get(&pdev->dev, "ether_clk");
+	if (IS_ERR(lp->ether_clk)) {
+		res = -ENODEV;
+		goto err_ioumap;
+	}
+	clk_enable(lp->ether_clk);
 
 	/* Install the interrupt handler */
+	dev->irq = platform_get_irq(pdev, 0);
 	if (request_irq(dev->irq, at91ether_interrupt, 0, dev->name, dev)) {
-		free_netdev(dev);
-		return -EBUSY;
+		res = -EBUSY;
+		goto err_disable_clock;
 	}
 
 	/* Allocate memory for DMA Receive descriptors */
-	lp = netdev_priv(dev);
 	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;
+		res = -ENOMEM;
+		goto err_free_irq;
 	}
-	lp->board_data = *board_data;
-	lp->ether_clk = ether_clk;
-	platform_set_drvdata(pdev, dev);
-
-	spin_lock_init(&lp->lock);
 
 	ether_setup(dev);
 	dev->netdev_ops = &at91ether_netdev_ops;
 	dev->ethtool_ops = &at91ether_ethtool_ops;
-
+	platform_set_drvdata(pdev, dev);
 	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);
+	at91_emac_write(lp, 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);
+	if (board_data->is_rmii)
+		at91_emac_write(lp, 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);
+		at91_emac_write(lp, 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);
-	} else if (machine_is_ecbat91())
-		write_phy(phy_address, MII_LEDCTRL_REG, 0x156A);
+	/* Detect PHY */
+	if (!at91ether_phy_detect(lp)) {
+		printk(KERN_ERR "at91_ether: Could not detect ethernet PHY\n");
+		res = -ENODEV;
+		goto err_free_dmamem;
+	}
 
-	disable_mdi();
-	spin_unlock_irq(&lp->lock);
+	initialize_phy(lp);
 
 	lp->mii.dev = dev;		/* Support for ethtool */
 	lp->mii.mdio_read = mdio_read;
 	lp->mii.mdio_write = mdio_write;
-	lp->mii.phy_id = phy_address;
+	lp->mii.phy_id = lp->phy_address;
 	lp->mii.phy_id_mask = 0x1f;
 	lp->mii.reg_num_mask = 0x1f;
 
-	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;
-	}
+	if (res)
+		goto err_free_dmamem;
 
 	/* Determine current link speed */
 	spin_lock_irq(&lp->lock);
-	enable_mdi();
+	enable_mdi(lp);
 	update_linkspeed(dev, 0);
-	disable_mdi();
+	disable_mdi(lp);
 	spin_unlock_irq(&lp->lock);
 	netif_carrier_off(dev);		/* will be enabled in open() */
 
 	/* If board has no PHY IRQ, use a timer to poll the PHY */
-	if (!gpio_is_valid(lp->board_data.phy_irq_pin)) {
+	if (gpio_is_valid(lp->board_data.phy_irq_pin)) {
+		gpio_request(board_data->phy_irq_pin, "ethernet_phy");
+	} else {
+		/* If board has no PHY IRQ, use a timer to poll the PHY */
 		init_timer(&lp->check_timer);
 		lp->check_timer.data = (unsigned long)dev;
 		lp->check_timer.function = at91ether_check_link;
-	} else if (lp->board_data.phy_irq_pin >= 32)
-		gpio_request(lp->board_data.phy_irq_pin, "ethernet_phy");
+	}
 
 	/* Display ethernet banner */
 	printk(KERN_INFO "%s: AT91 ethernet at 0x%08x int=%d %s%s (%pM)\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",
+	       at91_emac_read(lp, AT91_EMAC_CFG) & AT91_EMAC_SPD ? "100-" : "10-",
+	       at91_emac_read(lp, AT91_EMAC_CFG) & AT91_EMAC_FD ? "FullDuplex" : "HalfDuplex",
 	       dev->dev_addr);
-	if ((phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID))
+	if ((lp->phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID))
 		printk(KERN_INFO "%s: Davicom 9161 PHY %s\n", dev->name, (lp->phy_media == PORT_FIBRE) ? "(Fiber)" : "(Copper)");
-	else if (phy_type == MII_LXT971A_ID)
+	else if (lp->phy_type == MII_LXT971A_ID)
 		printk(KERN_INFO "%s: Intel LXT971A PHY\n", dev->name);
-	else if (phy_type == MII_RTL8201_ID)
+	else if (lp->phy_type == MII_RTL8201_ID)
 		printk(KERN_INFO "%s: Realtek RTL8201(B)L PHY\n", dev->name);
-	else if (phy_type == MII_BCM5221_ID)
+	else if (lp->phy_type == MII_BCM5221_ID)
 		printk(KERN_INFO "%s: Broadcom BCM5221 PHY\n", dev->name);
-	else if (phy_type == MII_DP83847_ID)
+	else if (lp->phy_type == MII_DP83847_ID)
 		printk(KERN_INFO "%s: National Semiconductor DP83847 PHY\n", dev->name);
-	else if (phy_type == MII_DP83848_ID)
+	else if (lp->phy_type == MII_DP83848_ID)
 		printk(KERN_INFO "%s: National Semiconductor DP83848 PHY\n", dev->name);
-	else if (phy_type == MII_AC101L_ID)
+	else if (lp->phy_type == MII_AC101L_ID)
 		printk(KERN_INFO "%s: Altima AC101L PHY\n", dev->name);
-	else if (phy_type == MII_KS8721_ID)
+	else if (lp->phy_type == MII_KS8721_ID)
 		printk(KERN_INFO "%s: Micrel KS8721 PHY\n", dev->name);
-	else if (phy_type == MII_T78Q21x3_ID)
+	else if (lp->phy_type == MII_T78Q21x3_ID)
 		printk(KERN_INFO "%s: Teridian 78Q21x3 PHY\n", dev->name);
-	else if (phy_type == MII_LAN83C185_ID)
+	else if (lp->phy_type == MII_LAN83C185_ID)
 		printk(KERN_INFO "%s: SMSC LAN83C185 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;
-	struct clk *ether_clk;
-
-	ether_clk = clk_get(&pdev->dev, "ether_clk");
-	if (IS_ERR(ether_clk)) {
-		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_DP83848_ID:		/* National Semiconductor DP83848:  */
-			case MII_AC101L_ID:		/* Altima AC101L: PHY_ID1 = 0x22, PHY_ID2 = 0x5520 */
-			case MII_KS8721_ID:		/* Micrel KS8721: PHY_ID1 = 0x22, PHY_ID2 = 0x1610 */
-			case MII_T78Q21x3_ID:		/* Teridian 78Q21x3: PHY_ID1 = 0x0E, PHY_ID2 = 7237 */
-			case MII_LAN83C185_ID:		/* SMSC LAN83C185: PHY_ID1 = 0x0007, PHY_ID2 = 0xC0A1 */
-				detected = at91ether_setup(phy_id, phy_address, pdev, ether_clk);
-				break;
-		}
+	clk_disable(lp->ether_clk);					/* Disable Peripheral clock */
 
-		phy_address++;
-	}
+	return 0;
 
-	clk_disable(ether_clk);					/* Disable Peripheral clock */
 
-	return detected;
+err_free_dmamem:
+	platform_set_drvdata(pdev, NULL);
+	dma_free_coherent(NULL, sizeof(struct recv_desc_bufs), lp->dlist, (dma_addr_t)lp->dlist_phys);
+err_free_irq:
+	free_irq(dev->irq, dev);
+err_disable_clock:
+	clk_disable(lp->ether_clk);
+	clk_put(lp->ether_clk);
+err_ioumap:
+	iounmap(lp->emac_base);
+err_free_dev:
+	free_netdev(dev);
+	return res;
 }
 
 static int __devexit at91ether_remove(struct platform_device *pdev)
@@ -1170,8 +1212,7 @@  static int __devexit at91ether_remove(struct platform_device *pdev)
 	struct net_device *dev = platform_get_drvdata(pdev);
 	struct at91_private *lp = netdev_priv(dev);
 
-	if (gpio_is_valid(lp->board_data.phy_irq_pin) &&
-	    lp->board_data.phy_irq_pin >= 32)
+	if (gpio_is_valid(lp->board_data.phy_irq_pin))
 		gpio_free(lp->board_data.phy_irq_pin);
 
 	unregister_netdev(dev);
diff --git a/drivers/net/ethernet/cadence/at91_ether.h b/drivers/net/ethernet/cadence/at91_ether.h
index 3725fbb0..0ef6328 100644
--- a/drivers/net/ethernet/cadence/at91_ether.h
+++ b/drivers/net/ethernet/cadence/at91_ether.h
@@ -88,6 +88,7 @@  struct at91_private
 	struct macb_platform_data board_data;	/* board-specific
 						 * configuration (shared with
 						 * macb for common data */
+	void __iomem *emac_base;		/* base register address */
 	struct clk *ether_clk;			/* clock */
 
 	/* PHY */