summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/dev/pci/pciide.c158
-rw-r--r--sys/dev/pci/pciide_natsemi_reg.h33
2 files changed, 189 insertions, 2 deletions
diff --git a/sys/dev/pci/pciide.c b/sys/dev/pci/pciide.c
index e9b413a07ca..da8400ee869 100644
--- a/sys/dev/pci/pciide.c
+++ b/sys/dev/pci/pciide.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pciide.c,v 1.159 2004/02/02 00:21:56 grange Exp $ */
+/* $OpenBSD: pciide.c,v 1.160 2004/02/02 19:38:43 grange Exp $ */
/* $NetBSD: pciide.c,v 1.127 2001/08/03 01:31:08 tsutsui Exp $ */
/*
@@ -252,6 +252,8 @@ void natsemi_chip_map(struct pciide_softc *, struct pci_attach_args *);
void natsemi_setup_channel(struct channel_softc *);
int natsemi_pci_intr(void *);
void natsemi_irqack(struct channel_softc *);
+void ns_scx200_chip_map(struct pciide_softc *, struct pci_attach_args *);
+void ns_scx200_setup_channel(struct channel_softc *);
void acer_chip_map(struct pciide_softc *, struct pci_attach_args *);
void acer_setup_channel(struct channel_softc *);
@@ -490,6 +492,10 @@ const struct pciide_product_desc pciide_natsemi_products[] = {
{ PCI_PRODUCT_NS_PC87415, /* National Semi PC87415 IDE */
0,
natsemi_chip_map
+ },
+ { PCI_PRODUCT_NS_SCx200_IDE, /* National Semi SCx200 IDE */
+ 0,
+ ns_scx200_chip_map
}
};
@@ -4173,6 +4179,156 @@ natsemi_pci_intr(arg)
}
void
+ns_scx200_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;
+
+ if (pciide_chipen(sc, pa) == 0)
+ return;
+
+ 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 = 2;
+
+ sc->sc_wdcdev.set_modes = ns_scx200_setup_channel;
+ sc->sc_wdcdev.channels = sc->wdc_chanarray;
+ sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS;
+
+ /*
+ * Soekris net4801 errata 0003:
+ *
+ * The SC1100 built in busmaster IDE controller is pretty standard,
+ * but have two bugs: data transfers need to be dword aligned and
+ * it cannot do an exact 64Kbyte data transfer.
+ *
+ * Assume that reducing maximum segment size by one page
+ * will be enough, and restrict boundary too for extra certainty.
+ */
+ if (sc->sc_pp->ide_product == PCI_PRODUCT_NS_SCx200_IDE) {
+ sc->sc_dma_maxsegsz = IDEDMA_BYTE_COUNT_MAX - PAGE_SIZE;
+ sc->sc_dma_boundary = IDEDMA_BYTE_COUNT_MAX - PAGE_SIZE;
+ }
+
+ 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
+ns_scx200_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;
+ int pioformat;
+ pcireg_t piotim, dmatim;
+
+ /* Setup DMA if needed */
+ pciide_channel_dma_setup(cp);
+
+ pioformat = (pci_conf_read(sc->sc_pc, sc->sc_tag,
+ SCx200_TIM_DMA(0, 0)) >> SCx200_PIOFORMAT_SHIFT) & 0x01;
+ WDCDEBUG_PRINT(("%s: pio format %d\n", __func__, pioformat),
+ DEBUG_PROBE);
+
+ /* 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;
+
+ piotim = pci_conf_read(sc->sc_pc, sc->sc_tag,
+ SCx200_TIM_PIO(channel, drive));
+ dmatim = pci_conf_read(sc->sc_pc, sc->sc_tag,
+ SCx200_TIM_DMA(channel, drive));
+ WDCDEBUG_PRINT(("%s:%d:%d: piotim=0x%x, dmatim=0x%x\n",
+ sc->sc_wdcdev.sc_dev.dv_xname, channel, drive,
+ piotim, dmatim), DEBUG_PROBE);
+
+ if ((chp->wdc->cap & WDC_CAPABILITY_UDMA) != 0 &&
+ (drvp->drive_flags & DRIVE_UDMA) != 0) {
+ /* Setup UltraDMA mode */
+ drvp->drive_flags &= ~DRIVE_DMA;
+ idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
+ dmatim = scx200_udma33[drvp->UDMA_mode];
+ 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;
+ idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
+ dmatim = scx200_dma33[drvp->DMA_mode];
+
+ /* 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;
+ }
+
+ /* Setup PIO mode */
+ drvp->PIO_mode = mode;
+ if (mode < 2)
+ drvp->DMA_mode = 0;
+ else
+ drvp->DMA_mode = mode - 2;
+
+ piotim = scx200_pio33[pioformat][drvp->PIO_mode];
+
+ WDCDEBUG_PRINT(("%s:%d:%d: new piotim=0x%x, dmatim=0x%x\n",
+ sc->sc_wdcdev.sc_dev.dv_xname, channel, drive,
+ piotim, dmatim), DEBUG_PROBE);
+
+ pci_conf_write(sc->sc_pc, sc->sc_tag,
+ SCx200_TIM_PIO(channel, drive), piotim);
+ pci_conf_write(sc->sc_pc, sc->sc_tag,
+ SCx200_TIM_DMA(channel, drive), dmatim);
+ }
+
+ 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);
+}
+
+void
acer_chip_map(sc, pa)
struct pciide_softc *sc;
struct pci_attach_args *pa;
diff --git a/sys/dev/pci/pciide_natsemi_reg.h b/sys/dev/pci/pciide_natsemi_reg.h
index f9f4cc2d95b..ee9291f8197 100644
--- a/sys/dev/pci/pciide_natsemi_reg.h
+++ b/sys/dev/pci/pciide_natsemi_reg.h
@@ -1,7 +1,8 @@
-/* $OpenBSD: pciide_natsemi_reg.h,v 1.4 2003/09/28 21:01:43 grange Exp $ */
+/* $OpenBSD: pciide_natsemi_reg.h,v 1.5 2004/02/02 19:38:43 grange Exp $ */
/*
* Copyright (c) 2001 Jason L. Wright (jason@thought.net)
+ * Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -97,3 +98,33 @@ static u_int8_t natsemi_dma_pulse[] = { 7, 10, 10 };
/* 16 - N = number of clocks */
static u_int8_t natsemi_pio_recover[] = { 6, 8, 11, 13, 15 };
static u_int8_t natsemi_dma_recover[] = { 6, 8, 9 };
+
+
+/*
+ * Register definitions for National Semiconductor SCx200 IDE found
+ * on Geode SC1100 IAOC.
+ */
+#define SCx200_TIM_PIO(chan, drive) (0x40 + 16 * (chan) + 8 * (drive))
+#define SCx200_TIM_DMA(chan, drive) (0x44 + 16 * (chan) + 8 * (drive))
+
+#define SCx200_PIOFORMAT_SHIFT 31
+
+/* PIO mode timings */
+const static u_int32_t scx200_pio33[2][5] = {
+ /* Format 0 */
+ { 0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010 },
+ /* Format 1 */
+ { 0x9172d132, 0x21717121, 0x00803020, 0x20102010, 0x00100010 }};
+const static u_int32_t scx200_pio66[2][5] = {
+ /* Fromat 0 */
+ { 0x0000f8e4, 0x000153f3, 0x000213f1, 0x00034231, 0x00041131 },
+ /* Format 1 */
+ { 0xf8e4f8e4, 0x53f3f353, 0x13f18141, 0x42314231, 0x11311131 }};
+
+/* DMA mode timings */
+const static u_int32_t scx200_dma33[] = { 0x00077771, 0x00012121, 0x00002020 };
+const static u_int32_t scx200_dma66[] = { 0x000ffff3, 0x00035352, 0x00015151 };
+
+/* UDMA mode timings */
+const static u_int32_t scx200_udma33[] = { 0x00921250, 0x00911140, 0x00911030 };
+const static u_int32_t scx200_udma66[] = { 0x009436a1, 0x00933481, 0x00923261 };