/************************************************************************** * * dmfe.c -- Etherboot device driver for the Davicom * DM9102/DM9102A/DM9102A+DM9801/DM9102A+DM9802 NIC fast ethernet card * * Written 2003-2003 by Timothy Legge <tlegge@rogers.com> * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Portions of this code based on: * * dmfe.c: A Davicom DM9102/DM9102A/DM9102A+DM9801/DM9102A+DM9802 * NIC fast ethernet driver for Linux. * Copyright (C) 1997 Sten Wang * (C)Copyright 1997-1998 DAVICOM Semiconductor,Inc. All Rights Reserved. * * * REVISION HISTORY: * ================ * v1.0 10-02-2004 timlegge Boots ltsp needs cleanup * * Indent Options: indent -kr -i8 * * ***************************************************************************/ FILE_LICENCE ( GPL2_OR_LATER ); /* to get some global routines like printf */ #include "etherboot.h" /* to get the interface to the body of the program */ #include "nic.h" /* to get the PCI support functions, if this is a PCI NIC */ #include <gpxe/pci.h> #include <gpxe/ethernet.h> /* #define EDEBUG 1 */ #ifdef EDEBUG #define dprintf(x) printf x #else #define dprintf(x) #endif /* Condensed operations for readability. */ #define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr)) #define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr)) /* Board/System/Debug information/definition ---------------- */ #define PCI_DM9132_ID 0x91321282 /* Davicom DM9132 ID */ #define PCI_DM9102_ID 0x91021282 /* Davicom DM9102 ID */ #define PCI_DM9100_ID 0x91001282 /* Davicom DM9100 ID */ #define PCI_DM9009_ID 0x90091282 /* Davicom DM9009 ID */ #define DM9102_IO_SIZE 0x80 #define DM9102A_IO_SIZE 0x100 #define TX_MAX_SEND_CNT 0x1 /* Maximum tx packet per time */ #define TX_DESC_CNT 0x10 /* Allocated Tx descriptors */ #define RX_DESC_CNT 0x20 /* Allocated Rx descriptors */ #define TX_FREE_DESC_CNT (TX_DESC_CNT - 2) /* Max TX packet count */ #define TX_WAKE_DESC_CNT (TX_DESC_CNT - 3) /* TX wakeup count */ #define DESC_ALL_CNT (TX_DESC_CNT + RX_DESC_CNT) #define TX_BUF_ALLOC 0x600 #define RX_ALLOC_SIZE 0x620 #define DM910X_RESET 1 #define CR0_DEFAULT 0x00E00000 /* TX & RX burst mode */ #define CR6_DEFAULT 0x00080000 /* HD */ #define CR7_DEFAULT 0x180c1 #define CR15_DEFAULT 0x06 /* TxJabber RxWatchdog */ #define TDES0_ERR_MASK 0x4302 /* TXJT, LC, EC, FUE */ #define MAX_PACKET_SIZE 1514 #define DMFE_MAX_MULTICAST 14 #define RX_COPY_SIZE 100 #define MAX_CHECK_PACKET 0x8000 #define DM9801_NOISE_FLOOR 8 #define DM9802_NOISE_FLOOR 5 #define DMFE_10MHF 0 #define DMFE_100MHF 1 #define DMFE_10MFD 4 #define DMFE_100MFD 5 #define DMFE_AUTO 8 #define DMFE_1M_HPNA 0x10 #define DMFE_TXTH_72 0x400000 /* TX TH 72 byte */ #define DMFE_TXTH_96 0x404000 /* TX TH 96 byte */ #define DMFE_TXTH_128 0x0000 /* TX TH 128 byte */ #define DMFE_TXTH_256 0x4000 /* TX TH 256 byte */ #define DMFE_TXTH_512 0x8000 /* TX TH 512 byte */ #define DMFE_TXTH_1K 0xC000 /* TX TH 1K byte */ #define DMFE_TIMER_WUT (jiffies + HZ * 1) /* timer wakeup time : 1 second */ #define DMFE_TX_TIMEOUT ((3*HZ)/2) /* tx packet time-out time 1.5 s" */ #define DMFE_TX_KICK (HZ/2) /* tx packet Kick-out time 0.5 s" */ #define DMFE_DBUG(dbug_now, msg, value) if (dmfe_debug || (dbug_now)) printk(KERN_ERR DRV_NAME ": %s %lx\n", (msg), (long) (value)) #define SHOW_MEDIA_TYPE(mode) printk(KERN_ERR DRV_NAME ": Change Speed to %sMhz %s duplex\n",mode & 1 ?"100":"10", mode & 4 ? "full":"half"); /* CR9 definition: SROM/MII */ #define CR9_SROM_READ 0x4800 #define CR9_SRCS 0x1 #define CR9_SRCLK 0x2 #define CR9_CRDOUT 0x8 #define SROM_DATA_0 0x0 #define SROM_DATA_1 0x4 #define PHY_DATA_1 0x20000 #define PHY_DATA_0 0x00000 #define MDCLKH 0x10000 #define PHY_POWER_DOWN 0x800 #define SROM_V41_CODE 0x14 #define SROM_CLK_WRITE(data, ioaddr) outl(data|CR9_SROM_READ|CR9_SRCS,ioaddr);udelay(5);outl(data|CR9_SROM_READ|CR9_SRCS|CR9_SRCLK,ioaddr);udelay(5);outl(data|CR9_SROM_READ|CR9_SRCS,ioaddr);udelay(5); #define __CHK_IO_SIZE(pci_id, dev_rev) ( ((pci_id)==PCI_DM9132_ID) || ((dev_rev) >= 0x02000030) ) ? DM9102A_IO_SIZE: DM9102_IO_SIZE #define CHK_IO_SIZE(pci_dev, dev_rev) __CHK_IO_SIZE(((pci_dev)->device << 16) | (pci_dev)->vendor, dev_rev) /* Sten Check */ #define DEVICE net_device /* Structure/enum declaration ------------------------------- */ struct tx_desc { u32 tdes0, tdes1, tdes2, tdes3; /* Data for the card */ void * tx_buf_ptr; /* Data for us */ struct tx_desc * next_tx_desc; } __attribute__ ((aligned(32))); struct rx_desc { u32 rdes0, rdes1, rdes2, rdes3; /* Data for the card */ void * rx_skb_ptr; /* Data for us */ struct rx_desc * next_rx_desc; } __attribute__ ((aligned(32))); static struct dmfe_private { u32 chip_id; /* Chip vendor/Device ID */ u32 chip_revision; /* Chip revision */ u32 cr0_data; // u32 cr5_data; u32 cr6_data; u32 cr7_data; u32 cr15_data; u16 HPNA_command; /* For HPNA register 16 */ u16 HPNA_timer; /* For HPNA remote device check */ u16 NIC_capability; /* NIC media capability */ u16 PHY_reg4; /* Saved Phyxcer register 4 value */ u8 HPNA_present; /* 0:none, 1:DM9801, 2:DM9802 */ u8 chip_type; /* Keep DM9102A chip type */ u8 media_mode; /* user specify media mode */ u8 op_mode; /* real work media mode */ u8 phy_addr; u8 dm910x_chk_mode; /* Operating mode check */ /* NIC SROM data */ unsigned char srom[128]; /* Etherboot Only */ u8 cur_tx; u8 cur_rx; } dfx; static struct dmfe_private *db; enum dmfe_offsets { DCR0 = 0x00, DCR1 = 0x08, DCR2 = 0x10, DCR3 = 0x18, DCR4 = 0x20, DCR5 = 0x28, DCR6 = 0x30, DCR7 = 0x38, DCR8 = 0x40, DCR9 = 0x48, DCR10 = 0x50, DCR11 = 0x58, DCR12 = 0x60, DCR13 = 0x68, DCR14 = 0x70, DCR15 = 0x78 }; enum dmfe_CR6_bits { CR6_RXSC = 0x2, CR6_PBF = 0x8, CR6_PM = 0x40, CR6_PAM = 0x80, CR6_FDM = 0x200, CR6_TXSC = 0x2000, CR6_STI = 0x100000, CR6_SFT = 0x200000, CR6_RXA = 0x40000000, CR6_NO_PURGE = 0x20000000 }; /* Global variable declaration ----------------------------- */ static struct nic_operations dmfe_operations; static unsigned char dmfe_media_mode = DMFE_AUTO; static u32 dmfe_cr6_user_set; /* For module input parameter */ static u8 chkmode = 1; static u8 HPNA_mode; /* Default: Low Power/High Speed */ static u8 HPNA_rx_cmd; /* Default: Disable Rx remote command */ static u8 HPNA_tx_cmd; /* Default: Don't issue remote command */ static u8 HPNA_NoiseFloor; /* Default: HPNA NoiseFloor */ static u8 SF_mode; /* Special Function: 1:VLAN, 2:RX Flow Control 4: TX pause packet */ /********************************************** * Descriptor Ring and Buffer defination ***********************************************/ struct { struct tx_desc txd[TX_DESC_CNT] __attribute__ ((aligned(32))); unsigned char txb[TX_BUF_ALLOC * TX_DESC_CNT] __attribute__ ((aligned(32))); struct rx_desc rxd[RX_DESC_CNT] __attribute__ ((aligned(32))); unsigned char rxb[RX_ALLOC_SIZE * RX_DESC_CNT] __attribute__ ((aligned(32))); } dmfe_bufs __shared; #define txd dmfe_bufs.txd #define txb dmfe_bufs.txb #define rxd dmfe_bufs.rxd #define rxb dmfe_bufs.rxb /* NIC specific static variables go here */ static long int BASE; static u16 read_srom_word(long ioaddr, int offset); static void dmfe_init_dm910x(struct nic *nic); static void dmfe_descriptor_init(struct nic *, unsigned long ioaddr); static void update_cr6(u32, unsigned long); static void send_filter_frame(struct nic *nic); static void dm9132_id_table(struct nic *nic); static u16 phy_read(unsigned long, u8, u8, u32); static void phy_write(unsigned long, u8, u8, u16, u32); static void phy_write_1bit(unsigned long, u32); static u16 phy_read_1bit(unsigned long); static void dmfe_set_phyxcer(struct nic *nic); static void dmfe_parse_srom(struct nic *nic); static void dmfe_program_DM9801(struct nic *nic, int); static void dmfe_program_DM9802(struct nic *nic); static void dmfe_reset(struct nic *nic) { /* system variable init */ db->cr6_data = CR6_DEFAULT | dmfe_cr6_user_set; db->NIC_capability = 0xf; /* All capability */ db->PHY_reg4 = 0x1e0; /* CR6 operation mode decision */ if (!chkmode || (db->chip_id == PCI_DM9132_ID) || (db->chip_revision >= 0x02000030)) { db->cr6_data |= DMFE_TXTH_256; db->cr0_data = CR0_DEFAULT; db->dm910x_chk_mode = 4; /* Enter the normal mode */ } else { db->cr6_data |= CR6_SFT; /* Store & Forward mode */ db->cr0_data = 0; db->dm910x_chk_mode = 1; /* Enter the check mode */ } /* Initilize DM910X board */ dmfe_init_dm910x(nic); return; } /* Initilize DM910X board * Reset DM910X board * Initilize TX/Rx descriptor chain structure * Send the set-up frame * Enable Tx/Rx machine */ static void dmfe_init_dm910x(struct nic *nic) { unsigned long ioaddr = BASE; /* Reset DM910x MAC controller */ outl(DM910X_RESET, ioaddr + DCR0); /* RESET MAC */ udelay(100); outl(db->cr0_data, ioaddr + DCR0); udelay(5); /* Phy addr : DM910(A)2/DM9132/9801, phy address = 1 */ db->phy_addr = 1; /* Parser SROM and media mode */ dmfe_parse_srom(nic); db->media_mode = dmfe_media_mode; /* RESET Phyxcer Chip by GPR port bit 7 */ outl(0x180, ioaddr + DCR12); /* Let bit 7 output port */ if (db->chip_id == PCI_DM9009_ID) { outl(0x80, ioaddr + DCR12); /* Issue RESET signal */ mdelay(300); /* Delay 300 ms */ } outl(0x0, ioaddr + DCR12); /* Clear RESET signal */ /* Process Phyxcer Media Mode */ if (!(db->media_mode & 0x10)) /* Force 1M mode */ dmfe_set_phyxcer(nic); /* Media Mode Process */ if (!(db->media_mode & DMFE_AUTO)) db->op_mode = db->media_mode; /* Force Mode */ /* Initiliaze Transmit/Receive decriptor and CR3/4 */ dmfe_descriptor_init(nic, ioaddr); /* tx descriptor start pointer */ outl(virt_to_le32desc(&txd[0]), ioaddr + DCR4); /* TX DESC address */ /* rx descriptor start pointer */ outl(virt_to_le32desc(&rxd[0]), ioaddr + DCR3); /* RX DESC address */ /* Init CR6 to program DM910x operation */ update_cr6(db->cr6_data, ioaddr); /* Send setup frame */ if (db->chip_id == PCI_DM9132_ID) { dm9132_id_table(nic); /* DM9132 */ } else { send_filter_frame(nic); /* DM9102/DM9102A */ } /* Init CR7, interrupt active bit */ db->cr7_data = CR7_DEFAULT; outl(db->cr7_data, ioaddr + DCR7); /* Init CR15, Tx jabber and Rx watchdog timer */ outl(db->cr15_data, ioaddr + DCR15); /* Enable DM910X Tx/Rx function */ db->cr6_data |= CR6_RXSC | CR6_TXSC | 0x40000; update_cr6(db->cr6_data, ioaddr); } #ifdef EDEBUG void hex_dump(const char *data, const unsigned int len); #endif /************************************************************************** POLL - Wait for a frame ***************************************************************************/ static int dmfe_poll(struct nic *nic, int retrieve) { u32 rdes0; int entry = db->cur_rx % RX_DESC_CNT; int rxlen; rdes0 = le32_to_cpu(rxd[entry].rdes0); if (rdes0 & 0x80000000) return 0; if (!retrieve) return 1; if ((rdes0 & 0x300) != 0x300) { /* A packet without First/Last flag */ printf("strange Packet\n"); rxd[entry].rdes0 = cpu_to_le32(0x80000000); return 0; } else { /* A packet with First/Last flag */ rxlen = ((rdes0 >> 16) & 0x3fff) - 4; /* error summary bit check */ if (rdes0 & 0x8000) { printf("Error\n"); return 0; } if (!(rdes0 & 0x8000) || ((db->cr6_data & CR6_PM) && (rxlen > 6))) { if (db->dm910x_chk_mode & 1) printf("Silly check mode\n"); nic->packetlen = rxlen; memcpy(nic->packet, rxb + (entry * RX_ALLOC_SIZE), nic->packetlen); } } rxd[entry].rdes0 = cpu_to_le32(0x80000000); db->cur_rx++; return 1; } static void dmfe_irq(struct nic *nic __unused, irq_action_t action __unused) { switch ( action ) { case DISABLE : break; case ENABLE : break; case FORCE : break; } } /************************************************************************** TRANSMIT - Transmit a frame ***************************************************************************/ static void dmfe_transmit(struct nic *nic, const char *dest, /* Destination */ unsigned int type, /* Type */ unsigned int size, /* size */ const char *packet) /* Packet */ { u16 nstype; u8 *ptxb; ptxb = &txb[db->cur_tx]; /* Stop Tx */ outl(0, BASE + DCR7); memcpy(ptxb, dest, ETH_ALEN); memcpy(ptxb + ETH_ALEN, nic->node_addr, ETH_ALEN); nstype = htons((u16) type); memcpy(ptxb + 2 * ETH_ALEN, (u8 *) & nstype, 2); memcpy(ptxb + ETH_HLEN, packet, size); size += ETH_HLEN; while (size < ETH_ZLEN) ptxb[size++] = '\0'; /* setup the transmit descriptor */ txd[db->cur_tx].tdes1 = cpu_to_le32(0xe1000000 | size); txd[db->cur_tx].tdes0 = cpu_to_le32(0x80000000); /* give ownership to device */ /* immediate transmit demand */ outl(0x1, BASE + DCR1); outl(db->cr7_data, BASE + DCR7); /* Point to next TX descriptor */ db->cur_tx++; db->cur_tx = db->cur_tx % TX_DESC_CNT; } /************************************************************************** DISABLE - Turn off ethernet interface ***************************************************************************/ static void dmfe_disable ( struct nic *nic __unused ) { /* Reset & stop DM910X board */ outl(DM910X_RESET, BASE + DCR0); udelay(5); phy_write(BASE, db->phy_addr, 0, 0x8000, db->chip_id); } /************************************************************************** PROBE - Look for an adapter, this routine's visible to the outside ***************************************************************************/ #define board_found 1 #define valid_link 0 static int dmfe_probe ( struct nic *nic, struct pci_device *pci ) { uint32_t dev_rev, pci_pmr; int i; if (pci->ioaddr == 0) return 0; BASE = pci->ioaddr; printf("dmfe.c: Found %s Vendor=0x%hX Device=0x%hX\n", pci->driver_name, pci->vendor, pci->device); /* Read Chip revision */ pci_read_config_dword(pci, PCI_REVISION_ID, &dev_rev); dprintf(("Revision %lX\n", dev_rev)); /* point to private storage */ db = &dfx; db->chip_id = ((u32) pci->device << 16) | pci->vendor; BASE = pci_bar_start(pci, PCI_BASE_ADDRESS_0); db->chip_revision = dev_rev; pci_read_config_dword(pci, 0x50, &pci_pmr); pci_pmr &= 0x70000; if ((pci_pmr == 0x10000) && (dev_rev == 0x02000031)) db->chip_type = 1; /* DM9102A E3 */ else db->chip_type = 0; dprintf(("Chip type : %d\n", db->chip_type)); /* read 64 word srom data */ for (i = 0; i < 64; i++) ((u16 *) db->srom)[i] = cpu_to_le16(read_srom_word(BASE, i)); /* Set Node address */ for (i = 0; i < 6; i++) nic->node_addr[i] = db->srom[20 + i]; /* Print out some hardware info */ DBG ( "%s: %s at ioaddr %4.4lx\n", pci->driver_name, eth_ntoa ( nic->node_addr ), BASE ); /* Set the card as PCI Bus Master */ adjust_pci_device(pci); dmfe_reset(nic); nic->irqno = 0; nic->ioaddr = pci->ioaddr; /* point to NIC specific routines */ nic->nic_op = &dmfe_operations; return 1; } /* * Initialize transmit/Receive descriptor * Using Chain structure, and allocate Tx/Rx buffer */ static void dmfe_descriptor_init(struct nic *nic __unused, unsigned long ioaddr) { int i; db->cur_tx = 0; db->cur_rx = 0; /* tx descriptor start pointer */ outl(virt_to_le32desc(&txd[0]), ioaddr + DCR4); /* TX DESC address */ /* rx descriptor start pointer */ outl(virt_to_le32desc(&rxd[0]), ioaddr + DCR3); /* RX DESC address */ /* Init Transmit chain */ for (i = 0; i < TX_DESC_CNT; i++) { txd[i].tx_buf_ptr = &txb[i]; txd[i].tdes0 = cpu_to_le32(0); txd[i].tdes1 = cpu_to_le32(0x81000000); /* IC, chain */ txd[i].tdes2 = cpu_to_le32(virt_to_bus(&txb[i])); txd[i].tdes3 = cpu_to_le32(virt_to_bus(&txd[i + 1])); txd[i].next_tx_desc = &txd[i + 1]; } /* Mark the last entry as wrapping the ring */ txd[i - 1].tdes3 = virt_to_le32desc(&txd[0]); txd[i - 1].next_tx_desc = &txd[0]; /* receive descriptor chain */ for (i = 0; i < RX_DESC_CNT; i++) { rxd[i].rx_skb_ptr = &rxb[i * RX_ALLOC_SIZE]; rxd[i].rdes0 = cpu_to_le32(0x80000000); rxd[i].rdes1 = cpu_to_le32(0x01000600); rxd[i].rdes2 = cpu_to_le32(virt_to_bus(&rxb[i * RX_ALLOC_SIZE])); rxd[i].rdes3 = cpu_to_le32(virt_to_bus(&rxd[i + 1])); rxd[i].next_rx_desc = &rxd[i + 1]; } /* Mark the last entry as wrapping the ring */ rxd[i - 1].rdes3 = cpu_to_le32(virt_to_bus(&rxd[0])); rxd[i - 1].next_rx_desc = &rxd[0]; } /* * Update CR6 value * Firstly stop DM910X , then written value and start */ static void update_cr6(u32 cr6_data, unsigned long ioaddr) { u32 cr6_tmp; cr6_tmp = cr6_data & ~0x2002; /* stop Tx/Rx */ outl(cr6_tmp, ioaddr + DCR6); udelay(5); outl(cr6_data, ioaddr + DCR6); udelay(5); } /* * Send a setup frame for DM9132 * This setup frame initilize DM910X addres filter mode */ static void dm9132_id_table(struct nic *nic __unused) { #ifdef LINUX u16 *addrptr; u8 dmi_addr[8]; unsigned long ioaddr = BASE + 0xc0; /* ID Table */ u32 hash_val; u16 i, hash_table[4]; #endif dprintf(("dm9132_id_table\n")); printf("FIXME: This function is broken. If you have this card contact " "Timothy Legge at the etherboot-user list\n"); #ifdef LINUX //DMFE_DBUG(0, "dm9132_id_table()", 0); /* Node address */ addrptr = (u16 *) nic->node_addr; outw(addrptr[0], ioaddr); ioaddr += 4; outw(addrptr[1], ioaddr); ioaddr += 4; outw(addrptr[2], ioaddr); ioaddr += 4; /* Clear Hash Table */ for (i = 0; i < 4; i++) hash_table[i] = 0x0; /* broadcast address */ hash_table[3] = 0x8000; /* the multicast address in Hash Table : 64 bits */ for (mcptr = mc_list, i = 0; i < mc_cnt; i++, mcptr = mcptr->next) { hash_val = cal_CRC((char *) mcptr->dmi_addr, 6, 0) & 0x3f; hash_table[hash_val / 16] |= (u16) 1 << (hash_val % 16); } /* Write the hash table to MAC MD table */ for (i = 0; i < 4; i++, ioaddr += 4) outw(hash_table[i], ioaddr); #endif } /* * Send a setup frame for DM9102/DM9102A * This setup frame initilize DM910X addres filter mode */ static void send_filter_frame(struct nic *nic) { u8 *ptxb; int i; dprintf(("send_filter_frame\n")); /* point to the current txb incase multiple tx_rings are used */ ptxb = &txb[db->cur_tx]; /* construct perfect filter frame with mac address as first match and broadcast address for all others */ for (i = 0; i < 192; i++) ptxb[i] = 0xFF; ptxb[0] = nic->node_addr[0]; ptxb[1] = nic->node_addr[1]; ptxb[4] = nic->node_addr[2]; ptxb[5] = nic->node_addr[3]; ptxb[8] = nic->node_addr[4]; ptxb[9] = nic->node_addr[5]; /* prepare the setup frame */ txd[db->cur_tx].tdes1 = cpu_to_le32(0x890000c0); txd[db->cur_tx].tdes0 = cpu_to_le32(0x80000000); update_cr6(db->cr6_data | 0x2000, BASE); outl(0x1, BASE + DCR1); /* Issue Tx polling */ update_cr6(db->cr6_data, BASE); db->cur_tx++; } /* * Read one word data from the serial ROM */ static u16 read_srom_word(long ioaddr, int offset) { int i; u16 srom_data = 0; long cr9_ioaddr = ioaddr + DCR9; outl(CR9_SROM_READ, cr9_ioaddr); outl(CR9_SROM_READ | CR9_SRCS, cr9_ioaddr); /* Send the Read Command 110b */ SROM_CLK_WRITE(SROM_DATA_1, cr9_ioaddr); SROM_CLK_WRITE(SROM_DATA_1, cr9_ioaddr); SROM_CLK_WRITE(SROM_DATA_0, cr9_ioaddr); /* Send the offset */ for (i = 5; i >= 0; i--) { srom_data = (offset & (1 << i)) ? SROM_DATA_1 : SROM_DATA_0; SROM_CLK_WRITE(srom_data, cr9_ioaddr); } outl(CR9_SROM_READ | CR9_SRCS, cr9_ioaddr); for (i = 16; i > 0; i--) { outl(CR9_SROM_READ | CR9_SRCS | CR9_SRCLK, cr9_ioaddr); udelay(5); srom_data = (srom_data << 1) | ((inl(cr9_ioaddr) & CR9_CRDOUT) ? 1 : 0); outl(CR9_SROM_READ | CR9_SRCS, cr9_ioaddr); udelay(5); } outl(CR9_SROM_READ, cr9_ioaddr); return srom_data; } /* * Auto sense the media mode */ #if 0 /* not used */ static u8 dmfe_sense_speed(struct nic *nic __unused) { u8 ErrFlag = 0; u16 phy_mode; /* CR6 bit18=0, select 10/100M */ update_cr6((db->cr6_data & ~0x40000), BASE); phy_mode = phy_read(BASE, db->phy_addr, 1, db->chip_id); phy_mode = phy_read(BASE, db->phy_addr, 1, db->chip_id); if ((phy_mode & 0x24) == 0x24) { if (db->chip_id == PCI_DM9132_ID) /* DM9132 */ phy_mode = phy_read(BASE, db->phy_addr, 7, db->chip_id) & 0xf000; else /* DM9102/DM9102A */ phy_mode = phy_read(BASE, db->phy_addr, 17, db->chip_id) & 0xf000; /* printk(DRV_NAME ": Phy_mode %x ",phy_mode); */ switch (phy_mode) { case 0x1000: db->op_mode = DMFE_10MHF; break; case 0x2000: db->op_mode = DMFE_10MFD; break; case 0x4000: db->op_mode = DMFE_100MHF; break; case 0x8000: db->op_mode = DMFE_100MFD; break; default: db->op_mode = DMFE_10MHF; ErrFlag = 1; break; } } else { db->op_mode = DMFE_10MHF; //DMFE_DBUG(0, "Link Failed :", phy_mode); ErrFlag = 1; } return ErrFlag; } #endif /* * Set 10/100 phyxcer capability * AUTO mode : phyxcer register4 is NIC capability * Force mode: phyxcer register4 is the force media */ static void dmfe_set_phyxcer(struct nic *nic __unused) { u16 phy_reg; /* Select 10/100M phyxcer */ db->cr6_data &= ~0x40000; update_cr6(db->cr6_data, BASE); /* DM9009 Chip: Phyxcer reg18 bit12=0 */ if (db->chip_id == PCI_DM9009_ID) { phy_reg = phy_read(BASE, db->phy_addr, 18, db->chip_id) & ~0x1000; phy_write(BASE, db->phy_addr, 18, phy_reg, db->chip_id); } /* Phyxcer capability setting */ phy_reg = phy_read(BASE, db->phy_addr, 4, db->chip_id) & ~0x01e0; if (db->media_mode & DMFE_AUTO) { /* AUTO Mode */ phy_reg |= db->PHY_reg4; } else { /* Force Mode */ switch (db->media_mode) { case DMFE_10MHF: phy_reg |= 0x20; break; case DMFE_10MFD: phy_reg |= 0x40; break; case DMFE_100MHF: phy_reg |= 0x80; break; case DMFE_100MFD: phy_reg |= 0x100; break; } if (db->chip_id == PCI_DM9009_ID) phy_reg &= 0x61; } /* Write new capability to Phyxcer Reg4 */ if (!(phy_reg & 0x01e0)) { phy_reg |= db->PHY_reg4; db->media_mode |= DMFE_AUTO; } phy_write(BASE, db->phy_addr, 4, phy_reg, db->chip_id); /* Restart Auto-Negotiation */ if (db->chip_type && (db->chip_id == PCI_DM9102_ID)) phy_write(BASE, db->phy_addr, 0, 0x1800, db->chip_id); if (!db->chip_type) phy_write(BASE, db->phy_addr, 0, 0x1200, db->chip_id); } /* * Process op-mode * AUTO mode : PHY controller in Auto-negotiation Mode * Force mode: PHY controller in force mode with HUB * N-way force capability with SWITCH */ #if 0 /* not used */ static void dmfe_process_mode(struct nic *nic __unused) { u16 phy_reg; /* Full Duplex Mode Check */ if (db->op_mode & 0x4) db->cr6_data |= CR6_FDM; /* Set Full Duplex Bit */ else db->cr6_data &= ~CR6_FDM; /* Clear Full Duplex Bit */ /* Transciver Selection */ if (db->op_mode & 0x10) /* 1M HomePNA */ db->cr6_data |= 0x40000; /* External MII select */ else db->cr6_data &= ~0x40000; /* Internal 10/100 transciver */ update_cr6(db->cr6_data, BASE); /* 10/100M phyxcer force mode need */ if (!(db->media_mode & 0x18)) { /* Forece Mode */ phy_reg = phy_read(BASE, db->phy_addr, 6, db->chip_id); if (!(phy_reg & 0x1)) { /* parter without N-Way capability */ phy_reg = 0x0; switch (db->op_mode) { case DMFE_10MHF: phy_reg = 0x0; break; case DMFE_10MFD: phy_reg = 0x100; break; case DMFE_100MHF: phy_reg = 0x2000; break; case DMFE_100MFD: phy_reg = 0x2100; break; } phy_write(BASE, db->phy_addr, 0, phy_reg, db->chip_id); if (db->chip_type && (db->chip_id == PCI_DM9102_ID)) mdelay(20); phy_write(BASE, db->phy_addr, 0, phy_reg, db->chip_id); } } } #endif /* * Write a word to Phy register */ static void phy_write(unsigned long iobase, u8 phy_addr, u8 offset, u16 phy_data, u32 chip_id) { u16 i; unsigned long ioaddr; if (chip_id == PCI_DM9132_ID) { ioaddr = iobase + 0x80 + offset * 4; outw(phy_data, ioaddr); } else { /* DM9102/DM9102A Chip */ ioaddr = iobase + DCR9; /* Send 33 synchronization clock to Phy controller */ for (i = 0; i < 35; i++) phy_write_1bit(ioaddr, PHY_DATA_1); /* Send start command(01) to Phy */ phy_write_1bit(ioaddr, PHY_DATA_0); phy_write_1bit(ioaddr, PHY_DATA_1); /* Send write command(01) to Phy */ phy_write_1bit(ioaddr, PHY_DATA_0); phy_write_1bit(ioaddr, PHY_DATA_1); /* Send Phy addres */ for (i = 0x10; i > 0; i = i >> 1) phy_write_1bit(ioaddr, phy_addr & i ? PHY_DATA_1 : PHY_DATA_0); /* Send register addres */ for (i = 0x10; i > 0; i = i >> 1) phy_write_1bit(ioaddr, offset & i ? PHY_DATA_1 : PHY_DATA_0); /* written trasnition */ phy_write_1bit(ioaddr, PHY_DATA_1); phy_write_1bit(ioaddr, PHY_DATA_0); /* Write a word data to PHY controller */ for (i = 0x8000; i > 0; i >>= 1) phy_write_1bit(ioaddr, phy_data & i ? PHY_DATA_1 : PHY_DATA_0); } } /* * Read a word data from phy register */ static u16 phy_read(unsigned long iobase, u8 phy_addr, u8 offset, u32 chip_id) { int i; u16 phy_data; unsigned long ioaddr; if (chip_id == PCI_DM9132_ID) { /* DM9132 Chip */ ioaddr = iobase + 0x80 + offset * 4; phy_data = inw(ioaddr); } else { /* DM9102/DM9102A Chip */ ioaddr = iobase + DCR9; /* Send 33 synchronization clock to Phy controller */ for (i = 0; i < 35; i++) phy_write_1bit(ioaddr, PHY_DATA_1); /* Send start command(01) to Phy */ phy_write_1bit(ioaddr, PHY_DATA_0); phy_write_1bit(ioaddr, PHY_DATA_1); /* Send read command(10) to Phy */ phy_write_1bit(ioaddr, PHY_DATA_1); phy_write_1bit(ioaddr, PHY_DATA_0); /* Send Phy addres */ for (i = 0x10; i > 0; i = i >> 1) phy_write_1bit(ioaddr, phy_addr & i ? PHY_DATA_1 : PHY_DATA_0); /* Send register addres */ for (i = 0x10; i > 0; i = i >> 1) phy_write_1bit(ioaddr, offset & i ? PHY_DATA_1 : PHY_DATA_0); /* Skip transition state */ phy_read_1bit(ioaddr); /* read 16bit data */ for (phy_data = 0, i = 0; i < 16; i++) { phy_data <<= 1; phy_data |= phy_read_1bit(ioaddr); } } return phy_data; } /* * Write one bit data to Phy Controller */ static void phy_write_1bit(unsigned long ioaddr, u32 phy_data) { outl(phy_data, ioaddr); /* MII Clock Low */ udelay(1); outl(phy_data | MDCLKH, ioaddr); /* MII Clock High */ udelay(1); outl(phy_data, ioaddr); /* MII Clock Low */ udelay(1); } /* * Read one bit phy data from PHY controller */ static u16 phy_read_1bit(unsigned long ioaddr) { u16 phy_data; outl(0x50000, ioaddr); udelay(1); phy_data = (inl(ioaddr) >> 19) & 0x1; outl(0x40000, ioaddr); udelay(1); return phy_data; } /* * Parser SROM and media mode */ static void dmfe_parse_srom(struct nic *nic) { unsigned char *srom = db->srom; int dmfe_mode, tmp_reg; /* Init CR15 */ db->cr15_data = CR15_DEFAULT; /* Check SROM Version */ if (((int) srom[18] & 0xff) == SROM_V41_CODE) { /* SROM V4.01 */ /* Get NIC support media mode */ db->NIC_capability = *(u16 *) (srom + 34); db->PHY_reg4 = 0; for (tmp_reg = 1; tmp_reg < 0x10; tmp_reg <<= 1) { switch (db->NIC_capability & tmp_reg) { case 0x1: db->PHY_reg4 |= 0x0020; break; case 0x2: db->PHY_reg4 |= 0x0040; break; case 0x4: db->PHY_reg4 |= 0x0080; break; case 0x8: db->PHY_reg4 |= 0x0100; break; } } /* Media Mode Force or not check */ dmfe_mode = *((int *) srom + 34) & *((int *) srom + 36); switch (dmfe_mode) { case 0x4: dmfe_media_mode = DMFE_100MHF; break; /* 100MHF */ case 0x2: dmfe_media_mode = DMFE_10MFD; break; /* 10MFD */ case 0x8: dmfe_media_mode = DMFE_100MFD; break; /* 100MFD */ case 0x100: case 0x200: dmfe_media_mode = DMFE_1M_HPNA; break; /* HomePNA */ } /* Special Function setting */ /* VLAN function */ if ((SF_mode & 0x1) || (srom[43] & 0x80)) db->cr15_data |= 0x40; /* Flow Control */ if ((SF_mode & 0x2) || (srom[40] & 0x1)) db->cr15_data |= 0x400; /* TX pause packet */ if ((SF_mode & 0x4) || (srom[40] & 0xe)) db->cr15_data |= 0x9800; } /* Parse HPNA parameter */ db->HPNA_command = 1; /* Accept remote command or not */ if (HPNA_rx_cmd == 0) db->HPNA_command |= 0x8000; /* Issue remote command & operation mode */ if (HPNA_tx_cmd == 1) switch (HPNA_mode) { /* Issue Remote Command */ case 0: db->HPNA_command |= 0x0904; break; case 1: db->HPNA_command |= 0x0a00; break; case 2: db->HPNA_command |= 0x0506; break; case 3: db->HPNA_command |= 0x0602; break; } else switch (HPNA_mode) { /* Don't Issue */ case 0: db->HPNA_command |= 0x0004; break; case 1: db->HPNA_command |= 0x0000; break; case 2: db->HPNA_command |= 0x0006; break; case 3: db->HPNA_command |= 0x0002; break; } /* Check DM9801 or DM9802 present or not */ db->HPNA_present = 0; update_cr6(db->cr6_data | 0x40000, BASE); tmp_reg = phy_read(BASE, db->phy_addr, 3, db->chip_id); if ((tmp_reg & 0xfff0) == 0xb900) { /* DM9801 or DM9802 present */ db->HPNA_timer = 8; if (phy_read(BASE, db->phy_addr, 31, db->chip_id) == 0x4404) { /* DM9801 HomeRun */ db->HPNA_present = 1; dmfe_program_DM9801(nic, tmp_reg); } else { /* DM9802 LongRun */ db->HPNA_present = 2; dmfe_program_DM9802(nic); } } } /* * Init HomeRun DM9801 */ static void dmfe_program_DM9801(struct nic *nic __unused, int HPNA_rev) { u32 reg17, reg25; if (!HPNA_NoiseFloor) HPNA_NoiseFloor = DM9801_NOISE_FLOOR; switch (HPNA_rev) { case 0xb900: /* DM9801 E3 */ db->HPNA_command |= 0x1000; reg25 = phy_read(BASE, db->phy_addr, 24, db->chip_id); reg25 = ((reg25 + HPNA_NoiseFloor) & 0xff) | 0xf000; reg17 = phy_read(BASE, db->phy_addr, 17, db->chip_id); break; case 0xb901: /* DM9801 E4 */ reg25 = phy_read(BASE, db->phy_addr, 25, db->chip_id); reg25 = (reg25 & 0xff00) + HPNA_NoiseFloor; reg17 = phy_read(BASE, db->phy_addr, 17, db->chip_id); reg17 = (reg17 & 0xfff0) + HPNA_NoiseFloor + 3; break; case 0xb902: /* DM9801 E5 */ case 0xb903: /* DM9801 E6 */ default: db->HPNA_command |= 0x1000; reg25 = phy_read(BASE, db->phy_addr, 25, db->chip_id); reg25 = (reg25 & 0xff00) + HPNA_NoiseFloor - 5; reg17 = phy_read(BASE, db->phy_addr, 17, db->chip_id); reg17 = (reg17 & 0xfff0) + HPNA_NoiseFloor; break; } phy_write(BASE, db->phy_addr, 16, db->HPNA_command, db->chip_id); phy_write(BASE, db->phy_addr, 17, reg17, db->chip_id); phy_write(BASE, db->phy_addr, 25, reg25, db->chip_id); } /* * Init HomeRun DM9802 */ static void dmfe_program_DM9802(struct nic *nic __unused) { u32 phy_reg; if (!HPNA_NoiseFloor) HPNA_NoiseFloor = DM9802_NOISE_FLOOR; phy_write(BASE, db->phy_addr, 16, db->HPNA_command, db->chip_id); phy_reg = phy_read(BASE, db->phy_addr, 25, db->chip_id); phy_reg = (phy_reg & 0xff00) + HPNA_NoiseFloor; phy_write(BASE, db->phy_addr, 25, phy_reg, db->chip_id); } static struct nic_operations dmfe_operations = { .connect = dummy_connect, .poll = dmfe_poll, .transmit = dmfe_transmit, .irq = dmfe_irq, }; static struct pci_device_id dmfe_nics[] = { PCI_ROM(0x1282, 0x9100, "dmfe9100", "Davicom 9100", 0), PCI_ROM(0x1282, 0x9102, "dmfe9102", "Davicom 9102", 0), PCI_ROM(0x1282, 0x9009, "dmfe9009", "Davicom 9009", 0), PCI_ROM(0x1282, 0x9132, "dmfe9132", "Davicom 9132", 0), /* Needs probably some fixing */ }; PCI_DRIVER ( dmfe_driver, dmfe_nics, PCI_NO_CLASS ); DRIVER ( "DMFE/PCI", nic_driver, pci_driver, dmfe_driver, dmfe_probe, dmfe_disable ); /* * Local variables: * c-basic-offset: 8 * c-indent-level: 8 * tab-width: 8 * End: */