Subject: pciide for Acer M5229 controller
To: None <port-i386@netbsd.org>
From: Manuel Bouyer <bouyer@antioche.lip6.fr>
List: port-i386
Date: 01/28/1999 19:12:29
--9vaYmALEf/7YXxc3
Content-Type: text/plain; charset=us-ascii


Hi,

below is a patch that should add support for the M5229 IDE controller
to pciide. Could people which have a chance to play with such hardware
give it a try and report me how it goes ?

--
Manuel Bouyer, LIP6, Universite Paris VI.           Manuel.Bouyer@lip6.fr
--

--9vaYmALEf/7YXxc3
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="pciide.diff"

Index: pciide.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/pciide.c,v
retrieving revision 1.29
diff -u -r1.29 pciide.c
--- pciide.c	1998/12/16 13:21:26	1.29
+++ pciide.c	1999/01/28 17:04:51
@@ -74,6 +74,7 @@
 #include <dev/pci/pciide_cmd_reg.h>
 #include <dev/pci/pciide_cy693_reg.h>
 #include <dev/pci/pciide_sis_reg.h>
+#include <dev/pci/pciide_acer_reg.h>
 #include <dev/ata/atavar.h>
 #include <dev/ic/wdcreg.h>
 #include <dev/ic/wdcvar.h>
@@ -174,6 +175,11 @@
 void sis_setup_channel __P((struct channel_softc*));
 void sis_channel_map __P((struct pci_attach_args *, struct pciide_channel *));
 
+void acer_setup_cap __P((struct pciide_softc*));
+void acer_setup_chip __P((struct pciide_softc*));
+void acer_setup_channel __P((struct channel_softc*));
+void acer_channel_map __P((struct pci_attach_args *, struct pciide_channel *));
+
 void pciide_channel_dma_setup __P((struct pciide_channel *));
 int  pciide_dma_table_setup __P((struct pciide_softc*, int, int));
 int  pciide_dma_init __P((void*, int, int, void *, size_t, int));
@@ -338,6 +344,22 @@
     }
 };
 
+const struct pciide_product_desc pciide_acer_products[] =  {
+    { PCI_PRODUCT_ALI_M5229,
+      0,
+      PCIIDE_NUM_CHANNELS,
+      "Acer Labs M5229 UDMA IDE Controller",
+      acer_setup_cap,
+      acer_setup_chip,
+      acer_channel_map
+    },
+    { 0,
+      0,
+      0,
+      NULL,
+    }
+};
+
 struct pciide_vendor_desc {
     u_int32_t ide_vendor;
     const struct pciide_product_desc *ide_products;
@@ -349,6 +371,7 @@
     { PCI_VENDOR_VIATECH, pciide_via_products },
     { PCI_VENDOR_CONTAQ, pciide_cypress_products },
     { PCI_VENDOR_SIS, pciide_sis_products },
+    { PCI_VENDOR_ALI, pciide_acer_products },
     { 0, NULL }
 };
 
@@ -2056,6 +2079,141 @@
 		else
 			sis_ctr0 &= ~SIS_CTRL0_CHAN1_EN;
 		pciide_pci_write(sc->sc_pc, sc->sc_tag, SIS_CTRL0, sis_ctr0);
