summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorJonathan Gray <jsg@cvs.openbsd.org>2009-05-31 04:42:17 +0000
committerJonathan Gray <jsg@cvs.openbsd.org>2009-05-31 04:42:17 +0000
commit4a9a1578beb07e49ccab159d6daa139143768dfa (patch)
tree0cbfd5eb282086721ed2534cc94f119cdc9faa8b /sys
parentb4348f06a8d76058212bb9a0349c975b6b41dc2e (diff)
Add SCH IDE support code.
Tested on a p series vaio.
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/pci/pciide.c120
-rw-r--r--sys/dev/pci/pciidereg.h12
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_ */