diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2007-07-05 18:01:24 +0200 |
---|---|---|
committer | Sascha Hauer <sha@octopus.labnet.pengutronix.de> | 2007-07-05 18:01:24 +0200 |
commit | 2c6d68cc7d67ec3746e5fd2747c24d81b8a6b09d (patch) | |
tree | c42d53dc643d3109d3bb515f85367f63dde96402 /drivers | |
parent | cab98427c270e2c4a4fd611fe534ed5fc20d9cb5 (diff) | |
download | barebox-2c6d68cc7d67ec3746e5fd2747c24d81b8a6b09d.tar.gz barebox-2c6d68cc7d67ec3746e5fd2747c24d81b8a6b09d.tar.xz |
svn_rev_113
new api, cleanup
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/dm9000.c | 380 | ||||
-rw-r--r-- | drivers/net/dm9000.h | 3 |
2 files changed, 112 insertions, 271 deletions
diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index 687707627e..d675327da1 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -44,12 +44,12 @@ TODO: Homerun NIC and longrun NIC are not functional, only internal at the #include <common.h> #include <command.h> +#include <clock.h> +#include <miiphy.h> #include <net.h> #include <asm/io.h> -#ifdef CONFIG_DRIVER_DM9000 - -#include "dm9000x.h" +#include "dm9000.h" /* Board/System/Debug information/definition ---------------- */ @@ -63,45 +63,6 @@ TODO: Homerun NIC and longrun NIC are not functional, only internal at the #else /* */ #define DM9000_DBG(fmt,args...) #endif /* */ -enum DM9000_PHY_mode { DM9000_10MHD = 0, DM9000_100MHD = - 1, DM9000_10MFD = 4, DM9000_100MFD = 5, DM9000_AUTO = - 8, DM9000_1M_HPNA = 0x10 -}; -enum DM9000_NIC_TYPE { FASTETHER_NIC = 0, HOMERUN_NIC = 1, LONGRUN_NIC = 2 -}; - -/* Structure/enum declaration ------------------------------- */ -typedef struct board_info { - u32 runt_length_counter; /* counter: RX length < 64byte */ - u32 long_length_counter; /* counter: RX length > 1514byte */ - u32 reset_counter; /* counter: RESET */ - u32 reset_tx_timeout; /* RESET caused by TX Timeout */ - u32 reset_rx_status; /* RESET caused by RX Statsus wrong */ - u16 tx_pkt_cnt; - u16 queue_start_addr; - u16 dbug_cnt; - u8 phy_addr; - u8 device_wait_reset; /* device state */ - u8 nic_type; /* NIC type */ - unsigned char srom[128]; -} board_info_t; -board_info_t dmfe_info; - -/* For module input parameter */ -static int media_mode = DM9000_AUTO; -static u8 nfloor = 0; - -/* function declaration ------------------------------------- */ -int eth_init(bd_t * bd); -int eth_send(volatile void *, int); -int eth_rx(void); -void eth_halt(void); -static int dm9000_probe(void); -static u16 phy_read(int); -static void phy_write(int, u16); -static u16 read_srom_word(int); -static u8 DM9000_ior(int); -static void DM9000_iow(int reg, u8 value); /* DM9000 network board routine ---------------------------- */ @@ -129,11 +90,50 @@ dump_regs(void) } #endif /* */ -/* - Search DM9000 board, allocate space and register it -*/ -int -dm9000_probe(void) +static u8 DM9000_ior(int reg) +{ + DM9000_outb(reg, DM9000_IO); + return DM9000_inb(DM9000_DATA); +} + +static void DM9000_iow(int reg, u8 value) +{ + DM9000_outb(reg, DM9000_IO); + DM9000_outb(value, DM9000_DATA); +} + +static u16 phy_read(int reg) +{ + u16 val; + + /* Fill the phyxcer register into REG_0C */ + DM9000_iow(DM9000_EPAR, DM9000_PHY | reg); + DM9000_iow(DM9000_EPCR, 0xc); /* Issue phyxcer read command */ + udelay(100); /* Wait read complete */ + DM9000_iow(DM9000_EPCR, 0x0); /* Clear phyxcer read command */ + val = (DM9000_ior(DM9000_EPDRH) << 8) | DM9000_ior(DM9000_EPDRL); + + /* The read data keeps on REG_0D & REG_0E */ + DM9000_DBG("phy_read(%d): %d\n", reg, val); + return val; +} + +static void phy_write(int reg, u16 value) +{ + + /* Fill the phyxcer register into REG_0C */ + DM9000_iow(DM9000_EPAR, DM9000_PHY | reg); + + /* Fill the written data into REG_0D & REG_0E */ + DM9000_iow(DM9000_EPDRL, (value & 0xff)); + DM9000_iow(DM9000_EPDRH, ((value >> 8) & 0xff)); + DM9000_iow(DM9000_EPCR, 0xa); /* Issue phyxcer write command */ + udelay(500); /* Wait write complete */ + DM9000_iow(DM9000_EPCR, 0x0); /* Clear phyxcer write command */ + DM9000_DBG("phy_write(reg:%d, value:%d)\n", reg, value); +} + +int dm9000_probe(void) { u32 id_val; id_val = DM9000_ior(DM9000_VIDL); @@ -151,144 +151,21 @@ dm9000_probe(void) } } -/* Set PHY operationg mode -*/ -static void -set_PHY_mode(void) -{ - u16 phy_reg4 = 0x01e1, phy_reg0 = 0x1000; - if (!(media_mode & DM9000_AUTO)) { - switch (media_mode) { - case DM9000_10MHD: - phy_reg4 = 0x21; - phy_reg0 = 0x0000; - break; - case DM9000_10MFD: - phy_reg4 = 0x41; - phy_reg0 = 0x1100; - break; - case DM9000_100MHD: - phy_reg4 = 0x81; - phy_reg0 = 0x2000; - break; - case DM9000_100MFD: - phy_reg4 = 0x101; - phy_reg0 = 0x3100; - break; - } - phy_write(4, phy_reg4); /* Set PHY media mode */ - phy_write(0, phy_reg0); /* Tmp */ - } - DM9000_iow(DM9000_GPCR, 0x01); /* Let GPIO0 output */ - DM9000_iow(DM9000_GPR, 0x00); /* Enable PHY */ -} - -/* - Init HomeRun DM9801 -*/ -static void -program_dm9801(u16 HPNA_rev) -{ - __u16 reg16, reg17, reg24, reg25; - if (!nfloor) - nfloor = DM9801_NOISE_FLOOR; - reg16 = phy_read(16); - reg17 = phy_read(17); - reg24 = phy_read(24); - reg25 = phy_read(25); - switch (HPNA_rev) { - case 0xb900: /* DM9801 E3 */ - reg16 |= 0x1000; - reg25 = ((reg24 + nfloor) & 0x00ff) | 0xf000; - break; - case 0xb901: /* DM9801 E4 */ - reg25 = ((reg24 + nfloor) & 0x00ff) | 0xc200; - reg17 = (reg17 & 0xfff0) + nfloor + 3; - break; - case 0xb902: /* DM9801 E5 */ - case 0xb903: /* DM9801 E6 */ - default: - reg16 |= 0x1000; - reg25 = ((reg24 + nfloor - 3) & 0x00ff) | 0xc200; - reg17 = (reg17 & 0xfff0) + nfloor; - } - phy_write(16, reg16); - phy_write(17, reg17); - phy_write(25, reg25); -} - -/* - Init LongRun DM9802 -*/ -static void -program_dm9802(void) -{ - __u16 reg25; - if (!nfloor) - nfloor = DM9802_NOISE_FLOOR; - reg25 = phy_read(25); - reg25 = (reg25 & 0xff00) + nfloor; - phy_write(25, reg25); -} - -/* Identify NIC type -*/ -static void -identify_nic(void) -{ - struct board_info *db = &dmfe_info; /* Point a board information structure */ - u16 phy_reg3; - DM9000_iow(DM9000_NCR, NCR_EXT_PHY); - phy_reg3 = phy_read(3); - switch (phy_reg3 & 0xfff0) { - case 0xb900: - if (phy_read(31) == 0x4404) { - db->nic_type = HOMERUN_NIC; - program_dm9801(phy_reg3); - DM9000_DBG("found homerun NIC\n"); - } else { - db->nic_type = LONGRUN_NIC; - DM9000_DBG("found longrun NIC\n"); - program_dm9802(); - } - break; - default: - db->nic_type = FASTETHER_NIC; - break; - } - DM9000_iow(DM9000_NCR, 0); -} - -/* General Purpose dm9000 reset routine */ -static void -dm9000_reset(void) +static void dm9000_reset(void) { DM9000_DBG("resetting\n"); DM9000_iow(DM9000_NCR, NCR_RST); udelay(1000); /* delay 1ms */ } -/* Initilize dm9000 board -*/ -int -eth_init(bd_t * bd) +int dm9000_eth_init(struct eth_device *ndev, bd_t * bd) { - int i, oft, lnk; - DM9000_DBG("eth_init()\n"); + printf("dm9000_eth_init()\n"); /* RESET device */ dm9000_reset(); dm9000_probe(); - /* NIC Type: FASTETHER, HOMERUN, LONGRUN */ - identify_nic(); - - /* GPIO0 on pre-activate PHY */ - DM9000_iow(DM9000_GPR, 0x00); /*REG_1F bit0 activate phyxcer */ - - /* Set PHY */ - set_PHY_mode(); - /* Program operating register */ DM9000_iow(DM9000_NCR, 0x0); /* only intern phy supported by now */ DM9000_iow(DM9000_TCR, 0); /* TX Polling clear */ @@ -299,32 +176,40 @@ eth_init(bd_t * bd) DM9000_iow(DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END); /* clear TX status */ DM9000_iow(DM9000_ISR, 0x0f); /* Clear interrupt status */ - /* Set Node address */ - for (i = 0; i < 6; i++) - ((u16 *) bd->bi_enetaddr)[i] = read_srom_word(i); - printf("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", bd->bi_enetaddr[0], - bd->bi_enetaddr[1], bd->bi_enetaddr[2], bd->bi_enetaddr[3], - bd->bi_enetaddr[4], bd->bi_enetaddr[5]); - for (i = 0, oft = 0x10; i < 6; i++, oft++) - DM9000_iow(oft, bd->bi_enetaddr[i]); - for (i = 0, oft = 0x16; i < 8; i++, oft++) - DM9000_iow(oft, 0xff); + return 0; +} - /* read back mac, just to be sure */ - for (i = 0, oft = 0x10; i < 6; i++, oft++) - DM9000_DBG("%02x:", DM9000_ior(oft)); - DM9000_DBG("\n"); + +int dm9000_eth_open(struct eth_device *ndev, bd_t * bd) +{ + int lnk, i = 0, ctl; /* Activate DM9000 */ + DM9000_iow(DM9000_GPCR, 0x01); /* Let GPIO0 output */ + DM9000_iow(DM9000_GPR, 0x00); /* Enable PHY */ DM9000_iow(DM9000_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN); /* RX enable */ DM9000_iow(DM9000_IMR, IMR_PAR); /* Enable TX/RX interrupt mask */ - i = 0; - while (!(phy_read(1) & 0x20)) { /* autonegation complete bit */ + + phy_write(0, 0x8000); /* PHY RESET */ + + ctl = phy_read(PHY_BMCR); + + if (ctl < 0) + return ctl; + + ctl |= (PHY_BMCR_AUTON | PHY_BMCR_RST_NEG); + + /* Don't isolate the PHY if we're negotiating */ + ctl &= ~(PHY_BMCR_ISO); + + phy_write(PHY_BMCR, ctl); + + while (!(phy_read(1) & 0x20)) { /* autonegation complete bit */ udelay(1000); i++; - if (i == 10000) { + if (i == 5000) { printf("could not establish link\n"); - return 0; + break; } } @@ -352,16 +237,11 @@ eth_init(bd_t * bd) return 0; } -/* - Hardware start transmission. - Send a packet to media from the upper layer. -*/ -int -eth_send(volatile void *packet, int length) +int dm9000_eth_send (struct eth_device *ndev, volatile void *packet, int length) { char *data_ptr; u32 tmplen, i; - int tmo; + uint64_t tmo; DM9000_DBG("eth_send: length: %d\n", length); for (i = 0; i < length; i++) { if (i % 8 == 0) @@ -400,9 +280,9 @@ eth_send(volatile void *packet, int length) DM9000_iow(DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */ /* wait for end of transmission */ - tmo = get_timer(0) + 5 * CFG_HZ; + tmo = get_time_ns(); while (DM9000_ior(DM9000_TCR) & TCR_TXREQ) { - if (get_timer(0) >= tmo) { + if (is_timeout(tmo, 5 * SECOND)) { printf("transmission timeout\n"); break; } @@ -411,27 +291,17 @@ eth_send(volatile void *packet, int length) return 0; } -/* - Stop the interface. - The interface is stopped when it is brought. -*/ -void -eth_halt(void) +void dm9000_eth_halt (struct eth_device *ndev) { - DM9000_DBG("eth_halt\n"); + printf("eth_halt\n"); - /* RESET devie */ phy_write(0, 0x8000); /* PHY RESET */ DM9000_iow(DM9000_GPR, 0x01); /* Power-Down PHY */ DM9000_iow(DM9000_IMR, 0x80); /* Disable all interrupt */ DM9000_iow(DM9000_RCR, 0x00); /* Disable RX */ } -/* - Received a packet and pass to upper layer -*/ -int -eth_rx(void) +int dm9000_eth_rx (struct eth_device *ndev) { u8 rxbyte, *rdptr = (u8 *) NetRxPackets[0]; u16 RxStatus, RxLen = 0; @@ -519,11 +389,7 @@ eth_rx(void) return 0; } -/* - Read a word data from SROM -*/ -static u16 -read_srom_word(int offset) +static u16 read_srom_word(int offset) { DM9000_iow(DM9000_EPAR, offset); DM9000_iow(DM9000_EPCR, 0x4); @@ -532,62 +398,40 @@ read_srom_word(int offset) return (DM9000_ior(DM9000_EPDRL) + (DM9000_ior(DM9000_EPDRH) << 8)); } -/* - Read a byte from I/O port -*/ -static u8 -DM9000_ior(int reg) +static int dm9000_get_mac_address(struct eth_device *eth, unsigned char *adr) { - DM9000_outb(reg, DM9000_IO); - return DM9000_inb(DM9000_DATA); -} + int i; -/* - Write a byte to I/O port -*/ -static void -DM9000_iow(int reg, u8 value) -{ - DM9000_outb(reg, DM9000_IO); - DM9000_outb(value, DM9000_DATA); + for (i = 0; i < 3; i++) + ((u16 *) adr)[i] = read_srom_word(i); + + return 0; } -/* - Read a word from phyxcer -*/ -static u16 -phy_read(int reg) +static int dm9000_set_mac_address(struct eth_device *eth, unsigned char *adr) { - u16 val; - - /* Fill the phyxcer register into REG_0C */ - DM9000_iow(DM9000_EPAR, DM9000_PHY | reg); - DM9000_iow(DM9000_EPCR, 0xc); /* Issue phyxcer read command */ - udelay(100); /* Wait read complete */ - DM9000_iow(DM9000_EPCR, 0x0); /* Clear phyxcer read command */ - val = (DM9000_ior(DM9000_EPDRH) << 8) | DM9000_ior(DM9000_EPDRL); + int i, oft; +printf("dm9000_set_mac_address\n"); + for (i = 0, oft = 0x10; i < 6; i++, oft++) + DM9000_iow(oft, adr[i]); + for (i = 0, oft = 0x16; i < 8; i++, oft++) + DM9000_iow(oft, 0xff); - /* The read data keeps on REG_0D & REG_0E */ - DM9000_DBG("phy_read(%d): %d\n", reg, val); - return val; +#if 0 + for (i = 0; i < 5; i++) + printf ("%02x:", adr[i]); + printf ("%02x\n", adr[5]); +#endif + return -0; } -/* - Write a word to phyxcer -*/ -static void -phy_write(int reg, u16 value) -{ - - /* Fill the phyxcer register into REG_0C */ - DM9000_iow(DM9000_EPAR, DM9000_PHY | reg); +struct eth_device dm9000_eth = { + .init = dm9000_eth_init, + .open = dm9000_eth_open, + .send = dm9000_eth_send, + .recv = dm9000_eth_rx, + .halt = dm9000_eth_halt, + .get_mac_address = dm9000_get_mac_address, + .set_mac_address = dm9000_set_mac_address, +}; - /* Fill the written data into REG_0D & REG_0E */ - DM9000_iow(DM9000_EPDRL, (value & 0xff)); - DM9000_iow(DM9000_EPDRH, ((value >> 8) & 0xff)); - DM9000_iow(DM9000_EPCR, 0xa); /* Issue phyxcer write command */ - udelay(500); /* Wait write complete */ - DM9000_iow(DM9000_EPCR, 0x0); /* Clear phyxcer write command */ - DM9000_DBG("phy_write(reg:%d, value:%d)\n", reg, value); -} -#endif /* CONFIG_DRIVER_DM9000 */ diff --git a/drivers/net/dm9000.h b/drivers/net/dm9000.h index f47ff8cb34..442c86ddbd 100644 --- a/drivers/net/dm9000.h +++ b/drivers/net/dm9000.h @@ -2,8 +2,6 @@ * dm9000 Ethernet */ -#ifdef CONFIG_DRIVER_DM9000 - #define DM9000_ID 0x90000A46 #define DM9000_PKT_MAX 1536 /* Received packet max size */ #define DM9000_PKT_RDY 0x01 /* Packet ready to receive */ @@ -116,4 +114,3 @@ #define IMR_PTM (1<<1) #define IMR_PRM (1<<0) -#endif |