+	}
+	pciide_map_compat_intr(pa, cp, wdc_cp->channel, interface);
+}
+
+void
+acer_setup_cap(sc)
+	struct pciide_softc *sc;
+{
+	sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA32 | WDC_CAPABILITY_MODE |
+	    WDC_CAPABILITY_DMA | WDC_CAPABILITY_UDMA;
+	sc->sc_wdcdev.PIO_cap = 4;
+	sc->sc_wdcdev.DMA_cap = 2;
+	sc->sc_wdcdev.UDMA_cap = 2;
+	sc->sc_wdcdev.set_modes = acer_setup_channel;
+}
+
+void
+acer_setup_chip(sc)
+	struct pciide_softc *sc;
+{
+	int channel;
+
+	for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) {
+		acer_setup_channel(&sc->pciide_channels[channel].wdc_channel);
+	}
+}
+
+void
+acer_setup_channel(chp)
+	struct channel_softc *chp;
+{
+	struct ata_drive_datas *drvp;
+	int drive;
+	u_int32_t acer_fifo_udma;
+	u_int32_t idedma_ctl;
+	struct pciide_channel *cp = (struct pciide_channel*)chp;
+	struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
+
+	idedma_ctl = 0;
+	acer_fifo_udma = pci_conf_read(sc->sc_pc, sc->sc_tag, ACER_FTH_UDMA);
+	WDCDEBUG_PRINT(("acer_setup_chip: old fifo/udma reg 0x%x\n", 
+	    acer_fifo_udma), DEBUG_PROBE);
+	/* setup DMA if needed */
+	pciide_channel_dma_setup(cp);
+
+	for (drive = 0; drive < 2; drive++) {
+		drvp = &chp->ch_drive[drive];
+		/* If no drive, skip */
+		if ((drvp->drive_flags & DRIVE) == 0)
+			continue;
+		WDCDEBUG_PRINT(("acer_setup_chip: old timings reg for "
+		    "channel %d drive %d 0x%x\n", chp->channel, drive,
+		    pciide_pci_read(sc->sc_pc, sc->sc_tag,
+		    ACER_IDETIM(chp->channel, drive))), DEBUG_PROBE);
+		/* clear FIFO/DMA mode */
+		acer_fifo_udma &= ~(ACER_FTH_OPL(chp->channel, drive, 0x3) |
+		    ACER_UDMA_EN(chp->channel, drive) |
+		    ACER_UDMA_TIM(chp->channel, drive, 0x7));
+
+		/* add timing values, setup DMA if needed */
+		if ((drvp->drive_flags & DRIVE_DMA) == 0 &&
+		    (drvp->drive_flags & DRIVE_UDMA) == 0) {
+			acer_fifo_udma |=
+			    ACER_FTH_OPL(chp->channel, drive, 0x1);
+			goto pio;
+		}
+
+		acer_fifo_udma |= ACER_FTH_OPL(chp->channel, drive, 0x2);
+		if (drvp->drive_flags & DRIVE_UDMA) {
+			/* use Ultra/DMA */
+			drvp->drive_flags &= ~DRIVE_DMA;
+			acer_fifo_udma |= ACER_UDMA_EN(chp->channel, drive);
+			acer_fifo_udma |= 
+			    ACER_UDMA_TIM(chp->channel, drive,
+				acer_udma[drvp->UDMA_mode]);
+		} else {
+			/*
+			 * use Multiword DMA
+			 * Timings will be used for both PIO and DMA,
+			 * so adjust DMA mode if needed
+			 */
+			if (drvp->PIO_mode > (drvp->DMA_mode + 2))
+				drvp->PIO_mode = drvp->DMA_mode + 2;
+			if (drvp->DMA_mode == 0)
+				drvp->PIO_mode = 0;
+		}
+		idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
+pio:		pciide_pci_write(sc->sc_pc, sc->sc_tag,
+		    ACER_IDETIM(chp->channel, drive),
+		    acer_pio[drvp->PIO_mode]);
+	}
+	WDCDEBUG_PRINT(("acer_setup_chip: old fifo/udma reg 0x%x\n",
+	    acer_fifo_udma), DEBUG_PROBE);
+	pci_conf_write(sc->sc_pc, sc->sc_tag, ACER_FTH_UDMA, acer_fifo_udma);
+	if (idedma_ctl != 0) {
+		/* Add software bits in status register */
+		bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh,
+		    IDEDMA_CTL, idedma_ctl);
+	}
+	pciide_print_modes(cp);
+}
+
+void
+acer_channel_map(pa, cp)
+	struct pci_attach_args *pa;
+	struct pciide_channel *cp;
+{
+	struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
+	bus_size_t cmdsize, ctlsize;
+	struct channel_softc *wdc_cp = &cp->wdc_channel;
+	u_int32_t cr = pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_CLASS_REG);
+	int interface = PCI_INTERFACE(cr);
+
+	/* Enable "microsoft register bits" R/W */
+	pciide_pci_write(sc->sc_pc, sc->sc_tag, ACER_CCAR3,
+	    pciide_pci_read(sc->sc_pc, sc->sc_tag, ACER_CCAR3) | ACER_CCAR3_PI);
+	pciide_pci_write(sc->sc_pc, sc->sc_tag, ACER_CCAR1,
+	    pciide_pci_read(sc->sc_pc, sc->sc_tag, ACER_CCAR1) &
+	    ~(ACER_CHANSTATUS_RO|PCIIDE_CHAN_RO(0)|PCIIDE_CHAN_RO(1)));
+	pciide_pci_write(sc->sc_pc, sc->sc_tag, ACER_CCAR2,
+	    pciide_pci_read(sc->sc_pc, sc->sc_tag, ACER_CCAR2) &
+	    ~ACER_CHANSTATUSREGS_RO);
+
+	if ((interface & PCIIDE_CHAN_EN(wdc_cp->channel)) == 0) {
+		printf("%s: %s channel ignored (disabled)\n",
+		    sc->sc_wdcdev.sc_dev.dv_xname, cp->name);
+		return;
+	}
+
+	pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize);
+	if (cp->hw_ok == 0)
+		return;
+	if (pciiide_chan_candisable(cp)) {
+		cr &= ~(PCIIDE_CHAN_EN(wdc_cp->channel) << PCI_INTERFACE_SHIFT);
+		pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_CLASS_REG, cr);
 	}
 	pciide_map_compat_intr(pa, cp, wdc_cp->channel, interface);
 }
