diff options
author | Jonathan Gray <jsg@cvs.openbsd.org> | 2007-03-21 12:20:31 +0000 |
---|---|---|
committer | Jonathan Gray <jsg@cvs.openbsd.org> | 2007-03-21 12:20:31 +0000 |
commit | cadcf6ece765dbbd4617ce6a3bcd5823ae8f563e (patch) | |
tree | 0e49b7e3cae0693cac037c7bf69be9d02f4e817c | |
parent | a75543aecae6a3e1c41846c4eb0562fbed48f05e (diff) |
Basic support for JMicron PATA.
JMB368 supported for now, multi port cards
that share PATA/SATA need to do a complicated
internal channel mapping dance I plan to look into next.
ok grange@
-rw-r--r-- | sys/dev/pci/pciide.c | 161 | ||||
-rw-r--r-- | sys/dev/pci/pciide_jmicron_reg.h | 32 |
2 files changed, 191 insertions, 2 deletions
diff --git a/sys/dev/pci/pciide.c b/sys/dev/pci/pciide.c index ca34830b223..fa85b4a178c 100644 --- a/sys/dev/pci/pciide.c +++ b/sys/dev/pci/pciide.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pciide.c,v 1.262 2006/11/21 21:48:54 brad Exp $ */ +/* $OpenBSD: pciide.c,v 1.263 2007/03/21 12:20:30 jsg Exp $ */ /* $NetBSD: pciide.c,v 1.127 2001/08/03 01:31:08 tsutsui Exp $ */ /* @@ -134,6 +134,7 @@ int wdcdebug_pciide_mask = WDCDEBUG_PCIIDE_MASK; #include <dev/pci/pciide_ite_reg.h> #include <dev/pci/pciide_ixp_reg.h> #include <dev/pci/pciide_svwsata_reg.h> +#include <dev/pci/pciide_jmicron_reg.h> #include <dev/pci/cy82c693var.h> /* inlines for reading/writing 8-bit PCI registers */ @@ -282,6 +283,9 @@ void ite_setup_channel(struct channel_softc *); void ixp_chip_map(struct pciide_softc *, struct pci_attach_args *); void ixp_setup_channel(struct channel_softc *); +void jmicron_chip_map(struct pciide_softc *, struct pci_attach_args *); +void jmicron_setup_channel(struct channel_softc *); + u_int8_t pciide_dmacmd_read(struct pciide_softc *, int); void pciide_dmacmd_write(struct pciide_softc *, int, u_int8_t); u_int8_t pciide_dmactl_read(struct pciide_softc *, int); @@ -1046,6 +1050,13 @@ const struct pciide_product_desc pciide_ati_products[] = { } }; +const struct pciide_product_desc pciide_jmicron_products[] = { + { PCI_PRODUCT_JMICRON_JMB368, + 0, + jmicron_chip_map + } +}; + struct pciide_vendor_desc { u_int32_t ide_vendor; const struct pciide_product_desc *ide_products; @@ -1086,7 +1097,9 @@ const struct pciide_vendor_desc pciide_vendors[] = { { PCI_VENDOR_ITEXPRESS, pciide_ite_products, sizeof(pciide_ite_products)/sizeof(pciide_ite_products[0]) }, { PCI_VENDOR_ATI, pciide_ati_products, - sizeof(pciide_ati_products)/sizeof(pciide_ati_products[0]) } + sizeof(pciide_ati_products)/sizeof(pciide_ati_products[0]) }, + { PCI_VENDOR_JMICRON, pciide_jmicron_products, + sizeof(pciide_jmicron_products)/sizeof(pciide_jmicron_products[0]) } }; /* options passed via the 'flags' config keyword */ @@ -8308,3 +8321,147 @@ ixp_setup_channel(struct channel_softc *chp) pciide_print_modes(cp); } + +void +jmicron_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa) +{ + struct pciide_channel *cp; + int channel; + pcireg_t interface = PCI_INTERFACE(pa->pa_class); + bus_size_t cmdsize, ctlsize; + u_int32_t conf; + + conf = pci_conf_read(sc->sc_pc, sc->sc_tag, JMICRON_CONF); + WDCDEBUG_PRINT(("%s: conf register 0x%x\n", + sc->sc_wdcdev.sc_dev.dv_xname, conf), DEBUG_PROBE); + + printf(": DMA"); + pciide_mapreg_dma(sc, pa); + + sc->sc_wdcdev.cap = WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32 | + WDC_CAPABILITY_MODE; + if (sc->sc_dma_ok) { + sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA | WDC_CAPABILITY_UDMA; + sc->sc_wdcdev.cap |= WDC_CAPABILITY_IRQACK; + sc->sc_wdcdev.irqack = pciide_irqack; + } + sc->sc_wdcdev.PIO_cap = 4; + sc->sc_wdcdev.DMA_cap = 2; + sc->sc_wdcdev.UDMA_cap = 6; + sc->sc_wdcdev.set_modes = jmicron_setup_channel; + sc->sc_wdcdev.channels = sc->wdc_chanarray; + sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS; + + pciide_print_channels(sc->sc_wdcdev.nchannels, interface); + + for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) { + cp = &sc->pciide_channels[channel]; + + if (pciide_chansetup(sc, channel, interface) == 0) + continue; + +#if 0 + if ((conf & JMICRON_CHAN_EN(channel)) == 0) { + printf("%s: %s ignored (disabled)\n", + sc->sc_wdcdev.sc_dev.dv_xname, cp->name); + continue; + } +#endif + + pciide_map_compat_intr(pa, cp, channel, interface); + if (cp->hw_ok == 0) + continue; + pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize, + pciide_pci_intr); + if (cp->hw_ok == 0) { + pciide_unmap_compat_intr(pa, cp, channel, interface); + continue; + } + + if (pciide_chan_candisable(cp)) { + conf &= ~JMICRON_CHAN_EN(channel); + pciide_unmap_compat_intr(pa, cp, channel, interface); + continue; + } + + sc->sc_wdcdev.set_modes(&cp->wdc_channel); + } + WDCDEBUG_PRINT(("%s: new conf register 0x%x\n", + sc->sc_wdcdev.sc_dev.dv_xname, conf), DEBUG_PROBE); + pci_conf_write(sc->sc_pc, sc->sc_tag, NFORCE_CONF, conf); +} + +void +jmicron_setup_channel(struct channel_softc *chp) +{ + struct ata_drive_datas *drvp; + int drive, mode; + u_int32_t idedma_ctl; + struct pciide_channel *cp = (struct pciide_channel *)chp; + struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc; + int channel = chp->channel; + u_int32_t conf; + + conf = pci_conf_read(sc->sc_pc, sc->sc_tag, JMICRON_CONF); + + /* Setup DMA if needed */ + pciide_channel_dma_setup(cp); + + /* Clear all bits for this channel */ + idedma_ctl = 0; + + /* Per channel settings */ + for (drive = 0; drive < 2; drive++) { + drvp = &chp->ch_drive[drive]; + + /* If no drive, skip */ + if ((drvp->drive_flags & DRIVE) == 0) + continue; + + if ((chp->wdc->cap & WDC_CAPABILITY_UDMA) != 0 && + (drvp->drive_flags & DRIVE_UDMA) != 0) { + /* Setup UltraDMA mode */ + drvp->drive_flags &= ~DRIVE_DMA; + + /* see if cable is up to scratch */ + if ((conf & JMICRON_CONF_40PIN) && + (drvp->UDMA_mode > 2)) + drvp->UDMA_mode = 2; + + mode = drvp->PIO_mode; + } else if ((chp->wdc->cap & WDC_CAPABILITY_DMA) != 0 && + (drvp->drive_flags & DRIVE_DMA) != 0) { + /* Setup multiword DMA mode */ + drvp->drive_flags &= ~DRIVE_UDMA; + + /* mode = min(pio, dma + 2) */ + if (drvp->PIO_mode <= (drvp->DMA_mode + 2)) + mode = drvp->PIO_mode; + else + mode = drvp->DMA_mode + 2; + } else { + mode = drvp->PIO_mode; + goto pio; + } + idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive); + +pio: + /* Setup PIO mode */ + if (mode <= 2) { + drvp->DMA_mode = 0; + drvp->PIO_mode = 0; + mode = 0; + } else { + drvp->PIO_mode = mode; + drvp->DMA_mode = mode - 2; + } + } + + if (idedma_ctl != 0) { + /* Add software bits in status register */ + bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh, + IDEDMA_CTL(channel), idedma_ctl); + } + + pciide_print_modes(cp); +} diff --git a/sys/dev/pci/pciide_jmicron_reg.h b/sys/dev/pci/pciide_jmicron_reg.h new file mode 100644 index 00000000000..4279c006743 --- /dev/null +++ b/sys/dev/pci/pciide_jmicron_reg.h @@ -0,0 +1,32 @@ +/* $OpenBSD: pciide_jmicron_reg.h,v 1.1 2007/03/21 12:20:30 jsg Exp $ */ + +/* + * Copyright (c) 2007 Jonathan Gray <jsg@openbsd.org> + * + * 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. + */ + +#ifndef _DEV_PCI_PCIIDE_JMICRON_REG_H +#define _DEV_PCI_PCIIDE_JMICRON_REG_H + +#define JMICRON_MASTER_UDMA (1 << 2) +#define JMICRON_MASTER_SHIFT 4 +#define JMICRON_SLAVE_SHIFT 12 + +#define JMICRON_CONF 0x40 +#define JMICRON_CHAN_EN(chan) ((chan == 1) ? 4 : 0) + +#define JMICRON_CONF_SWAP (1 << 22) +#define JMICRON_CONF_40PIN (1 << 3) + +#endif |