/*
* 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/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 timer_list check_timer;
#define LINK_POLL_INTERVAL (HZ)
/* ..................................................................... */
/*
* 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_