Index: pciide_acer_reg.h
===================================================================
RCS file: pciide_acer_reg.h
diff -N pciide_acer_reg.h
--- /dev/null	Thu Jan 28 03:36:12 1999
+++ pciide_acer_reg.h	Thu Jan 28 09:04:51 1999
@@ -0,0 +1,73 @@
+/*	$NetBSD: $	*/
+
+/*
+ * Copyright (c) 1999 Manuel Bouyer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*  class code attribute register 1 (1 byte) */
+#define ACER_CCAR1	0x43
+#define ACER_CHANSTATUS_RO            0x40
+#define PCIIDE_CHAN_RO(chan)            (0x10 << (chan))
+
+/* class code attribute register 2 (1 byte) */
+#define ACER_CCAR2	0x4d
+#define ACER_CHANSTATUSREGS_RO 0x80
+
+/* class code attribute register 3 (1 byte) */
+#define ACER_CCAR3	0x50
+#define ACER_CCAR3_PI	0x02
+
+/* Fifo threshold and Ultra-DMA settings (4 bytes). */
+#define ACER_FTH_UDMA	0x54
+#define ACER_FTH_VAL(chan, drv, val) \
+	(((val) & 0x3) << ((drv) * 4 + (chan) * 8))
+#define ACER_FTH_OPL(chan, drv, val) \
+	(((val) & 0x3) << (2 + (drv) * 4 + (chan) * 8))
+#define ACER_UDMA_EN(chan, drv) \
+	(0x8 << (16 + (drv) * 4 + (chan) * 8))
+#define ACER_UDMA_TIM(chan, drv, val) \
+	(((val) & 0x7) << (16 + (drv) * 4 + (chan) * 8))
+
+/* drives timings setup (1 byte) */
+#define ACER_IDETIM(chan, drv) (0x5a + (drv) + (chan) * 4)
+
+/*
+ * IDE bus frequency (1 byte)
+ * This should be setup by the BIOS - can we rely on this ?
+ */
+#define ACER_IDE_CLK	0x78 
+
+static int8_t acer_udma[] = {0x4, 0x3, 0x2};
+static int8_t acer_pio[] = {0x0c, 0x58, 0x44, 0x33, 0x31};
+#ifdef unused
+static int8_t acer_dma[] = {0x08, 0x33, 0x31};
+#endif
Index: pciidereg.h
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/pciidereg.h,v
retrieving revision 1.3
diff -u -r1.3 pciidereg.h
--- pciidereg.h	1998/10/12 16:09:22	1.3
+++ pciidereg.h	1999/01/28 17:04:51
@@ -55,7 +55,12 @@
 
 /*
  * Bits in the PCI Programming Interface register (some are per-channel).
+ * Bits 6-4 are defined as read-only in PCI 2.1 specification.
+ * Microsoft proposed to use these bits for independant channels
+ * enable/disable. This feature is enabled based on the value of bit 6.
  */
+#define PCIIDE_CHANSTATUS_EN		0x40
+#define PCIIDE_CHAN_EN(chan)		(0x10 << (chan))
 #define	PCIIDE_INTERFACE_PCI(chan)	(0x01 << (2 * (chan)))
 #define	PCIIDE_INTERFACE_SETTABLE(chan)	(0x02 << (2 * (chan)))
 #define	PCIIDE_INTERFACE_BUS_MASTER_DMA	0x80

--9vaYmALEf/7YXxc3--