1*ce099b40Smartin /* $NetBSD: if_ate_mca.c,v 1.21 2008/04/28 20:23:53 martin Exp $ */
25f3d9f1dSjdolecek
35f3d9f1dSjdolecek /*-
45f3d9f1dSjdolecek * Copyright (c) 2001 The NetBSD Foundation, Inc.
55f3d9f1dSjdolecek * All rights reserved.
65f3d9f1dSjdolecek *
75f3d9f1dSjdolecek * This code is derived from software contributed to The NetBSD Foundation
85f3d9f1dSjdolecek * by Jaromir Dolecek.
95f3d9f1dSjdolecek *
105f3d9f1dSjdolecek * Redistribution and use in source and binary forms, with or without
115f3d9f1dSjdolecek * modification, are permitted provided that the following conditions
125f3d9f1dSjdolecek * are met:
135f3d9f1dSjdolecek * 1. Redistributions of source code must retain the above copyright
145f3d9f1dSjdolecek * notice, this list of conditions and the following disclaimer.
155f3d9f1dSjdolecek * 2. Redistributions in binary form must reproduce the above copyright
165f3d9f1dSjdolecek * notice, this list of conditions and the following disclaimer in the
175f3d9f1dSjdolecek * documentation and/or other materials provided with the distribution.
185f3d9f1dSjdolecek *
195f3d9f1dSjdolecek * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
205f3d9f1dSjdolecek * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
215f3d9f1dSjdolecek * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
225f3d9f1dSjdolecek * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
235f3d9f1dSjdolecek * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
245f3d9f1dSjdolecek * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
255f3d9f1dSjdolecek * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
265f3d9f1dSjdolecek * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
275f3d9f1dSjdolecek * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
285f3d9f1dSjdolecek * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
295f3d9f1dSjdolecek * POSSIBILITY OF SUCH DAMAGE.
305f3d9f1dSjdolecek */
315f3d9f1dSjdolecek
325f3d9f1dSjdolecek /*
335f3d9f1dSjdolecek * Driver for ATI AT1720X MCA cards based on Fujitsu MB8696xA controller.
345f3d9f1dSjdolecek */
355f3d9f1dSjdolecek
368b7bb912Slukem #include <sys/cdefs.h>
37*ce099b40Smartin __KERNEL_RCSID(0, "$NetBSD: if_ate_mca.c,v 1.21 2008/04/28 20:23:53 martin Exp $");
388b7bb912Slukem
395f3d9f1dSjdolecek #include <sys/param.h>
405f3d9f1dSjdolecek #include <sys/systm.h>
415f3d9f1dSjdolecek #include <sys/device.h>
425f3d9f1dSjdolecek #include <sys/socket.h>
435f3d9f1dSjdolecek #include <sys/syslog.h>
445f3d9f1dSjdolecek
455f3d9f1dSjdolecek #include <net/if.h>
465f3d9f1dSjdolecek #include <net/if_ether.h>
475f3d9f1dSjdolecek #include <net/if_media.h>
485f3d9f1dSjdolecek
49a2a38285Sad #include <sys/bus.h>
50a2a38285Sad #include <sys/intr.h>
515f3d9f1dSjdolecek
525f3d9f1dSjdolecek #include <dev/ic/mb86960reg.h>
535f3d9f1dSjdolecek #include <dev/ic/mb86960var.h>
545f3d9f1dSjdolecek
555f3d9f1dSjdolecek #include <dev/mca/mcavar.h>
565f3d9f1dSjdolecek #include <dev/mca/mcadevs.h>
575f3d9f1dSjdolecek
587c06c0a3Stsutsui int ate_mca_match(device_t, cfdata_t, void *);
597c06c0a3Stsutsui void ate_mca_attach(device_t, device_t, void *);
6018db93c7Sperry static void ate_mca_detect(bus_space_tag_t, bus_space_handle_t,
617c06c0a3Stsutsui uint8_t enaddr[ETHER_ADDR_LEN]);
625f3d9f1dSjdolecek
635f3d9f1dSjdolecek #define ATE_NPORTS 0x20
645f3d9f1dSjdolecek
655f3d9f1dSjdolecek struct ate_softc {
665f3d9f1dSjdolecek struct mb86960_softc sc_mb86960; /* real "mb86960" softc */
675f3d9f1dSjdolecek
685f3d9f1dSjdolecek /* MCA-specific goo. */
695f3d9f1dSjdolecek void *sc_ih; /* interrupt cookie */
705f3d9f1dSjdolecek };
715f3d9f1dSjdolecek
727c06c0a3Stsutsui CFATTACH_DECL_NEW(ate_mca, sizeof(struct ate_softc),
73c9b3657cSthorpej ate_mca_match, ate_mca_attach, NULL, NULL);
745f3d9f1dSjdolecek
755f3d9f1dSjdolecek static const struct ate_mca_product {
767c06c0a3Stsutsui uint32_t at_prodid; /* MCA product ID */
775f3d9f1dSjdolecek const char *at_name; /* device name */
785f3d9f1dSjdolecek int at_type; /* device type */
795f3d9f1dSjdolecek } ate_mca_products[] = {
805f3d9f1dSjdolecek { MCA_PRODUCT_AT1720T, "ATI AT1720T", FE_TYPE_AT1700T },
815f3d9f1dSjdolecek { MCA_PRODUCT_AT1720BT, "ATI AT1720BT", FE_TYPE_AT1700BT },
825f3d9f1dSjdolecek { MCA_PRODUCT_AT1720AT, "ATI AT1720AT", FE_TYPE_AT1700AT },
835f3d9f1dSjdolecek { MCA_PRODUCT_AT1720FT, "ATI AT1720FT", FE_TYPE_AT1700FT },
84e9198d13Schristos { 0, NULL, 0 },
855f3d9f1dSjdolecek };
865f3d9f1dSjdolecek
877c06c0a3Stsutsui static const struct ate_mca_product *ate_mca_lookup(uint32_t);
885f3d9f1dSjdolecek
895f3d9f1dSjdolecek static const struct ate_mca_product *
ate_mca_lookup(uint32_t id)907c06c0a3Stsutsui ate_mca_lookup(uint32_t id)
915f3d9f1dSjdolecek {
925f3d9f1dSjdolecek const struct ate_mca_product *atp;
935f3d9f1dSjdolecek
945f3d9f1dSjdolecek for (atp = ate_mca_products; atp->at_name != NULL; atp++)
955f3d9f1dSjdolecek if (id == atp->at_prodid)
967c06c0a3Stsutsui return atp;
975f3d9f1dSjdolecek
987c06c0a3Stsutsui return NULL;
995f3d9f1dSjdolecek }
1005f3d9f1dSjdolecek
1015f3d9f1dSjdolecek int
ate_mca_match(device_t parent,cfdata_t cf,void * aux)1027c06c0a3Stsutsui ate_mca_match(device_t parent, cfdata_t cf, void *aux)
1035f3d9f1dSjdolecek {
1047c06c0a3Stsutsui struct mca_attach_args *ma = aux;
1055f3d9f1dSjdolecek
1065f3d9f1dSjdolecek if (ate_mca_lookup(ma->ma_id) != NULL)
1077c06c0a3Stsutsui return 1;
1085f3d9f1dSjdolecek
1097c06c0a3Stsutsui return 0;
1105f3d9f1dSjdolecek }
1115f3d9f1dSjdolecek
1125f3d9f1dSjdolecek /* see POS diagrams below for explanation of these arrays' contents */
1135f3d9f1dSjdolecek static const int ats_iobase[] = {
1145f3d9f1dSjdolecek 0x400, 0x2400, 0x4400, 0x6400, 0x1400, 0x3400, 0x5400, 0x7400
1155f3d9f1dSjdolecek };
1165f3d9f1dSjdolecek static const int ats_irq[] = {
1175f3d9f1dSjdolecek 3, 4, 5, 9, 10, 11, 12, 15
1185f3d9f1dSjdolecek };
1195f3d9f1dSjdolecek
1205f3d9f1dSjdolecek void
ate_mca_attach(device_t parent,device_t self,void * aux)1217c06c0a3Stsutsui ate_mca_attach(device_t parent, device_t self, void *aux)
1225f3d9f1dSjdolecek {
123838ee1e0Sthorpej struct ate_softc *isc = device_private(self);
1245f3d9f1dSjdolecek struct mb86960_softc *sc = &isc->sc_mb86960;
1255f3d9f1dSjdolecek struct mca_attach_args *ma = aux;
1265f3d9f1dSjdolecek bus_space_tag_t iot = ma->ma_iot;
1275f3d9f1dSjdolecek bus_space_handle_t ioh;
1287c06c0a3Stsutsui uint8_t myea[ETHER_ADDR_LEN];
129e40197c4Ssimonb int pos3, pos4;
1305f3d9f1dSjdolecek int iobase, irq;
1315f3d9f1dSjdolecek const struct ate_mca_product *atp;
1325f3d9f1dSjdolecek
1337c06c0a3Stsutsui sc->sc_dev = self;
1347c06c0a3Stsutsui
1355f3d9f1dSjdolecek pos3 = mca_conf_read(ma->ma_mc, ma->ma_slot, 3);
1365f3d9f1dSjdolecek pos4 = mca_conf_read(ma->ma_mc, ma->ma_slot, 4);
1375f3d9f1dSjdolecek
1385f3d9f1dSjdolecek /*
1395f3d9f1dSjdolecek * POS register 2: (adf pos0)
1405f3d9f1dSjdolecek * 7 6 5 4 3 2 1 0
1415f3d9f1dSjdolecek * \__ enable: 0=adapter disabled, 1=adapter enabled
1425f3d9f1dSjdolecek *
1435f3d9f1dSjdolecek * POS register 3: (adf pos1)
1445f3d9f1dSjdolecek *
1455f3d9f1dSjdolecek * 7 6 5 4 3 2 1 0
1465f3d9f1dSjdolecek * \_/ \___/ \___/
1475f3d9f1dSjdolecek * \ \ \__ I/O Port Addresses: 000=0x400-0x4FF 100=0x1400-
1485f3d9f1dSjdolecek * \ \ 001=0x2400 101=0x3400 010=0x4400 110=0x5400
1495f3d9f1dSjdolecek * \ \ 011=0x6400 111=0x7400
1505f3d9f1dSjdolecek * \ \_____ Boot ROM Memory Address
1515f3d9f1dSjdolecek * \
1525f3d9f1dSjdolecek * \_________ Lower 2 bit of Interrupt Request Number
1535f3d9f1dSjdolecek *
1545f3d9f1dSjdolecek * POS register 4: (adf pos2)
1555f3d9f1dSjdolecek *
1565f3d9f1dSjdolecek * 7 6 5 4 3 2 1 0
1575f3d9f1dSjdolecek * \ \_______ Twisted Pair Type: 0=100 ohm, Unshielded
1585f3d9f1dSjdolecek * \ 1=150 ohm, Shielded
1595f3d9f1dSjdolecek * \____________ Higher 1 bit of Interrupt Request Number:
1605f3d9f1dSjdolecek * 000=3 001=4 010=5 011=9 100=10 101=11 110=12 111=15
1615f3d9f1dSjdolecek */
1625f3d9f1dSjdolecek
1635f3d9f1dSjdolecek atp = ate_mca_lookup(ma->ma_id);
1645f3d9f1dSjdolecek #ifdef DIAGNOSTIC
1655f3d9f1dSjdolecek if (atp == NULL) {
1661ef783cbScegger aprint_normal("\n");
1677c06c0a3Stsutsui aprint_error_dev(sc->sc_dev, "where did the card go?\n");
1685f3d9f1dSjdolecek return;
1695f3d9f1dSjdolecek }
1705f3d9f1dSjdolecek #endif
1715f3d9f1dSjdolecek
1725f3d9f1dSjdolecek iobase = ats_iobase[pos3 & 0x7];
1735f3d9f1dSjdolecek irq = ats_irq[((pos4 & 0x40) >> 4) | ((pos3 & 0xc0) >> 6)];
1745f3d9f1dSjdolecek
1757c06c0a3Stsutsui aprint_normal(" slot %d irq %d: %s\n",
1767c06c0a3Stsutsui ma->ma_slot + 1, irq, atp->at_name);
17715224351Sjdolecek
1785f3d9f1dSjdolecek /* Map i/o space. */
1795f3d9f1dSjdolecek if (bus_space_map(iot, iobase, ATE_NPORTS, 0, &ioh)) {
1807c06c0a3Stsutsui aprint_error_dev(sc->sc_dev, "can't map i/o space\n");
1815f3d9f1dSjdolecek return;
1825f3d9f1dSjdolecek }
1835f3d9f1dSjdolecek
1845f3d9f1dSjdolecek sc->sc_bst = iot;
1855f3d9f1dSjdolecek sc->sc_bsh = ioh;
1865f3d9f1dSjdolecek
187e40197c4Ssimonb /* Get ethernet address. */
1885f3d9f1dSjdolecek ate_mca_detect(iot, ioh, myea);
1895f3d9f1dSjdolecek
1905f3d9f1dSjdolecek /* This interface is always enabled. */
1919604e768Stsutsui sc->sc_stat |= FE_STAT_ENABLED;
1925f3d9f1dSjdolecek
1935f3d9f1dSjdolecek /*
1945f3d9f1dSjdolecek * Do generic MB86960 attach.
1955f3d9f1dSjdolecek */
1969604e768Stsutsui mb86960_attach(sc, myea);
1975f3d9f1dSjdolecek
1985f3d9f1dSjdolecek mb86960_config(sc, NULL, 0, 0);
1995f3d9f1dSjdolecek
2005f3d9f1dSjdolecek /* Establish the interrupt handler. */
2015f3d9f1dSjdolecek isc->sc_ih = mca_intr_establish(ma->ma_mc, irq, IPL_NET,
2025f3d9f1dSjdolecek mb86960_intr, sc);
2035f3d9f1dSjdolecek if (isc->sc_ih == NULL) {
2047c06c0a3Stsutsui aprint_error_dev(sc->sc_dev,
2057c06c0a3Stsutsui "couldn't establish interrupt handler\n");
2065f3d9f1dSjdolecek return;
2075f3d9f1dSjdolecek }
2085f3d9f1dSjdolecek }
2095f3d9f1dSjdolecek
2105f3d9f1dSjdolecek /*
2115f3d9f1dSjdolecek * Very simplified ate_detect() from dev/isa/if_ate.c, only
2125f3d9f1dSjdolecek * to determine ethernet address.
2135f3d9f1dSjdolecek */
2145f3d9f1dSjdolecek static void
ate_mca_detect(bus_space_tag_t iot,bus_space_handle_t ioh,uint8_t enaddr[ETHER_ADDR_LEN])2157c06c0a3Stsutsui ate_mca_detect(bus_space_tag_t iot, bus_space_handle_t ioh,
2167c06c0a3Stsutsui uint8_t enaddr[ETHER_ADDR_LEN])
2175f3d9f1dSjdolecek {
2187c06c0a3Stsutsui uint8_t eeprom[FE_EEPROM_SIZE];
2195f3d9f1dSjdolecek
2205f3d9f1dSjdolecek /* Get our station address from EEPROM. */
221fdedb8dbStsutsui mb86965_read_eeprom(iot, ioh, eeprom);
222fdedb8dbStsutsui memcpy(enaddr, eeprom + FE_ATI_EEP_ADDR, ETHER_ADDR_LEN);
2235f3d9f1dSjdolecek }
224