diff options
author | kato <kato@FreeBSD.org> | 1997-06-17 11:26:50 +0000 |
---|---|---|
committer | kato <kato@FreeBSD.org> | 1997-06-17 11:26:50 +0000 |
commit | ec7ac3a30e38c701708d07fc6d764a4ae492f877 (patch) | |
tree | 87fc9345ab2b922318047e64de6370b20da7dee4 | |
parent | 4bddfca39812c69bc87b94b8e5b5bf29c2292f7c (diff) | |
download | FreeBSD-src-ec7ac3a30e38c701708d07fc6d764a4ae492f877.zip FreeBSD-src-ec7ac3a30e38c701708d07fc6d764a4ae492f877.tar.gz |
Added CONTEC C-NET(9N) and C-NET(98)P2 support.
Submitted by: Chiharu Shibata <chi@rd.njk.co.jp>
-rw-r--r-- | sys/pc98/pc98/if_fe.c | 417 |
1 files changed, 415 insertions, 2 deletions
diff --git a/sys/pc98/pc98/if_fe.c b/sys/pc98/pc98/if_fe.c index 5e85f76..78a5da9 100644 --- a/sys/pc98/pc98/if_fe.c +++ b/sys/pc98/pc98/if_fe.c @@ -21,7 +21,7 @@ */ /* - * $Id: if_fe.c,v 1.20 1997/02/22 09:43:38 peter Exp $ + * $Id: if_fe.c,v 1.21 1997/03/24 12:29:30 bde Exp $ * * Device driver for Fujitsu MB86960A/MB86965A based Ethernet cards. * To be used with FreeBSD 2.x @@ -227,6 +227,7 @@ static struct fe_softc { u_char proto_dlcr6; /* DLCR6 prototype. */ u_char proto_dlcr7; /* DLCR7 prototype. */ u_char proto_bmpr13; /* BMPR13 prototype. */ + u_char proto_bmpr14; /* BMPR14 prototype. */ /* Vendor specific hooks. */ void ( * init )( struct fe_softc * ); /* Just before fe_init(). */ @@ -263,6 +264,8 @@ static void fe_watchdog ( struct ifnet * ); #ifdef PC98 static int fe_probe_re1000 ( DEVICE *, struct fe_softc * ); static int fe_probe_re1000p( DEVICE *, struct fe_softc * ); +static int fe_probe_cnet9ne ( DEVICE *, struct fe_softc * ); +static int fe_probe_cnet98p2( DEVICE *, struct fe_softc * ); #else static int fe_probe_fmv ( DEVICE *, struct fe_softc * ); static int fe_probe_ati ( DEVICE *, struct fe_softc * ); @@ -477,6 +480,11 @@ static u_short const fe_re1000_addr [] = 0x1D0, 0x1D2, 0x1D4, 0x1D6, 0x1D8, 0x1DA, 0x1DC, 0x1DE, 0 }; static u_short const fe_re1000p_addr [] = { 0x0D0, 0x0D2, 0x0D4, 0x0D8, 0x1D4, 0x1D6, 0x1D8, 0x1DA, 0 }; +static u_short const fe_cnet9ne_addr [] = + { 0x73D0, 0 }; +static u_short const fe_cnet98p2_addr [] = + { 0x03D0, 0x13D0, 0x23D0, 0x33D0, 0x43D0, 0x53D0, 0x63D0, + 0x73D0, 0x83D0, 0x93D0, 0xA3D0, 0xB3D0, 0xC3D0, 0xD3D0, 0 }; #else static u_short const fe_fmv_addr [] = { 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x300, 0x340, 0 }; @@ -489,6 +497,9 @@ static struct fe_probe_list const fe_probe_list [] = #ifdef PC98 { fe_probe_re1000, fe_re1000_addr }, { fe_probe_re1000p, fe_re1000p_addr }, + /* XXX: We must probe C-NET(98)P2 after C-NET(9N)E. */ + { fe_probe_cnet9ne, fe_cnet9ne_addr }, + { fe_probe_cnet98p2, fe_cnet98p2_addr }, #else { fe_probe_fmv, fe_fmv_addr }, { fe_probe_ati, fe_ati_addr }, @@ -525,6 +536,9 @@ fe_probe ( DEVICE * dev ) sc = &fe_softc[ dev->id_unit ]; sc->sc_unit = dev->id_unit; + /* TODO: Should be in each probe routines */ + sc->proto_bmpr14 = 0; + #if NCRD > 0 /* * If PC-Card probe required, then register driver with @@ -967,6 +981,405 @@ fe_probe_re1000p ( DEVICE * isa_dev, struct fe_softc * sc ) */ return 2; /* ??? */ } + +/* + * Probe and initialization for Contec C-NET(9N)E series. + */ + +/* TODO: Should be in "if_fereg.h" */ +#define FE_CNET9NE_INTR 0x10 /* Interrupt Mask? */ +#define FE_CNET9NE_MAC0 0x11 /* Station(MAC) address */ +#define FE_CNET9NE_MAC1 0x13 +#define FE_CNET9NE_MAC2 0x15 +#define FE_CNET9NE_MAC3 0x17 +#define FE_CNET9NE_MAC4 0x19 +#define FE_CNET9NE_MAC5 0x1B + +/* TODO: Should be in "ic/mb86960.h" */ +#define FE_D7_ENDEC 0xC0 /* Encoder/Decoder mode(86960 only) */ +#define FE_D7_ENDEC_NORMAL_NICE 0x00 /* Normal NICE */ +#define FE_D7_ENDEC_NICE_MONITOR 0x40 /* NICE + Monitor */ +#define FE_D7_ENDEC_BYPASS 0x80 /* Encoder/Decoder Bypass */ +#define FE_D7_ENDEC_TEST 0xC0 /* Encoder/Decoder Test */ + +static int +fe_probe_cnet9ne ( DEVICE * isa_dev, struct fe_softc * sc ) +{ + int i; + u_char c; + +#if FE_DEBUG >= 3 + log( LOG_INFO, "fe%d: probe (0x%x) for C-NET(9N)E\n", sc->sc_unit, sc->iobase ); +#endif + + /* Setup an I/O address mapping table. */ + for ( i = 0; i < 16; i++ ) { + sc->ioaddr[i] = sc->iobase + i; + } + for ( ; i < MAXREGISTERS; i++ ) { + sc->ioaddr[i] = sc->iobase + 0x400 - 16 + i; + } + +#if FE_DEBUG >= 3 + fe_dump( LOG_INFO, sc, NULL ); +#endif + + /* Get our station address from EEPROM. */ + sc->sc_enaddr[0] = inb( sc->ioaddr[FE_CNET9NE_MAC0] ); + sc->sc_enaddr[1] = inb( sc->ioaddr[FE_CNET9NE_MAC1] ); + sc->sc_enaddr[2] = inb( sc->ioaddr[FE_CNET9NE_MAC2] ); + sc->sc_enaddr[3] = inb( sc->ioaddr[FE_CNET9NE_MAC3] ); + sc->sc_enaddr[4] = inb( sc->ioaddr[FE_CNET9NE_MAC4] ); + sc->sc_enaddr[5] = inb( sc->ioaddr[FE_CNET9NE_MAC5] ); + +#if 1 + /* + * Check the Ethernet address here. + * + * Contec uses 00 80 4C ?? ?? ??. + */ + if ( sc->sc_enaddr[0] != (u_char)0x00 + || sc->sc_enaddr[1] != (u_char)0x80 + || sc->sc_enaddr[2] != (u_char)0x4C ) { +#else + /* + * Make sure we got a valid Ethernet address. + */ + if ( ( sc->sc_enaddr[0] & 0x03 ) != 0x00 /* Multicast or Local address. */ + || ( sc->sc_enaddr[0] | sc->sc_enaddr[1] | sc->sc_enaddr[2] ) == 0x00 ) { +#endif +#if FE_DEBUG >= 3 + log( LOG_INFO, "fe%d: invalid MAC adrs(%x:%x:%x:%x:%x:%x)\n" + , sc->sc_unit + , (u_char)sc->sc_enaddr[0], (u_char)sc->sc_enaddr[1] + , (u_char)sc->sc_enaddr[2], (u_char)sc->sc_enaddr[3] + , (u_char)sc->sc_enaddr[4], (u_char)sc->sc_enaddr[5] ); +#endif + return 0; + } + + /* See if C-NET(9N)E is on its address. */ + if ( inb( sc->ioaddr[FE_DLCR6] ) == (u_char)0xff ) { +#if FE_DEBUG >= 3 + log( LOG_INFO, "fe%d: inb(%x) returns 0xff\n" + , sc->sc_unit, sc->ioaddr[FE_DLCR6] ); +#endif + return 0; + } + + sc->typestr = "C-NET9NE"; + + /* + * Program the 86960 as follows: + * SRAM: 64KB, word-wide access. + * Transmission buffer: 4KB x 2. + * System bus interface: 16 bits. + * Encoder/Decoder mode: Normal NICE. + * + * 86960 manual says that SRAM access-time can't be configured. + * (must be 1) + */ + sc->proto_dlcr4 = FE_D4_LBC_DISABLE | FE_D4_CNTRL; + sc->proto_dlcr5 = FE_D5_RMTRST; /* reserved bit(must be 1) */ + sc->proto_dlcr6 = FE_D6_BUFSIZ_64KB | FE_D6_TXBSIZ_2x4KB + | FE_D6_BBW_WORD | FE_D6_SBW_WORD | FE_D6_SRAM; +#ifndef CNET9NC + sc->proto_dlcr7 = FE_D7_BYTSWP_LH | FE_D7_ENDEC_NORMAL_NICE; +#else + sc->proto_dlcr7 = FE_D7_BYTSWP_LH | FE_D7_ENDEC_BYPASS; +#endif + sc->proto_bmpr13 = FE_B13_TPTYPE_UTP | FE_B13_PORT_AUTO; + sc->proto_bmpr14 = 0; + + sc->stop = sc->init = NULL; + +#if FE_DEBUG >= 3 + fe_dump( LOG_INFO, sc, "C-NET(9N)E found" ); +#endif + + /* Initialize 86960. */ + outb( sc->ioaddr[FE_DLCR6], sc->proto_dlcr6 | FE_D6_DLC_DISABLE ); + DELAY( 200 ); + +#if 1 /* XXX: Is this really necessary? FIXME. */ + c = inb( sc->ioaddr[FE_DLCR1] ); + if ( c == (u_char)0xff ) { +#if FE_DEBUG >= 3 + log( LOG_INFO, "fe%d: inb(%x) returns 0xff\n" + , sc->sc_unit, sc->ioaddr[FE_DLCR1] ); +#endif + return 0; + } + if ( ( c & FE_D1_PKTRDY ) == 0 ) { + outb( sc->ioaddr[FE_DLCR1], FE_D1_PKTRDY ); + } +#endif + + /* Disable all interrupts. */ + outb( sc->ioaddr[FE_DLCR2], 0 ); + outb( sc->ioaddr[FE_DLCR3], 0 ); + +#ifndef CNET9NC + /* Enable interrupt? FIXME. */ + outb( sc->ioaddr[FE_CNET9NE_INTR], 0x10 ); +#endif + +#if FE_DEBUG >= 3 + fe_dump( LOG_INFO, sc, "end of fe_probe_cnet9ne()" ); +#endif + + /* + * XXX: The I/O address range is fragmented in the CNET(9N)E. + * "16" is the number of regs at iobase. + */ + return 16; +} + +/* + * Probe and initialization for Contec C-NET(98)P2 series. + */ + +/* + * Routines to read all bytes from the config EEPROM through TDK 78Q8377A. + * I'm not sure what exactly I'm doing here... I was told just to follow + * the steps, and it worked. Could someone tell me why the following + * code works? FIXME. + */ + +static void +fe_strobe_eeprom_tdk ( u_short bmpr12 ) +{ + outb( bmpr12, 0x10 ); + outb( bmpr12, 0x12 ); + outb( bmpr12, 0x12 ); + outb( bmpr12, 0x16 ); + outb( bmpr12, 0x12 | 0x01 ); + outb( bmpr12, 0x16 | 0x01 ); + outb( bmpr12, 0x12 | 0x01 ); + outb( bmpr12, 0x16 | 0x01 ); + outb( bmpr12, 0x12 ); + outb( bmpr12, 0x16 ); +} + +static void +fe_read_eeprom_tdk ( struct fe_softc * sc, u_char * data ) +{ + u_short bmpr12 = sc->ioaddr[FE_DLCR12]; + u_char n, val, bit; + + outb( sc->ioaddr[FE_DLCR6], FE_D6_BBW_WORD | FE_D6_SBW_WORD + | FE_D6_DLC_DISABLE ); + outb( sc->ioaddr[FE_DLCR7], FE_D7_BYTSWP_LH | FE_D7_RBS_BMPR + | FE_D7_RDYPNS | FE_D7_POWER_UP ); + + /* Read bytes from EEPROM; two bytes per an iteration. */ + for ( n = 0; n < FE_EEPROM_SIZE / 2; n++ ) { + + /* Start EEPROM access. */ + fe_strobe_eeprom_tdk( bmpr12 ); + + /* Pass the iteration count to the chip. */ + for ( bit = 0x80; bit != 0x00; bit >>= 1 ) { + val = ( n & bit ) ? 0x01 : 0x00; + outb( bmpr12, 0x12 | val ); + outb( bmpr12, 0x16 | val ); + } + + /* Read a byte. */ + val = 0; + for ( bit = 0x80; bit != 0x00; bit >>= 1 ) { + outb( bmpr12, 0x12 ); + outb( bmpr12, 0x16 ); + if ( inb( bmpr12 ) & 0x01 ) { + val |= bit; + } + } + *data++ = val; + + /* Read one more byte. */ + val = 0; + for ( bit = 0x80; bit != 0x00; bit >>= 1 ) { + outb( bmpr12, 0x12 ); + outb( bmpr12, 0x16 ); + if ( inb( bmpr12 ) & 0x01 ) { + val |= bit; + } + } + *data++ = val; + + outb( bmpr12, 0x10 ); + } + + /* Reset the EEPROM interface. */ + outb( bmpr12, 0x00 ); + +#if FE_DEBUG >= 3 + /* Report what we got. */ + data -= FE_EEPROM_SIZE; + log( LOG_INFO, "fe%d: EEPROM:" + " %02x%02x%02x%02x %02x%02x%02x%02x -" + " %02x%02x%02x%02x %02x%02x%02x%02x -" + " %02x%02x%02x%02x %02x%02x%02x%02x -" + " %02x%02x%02x%02x %02x%02x%02x%02x\n", + sc->sc_unit, + data[ 0], data[ 1], data[ 2], data[ 3], + data[ 4], data[ 5], data[ 6], data[ 7], + data[ 8], data[ 9], data[10], data[11], + data[12], data[13], data[14], data[15], + data[16], data[17], data[18], data[19], + data[20], data[21], data[22], data[23], + data[24], data[25], data[26], data[27], + data[28], data[29], data[30], data[31] ); +#endif +} + +/* TODO: Should be in "if_fereg.h" */ +#define FE_CNET98P2_EEP_IRQ (0x04 * 2 + 1) /* Irq */ +#define FE_CNET98P2_EEP_ADDR (0x08 * 2) /* Station(MAC) address */ +#define FE_CNET98P2_EEP_DUPLEX (0x0c * 2 + 1) /* Duplex mode */ + +static int +fe_probe_cnet98p2 ( DEVICE * isa_dev, struct fe_softc * sc ) +{ + int i; + u_char duplex; + u_char eeprom[FE_EEPROM_SIZE]; + static u_short const irqmap [] = + /* INT0 INT1 INT2 */ + { NO_IRQ, NO_IRQ, NO_IRQ, IRQ3, NO_IRQ, IRQ5, IRQ6, NO_IRQ, + NO_IRQ, IRQ9, IRQ10, NO_IRQ, IRQ12, IRQ13, NO_IRQ, NO_IRQ }; + /* INT3 INT4 INT5 INT6 */ + +#if FE_DEBUG >= 3 + log( LOG_INFO, "fe%d: probe (0x%x) for C-NET(98)P2\n", sc->sc_unit, sc->iobase ); +#endif + + /* Setup an I/O address mapping table. */ + for ( i = 0; i < 16; i++ ) { + sc->ioaddr[i] = sc->iobase + i; + } + /* Full unused slots with a safe address. */ + for ( ; i < MAXREGISTERS; i++ ) { + sc->ioaddr[i] = sc->iobase; + } + +#if FE_DEBUG >= 3 + fe_dump( LOG_INFO, sc, NULL ); +#endif + + /* See if C-NET(98)P2 is on its address. */ + if ( inb( sc->ioaddr[FE_DLCR0] ) == (u_char)0xff ) { +#if FE_DEBUG >= 3 + log( LOG_INFO, "fe%d: inb(%x) returns 0xff\n" + , sc->sc_unit, sc->ioaddr[FE_DLCR0] ); +#endif + return 0; + } + if ( inb( sc->ioaddr[FE_DLCR6] ) == (u_char)0xff ) { +#if FE_DEBUG >= 3 + log( LOG_INFO, "fe%d: inb(%x) returns 0xff\n" + , sc->sc_unit, sc->ioaddr[FE_DLCR6] ); +#endif + return 0; + } + + /* + * We are now almost sure we have a 78Q8377 at the given + * address. So, read EEPROM through 78Q8377. We have to write + * into LSI registers to read from EEPROM. FIXME. + */ + fe_read_eeprom_tdk( sc, eeprom ); + + /* + * Initialize constants in the per-line structure. + */ + + /* Get our station address from EEPROM. */ + bcopy( eeprom + FE_CNET98P2_EEP_ADDR, sc->sc_enaddr, ETHER_ADDR_LEN ); + +#if 1 + /* + * Check the Ethernet address here. + * + * Contec uses 00 80 4C ?? ?? ??. + */ + if ( sc->sc_enaddr[0] != (u_char)0x00 + || sc->sc_enaddr[1] != (u_char)0x80 + || sc->sc_enaddr[2] != (u_char)0x4C ) { +#else + /* + * Make sure we got a valid Ethernet address. + */ + if ( ( sc->sc_enaddr[0] & 0x03 ) != 0x00 /* Multicast or Local address. */ + || ( sc->sc_enaddr[0] | sc->sc_enaddr[1] | sc->sc_enaddr[2] ) == 0x00 ) { +#endif +#if FE_DEBUG >= 3 + log( LOG_INFO, "fe%d: invalid MAC adrs(%x:%x:%x:%x:%x:%x)\n" + , sc->sc_unit + , (u_char)sc->sc_enaddr[0], (u_char)sc->sc_enaddr[1] + , (u_char)sc->sc_enaddr[2], (u_char)sc->sc_enaddr[3] + , (u_char)sc->sc_enaddr[4], (u_char)sc->sc_enaddr[5] ); +#endif + return 0; + } + + /* + * Get IRQ configuration from EEPROM. + */ + isa_dev->id_irq = irqmap[ eeprom[FE_CNET98P2_EEP_IRQ] ]; + if ( isa_dev->id_irq == NO_IRQ ) { +#if FE_DEBUG >= 3 + log( LOG_INFO, "fe%d: invalid irq configuration(%d)\n" + , sc->sc_unit, eeprom[FE_CNET98P2_EEP_IRQ] ); +#endif + return 0; + } + + /* + * Get Duplex-mode configuration from EEPROM. + */ + duplex = eeprom[FE_CNET98P2_EEP_DUPLEX] & FE_D4_DSC; + sc->typestr = ( duplex ? "CNET98P2(Full duplex)" + : "CNET98P2(Half duplex)" ); + + /* + * Program the 78Q8377 as follows: + * SRAM: 32KB, 100ns, byte-wide access. + * Transmission buffer: 4KB x 2. + * System bus interface: 16 bits. + * XXX: Should we add IDENT_NICE or IDENT_EC to DLCR7? FIXME. + */ + sc->proto_dlcr4 = FE_D4_LBC_DISABLE | FE_D4_CNTRL | duplex; + sc->proto_dlcr5 = 0; + sc->proto_dlcr6 = FE_D6_BUFSIZ_32KB | FE_D6_TXBSIZ_2x4KB + | FE_D6_BBW_BYTE | FE_D6_SBW_WORD | FE_D6_SRAM_100ns; + sc->proto_dlcr7 = FE_D7_BYTSWP_LH; + sc->proto_bmpr13 = FE_B13_TPTYPE_UTP | FE_B13_PORT_AUTO; + sc->proto_bmpr14 = FE_B14_FILTER; + + sc->stop = sc->init = NULL; + +#if FE_DEBUG >= 3 + fe_dump( LOG_INFO, sc, "C-NET(98)P2 found" ); +#endif + + /* Initialize 78Q8377. */ + outb( sc->ioaddr[FE_DLCR6], sc->proto_dlcr6 | FE_D6_DLC_DISABLE ); + DELAY( 200 ); + + /* Disable all interrupts. */ + outb( sc->ioaddr[FE_DLCR2], 0 ); + outb( sc->ioaddr[FE_DLCR3], 0 ); + +#if FE_DEBUG >= 3 + fe_dump( LOG_INFO, sc, "end of fe_probe_cnet98p2()" ); +#endif + + /* + * That's all. C-NET(98)P2 occupies 16 I/O addresses, as always. + */ + return 16; +} #else /* * Probe and initialization for Fujitsu FMV-180 series boards @@ -2362,7 +2775,7 @@ fe_droppacket ( struct fe_softc * sc, int len ) /* Read 4 more bytes, and skip the rest of the packet. */ ( void )inw( sc->ioaddr[ FE_BMPR8 ] ); ( void )inw( sc->ioaddr[ FE_BMPR8 ] ); - outb( sc->ioaddr[ FE_BMPR14 ], FE_B14_SKIP ); + outb( sc->ioaddr[ FE_BMPR14 ], sc->proto_bmpr14 | FE_B14_SKIP ); } else { /* We should not come here unless receiving RUNTs. */ for ( i = 0; i < len; i += 2 ) { |