diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2008-04-07 22:53:01 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2008-04-07 22:53:01 +0000 |
commit | 1be3afb16ec8dbaa2507fafa1c68ee252216b1a5 (patch) | |
tree | 7e2dc715a2d75eab29642d8e942bb80e2a6fed10 | |
parent | bfd8c07d7d18784c1e8e8b9cf752b71043b31350 (diff) |
Preliminary IOC3 multi-function chip driver, from jsing@ and I. Currently
missing a driver for the ethernet part, and interrupt handling is not written
yet.
-rw-r--r-- | sys/arch/sgi/pci/ioc.c | 335 | ||||
-rw-r--r-- | sys/arch/sgi/pci/iocreg.h | 33 | ||||
-rw-r--r-- | sys/arch/sgi/pci/iocvar.h | 29 |
3 files changed, 397 insertions, 0 deletions
diff --git a/sys/arch/sgi/pci/ioc.c b/sys/arch/sgi/pci/ioc.c new file mode 100644 index 00000000000..f4dfc901d33 --- /dev/null +++ b/sys/arch/sgi/pci/ioc.c @@ -0,0 +1,335 @@ +/* $OpenBSD: ioc.c,v 1.1 2008/04/07 22:53:00 miod Exp $ */ + +/* + * Copyright (c) 2008 Joel Sing. + * Copyright (c) 2008 Miodrag Vallat. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * IOC device driver. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/device.h> +#include <sys/malloc.h> + +#include <machine/autoconf.h> +#include <machine/bus.h> +#include <machine/cpu.h> + +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> +#include <dev/pci/pcidevs.h> + +#include <sgi/pci/iocreg.h> +#include <sgi/pci/iocvar.h> + +#include <dev/onewire/onewirereg.h> +#include <dev/onewire/onewirevar.h> + +#include <sgi/dev/owmacvar.h> + +#include <sgi/xbow/xbow.h> + +int ioc_match(struct device *, void *, void *); +void ioc_attach(struct device *, struct device *, void *); +int ioc_search_onewire(struct device *, void *, void *); +int ioc_search_mundane(struct device *, void *, void *); +int ioc_print(void *, const char *); + +struct ioc_softc { + struct device sc_dev; + + struct mips_bus_space *sc_mem_bus_space; + + bus_space_tag_t sc_memt; + bus_space_handle_t sc_memh; + bus_dma_tag_t sc_dmat; + + struct onewire_bus sc_bus; + + struct owmac_softc *sc_owmac; +}; + +struct cfattach ioc_ca = { + sizeof(struct ioc_softc), ioc_match, ioc_attach, +}; + +struct cfdriver ioc_cd = { + NULL, "ioc", DV_DULL, +}; + +int iocow_reset(void *); +int iocow_read_bit(struct ioc_softc *); +int iocow_send_bit(void *, int); +int iocow_read_byte(void *); +int iocow_triplet(void *, int); +int iocow_pulse(struct ioc_softc *, int, int); + +int +ioc_match(struct device *parent, void *match, void *aux) +{ + struct pci_attach_args *pa = aux; + + if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_SGI && + PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_SGI_IOC3) + return (1); + + return (0); +} + +int +ioc_print(void *aux, const char *iocname) +{ + struct ioc_attach_args *iaa = aux; + + if (iocname != NULL) + printf("%s at %s", iaa->iaa_name, iocname); + + if (iaa->iaa_base != 0) + printf(" base 0x%08x", iaa->iaa_base); + if (iaa->iaa_intr != 0) + printf(" irq %d", iaa->iaa_intr); + + return (UNCONF); +} + +void +ioc_attach(struct device *parent, struct device *self, void *aux) +{ + struct ioc_softc *sc = (struct ioc_softc *)self; + struct pci_attach_args *pa = aux; + bus_space_tag_t memt; + bus_space_handle_t memh; + bus_size_t memsize; + + if (pci_mapreg_map(pa, PCI_MAPREG_START, PCI_MAPREG_TYPE_MEM, 0, + &memt, &memh, NULL, &memsize, 0)) { + printf(": cannot map memory space!\n"); + return; + } + + sc->sc_dmat = pa->pa_dmat; + + /* + * Build a suitable bus_space_handle by rebasing the xbridge + * inherited one to our BAR, and restoring the original + * non-swapped subword access methods. + * + * XXX This is horrible and will need to be rethought if + * XXX we ever support ioc3 cards not plugged to xbridges. + */ + + sc->sc_mem_bus_space = malloc(sizeof (*sc->sc_mem_bus_space), + M_DEVBUF, M_NOWAIT); + if (sc->sc_mem_bus_space == NULL) { + bus_space_unmap(memt, memh, memsize); + printf(": cannot allocate bus_space\n"); + return; + } + + bcopy(memt, sc->sc_mem_bus_space, sizeof(*sc->sc_mem_bus_space)); + sc->sc_mem_bus_space->bus_base = memh; + sc->sc_mem_bus_space->_space_read_1 = xbow_read_1; + sc->sc_mem_bus_space->_space_read_2 = xbow_read_2; + sc->sc_mem_bus_space->_space_write_1 = xbow_write_1; + sc->sc_mem_bus_space->_space_write_2 = xbow_write_2; + + sc->sc_memt = sc->sc_mem_bus_space; + sc->sc_memh = memh; + + printf("\n"); + + /* + * Attach the 1-Wire interface first, other sub-devices may + * need the information they'll provide. + */ + config_search(ioc_search_onewire, self, aux); + + /* + * Attach other sub-devices. + */ + config_search(ioc_search_mundane, self, aux); +} + +int +ioc_search_mundane(struct device *parent, void *vcf, void *args) +{ + struct ioc_softc *sc = (struct ioc_softc *)parent; + struct cfdata *cf = vcf; + struct ioc_attach_args iaa; + + if (strcmp(cf->cf_driver->cd_name, "onewire") == 0) + return 0; + + iaa.iaa_name = cf->cf_driver->cd_name; + iaa.iaa_memt = sc->sc_memt; + iaa.iaa_dmat = sc->sc_dmat; + + if (cf->cf_loc[0] == -1) + iaa.iaa_base = 0; + else + iaa.iaa_base = cf->cf_loc[0]; + if (cf->cf_loc[1] == -1) + iaa.iaa_intr = 0; + else + iaa.iaa_intr = cf->cf_loc[1]; + + if (sc->sc_owmac != NULL) + memcpy(iaa.iaa_enaddr, sc->sc_owmac->sc_enaddr, 6); + else + bzero(iaa.iaa_enaddr, 6); + + if ((*cf->cf_attach->ca_match)(parent, cf, &iaa) == 0) + return 0; + + config_attach(parent, cf, &iaa, ioc_print); + return 1; +} + +/* + * Number-In-a-Can access driver (1-Wire interface through IOC) + */ + +int +ioc_search_onewire(struct device *parent, void *vcf, void *args) +{ + struct ioc_softc *sc = (struct ioc_softc *)parent; + struct cfdata *cf = vcf; + struct onewirebus_attach_args oba; + struct device *owdev, *dev; + extern struct cfdriver owmac_cd; + + if (strcmp(cf->cf_driver->cd_name, "onewire") != 0) + return 0; + + sc->sc_bus.bus_cookie = sc; + sc->sc_bus.bus_reset = iocow_reset; + sc->sc_bus.bus_bit = iocow_send_bit; + sc->sc_bus.bus_read_byte = iocow_read_byte; + sc->sc_bus.bus_write_byte = NULL; /* use default routine */ + sc->sc_bus.bus_read_block = NULL; /* use default routine */ + sc->sc_bus.bus_write_block = NULL; /* use default routine */ + sc->sc_bus.bus_triplet = iocow_triplet; + sc->sc_bus.bus_matchrom = NULL; /* use default routine */ + sc->sc_bus.bus_search = NULL; /* use default routine */ + + oba.oba_bus = &sc->sc_bus; + oba.oba_flags = ONEWIRE_SCAN_NOW | ONEWIRE_NO_PERIODIC_SCAN; + + /* in case onewire is disabled in UKC */ + if ((*cf->cf_attach->ca_match)(parent, cf, &oba) == 0) + return 0; + + owdev = config_attach(parent, cf, &oba, onewirebus_print); + + /* + * Find the first owmac child of the onewire bus, and keep + * a pointer to it. This allows us to pass the ethernet + * address to the ethernet subdevice. + */ + if (owdev != NULL) { + TAILQ_FOREACH(dev, &alldevs, dv_list) + if (dev->dv_parent == owdev && + dev->dv_cfdata->cf_driver == &owmac_cd) { + sc->sc_owmac = (struct owmac_softc *)dev; + break; + } + } + return 1; +} + +int +iocow_reset(void *v) +{ + struct ioc_softc *sc = v; + return iocow_pulse(sc, 500, 65); +} + +int +iocow_read_bit(struct ioc_softc *sc) +{ + return iocow_pulse(sc, 6, 13); +} + +int +iocow_send_bit(void *v, int bit) +{ + struct ioc_softc *sc = v; + int rc; + + if (bit != 0) + rc = iocow_pulse(sc, 6, 110); + else + rc = iocow_pulse(sc, 80, 30); + return rc; +} + +int +iocow_read_byte(void *v) +{ + struct ioc_softc *sc = v; + unsigned int byte = 0; + int i; + + for (i = 0; i < 8; i++) + byte |= iocow_read_bit(sc) << i; + + return byte; +} + +int +iocow_triplet(void *v, int dir) +{ + struct ioc_softc *sc = v; + int rc; + + rc = iocow_read_bit(sc); + rc <<= 1; + rc |= iocow_read_bit(sc); + + switch (rc) { + case 0x0: + iocow_send_bit(v, dir); + break; + case 0x1: + iocow_send_bit(v, 0); + break; + default: + iocow_send_bit(v, 1); + break; + } + + return (rc); +} + +int +iocow_pulse(struct ioc_softc *sc, int pulse, int data) +{ + uint32_t mcr_value; + + mcr_value = (pulse << 10) | (data << 2); + bus_space_write_4(sc->sc_memt, sc->sc_memh, IOC3_MCR, mcr_value); + do { + mcr_value = + bus_space_read_4(sc->sc_memt, sc->sc_memh, IOC3_MCR); + } while ((mcr_value & 0x00000002) == 0); + + delay(500); + + return (mcr_value & 1); +} diff --git a/sys/arch/sgi/pci/iocreg.h b/sys/arch/sgi/pci/iocreg.h new file mode 100644 index 00000000000..83505242507 --- /dev/null +++ b/sys/arch/sgi/pci/iocreg.h @@ -0,0 +1,33 @@ +/* $OpenBSD: iocreg.h,v 1.1 2008/04/07 22:53:00 miod Exp $ */ + +/* + * Copyright (c) 2008 Joel Sing. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Register definitions for SGI IOC ASIC. + */ + +#define IOC3_MCR 0x00030 + +#define IOC3_RTC_BASE 0x20168 + +#define IOC3_UARTA_BASE 0x20178 +#define IOC3_UARTB_BASE 0x20170 + +#define IOC3_BYTEBUS_0 0x80000 +#define IOC3_BYTEBUS_1 0xa0000 +#define IOC3_BYTEBUS_2 0xc0000 +#define IOC3_BYTEBUS_3 0xe0000 diff --git a/sys/arch/sgi/pci/iocvar.h b/sys/arch/sgi/pci/iocvar.h new file mode 100644 index 00000000000..b625d712797 --- /dev/null +++ b/sys/arch/sgi/pci/iocvar.h @@ -0,0 +1,29 @@ +/* $OpenBSD: iocvar.h,v 1.1 2008/04/07 22:53:00 miod Exp $ */ + +/* + * Copyright (c) 2008 Miodrag Vallat. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +struct ioc_attach_args { + const char *iaa_name; + + bus_space_tag_t iaa_memt; + bus_dma_tag_t iaa_dmat; + + bus_addr_t iaa_base; + int iaa_intr; + + uint8_t iaa_enaddr[6]; +}; |