diff options
author | Jonathan Gray <jsg@cvs.openbsd.org> | 2009-05-31 04:42:17 +0000 |
---|---|---|
committer | Jonathan Gray <jsg@cvs.openbsd.org> | 2009-05-31 04:42:17 +0000 |
commit | 4a9a1578beb07e49ccab159d6daa139143768dfa (patch) | |
tree | 0cbfd5eb282086721ed2534cc94f119cdc9faa8b /sys | |
parent | b4348f06a8d76058212bb9a0349c975b6b41dc2e (diff) |
Add SCH IDE support code.
Tested on a p series vaio.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/pci/pciide.c | 120 | ||||
-rw-r--r-- | sys/dev/pci/pciidereg.h | 12 |
2 files changed, 130 insertions, 2 deletions
diff --git a/sys/dev/pci/pciide.c b/sys/dev/pci/pciide.c index 71a6f126990..d04fb19a0e6 100644 --- a/sys/dev/pci/pciide.c +++ b/sys/dev/pci/pciide.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pciide.c,v 1.294 2009/04/24 07:59:50 jsg Exp $ */ +/* $OpenBSD: pciide.c,v 1.295 2009/05/31 04:42:16 jsg Exp $ */ /* $NetBSD: pciide.c,v 1.127 2001/08/03 01:31:08 tsutsui Exp $ */ /* @@ -281,6 +281,9 @@ 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 *); +void sch_chip_map(struct pciide_softc *, struct pci_attach_args *); +void sch_setup_channel(struct channel_softc *); + struct pciide_product_desc { u_int32_t ide_product; u_short ide_flags; @@ -527,6 +530,10 @@ const struct pciide_product_desc pciide_intel_products[] = { { PCI_PRODUCT_INTEL_6321ESB_SATA, /* Intel 6321ESB SATA */ 0, piixsata_chip_map + }, + { PCI_PRODUCT_INTEL_SCH_IDE, /* Intel SCH IDE */ + 0, + sch_chip_map } }; @@ -8468,3 +8475,114 @@ pio: pciide_print_modes(cp); } + +void +sch_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; + + 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 = sch_setup_channel; + sc->sc_wdcdev.channels = sc->wdc_chanarray; + sc->sc_wdcdev.nchannels = 1; + + 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; + + 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; + } + + sc->sc_wdcdev.set_modes(&cp->wdc_channel); + } +} + +void +sch_setup_channel(struct channel_softc *chp) +{ + struct ata_drive_datas *drvp; + int drive, mode; + u_int32_t tim, timaddr; + struct pciide_channel *cp = (struct pciide_channel *)chp; + struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc; + + /* Setup DMA if needed */ + pciide_channel_dma_setup(cp); + + /* 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; + + timaddr = (drive == 0) ? SCH_D0TIM : SCH_D1TIM; + tim = pci_conf_read(sc->sc_pc, sc->sc_tag, timaddr); + tim &= ~SCH_TIM_MASK; + + if ((chp->wdc->cap & WDC_CAPABILITY_UDMA) != 0 && + (drvp->drive_flags & DRIVE_UDMA) != 0) { + /* Setup UltraDMA mode */ + drvp->drive_flags &= ~DRIVE_DMA; + + mode = drvp->PIO_mode; + tim |= (drvp->UDMA_mode << 16) | SCH_TIM_SYNCDMA; + } else if ((chp->wdc->cap & WDC_CAPABILITY_DMA) != 0 && + (drvp->drive_flags & DRIVE_DMA) != 0) { + /* Setup multiword DMA mode */ + drvp->drive_flags &= ~DRIVE_UDMA; + + tim &= ~SCH_TIM_SYNCDMA; + + /* 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; + } + +pio: + /* Setup PIO mode */ + if (mode <= 2) { + drvp->DMA_mode = 0; + drvp->PIO_mode = 0; + } else { + drvp->PIO_mode = mode; + drvp->DMA_mode = mode - 2; + } + tim |= (drvp->DMA_mode << 8) | (drvp->PIO_mode); + pci_conf_write(sc->sc_pc, sc->sc_tag, timaddr, tim); + } + + pciide_print_modes(cp); +} diff --git a/sys/dev/pci/pciidereg.h b/sys/dev/pci/pciidereg.h index e579ed24e91..a4d368f2e3d 100644 --- a/sys/dev/pci/pciidereg.h +++ b/sys/dev/pci/pciidereg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pciidereg.h,v 1.7 2004/10/17 08:44:41 grange Exp $ */ +/* $OpenBSD: pciidereg.h,v 1.8 2009/05/31 04:42:16 jsg Exp $ */ /* $NetBSD: pciidereg.h,v 1.6 2000/11/14 18:42:58 thorpej Exp $ */ /* @@ -120,4 +120,14 @@ struct idedma_table { /* Number of idedma table needed */ #define NIDEDMA_TABLES (MAXPHYS/PAGE_SIZE + 1) +/* Intel SCH */ +#define SCH_D0TIM 0x80 +#define SCH_D1TIM 0x84 +#define SCH_TIM_UDMA 0x30000 +#define SCH_TIM_MDMA 0x00300 +#define SCH_TIM_PIO 0x00007 +#define SCH_TIM_SYNCDMA (1 << 31) + +#define SCH_TIM_MASK (SCH_TIM_UDMA | SCH_TIM_MDMA | SCH_TIM_PIO) + #endif /* !_DEV_PCI_PCIIDEREG_H_ */ |