/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Rafal K. Boni.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
if (ia->ia_nio < 1)
return 0;
if (ia->ia_niomem < 1)
return 0;
if (ia->ia_nirq < 1)
return 0;
if (ISA_DIRECT_CONFIG(ia))
return 0;
iot = ia->ia_iot;
if (ia->ia_io[0].ir_addr == ISA_UNKNOWN_PORT)
return 0;
if (bus_space_map(iot, ia->ia_io[0].ir_addr,
IX_IOSIZE, 0, &ioh) != 0) {
DPRINTF(("Can't map io space at 0x%x\n",
ia->ia_io[0].ir_addr));
return 0;
}
/* XXX: reset any ee16 at the current iobase */
bus_space_write_1(iot, ioh, IX_ECTRL, IX_RESET_ASIC);
bus_space_write_1(iot, ioh, IX_ECTRL, 0);
delay(240);
/* Now look for ee16. */
board_id = id_var1 = id_var2 = 0;
for (i = 0; i < 4 ; i++) {
id_var1 = bus_space_read_1(iot, ioh, IX_ID_PORT);
id_var2 = ((id_var1 & 0x03) << 2);
board_id |= (( id_var1 >> 4) << id_var2);
}
if (board_id != IX_ID) {
DPRINTF(("BART ID mismatch (got 0x%04x, expected 0x%04x)\n",
board_id, IX_ID));
goto out;
}
/*
* The shared RAM size and location of the EE16 is encoded into
* EEPROM location 6. The location of the first set bit tells us
* the memory address (0xc0000 + (0x4000 * FSB)), where FSB is the
* number of the first set bit. The zeroes are then shifted out,
* and the results is the memory size (1 = 16k, 3 = 32k, 7 = 48k,
* 0x0f = 64k).
*
* Examples:
* 0x3c -> 64k@0xc8000, 0x70 -> 48k@0xd0000, 0xc0 -> 32k@0xd8000
* 0x80 -> 16k@0xdc000.
*
* Side note: this comes from reading the old driver rather than
* from a more definitive source, so it could be out-of-whack
* with what the card can do...
*/
val = ix_read_eeprom(iot, ioh, 6) & 0xff;
for (pg = 0; pg < 8; pg++) {
if (val & 1)
break;
val >>= 1;
}
/*
* Only do the following bit if using memory-mapped access. For
* boards with no mapped memory, we use PIO. We also use PIO for
* boards with 16K of mapped memory, as those setups don't seem
* to work otherwise.
*/
if (msiz != 0 && msiz != 16384) {
/* Set board up with memory-mapping info */
adjust = IX_MCTRL_FMCS16 | (pg & 0x3) << 2;
decode = ((1 << (ia->ia_iomem[0].ir_size / 16384)) - 1) << pg;
edecode = ((~decode >> 4) & 0xF0) | (decode >> 8);
/*
* Get the encoded interrupt number from the EEPROM, check it
* against the passed in IRQ. Issue a warning if they do not
* match, and fail the probe. If irq is 'ISA_UNKNOWN_IRQ' then we
* use the EEPROM irq, and continue.
*/
irq_encoded = ix_read_eeprom(iot, ioh, IX_EEPROM_CONFIG1);
irq_encoded = (irq_encoded & IX_EEPROM_IRQ) >> IX_EEPROM_IRQ_SHIFT;
irq = irq_translate[irq_encoded];
if (ia->ia_irq[0].ir_irq != ISA_UNKNOWN_IRQ &&
irq != ia->ia_irq[0].ir_irq) {
DPRINTF(("board IRQ %d does not match config\n", irq));
goto out;
}
/* Disable the board interrupts */
bus_space_write_1(iot, ioh, IX_IRQ, irq_encoded);
int media;
int i, memsize;
uint8_t bart_config;
bus_space_tag_t iot;
uint8_t bpat, bval;
uint16_t wpat, wval;
bus_space_handle_t ioh, memh;
uint16_t irq_encoded;
uint8_t ethaddr[ETHER_ADDR_LEN];
sc->sc_dev = self;
iot = ia->ia_iot;
/*
* Shared memory access seems to fail on 16K mapped boards, so
* disable shared memory access if the board is in 16K mode. If
* no memory is mapped, we have no choice but to use PIO
*/
isc->use_pio = (ia->ia_iomem[0].ir_size <= (16 * 1024));
if (bus_space_map(iot, ia->ia_io[0].ir_addr,
ia->ia_io[0].ir_size, 0, &ioh) != 0) {
/* We map memory even if using PIO so something else doesn't grab it */
if (ia->ia_iomem[0].ir_size) {
if (bus_space_map(ia->ia_memt, ia->ia_iomem[0].ir_addr,
ia->ia_iomem[0].ir_size, 0, &memh) != 0) {
DPRINTF(("\n%s: can't map iomem space 0x%x-0x%x\n",
device_xname(self), ia->ia_iomem[0].ir_addr,
ia->ia_iomem[0].ir_addr
+ ia->ia_iomem[0].ir_size - 1));
bus_space_unmap(iot, ioh, ia->ia_io[0].ir_size);
return;
}
}
isc->sc_regt = iot;
isc->sc_regh = ioh;
/*
* Get the hardware ethernet address from the EEPROM and
* save it in the softc for use by the 586 setup code.
*/
wval = ix_read_eeprom(iot, ioh, IX_EEPROM_ENET_HIGH);
ethaddr[1] = wval & 0xFF;
ethaddr[0] = wval >> 8;
wval = ix_read_eeprom(iot, ioh, IX_EEPROM_ENET_MID);
ethaddr[3] = wval & 0xFF;
ethaddr[2] = wval >> 8;
wval = ix_read_eeprom(iot, ioh, IX_EEPROM_ENET_LOW);
ethaddr[5] = wval & 0xFF;
ethaddr[4] = wval >> 8;
/*
* If using PIO, the memory size is bounded by on-card memory,
* not by how much is mapped into the memory-mapped region, so
* determine how much total memory we have to play with here.
*/
for (memsize = 64 * 1024; memsize; memsize -= 16 * 1024) {
/* warm up shared memory, the zero it all out */
ix_zeromem(sc, 0, 32);
ix_zeromem(sc, 0, memsize);
/* Reset write pointer to the start of RAM */
bus_space_write_2(iot, ioh, IX_WRITEPTR, 0);
/* Write test pattern */
for (i = 0, wpat = 1; i < memsize; i += 2) {
bus_space_write_2(iot, ioh, IX_DATAPORT, wpat);
wpat += 3;
}
/* Reset read pointer to beginning of card RAM */
bus_space_write_2(iot, ioh, IX_READPTR, 0);
/* Read and verify test pattern */
for (i = 0, wpat = 1; i < memsize; i += 2) {
wval = bus_space_read_2(iot, ioh, IX_DATAPORT);
if (wval != wpat)
break;
wpat += 3;
}
/* If we failed, try next size down */
if (i != memsize)
continue;
/* Now try it all with byte reads/writes */
ix_zeromem(sc, 0, 32);
ix_zeromem(sc, 0, memsize);
/* Reset write pointer to start of card RAM */
bus_space_write_2(iot, ioh, IX_WRITEPTR, 0);
/* Write out test pattern */
for (i = 0, bpat = 1; i < memsize; i++) {
bus_space_write_1(iot, ioh, IX_DATAPORT, bpat);
bpat += 3;
}
/* Reset read pointer to beginning of card RAM */
bus_space_write_2(iot, ioh, IX_READPTR, 0);
/* Read and verify test pattern */
for (i = 0, bpat = 1; i < memsize; i++) {
bval = bus_space_read_1(iot, ioh, IX_DATAPORT);
if (bval != bpat)
bpat += 3;
}
/* If we got through all of memory, we're done! */
if (i == memsize)
break;
}
/* Set up pointers to key structures */
ix_write_24(sc, IE_SCP_ISCP((u_long)sc->scp), (u_long)sc->iscp);
ix_write_16(sc, IE_ISCP_SCB((u_long)sc->iscp), (u_long)sc->scb);
ix_write_24(sc, IE_ISCP_BASE((u_long)sc->iscp), (u_long)sc->iscp);
/* Flush setup of pointers, check if chip answers */
if (!i82586_proberam(sc)) {
DPRINTF(("\n%s: Can't talk to i82586!\n",
device_xname(self)));
bus_space_unmap(iot, ioh, ia->ia_io[0].ir_size);
if (ia->ia_iomem[0].ir_size)
bus_space_unmap(ia->ia_memt, memh,
ia->ia_iomem[0].ir_size);
return;
}
/* Figure out which media is being used... */
if (ix_read_eeprom(iot, ioh, IX_EEPROM_CONFIG1) &
IX_EEPROM_MEDIA_EXT) {
if (ix_read_eeprom(iot, ioh, IX_EEPROM_MEDIA) &
IX_EEPROM_MEDIA_TP)
media = IFM_ETHER | IFM_10_T;
else
media = IFM_ETHER | IFM_10_2;
} else
media = IFM_ETHER | IFM_10_5;
/* Take the card out of loopback */
bart_config = bus_space_read_1(iot, ioh, IX_CONFIG);
bart_config &= ~IX_BART_LOOPBACK;
bart_config |= IX_BART_MCS16_TEST; /* inb doesn't get bit! */
bus_space_write_1(iot, ioh, IX_CONFIG, bart_config);
bart_config = bus_space_read_1(iot, ioh, IX_CONFIG);